diff options
Diffstat (limited to 'client/player/controllable_player.gd')
-rw-r--r-- | client/player/controllable_player.gd | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/client/player/controllable_player.gd b/client/player/controllable_player.gd new file mode 100644 index 00000000..4c157349 --- /dev/null +++ b/client/player/controllable_player.gd @@ -0,0 +1,110 @@ +# Undercooked - a game about cooking +# Copyright 2024 nokoe +# Copyright 2024 metamuffin +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, version 3 of the License only. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +class_name ControllablePlayer +extends Player + + +const PLAYER_SPEED: float = 25.; + +var facing = Vector2(1, 0) +var velocity_ = Vector2(0, 0) + +var target: Vector2i = Vector2i(0, 0) + +func _ready(): + var timer = Timer.new() + timer.one_shot = false + timer.wait_time = 1. / 25. + add_child(timer) + timer.start() + timer.connect("timeout", func(): + Multiplayer.send_position(Vector2(position.x, position.z), rotation.y) + ) + +func _process(delta): + var input = Vector2(Input.get_axis("left", "right"), Input.get_axis("forward", "backwards")).normalized() + input = input.rotated(-game.camera.angle_target) + position_anim = position_ + rotation_anim = rotation_ + if Input.is_action_pressed("interact") or Input.is_action_just_released("interact"): + input *= 0 + else: + target = Vector2i( + int(floor(position.x + sin(rotation.y))), + int(floor(position.z + cos(rotation.y))) + ) + interact() + update(delta, input) + super(delta) + +func update(dt: float, input: Vector2): + var direction = input.limit_length(1.); + rotation.y = atan2(self.facing.x, self.facing.y); + if direction.length() > 0.1: + self.facing = direction + (self.facing - direction) * exp(-dt * 10.); + self.velocity_ += direction * dt * PLAYER_SPEED; + self.position_ += self.velocity_ * dt; + self.velocity_ = self.velocity_ * exp(-dt * 5.); + collide(dt); + +func collide(dt: float): + for xo in range(-1,2): + for yo in range(-1,2): + var tile = Vector2i(xo, yo) + Vector2i(self.position_); + if !Multiplayer.get_tile_collision(tile): continue + tile = Vector2(tile) + var d = aabb_point_distance(tile, tile + Vector2.ONE, self.position_); + if d > PLAYER_SIZE: continue + var h = 0.01; + var d_sample_x = aabb_point_distance(tile, tile + Vector2.ONE, self.position_ + Vector2(h, 0)); + var d_sample_y = aabb_point_distance(tile, tile + Vector2.ONE, self.position_ + Vector2(0, h)); + var grad = (Vector2(d_sample_x - d, d_sample_y - d)) / h; + + self.position_ += (PLAYER_SIZE - d) * grad; + self.velocity_ -= grad * grad.dot(self.velocity_) + + for player: Player in game.players.values(): + var diff = self.position_ - player.position_ + var d = diff.length() + if d < 0.01: continue + if d >= PLAYER_SIZE * 2: continue + var norm = diff.normalized(); + var f = 100 / (1 + d) + self.velocity_.x += norm.x * f * dt + self.velocity_.y += norm.y * f * dt + +func aabb_point_distance(mi: Vector2, ma: Vector2, p: Vector2) -> float: + return (p - p.clamp(mi, ma)).length() + +func update_position(new_position: Vector2, _new_rotation: float): + if (new_position - position_).length() > 3.: + position_ = new_position + +func interact(): + var tile_idx = str(target) + var t: Floor = game.map.tile_by_pos.get(tile_idx) + if t != null: + game.marker.set_interactive(Multiplayer.get_tile_interactive(target)) + game.marker.visible = true + game.marker_target = t.item_base.global_position + if Input.is_action_just_pressed("interact"): + Multiplayer.send_interact(target, true) + t.interact() + elif Input.is_action_just_released("interact"): + Multiplayer.send_interact(target, false) + else: + game.marker.visible = false |