Movement Package - EasterEggProductions/adventure-mode-godot GitHub Wiki

MovementPackage is a resource that is to be treated as an abstract class, and extended into the usable movement packages. Note that this and resources that extend it are classes, and you will need to make instances of them in the editor. This point is expanded upon in the mvpk_combat section.

Table of Contents

Structure

This resource has 3 properties:

  • Name - a descriptive name of the package.
  • anim_tree - A reference to the root animation tree that is used for this package.
  • anim_library - A reference to the animation library that this movement package is to use. This is not actually used at this time, and will likely be replaced with a more robust dependency system. The intent here is for the movement package to be able to make sure the required animations are on the Actor it is applied to.
And 4 methods:
  • pack_type - This can be overridden to allow for various special checks. This was done because Godot does not support checking custom class names.
  • transfer_situation_check - Every frame the actor iterates through every package it has, passing itself in as _thrall, and this function returns a boolean, true if this package should take control, and false otherwise.
  • release_situation_check - Every frame the actor calls this on it's current package, and it returns true if the current package should not be in charge. It no other package says it should be in charge, the Actor defaults to the package at index 0.
  • move_thrall - This is the actual update method, taking in the Actor as _thrall, and the delta time.
Consider this example from mvpk_walk.gd:
func move_thrall(thrall : Actor, delta : float):
	var old_vel = thrall.velocity
	# Get the motion delta.
	thrall.velocity = ((thrall.animation_tree.get_root_motion_rotation_accumulator().inverse() * thrall.get_quaternion()) * thrall.animation_tree.get_root_motion_position() / delta) * 1

	# Add the gravity.
	if not thrall.is_on_floor():
		thrall.velocity = old_vel
	thrall.velocity.y -= gravity * delta
	thrall.quaternion = thrall.quaternion * ((thrall.animation_tree.get_root_motion_rotation() / delta) * 10)
	# Actually move thrall
	thrall.move_and_slide()
Here it caches the old velocity from the Actor, updates it based on the animations root motion, applies gravity, then uses the Actor's move_and_slide function to have it move about the world.

For another example, look at vmpk_glide.gd in whole,

extends MovementPackage

class_name mvpk_glide

var termnalVel = -1.0


func pack_type() -> String:
	return "mvpk_glide" # godot does not support getting custom class names 

func transfer_situation_check(thrall : Actor) -> bool:
	if thrall.is_on_floor() == false:
		if Input.is_action_just_pressed("p1_jump"):
			thrall.combat_mode = false
			return true
	return false

func release_situation_check(thrall : Actor) -> bool:	
	if thrall.is_on_floor() or Input.is_action_just_pressed("p1_crouch"):
		return true
	return false

func move_thrall(thrall : Actor, delta : float):	
	var old_fallVel = thrall.velocity.y
	# Get the motion delta.
	thrall.velocity = ((thrall.animation_tree.get_root_motion_rotation_accumulator().inverse() * thrall.get_quaternion()) * thrall.animation_tree.get_root_motion_position() / delta) * 2

	# if gliding we know we arent on the ground
	thrall.velocity.y = old_fallVel 
	thrall.velocity.y -= 1 * delta
	thrall.velocity.y = clampf(thrall.velocity.y, termnalVel, -(termnalVel * 2))
	thrall.quaternion = thrall.quaternion * ((thrall.animation_tree.get_root_motion_rotation() / delta) * 10)

	thrall.move_and_slide()
Here the transfer situation functions are actually checking if the character is in the air or grounded, and a terminalVel is defined and used to limit the descent of the Actor to 1 unit per second.

This package checks if we are in the air and press jump to transfer in, and if we click the crouch button or touch the ground to transfer out. We could modify it to only transfer in if we have enough height (like Breath of the Wild), by adding a raycast downward in the transfer_situation_check, and seeing if we are high enough to begin gliding.

Current Packages

mvpk_walk

A simple package with no enter or exit check logic. If this is set as the first package in an Actor's array, it will use this animation set as it's default.

mvpk_glide

This package implements some basic logic to control a Breath of the Wild style gliding system. If you are in the air and tap jump, you will start gliding. If you are gliding and touch the ground or crouch, you will exit this package.

mvpk_climb

This package activates if you are facing a wall and try to jump onto it. It uses a raycast to detect this, and so may be useful as an example of that.

mvpk_area_dep

This is a slightly outdated package meant to implement swimming. It accesses the actor's node, looking for a child called 'water_cast' which is a shape cast 3d used to detect if it is within or touching a collision shape of a particular name ("water" by default). It then switches to this package if it is within that zone. This package is outdated, and should not be used. It's referencing of a child of the actor that is not universal is bad practice, and this will be updated in the future.

mvpk_combat

This package is meant to hold the entire moveset of a weapon. It is under development but right now it switches to this package when the weapon is in hand, and leaves when the weapon is out of hand. This is the package that has the most instances in the project. with w_1H-sword_moveset.tres and w_claymore_moveset.tres being a movement pack for a one handed sword, and claymore respectively. This is an example of how multiple instances of the resource can be used.

Known Issues

Movement packages are a useful system, but they are pushing the animation handling tools of Godot to their limit. In Godot, animation trees can be nested and cross referenced. For example a Blend Tree can have as a node within it, a state machine. This is leveraged heavily in the existing animation trees, but some errors seem to exist in how those sub trees are initialized or started, resulting in some not playing during gameplay.

Currently there is no way for an animation tree to send a signal that it is done, or that it should switch to a different movement package. This would be useful for sheathing a sword, and switching back to the default walk package when that is done, or sheathing one weapon to draw another, instead of instantly switching to the other weapon.

Currently there is no provision for swappable sub components within a moveset. For example allowing an ash of war style system, or altering offhand attacks at runtime.

⚠️ **GitHub.com Fallback** ⚠️