# Hurry Curry! - a game about cooking # Copyright 2024 metamuffin # Copyright 2024 tpart # Copyright 2024 nokoe # # 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 . # class_name ControllablePlayer extends Player const PLAYER_FRICTION = 10 const PLAYER_SPEED = 55 const BOOST_FACTOR = 2.5 const BOOST_DURATION = 0.3 const BOOST_RESTORE = 0.5 var onscreen_controls = preload("res://player/onscreen_controls/controls.tscn").instantiate() var facing = Vector2(1, 0) var velocity_ = Vector2(0, 0) var stamina = 0 var chat_open := false var enable_input := true 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(): if game.mp != null: game.mp.send_position(position_, rotation_, boosting) ) add_child(onscreen_controls) super() chat_bubble.submit_message.connect(submit_message) func _input(_event): if Input.is_action_just_pressed("chat"): if chat_open: chat_bubble.stop_edit() else: chat_bubble.edit() chat_open = !chat_open enable_input = !enable_input const MAX_DT = 1./50. func _process(delta): marker.position = G.interpolate(marker.position, marker_target, delta * 30.) while delta > 0.001: var dt = min(delta, MAX_DT) _process_movement(dt) delta -= dt super(delta) func _process_movement(delta): var input = Input.get_vector("left", "right", "forward", "backwards") if enable_input else Vector2.ZERO var boost = Input.is_action_pressed("boost") or (Global.get_setting("latch_boost") and boosting) input = input.rotated( - game.camera.angle_target) if Input.is_action_pressed("interact") or Input.is_action_just_released("interact"): input *= 0 else: target = Vector2i( int(floor(movement_base.position.x + sin(movement_base.rotation.y))), int(floor(movement_base.position.z + cos(movement_base.rotation.y))) ) interact() var was_boosting = boosting update(delta, input, boost) if boosting and not was_boosting: Input.start_joy_vibration(0, 0, 1, 0.15) walking = input.length_squared() > 0.1 position_anim = position_ rotation_anim = rotation_ func update(dt: float, input: Vector2, boost: bool): input = input.limit_length(1.); if input.length() > 0.1: self.facing = input + (self.facing - input) * exp( - dt * 10.) rotation_ = atan2(self.facing.x, self.facing.y); boost = boost and input.length() > 0.1 boosting = boost and (boosting or stamina >= 1.0) and stamina > 0 if boosting: stamina -= dt / BOOST_DURATION else: stamina += dt / BOOST_RESTORE stamina = max(min(stamina, 1.0), 0.0) var speed = PLAYER_SPEED * (BOOST_FACTOR if boosting else 1.) self.velocity_ += input * dt * speed self.position_ += self.velocity_ * dt self.velocity_ = self.velocity_ * exp( - dt * 15.) 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 !game.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, _new_boosting: bool): pass func submit_message(text: String): game.mp.send_chat(text) func progress(p: float, warn: bool): super(p, warn) Input.start_joy_vibration(0, 0.5, 0.1, 0.15) func put_item(tile: Tile): super(tile) Input.start_joy_vibration(0, 0.1, 0.0, 0.075) func take_item(tile: Tile): super(tile) Input.start_joy_vibration(0, 0.1, 0.0, 0.075) func interact(): if not enable_input: return var tile = game.map.get_tile_instance(target) if tile != null: marker.set_interactive(game.get_tile_interactive(target)) marker.visible = true marker_target = tile.item_base.global_position if Input.is_action_just_pressed("interact"): game.mp.send_tile_interact(target, true) tile.interact() elif Input.is_action_just_released("interact"): game.mp.send_tile_interact(target, false) else: marker.visible = false func set_input_enabled(b: bool): enable_input = b