libGDX. Озвучка персонажа.
Анимированный персонаж - это хорошо, но озвученный еще лучше. Добавим к нашему роботу звуки шагов и прыжка.
Во-первых, нам нужны звуки - можно скачать готовые звуки, создать в онлайн генераторе звуков (например, тут), ну или записать самостоятельно. Скачать или сгенерировать звук стопроцентно подходящий под анимацию вряд ли удастся, поэтому при создании звуков не обойтись без звукового редактора - я пользуюсь Audition.
Звук прыжка, например, я сделал из двух сэмплов:

Поскольку озвучивать мы будем анимацию, звук и анимация должны быть согласованы, т.е. звук шага должен быть воспроизведен именно в тот момент когда нога робота касается поверхности земли. Для этого нужно в 3D-редакторе засечь время, когда это происходит и при редактировании звукового файла звук шага поставить на этот момент времени.
Все содержание папки asset с отредактированными звуками, изображениями и моделью забираем здесь. Модель из предыдущей статьи нужно заменить, т.к. была ускорена анимация и звуки подогнаны под новый вариант модели.
Ресурсы подготовлены, можно писать код.
Сначала нужно объявить объекты класса Sound и инициализировать их.
Sound step_sound, jump_sound;
........
@Override
public void create () {
......
step_sound = Gdx.audio.newSound(Gdx.files.internal("sounds/step.mp3"));
jump_sound = Gdx.audio.newSound(Gdx.files.internal("sounds/jump.mp3"));
......
}
Начнем с прыжка. При нажатии пробела или соответствующей кнопки на экране вместе с запуском анимации воспроизводим звук прыжка.
public class TheStage extends Stage{
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
....
if(aName.equals("jump")){
animController.animate("Jump", 1, jumpListener, 1);
if(jump >= 1)jump = 0;
jump_sound.play();
}
....
}
@Override
public boolean keyDown(int keycode) {
....
switch(keycode){
.....
case Keys.SPACE:
animController.animate("Jump", 1, jumpListener, 1);
jump = 0;
jump_sound.play();
break;
}
.....
}
Здесь все просто - анимация прыжка всегда воспроизводится от начала и до конца единожды при нажатии кнопки. Поэтому нам достаточно воспроизвести звук от начала до конца.
Перейдем к озвучке шагов.
public class TheStage extends Stage{
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
screenY = scrY - screenY;
Actor actor = hit(screenX, screenY, true);
if(actor == null){
aName = "null";
return false;
}else{
aName = actor.getName();
String curAnim = "";
if(aName.equals("forward")){
forward = true;
curAnim = CheckAnimationSens();
animController.animate(curAnim, -1, walkListener, 1);
}
if(aName.equals("back")){
back = true;
curAnim = CheckAnimationSens();
animController.animate(curAnim, -1, walkListener, 1);
}
if(aName.equals("right")){
right = true;
curAnim = CheckAnimationSens();
animController.animate(curAnim, -1, walkListener, 1);
}
if(aName.equals("left")){
left = true;
curAnim = CheckAnimationSens();
animController.animate(curAnim, -1, walkListener, 1);
}
if(aName.equals("rotate_left")){
rotateAngle = -1;
}
if(aName.equals("rotate_right")){
rotateAngle = 1;
}
if(aName.equals("jump")){
animController.animate("Jump", 1, jumpListener, 1);
if(jump >= 1)jump = 0;
jump_sound.play();
}
if(curAnim.equals("Walk")||curAnim.equals("Back")||curAnim.equals("Right")||curAnim.equals("Left")){
step_sound.play();
}
return true;
}
}
@Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
.......
if(!forward||!back||!right||!left)step_sound.stop();
return true;
}
}
@Override
public void create () {
......
jumpListener = new AnimationListener(){
@Override
public void onEnd(AnimationDesc animation) {
animController.queue(CheckAnimationSens(), -1, 1, walkListener, 1);
}
@Override
public void onLoop(AnimationDesc animation) {
}
};
walkListener = new AnimationListener(){
@Override
public void onEnd(AnimationDesc animation) {
}
@Override
public void onLoop(AnimationDesc animation) {
if(forward||back||right||left){
step_sound.play();
}
}
};
}
@Override
public void dispose(){
.....
step_sound.dispose();
jump_sound.dispose();
}
@Override
public boolean keyDown(int keycode) {
String curAnim = "";
switch(keycode){
case Keys.UP:
forward = true;
curAnim = CheckAnimationSens();
animController.animate(curAnim, -1, walkListener, 1);
break;
case Keys.DOWN:
back = true;
curAnim = CheckAnimationSens();
animController.animate(curAnim, -1, walkListener, 1);
break;
case Keys.RIGHT:
right = true;
curAnim = CheckAnimationSens();
animController.animate(curAnim, -1, walkListener, 1);
break;
case Keys.LEFT:
left = true;
curAnim = CheckAnimationSens();
animController.animate(curAnim, -1, walkListener, 1);
break;
case Keys.SPACE:
animController.animate("Jump", 1, jumpListener, 1);
jump = 0;
jump_sound.play();
break;
}
if(curAnim.equals("Walk")||curAnim.equals("Back")||curAnim.equals("Right")||curAnim.equals("Left")){
step_sound.play();
}
return true;
}
@Override
public boolean keyUp(int keycode) {
.....
if(!forward||!back||!right||!left)step_sound.stop();
return true;
}
В этом случае, мы при нажатии кнопки проверяем текущую анимацию, если для нее нужен звук шагов, запускаем его воспроизведение. Но звук воспроизведется только один раз, а идти робот может не один цикл анимации. Поэтому нам понадобится слушатель анимации walkListener, в методе onLoop которого будем запускать воспроизведение звука шагов при каждом новом цикле анимации. Теперь во всем коде запуска анимации шагания нужно указать слушателя walkListener вместо null.
Поскольку пользователь в любой момент может отпустить кнопку и прервать анимацию, нужно чтобы звук прерывался тоже в этот же момент. Поэтому в методах touchUp и keyUp добавим строку прерывающую воспроизведение звука, если все флаги движения равны false.
Готово! Прыжок и шаги робота озвучены.

libGDX. Анимация персонажа.
libGDX. Scene2D. Сенсорное управление персонажем.
libGDX. Scene2D.
libGDX. Формы столкновений.
libGDX. Bullet. Динамика твердого тела. Часть 2.
libGDX. Bullet. Динамика твердого тела.
libGDX. Обработка столкновений. Библиотека Bullet. Часть 3.
libGDX. Обработка столкновений. Библиотека Bullet. Часть 2.
libGDX. Обработка столкновений. Библиотека Bullet.
libGDX. Интерактивное взаимодействие с 3D объектами.
libGDX. Отбраковка объектов не попадающих в обзор камеры.
3D модель для libGDX. Пишем код.
3D модель для движка libGDX
Строим модель с помощью ModelBuilder
libGDX. Основы 3D программирования.
Игра Flower. Ловим капли.
TexturePacker.Создаем атлас текстур.
Создаем проект на движке libGDX |