1. Starting Out
1. Godot Download, Orientation, and Setup

godot4




关掉3d编辑器

create profile





点击3个点可以切换选项卡位置


编辑器->编辑器设置->
2. Creating the Player

kenney


拖动图片到godot的res://目录下

新建资源文件夹





click 'other node'

创建characterBody2D, 让角色可以移动



使用精灵节点来让角色节点显示图片

ctrl+s保存


重命名

重命名

拖动png到精灵节点的texture属性上

让图片清晰(当前项目纹理效果和图片的不匹配) ,项目->项目设置->渲染->纹理

让人物的脚站在地面上

添加子节点




点击circleshape, 弹出子菜单, 调整大小

调整node2d>transform>position>y为-5



如果使用矩形碰撞结构, 容易卡在墙角(转弯)
3. Player Movement

添加脚本到节点


项目->项目设置->输入映射->添加

点击动作右侧+号弹出, 绑定按键监听


继续添加

f1可以打开帮助文档
# player.gd
extends CharacterBody2D
const MAX_SPEED = 200
# Called when the node enters the scene tree for the first time.
# 该节点位于场景树中, 一切都可以使用, 此时其子节点都加载完毕
func _ready():
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
# 每帧都会被调用的函数
func _process(delta):
var movement_vector = get_movement_vector()
# 归一化 -> 变成长度为1的向量
var direction = movement_vector.normalized()
# velocity: 角色的速度属性
velocity = direction * MAX_SPEED
# 根据velocity移动
move_and_slide()
func get_movement_vector():
var movement_vector = Vector2.ZERO
# 按下-> get_action_strength("move_right")==1, 没按为0, 左右都按抵消==0
var x_movement = Input.get_action_strength("move_right") - Input.get_action_strength("move_left")
var y_movement = Input.get_action_strength("move_down") - Input.get_action_strength("move_up")
return Vector2(x_movement, y_movement)

点击回到2D


添加角色用来移动的场景

重命名为Main

ctrl+s保存




按w, 小人身上出现箭头, 拖动小人到右下角, 点击f5或运行按钮-> 提示没有场景-> 点击选择当前-> 运行

4. Creating a TileMap

项目设置 -> 设置游戏窗口大小

mode=='viewpoint' -> 低分辨率显示, 更像素化

高级设置->默认窗口大小(我的电脑屏幕比较小, 用1280x720)










拖动tilemap_packed.png到godot项目



拖动tilemap_packed.png到tileset编辑窗口 -> click no

单击选择

terrain sets -> add element




点击图块里的小格


切换到概率, 输入概率值后点击图块, 设置该图块被平铺的概率






同时选中tileset, tilemap, 地形栏才有东西

左上角切为箭头, 开始绘制地板

点击小方框图标, 可以大范围绘制
5. Game Camera

ctrl+n

ctrl+a

ctrl+s




ctrl+shift+o



group的作用是可以从任何地方访问的标识符
# game_camera.gd
extends Camera2D
# Called when the node enters the scene tree for the first time.
func _ready():
make_current()
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
# 获取当前场景树, 获取树中节点
var player_nodes = get_tree().get_nodes_in_group("player")
if player_nodes.size() > 0:
var player = player_nodes[0] as Node2D
global_position = player.global_position

camera添加到场景



让镜头比人物慢一点, 显得更自然, 我们可以使用独立的帧率来实现
# game_camera.gd
extends Camera2D
var target_position = Vector2.ZERO
# Called when the node enters the scene tree for the first time.
func _ready():
make_current()
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
acquire_target()
# lerp 线性插值 有开始和结束点, 用百分比来表示两个位置的距离的百分比
# 每一帧都会移动到离target_position 1.0 - exp(-delta * 10)的位置
global_position = global_position.lerp(target_position, 1.0 - exp(-delta * 10))
func acquire_target():
# 获取当前场景树, 获取树中节点
var player_nodes = get_tree().get_nodes_in_group("player")
if player_nodes.size() > 0:
var player = player_nodes[0] as Node2D
target_position = player.global_position
global_position = player.global_position
2. Building the Foundation
1. Creating a Rat Enemy

ctrl+N 创建新场景

ctrl+s保存

找到敌人图片

拖入项目目录并改名


选中basicEnemy节点,ctrl+a添加精灵

拖动敌人图片到精灵节点的texture属性

修改y的值,让老鼠的脚和地面对齐

选中basicEnemy节点,ctrl+a添加形状


radius:5

position: y: -5

添加脚本
extends CharacterBody2D
const MAX_SPEED = 75
# Called when the node enters the scene tree for the first time.
func _ready():
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
var direction = get_direction_to_player()
velocity = direction * MAX_SPEED
move_and_slide()
func get_direction_to_player():
var player_node = get_tree().get_first_node_in_group("player") as Node2D
if player_node != null:
return (player_node.global_position - global_position).normalized()
return Vector2.ZERO

main场景,按ctrl+shift+a,将敌人添加到场景







现在碰撞后不会粘在一起,可以移动过去
2. Creating the First Sword Ability



新建2d场景





ctrl+按住中间的点, 可以旋转




新建场景

创建脚本

export属性, 保存后出现一个新的inspector属性


+子节点timer


ctrl+shift+a, 添加实例化子节点

关掉, 否则定时器只触发一次
extends Node
# 导出全局变量
@export var sword_ability: PackedScene
# Called when the node enters the scene tree for the first time.
func _ready():
#get_node('Timer')
$Timer.timeout.connect(on_timer_timeout)
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
pass
# 每次触发计时器执行的操作
func on_timer_timeout():
var player = get_tree().get_first_node_in_group("player") as Node2D
if player == null:
return
# 插入到scene: main
var sword_instance = sword_ability.instantiate() as Node2D
player.get_parent().add_child(sword_instance)
sword_instance.global_position = player.global_position

3. Introduction to AnimationPlayer

添加animationPlayer, 实现剑的动画效果










点击小点会出来这个界面

单击第一个










动画改为0.5s, shift拖动出蓝框, 范围选中关键帧, 然后点按拖动到后面















我们需要让动画结束后, 从场景树中移除


右键->插入关键帧

在下一个空闲帧时移除


运行游戏, 然后暂停, 点击remote查看当前场景树, 动画被自动移除

4. Targeting Enemies With Sword Ability

给enemy添加分组, 这样就可以在其他节点访问该节点, 获取位置

extends Node
const MAX_RANGE = 150
# 导出全局变量
@export var sword_ability: PackedScene
# Called when the node enters the scene tree for the first time.
func _ready():
#get_node('Timer')
$Timer.timeout.connect(on_timer_timeout)
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
pass
# 每次触发计时器执行的操作
func on_timer_timeout():
var player = get_tree().get_first_node_in_group("player") as Node2D
if player == null:
return
var enemies = get_tree().get_nodes_in_group("enemy")
# 过滤掉距离玩家超过150方圆的敌人
enemies = enemies.filter(func(enemy: Node2D):
return enemy.global_position.distance_squared_to(player.global_position) < pow(MAX_RANGE, 2)
)
if enemies.size() == 0:
return
enemies.sort_custom(func(a: Node2D, b: Node2D):
var a_distance = a.global_position.distance_squared_to(player.global_position)
var b_distance = b.global_position.distance_squared_to(player.global_position)
return a_distance < b_distance
)
# 插入到scene: main
var sword_instance = sword_ability.instantiate() as Node2D
player.get_parent().add_child(sword_instance)
sword_instance.global_position = enemies[0].global_position