Pull to refresh

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

Reading time 4 min
Views 275K


Введение и подготовка



Привет хаброжители. Данный пост является «рерайтом» моего поста для песочницы. На этот раз я постараюсь охватить больше тем, чем тогда.

Почему 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
Tags:
Hubs:
+30
Comments 50
Comments Comments 50

Articles