Создание игры на Java без сторонних библиотек, часть первая




Почему 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);


Результат:



Весь код Game.java

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
Если вы ведёте свой блог, микроблог, либо участвуете в какой-то популярной социальной сети, то вы можете быстро поделиться данной заметкой со своими друзьями и посетителями. Для этого воспользуйтесь предлагаемыми ниже кнопками:



Блог: http://romanlovetext.blogspot.com/