跳到主要内容

场景4—动态添加节点

概述

这个案例实现了一个点击屏幕后发射一个小球,小球会在一定时间后自动销毁的效果,完整的项目介绍请见应用教程

场景准备

  1. 创建一个空场景,在场景中新建一个网格实例,在属性中选择“网格” -> “新建Sphere Mesh”,生成一个球体的网格实例,将缩放设为”0.2, 0.2, 0.2“

  2. 点击球体节点,使用工具栏左上角的“一键转换为刚体”

  3. 调整生成的刚体节点的属性,将质量调整为0.02

  4. 保存场景,命名为”球体.scene“

  5. 创建一个3D场景,命名为”动态创建节点.scene“(本案例添加了几个靶子作为交互的刚体,你可以在该场景文件夹中找到这些素材)

脚本实现

动态创建节点.is

在动态创建节点场景的根节点创建一个”动态创建节点脚本.is“,实现以下功能:

1. 在鼠标点击位置生成球体

每次点击时,首先通过相机的project_position方法将鼠标点击的屏幕坐标投影到3D空间,得到球体发射的位置。这里使用get_tree().get_root().get_camera()获取场景中正在使用的相机,也可以直接使用get_node获取相机节点。

然后需要生成一个新的球体实例,使用duplicate方法复制得到一个新的球体,将新的球体通过add_child添加到根节点下,然后将其世界坐标设置为之前获取的位置。

func _input(event):
#当输入事件是鼠标按键左键且是按下状态时
if event is InputEventMouseButton and event.button_index == 1 and event.is_pressed():
var camera = get_tree().get_root().get_camera() #获取当前相机
var position = camera.project_position(event.position, 1) #根据点击所在屏幕位置生成投影到3D位置
var sphere = load("res://场景/场景4/球体.scene").instance() #加载球体场景
add_child(sphere) #添加球体
sphere.global_transform.origin = position #设置球体位置
var direction = camera.project_ray_normal(event.position) #获取垂直于相机屏幕的一个法线向量
info

通过load方法获取文件中保存的球体场景,场景以PackedScene类型存储,无法直接将其加入到场景树中,需要通过instance方法将其转换为可以添加到场景中的Node类型。

运行场景,可以看到点击屏幕后小球从点击位置掉落的效果:

2. 球体向前发射

球体是一个刚体类型,add_central_force方法可以为其施加一个力,使其产生加速度。

力的方向垂直于相机屏幕朝前,这个方向可以通过相机的project_ray_normal方法获取。

最后,将球体的质量设为0.02,使力的作用效果更加明显(也可以通过增加力的大小实现)。

        direction = camera.project_ray_normal(event.position) #获取垂直于相机屏幕的一个法线向量
sphere.mass = 0.2 #设置刚体质量
sphere.add_central_force(750*direction) #施加一个力,产生加速度

运行场景,此时小球有发射的效果:

球体.is

在球体.scene的根节点创建一个”球体.is“脚本。

现在每次点击都会生成一个球体的刚体,在球体数量过多时可能会产生性能问题。通过queue_free方法实现球体节点的销毁,在球体的脚本上添加以下内容:

var DESTORY_TIME = 3 #自动销毁等待的时间,单位为秒
var time = 0 #节点创建后经历的时间

func _physics_process(delta):
time += delta
if time >= DESTORY_TIME:
queue_free() #销毁节点

运行场景,所有发射出的小球会在三秒后自动消失。