feat: Implement core player character logic, including state management, network synchronization, character selection, and manager initialization.
This commit is contained in:
+92
-9
@@ -975,6 +975,8 @@ func _physics_process(delta):
|
||||
func _unhandled_input(event):
|
||||
# Handle power-up usage
|
||||
if event.is_action_pressed("use_powerup") and is_multiplayer_authority():
|
||||
if is_frozen:
|
||||
return
|
||||
if powerup_manager and powerup_manager.can_use_special():
|
||||
powerup_manager.use_special_effect()
|
||||
return
|
||||
@@ -1834,16 +1836,34 @@ func sync_grab_tekton(tekton_path: NodePath):
|
||||
print("[Player %s] Grabbed Tekton %s" % [name, tekton.name])
|
||||
|
||||
func throw_tekton():
|
||||
if not is_multiplayer_authority() or not is_carrying_tekton:
|
||||
if not is_multiplayer_authority() or not is_carrying_tekton or is_frozen:
|
||||
return
|
||||
|
||||
# Determine throw direction (where player is facing)
|
||||
# For simplicity, we use the player's current rotation to find the target tile
|
||||
var forward = - global_transform.basis.z.normalized()
|
||||
# NOTE: Movement manager uses atan2(x, z) which implies 0 rotation = +Z facing.
|
||||
# So we must use +basis.z (Positive Z) as forward, not standard -basis.z.
|
||||
var forward = global_transform.basis.z.normalized()
|
||||
var throw_dir = Vector2i(round(forward.x), round(forward.z))
|
||||
if throw_dir == Vector2i.ZERO: throw_dir = Vector2i(1, 0) # Fallback
|
||||
|
||||
var target_pos = current_position + throw_dir
|
||||
# Calculate distance (5 to 7 tiles)
|
||||
var rng = RandomNumberGenerator.new()
|
||||
rng.randomize()
|
||||
var distance = rng.randi_range(5, 7)
|
||||
|
||||
var target_pos = current_position + (throw_dir * distance)
|
||||
|
||||
# Clamp to grid bounds if possible, or just check validity
|
||||
if enhanced_gridmap:
|
||||
# Simple clamp assuming 0-based indexing and knowing size would be better,
|
||||
# but if we don't have size, we can just raycast or check validity step by step?
|
||||
# Let's just try the target. If invalid, maybe pull back?
|
||||
# Or just let it land "off map" and handle it?
|
||||
# Better: Clamp to grid dimensions if known.
|
||||
# EnhancedGridMap usually has columns/rows.
|
||||
if "columns" in enhanced_gridmap and "rows" in enhanced_gridmap:
|
||||
target_pos.x = clamp(target_pos.x, 0, enhanced_gridmap.columns - 1)
|
||||
target_pos.y = clamp(target_pos.y, 0, enhanced_gridmap.rows - 1)
|
||||
|
||||
if is_multiplayer_authority():
|
||||
rpc("sync_throw_tekton", target_pos)
|
||||
@@ -1856,13 +1876,76 @@ func sync_throw_tekton(target_pos: Vector2i):
|
||||
is_carrying_tekton = false
|
||||
tekton.set_carried(false)
|
||||
|
||||
# Move Tekton to target pos
|
||||
tekton.current_position = target_pos
|
||||
# Visual Arc Tween
|
||||
var start_pos = tekton.global_position
|
||||
# Target world position
|
||||
var end_world_pos = Vector3(
|
||||
target_pos.x * cell_size.x + cell_size.x * 0.5,
|
||||
cell_size.y, # Floor Y
|
||||
target_pos.y * cell_size.z + cell_size.z * 0.5
|
||||
) + cell_offset
|
||||
|
||||
# Intensity 0.5 for throw (drops 50% tiles)
|
||||
tekton.on_hit(self , 0.5)
|
||||
var mid_pos = (start_pos + end_world_pos) / 2.0
|
||||
mid_pos.y += 4.0 # Arc height
|
||||
|
||||
print("[Player %s] Threw Tekton to %s" % [name, target_pos])
|
||||
var tween = create_tween()
|
||||
tween.set_parallel(true)
|
||||
|
||||
# We can use a curve or just simple jump logic.
|
||||
# For a nice arc in 3D: Tween X/Z linearly, Tween Y with ease out/in (bounce-like)?
|
||||
# Or use a method that interpolates a curve.
|
||||
# Simple approach: Tween 'position' effectively? No, linear pos is straight line.
|
||||
# Let's use a value tween and update position manually, or just use a parabolic path helper?
|
||||
# Easiest readable way: likely just tweening horizontal and vertical separately if we could.
|
||||
|
||||
# Let's stick to a simple "Jump" tween:
|
||||
# 1. Move X/Z linearly to target
|
||||
tween.tween_property(tekton, "global_position:x", end_world_pos.x, 0.6).set_trans(Tween.TRANS_LINEAR)
|
||||
tween.tween_property(tekton, "global_position:z", end_world_pos.z, 0.6).set_trans(Tween.TRANS_LINEAR)
|
||||
|
||||
# 2. Move Y up then down
|
||||
var jump_tween = create_tween()
|
||||
jump_tween.tween_property(tekton, "global_position:y", mid_pos.y, 0.3).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT)
|
||||
jump_tween.tween_property(tekton, "global_position:y", end_world_pos.y, 0.3).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_IN).set_delay(0.3)
|
||||
|
||||
# Landing Callback
|
||||
jump_tween.tween_callback(func():
|
||||
tekton.current_position = target_pos
|
||||
|
||||
# Impact Effects!
|
||||
|
||||
# 1. Stun nearby players (Radius 2?)
|
||||
# "if there's a player around that floor they will got stunned" -> "around that floor" implies radius
|
||||
var impact_center = target_pos
|
||||
var stun_radius = 1.5
|
||||
|
||||
var players = get_tree().get_nodes_in_group("Players")
|
||||
print("[Throw] Checking stun impact at %s. Found %d players." % [impact_center, players.size()])
|
||||
|
||||
for p in players:
|
||||
if p == self: continue
|
||||
|
||||
# Check distance
|
||||
var dist = Vector2(p.current_position.x, p.current_position.y).distance_to(Vector2(impact_center.x, impact_center.y))
|
||||
print("[Throw] Player %s at %s. Dist: %.2f (Radius: %.1f)" % [p.name, p.current_position, dist, stun_radius])
|
||||
|
||||
if dist <= stun_radius:
|
||||
if p.has_method("apply_stagger"):
|
||||
print("[Throw] Applying stagger to %s" % p.name)
|
||||
p.apply_stagger(3.0)
|
||||
NotificationManager.send_message(self , "Stunned " + p.name + "!", NotificationManager.MessageType.WARNING)
|
||||
|
||||
# 2. Tekton drops tiles (Spawn tiles around) AND shrinks
|
||||
if tekton.has_method("on_thrown_landing"):
|
||||
tekton.on_thrown_landing(self )
|
||||
else:
|
||||
# Fallback
|
||||
tekton.on_hit(self , 1.0)
|
||||
|
||||
print("[Player %s] Tekton landed at %s" % [name, target_pos])
|
||||
).set_delay(0.6)
|
||||
|
||||
print("[Player %s] Threw Tekton to %s (Dist: %s)" % [name, target_pos, target_pos.distance_to(tekton.current_position)])
|
||||
|
||||
func knock_tekton():
|
||||
if not is_multiplayer_authority() or is_frozen:
|
||||
|
||||
Reference in New Issue
Block a user