feat: wall jumps

This commit is contained in:
Sara Gerretsen 2026-04-28 14:31:49 +02:00
parent 4a2e637218
commit e9d6124d10
6 changed files with 107 additions and 27 deletions

View file

@ -0,0 +1,21 @@
#include "player_action.h"
#include "macros.h"
void PlayerAction::_bind_methods() {
BIND_HPROPERTY(Variant::OBJECT, blackboard, PROPERTY_HINT_NODE_TYPE, "PlayerBehaviourTree", PROPERTY_USAGE_READ_ONLY);
BIND_HPROPERTY(Variant::OBJECT, body, PROPERTY_HINT_NODE_TYPE, "PlayerBody", PROPERTY_USAGE_READ_ONLY);
}
void PlayerAction::_notification(int what) {
if (Engine::get_singleton()->is_editor_hint()) {
return;
}
switch (what) {
default:
return;
case NOTIFICATION_ENTER_TREE:
this->blackboard = cast_to<PlayerBehaviourTree>(get_behaviour_tree());
this->body = this->blackboard->get_player_body();
ERR_FAIL_COND_EDMSG(this->blackboard == nullptr, "BehaviourTree of PlayerAction is not a PlayerBehaviourTree");
}
}

View file

@ -0,0 +1,21 @@
#pragma once
#include "behaviour_nodes/behaviour_action.h"
#include "viscosity/player_behaviour_tree.h"
#include "viscosity/player_body.h"
class PlayerAction : public BehaviourAction {
GDCLASS(PlayerAction, BehaviourAction);
static void _bind_methods();
protected:
void _notification(int what);
private:
PlayerBehaviourTree *blackboard{ nullptr };
PlayerBody *body{ nullptr };
public:
GET_SET_FNS(PlayerBehaviourTree *, blackboard);
GET_SET_FNS(PlayerBody *, body);
};

View file

@ -9,13 +9,10 @@ void PlayerMovementAction::_bind_methods() {
}
void PlayerMovementAction::process_movement() {
if (this->blackboard == nullptr) {
this->blackboard = cast_to<PlayerBehaviourTree>(get_behaviour_tree());
}
ERR_FAIL_COND_EDMSG(this->blackboard == nullptr, "Parent behaviour tree of PlayerMovementAction is not a PlayerBehaviourTree");
ERR_FAIL_COND_EDMSG(get_blackboard() == nullptr, "Parent behaviour tree of PlayerMovementAction is not a PlayerBehaviourTree");
double const delta{ get_process_delta_time() };
Vector3 target_velocity{ this->blackboard->get_world_move_input().normalized() * this->target_speed };
Vector3 velocity{ this->blackboard->get_player_body()->get_velocity() };
Vector3 target_velocity{ get_blackboard()->get_world_move_input().normalized() * this->target_speed };
Vector3 velocity{ get_blackboard()->get_player_body()->get_velocity() };
float actual_acceleration{
target_velocity.normalized().dot(velocity.normalized()) > 0.8f
? this->acceleration
@ -24,7 +21,7 @@ void PlayerMovementAction::process_movement() {
target_velocity.y = velocity.y;
velocity = velocity.move_toward(target_velocity, delta * actual_acceleration);
if (!velocity.is_zero_approx()) {
this->blackboard->get_character()->look_at(this->blackboard->get_character()->get_global_position() + velocity);
get_blackboard()->get_character()->look_at(get_blackboard()->get_character()->get_global_position() + velocity);
}
this->blackboard->get_player_body()->set_velocity(velocity);
get_blackboard()->get_player_body()->set_velocity(velocity);
}

View file

@ -1,11 +1,10 @@
#pragma once
#include "behaviour_nodes/behaviour_action.h"
#include "macros.h"
#include "viscosity/player_behaviour_tree.h"
#include "viscosity/player_action.h"
class PlayerMovementAction : public BehaviourAction {
GDCLASS(PlayerMovementAction, BehaviourAction);
class PlayerMovementAction : public PlayerAction {
GDCLASS(PlayerMovementAction, PlayerAction);
static void _bind_methods();
public:
@ -15,7 +14,6 @@ private:
float target_speed{ 5.f };
float acceleration{ 10.f };
float deceleration{ 20.f };
PlayerBehaviourTree *blackboard{ nullptr };
public:
GET_SET_FNS(float, target_speed);

View file

@ -1,6 +1,7 @@
#include "register_types.h"
#include "core/object/class_db.h"
#include "viscosity/player_action.h"
#include "viscosity/player_behaviour_tree.h"
#include "viscosity/player_body.h"
#include "viscosity/player_camera.h"
@ -13,6 +14,7 @@ void initialize_viscosity_module(ModuleInitializationLevel p_level) {
ClassDB::register_class<PlayerBody>();
ClassDB::register_class<PlayerBehaviourTree>();
ClassDB::register_class<PlayerCamera>();
ClassDB::register_class<PlayerAction>();
ClassDB::register_class<PlayerMovementAction>();
}

View file

@ -8,15 +8,49 @@ radius = 0.6972656
[sub_resource type="BoxMesh" id="BoxMesh_bxedw"]
size = Vector3(0.2, 0.2, 0.2)
[sub_resource type="GDScript" id="GDScript_ykyjo"]
resource_name = "FallingAction"
script/source = "extends BehaviourAction
@onready var behaviour_tree := get_behaviour_tree() as PlayerBehaviourTree
[sub_resource type="GDScript" id="GDScript_f46kd"]
resource_name = "WallJumpAction"
script/source = "extends PlayerAction
func _enter() -> int:
if not behaviour_tree.player_body.is_on_floor():
behaviour_tree.player_body.velocity += behaviour_tree.player_body.get_gravity() * get_process_delta_time()
if body.is_on_wall_only() and Input.is_action_just_pressed(\"jump\"):
var wall := body.get_wall_normal()
if wall.dot(blackboard.get_world_move_input().normalized()) > 0.75:
body.velocity = body.get_wall_normal() * 4
body.velocity.y = 6
else:
body.velocity += body.get_wall_normal() * 3
body.velocity.y = 4
blackboard.character.look_at(blackboard.character.global_position + Vector3(body.velocity.x, 0, body.velocity.y))
return Success
else:
return Fail
"
[sub_resource type="GDScript" id="GDScript_nmc1l"]
resource_name = "WallSlideAction"
script/source = "extends PlayerAction
@export var wall_drag : float
func _enter() -> int:
if body.is_on_wall_only():
var delta := get_process_delta_time()
var target_velocity := Vector3(0, min(body.velocity.y, 0.0), 0)
body.velocity = body.velocity.move_toward(target_velocity, wall_drag * delta) + (body.get_gravity() * 0.2 * delta)
blackboard.character.look_at(blackboard.character.global_position + body.get_wall_normal())
return Success
else:
return Fail
"
[sub_resource type="GDScript" id="GDScript_ykyjo"]
resource_name = "FallingAction"
script/source = "extends PlayerAction
func _enter() -> int:
if not body.is_on_floor():
body.velocity += body.get_gravity() * get_process_delta_time()
return Success
else:
return Fail
@ -24,15 +58,13 @@ func _enter() -> int:
[sub_resource type="GDScript" id="GDScript_eqqp1"]
resource_name = "JumpAction"
script/source = "extends BehaviourAction
script/source = "extends PlayerAction
@export var vertical_jump_velocity : float
@onready var behaviour_tree := get_behaviour_tree() as PlayerBehaviourTree
func _enter() -> int:
if Input.is_action_just_pressed(\"jump\"):
behaviour_tree.player_body.velocity.y = vertical_jump_velocity
body.velocity.y = vertical_jump_velocity
return Success
else:
return Fail
@ -60,6 +92,8 @@ func _enter() -> int:
"
[node name="Player" type="PlayerBody" unique_id=591139793]
slide_on_ceiling = false
wall_min_slide_angle = 1.0471976
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1143027860]
shape = SubResource("CapsuleShape3D_bxedw")
@ -84,15 +118,22 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2.3841858e-07, 1.3299754, 4.
[node name="ActionSelector" type="BehaviourSelector" parent="PlayerBehaviourTree/BehaviourRepeater" unique_id=433229675]
[node name="FallingAction" type="BehaviourAction" parent="PlayerBehaviourTree/BehaviourRepeater/ActionSelector" unique_id=740542779]
[node name="WallJumpAction" type="PlayerAction" parent="PlayerBehaviourTree/BehaviourRepeater/ActionSelector" unique_id=1070446491]
script = SubResource("GDScript_f46kd")
[node name="WallSlideAction" type="PlayerAction" parent="PlayerBehaviourTree/BehaviourRepeater/ActionSelector" unique_id=85039173]
script = SubResource("GDScript_nmc1l")
wall_drag = 5.0
[node name="FallingAction" type="PlayerAction" parent="PlayerBehaviourTree/BehaviourRepeater/ActionSelector" unique_id=570179125]
script = SubResource("GDScript_ykyjo")
[node name="JumpAction" type="BehaviourAction" parent="PlayerBehaviourTree/BehaviourRepeater/ActionSelector" unique_id=35567373]
[node name="JumpAction" type="PlayerAction" parent="PlayerBehaviourTree/BehaviourRepeater/ActionSelector" unique_id=553747039]
script = SubResource("GDScript_eqqp1")
vertical_jump_velocity = 5.0
[node name="RunningAction" type="PlayerMovementAction" parent="PlayerBehaviourTree/BehaviourRepeater/ActionSelector" unique_id=2080183164]
target_speed = 15.0
target_speed = 10.0
script = SubResource("GDScript_bxedw")
[node name="WalkAction" type="PlayerMovementAction" parent="PlayerBehaviourTree/BehaviourRepeater/ActionSelector" unique_id=1371791141]