feat:增加多角色在线功能
- 增加远程登录角色精灵 - 基于后端接口完成位置同步 - 实现多人在线以及跳转 - 增加个人房间功能
This commit is contained in:
1
scenes/characters/PlayerController.gd.uid
Normal file
1
scenes/characters/PlayerController.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://fdswi18nel8n
|
||||
87
scenes/characters/RemotePlayer.gd
Normal file
87
scenes/characters/RemotePlayer.gd
Normal file
@@ -0,0 +1,87 @@
|
||||
extends CharacterBody2D
|
||||
|
||||
# 远程玩家脚本
|
||||
# 负责处理位置同步和动画播放
|
||||
# 严格遵循 Visual Only 原则:无输入处理,无物理碰撞
|
||||
|
||||
# 公共属性 (snake_case)
|
||||
var user_id: String = ""
|
||||
var target_position: Vector2 = Vector2.ZERO
|
||||
|
||||
# 内部状态
|
||||
var last_direction: String = "down"
|
||||
@onready var animation_player: AnimationPlayer = $AnimationPlayer
|
||||
@onready var sprite: Sprite2D = $Sprite2D
|
||||
|
||||
func _ready():
|
||||
# 初始化时确保无物理处理
|
||||
set_physics_process(false)
|
||||
# 初始位置设为当前位置
|
||||
target_position = global_position
|
||||
|
||||
# 确保禁用物理碰撞 (双重保险)
|
||||
if has_node("CollisionShape2D"):
|
||||
$CollisionShape2D.disabled = true
|
||||
|
||||
func _process(delta: float):
|
||||
# 1. 平滑移动插值
|
||||
var current_pos = global_position
|
||||
var dist = current_pos.distance_to(target_position)
|
||||
|
||||
if dist > 1.0:
|
||||
# 简单的线性插值,速度系数 10.0 可根据需要调整
|
||||
var new_pos = current_pos.lerp(target_position, 10.0 * delta)
|
||||
|
||||
# 计算移动向量用于动画朝向
|
||||
var move_vec = new_pos - current_pos
|
||||
_update_animation(move_vec)
|
||||
|
||||
global_position = new_pos
|
||||
else:
|
||||
# 距离很近时直接吸附并播放待机动画
|
||||
global_position = target_position
|
||||
_play_idle_animation()
|
||||
|
||||
# 统一初始化方法
|
||||
# data: 包含 camelCase 字段的字典 (userId, username, position 等)
|
||||
func setup(data: Dictionary):
|
||||
if data.has("userId"):
|
||||
user_id = data.userId
|
||||
|
||||
if data.has("position"):
|
||||
var pos_data = data.position
|
||||
if pos_data.has("x") and pos_data.has("y"):
|
||||
var new_pos = Vector2(pos_data.x, pos_data.y)
|
||||
global_position = new_pos
|
||||
target_position = new_pos
|
||||
|
||||
# 如果有名字显示需求,可在此扩展
|
||||
# if data.has("username") and has_node("Label"):
|
||||
# $Label.text = data.username
|
||||
|
||||
# 更新目标位置
|
||||
func update_position(new_pos: Vector2):
|
||||
target_position = new_pos
|
||||
|
||||
# 动画更新逻辑 (复用 PlayerController 的命名规范)
|
||||
func _update_animation(move_vec: Vector2):
|
||||
if not animation_player:
|
||||
return
|
||||
|
||||
# 确定主方向
|
||||
if abs(move_vec.x) > abs(move_vec.y):
|
||||
if move_vec.x > 0:
|
||||
last_direction = "right"
|
||||
else:
|
||||
last_direction = "left"
|
||||
else:
|
||||
if move_vec.y > 0:
|
||||
last_direction = "down"
|
||||
else:
|
||||
last_direction = "up"
|
||||
|
||||
animation_player.play("walk_" + last_direction)
|
||||
|
||||
func _play_idle_animation():
|
||||
if animation_player:
|
||||
animation_player.play("idle_" + last_direction)
|
||||
1
scenes/characters/RemotePlayer.gd.uid
Normal file
1
scenes/characters/RemotePlayer.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dtbajfsljdht5
|
||||
@@ -1,6 +1,6 @@
|
||||
[gd_scene load_steps=13 format=3 uid="uid://b2f8e24plwqgj"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://btka26hrcvgen" path="res://Scenes/characters/player.gd" id="1_script"]
|
||||
[ext_resource type="Script" uid="uid://fdswi18nel8n" path="res://scenes/characters/PlayerController.gd" id="1_script"]
|
||||
[ext_resource type="Texture2D" uid="uid://cghab1hkx5lg5" path="res://assets/characters/player_spritesheet.png" id="2_texture"]
|
||||
|
||||
[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_1"]
|
||||
|
||||
175
scenes/characters/remote_player.tscn
Normal file
175
scenes/characters/remote_player.tscn
Normal file
@@ -0,0 +1,175 @@
|
||||
[gd_scene load_steps=13 format=3 uid="uid://chb8mcqhfnkkr"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://dtbajfsljdht5" path="res://scenes/characters/RemotePlayer.gd" id="1_mu86i"]
|
||||
[ext_resource type="Texture2D" uid="uid://cghab1hkx5lg5" path="res://assets/characters/player_spritesheet.png" id="2_7oc7u"]
|
||||
|
||||
[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_1"]
|
||||
radius = 21.0
|
||||
height = 48.0
|
||||
|
||||
[sub_resource type="Animation" id="Animation_idle_down"]
|
||||
resource_name = "idle_down"
|
||||
length = 0.1
|
||||
loop_mode = 1
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Sprite2D:frame")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [0]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_idle_left"]
|
||||
resource_name = "idle_left"
|
||||
length = 0.1
|
||||
loop_mode = 1
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Sprite2D:frame")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [12]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_idle_right"]
|
||||
resource_name = "idle_right"
|
||||
length = 0.1
|
||||
loop_mode = 1
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Sprite2D:frame")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [8]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_idle_up"]
|
||||
resource_name = "idle_up"
|
||||
length = 0.1
|
||||
loop_mode = 1
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Sprite2D:frame")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [4]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_walk_down"]
|
||||
resource_name = "walk_down"
|
||||
length = 0.8
|
||||
loop_mode = 1
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Sprite2D:frame")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0, 0.2, 0.4, 0.6),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [0, 1, 2, 3]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_walk_left"]
|
||||
resource_name = "walk_left"
|
||||
length = 0.8
|
||||
loop_mode = 1
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Sprite2D:frame")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0, 0.2, 0.4, 0.6),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [12, 13, 14, 15]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_walk_right"]
|
||||
resource_name = "walk_right"
|
||||
length = 0.8
|
||||
loop_mode = 1
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Sprite2D:frame")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0, 0.2, 0.4, 0.6),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [8, 9, 10, 11]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_walk_up"]
|
||||
resource_name = "walk_up"
|
||||
length = 0.8
|
||||
loop_mode = 1
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Sprite2D:frame")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0, 0.2, 0.4, 0.6),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [4, 5, 6, 7]
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_1"]
|
||||
_data = {
|
||||
&"idle_down": SubResource("Animation_idle_down"),
|
||||
&"idle_left": SubResource("Animation_idle_left"),
|
||||
&"idle_right": SubResource("Animation_idle_right"),
|
||||
&"idle_up": SubResource("Animation_idle_up"),
|
||||
&"walk_down": SubResource("Animation_walk_down"),
|
||||
&"walk_left": SubResource("Animation_walk_left"),
|
||||
&"walk_right": SubResource("Animation_walk_right"),
|
||||
&"walk_up": SubResource("Animation_walk_up")
|
||||
}
|
||||
|
||||
[node name="RemotePlayer" type="CharacterBody2D"]
|
||||
script = ExtResource("1_mu86i")
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||
position = Vector2(1.5000005, -24.5)
|
||||
texture = ExtResource("2_7oc7u")
|
||||
hframes = 4
|
||||
vframes = 4
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
position = Vector2(2, -24)
|
||||
shape = SubResource("CapsuleShape2D_1")
|
||||
disabled = true
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
||||
libraries = {
|
||||
&"": SubResource("AnimationLibrary_1")
|
||||
}
|
||||
Reference in New Issue
Block a user