如何让仅含4个斜向精灵的Godot角色实现8方向移动?
问题描述
我想在Godot引擎中实现角色8方向移动,但只准备了东南(DownRight)、东北(UpRight)、西南(DownLeft)、西北(UpLeft)4个斜向方向的精灵。预期逻辑如下:
- 角色朝东南方向时,单独向南移动不切换精灵;朝西南方向时,单独向南移动同理
- 从东南方向改为向上移动,切换为东北方向精灵;从东北方向改为向左移动,切换为西北方向精灵;东南转西南的逻辑以此类推
目前角色能正常控制移动,但精灵切换完全不符合预期,始终显示UpLeft行走动画,原代码如下:
extends CharacterBody2D const max_speed = 50 const accel = 1500 const friction = 400 var input = Vector2.ZERO @onready var animation = $AnimationPlayer func get_input(): input.x = int(Input.is_action_pressed("ui_right")) - int(Input.is_action_pressed("ui_left")) input.y = int(Input.is_action_pressed("ui_down")) - int(Input.is_action_pressed("ui_up")) return input.normalized() func player_movement(delta): input = get_input() if input == Vector2.ZERO: if velocity.length() > (friction * delta): velocity -= velocity.normalized() * (friction * delta) else: velocity = Vector2.ZERO else: velocity += (input * accel * delta) velocity = velocity.limit_length(max_speed) move_and_slide() func updateAnimation(): var direction = "_DownRight" if Vector2(1, -1): direction = "_UpRight" if Vector2.ONE: direction = "_DownRight" if Vector2(-1, 1): direction = "_DownLeft" if Vector2(-1, -1): direction = "_UpLeft" if Vector2.ZERO: animation.play("walk" + direction + "Idle") else: animation.play("walk" + direction) func _physics_process(delta): player_movement(delta) updateAnimation()
解决方案
你的updateAnimation函数逻辑完全错误——没有基于实际输入或角色速度判断方向,而是直接判断固定的Vector2常量(这些判断永远为真,最后一个Vector2(-1,-1)的赋值覆盖了前面所有结果,所以才会一直显示UpLeft动画)。以下是符合你需求的修正方案:
核心逻辑
把8方向输入映射到4个斜向精灵,遵循你的规则:
- 当有左右输入时,优先锁定左右方向,再结合上下输入确定斜向
- 当只有上下输入时,保留当前的左右方向,切换对应上下斜向
- 当只有左右输入时,保留当前的上下方向,切换对应左右斜向
修正后的完整代码
extends CharacterBody2D const max_speed = 50 const accel = 1500 const friction = 400 var input = Vector2.ZERO # 记录当前使用的方向精灵,避免无意义的动画切换 var current_direction = "_DownRight" @onready var animation = $AnimationPlayer func get_input(): input.x = int(Input.is_action_pressed("ui_right")) - int(Input.is_action_pressed("ui_left")) input.y = int(Input.is_action_pressed("ui_down")) - int(Input.is_action_pressed("ui_up")) # 零向量不归一化,避免报错 return input if input != Vector2.ZERO else Vector2.ZERO func player_movement(delta): input = get_input() if input == Vector2.ZERO: if velocity.length() > (friction * delta): velocity -= velocity.normalized() * (friction * delta) else: velocity = Vector2.ZERO else: velocity += (input * accel * delta) velocity = velocity.limit_length(max_speed) move_and_slide() func updateAnimation(): # 有输入时更新方向 if input != Vector2.ZERO: # 优先处理左右输入 if input.x > 0: # 向右:结合上下输入确定右上/右下 current_direction = "_UpRight" if input.y < 0 else "_DownRight" elif input.x < 0: # 向左:结合上下输入确定左上/左下 current_direction = "_UpLeft" if input.y < 0 else "_DownLeft" else: # 只有上下输入:保留当前左右方向,切换上下 if current_direction.contains("Right"): current_direction = "_UpRight" if input.y < 0 else "_DownRight" else: current_direction = "_UpLeft" if input.y < 0 else "_DownLeft" # 根据角色是否移动播放对应动画 if velocity == Vector2.ZERO: animation.play("walk" + current_direction + "Idle") else: animation.play("walk" + current_direction) func _physics_process(delta): player_movement(delta) updateAnimation()
关键修改说明
- 修复输入归一化问题:
get_input中不对零向量归一化,避免Godot报错 - 新增
current_direction变量:记录当前使用的方向精灵,纯上下/左右移动时保留原有斜向的一侧属性 - 正确的方向判断逻辑:完全基于输入的x、y分量判断,符合你要求的切换规则
- 动画播放优化:根据
velocity判断是否播放 idle 动画(输入为零时角色可能还在减速移动)
内容的提问来源于stack exchange,提问作者ConvexProjects
相关产品推荐
相关产品推荐

