TurrentAnimation in ES

Hi Guys,

I was hoping I could get some input on how to best model a tower defence like turrent and it’s animation in an EntitySystem. I currently have my turrents implemented in an OOP model, but I want to swap to an Entity within an ES.

The turrent animation has to:

  • Turn the gunhouse to aim
  • Pivot the turrents to aim
  • recoil the turrents to fire
    There are 3 levels of spatials in the turrent tree, each attach to the previous: Base, GunHouse, Barrel(s)

I remember reading on this forum that all components should be immutable. How do you solve this for animations? My current TurrentComponent will illustrate my current thinking, that involves holding references to the spatials:
[java]
public class TurrentComponent {

public enum TurrentAnimationType{ Single( 1 ), Dual( 2 ), Quad( 4 );
    private final int barrelCount;
    TurrentAnimationType( int barrelCount ){
        this.barrelCount = barrelCount;
    }
    public int getBarrelCount() {
        return barrelCount;
    }
}

public Spatial barrels[];
public Spatial gunHouse;

public float cooldowns[];
public float timers[];

public TurrentAnimationType type;

}
[/java]

This Component would be used by a TurrentAnimationSystem ( handling aiming, recoiling ). Should I implement it inside a more general animation system? Also, I imagine cooldowns might be moved to an AttackComponent, that also holds cooldown and base damage, looking a bit like this:
[java]
public class AttackComponent {
public float cooldown;
public float baseDamage;
}
[/java]
Is there a better way to model my Turrents? Should I reference Spatial by name? Will searching for spatial every iteration not slow it down?

Any input is much appreciated!

Components should not have spatials in them. That is a sign that you are mixing game data with the visualization which is bad.

Also, the turret is not a component, it is an entity. Animation type might be a component… it just depends on how your systems are written.

You do not need to keep a reference to the spatial by name because the spatial will be related to the entity in some way. You may need to keep track of which spatials belong to which entities, etc., but again this would be system dependent.

1 Like
<cite>@pspeed said:</cite> Components should not have spatials in them. That is a sign that you are mixing game data with the visualization which is bad.

This is the main thing I wanted an answer to. But I am having trouble thinking up a structured way to store spatials outside components, that will be fast to retrieve. I have a HashMap&lt; Entity, Spatial &gt; for the root node of all entities. I could do a .findByName( … ) from that root, but I really do not like “searching” for the sub-spatials, I fear it will be a slow approach.

<cite>@pspeed said:</cite> Also, the turret is not a component, it is an entity. Animation type _might_ be a component… it just depends on how your systems are written.
I do model turrents as Entities, not components. I guess instead of "TurrentComponent" i should have called it "TurrentAnimationComponent", still I would prefer a more general "AnimationComponent". But it really boils down to finding a fast way to retrieve spatials outside the components.

If you have a hashmap of entities to spatials then why would you look them up by name?

I feel like I’m missing a lot of information. Your animation system should already know how to find the spatials because that’s one of its jobs. The entities exist outside of the visualization. It’s like MVC (model view controller) The Scene graph is the view and the entities are the model.

You wouldn’t store a JLabel in a database and you don’t put Spatials in components.

<cite>@pspeed said:</cite> If you have a hashmap of entities to spatials then why would you look them up by name?

Well, the hashmap only contains the root node. In the case of the turrent, it has a tree that from buttom-up looks like turrentRootNode > gunHouseNode > barrel(s), so the two upper levels does not appear in the hashmap, only the turrentRootNode does.

And sorry I am not providing more information, I am in the planning stage of this module, I have not written my AnimationSystem yet. The animation is currently ( in my OOP approach ) handled inside a Turrent class, that has Spatials, timings, damage and health. I am splitting it into components.

From your input I lean towards a HashMap containing a TreeMap with the spatials, sort of like HashMap< Entity, RigidAnimationTree >, where RigidAnimationTree is a TreeMap containing the spatials in each entity with rigid animations. An rought structure of the animation system would be sort of like this:
[java]
public class RigidAnimationSystem {
HashMap< Entity, RigidAnimationTree > animationSpatials;

public static class RigidAnimationTree extends TreeMap< ?, Spatial > {

}

private void updateEntity( Entity e ){
RigidAnimationTree tree = animaitonSpatials.get( e );
AnimationComponent aniComp = e.getComponent( AnimationComponent.class );
// Lookup the appropriate animation model, based on the AnimationType found in the AnimationComponent and execute using the animationTimer from AnimationComponent
}

}
[/java]

But if it’s something addressable by a system then it probably has an entity.

Maybe I’m getting confused because I don’t know what a “turrent” is and google only keeps pointing me to “turret”.

If it is a turret then a turret is an entity. It has some component which points to its parent entity. It has some game state (position, orientation, whatever) that some other system might be adjusting through components. Rotating is not an animation in and of itself… it’s a game state change of rotation. If an animation system is involved in this case then it is a case of it adjusting the rotation component based on some “target rotation” component.

And I wouldn’t necessarily consider it an animation system at that point since it could take other game state into account like how fast the turret can turn, etc. in order to decide how fast to react to that new target rotation.

One cannot really simply step off of OOP into ES. It is a total rethinking to be data driven.

1 Like

Damn, you are right, I mean turret - I have always been pronouncing it turre(n)t and spelling it like that… This is an eye opener, my whole life is a lie! Thanks for pointing that out, I need to refactor my code now. :slight_smile:

<cite>@pspeed said:</cite> One cannot really simply step off of OOP into ES. It is a total rethinking to be data driven.
And I am very happy you are willing to take your time helping me arrange my thoughts, it is always a massive help.

I have wipped up a skeleton for my TurrentAnimationSystem now, does it along the right lines? ( I am using Artemis, in case you wondered )
[java]
public class RigidAnimationComponent extends Component {
public String animationType;
public float animationTimer;
public float animationSpeed;
}

public class TurrentAnimationSystem extends EntityProcessingSystem {

@Mapper ComponentMapper&lt; RigidAnimationComponent &gt; rigidMapper;
@Mapper ComponentMapper&lt; TargetComponent &gt; targetMapper;

private HashMap&lt; Entity, RigidAnimationTree &gt; animationTrees;

private HashMap&lt; String, TurretAnimator &gt; animators;

public TurrentAnimationSystem() {
    super( Aspect.getAspectForAll( RigidAnimationComponent.class ) );
    throw new UnsupportedOperationException( "This was written from an Idea, not tested!" );
}

public void registerAnimator( String animationType, TurretAnimator animator ){
    this.animators.put( animationType, animator );
}

public void addAnimationTree( Entity e, RigidAnimationTree tree ){
    this.animationTrees.put( e, tree );
}

@Override
protected void process( Entity e ) {
    
    // Get the animation tree
    RigidAnimationTree tree = this.animationTrees.get( e );
    
    // Get component
    RigidAnimationComponent component = this.rigidMapper.get( e );
    TargetComponent target = this.targetMapper.get( e );
    
    // Get the associated animator
    String type = target == null ? "Idle" : component.animationType;
    TurretAnimator animator = this.animators.get( type );
    
    if( animator != null ){
        animator.process( tree, component, target );
    } else {
        throw new RuntimeException( "Has no animator associated with animation type: " + component.animationType );
    }
    
}

}

[/java]

The turrent is reduced to:
A RigidAnimationComponent, a TargetComponent, and an AnimationTreeMap that has to be registred with the TurrentAnimationSystem. An animator also has to be registered, that knows how to animate the AnimationTreeMap with the specific type of animaiton.

Yeah, I think it’s much closer to being on the right track. I think some of the things I find distasteful now are probably just artifacts of artemis which I also find a little distasteful.