I have this little character that goes on to hit an NPC for a test, and the NPC dies on the spot. Actually, now that I remember, I have an animation for the death of my NPC. What I want to make happen:

  • The PC getting hit
    • A NPC needs to aim their action at the PC.
    • User interaction needs to be disabled while the PC register the hit.
    • An animation needs to be played.
    • Other effects may be seen, e.g. lose life points
  • The NPC not chasing after the PC while dying (that’s a bug)

I’d rather use my behavior (pseudo)scripting API instead of just hacking away. Conceptually, integrating player decisions with standard NPC scripting fits fairly well, so I should put my code where my brains are.

Design bites back, the dog doesn’t.

My ‘biting dog’ script doesn’t seem to work as well as it used to be. This relates in part to design issues with my framework:

  • In my script, the dog would walk to the player and start to bite. If the player moves away, the dog starts chasing the player. This is correct since the player has moved within ‘chase range’ and is now out of biting range. However, at that point the biting action is not reset and that has reached frame zero. I need to reset an action whenever it completes, so I have introduced a ‘reset’ method.
    >> actions are instantiated too early. The action descriptor should be used to regenerate the action whenever the condition is filled. This will avoid relying on a ‘reset’ call. In other words, the condition should be armed and attached to the agent; the action descriptor should be attached to the condition. When the condition is fulfilled, a new instance of the matching action should be created.
  • I used to rely on the agent having non zero speed to determine the agent state is ‘walking’. This is more than wrong. There are various factors that can affect an agent speed. I have corrected this but forgot to update the action tag in Approach, Avoid, MoveTo, etc…

Let the player be hurt

I add a couple of lignes to my script (in fact i add a player script since I have none) for the player to be ‘hurt’. Hurt is just a label here, but that could bind an animation.

Roughly speaking, things work out pretty good, but not good enough. If the player targets the dog, the PC and NPC end up rushing each other. I can’t clearly see which one hits the other first. The player seems to have the upper hand.

Bite me, Stab me

I still need to ensure two things:

  • I seem to have a targeting problem.
    • There is a limit angle for a hit to register – an actor needs to be facing the target. This shouldn’t, but seems to be a problem.
  • Both the player and the dog should be able to hit each other in turn.
    • As far as I know there is no lag time between hits.
    • Also, I have no ‘impact frame’ defined. In other words, while an actor is acting, the actor is being hit – these are ‘linked states’ rather than an action and reaction.

Whenever I bind a script using my Interpreter, the following occurs:

  1. For each type definition in the script (a type definition is associated with an actor’s label, bindType is invoked.
  2. bindType, creates both a reflex map and an affect map.
  3. Actions are added to the reflex map ; interactions are added to the affect map.

This means that action/interaction couples are grouped per actor in the main transition. Although not ideal, this seems to work fine:

(Aim) player aims action:stab

(AffectAction) player targetted by:hurt

(BasicActorUpdates) resolve Actor player {…} to hurt

(BasicActorUpdates) resolve Actor dog {…} to bite

What the log indicates is that even though the player aims the stab action, it is being hurt, which overrides the player’s intent.

If I look at AffectBinding (which causes both the dog to bite the dust and the player to be hurt when attacked), I see that states are linked at every frame. In retrospect, this is an obviously poor design. It would be way more efficient and probably more useful to just trigger the affect once. But what happens in my case is that the affect triggers over and over until the activity stops.

So in this case, for as long as the dog is in ‘bite state’, the player state is ‘hurt’. Since the dog bites in a loop, the player can never counter-attack, because affects (passive actions) override decisions.

In ActorAffectCondition (a condition that triggers an affect, such as being hurt, when another actor is performing an action on the target), i have a checkAgainst: method. There, I add a condition specifying an ‘impact frame’ for the source action.

The result is immediate (and visually obvious) – instead of  sticking to the ‘hurt state’ the PC now blips between hurt and normal. This also means that the PC can counter-attack.

R.I.P

I still have this problem with the ‘zombie dog’. The death state shouldn’t allow wagging dog tail and biting a victorious player.

In theory I could add a capacity switch to the dog’s stab response. But there’s nothing to check for capacities just yet. Since being dead is a peculiar state, I will hack this once.

Activity change is ultimately driven by an actor’s step: method. This iterates activities and cycles them. For now, this allows all activities to be interrupted.

I could force all activities to complete before another starts. Trying this is interesting but for now, not very effective, causing more inconsistent behavior.

Instead I only force the ‘rip state’ to be sticky.

Oh my. This dog is still running around though. Motion is controlled independently from action… so I wire another hack into my
[BasicActorUpdates updateActorLocation:]
method.

Conclusion

This is my first debugging session on the behavior engine since I wrote the original draft and validated the test suite. Since the test suite was so simple – testing really basic cases – surprises tend to occur.

The design of behavior implementation isn’t good. I’ll make another implementation later I guess, including only current activities in the loop and adopting an event driven approach for higher level behaviors. This will be cleaner, more intuitive, and reduce processing load.

Meanwhile, there are also shortages in action descriptions:

  • An action should at least have a flag (maybe with a default) indicating whether this action can be interrupted. Passive responses shouldn’t be interruptible. Many actions (e.g., walk cycle) work out better if they can be interrupted.
  • An action should specify an impact frame, and whether the effect is punctual or continuous.
  • An action should ideally have a lag time. This could somehow be made integral to impact frames.

At higher level, a working combat model should take into account the following:

  1. The speed of an attack depends on the length of the attack animation. If the attack has an ‘impact frame’ then a longer attack means attacking less often.
  2. If the attack can be interrupted, then the later the impact frame, the easier it is for the player to anticipate the attack.
  3. The speed of recovery determines the ability to counter-attack. If recovery is slow, then the opponent may be able to attack another time.

Tomorrow, I need to:

  • Allow specifying impact frames.
  • Test with actual animations
  • Allow specifying which actions can be interrupted, and which cannot.