This commit is contained in:
WangXiang
2025-12-22 18:57:51 +08:00
commit 6119faf53e
159 changed files with 19162 additions and 0 deletions

222
Scripts/Player.gd Normal file
View File

@@ -0,0 +1,222 @@
extends CharacterBody2D
@export var grid_size := 16
var player_id: int = -1
var is_local := false
var is_moving := false
var server_position := Vector2.ZERO
signal interaction_request(target_id, target_name)
@onready var ray = $RayCast2D
func _ready():
server_position = position
# Initial sprite setup
$Sprite2D.scale = Vector2(0.5, 0.5)
$Sprite2D.frame = 1
# Physics Collision (Movement)
collision_layer = 2 # Force Player to be on Layer 2
collision_mask = 1 # Only collide with World (Layer 1), walk through other Players (Layer 2)
# RayCast Setup
ray.enabled = true
ray.hit_from_inside = true # Detect if overlapping
ray.collision_mask = 3 # Layers 1 (World) and 2 (Player)
ray.add_exception(self) # Ignore local player
if is_local:
var cam = Camera2D.new()
cam.zoom = Vector2(1.0, 1.0)
cam.position_smoothing_enabled = true
add_child(cam)
NetworkManager.chat_message_received.connect(_on_chat_message)
# Set Name Label
var name_label = $NameLabel
if is_local:
name_label.text = NetworkManager.player_info["name"]
name_label.modulate = Color(0.5, 1, 0.5) # Highlight local player
elif player_id != -1 and NetworkManager.players.has(player_id):
name_label.text = NetworkManager.players[player_id].name
func _physics_process(_delta):
if is_local:
_process_input()
else:
_process_remote_movement()
# Interaction Check (F Key) moved to _input to prevent spam
var is_sitting := false
var current_chair: Node2D = null
func _process_input():
# Stop input if chatting
var focus_owner = get_viewport().gui_get_focus_owner()
if focus_owner is LineEdit:
return
if is_moving or is_sitting:
return
var input_dir := Vector2.ZERO
if Input.is_action_pressed("ui_up") or Input.is_key_pressed(KEY_W):
input_dir = Vector2.UP
$Sprite2D.frame = 4 # Row 1, Center (Back view)
$Sprite2D.flip_h = false
ray.target_position = Vector2(0, -96)
elif Input.is_action_pressed("ui_down") or Input.is_key_pressed(KEY_S):
input_dir = Vector2.DOWN
$Sprite2D.frame = 1 # Row 0, Center (Front view)
$Sprite2D.flip_h = false
ray.target_position = Vector2(0, 96)
elif Input.is_action_pressed("ui_left") or Input.is_key_pressed(KEY_A):
input_dir = Vector2.LEFT
$Sprite2D.frame = 3 # Row 1, Left (Side view)
$Sprite2D.flip_h = false
ray.target_position = Vector2(-96, 0)
elif Input.is_action_pressed("ui_right") or Input.is_key_pressed(KEY_D):
input_dir = Vector2.RIGHT
$Sprite2D.frame = 3 # Use same side view
$Sprite2D.flip_h = true # Flip it
ray.target_position = Vector2(96, 0)
if input_dir != Vector2.ZERO:
_attempt_move(input_dir)
func _input(event):
if not is_local:
return
if event is InputEventKey and event.pressed and not event.echo and event.keycode == KEY_F:
# Check if ignoring input (chatting)
var focus_owner = get_viewport().gui_get_focus_owner()
if focus_owner is LineEdit:
return
if is_sitting:
stand_up()
return
ray.force_raycast_update()
if ray.is_colliding():
var collider = ray.get_collider()
# Check if collider is a player (ID-based name)
if collider:
if collider.has_method("interact"):
var text = collider.interact()
if text:
show_bubble(text) # Show response locally for now
elif collider.name.is_valid_int():
var target_id = int(str(collider.name))
var p_info = NetworkManager.players.get(target_id)
var t_name = p_info["name"] if p_info else "Unknown"
interaction_request.emit(target_id, t_name)
func start_sitting(target_pos: Vector2, chair: Node2D):
if is_sitting:
return
is_sitting = true
is_moving = false # Force stop moving
current_chair = chair
# Disable physics/collision
set_physics_process(false)
$CollisionShape2D.set_deferred("disabled", true)
# Tween to seat
var tween = create_tween()
tween.tween_property(self, "position", target_pos, 0.3).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_OUT)
# Visuals
$Sprite2D.frame = 1 # Sit/Idle Front
$Sprite2D.flip_h = false
# You might want to offset Z-index if chair has backrest vs stool
# z_index = 0 # Default
func stand_up():
if not is_sitting:
return
is_sitting = false
# Notify chair
if current_chair and current_chair.has_method("on_player_stand_up"):
current_chair.on_player_stand_up()
current_chair = null
# Restore physics
set_physics_process(true)
$CollisionShape2D.set_deferred("disabled", false)
# Optional: Move slightly forward to avoid clipping immediately if collision enables
var exit_pos = position + Vector2(0, 10)
position = exit_pos
NetworkManager.send_move(position.x, position.y, $Sprite2D.flip_h, $Sprite2D.frame)
func _attempt_move(dir: Vector2):
var target_pos = position + dir * grid_size
# Save state
var old_target = ray.target_position
var old_mask = ray.collision_mask
var old_hfi = ray.hit_from_inside
var old_cwa = ray.collide_with_areas
# Configure for movement check (World Only, Short Range, Bodies Only)
ray.target_position = dir * grid_size
ray.collision_mask = 1
ray.hit_from_inside = false
ray.collide_with_areas = false # Ignore Areas (like Doors), only hit Walls (Bodies)
ray.force_raycast_update()
var blocked = ray.is_colliding()
# Restore state for Chat Interaction
ray.target_position = old_target
ray.collision_mask = old_mask
ray.hit_from_inside = old_hfi
ray.collide_with_areas = old_cwa
if not blocked:
_tween_movement(target_pos)
# Send to server WITH orientation
NetworkManager.send_move(target_pos.x, target_pos.y, $Sprite2D.flip_h, $Sprite2D.frame)
func _process_remote_movement():
if position != server_position and not is_moving:
_tween_movement(server_position)
func set_remote_state(pos: Vector2, flip_h: bool, frame: int):
if is_local:
return # Do not let remote updates override local input
server_position = pos
$Sprite2D.flip_h = flip_h
$Sprite2D.frame = frame
func _tween_movement(target_pos: Vector2):
is_moving = true
var tween = create_tween()
tween.tween_property(self, "position", target_pos, 0.2)
tween.tween_callback(func(): is_moving = false)
func _on_chat_message(sender_id, text):
if sender_id == player_id:
show_bubble(text)
func show_bubble(text):
$NameLabel.hide()
var bubble = preload("res://Scenes/UI/ChatBubble.tscn").instantiate()
add_child(bubble)
bubble.set_text(text)
bubble.tree_exited.connect(func(): $NameLabel.show())