diff --git a/client/Main.tscn b/client/Main.tscn index b0992b9..51f6356 100644 --- a/client/Main.tscn +++ b/client/Main.tscn @@ -18,7 +18,7 @@ [ext_resource type="PackedScene" uid="uid://cb2t7bvvf3gwh" path="res://enemy/slime/Slime.tscn" id="15_hgl78"] [ext_resource type="Script" path="res://world/PlayerManager.gd" id="16_dp6bj"] [ext_resource type="PackedScene" uid="uid://dagn5bf7ou3sd" path="res://ui/UI.tscn" id="17_43qhq"] -[ext_resource type="Material" uid="uid://bdsblfaxbipaa" path="res://grass/grass_material.tres" id="18_tja64"] +[ext_resource type="Material" uid="uid://bdsblfaxbipaa" path="res://world/grass/grass_material.tres" id="18_tja64"] [ext_resource type="Script" path="res://camera/Camera.gd" id="18_wogcj"] [ext_resource type="MultiMesh" uid="uid://dog5aq5n2q025" path="res://assets/grass/grass.multimesh" id="19_ae26a"] @@ -74,6 +74,7 @@ packet_type = 11 [node name="PlayerMove" type="Node" parent="Client"] script = ExtResource("8_ke1yy") +delay = 100 packet_type = 12 [node name="PlayerJump" type="Node" parent="Client"] diff --git a/client/character/Character.gd b/client/character/Character.gd index 57122a2..e836503 100644 --- a/client/character/Character.gd +++ b/client/character/Character.gd @@ -1,48 +1,2 @@ class_name Character -extends CharacterBody3D - -signal jumped - -@export var model: Node3D -@export var move_speed: float = 4.5 -@export var rotation_speed: float = 20.0 - -const JUMP_VELOCITY := 4.5 -const DECELERATE := 0.75 - -var direction: Vector3 -var angle: float -var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity") -var controller: Node - -func _process(delta): - if direction != Vector3.ZERO: - angle = atan2(direction.x, direction.z) - - model.rotation.y = lerp_angle(model.rotation.y, angle, rotation_speed * delta) - -func _physics_process(delta): - if direction: - velocity.x = direction.x * move_speed - velocity.z = direction.z * move_speed - else: - velocity.x *= DECELERATE - velocity.z *= DECELERATE - - if !is_on_floor(): - velocity.y -= gravity * delta - - move_and_slide() - -func jump(): - if !is_on_floor(): - return - - velocity.y = JUMP_VELOCITY - jumped.emit() - -func dash(): - print("dash") - -func attack(): - print("attack") +extends CharacterBody3D \ No newline at end of file diff --git a/client/character/animation/AnimationComponent.gd b/client/character/animation/AnimationComponent.gd new file mode 100644 index 0000000..9bb4a6f --- /dev/null +++ b/client/character/animation/AnimationComponent.gd @@ -0,0 +1,55 @@ +class_name AnimationComponent +extends Node + +const RESET = "human/RESET" + +var animation_player: AnimationPlayer +var movement: MovementComponent +var next_animation: StringName = RESET +var skip: int + +func _ready(): + var player := owner as Player + player.dashed.connect(dash) + player.attacked.connect(attack) + movement = player.find_child("Movement") + animation_player = $AnimationPlayer + +func _process(_delta): + if skip == 0: + play_movement() + + if animation_player.current_animation == next_animation: + return + + animation_player.play(next_animation) + +func play_movement(): + if !movement: + play(RESET) + return + + if movement.body.velocity.y > 0: + play("human/jump") + elif movement.body.velocity.y < 0: + play("human/fall") + elif movement.direction != Vector3.ZERO: + play("human/run-fast") + else: + play("human/idle") + +func dash(): + play_with_duration("human/roll", 1.0) + +func attack(): + play_with_duration("human/slash", 1.0) + +func play(action_name: StringName): + next_animation = action_name + +func play_with_duration(action_name: StringName, duration: float): + next_animation = action_name + skip += 1 + await get_tree().create_timer(duration).timeout + skip -= 1 + diff --git a/client/character/animation/AnimationComponent.tscn b/client/character/animation/AnimationComponent.tscn new file mode 100644 index 0000000..b5e57c7 --- /dev/null +++ b/client/character/animation/AnimationComponent.tscn @@ -0,0 +1,9 @@ +[gd_scene load_steps=2 format=3 uid="uid://bivxnxwi863o0"] + +[ext_resource type="Script" path="res://character/animation/AnimationComponent.gd" id="1_lenw3"] + +[node name="Animation" type="Node"] +script = ExtResource("1_lenw3") + +[node name="AnimationPlayer" type="AnimationPlayer" parent="."] +playback_default_blend_time = 0.2 diff --git a/client/character/health/HealthComponent.gd b/client/character/health/HealthComponent.gd index ce1be1e..8c5c529 100644 --- a/client/character/health/HealthComponent.gd +++ b/client/character/health/HealthComponent.gd @@ -2,10 +2,11 @@ class_name HealthComponent extends Node @export var max_health: float + var health: float func _ready(): - pass + health = max_health func take_damage(attack: Attack): health -= attack.damage diff --git a/client/character/health/HealthComponent.tscn b/client/character/health/HealthComponent.tscn index d1fb4ab..6aab3ba 100644 --- a/client/character/health/HealthComponent.tscn +++ b/client/character/health/HealthComponent.tscn @@ -2,5 +2,5 @@ [ext_resource type="Script" path="res://character/health/HealthComponent.gd" id="1_403dm"] -[node name="HealthComponent" type="Node"] +[node name="Health" type="Node"] script = ExtResource("1_403dm") diff --git a/client/character/movement/MovementComponent.gd b/client/character/movement/MovementComponent.gd new file mode 100644 index 0000000..218c4af --- /dev/null +++ b/client/character/movement/MovementComponent.gd @@ -0,0 +1,42 @@ +class_name MovementComponent +extends Node + +@export var move_speed := 4.5 +@export var jump_velocity := 4.5 +@export var deceleration := 0.75 + +var body: CharacterBody3D +var direction: Vector3 +var gravity: float + +func _ready(): + if owner.has_signal("direction_changed"): + owner.direction_changed.connect(on_direction_changed) + + if owner.has_signal("jumped"): + owner.jumped.connect(jump) + + body = owner as CharacterBody3D + gravity = ProjectSettings.get_setting("physics/3d/default_gravity") + +func _physics_process(delta): + if direction: + body.velocity.x = direction.x * move_speed + body.velocity.z = direction.z * move_speed + else: + body.velocity.x *= deceleration + body.velocity.z *= deceleration + + if !body.is_on_floor(): + body.velocity.y -= gravity * delta + + body.move_and_slide() + +func on_direction_changed(new_direction: Vector3): + direction = new_direction + +func can_jump() -> bool: + return body.is_on_floor() + +func jump(): + body.velocity.y = jump_velocity diff --git a/client/character/movement/MovementComponent.tscn b/client/character/movement/MovementComponent.tscn new file mode 100644 index 0000000..d6657a7 --- /dev/null +++ b/client/character/movement/MovementComponent.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3 uid="uid://x102pryt2s5a"] + +[ext_resource type="Script" path="res://character/movement/MovementComponent.gd" id="1_2gnmd"] + +[node name="Movement" type="Node"] +script = ExtResource("1_2gnmd") diff --git a/client/character/rotation/RotationComponent.gd b/client/character/rotation/RotationComponent.gd new file mode 100644 index 0000000..6e616e1 --- /dev/null +++ b/client/character/rotation/RotationComponent.gd @@ -0,0 +1,25 @@ +class_name RotationComponent +extends Node + +@export var root: Node3D +@export var rotation_speed: float = 20.0 + +var direction: Vector3 +var angle: float + +func _ready(): + assert(root, "Rotation root needs to be set") + + if owner.has_signal("direction_changed"): + owner.direction_changed.connect(on_direction_changed) + + update_configuration_warnings() + +func _process(delta): + if direction != Vector3.ZERO: + angle = atan2(direction.x, direction.z) + + root.rotation.y = lerp_angle(root.rotation.y, angle, rotation_speed * delta) + +func on_direction_changed(new_direction: Vector3): + direction = new_direction \ No newline at end of file diff --git a/client/character/rotation/RotationComponent.tscn b/client/character/rotation/RotationComponent.tscn new file mode 100644 index 0000000..8520798 --- /dev/null +++ b/client/character/rotation/RotationComponent.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3 uid="uid://d0onbq0ad1ap4"] + +[ext_resource type="Script" path="res://character/rotation/RotationComponent.gd" id="1_j1874"] + +[node name="Rotation" type="Node"] +script = ExtResource("1_j1874") diff --git a/client/controller/Controller.gd b/client/controller/Controller.gd new file mode 100644 index 0000000..1dd9ea7 --- /dev/null +++ b/client/controller/Controller.gd @@ -0,0 +1,2 @@ +class_name Controller +extends Node \ No newline at end of file diff --git a/client/enemy/EnemyController.gd b/client/controller/EnemyController.gd similarity index 58% rename from client/enemy/EnemyController.gd rename to client/controller/EnemyController.gd index 896eea6..ef8935b 100644 --- a/client/enemy/EnemyController.gd +++ b/client/controller/EnemyController.gd @@ -1,2 +1,2 @@ class_name EnemyController -extends Node +extends Controller diff --git a/client/controller/PlayerController.gd b/client/controller/PlayerController.gd new file mode 100644 index 0000000..d81360c --- /dev/null +++ b/client/controller/PlayerController.gd @@ -0,0 +1,34 @@ +class_name PlayerController +extends Controller + +## The character that we're controlling. +var player: Player + +## We need the movement component to check if we can perform certain actions. +var movement: MovementComponent + +func _init(new_player: Player): + player = new_player + movement = player.find_child("Movement") + +func _unhandled_input(event): + if Global.interacting_with_ui: + return + + # Calculate the direction + var move := Input.get_vector("move_left", "move_right", "move_forward", "move_backward") + var direction := (Global.camera.transform.basis * Vector3(move.x, 0, move.y)) + direction.y = 0 + direction = direction.normalized() + + # Notify components + player.set_direction(direction) + + if event.is_action_pressed("jump") && movement && movement.can_jump(): + player.jump() + + if event.is_action_pressed("dash"): + player.dash() + + if event.is_action_pressed("attack"): + player.attack() diff --git a/client/controller/ProxyController.gd b/client/controller/ProxyController.gd new file mode 100644 index 0000000..c2aff0e --- /dev/null +++ b/client/controller/ProxyController.gd @@ -0,0 +1,25 @@ +class_name ProxyController +extends Controller + +## The character that we're controlling. +var player: Player + +## The authoritative position on the server. +var server_position: Vector3 + +func _init(new_player: Player): + player = new_player + +func _ready(): + server_position = player.position + +func _process(_delta): + var move := server_position - player.position + move.y = 0.0 + + if move.length_squared() < 0.01: + player.set_direction(Vector3.ZERO) + return + + var direction := Vector3(move.x, 0, move.z).normalized() + player.set_direction(direction) \ No newline at end of file diff --git a/client/enemy/slime/Slime.tscn b/client/enemy/slime/Slime.tscn index 534cf3f..1dba403 100644 --- a/client/enemy/slime/Slime.tscn +++ b/client/enemy/slime/Slime.tscn @@ -1,8 +1,9 @@ -[gd_scene load_steps=8 format=3 uid="uid://cb2t7bvvf3gwh"] +[gd_scene load_steps=9 format=3 uid="uid://cb2t7bvvf3gwh"] [ext_resource type="PackedScene" uid="uid://b358op5h1y83m" path="res://assets/slime/Slime.blend" id="1_1h1hj"] [ext_resource type="Script" path="res://enemy/Enemy.gd" id="1_r5888"] [ext_resource type="PackedScene" uid="uid://2bbycjulf00g" path="res://character/health/HealthComponent.tscn" id="2_fsqxc"] +[ext_resource type="PackedScene" uid="uid://x102pryt2s5a" path="res://character/movement/MovementComponent.tscn" id="3_2phqx"] [sub_resource type="BoxShape3D" id="BoxShape3D_x1ppt"] size = Vector3(0.7, 0.6, 0.7) @@ -35,9 +36,8 @@ _data = { "slime_idle": SubResource("Animation_mdtm7") } -[node name="Slime" type="CharacterBody3D" node_paths=PackedStringArray("model") groups=["enemy"]] +[node name="Slime" type="CharacterBody3D" groups=["enemy"]] script = ExtResource("1_r5888") -model = NodePath("Model") [node name="Model" parent="." instance=ExtResource("1_1h1hj")] @@ -53,3 +53,5 @@ libraries = { autoplay = "slime_idle" [node name="Health" parent="." instance=ExtResource("2_fsqxc")] + +[node name="Movement" parent="." instance=ExtResource("3_2phqx")] diff --git a/client/network/PlayerAdd.gd b/client/network/PlayerAdd.gd index f214d7d..a874177 100644 --- a/client/network/PlayerAdd.gd +++ b/client/network/PlayerAdd.gd @@ -41,12 +41,11 @@ func spawn_player(id: String) -> Player: player.id = id if id == Global.account_id: - player.controller = PlayerController.new() + player.controller = PlayerController.new(player) Global.player = player main_player_spawned.emit(player) else: - player.controller = ProxyController.new() + player.controller = ProxyController.new(player) - player.controller.character = player player.add_child(player.controller) return player diff --git a/client/player/AnimationController.gd b/client/player/AnimationController.gd deleted file mode 100644 index b433780..0000000 --- a/client/player/AnimationController.gd +++ /dev/null @@ -1,64 +0,0 @@ -class_name AnimationController -extends Node - -@export var character: Character -@export var animation_player: AnimationPlayer - -var next_animation: StringName = "RESET" - -func _ready(): - assert(character) - assert(animation_player) - -func _process(_delta): - if character.velocity.y > 0: - play("human/jump") - elif character.velocity.y < 0: - play("human/fall") - elif character.direction != Vector3.ZERO: - play("human/run-fast") - else: - play("human/idle") - - if animation_player.current_animation == next_animation: - return - - animation_player.play(next_animation) - -func play(action_name: StringName): - next_animation = action_name - -# func air(y_velocity: float): -# if y_velocity > 0: -# play("rifle_jump") -# else: -# play("falling") - -# func aim(move: Vector2, is_shooting: bool): -# if move.x > 0: -# play("rifle_aim_strafe_right") -# elif move.x < 0: -# play("rifle_aim_strafe_left") -# elif move.y < 0: -# play("rifle_aim_walk_forward") -# elif move.y > 0: -# play("rifle_aim_walk_backward") -# else: -# play("rifle_aim") - -# if is_shooting: -# play("rifle_shoot") - -# func run(move: Vector2, is_shooting: bool): -# if move.y < 0: -# play("rifle_run_forward") -# elif move.y > 0: -# play("rifle_run_backward") -# elif move.x > 0: -# play("rifle_run_right") -# elif move.x < 0: -# play("rifle_run_left") -# elif is_shooting: -# play("rifle_shoot") -# else: -# play("rifle_idle") diff --git a/client/player/Player.gd b/client/player/Player.gd index 70711ec..906609c 100644 --- a/client/player/Player.gd +++ b/client/player/Player.gd @@ -1,8 +1,29 @@ class_name Player -extends Character +extends CharacterBody3D + +signal attacked +signal dashed +signal jumped +signal direction_changed + +var controller: Controller + +func attack(): + attacked.emit() + +func dash(): + dashed.emit() + +func jump(): + jumped.emit() + +func set_direction(direction: Vector3): + direction_changed.emit(direction) + +# TODO: Remove this: var id: String func set_character_name(new_name: String): name = new_name - get_node("Label").text = name \ No newline at end of file + $Label.text = name diff --git a/client/player/Player.tscn b/client/player/Player.tscn index 95f68b1..fbd920a 100644 --- a/client/player/Player.tscn +++ b/client/player/Player.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=11 format=3 uid="uid://2lcnu3dy54lx"] +[gd_scene load_steps=13 format=3 uid="uid://2lcnu3dy54lx"] [ext_resource type="Script" path="res://player/Player.gd" id="1_8gebs"] [ext_resource type="PackedScene" uid="uid://c8j7t4yg7anb0" path="res://assets/female/Female.blend" id="2_8nah6"] @@ -6,17 +6,18 @@ [ext_resource type="PackedScene" uid="uid://cgqbkj8wbcatv" path="res://assets/hair/PonyTail.blend" id="3_umw6q"] [ext_resource type="FontFile" uid="uid://b7mov13kwi8u8" path="res://assets/font/ubuntu_nf_regular.ttf" id="4_76ehj"] [ext_resource type="Skin" uid="uid://bbqyiue1vj37f" path="res://assets/hoodie/Hoodie_Skin.tres" id="4_b1tg1"] -[ext_resource type="Script" path="res://player/AnimationController.gd" id="4_i2ybk"] [ext_resource type="ArrayMesh" uid="uid://b3qvgfg41b7jo" path="res://assets/hoodie/Hoodie_Mesh.res" id="5_mkrgn"] -[ext_resource type="AnimationLibrary" uid="uid://d4n0puibh4hyt" path="res://assets/animations/human.blend" id="6_fl6or"] +[ext_resource type="PackedScene" uid="uid://x102pryt2s5a" path="res://character/movement/MovementComponent.tscn" id="8_25qd0"] +[ext_resource type="PackedScene" uid="uid://d0onbq0ad1ap4" path="res://character/rotation/RotationComponent.tscn" id="9_agxqu"] +[ext_resource type="PackedScene" uid="uid://bivxnxwi863o0" path="res://character/animation/AnimationComponent.tscn" id="10_bcaeg"] +[ext_resource type="AnimationLibrary" uid="uid://d4n0puibh4hyt" path="res://assets/animations/human.blend" id="11_d0e6r"] [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_2f50n"] radius = 0.25 height = 1.6 -[node name="Player" type="CharacterBody3D" node_paths=PackedStringArray("model") groups=["player"]] +[node name="Player" type="CharacterBody3D" groups=["player"]] script = ExtResource("1_8gebs") -model = NodePath("Model") [node name="Model" type="Node3D" parent="."] @@ -94,20 +95,6 @@ bone_idx = 12 transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.8, 0) shape = SubResource("CapsuleShape3D_2f50n") -[node name="Animation" type="Node" parent="." node_paths=PackedStringArray("character", "animation_player")] -script = ExtResource("4_i2ybk") -character = NodePath("..") -animation_player = NodePath("../AnimationPlayer") - -[node name="Health" parent="." instance=ExtResource("2_np5ag")] - -[node name="AnimationPlayer" type="AnimationPlayer" parent="."] -root_node = NodePath("../Model/Female") -libraries = { -"human": ExtResource("6_fl6or") -} -playback_default_blend_time = 0.2 - [node name="Label" type="Label3D" parent="."] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0) pixel_size = 0.001 @@ -119,4 +106,20 @@ font = ExtResource("4_76ehj") font_size = 128 outline_size = 32 +[node name="Health" parent="." instance=ExtResource("2_np5ag")] + +[node name="Movement" parent="." instance=ExtResource("8_25qd0")] + +[node name="Rotation" parent="." node_paths=PackedStringArray("root") instance=ExtResource("9_agxqu")] +root = NodePath("../Model") + +[node name="Animation" parent="." instance=ExtResource("10_bcaeg")] + +[node name="AnimationPlayer" parent="Animation" index="0"] +root_node = NodePath("../../Model/Female") +libraries = { +"human": ExtResource("11_d0e6r") +} + [editable path="Model/Female"] +[editable path="Animation"] diff --git a/client/player/controller/Controller.gd b/client/player/controller/Controller.gd deleted file mode 100644 index d39ae8d..0000000 --- a/client/player/controller/Controller.gd +++ /dev/null @@ -1,5 +0,0 @@ -class_name Controller -extends Node - -## The character that we're controlling. -@export var character: Character \ No newline at end of file diff --git a/client/player/controller/PlayerController.gd b/client/player/controller/PlayerController.gd deleted file mode 100644 index c5c30c6..0000000 --- a/client/player/controller/PlayerController.gd +++ /dev/null @@ -1,22 +0,0 @@ -class_name PlayerController -extends Controller - -var move: Vector2 - -func _unhandled_input(event): - if Global.interacting_with_ui: - return - - move = Input.get_vector("move_left", "move_right", "move_forward", "move_backward") - character.direction = (Global.camera.transform.basis * Vector3(move.x, 0, move.y)) - character.direction.y = 0 - character.direction = character.direction.normalized() - - if event.is_action_pressed("jump"): - character.jump() - - if event.is_action_pressed("dash"): - character.dash() - - if event.is_action_pressed("attack"): - character.attack() diff --git a/client/player/controller/ProxyController.gd b/client/player/controller/ProxyController.gd deleted file mode 100644 index 541d6e9..0000000 --- a/client/player/controller/ProxyController.gd +++ /dev/null @@ -1,19 +0,0 @@ -class_name ProxyController -extends Controller - -## The authoritative position on the server. -var server_position: Vector3 - -func _ready(): - server_position = character.position - -func _process(_delta): - var move := server_position - character.position - move.y = 0.0 - - if move.length_squared() < 0.01: - character.direction = Vector3.ZERO - return - - character.direction = Vector3(move.x, 0, move.z) - character.direction = character.direction.normalized() \ No newline at end of file