Libgdx 如何将方法仅应用于舞台中演员的某个子类

Libgdx 如何将方法仅应用于舞台中演员的某个子类,libgdx,Libgdx,我的游戏有一个名为敌人的类,它扩展了演员。此外,我还有一个EnemyAffector类,它的方法会影响敌人,大致如下: class EnemyAffector { public void affect(Enemy enemy) { ... } } @Override public void act() { super.act(); for (Enemy enemy: enemyArray) { enemyAffector.affect(enemy);

我的游戏有一个名为
敌人
的类,它扩展了
演员
。此外,我还有一个
EnemyAffector
类,它的方法会影响
敌人
,大致如下:

class EnemyAffector {
    public void affect(Enemy enemy) { ... }
}
@Override
public void act() {
    super.act();
    for (Enemy enemy: enemyArray) {
        enemyAffector.affect(enemy);
    }
...
}
在我的
Stage
中,在
act
方法中,我想迭代所有
敌人
,并对他们应用
EnemyAffector
。显而易见的方法是铸造:

@Override
public void act() {
    super.act();
    for (Actor actor: getActors()) {
        if (actor instanceof Enemy) {
            enemyAffector.affect((Enemy)actor);
        }
    }
...
}
然而,传说中使用
instanceof
。因此,我考虑保留一个额外的
数组
,当敌人被添加到
阶段
时,我将向其中添加
敌人
,也就是说,使用另一个
addActor
方法重载我的
阶段

public void addActor(EnemyProjectile pEnemyProjectile) { // add to Enemy Array }
现在我的
act
方法如下所示:

class EnemyAffector {
    public void affect(Enemy enemy) { ... }
}
@Override
public void act() {
    super.act();
    for (Enemy enemy: enemyArray) {
        enemyAffector.affect(enemy);
    }
...
}
耶!无
实例

但是,此解决方案的问题是,我将始终需要在
敌人
阵列
和标准
参与者
阵列
之间进行同步,因为
敌人
阵列
中的
敌人
可能已从
阶段
中删除


我的问题是,这里有没有一种不同的、更干净的方法

在我看来,生成最少行代码的最简单方法是使用UserObjectActor字段,如:

    Actor actor = new Actor(); //or its children ofc
    actor.setUserObject("enemy");

    //...

    if( actor.getUserObject().equals("enemy") )
    {
        //yup this is enemy
    }
当然,由于OOP的原因,它不是最好的解决方案,在某些情况下可能不是很灵活,但老实说,在这种情况下,处理额外的数组等只会使事情变得复杂

请注意,UserObject是对象类型,因此,如果您想将Java无法自行转换的东西推送到那里,您必须自己转换它


但是,如果您想成为超级ok,这里有另一个更优雅的解决方案:

  • 您正在使用自己的MyActor类覆盖Actor类,并使用一些不起任何作用的customAction()方法。您现在将从该类继承,而不是从Actor继承
  • 在每个子类中,该方法什么也不做,但在您的敌人类中,您正在实现函数性
  • 在一个循环中,您将强制转换到(MyActor)并调用customAction方法

    for (Actor actor: getActors()) {
        ((MyActor)actor).customAction();
    }
    
    customAction方法具有来自EnemyEffector的逻辑


如果您正在继承从Actor继承的类(如Label class),那么这将产生一些问题,如果EnemyEffector逻辑正在使用Actor实例不应该知道的数据,那么这也是一个问题,因为它们是全局的,例如,不应该是冗余的(当然,您也可以将信息作为customAction方法的参数传递)

您可以使用可以添加到参与者的
UserObject

public enum ActorType
{
    PLAYER, ENEMY, ETC;
}

//...

Enemy enemy = new Enemy();

// Or set this in the constructor
enemy.setUserObject(ActorType.ENEMY);

for (Actor actor : actors)
{
    if (actor.getUserObject() == ActorType.ENEMY)
    {
        // Do stuff...
    }
}
或者将两个数组放在一个额外的类中,并添加用于添加/删除的方法:

public class ActorManager
{
    private Array<Actor>    actors  = new Array<>();
    private Array<Enemy>    enemies = new Array<>();

    public void add(Actor actor)
    {
        actors.add(actor);
    }

    public void add(Enemy enemy)
    {
        actors.add(enemy);
        enemies.add(enemy);
    }

    public void remove(Actor actor)
    {
        actors.removeValue(actor, true);
    }

    public void remove(Enemy enemy)
    {
        actors.removeValue(enemy, true);
        enemies.removeValue(enemy, true);
    }

    // To make sure our backing arrays are not modified:

    public Array<Actor> getAll()
    {
        return new Array<>(actors);
    }

    public Array<Actor> getEnemies()
    {
        return new Array<>(enemies);
    }
}
公共类ActorManager
{
私有数组参与者=新数组();
私有数组敌人=新数组();
公共无效添加(参与者)
{
添加(actor);
}
公共无效添加(敌人)
{
添加(敌人);
敌人。添加(敌人);
}
公共无效删除(参与者)
{
actors.removeValue(actor,true);
}
公共空间移除(敌人)
{
移除值(敌人,真实);
敌人。移除值(敌人,真);
}
//为确保我们的备份阵列未被修改:
公共数组getAll()
{
返回新数组(actors);
}
公共数组getfeeds()
{
返回新阵法(敌人);
}
}

我很快在
LibGDX
Actor
Stage
类中遇到了类似的情况。我创建了自己的子类,扩展了
Actor
,将其用作所有Actor的“基本Actor”对象

这样,您可以设置在特定情况下所有参与者都将调用的方法

class MyStage extends Stage
{
    public void addActor(MyActor pEnemyProjectile) { // call onAdd }

    //override other methods as necessary,
      //possibly getActors() to return Actors as MyActors, etc
}

class MyActor extends Actor
{

    public void update(double delta)
    {
        //I find it easiest to have "removal" code happen in the Actor's update method, then I can call onRemove()
        //This could happen by finding death conditions or just checking a "isDead" boolean.
    }

    public void onAdd()
    {
        //can set up a default behavior, or just override on other subclasses
    }

    public void onRemove()
    {
        //call for every Actor that gets removed - can extend and remove Enemies from an Enemy list if desired
    }

    //maybe it would be better to check if the Object can be Affected here?
      //rather than keeping and maintaining a separate list
    public boolean isAffected()
    {
        return false; //return true by Enemies
    }
}

class Enemy extends MyActor
{
    //implement onRemove, onAdd, etc..
}
如果它工作得更好,
MyActor
也可以创建为
接口
,然后您可以轻松地为
Label
或其他继承自
Actor
LibGdx
类创建子类


我个人选择将其作为一个子类,只是因为我可以创建更易于键入和调用的助手方法,例如我的“移动”和“旋转”代码,它不使用
Action
类,而
LibGdx
类随附。

什么时候删除演员?你不能在将他们从舞台演员列表中删除的同时将他们从敌人列表中删除吗?有时候最简单的解决方案是最好的。闭上眼睛,使用实例…代码少,错误少…@vojta s有时这可能是最好的。如果OP最终不想从列表中删除敌人的
实例(有两条生命的敌人,或者电影中的“死亡对话”原因?),或者如果他最终想对其他对象做不同的事情(为“玩家”分开
实例),他就会知道他应该创建一个新的解决方案,“AlliedNPC”等)-一开始就这么做会导致“instanceof”不受欢迎的原因(混乱的代码),但如果经过深思熟虑,它可能是无害的。我认为在这种情况下,
instanceof
是最简单的,因此也是最好的解决方案。我不同意的唯一原因是,我发现他可能需要在将来再次区分不同的
演员,他会在那个时候尝试列出另一个名单,并且使用另一个
实例-
-但如果/直到那个时候到来,他可以等待,所以我也不是真的反对。如果你这样开始,就不要陷入“黑暗面”。很好的解决方案!:)看起来和我的一模一样:)@m.antkowicz我没有注意到你答案的第二部分!如果我踩到了你的脚趾,很抱歉,谢谢你的回答。请查看我对@m.antkowicz答案的评论。第一页