Godot4.3类星露谷游戏开发之【可砍伐的树】

千里之行,始于足下

零、 笔记

学习了解 碰撞/受击箱,并根据其原理实现可砍伐的树。

一、碰撞箱与受击箱

图中玩家斧头砍下时,出现的 红色区域碰撞箱 ,树木带有的 紫色区域受击箱 ,因此砍树的过程,就是两者 检测碰撞 后响应的过程。

请添加图片描述

二、创建树木

第一步、以树(StaticBody2D)为根节点,Sprite2DCollisionShape2D 为子节点,创建场景如图:

在这里插入图片描述
第二步,将当前场景保存到路径 res://场景/物品 下;

在这里插入图片描述
第三步,选中 Sprite2D 节点,在 检查器->Texture 新建 AtlasTexture

在这里插入图片描述
第四步,从路径 res://资产/Sprout Lands - Sprites - Basic pack/Objects 导入 Atlas

在这里插入图片描述
第五步,点击 编辑区域

在这里插入图片描述
第六步,在弹窗中改变吸附模式为 像素吸附 ,框选中想要的树木后关闭;

在这里插入图片描述
第七步,选中 CollisionShape2D 节点,在检查器中新建 长方形碰撞 ,并覆盖树干作为树的碰撞体;

在这里插入图片描述
在这里插入图片描述

三、创建受击组件

第一步,以受击组件( Area2D )为根节点,创建场景如图;

在这里插入图片描述
第二步,保存至路径 res://场景/组件/ 下;

第三步,在 项目->项目设置->常规->层名称->Layer 8 中添加层名字:受击

在这里插入图片描述
第四步,选中 受击组件 节点,在 检查器->Collision 选择Layer 8,Mask 7;

在这里插入图片描述

第五步,添加脚本;

class_name 受击组件
extends Area2D

signal 已受击


func _on_area_entered(area: Area2D) -> void:
	已受击.emit()  # 识别工具后发射信号

四、创建碰撞组件

第一步,以碰撞组件( Area2D )为根节点,创建场景如图;

在这里插入图片描述
第二步,保存至路径 res://场景/组件/ 下;

第三步,在 项目->项目设置->常规->层名称->Layer 7 中添加层名字:碰撞

在这里插入图片描述
第四步,选中 碰撞组件 节点,在 检查器->Collision 选择Layer 7,Mask 8;

在这里插入图片描述
第五步,添加脚本;

class_name 碰撞组件
extends Area2D

五、可砍伐的树

第一步,切换到树场景, 将 受击组件 实例化为子节点,并添加 碰撞形状

在这里插入图片描述
在这里插入图片描述
第二步,选中受击组件,连接信号 area_entered(area: Area2D)受击组件

在这里插入图片描述
在这里插入图片描述
第三步,在路径 res://脚本/ 下新建 工具箱 文件夹,并新建 工具箱.gd 脚本文件;

在这里插入图片描述

class_name 工具箱
extends Node


static var 工具: String

第四步,切换回 树.tscn 场景选中 节点,添加脚本;

extends StaticBody2D

var 生命值: int = 2

@onready var 受击组件: Area2D = $"受击组件"


func _ready() -> void:
	受击组件.已受击.connect(树木消失)
	
	
func 树木消失() ->void:
	if 工具箱.工具 == "砍树":
		生命值 -= 1
		if 生命值 == 0:
			queue_free()

六、使玩家可砍伐

第一步 ,在 玩家1 场景中,添加 碰撞组件 实例化节点;

在这里插入图片描述
第二步 ,为碰撞组件添加 CollisionShape2D 子节点,以定义碰撞组件的形状;

在这里插入图片描述
第三步,选中CollsionShape2D节点,在检查器中 新建圆形碰撞形状

在这里插入图片描述
第四步,在2D界面中,手动调节碰撞形状的 大小、位置 ,使其大概贴合玩家砍伐的范围,这里以玩家 砍树_前 动画为例;

在这里插入图片描述
第五步,选中CollsionShape2D节点,在 检查器->Node2D->Transform->Position 中记录此时碰撞形状的 位置(之后要用到);

在这里插入图片描述
第六步,同理,调节碰撞形状位置,并记录 砍树_左、砍树_右、砍树_后 不同动画下,碰撞形状的位置;

在这里插入图片描述
这里给出表格:

动画方向碰撞位置
砍树_左(-9,3)
砍树_右(9,3)
砍树_后(0,-11)
砍树_前(0,10)

第七步,不同碰撞形状混在一起时,容易辨识不清,而从 CollisionShape->Debug Color 更改颜色可以更好识别;

在这里插入图片描述
在这里插入图片描述
第八步,更新 玩家1.gd 脚本;

class_name 玩家1
extends CharacterBody2D

const 速度: float = 80.0

var 玩家方向: Vector2 = Vector2.DOWN	# 默认朝向下方
var 工具启用: bool = false				# 正在使用工具的标志
var 碰撞位置: Dictionary = {
	"_后": Vector2(0, -11),  # 面朝后
	"_前": Vector2(0, 10),  # 面朝前
	"_左": Vector2(-9, 3),  # 面朝左
	"_右": Vector2(9, 3),  # 面朝右
}

@onready var animated_sprite_2d: AnimatedSprite2D = $AnimatedSprite2D
@onready var collision_shape_2d: CollisionShape2D = $"碰撞组件/CollisionShape2D"


func _ready():
	# 连接动画结束信号
	animated_sprite_2d.animation_finished.connect(_on_animation_finished)
	collision_shape_2d.disabled = true


func _physics_process(_delta: float) -> void:
	if 工具启用:
		velocity = Vector2.ZERO		# 使用工具时停止移动
		move_and_slide()
		return
	
	# 正常移动逻辑
	var 向量 = Input.get_vector("左", "右", "上", "下")
	处理动画(向量)
	velocity = 速度 * 向量
	move_and_slide()
	
	# 检测工具按键(U=砍树,I=浇水,O=锄地)
	if Input.is_action_just_pressed("砍树"):
		工具箱.工具 = "砍树"  # 切换工具砍树
		使用工具("砍树")
	elif Input.is_action_just_pressed("浇水"):
		工具箱.工具 = "浇水"  # 切换工具浇水
		使用工具("浇水")
	elif Input.is_action_just_pressed("锄地"):
		工具箱.工具 = "锄地"  # 切换工具锄地
		使用工具("锄地")


func 处理动画(向量: Vector2):
	# 更新玩家朝向
	if 向量 != Vector2.ZERO:
		玩家方向 = 向量
	
	# 根据方向设置动画
	var 方向后缀 = 获取方向后缀()
	if 向量 != Vector2.ZERO:
		animated_sprite_2d.play("行走" + 方向后缀)
	else:
		animated_sprite_2d.play("空闲" + 方向后缀)
		
		
func 使用工具(行动名: String):
	if 工具启用: 
		return

	var 方向后缀 = 获取方向后缀()
	
	# 设置碰撞形状位置
	if 碰撞位置.has(方向后缀):
		collision_shape_2d.position = 碰撞位置[方向后缀]
		
	# 构建动画名称(例如:"砍树_下")
	var 工具动画名 = 行动名 + 获取方向后缀()
	if animated_sprite_2d.sprite_frames.has_animation(工具动画名):
		工具启用 = true
		collision_shape_2d.disabled = false
		animated_sprite_2d.play(工具动画名)
	#print("当前方向: ", 方向后缀, " 碰撞位置: ", collision_shape_2d.position)

		
func 获取方向后缀() -> String:
	# 根据最后朝向返回方向后缀
	if 玩家方向.x > 0: 
		return "_右"
	if 玩家方向.x < 0: 
		return "_左"
	if 玩家方向.y > 0: 
		return "_前"
	return "_后"	# 默认朝向下方
	
	
func _on_animation_finished():
	# 当工具动画播放完毕时恢复状态
	工具启用 = false
	collision_shape_2d.disabled = true
	# 保持最后朝向的静止动画
	animated_sprite_2d.play("空闲" + 获取方向后缀())

七、测试1

第一步,将路径 res://场景/测试 下的 测试_基本地形 复制为 测试_可砍伐的树

在这里插入图片描述
第二步,将 树.tscn 实例化为当前场景子节点,并调整到合适位置便于测试;

在这里插入图片描述
第三步,测试;

请添加图片描述
测试1完成!

八、添加掉落物

第一步,新建场景 木头.tscn,以 木头(Sprite2D)作为根节点;

在这里插入图片描述
第二步,保存当前场景至路径 res://场景/物品 下;

第三步,添加 可收集组件,见文章Godot4.3类星露谷游戏开发之【可收集物品】

在这里插入图片描述
第四步,选中 木头(Sprite2D)节点,新建 AtlasTexture ,导入路径 res://资产/Sprout Lands - Sprites - Basic pack/Objects/ 下的精灵表图片;

在这里插入图片描述
第五步,点击 编辑区域 后,框选中木头图片后关闭;

在这里插入图片描述
在这里插入图片描述

第六步,切换到 树.tscn 场景,更新脚本;

extends StaticBody2D

const 木头 = preload("res://场景/物品/木头.tscn")

var 生命值: int = 2

@onready var 受击组件: Area2D = $"受击组件"


func _ready() -> void:
	受击组件.已受击.connect(树木消失)
	
	
func 树木消失() ->void:
	if 工具箱.工具 == "砍树":
		生命值 -= 1
		if 生命值 == 0:
			var 掉落的木头: Node = 木头.instantiate()
			掉落的木头.global_position = global_position
			get_parent().add_child(掉落的木头)
			queue_free()

九、测试2

运行 测试_可砍伐的树.tscn 场景,开始测试;

请添加图片描述
测试2完成!

十、免费开源资产包

某开源网站精灵图资源包链接: 点击此处

  1. 进入链接后点击下图按钮;

下载

  1. 然后点击【No thanks,just take me to the downloads】(不了谢谢,只想下载);

No thanks,just take me to the downloads

  1. 最后点击下图按钮完成下载(注意导入前需解压缩);

下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ForBigData

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值