Код программы на java игры

В этой статье будет описываться создание 2D игры на Java. Сразу предупреждаю, вы должны хотя бы базово знать язык Java, поскольку на подробное объяснение каждой строки у меня нету времени. И очень прошу вас, не списывать просто код, а пытаться понять что означает каждая строка, и писать со смыслом. И еще, я использую Eclipse, но вы можете использовать любой IDE.

Задача:

Я планирую создать игру, напоминающую шутер с видом от 3 лица.

Начало:

Ну что, приступим!

Для начала создадим проект. Назовем его «Just game». И сразу создаем класс Display.java. В него пишем:

public static void main(String[] args) < JFrame frame = new JFrame(/* название нашей игры */); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setExtendedState(JFrame.MAXIMIZED_BOTH); frame.setUndecorated(true); frame.setVisible(true); >

Теперь разберемся, что мы сделали.

JFrame frame = new JFrame(/*название нашей игры*/);

Как написать свою змейку на Java за 15 минут

Обложка: Как написать свою змейку на Java за 15 минут

Как запускать игры и приложения на Java

В предыдущей статье мы писали сапёра за 15 минут, теперь займёмся классической змейкой.

В этот раз нам снова понадобятся:

  • 15 минут свободного времени;
  • Настроенная рабочая среда, т.е. JDK и IDE (например Eclipse);
  • Библиотека LWJGL (версии 2.x.x) для работы с Open GL. Обратите внимание, что для LWJGL версий выше 3 потребуется написать код, отличающийся от того, что приведён в статье;
  • Спрайты, т.е. картинки самой змеи и фрукта, который она будет есть. Можно чисто символически нарисовать самому, или скачать использовавшиеся при написании статьи.

Подключение библиотек

В прошлый раз у многих возникли с этим вопросом проблемы, поэтому мне показалось уместным посвятить этому немного времени. Во-первых, выше я дал ссылку на скачивание архива с библиотеками, которые использую я, чтобы не было путаницы с версиями и вопросов, где найти что-то. Папку из архива требуется поместить в папку проекта и подключить через вашу IDE.

Во-вторых, у многих пользователей InteliJ IDEA возникли проблемы как раз с их подключением. Я нашёл в сети следующий видеогайд:

После того, как я сделал всё в точности по нему, у меня библиотеки подключились корректно и всё заработало.

Работа с графикой

С этой стороны наша задача мало отличается от той, что мы выполняли при написании Сапёра. Снова создаём класс GUI, который будет хранить и обновлять состояние всех графических элементов. Если точнее:

  • Класс будет выполнять инициализацию OpenGL:

///Class GUI private static void initializeOpenGL() < try < //Задаём размер будущего окна Display.setDisplayMode(new DisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT)); //Задаём имя будущего окна Display.setTitle(SCREEN_NAME); //Создаём окно Display.create(); >catch (LWJGLException e) < e.printStackTrace(); >glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0,SCREEN_WIDTH,0,SCREEN_HEIGHT,1,-1); glMatrixMode(GL_MODELVIEW); /* * Для поддержки текстур */ glEnable(GL_TEXTURE_2D); /* * Для поддержки прозрачности */ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /* * Белый фоновый цвет */ glClearColor(1,1,1,1); >

  • Должен хранить текущие состояния ячеек:

//Класс Cells напишем несколько позже private static Cell[][] cells;
///Рисует все клетки public static void draw() < ///Очищает экран от старого изображения glClear(GL_COLOR_BUFFER_BIT); for(Cell[] line:cells)< for(Cell cell:line)< drawElement(cell); >> > private static void drawElement(Cell elem)< ///Если у ячейки нет спрайта, то рисовать её не нужно if(elem.getSprite() == null) return; ///Собственно, рисуем. Подробно не останавливаюсь, так как нам интересна сама логика игры, а не LWJGL elem.getSprite().getTexture().bind(); glBegin(GL_QUADS); glTexCoord2f(0,0); glVertex2f(elem.getX(),elem.getY()+elem.getHeight()); glTexCoord2f(1,0); glVertex2f(elem.getX()+elem.getWidth(),elem.getY()+elem.getHeight()); glTexCoord2f(1,1); glVertex2f(elem.getX()+elem.getWidth(), elem.getY()); glTexCoord2f(0,1); glVertex2f(elem.getX(), elem.getY()); glEnd(); >
//Этот метод будет вызываться извне public static void update(boolean have_to_decrease) < updateOpenGL(); for(Cell[] line:cells)< for(Cell cell:line)< cell.update(have_to_decrease); >> > ///А этот метод будет использоваться только локально, /// т.к. базовым другие классы должны работать на более высоком уровне private static void updateOpenGL()

Как вы можете видеть, здесь я уже использовал несколько констант. Для них был создан отдельный класс Constants с public static полями. Вот он целиком:

Читайте также:
Программа чтобы не звонили банки

Как научиться программировать с нуля играя в игры. Java, JavaScript, C++, C#, Python, PHP, Ruby


public class Constants < ///Размер игровой ячейки public static final int CELL_SIZE = 32; ///Размеры игрового поля в ячейках public static final int CELLS_COUNT_X = 20; public static final int CELLS_COUNT_Y = 20; ///Шанс появления ягод на старте в процентах. ///При выставленном значении спавнится 3-5 ягод. ///Не беспокойтесь, что значение слишком низкое, как минимум одна ягода создаётся отдельно. public static final int INITIAL_SPAWN_CHANCE = 1;//% ///В нашем случае змея проходит одну клетку за один фрейм. ///Значение 5 мне показалось оптимальным, но вы можете экспериментировать. public static final int FPS = 5; ///Константы для создания окна, названия достаточно говорящие. public static final int SCREEN_WIDTH =CELLS_COUNT_X*CELL_SIZE; public static final int SCREEN_HEIGHT = CELLS_COUNT_Y*CELL_SIZE; public static final String SCREEN_NAME = «Tproger’s Snake»; >

Enum Sprite , который отвечает за подгрузку текстур, полностью идентичен тому, что мы писали для Сапёра, за исключением того, что нам нужно только две текстуры — для змеи и для ягод. Вот код:

public enum Sprite < ///Файлы с именами circle и cherries должны лежать по адресу /// %папка проекта%/res/ в расширении .png BODY(«circle»), CHERRIES(«cherries»); private Texture texture; private Sprite(String texturename)< try < this.texture = TextureLoader.getTexture(«PNG», new FileInputStream(new File(«res/»+texturename+».png»))); >catch (IOException e) < e.printStackTrace(); >> public Texture getTexture() < return this.texture; >>

Механика игры

Самое время поговорить о том, как наша змея будет, собственно, перемещаться.

Вам наверняка доводилось видеть вывески, вокруг которых по кругу бегают огоньки? Разумеется, сами лампочки в них не перемещаются, просто каждый тик последняя гаснет, а первая зажигается. Таким же образом будет перемещаться и наша змея.

Несложно подсчитать, что каждая лампочка должна гореть столько тиков, какова длина «змеи». Значит, мы должны сообщить клетке, в которую попадает змея, что она должна гореть определённое количество секунд, а каждый тик уменьшать это число у каждой клетки с ненулевым таймером, и менять спрайт, если змея из клетки уже выползла (т.е. таймер стал равен нулю). В случае же необходимости удлинить цепочку, достаточно просто не уменьшать время «горения» клеток на каком-то тике. Именно поэтому метод update() у классов Cell и GUI принимает параметр — если он равен false , значит, змея что-то съела.

Пишем класс клетки

public class Cell < private int x; private int y; private int state;/* 0 ->ячейка пуста >0 -> в ячейке тело змеи, которое будет там ещё N фреймов Что-то необычное: -1: Ягоды */ ///Конструктор просто выставляет начальные значения координат и состояния public Cell (int x, int y, int state) < this.x=x; this.y=y; this.state=state; >///==== Ничем не примечательные геттеры и сеттеры public int getX() < return x; >public int getY() < return y; >public int getHeight() < return CELL_SIZE; >public int getWidth() < return CELL_SIZE; >public int getState() < return this.state; >public void setState(int state) < this.state = state; >///==== ///Метод обновления клетки. Уменьшаем время «горения», если это необходимо public void update(boolean have_to_decrease) < if (have_to_decrease this.state >0) < this.state—; >> ///Ячейка «думает» как она должна выглядеть public Sprite getSprite() < if(this.state >0)< ///Если в ней тело змеи — как змея return Sprite.BODY; >else if(this.state==0)< ///Если в ней нет ничего — никак выглядеть и не должна return null; >else < ///Иначе проходимся свитчем по возможным объектам. ///Так как это демо — я добавил только ягоды switch(this.state)< default: return Sprite.CHERRIES; >> > >

Добавляем геттер и сеттер для состояния клетки поля в GUI

getState(x,y) < return cells[x][y].getState(); >setState(x,y,state)

Добавляем метод, создающий начальное поле в GUI

Просто инициализируем OpenGL, затем массив Cell[][] cells и заполняем последний клетками со случайным полем state .

public static void init() < initializeOpenGL(); cells = new Cell[CELLS_COUNT_X][CELLS_COUNT_Y]; Random rnd = new Random(); for(int i=0; i> >

Главный управляющий класс

class Main < ///Переменная, при обращении которой в true приложение закрывается private static boolean isExitRequested=false; ///Данные о нашей змее.

Читайте также:
Что такое патч для программы и как им пользоваться

Выползать она будет из нижнего левого угла, ///Вправо (направления посчитаны по часовой стрелки от севера, т.е. /// 0 — вверх, 1 — вправо, 2 — вниз, 3 — влево private static int x=-1,y=0, direction=1, length=3; ///Флаг, который обращается в false, если на данном тике змея что-то съела private static boolean have_to_decrease = true; ///Входной класс public static void main(String[] args) < ///Инициализируем графический интерфейс GUI.init(); ///Создаём ягодку в случайном месте generate_new_obj(); ///Пока не получим сигнал на закрытие, в цикле. while(!isExitRequested)< ///Проверяем ввод данных input(); ///Двигаем змею move(); ///Обновляем и рисуем графические элементы GUI.draw(); GUI.update(have_to_decrease); >> private static void move() < /// Если на прошлом тике мы что-то съели, то на этом должны вернуть значение на true have_to_decrease=true; ///Меняем координаты змеи в зависимости от направления switch(direction)< case 0: y++; break; case 1: x++; break; case 2: y—; break; case 3: x—; break; >///Проверяем, не вышла ли змея за границы if(x < 0 || x >= CELLS_COUNT_X || y < 0 || y >= CELLS_COUNT_Y) < //TODO gameover System.exit(1); >///Смотрим состояние ячейки, куда зашла змея int next_cell_state = GUI.getState(x,y); ///Если там змея, то это проигрыш if(next_cell_state>0)< //TODO gameover System.exit(1); >else < ///Если там еда, то if(next_cell_state < 0)< length++; ///Увеличиваем длину на единицу generate_new_obj(); ///Создаём новую еду have_to_decrease=false; ///Выставляем флаг того, что мы съели что-то >///»Зажигаем» клетку GUI.setState(x,y,length); > > /*Алгоритм генерации новой еды следующий. Мы высчитываем количество клеток, которые не заполнены змеёй, по формуле: CELLS_COUNT_X*CELLS_COUNT_Y-length И выбираем случайную такую клетку (сохраняем её номер в point).

Потом проходимся по всем клеткам, и, если в клетке не змея, уменьшаем счётчик. Как только счётчик равен нулю, создаём в этой клетке еду и выходим из цикла. ВНИМАНИЕ! При таком методе ягоды могут создаваться поверх других ягод, т.е. Их общее количество будет уменьшаться со временем.

Чтобы избежать этого можно при уничтожении одной ягоды создавать случайное число (1-3) ягод. */ private static void generate_new_obj() < int point = new Random().nextInt(CELLS_COUNT_X*CELLS_COUNT_Y-length); for(int i=0; ielse < point—; >> > > > private static void input() < ///Перебираем события клавиатуры int newdirection = direction; while(Keyboard.next())< if(Keyboard.getEventKeyState())< switch(Keyboard.getEventKey()) < case Keyboard.KEY_ESCAPE: isExitRequested = true; break; case Keyboard.KEY_UP: if(direction!=2) newdirection=0; break; case Keyboard.KEY_RIGHT: if(direction!=3) newdirection=1; break; case Keyboard.KEY_DOWN: if(direction!=0) newdirection=2; break; case Keyboard.KEY_LEFT: if(direction!=1) newdirection=3; break; >> > direction = newdirection; //Эти рокировки нужны, чтобы правильно работала система условий, //запрещающая поворачивать назад, «в себя» ///Обрабатываем клик по кнопке «закрыть» окна isExitRequested=isExitRequested || Display.isCloseRequested(); > >

P.S. Исходники можно скачать здесь (архив всей папки проекта).

Источник: tproger.ru

Создание игры на 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()

Создадим три функции — 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++; >>

Источник: h.amazingsoftworks.com

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru