#1 Attack Collisions

godot devlog hammer-time

From animations to collisions

In the last entry on this series I stated that players could perform movements and attacks using the character controller I wrote, but that was just a partial truth. Although players could trigger attacks, only their animations would play.

A collision system for a project like this can grow quite complex, so I left it out for the time being to keep things short and simple in the character controller. However, that is what I worked on next and what I will be covering in this post.

In the case of hammer-time, its collition system had the following requirements:

  • The PlayerCharacter should be able to attack both enemies and elements in the environment (for convenience, I will refer to the group of them as Interactables from now on).
  • Interactables shouldn’t need a reference to the PlayerCharacter in order to work, or vice versa.
  • The PlayerCharacter shouldn’t care whether an Interactable is an enemy or an element in the scene.
  • Since the PlayerCharacter has multiple attacks to choose from, I wanted the Interactables to be able to react differently to them if necessary.

A screenshot of the prototype running where the player character is attacking a green ball, which turns red when registering the hit.
A screenshot of the player character attacking a green ball, which turns red when registering the hit.

The interactable hurtboxes

I began by creating an InteractableHurtbox node that would receive (and forward using signals) information about player attacks. This node is meant to be placed as a direct child of any detectable Area3D by the player. This hurtbox would be checked for using a constant, relative NodePath:

var hurt_box: InteractableHurtbox = detected_area_3d.get_node_or_null(INTERACTABLE_HURTBOX_RELATIVE_PATH)

This way the logic of the hurtbox is decoupled from the physics nodes using it. It might seem confusing, but the result is that creating a new Interactable is as easy as:

  1. Adding an InteractableHurtbox inside an Area3D.
  2. Connecting the signals of the hurtbox that the new Interactable reacts to.
  3. Writting the desired behaviours in the callback methods.

A screenshot of the Godot editor where the script editor shows code for an interactable implementation that reacts to player attacks using physics.
An example implementation of an interactable, connected to the signals from its hurtbox.

The player attack hitboxes

With the interactables ready, the next step was for the PlayerCharacter to actually look for them when attacking. I needed to make sure that my approach fit nicely with the character controller and the finite state machine I already had.

I first created a new direct child in the player scene, attaching a PlayerCharacterHitboxes script to it. This node parents all Area3D hitboxes that the attack animations might use and sends a signal whenever an InteractableHurtbox is detected. After that I updated said animations to include and fit them to the reach of each attack.

Lastly, I added a reference to PlayerCharacterHitboxes in the base attack state of the FSM. Every time an attack state is entered/exited it connects/disconnects the exposed signal. The callback method sends the appropiate data to the hurtbox.

func on_interactable_hurtbox_hit(hurt_box: InteractableHurtbox) -> void:
	hurt_box.receive_player_attack(_attack, _attack_type, player_character.global_transform)

A screenshot of the Godot editor, where the animation player node of the player character shows an updated attack animation where a hitbox is now included.
A screenshot of an updated attack animation, after adding hitboxes to it.

Wrapping up and some examples

PeerTube Hammer-time devlog #1 - Player Attacks Interactables

The two components I talked about so far, hurtboxes and hitboxes, are all that is needed to set up a basic collision system. On top of that, the use of forward signals really helps keeping things decoupled while at the same time providing modularity and scalability.

In the video above, the PlayerCharacter attacks three different implementations of Interactable that I wrote to showcase some of the cool stuff that can be done with this workflow:

  • SimpleInteractable: The small green ball. It does not move, simply shakes and changes color whenever an attack is received. (It also triggers camera shake and time freeze effects, but that is out of the scope of this article!)

  • PhysicsInteractable: The big orange ball. It is affected by gravity and collisions. It can be moved and thrown differently depending on the attack received. This interactable is fed a resource file that contains the data of the forces and torques to apply per attack.

  • LaunchablePhysicsInteractable: The pink cube. It extends PhysicsInteractable to include a launch functionality. Attacking this cube in the direction of another interactable launches it flying towards its target causing a chained attack.

Drawings of other possible implementations



Previous
#0 Character Controller