Skip to content

Commit

Permalink
AnimationTree State Machine
Browse files Browse the repository at this point in the history
Learning Godot's built in StateMachine!!!
It's been okay, but I wish it had signals.
Also, the backing AnimationPlayer doesn't emit signals which sucks.
godotengine/godot#28311
  • Loading branch information
ArtlessAvian committed Jul 13, 2019
1 parent a39dd84 commit 414e45d
Show file tree
Hide file tree
Showing 6 changed files with 307 additions and 74 deletions.
49 changes: 49 additions & 0 deletions Entities/Empty.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
[gd_scene load_steps=5 format=2]

[ext_resource path="res://Entities/Player.gd" type="Script" id=1]
[ext_resource path="res://Assets/spritesheet test.png" type="Texture" id=2]

[sub_resource type="RectangleShape2D" id=1]
extents = Vector2( 20, 20 )

[sub_resource type="RectangleShape2D" id=2]
extents = Vector2( 10, 20 )

[node name="Player" type="Node2D"]
script = ExtResource( 1 )

[node name="Sprite" type="Sprite" parent="."]
position = Vector2( 0, -4.24121 )
scale = Vector2( 0.2, 0.2 )
texture = ExtResource( 2 )
vframes = 8
hframes = 8
__meta__ = {
"_edit_lock_": true
}

[node name="Hitbox" type="Area2D" parent="."]
collision_layer = 0
__meta__ = {
"_edit_lock_": true
}

[node name="CollisionShape2D" type="CollisionShape2D" parent="Hitbox"]
shape = SubResource( 1 )

[node name="Hurtboxes" type="Area2D" parent="."]
collision_mask = 0
__meta__ = {
"_edit_lock_": true
}

[node name="CollisionShape2D" type="CollisionShape2D" parent="Hurtboxes"]
position = Vector2( 37, 0 )
shape = SubResource( 2 )
disabled = true

[node name="AnimationPlayer" type="AnimationPlayer" parent="."]

[node name="AnimationTree" type="AnimationTree" parent="."]
anim_player = NodePath("../AnimationPlayer")
[connection signal="area_entered" from="Hurtboxes" to="." method="_on_Hurtboxes_area_entered"]
23 changes: 22 additions & 1 deletion Entities/EnemyTest.tscn
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[gd_scene load_steps=9 format=2]
[gd_scene load_steps=13 format=2]

[ext_resource path="res://Entities/Entity.gd" type="Script" id=1]
[ext_resource path="res://Assets/spritesheet test.png" type="Texture" id=2]
Expand Down Expand Up @@ -109,10 +109,25 @@ tracks/0/keys = {
"values": [ 8, 9, 10, 11, 12 ]
}

[sub_resource type="AnimationNodeAnimation" id=9]
animation = "Idle"

[sub_resource type="AnimationNodeAnimation" id=10]
animation = "Oof"

[sub_resource type="AnimationNodeStateMachine" id=7]
states/Idle/node = SubResource( 9 )
states/Idle/position = Vector2( 393, 94 )
states/Oof/node = SubResource( 10 )
states/Oof/position = Vector2( 200, 94 )

[sub_resource type="AnimationNodeStateMachinePlayback" id=8]

[node name="Entity" type="Node2D"]
script = ExtResource( 1 )

[node name="Sprite" type="Sprite" parent="."]
position = Vector2( 0, -4.67889 )
scale = Vector2( 0.2, 0.2 )
texture = ExtResource( 2 )
vframes = 8
Expand Down Expand Up @@ -146,4 +161,10 @@ anims/Idle = SubResource( 3 )
anims/Light1 = SubResource( 4 )
anims/Oof = SubResource( 5 )
anims/WalkRight = SubResource( 6 )

[node name="AnimationTree" type="AnimationTree" parent="."]
tree_root = SubResource( 7 )
anim_player = NodePath("../AnimationPlayer")
active = true
parameters/playback = SubResource( 8 )
[connection signal="area_entered" from="Hurtboxes" to="." method="_on_Hurtboxes_area_entered"]
36 changes: 23 additions & 13 deletions Entities/Entity.gd
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ var knockback : Vector2 = Vector2.ZERO; # Generally only X and Y
var hitstun : float = 0;
var knockdown : bool = false;

var state_machine : AnimationNodeStateMachinePlayback;

func _ready():
self.true_pos = Vector3(self.position.x, 0, self.position.y);
# self.air_vel = Vector3(300, 300, 0);
self.state_machine = $AnimationTree.get("parameters/playback");

func _process(_delta : float):
if not Engine.editor_hint:
self.position.x = self.true_pos.x;
Expand All @@ -35,27 +37,29 @@ func _process(_delta : float):
self.air_vel.y = 600;
self.grounded = false;

func _physics_process(_delta):
func _physics_process(delta):
self.propagate_call(self.state_machine.get_current_node() + "Run", [delta]);

if self.hitstun <= 0 and not knockdown:
if grounded:
self.true_pos += self.ground_vel * _delta;
self.true_pos += self.ground_vel * delta;
else:
self.true_pos += self.air_vel * _delta;
self.air_vel.y -= GRAVITY * _delta;
self.true_pos += self.air_vel * delta;
self.air_vel.y -= GRAVITY * delta;
else:
self.true_pos.x += self.knockback.x * _delta;
self.true_pos.x += self.knockback.x * delta;
if grounded:
self.knockback.x -= sign(self.knockback.x) * max(0, 10 * _delta)
self.knockback.x -= sign(self.knockback.x) * max(0, 10 * delta)
else:
self.true_pos.y += self.knockback.y * _delta;
self.knockback.y -= GRAVITY * _delta;
self.true_pos.y += self.knockback.y * delta;
self.knockback.y -= GRAVITY * delta;

hitstun -= _delta
hitstun -= delta
if hitstun <= 0:
if not self.grounded:
self.air_vel.x = self.knockback.x;
self.air_vel.y = self.knockback.y;
$AnimationPlayer.play("Idle");
self.state_machine.start("Idle");

if self.true_pos.y <= 0:
if not knockdown or self.knockback.y < KNOCKDOWN_RECOVERY:
Expand Down Expand Up @@ -90,4 +94,10 @@ func receive_knockback(hitter : Entity, kb : Vector2, hs : float, kd : bool):
self.hitstun = hs;
self.knockdown = kd;
$Hurtboxes/CollisionShape2D.disabled = true;
$AnimationPlayer.play("Oof");
self.state_machine.start("Oof");

# Animation Shenangians
# This would work, but https://github.com/godotengine/godot/issues/28311
#func _on_AnimationPlayer_animation_changed(old_name, new_name):
# self.propagate_call(old_name + "Exit");
# self.propagate_call(new_name + "Enter");
101 changes: 63 additions & 38 deletions Entities/Player.gd
Original file line number Diff line number Diff line change
@@ -1,46 +1,54 @@
extends Entity

var attacking : bool = false;
const P_C : String = "parameters/conditions/"
const DEADZONE : float = 0.2;

func _physics_process(_delta):
var input : Vector3 = self.get_input()
var input : Vector3 = self.get_input();

if attacking:
if not $AnimationPlayer.is_playing():
attacking = false;

if not attacking:
if grounded:
if (input.length_squared() < 0.4):
if not $AnimationPlayer.current_animation in ["StopWalking", "Idle"]:
$AnimationPlayer.play("StopWalking");
$AnimationPlayer.queue("Idle");
else:
match $AnimationPlayer.current_animation:
"StopWalking":
self.ground_vel *= 0.9;
"Idle":
self.ground_vel = Vector3.ZERO;
else:
match $AnimationPlayer.current_animation:
"StopWalking":
$AnimationPlayer.play("Run");
self.ground_vel = input * 400;
"Idle":
$AnimationPlayer.play("Walk");
self.ground_vel = input * 200;
"Walk":
self.ground_vel = input * 200;
"Run":
self.ground_vel = input * 400;

if self.ground_vel.x != 0:
self.scale.x = sign(self.ground_vel.x);

if Input.is_action_just_pressed("ui_accept"):
attacking = true;
self.ground_vel = Vector3.ZERO;
$AnimationPlayer.play("Light1");
$AnimationTree.set(P_C + "input", input != Vector3.ZERO);
$AnimationTree.set(P_C + "!input", input == Vector3.ZERO);
$AnimationTree.set(P_C + "light", Input.is_action_just_pressed("ui_accept"));
$AnimationTree.set(P_C + "grounded", self.grounded);

# $AnimationTree.tree_root.set_parameter("parameters/conditions/input", input == Vector3.ZERO)

# if attacking:
# if not $AnimationPlayer.is_playing():
# attacking = false;
#
# if not attacking:
# if grounded:
# if (input.length_squared() < 0.4):
# if not $AnimationPlayer.current_animation in ["StopWalking", "Idle"]:
# $AnimationPlayer.play("StopWalking");
# $AnimationPlayer.queue("Idle");
# else:
# match $AnimationPlayer.current_animation:
# "StopWalking":
# self.ground_vel *= 0.9;
# "Idle":
# self.ground_vel = Vector3.ZERO;
# else:
# match $AnimationPlayer.current_animation:
# "StopWalking":
# $AnimationPlayer.play("Run");
# self.ground_vel = input * 400;
# "Idle":
# $AnimationPlayer.play("Walk");
# self.ground_vel = input * 200;
# "Walk":
# self.ground_vel = input * 200;
# "Run":
# self.ground_vel = input * 400;
#
# if self.ground_vel.x != 0:
# self.scale.x = sign(self.ground_vel.x);
#
# if Input.is_action_just_pressed("ui_accept"):
# attacking = true;
# self.ground_vel = Vector3.ZERO;
# $AnimationPlayer.play("Light1");

# ._physics_process(delta);

Expand All @@ -51,3 +59,20 @@ static func get_input() -> Vector3:
if input.length_squared() > 1:
input = input.normalized();
return input;

func RunRun(_delta : float):
self.ground_vel = get_input() * 400;
if self.ground_vel.x != 0:
self.scale.x = sign(self.ground_vel.x);

func WalkRun(_delta : float):
self.ground_vel = get_input() * 200;
if self.ground_vel.x != 0:
self.scale.x = sign(self.ground_vel.x);

func WalkExit():
self.ground_vel = Vector3.ZERO;

func RunExit():
self.ground_vel = Vector3.ZERO;

Loading

0 comments on commit 414e45d

Please sign in to comment.