效果预览

1 开发前的准备
1 默认渲染设置
因为是像素风,需要调整默认渲染设置:Nearest

2 运行窗口大小设置
推荐的像素游戏窗口大小: 320 x 180

3 开发窗口大小设置
此时开发时的窗口大小,跟随着上一步;如果不单独设置,就是上一步设置的、运行窗口大小,开发的时候根本看不清,所以打开高级设置,开启窗口高度覆盖

4 拉伸模式设置
重新运行,发现只有运行窗口变大了,图片素材还是原大小,设置拉伸模式,使图片大小自适应拉伸

2 创建玩家
1 前言:
Godot中有3种物理物体
1 StaticBody2D
适用于无法被外力移动的 2D 物理物体。手动移动时不会影响路径上的其他物体。
2 RigidBody2D
适用于由物理仿真进行移动的 2D 物理体。

3 CharacterBody2D
(3.x版本叫KinematicBody2D)
用作玩家节点,选用CharacterBody2D,官方给出的介绍如下:

2 创建玩家角色
在场景下创建一个CharacterBody2D节点,作为玩家对象,并添加一个Sprite2D子节点,给一个玩家图片

接着,自动切割,选择一张,在Player节点上开启子节点不可选择,将Player节点和图片绑定在一起,这样移动玩家图片,Player节点(父节点)也会跟着移动。
PS:使子节点无法/可以选择快捷键:CTRL + SHIFT +G,CTRL + G

3 玩家移动脚本 Player.gd
第1版 基础移动
通过x,y坐标实现基础移动
velocity在4.x版本已经定义好了,直接用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| extends CharacterBody2D
func _physics_process(delta): if Input.is_action_pressed("ui_right"): velocity.x = 4 elif Input.is_action_pressed("ui_left"): velocity.x = -4 elif Input.is_action_pressed("ui_down"): velocity.y = 4 elif Input.is_action_pressed("ui_up"): velocity.y = -4 else: velocity.x=0 velocity.y=0 move_and_collide(velocity) #系统方法,传入向量
|
第2版 向量版,支持手柄
extends CharacterBody2D
func _physics_process(delta):
var input_vector = Vector2.ZERO
input_vector.x=Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
input_vector.y=Input.get_action_strength("ui_down") - Input.get_action_strength("ui_up")
if input_vector != Vector2.ZERO:
velocity = input_vector
else :
velocity = Vector2.ZERO
move_and_collide(velocity)
存在问题:斜角移动更快,移速因帧率不同的问题
第3版 解决速度受帧影响的问题
delta和physics_process
physics_process这一个回调函数是每一次物理帧时调用:固定每1/60秒调用一次
此时速度在第2版的基础上, 乘了帧,帧的单位是秒
第2版移动速度是根据delta决定的,速度是x每帧,因此会受到帧率影响;
第3版移动速度在第2版基础上乘delta,速度从x每帧变为了x每秒 (v=s*t)
然后新增MAX_SPEED,控制移动速度,解决移动速度很慢的问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| extends CharacterBody2D
const MAX_SPEED = 100
func _physics_process(delta): var input_vector = Vector2.ZERO input_vector.x=Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left") input_vector.y=Input.get_action_strength("ui_down") - Input.get_action_strength("ui_up") input_vector = input_vector.normalized() if input_vector != Vector2.ZERO: velocity = input_vector * MAX_SPEED else : velocity = Vector2.ZERO move_and_collide(velocity * delta)
|
第4版 引入单位向量、加速度、摩擦力、最大速度
normalized(),单位向量,返回原本向量单位化的值
limit_length(),限制最大值的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| extends CharacterBody2D
const ACCELERATION = 15 * 60 const MAX_SPEED = 100 const FRICTION = 15 * 60
func _physics_process(delta): var input_vector = velocity input_vector.x=Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left") input_vector.y=Input.get_action_strength("ui_down") - Input.get_action_strength("ui_up") input_vector = input_vector.normalized() #非零向量 if input_vector != Vector2.ZERO: velocity = velocity.move_toward(input_vector * MAX_SPEED,ACCELERATION * delta) #velocity += input_vector * ACCELERATION * delta #velocity = velocity.limit_length(MAX_SPEED) #限制最大速度,* delta放在后面,否则加上上一行代码的* delta就出现2次* delta,就不准确了 else : velocity = velocity.move_toward(Vector2.ZERO,FRICTION * delta) #摩擦力 move_and_collide(velocity * delta)
|
第5版 最终版
之前的逻辑在持续按住移动键时不应用摩擦力,这是因为摩擦力的减速度只在没有输入时应用。现在进行修复。
并微调,减少重复计算,使用get_axis()获取轴输入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| extends CharacterBody2D
const ACCELERATION = 15 * 60 const MAX_SPEED = 100 const FRICTION = 10 * 60
var input_vector = Vector2.ZERO
func _physics_process(delta: float) -> void: # 更新输入向量(仅当输入发生变化时才重新计算归一化) input_vector.x=Input.get_axis("ui_left", "ui_right") input_vector.y=Input.get_axis("ui_up", "ui_down") if input_vector.length() > 0.01: # 防止除以零 input_vector = input_vector.normalized() #非零向量 if input_vector != Vector2.ZERO: velocity = velocity.move_toward(input_vector * MAX_SPEED,ACCELERATION * delta - FRICTION * delta) else : velocity = velocity.move_toward(Vector2.ZERO,FRICTION * delta) #摩擦力 move_and_collide(velocity * delta)
|
完成