на Главную Вход Регистрация Забыли пароль ?

skype: megainformatic, телеграм: megainformatic, онлайн-чат (megainformatic live chat), форма обратной связи

Онлайн Школа Компьютерных Наук Андрея Синицина

Онлайн Школа Компьютерных Наук Андрея Синицина - автор

Добро пожаловать в нашу школу ! Давайте вместе откроем путь к новым перспективам !!!

Создание игры на java и libgdx - урок 2 - анимация спрайта, перемещения в сцене




В предыдущей статье -
Создание первого приложения Hello World на java и компиляция в jar

были рассмотрены основы того, как создать простейшее приложение и скомпилировать его в jar.

Освоив эти шаги можно двигаться дальше - попробовать научиться создавать что-то более сложное.

Лучшей практикой на мой взгляд является создание на языке программирования какой-нибудь не слишком
большой игры.

Кроме того, в разработке нашей игры нам поможет фреймворк libgdx. Он возьмет на себя ряд типовых рутинных
задач, что позволит быстрее создать что-то действительно стоящее и интересное.

Наличие созданной игры, даже такой простой, в вашем портфолио, несомненно повысит интерес к Вам как программисту java.

Давайте начнём.


Я буду рассматривать создание игры на примере своего собственного реального проекта - enterra -

enterra игра

если кликать картинку она будет последовательно меняться в размерах от 640 до 1280 пиксель.
В предыдущем уроке - Создание игры на java и libgdx - урок 1 - введение мы познакомились с тем, как создать основу нашей будущей игры, используя libgdx. Выяснили общие принципы изменения кода и запуска игры. Научились создавать jar файл и запускать его из терминала Windows. Теперь пришло время познакомиться с непосредственными вопросами разработки игры. А именно: как выводить анимацию спрайтов, как осуществить перемещения персонажа по клавишам в сцене и некоторые другие вопросы. Начнём мы с того, что увеличим размеры окна нашей игры. До этого момента размер окна был 642х512 запуск игры Давайте увеличим размеры окна до 1280 х 720, а также добавим еще некоторые настройки. Для этого изменим содержимое файла my_java_game\desktop\src\com\mygdx\game\DesktopLauncher.java package com.mygdx.game; import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application; import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration; import com.mygdx.game.MyJavaGame; // Please note that on macOS your application needs to be started with the -XstartOnFirstThread JVM argument public class DesktopLauncher { public static void main (String[] arg) { Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration(); config.setForegroundFPS(60); config.setTitle("my_java_game build 2"); new Lwjgl3Application(new MyJavaGame(), config); } } На такое - package com.mygdx.game; import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application; import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration; import com.mygdx.game.MyJavaGame; // Please note that on macOS your application needs to be started with the -XstartOnFirstThread JVM argument public class DesktopLauncher { public static void main (String[] arg) { Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration(); //config.setForegroundFPS(60); //config.setTitle("my_java_game build 2"); config.setTitle("enterra game version: 1 build: 3"); config.setWindowedMode(1280, 720); config.useVsync(true); config.setForegroundFPS(60); new Lwjgl3Application(new MyJavaGame(), config); } } Сохраним изменения - Ctrl + S или File > Save All и запустим приложение кликнув по пункту Run, как мы это уже делали в предыдущем уроке. enterra игра
если кликать картинку она будет последовательно меняться в размерах от 640 до 1920 пиксель.
т. е. я закомментировал строки //config.setForegroundFPS(60); //config.setTitle("my_java_game build 2"); и добавил после них - config.setTitle("enterra game version: 1 build: 3"); config.setWindowedMode(1280, 720); config.useVsync(true); config.setForegroundFPS(60); config.setTitle("enterra game version: 1 build: 3"); //задаем нужный заголовок окна приложения config.setWindowedMode(1280, 720); //задаем размеры окна config.useVsync(true); //включаем вертикальную синхронизацию config.setForegroundFPS(60); //и задаем значение fps. После старта вы увидите, что окно теперь выглядит так - enterra игра
если кликать картинку она будет последовательно меняться в размерах от 640 до 1282 пиксель.
Изменим зеленый цвет заполнения на черный. Что будет более типично для игр. в файле my_java_game\core\src\com\mygdx\game\MyJavaGame.java строку ScreenUtils.clear(0.0f, 1.0f, 0.0f, 1.0f); изменим на ScreenUtils.clear(0.0f, 0.0f, 0.0f, 1.0f); сохраним изменения и снова запустим игру. enterra игра
если кликать картинку она будет последовательно меняться в размерах от 640 до 1282 пиксель.
Удобно будет реализовать закрытие окна игры по нажатию клавиши Esc. Но для этого вам нужно изменить код my_java_game\core\src\com\mygdx\game\MyJavaGame.java сейчас ваш код выглядит так - package com.mygdx.game; import com.badlogic.gdx.ApplicationAdapter; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.utils.ScreenUtils; public class MyJavaGame extends ApplicationAdapter { SpriteBatch batch; Texture img; @Override public void create () { batch = new SpriteBatch(); img = new Texture("assets/floor3.jpg"); } @Override public void render () { ScreenUtils.clear(0.0f, 0.0f, 0.0f, 1.0f); batch.begin(); batch.draw(img, 0, 0); batch.end(); } @Override public void dispose () { batch.dispose(); img.dispose(); } } измените его на такой - package com.mygdx.game; import com.badlogic.gdx.ApplicationAdapter; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.utils.ScreenUtils; import com.badlogic.gdx.InputProcessor; public class MyJavaGame extends ApplicationAdapter implements InputProcessor { SpriteBatch batch; Texture img; @Override public void create () { batch = new SpriteBatch(); img = new Texture("assets/floor3.jpg"); } @Override public boolean keyDown (int keycode) { return false; } @Override public boolean keyUp (int keycode) { return false; } @Override public boolean keyTyped (char character) { return false; } @Override public boolean scrolled (float amountX, float amountY) { return false; } public boolean touchDragged (int screenX, int screenY, int pointer) { return false; } @Override public boolean touchUp (int screenX, int screenY, int pointer, int button) { return false; } public boolean touchDown (int screenX, int screenY, int pointer, int button) { return false; } public boolean mouseMoved (int screenX, int screenY) { return false; } @Override public void render () { ScreenUtils.clear(0.0f, 0.0f, 0.0f, 1.0f); batch.begin(); batch.draw(img, 0, 0); batch.end(); if(Gdx.input.isKeyPressed(Input.Keys.ESCAPE)) Gdx.app.exit(); } @Override public void dispose () { batch.dispose(); img.dispose(); } } Сохраните изменения и запустите игру. Теперь при нажатии клавиши [Esc], игра будет закрыта, как если бы мы нажали крестик в правом верхнем углу окна игры. Строка которая добавляет обработчик выхода по [Esc], как вы уже догадались наверное, выглядит так - if(Gdx.input.isKeyPressed(Input.Keys.ESCAPE)) Gdx.app.exit(); т. е. проверяется нажатие ESCAPE и если он был нажат - вызывается метод закрытия приложения - Gdx.app.exit(); Весь остальной код, который мы добавили представляет обработчики для нажатия и удержания клавиш, а также отслеживания действий мышкой. Пока он нам не нужен, но потребуется чуть позже, когда мы начнём рассмотрение вопроса: как перемещать персонажа в игре по клавишам стрелок или wasd. Давайте сначала сделаем анимированного персонажа. Для этого используем такую картинку - картинка для анимации персонажа Либо вы можете использовать что-то другое, но количество кадров должно быть таким же. Если оно у вас будет другим, то в коде, где будет задано их количество нужно будет изменить значения на соответствующее вашему варианту анимации. Чтобы вывести предложенный спрайт и сделать его анимированным добавим в файл my_java_game\core\src\com\mygdx\game\MyJavaGame.java такой код после строки Texture img; добавим - public Animation inkyWalkRightAnimation; Texture inkyWalkRightTextureAnim; private static final int INKY_WALK_FRAME_COLS = 8, INKY_WALK_FRAME_ROWS = 6; метод create изменится так - public void create () { batch = new SpriteBatch(); img = new Texture("assets/floor3.jpg"); inkyWalkRightTextureAnim = new Texture(Gdx.files.internal("assets/textures/scenes/scene_1/inky_walk_right.png")); TextureRegion[][] tmp = TextureRegion.split(inkyWalkRightTextureAnim, inkyWalkRightTextureAnim.getWidth() / INKY_WALK_FRAME_COLS, inkyWalkRightTextureAnim.getHeight() / INKY_WALK_FRAME_ROWS); TextureRegion[] inkyWalkRighFrames = new TextureRegion[INKY_WALK_FRAME_COLS * INKY_WALK_FRAME_ROWS]; int index = 0; for (int i = 0; i < INKY_WALK_FRAME_ROWS; i++) { for (int j = 0; j < INKY_WALK_FRAME_COLS; j++) { inkyWalkRighFrames[index++] = tmp[i][j]; } } inkyWalkRightAnimation = new Animation(0.04f, inkyWalkRighFrames); } Картинку inky_walk_right.png вам нужно разместить в папках - my_java_game\assets\assets\textures\scenes\scene_1\ my_java_game\out\artifacts\my_java_game_jar\assets\assets\textures\scenes\scene_1\ вашего проекта. Файл floor3.jpg также перенесите в эти же папки, а строку кода img = new Texture("assets/floor3.jpg"); измените на img = new Texture("assets/textures/scenes/scene_1/floor3.jpg"); Остается добавить код для вывода анимированного спрайта. stateTime += Gdx.graphics.getDeltaTime(); inkyWalkRightCurrentFrame = inkyWalkRightAnimation.getKeyFrame(stateTime, true); и отрисовку batch.draw(inkyWalkRightCurrentFrame, 0, 0); И не забыть вызвать метод dispose в методе public void dispose освобождения ресурсов приложения inkyWalkRightTextureAnim.dispose(); В итоге файл my_java_game\core\src\com\mygdx\game\MyJavaGame.java должен сейчас у вас выглядеть так -
package com.mygdx.game; import com.badlogic.gdx.ApplicationAdapter; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.Animation; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.utils.ScreenUtils; import com.badlogic.gdx.InputProcessor; public class MyJavaGame extends ApplicationAdapter implements InputProcessor { SpriteBatch batch; Texture img; public Animation inkyWalkRightAnimation; Texture inkyWalkRightTextureAnim; private static final int INKY_WALK_FRAME_COLS = 8, INKY_WALK_FRAME_ROWS = 6; private float stateTime; @Override public void create () { batch = new SpriteBatch(); img = new Texture("assets/textures/scenes/scene_1/floor3.jpg"); inkyWalkRightTextureAnim = new Texture(Gdx.files.internal("assets/textures/scenes/scene_1/inky_walk_right.png")); TextureRegion[][] tmp = TextureRegion.split(inkyWalkRightTextureAnim, inkyWalkRightTextureAnim.getWidth() / INKY_WALK_FRAME_COLS, inkyWalkRightTextureAnim.getHeight() / INKY_WALK_FRAME_ROWS); TextureRegion[] inkyWalkRighFrames = new TextureRegion[INKY_WALK_FRAME_COLS * INKY_WALK_FRAME_ROWS]; int index = 0; for (int i = 0; i < INKY_WALK_FRAME_ROWS; i++) { for (int j = 0; j < INKY_WALK_FRAME_COLS; j++) { inkyWalkRighFrames[index++] = tmp[i][j]; } } inkyWalkRightAnimation = new Animation(0.04f, inkyWalkRighFrames); stateTime = 0.0f; } @Override public boolean keyDown (int keycode) { return false; } @Override public boolean keyUp (int keycode) { return false; } @Override public boolean keyTyped (char character) { return false; } @Override public boolean scrolled (float amountX, float amountY) { return false; } public boolean touchDragged (int screenX, int screenY, int pointer) { return false; } @Override public boolean touchUp (int screenX, int screenY, int pointer, int button) { return false; } public boolean touchDown (int screenX, int screenY, int pointer, int button) { return false; } public boolean mouseMoved (int screenX, int screenY) { return false; } TextureRegion inkyWalkRightCurrentFrame; @Override public void render () { ScreenUtils.clear(0.0f, 0.0f, 0.0f, 1.0f); stateTime += Gdx.graphics.getDeltaTime(); inkyWalkRightCurrentFrame = inkyWalkRightAnimation.getKeyFrame(stateTime, true); batch.begin(); batch.draw(img, 0, 0); batch.draw(inkyWalkRightCurrentFrame, 0, 0); batch.end(); if(Gdx.input.isKeyPressed(Input.Keys.ESCAPE)) Gdx.app.exit(); } @Override public void dispose () { batch.dispose(); img.dispose(); inkyWalkRightTextureAnim.dispose(); } }
Сохраним изменения в проект, запустим его как это уже делали раньше. В окне приложения будет такой вид - enterra игра - запуск игры
если кликать картинку она будет последовательно меняться в размерах от 640 до 1282 пиксель.
Персонаж в левом нижнем углу будет выводиться анимированным. Как это выглядит показано в нижеследующем видео - Поясним код, который выполняет анимацию. public Animation inkyWalkRightAnimation; //сначала добавляем переменную для хранения области на текстуре, она будет хранить кадры анимации спрайта Texture inkyWalkRightTextureAnim; //в этой переменной будет создан объект с текстурой спрайт private static final int INKY_WALK_FRAME_COLS = 8, INKY_WALK_FRAME_ROWS = 6; //эти параметры задают количество кадров спрайта в длину 8 и //в высоту - 6 private float stateTime; //данная переменная будет накапливать значения отсчетов времени, чтобы передавать их в объект анимации спрайта //и чтобы анимация получалась плавной и без рывков. inkyWalkRightTextureAnim = new Texture(Gdx.files.internal("assets/textures/scenes/scene_1/inky_walk_right.png")); //загружаем текстуру спрайта анимации из //указанного файла //задаем текстурные области разрезая методом split на отдельные кадры TextureRegion[][] tmp = TextureRegion.split(inkyWalkRightTextureAnim, inkyWalkRightTextureAnim.getWidth() / INKY_WALK_FRAME_COLS, inkyWalkRightTextureAnim.getHeight() / INKY_WALK_FRAME_ROWS); //создаем массив из нарезанных кадров анимации TextureRegion[] inkyWalkRighFrames = new TextureRegion[INKY_WALK_FRAME_COLS * INKY_WALK_FRAME_ROWS]; //копируем их из временного массива tmp, в массив inkyWalkRighFrames int index = 0; for (int i = 0; i < INKY_WALK_FRAME_ROWS; i++) { for (int j = 0; j < INKY_WALK_FRAME_COLS; j++) { inkyWalkRighFrames[index++] = tmp[i][j]; } } inkyWalkRightAnimation = new Animation(0.04f, inkyWalkRighFrames); //задаем скорость анимации 0.04f и все кадры анимации в данном //объекте stateTime = 0.0f; //сбрасываем начальное значение таймера в 0 анимация будет работать следующим образом: stateTime += Gdx.graphics.getDeltaTime(); //сохраняем текущее значение отсчета таймера в переменной stateTime - значение накапливается inkyWalkRightCurrentFrame = inkyWalkRightAnimation.getKeyFrame(stateTime, true); //обновляем кадр анимации в соответствии с накопленным //значением таймера batch.begin(); batch.draw(img, 0, 0); batch.draw(inkyWalkRightCurrentFrame, 0, 0); //выводим текущий кадр анимированного спрайта batch.end(); Собственно вот так и выполняется любая анимация подобного вида. Т. е. спрайтовая, использующая текстуру в виде спрайт-листа. Если вы используете в своем проекте спрайт-лист с другим числом кадров по длине и высоте, то значения констант private static final int INKY_WALK_FRAME_COLS = 8, INKY_WALK_FRAME_ROWS = 6; нужно изменить на нужные вам. Весь остальной код (кроме разумеется, названия файла с анимированным спрайтом - там вы укажете своё имя файла), будет абсолютно таким же. Ну и если вы захотите ускорить или замедлить скорость анимации - меняйте параметр в строке кода inkyWalkRightAnimation = new Animation(0.04f, inkyWalkRighFrames); т. е. вместо значения 0.04f подставьте такое, какое нужно Вам, или поэкспериментируйте, чтобы увидеть как значения влияют на скорость анимации. Так, например для показанного примера значение 0.5f приведет к очень замедленному воспроизведению кадров анимации - как будто в замедленной съемке. И в то же время значение 0.005f будет отображать очень и очень быструю анимацию. Таким образом увеличивая межкадровый интервал Вы можете замедлять анимацию и наоборот - уменьшая - ускорять. Значения более 1.0f приведут к очень медленной скорости анимации. Но конечно бывают случаи, когда и такая анимация нужна. Все зависит от целей, для которых Вы её делаете. Также не стоит забывать, что текстура со спрайт-листом должна быть обязательно квадратной или прямоугольной, но с одинаковым размером каждого кадра. Если кадры будут нарисованы в текстуре спрайт-листа со смещением или не удовлетворяя указанным условиям, то анимация в вашей игре будет отображаться некорректно. Так что прежде чем перейти к созданию каких-то сложных и многокадровых анимаций, рекомендую сначала потренироваться на более простых, содержащих малое число кадров, например 2х2. Чтобы было понятнее о чем речь идет если анимация некорректная покажу пример. Для этого используйте вот эту картинку в качестве спрайт листа - тестовый спрайт-лист с примером некорректной анимации Поместите данный файл в папки my_java_game\assets\assets\textures\scenes\scene_1\ my_java_game\out\artifacts\my_java_game_jar\assets\assets\textures\scenes\scene_1\ Вашего проекта, а код немного изменим. //private static final int INKY_WALK_FRAME_COLS = 8, INKY_WALK_FRAME_ROWS = 6; private static final int INKY_WALK_FRAME_COLS = 2, INKY_WALK_FRAME_ROWS = 2; //inkyWalkRightTextureAnim = new Texture(Gdx.files.internal("assets/textures/scenes/scene_1/inky_walk_right.png")); inkyWalkRightTextureAnim = new Texture(Gdx.files.internal("assets/textures/scenes/scene_1/inky_walk_anim_test_1.png")); Сохранив изменения и запустив приложение увидим следующее - Скорость анимации я задал так - inkyWalkRightAnimation = new Animation(0.1f, inkyWalkRighFrames); Т. е. персонаж как бы "прыгает" вверх-вниз, чего при нормальном соответствии описанным условиям для спрайт-листа быть не должно. Теперь замените картинку спрайта на другую - тестовый спрайт-лист с примером некорректной анимации Также поместите её в те же папки, что и предыдущую, а строку кода inkyWalkRightTextureAnim = new Texture(Gdx.files.internal("assets/textures/scenes/scene_1/inky_walk_anim_test_1.png")); измените на inkyWalkRightTextureAnim = new Texture(Gdx.files.internal("assets/textures/scenes/scene_1/inky_walk_anim_test_2.png")); Анимация, как видите стала более качественной. Без ненужных движений вверх-вниз. Если кадры анимации заданы в спрайт-листе неправильно, то анимации будут отображаться с большими сдвигами или совершенно не так, как задумано. Например если задать количество кадров не 2х2, а 3х4, то будет такой вид анимации - Вот это как раз и есть тот вариант, когда анимация нарисована или задана в коде неправильно. Имейте это в виду, когда будете создавать свои анимации. Далее мы рассмотрим как управлять перемещением персонажа в сцене по клавишам стрелок или wasd. Перемещение персонажа может быть двух видов: - это когда персонаж остается на месте, а фон за ним и все объекты перемещаются - это называется скроллом - прокруткой сцены; - сцена и объекты неподвижны, а меняются координаты лишь для персонажа; Для лучшего понимания рассмотрим оба эти варианта и начнём с 1. Для этого объявим переменную Vector2 sceneScrollPos; в методе create инициализируем её - sceneScrollPos = new Vector2(0, 0); добавим метод с таким кодом MoveHero private void MoveHero() { if ( heroMoveLeft ) { sceneScrollPos.x = sceneScrollPos.x + elapsedTime * MoveSpeed; } if ( heroMoveRight ) { sceneScrollPos.x = sceneScrollPos.x - elapsedTime * MoveSpeed; } if ( heroMoveUp ) { sceneScrollPos.y = sceneScrollPos.y - elapsedTime * MoveSpeed; } if ( heroMoveDown ) { sceneScrollPos.y = sceneScrollPos.y + elapsedTime * MoveSpeed; } } Также вам будет нужно объявить переменные private boolean heroMoveLeft; private boolean heroMoveRight; private boolean heroMoveUp; private boolean heroMoveDown; и private float elapsedTime; private float MoveSpeed; И также инициализировать их в методе create: heroMoveLeft = false; heroMoveRight = false; heroMoveUp = false; heroMoveDown = false; elapsedTime = 0.0f; MoveSpeed = 225.5f; в методе render добавить такую строку кода - elapsedTime = Gdx.graphics.getDeltaTime(); вызов метода MoveHero(); также добавить в метод render метод keyDown обновить так - @Override public boolean keyDown (int keycode) { if ( keycode == Keys.A || keycode == Keys.LEFT || keycode == Keys.NUMPAD_4 ) { heroMoveLeft = true; } if ( keycode == Keys.D || keycode == Keys.RIGHT || keycode == Keys.NUMPAD_6 ) { heroMoveRight = true; } if ( keycode == Keys.W || keycode == Keys.UP || keycode == Keys.NUMPAD_8 ) { heroMoveUp = true; } if ( keycode == Keys.S || keycode == Keys.DOWN || keycode == Keys.NUMPAD_2 ) { heroMoveDown = true; } return false; } а метод keyUp так - @Override public boolean keyUp (int keycode) { if ( keycode == Keys.A || keycode == Keys.LEFT || keycode == Keys.NUMPAD_4 ) { heroMoveLeft = false; } if ( keycode == Keys.D || keycode == Keys.RIGHT || keycode == Keys.NUMPAD_6 ) { heroMoveRight = false; } if ( keycode == Keys.W || keycode == Keys.UP || keycode == Keys.NUMPAD_8 ) { heroMoveUp = false; } if ( keycode == Keys.S || keycode == Keys.DOWN || keycode == Keys.NUMPAD_2 ) { heroMoveDown = false; } return false; } в методе render строку batch.draw(img, 0, 0); заменить на batch.draw(img, sceneScrollPos.x, sceneScrollPos.y); В итоге код файла my_java_game\core\src\com\mygdx\game\MyJavaGame.java у вас сейчас должен выглядеть так -
package com.mygdx.game; import com.badlogic.gdx.ApplicationAdapter; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.Animation; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.utils.ScreenUtils; import com.badlogic.gdx.InputProcessor; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.Input.Keys; public class MyJavaGame extends ApplicationAdapter implements InputProcessor { SpriteBatch batch; Texture img; public Animation inkyWalkRightAnimation; Texture inkyWalkRightTextureAnim; private static final int INKY_WALK_FRAME_COLS = 8, INKY_WALK_FRAME_ROWS = 6; private float stateTime; Vector2 sceneScrollPos; private boolean heroMoveLeft; private boolean heroMoveRight; private boolean heroMoveUp; private boolean heroMoveDown; private float elapsedTime; private float MoveSpeed; BitmapFont font; @Override public void create () { batch = new SpriteBatch(); img = new Texture("assets/textures/scenes/scene_1/floor3.jpg"); inkyWalkRightTextureAnim = new Texture(Gdx.files.internal("assets/textures/scenes/scene_1/inky_walk_right.png")); TextureRegion[][] tmp = TextureRegion.split(inkyWalkRightTextureAnim, inkyWalkRightTextureAnim.getWidth() / INKY_WALK_FRAME_COLS, inkyWalkRightTextureAnim.getHeight() / INKY_WALK_FRAME_ROWS); TextureRegion[] inkyWalkRighFrames = new TextureRegion[INKY_WALK_FRAME_COLS * INKY_WALK_FRAME_ROWS]; int index = 0; for (int i = 0; i < INKY_WALK_FRAME_ROWS; i++) { for (int j = 0; j < INKY_WALK_FRAME_COLS; j++) { inkyWalkRighFrames[index++] = tmp[i][j]; } } inkyWalkRightAnimation = new Animation(0.03f, inkyWalkRighFrames); stateTime = 0.0f; sceneScrollPos = new Vector2(0, 0); heroMoveLeft = false; heroMoveRight = false; heroMoveUp = false; heroMoveDown = false; elapsedTime = 0.0f; MoveSpeed = 225.5f; font = new BitmapFont(); font.setColor(0.9f, 0.9f, 0.7f, 1.0f); Gdx.input.setInputProcessor(this); } private void MoveHero() { if ( heroMoveLeft ) { sceneScrollPos.x = sceneScrollPos.x + elapsedTime * MoveSpeed; } if ( heroMoveRight ) { sceneScrollPos.x = sceneScrollPos.x - elapsedTime * MoveSpeed; } if ( heroMoveUp ) { sceneScrollPos.y = sceneScrollPos.y - elapsedTime * MoveSpeed; } if ( heroMoveDown ) { sceneScrollPos.y = sceneScrollPos.y + elapsedTime * MoveSpeed; } } @Override public boolean keyDown (int keycode) { if ( keycode == Keys.A || keycode == Keys.LEFT || keycode == Keys.NUMPAD_4 ) { heroMoveLeft = true; } if ( keycode == Keys.D || keycode == Keys.RIGHT || keycode == Keys.NUMPAD_6 ) { heroMoveRight = true; } if ( keycode == Keys.W || keycode == Keys.UP || keycode == Keys.NUMPAD_8 ) { heroMoveUp = true; } if ( keycode == Keys.S || keycode == Keys.DOWN || keycode == Keys.NUMPAD_2 ) { heroMoveDown = true; } return false; } @Override public boolean keyUp (int keycode) { if ( keycode == Keys.A || keycode == Keys.LEFT || keycode == Keys.NUMPAD_4 ) { heroMoveLeft = false; } if ( keycode == Keys.D || keycode == Keys.RIGHT || keycode == Keys.NUMPAD_6 ) { heroMoveRight = false; } if ( keycode == Keys.W || keycode == Keys.UP || keycode == Keys.NUMPAD_8 ) { heroMoveUp = false; } if ( keycode == Keys.S || keycode == Keys.DOWN || keycode == Keys.NUMPAD_2 ) { heroMoveDown = false; } return false; } @Override public boolean keyTyped (char character) { return false; } @Override public boolean scrolled (float amountX, float amountY) { return false; } public boolean touchDragged (int screenX, int screenY, int pointer) { return false; } @Override public boolean touchUp (int screenX, int screenY, int pointer, int button) { return false; } public boolean touchDown (int screenX, int screenY, int pointer, int button) { return false; } public boolean mouseMoved (int screenX, int screenY) { return false; } TextureRegion inkyWalkRightCurrentFrame; @Override public void render () { ScreenUtils.clear(0.0f, 0.0f, 0.0f, 1.0f); stateTime += Gdx.graphics.getDeltaTime(); elapsedTime = Gdx.graphics.getDeltaTime(); inkyWalkRightCurrentFrame = inkyWalkRightAnimation.getKeyFrame(stateTime, true); MoveHero(); batch.begin(); batch.draw(img, sceneScrollPos.x, sceneScrollPos.y); batch.draw(inkyWalkRightCurrentFrame, 0, 0); font.draw(batch, " hx: " + sceneScrollPos.x + " hy: "+(int)Math.floor(sceneScrollPos.y), 10, 15); batch.end(); if(Gdx.input.isKeyPressed(Input.Keys.ESCAPE)) Gdx.app.exit(); } @Override public void dispose () { batch.dispose(); img.dispose(); inkyWalkRightTextureAnim.dispose(); font.dispose(); } }
Сохраним изменения, запустим игру. По клавишам wasd, стрелкам или стрелкам на цифровой клавиатуре сцена представленная объектом img должна скроллится - т. е. данный объект будет перемещаться как будто персонаж перемещается по сцене. В коде вы обнаружите элементы, о которых я ничего не говорил. Это объект font, строка вызова Gdx.input.setInputProcessor(this); в методе create, а также вывод в окне игры в левом нижнем углу неких цифр - координат прокрутки сцены. вызов Gdx.input.setInputProcessor(this); нужен, чтобы ввод клавиш с клавиатуры начал работать. Без него нажатия клавиш ни к чему не будут приводить. А объект font, как раз и используется для вывода текста с координатами переменной sceneScrollPos причём координата sceneScrollPos.x выводится без округления до целого, а sceneScrollPos.y с округлением. Ваша игра на текущий момент должна работать так - т. е. нажимая клавиши wasd или стрелки на основной или цифровой клавиатуре мы заставим элемент пола в левом нижнем углу перемещаться по экрану. А персонаж при этом остается на месте. Я также показал на данном видео и 2 способ перемещений - когда сцена не движется, а движется персонаж. Единственное при этом направления действия клавиш будут противоположными, т. е. нажимая a или стрелку влево вы получите движение персонажа вправо. Чтобы он двигался правильно вам нужно будет поменять знак с + на - и наоброт в выражениях метода keyDown. Также обратите внимание, что движение работает пока клавиша нажата. Стоит вам отпустить клавишу - движение прекращается. Именно это и выполняется в методе keyUp который как только мы отпустили соответствующую клавишу выставляет переменную движения в указанном направлении в false. Если с этими вопросами вам все ясно, то можно двигаться дальше. В следующем уроке мы займёмся созданием для сцены механизма генерации плиток фона, т. е. будем выводить фон для пола сцены программным путём. далее - Создание игры на java и libgdx - урок 3 - генерация пола для сцены, взятие бонусов
оцените статью:
0
Понравилось!
0
Не понравилось!
 

Оставленные комментарии


megainformatic 2006 - 2024 карта сайта




Посетили страницу: 38