死亡复活
闯关小游戏需要一个角色死亡的条件,在该游戏中,当角色触碰到地面(Ground)即为死亡。本节课我们将通过学习触发器来制作死亡与复活的相关功能。
1.布置死亡区域
使用触发器来完成对关卡地面区域的覆盖,这片区域即为死亡区域。
①选择资源库下的功能对象分类
②点击“游戏功能对象”
③将触发器拖动到场景中
④调整触发器的大小和位置,让其覆盖关卡地面
2.GameStart脚本
接下来我们需要编写代码了,在这里以GameStart脚本为例,给大家介绍一下如何创建脚本,以及了解脚本的运行逻辑。
创建脚本
①在工程内容中选择“脚本”
②点击“新建脚本”按钮
③将脚本名称修改为“GameStart”(这个命名可以是任意值,GameStart只是用作示例)
④将脚本拖动到挂载到场景中(挂载到场景上的脚本才会执行逻辑,后面会讲)
脚本的默认结构
新建一个脚本,编辑器会默认向脚本中添加如下内容:
①class装饰器(没有这个装饰器,属性同步将不会生效)
②Script类(只有继承了这个类的脚本,才能够执行脚本的生命周期函数)
③onStart函数(当脚本被挂载到场景上的时候,onStart会在游戏启动后自动执行)
④onUpdate函数(周期函数,每帧执行,前提是将this.useUpdate赋值为true)
⑤onDestroy函数(脚本被销毁时最后一帧执行完调用此函数)
3.使用触发器
我们前面向场景中布置了一个触发器,由于触发器是需要配合脚本进行使用的,所以接下来教大家编写代码来使用触发器。
在GameStart脚本中编写如下逻辑:
脚本实现了查找到场景上的触发器,并且给触发器添加进入逻辑,现在触发器就能够实现:当有物体进入触发器区域,就会在日志窗口打印“有物体进入”。
ts
@Component
export default class GameStart extends Script {
/** 当脚本被实例后,会在第一帧更新前调用此函数 */
protected async onStart(): Promise<void> {
console.log("脚本启动")
// 查找触发器
let trigger = await GameObject.asyncFindGameObjectById("299CDDA6") as Trigger
// 给触发器添加进入逻辑
trigger.onEnter.add((other: GameObject) => {
console.log("有物体进入")
})
}
/**
* 周期函数 每帧执行
* 此函数执行需要将this.useUpdate赋值为true
* @param dt 当前帧与上一帧的延迟 / 秒
*/
protected onUpdate(dt: number): void {
}
/** 脚本被销毁时最后一帧执行完调用此函数 */
protected onDestroy(): void {
}
}
@Component
export default class GameStart extends Script {
/** 当脚本被实例后,会在第一帧更新前调用此函数 */
protected async onStart(): Promise<void> {
console.log("脚本启动")
// 查找触发器
let trigger = await GameObject.asyncFindGameObjectById("299CDDA6") as Trigger
// 给触发器添加进入逻辑
trigger.onEnter.add((other: GameObject) => {
console.log("有物体进入")
})
}
/**
* 周期函数 每帧执行
* 此函数执行需要将this.useUpdate赋值为true
* @param dt 当前帧与上一帧的延迟 / 秒
*/
protected onUpdate(dt: number): void {
}
/** 脚本被销毁时最后一帧执行完调用此函数 */
protected onDestroy(): void {
}
}
提示
上述代码中"299CDDA6"这串字符,它是我们铺设在场景上的触发器的 Guid
(场景上的每一个物体都有一个唯一的对象ID(即 Guid)。我们可以通过选中物体,然后右键,在弹出的选项里点击“复制对象ID”即可完成复制)
效果展示
运行游戏后,操控角色进入触发器区域,就会将“有物体进入”打印在日志窗口
4.LevelManager脚本
好的,你已经会使用触发器了,那么接下来让我们完成闯关小游戏的第一个核心逻辑吧。
在这里我们使用一个脚本来专门处理与游戏关卡有关的逻辑,可以称这个脚本为“关卡管理器”。
新建一个脚本,并将其命名为LevelManager,编写逻辑如下:
该脚本有如下几个要点:
① LevelManager使用了单例模式,因此这个脚本不需要挂载到场景中。这个脚本将会通过挂载到场景上的GameStart脚本来进行驱动。
② 提供了一个初始化函数init,这个函数进行了对触发器的查找,并给触发器添加了进入逻辑。
③ 通过控制角色布娃娃属性的开启或关闭来代表死亡与复活。
④ 复活位置即是场景上初生点的位置,我们可以从属性面板上获取这个值。
typescript
/**
* 关卡管理器
*/
export class LevelManager{
// 单例模式
private static _instacne:LevelManager
public static get instance():LevelManager{
if(LevelManager._instacne==null){
LevelManager._instacne = new LevelManager()
}
return LevelManager._instacne
}
/**死亡触发器 */
private _deathTrigger:Trigger
/**复活位置 */
private _rebornPosition:Vector = new Vector(10,0,420)
public async init(){
this._deathTrigger = await GameObject.asyncFindGameObjectById("299CDDA6") as Trigger
this._deathTrigger.onEnter.add((other:GameObject)=>{
// 当进入的物体是角色类型
if(other instanceof Character){
// 让角色死亡
this.charDeath(other)
}
})
}
/**让角色死亡 */
private charDeath(char:Character){
// 开启布娃娃属性
char.ragdollEnabled = true
setTimeout(() => {
// 让角色复活
this.charReborn(char)
}, 3000);
}
/**让角色复活 */
private charReborn(char:Character){
// 将角色的位置改变到复活点
char.worldTransform.position = this._rebornPosition.clone()
// 关闭布娃娃属性
char.ragdollEnabled = false
}
}
/**
* 关卡管理器
*/
export class LevelManager{
// 单例模式
private static _instacne:LevelManager
public static get instance():LevelManager{
if(LevelManager._instacne==null){
LevelManager._instacne = new LevelManager()
}
return LevelManager._instacne
}
/**死亡触发器 */
private _deathTrigger:Trigger
/**复活位置 */
private _rebornPosition:Vector = new Vector(10,0,420)
public async init(){
this._deathTrigger = await GameObject.asyncFindGameObjectById("299CDDA6") as Trigger
this._deathTrigger.onEnter.add((other:GameObject)=>{
// 当进入的物体是角色类型
if(other instanceof Character){
// 让角色死亡
this.charDeath(other)
}
})
}
/**让角色死亡 */
private charDeath(char:Character){
// 开启布娃娃属性
char.ragdollEnabled = true
setTimeout(() => {
// 让角色复活
this.charReborn(char)
}, 3000);
}
/**让角色复活 */
private charReborn(char:Character){
// 将角色的位置改变到复活点
char.worldTransform.position = this._rebornPosition.clone()
// 关闭布娃娃属性
char.ragdollEnabled = false
}
}
5.功能测试
功能测试之前,还需要对GameStart脚本进行一下改写,让其对LevelManager进行初始化。
GameStart脚本:
ts
import { LevelManager } from "./LevelManager";
@Component
export default class GameStart extends Script {
/** 当脚本被实例后,会在第一帧更新前调用此函数 */
protected async onStart(): Promise<void> {
if (SystemUtil.isClient()) {
LevelManager.instance.init()
}
}
/**
* 周期函数 每帧执行
* 此函数执行需要将this.useUpdate赋值为true
* @param dt 当前帧与上一帧的延迟 / 秒
*/
protected onUpdate(dt: number): void {
}
/** 脚本被销毁时最后一帧执行完调用此函数 */
protected onDestroy(): void {
}
}
import { LevelManager } from "./LevelManager";
@Component
export default class GameStart extends Script {
/** 当脚本被实例后,会在第一帧更新前调用此函数 */
protected async onStart(): Promise<void> {
if (SystemUtil.isClient()) {
LevelManager.instance.init()
}
}
/**
* 周期函数 每帧执行
* 此函数执行需要将this.useUpdate赋值为true
* @param dt 当前帧与上一帧的延迟 / 秒
*/
protected onUpdate(dt: number): void {
}
/** 脚本被销毁时最后一帧执行完调用此函数 */
protected onDestroy(): void {
}
}
启动游戏后,操控角色进入地面,角色就会切换到布娃娃模式,延迟3秒后,角色会复活在起点。