diff options
Diffstat (limited to 'client')
| -rw-r--r-- | client/game.gd | 4 | ||||
| -rw-r--r-- | client/multiplayer.gd | 12 | ||||
| -rw-r--r-- | client/player/controllable_player.gd | 226 | ||||
| -rw-r--r-- | client/player/marker/marker.gd | 6 | ||||
| -rw-r--r-- | client/system/settings.gd | 1 |
5 files changed, 110 insertions, 139 deletions
diff --git a/client/game.gd b/client/game.gd index 18b23e08..d490e61e 100644 --- a/client/game.gd +++ b/client/game.gd @@ -396,7 +396,7 @@ func handle_packet(p): overlay_score.set_paused(p.state) Global.game_paused = p.state - _: push_error("Unrecognized packet type: %s" % p.type) + _: push_warning("Unrecognized packet type: %s" % p.type) func system_message(s: String): var message = TextMessage.new() @@ -431,7 +431,7 @@ func get_tile_collision(pos: Vector2i) -> bool: if t == null: return true else: return not tile_walkable.has(tile_index_by_name[t]) -func get_tile_interactive(pos: Vector2i, hands: Array) -> bool: +func is_tile_interactive(pos: Vector2i, hands: Array) -> bool: var tile_name = map.get_tile_name(pos) if tile_name == null: return false var tile = tile_index_by_name[tile_name] diff --git a/client/multiplayer.gd b/client/multiplayer.gd index d635db41..d5221b15 100644 --- a/client/multiplayer.gd +++ b/client/multiplayer.gd @@ -110,12 +110,18 @@ func send_tile_interact(player, pos: Vector2i, edge: bool, hand: int): send_packet({ "type": "interact", "player": player, + "target": {"tile": [pos.x, pos.y]} if edge else null, "hand": hand, - "pos": [pos.x, pos.y] if edge else null, }) -func send_player_interact(_player, _edge: bool): - push_error("not yet implemented") +func send_player_interact(player, target_player, target_hand: int, edge: bool, hand: int): + @warning_ignore("incompatible_ternary") + send_packet({ + "type": "interact", + "player": player, + "target": {"player": [target_player, target_hand]} if edge else null, + "hand": hand, + }) func send_chat(player, message: String): send_packet({ diff --git a/client/player/controllable_player.gd b/client/player/controllable_player.gd index 83d1bdce..3ab60590 100644 --- a/client/player/controllable_player.gd +++ b/client/player/controllable_player.gd @@ -16,6 +16,29 @@ class_name ControllablePlayer extends Player +@abstract class InteractTarget: + var target_visual_pos: Vector3 + var target_visual_rot: float + +class EmptyTarget extends InteractTarget: + pass + +class PlayerTarget extends InteractTarget: + var player: Player + func _init(player_: Player, target_visual_pos_: Vector3, target_visual_rot_: float) -> void: + player = player_ + target_visual_pos = target_visual_pos_ + target_visual_rot = target_visual_rot_ + +class TileTarget extends InteractTarget: + var pos: Vector2i + var tile: Tile + func _init(pos_: Vector2i, tile_: Tile, target_visual_pos_: Vector3, target_visual_rot_: float) -> void: + pos = pos_ + tile = tile_ + target_visual_pos = target_visual_pos_ + target_visual_rot = target_visual_rot_ + const PLAYER_SPEED = 55 const PLAYER_FRICTION = 15 const BOOST_FACTOR = 2.5 @@ -26,6 +49,7 @@ const MAX_PLAYER_INTERACT_DIST := 1.9 var onscreen_controls = preload("res://player/onscreen_controls/controls.tscn").instantiate() var marker: Marker = preload("res://player/marker/marker.tscn").instantiate() +var current_interact_target: InteractTarget = EmptyTarget.new() var facing := Vector2(1, 0) var velocity_ := Vector2(0, 0) var direction := Vector2(0, 0) @@ -37,12 +61,6 @@ var vibration_timer := Timer.new() var current_vibration_strength := 0. var current_vibration_change := 0. -var target_tile: Vector2i = Vector2i.ZERO -var target_visual: Vector3 = Vector3.ZERO -var found_interact_target := false - -var last_interaction = null # : Vector2i? - func _ready(): vibration_timer = Timer.new() vibration_timer.wait_time = 0.1 @@ -68,7 +86,7 @@ func _ready(): const MAX_DT = 1. / 50. func _process(delta): super(delta) - marker.position = G.interpolate(marker.position, target_visual, delta * 30.) + marker.position = G.interpolate(marker.position, current_interact_target.target_visual_pos, delta * 30.) if is_despawning: return while delta > 0.001: var dt = min(delta, MAX_DT) @@ -91,7 +109,6 @@ func _input(event: InputEvent): _: return if event.pressed: Input.action_press(action) else: Input.action_release(action) - var fps_look = Vector2(0., 0.) func _process_movement(delta): @@ -100,7 +117,6 @@ func _process_movement(delta): if Settings.read("gameplay.first_person"): input = (input + Vector2(0.0, -0.1)).rotated(fps_look.y) else: input = input.rotated(input_rotation) - var boost = Input.is_action_pressed("boost") or (Settings.read("gameplay.latch_boost") and boosting) if (Input.is_action_pressed("interact_left") or Input.is_action_just_released("interact_left") @@ -108,12 +124,15 @@ func _process_movement(delta): or Input.is_action_just_released("interact_right")): input *= 0 else: - update_interact_target() + if Settings.read("gameplay.first_person"): current_interact_target = get_interact_target_fps() + else: current_interact_target = get_interact_target() - interact() + interact(current_interact_target) + + var boost = Input.is_action_pressed("boost") or (Settings.read("gameplay.latch_boost") and boosting) var was_boosting = boosting direction = input - update(delta, boost) + update_movement(delta, boost) if boosting and not was_boosting and Settings.read("gameplay.vibration"): Input.start_joy_vibration(0, 0, input.length(), 0.15) Input.vibrate_handheld(75, input.length() * 0.1) @@ -121,7 +140,9 @@ func _process_movement(delta): position_anim = position_ rotation_anim = rotation_ -func update(dt: float, boost: bool): +func update_movement(dt: float, boost: bool): + # This function implements the server's movement system. + # It may not be modified, so that it matches the server's logic. direction = direction.limit_length(1.) if direction.length() > 0.05: facing = direction + (facing - direction) * exp(-dt * 10.) @@ -154,7 +175,6 @@ func collide(dt: float): position_ += (PLAYER_SIZE - d) * grad; velocity_ -= grad * grad.dot(velocity_) - for player: Player in game.players.values(): var diff = position_ - player.position_ var d = diff.length() @@ -175,12 +195,15 @@ func update_touch_scrolls(): onscreen_controls.visible = is_input_enabled() func aabb_point_distance(mi: Vector2, ma: Vector2, p: Vector2) -> float: + # Calculates the signed distance of a point p to an axis aligned bounding box return (p - p.clamp(mi, ma)).length() func update_position(_new_position: Vector2, _new_rotation: float, _new_boosting: bool): + # Ignore movement packets from server. (This is not a movement sync) pass func progress(position__: float, speed: float, warn: bool, h): + # An item the player is holding is making progress super(position__, speed, warn, h) if warn: current_vibration_strength = position__ @@ -215,135 +238,78 @@ func take_item(tile: Tile, h: int): Input.start_joy_vibration(0, 0.1, 0.0, 0.075) Input.vibrate_handheld(75, 0.1) -func interact(): +func interact(interact_target: InteractTarget): if not is_input_enabled(): return - var tile = game.map.get_tile_instance(target_tile) - if tile != null: + if interact_target is EmptyTarget: + marker.visible = false + marker.rotation.y = 0. + return + else: if not marker.visible: + # New target acquired! marker.visible = true - marker.position = target_visual - - # clear last interaction if target_tile has moved since - if last_interaction != null and not last_interaction == target_tile: - game.mp.send_tile_interact(game.my_player_id, last_interaction, false, 0) - marker.set_interacting(false) - last_interaction = null - marker.set_interactive(found_interact_target) - if found_interact_target: - for h in [0, 1]: - if Input.is_action_just_pressed("interact_" + G.index_to_hand(h)) and last_interaction == null: - last_interaction = target_tile - game.mp.send_tile_interact(game.my_player_id, target_tile, true, h if h < Global.hand_count else 0) - tile.interact() - marker.set_interacting(true) - if Input.is_action_just_released("interact_" + G.index_to_hand(h)): - last_interaction = null - game.mp.send_tile_interact(game.my_player_id, target_tile, false, h if h < Global.hand_count else 0) - marker.set_interacting(false) - else: - marker.visible = false - -func update_interact_target(): - if Settings.read("gameplay.first_person"): - return update_interact_target_fps() - match Settings.read("gameplay.interact_target"): - "dirsnap": return update_interact_target_dirsnap() - "dir": return update_interact_target_dir() - _: return update_interact_target_dir() + marker.position = interact_target.target_visual_pos + marker.rotation.y = interact_target.target_visual_rot + + if interact_target is TileTarget: + for h in [0, 1]: + var hand_: int = h if h < Global.hand_count else 0 + if Input.is_action_just_pressed("interact_" + G.index_to_hand(h)) and not marker.interacting: + game.mp.send_tile_interact(game.my_player_id, interact_target.pos, true, hand_) + interact_target.tile.interact() + marker.set_interacting(true) + if Input.is_action_just_released("interact_" + G.index_to_hand(h)): + game.mp.send_tile_interact(game.my_player_id, interact_target.pos, false, hand_) + marker.set_interacting(false) + elif interact_target is PlayerTarget: + for h in [0, 1]: + var hand_: int = h if h < Global.hand_count else 0 + if Input.is_action_just_pressed("interact_" + G.index_to_hand(h)) and not marker.interacting: + game.mp.send_player_interact(game.my_player_id, interact_target.player.id, hand_, true, hand_) + marker.set_interacting(true) + if Input.is_action_just_released("interact_" + G.index_to_hand(h)): + game.mp.send_player_interact(game.my_player_id, interact_target.player.id, hand_, false, hand_) + marker.set_interacting(false) -func update_interact_target_dir(): - target_tile = Vector2i( - int(floor(movement_base.position.x + sin(movement_base.rotation.y))), - int(floor(movement_base.position.z + cos(movement_base.rotation.y))) - ) - var tile = game.map.get_tile_instance(target_tile) - if tile != null: - found_interact_target = game.get_tile_interactive(target_tile, hand) - target_visual = tile.item_base.global_position - else: - found_interact_target = false - target_visual = Vector3(float(target_tile.x), 1., float(target_tile.y)) +func get_interact_target_fps() -> InteractTarget: + # TODO! + return EmptyTarget.new() -func update_interact_target_fps(): - target_tile = Vector2i( - int(floor(movement_base.position.x + sin(-fps_look.y + PI))), - int(floor(movement_base.position.z + cos(-fps_look.y + PI))) +func get_interact_target() -> InteractTarget: + var movement_base_2d := Vector2(movement_base.position.x, movement_base.position.z) + var interact_target_pos := movement_base_2d + Vector2( + sin(movement_base.rotation.y) * 0.7, + cos(movement_base.rotation.y) * 0.7 ) - var tile = game.map.get_tile_instance(target_tile) - if tile != null: - found_interact_target = game.get_tile_interactive(target_tile, hand) - target_visual = tile.item_base.global_position - else: - found_interact_target = false - target_visual = Vector3(float(target_tile.x), 1., float(target_tile.y)) + var interact_target_pos_i := interact_target_pos.floor() - -func update_interact_target_dirsnap(): - var interact_target := Vector2( - movement_base.position.x + sin(movement_base.rotation.y) * 0.7, - movement_base.position.z + cos(movement_base.rotation.y) * 0.7 - ) - var interact_target_i := interact_target.floor() - target_visual = Vector3(interact_target_i.x, 0, interact_target_i.y) - target_tile = interact_target_i + var best_interact_target: InteractTarget = EmptyTarget.new() var best_distance := 100. - found_interact_target = false - # Calculate player positions. Tiles with players on them are valid interact targets. - var player_positions: Dictionary = {} # Dictionary[id: int, pos: Vector3] for p: Player in game.players.values(): - if not p.is_chef: continue - player_positions[p.id] = Vector3(p.position_anim.x, 0, p.position_anim.y) + if not p.is_chef: continue # Customers cannot be interacted with + if p.id == game.my_player_id: continue # I can't interact with myself + var distance: float = p.position_anim.distance_to(interact_target_pos) + var self_target_distance: float = p.position_anim.distance_to(movement_base_2d) + if self_target_distance < MAX_PLAYER_INTERACT_DIST and distance < best_distance: + best_distance = distance + best_interact_target = PlayerTarget.new(p, Vector3(p.position_anim.x, 0, p.position_anim.y), p.rotation_anim) # Test all tiles in a 3x3 square around the player for interactible tiles. - # Return the one which is closest to interact_target. + # Return the one which is closest to interact_target_pos. for offset_x in range(-1, 2): - for offset_y in range (-1, 2): - var offset_cursor := interact_target_i + Vector2(offset_x, offset_y) + for offset_y in range(-1, 2): + var offset_cursor := interact_target_pos_i + Vector2(offset_x, offset_y) var tile_center := Vector2(offset_cursor) + Vector2(0.5, 0.5) - if game.get_tile_interactive(offset_cursor, hand): - var cursor_tile_distance := interact_target.distance_to(tile_center) - var player_tile_distance := Vector2( - movement_base.position.x - tile_center.x, - movement_base.position.z - tile_center.y - ).length() - if player_tile_distance < MAX_PLAYER_INTERACT_DIST && cursor_tile_distance < best_distance: - found_interact_target = true - best_distance = cursor_tile_distance - var tile = game.map.get_tile_instance(offset_cursor) - target_visual = tile.item_base.global_position - if tile.item != null and not tile.item.is_round(): - marker.rotation.y = tile.item.rotation.y - else: marker.rotation.y = 0. - target_tile = offset_cursor - continue - - # Check if there are any players on this tile. - # If there are multilpe, remember the player closest to the center of the tile - # (They will be the interact target) - var best_cursor_tile_distance := 100. - var best_player_tile_distance := 100. - var best_player_pos: Vector3 - var best_player_rot: float - for p_id in player_positions.keys(): - if p_id == game.my_player_id: continue # I can't interact with myself - var p_pos: Vector3 = player_positions[p_id] - var p_pos_2d := Vector2(p_pos.x, p_pos.z) - var tile_center_distance := p_pos_2d.distance_to(tile_center) - var cursor_tile_distance := interact_target.distance_to(tile_center) - var player_tile_distance := Vector2(movement_base.position.x, movement_base.position.z).distance_to(tile_center) - if tile_center_distance < 0.7: - if cursor_tile_distance < best_cursor_tile_distance: - best_cursor_tile_distance = cursor_tile_distance - best_player_tile_distance = player_tile_distance - best_player_pos = p_pos - best_player_rot = game.players[p_id].rotation_anim - - if best_player_tile_distance < MAX_PLAYER_INTERACT_DIST && best_cursor_tile_distance < best_distance: - found_interact_target = true - best_distance = best_cursor_tile_distance - target_visual = best_player_pos - marker.rotation.y = best_player_rot - target_tile = offset_cursor + if game.is_tile_interactive(offset_cursor, hand): + var distance := interact_target_pos.distance_to(tile_center) + var self_target_distance := movement_base_2d.distance_to(tile_center) + if self_target_distance < MAX_PLAYER_INTERACT_DIST && distance < best_distance: + best_distance = distance + var tile := game.map.get_tile_instance(offset_cursor) + var target_rot := tile.item.rotation.y if tile.item != null and not tile.item.is_round() else 0. + best_interact_target = TileTarget.new(offset_cursor, tile, tile.item_base.global_position, target_rot) + + return best_interact_target diff --git a/client/player/marker/marker.gd b/client/player/marker/marker.gd index 31c99e2d..7f9616c2 100644 --- a/client/player/marker/marker.gd +++ b/client/player/marker/marker.gd @@ -16,11 +16,11 @@ class_name Marker extends Node3D +var interacting := false + @onready var _cube: MeshInstance3D = $Cube @onready var mat: ShaderMaterial = _cube.get_active_material(0) -func set_interactive(val: bool): - visible = val - func set_interacting(val: bool): mat.set_shader_parameter("interacting", val) + interacting = val diff --git a/client/system/settings.gd b/client/system/settings.gd index 5fb9de82..4ab16fbf 100644 --- a/client/system/settings.gd +++ b/client/system/settings.gd @@ -27,7 +27,6 @@ static func get_root(): ButtonSetting.new("setup_completed", false, launch_setup), ToggleSetting.new("tutorial_disabled", false), ToggleSetting.new("first_person", false), - DropdownSetting.new("interact_target", "dirsnap", ["dir", "dirsnap"]), PathSetting.new("screenshot_path", "", FileDialog.FileMode.FILE_MODE_OPEN_DIR), ]), SettingsCategory.new("graphics", [ |