init
This commit is contained in:
222
Scripts/Player.gd
Normal file
222
Scripts/Player.gd
Normal 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())
|
||||
Reference in New Issue
Block a user