HowTo: Make objects take damage from collisions


#1

In order to make stuff hurt other stuff in frogatto:

Concerning HP:
Objects have hitpoints as a built-in variable. When you take damage, you must manually decrement them with either the set(hitpoints,value) or add(hitpoints,-value) functions. One of the few bits of hard-coded C++ behavior is that if an object’s HP falls below zero, their die event will be called automatically.

Die is an event that lets you trigger other stuff just before an object is removed - the removal is automatic, but you can ‘cheat death’ by respawning a copy of yourself in the exact same spot. Common uses of the on_die event are to perform loot drops, give the player points, and initiate the death explosion animation. You can cause an object to die, manually, by calling “die()”.

Another command, rarely used directly, is “remove_object()”. This is internally called by “die()”, and it enacts no special behavior or animations. It simply deletes the object.

In Theory:

  • Inside of animations, objects can be given “collision areas”. These areas check for collisions, but only collisions between non-transparent pixels. These will only trigger when two areas you’ve actually defined touch each other - there are no areas that are automatically defined for you. These can be freely named, and will then be triggered by corresponding “on_collide_name” events.

None of these are hard-coded into the engine, but our prototypes have two areas they’re written to work with: “Attack”, and “body”. The way our prototypes handle this, an object will take damage any time its body area touches another object’s attack area, and it will take the amount listed in that object’s vars.damage

These areas are defined inside animations, with rectangles that have an origin in the upper-left-corner of the frame. You can use two special words, “all” or “none”, and these do what you’d expect.

  • The typical use case for this is making only part of an enemy take damage; frogatto, for example, does not take damage from his tongue. Likewise, only his tongue can hurt/grab an opponent.

Another obvious use-case of this, which we don’t really do in game, yet, is establishing special “weak points” on an enemy (especially a boss) which have some special behavior that doesn’t happen otherwise (easy, cheap examples include receiving double damage, turtling up, changing their attack pattern, or getting stunned.

  • Comparisons of whether objects should hurt another or not are done by comparing teams. If two objects are on the same team, they don’t hurt each other. This behaviour isn’t in the engine, just in our prototypes, so if you’re making a prototype-less object, you’ll need to enforce this yourself.

  • Inside of on_collide_object* handlers, there’s a special variable called collide_with. This lets you access “the other guy in the crash”.

In Practice:
For most stuff, just derive from a prototype. Or, extend a prototype, carefully, to add the behavior you need. Prototypes do all of our nuanced behavior, like how objects damage each other when thrown, or don’t repeatedly deal damage every frame if they’ve just hit an opponent, and attempting to recreate this behavior by-hand is very error-prone, and tough to maintain.

For stuff where you really need to be custom:

  • set vars.team, and vars.damage. Conventional teams are ‘player’ and ‘evil’

  • add an on_collide_object_body handler. As an object, this gets fired when something hits your body; in it, you typically check if the other thing is a harmful area, and take damage if that’s the case.

  • maybe add an on_collide_object_attack. This gets called when someone collides with your weapon. This is not used to deal damage to them; their body handler takes care of that. Instead, this is used to do stuff to yourself. Common use-cases include recoiling as though you’d just delivered a blow, and destroying yourself (in the case of missiles, or suicide bombers).


#2

Small correction here: remove_object() doesn’t “delete” the object. Rather, it removes it from the game. However, you can still hold a reference to the object if you have stored one. Then you could look up its properties, or add it back in (either to this level or another level) using add_object() at a later time.

An object is automatically deleted when there are no more references to it. remove_object() will cause it to be deleted if you don’t hold references to it, but this isn’t necessarily so.

David