Как сделать вражеский счетчик в libgdx?

В моей игре сверху вниз у меня есть детектор врага, чтобы обнаружить, что противник близок. Моя проблема заключается в том, как я могу создать анимационную панель счетчика с переходом? Я к новому в эту структуру. «Спасибо» и «Advance»

Когда игрок обнаруживает врага рядом, панель индикатора будет анимировать так же, как и снимок экрана снизу

Когда враг находится рядом с игроком

Без врага

Без врага Введите описание изображения здесь

Мой код:

//detector meter_bar = new Texture("meter_bar.png"); myTextureRegion = new TextureRegion(meter_bar); myTexRegionDrawable = new TextureRegionDrawable(myTextureRegion); actormeter_bar = new Image(myTexRegionDrawable); actormeter_bar.setPosition(200,1005); stage.addActor(actormeter_bar); meter = new Texture("meter.png"); myTextureRegion = new TextureRegion(meter); myTexRegionDrawable = new TextureRegionDrawable(myTextureRegion); actormetter = new Image(myTexRegionDrawable); actormetter.setPosition(190,990); stage.addActor( actormetter); 

Движение игрока (вперед):

 //right_control right_paw = new Texture(Gdx.files.internal("right_paw.png")); myTextureRegion = new TextureRegion(right_paw); myTexRegionDrawable = new TextureRegionDrawable(myTextureRegion); moveForward = new ImageButton(myTexRegionDrawable); //Set the button up moveForward.getStyle().imageUp = new TextureRegionDrawable(new TextureRegion(new Texture(Gdx.files.internal("right_paw.png")))); //the hover moveForward.getStyle().imageDown = new TextureRegionDrawable(new TextureRegion(new Texture(Gdx.files.internal("right_paw-hover.png")))); moveForward.setPosition(520,110); stage.addActor(moveForward); //Add the button to the stage to perform rendering and take input. Gdx.input.setInputProcessor(stage); moveForward.addListener(new InputListener(){ @Override public void touchUp (InputEvent event, float x, float y, int pointer, int button) { System.out.println("Right Button Pressed"); progressKnobX = progressKnobX + 4; actorprogressknob.setX(progressKnobX); // x-position to move to if(progressKnobX > 418 ) progressKnobX= 418 ; music.play(); motionState=MotionState.NONE; } @Override public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { motionState=MotionState.UP; return true; } }); stage.addActor(moveForward); 

Движение EnemySprite:

  zombie = new Texture(Gdx.files.internal("enemy/ZombieSprite.png")); zombiesprite = new Sprite(zombie); zombieenemy = new Rectangle(); zombieenemy.setWidth(zombiesprite.getWidth()); zombieenemy = zombiesprite.getBoundingRectangle(); zombieenemy.x = zombieX; zombieenemy.y = zombieY; TextureRegion[][] zom = TextureRegion.split(zombie, zombie.getWidth() / Zombie_FRAME_COLS, zombie.getHeight() / Zombie_FRAME_ROWS); TextureRegion[] zwalkFrames = new TextureRegion[Zombie_FRAME_COLS * Zombie_FRAME_ROWS]; index = 0; for (int i = 0; i < Zombie_FRAME_ROWS; i++) { for (int j = 0; j < Zombie_FRAME_COLS; j++) { zwalkFrames[index++] = zom[i][j]; } } zombiewalkAnimation = new Animation<TextureRegion>(0.120f, zwalkFrames); 

Кнопка MoveForward:

 //button functions MotionState motionState=MotionState.NONE; enum MotionState { NONE { @Override public boolean update(Rectangle player) { return true; } }, UP { @Override public boolean update(Rectangle player) { player.y += 300 * Gdx.graphics.getDeltaTime(); return false; } }, DOWN{ @Override public boolean update(Rectangle player) { player.y -= 300 * Gdx.graphics.getDeltaTime(); return false; } }, LEFT{ @Override public boolean update(Rectangle player) { player.x -= 100 * Gdx.graphics.getDeltaTime(); return false; } }, RIGHT{ @Override public boolean update(Rectangle player) { player.x += 100 * Gdx.graphics.getDeltaTime(); return false; } }; public abstract boolean update(Rectangle player); } 

оказывать

  if(Gdx.input.isKeyPressed(Input.Keys.DOWN)) motionState = MotionState.DOWN; if(Gdx.input.isKeyPressed(Input.Keys.UP)) motionState=MotionState.UP; if(Gdx.input.isKeyPressed(Input.Keys.LEFT)) motionState=MotionState.LEFT; if(Gdx.input.isKeyPressed(Input.Keys.RIGHT)) motionState=MotionState.RIGHT; if(motionState.update(player)) motionState=MotionState.NONE; if(player.y> 1910){ zombieenemy.y -= 60 * Gdx.graphics.getDeltaTime(); } 

Прежде чем я отвечу на ваш первоначальный вопрос, я хотел бы предложить вам научиться использовать расширение Libgdx Ashley, потому что, как все выглядит так, очень грязно, и вам будет сложно поддерживать его.

Мой ответ:

Держите ArrayList <> или аналогичную модель данных со всеми игровыми врагами внутри, затем мы будем проходить через каждую из них и получать ее позицию и вычислять расстояние до игрока.

 Enemy closestEnemy = null; float closestEnemyDist = -1; for(Enemy enemy : ListOfEnemies){ /* here we find the distance to the player */ float distToPlayer = Math.sqrt((enemy.y-player.x)^2 + (enemy.y-player.y)^2); /* initiate closestEnemyDist for the first time */ if(closestEnemyDist == -1){ closestEnemyDist = distToPlayer; } /* we find the closest distance to the player */ float minDist = Math.min(closestEnemyDist, distToPlayer); /* we make sure it is the closest and save the closest enemy as well */ if(minDist <= closestEnemyDist){ closestEnemyDist = minDist; closestEnemy = enemy; } } 

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

Измеритель расстояния:

Здесь мы собираемся сделать небольшую математику, скажем, ваш метр показывает проценты … от 0% до 100%, вы должны выбрать максимальное расстояние, которое ваш метр считает 0% (что означает, что противник очень далеко называет его maxDistance), для вас Легко понять это, представьте, что расстояние 100 и посмотреть на этот метод.

 public int calcMeter(float closestEnemyDist, float maxDistance) { int meter = 0; /* calculate only if enemy is in range */ if(closestEnemyDist < maxDistance){ /* using rounding and multiply by 100f because we wanted * values from 0 - 100, you can can modify this to work just * with float from 0 - 1f */ meter = Math.round( /* * here we flip the percentage so if the enemy is very * close then your meter will be higher */ (1f - (closestEnemyDist / maxDistance)) * 100f ); } return meter; } 

Надеюсь, это поможет вам, удачи 🙂

Я использую класс Stack для создания класса Meter. Изображение измерителя должно быть прозрачным, а изображение в баре должно быть анимацией. Stack Actor может перекрывать изображения и визуализировать их друг над другом. Вот класс Meter:

 public class Meter extends Stack { private Animation<Drawable> animation; private Image bar; public Meter( Skin skin ){ Array<Drawable> drawables = new Array<Drawable>(); for ( int i = 0; i < TestScreen.LENGTH; ++i ){ drawables.add( skin.getDrawable( TestScreen.BAR + Integer.toString( i ) ) ); } animation = new Animation<Drawable>( 1f, drawables ); bar = new Image( animation.getKeyFrame( 0f ) ); addActor( bar ); addActor( new Image( skin.getDrawable( TestScreen.METER ) ) ); setTouchable( Touchable.disabled ); } /** * Set the "hotness" of the meter. * @param value float between 0 and 1 */ public void setValue( float value ){ // actions are the default way to animate simple effects to the actors // this is just to add a pop in effect when you have a really smooth animation this isn't really necessary bar.addAction( Actions.sequence( Actions.alpha( 0 ), Actions.fadeIn( 0.01f, Interpolation.smooth ) ) ); // set the new image to the value percentage bar.setDrawable( animation.getKeyFrame( value * animation.getAnimationDuration() ) ); bar.setSize( bar.getPrefWidth(), bar.getPrefHeight() ); } } 

Класс Stage, который использует скин для установки актеров.

 public class MyStage extends Stage { public Meter meter; public MyStage( Skin skin ){ super(); meter = new Meter( skin ); Table table = new Table( skin ); table.setFillParent( true ); table.setOrigin( Align.top ); table.add( meter ).width( (1/10f) * Gdx.graphics.getWidth() ); addActor( table ); } } 

Лучшей практикой является создание скина и размещение всех ресурсов ui там. Загрузите файл в объект TextureAtlas и передайте этот объект в скин. Я создал простую анимацию, которая не масштабируется правильно, как пример. В объекте экрана или игровом объекте:

 private MyStage myStage; @Override public void show(){ Skin skin = new Skin(); skin.add( METER, new TextureRegionDrawable( new TextureRegion( meter_texture ) ), Drawable.class ); float w = meter_bar_texture.getWidth() / (float) LENGTH; for ( int i = 0; i < LENGTH; ++i ){ TextureRegion region = new TextureRegion( meter_bar_texture, 0, 0, (int)(i * w), meter_bar_texture.getHeight() ); skin.add( BAR + Integer.toString( i ), new TextureRegionDrawable( region ), Drawable.class ); } this.myStage = new MyStage( skin ); } @Override public void hide() { super.hide(); this.meter_bar_texture.dispose(); this.meter_texture.dispose(); } @Override public void update( float delta ) { if ( dangerIncreased() && value < 100 ){ danger += 5; this.myStage.meter.setValue( danger / 100f ); } else if ( dangerDecreased() && danger > 0 ){ danger -= 5; this.myStage.meter.setValue( danger / 100f ); } this.myStage.act( delta ); } public static final String METER = "meter"; public static final String BAR = "bar"; public static final int LENGTH = 10;