Введение и подготовка
Привет хаброжители. Данный пост является «рерайтом» моего поста для песочницы. На этот раз я постараюсь охватить больше тем, чем тогда.
Почему Java?
Ничего объективного я тут не скажу, а скажу лишь то, что я люблю этот язык, и мне нравиться писать на нем. Да, на Java нет игр AAA-класса, но Java предоставляет огромные возможности, больше кол-во встроенных средств и быстроту написания кода.
IDE
Начнем с выбора IDE. Я являюсь фанатом Eclipse и посоветую вам его.
Если же почему то вам он не понравился, вы можете использовать NetBeans, Intellij IDEA или командную строку и ваш любимый редактор.
JDK
И скачаем JDK последней версии: JDK 7u4
Скорее всего проблем с установкой IDE у вас не возникнет, а если у вас 64-битная система, все же посоветую устанавливать 32-битный Eclipse, так как иногда бывают ошибки и Eclipse у вас просто не запуститься.
Под катом мы приступим к созданию игры.
Класс Game
Итак, создаем проект, в нем класс Game(попутно создав в нем точку входа). Данный класс должен наследовать класс Canvas и реализовать интерфейс Runnable:
public class Game extends Canvas implements Runnable {
private static final long serialVersionUID = 1L;
public void run() { //функция run появляется после того, как мы добавили "implements Runnable"
}
public static void main(String[] args) {
}
}
Создадим переменную running типа Boolean, которая, как вы уже догадались будет показывать нам запущена ли игра, или нет.
Создадим функцию start() и в ней мы будем создавать новый поток и переводить running в true:
public void start() {
running = true;
new Thread(this).start();
}
Создадим три функции — update(long delta), render() и init(). Я надеюсь что их значение вам понятно. В функции run() создадим главный игровой цикл, перед ним будем вызывать init(), а в нем самом render() и update(). Так же мы будем вычислять разницу между кадрами(delta time).
public void run() {
long lastTime = System.currentTimeMillis();
long delta;
init();
while(running) {
delta = System.currentTimeMillis() - lastTime;
lastTime = System.currentTimeMillis();
update(delta);
render();
}
}
public void init() {
}
public void render() {
}
public void update(long delta) {
}
Пока поработаем над функцией render().
public void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(2); //создаем BufferStrategy для нашего холста
requestFocus();
return;
}
Graphics g = bs.getDrawGraphics(); //получаем Graphics из созданной нами BufferStrategy
g.setColor(Color.black); //выбрать цвет
g.fillRect(0, 0, getWidth(), getHeight()); //заполнить прямоугольник
g.dispose();
bs.show(); //показать
}
Вам наверное уже не терпится запустить и попробовать, но не спешите. Мы должны создать фрейм и добавить наш холст на него. Заодно и объявим три переменных.
public static int WIDTH = 400; //ширина
public static int HEIGHT = 300; //высота
public static String NAME = "TUTORIAL 1"; //заголовок окна
public static void main(String[] args) {
Game game = new Game();
game.setPreferredSize(new Dimension(WIDTH, HEIGHT));
JFrame frame = new JFrame(Game.NAME);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //выход из приложения по нажатию клавиши ESC
frame.setLayout(new BorderLayout());
frame.add(game, BorderLayout.CENTER); //добавляем холст на наш фрейм
frame.pack();
frame.setResizable(false);
frame.setVisible(true);
game.start();
}
Примерно вот так выглядит наш класс Game сейчас.
Класс Sprite
Создадим новый класс Sprite. Поскольку этот класс небольшой, я сразу приведу весь его код с комментариями:
import java.awt.Graphics;
import java.awt.Image;
public class Sprite {
private Image image; //изображение
public Sprite(Image image) {
this.image = image;
}
public int getWidth() { //получаем ширину картинки
return image.getWidth(null);
}
public int getHeight() { //получаем высоту картинки
return image.getHeight(null);
}
public void draw(Graphics g,int x,int y) { //рисуем картинку
g.drawImage(image,x,y,null);
}
}
Сразу же проверим работоспособность. Возьмем эту картинку и скопируем ее в папку с нашим классом Sprite. Добавим функцию getSprite() в класс Game(временно).
public Sprite getSprite(String path) {
BufferedImage sourceImage = null;
try {
URL url = this.getClass().getClassLoader().getResource(path);
sourceImage = ImageIO.read(url);
} catch (IOException e) {
e.printStackTrace();
}
Sprite sprite = new Sprite(Toolkit.getDefaultToolkit().createImage(sourceImage.getSource()));
return sprite;
}
Добавим нашу картинку в папку assets(папку создать в корне проекта), саму папку надо добавить в build path.
Далее создаем переменную hero типа Sprite. В функции init() инициализируем ее. В Функции render() рисуем:
//в "шапку"
public static Sprite hero;
//в init()
hero = getSprite("man.png");
//в render() после g.fillRect(0, 0, getWidth(), getHeight());
hero.draw(g, 20, 20);
Результат:
Input
Для обработки инпута мы создадим класс, наследующий KeyAdapter:
private class KeyInputHandler extends KeyAdapter {
}
Тут же и объявим две переменных в шапке класса Game:
private boolean leftPressed = false;
private boolean rightPressed = false;
Внутри класса KeyInputHandler создадим две функции:
public void keyPressed(KeyEvent e) { //клавиша нажата
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
leftPressed = true;
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
rightPressed = true;
}
}
public void keyReleased(KeyEvent e) { //клавиша отпущена
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
leftPressed = false;
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
rightPressed = false;
}
}
Теперь в функции init() добавим следующее:
addKeyListener(new KeyInputHandler());
Создадим переменные x и y для героя(так как пока что мы еще не написали класс Entity). Сделаем чтобы герой всегда рисовался на этих координатах.
private static int x = 0;
private static int y = 0;
hero.draw(g, x, y);
А теперь в функции update() будем проверять нажаты ли клавиши и изменять x-координату.
public void update(long delta) {
if (leftPressed == true) {
x--;
}
if (rightPressed == true) {
x++;
}
}
Он двигается!
Спасибо за внимание.
P.S. Ссылка на github
Автор: TideSofDarK