Skip to content
触发器与触发检测

触发器与触发检测

阅读本文大概需要 15 分钟。

游戏开发中,触发器可谓是无处不在,甚至很多游戏编辑器的主要开发手段就是触发器 + 事件,走到物品上拾取物品、走到某个区域触发某个剧情、走到陷阱上减少血量等等,接下来我们就来看看如何实现触发检测吧。

关于触发器使用见产品文档:触发器

1. 使用触发器实现触发检测

触发器可以用来划定一个区域,当有游戏物体进入该区域或离开该区域时,触发器就会触发相应的事件,开发者在接收到事件后编写对应的游戏逻辑,即可完成各种各样的触发功能。例如设置一个道具触发器,玩家就可以进入该区域获取道具;设置一个沼泽区域,玩家进入后会降低移动速度;设置一个陷阱区域,玩家进入后就会持续掉血等。

注意

触发器不会与另外一个触发器产生检测事件。

1.1 创建触发器

接下来我们创建一个触发器,在游戏功能对象中,将触发器拖拽到场景中,即可使用触发器,如图:

如果拖拽到场景上之后,没有看到半透明的方块,可以检查 ①显示 --> ② 图标与线框 是否为开启状态。只有开启才可以在编辑器主视口中看到触发器。

打开线框

1.2 在运行时显示触发器

因为触发器只是划定了一个区域,在,当我们运行游戏后,就找不到我们触发器所在位置了。这时我们可以使用调试命令将它显示出来:

  • 我们可以在运行后按下 ~ 键呼出控制台。
  • 输入 show Collision 按下回车,即可看到触发器的线框。

1.3 在脚本中添加事件监听

这里我们创建一个脚本,命名为 TriggerTest,将脚本添加到对象列表中,如图:

右键触发器,在菜单中单击 “复制对象 ID”,将触发器的 对象ID 保存下来,如图;

复制对象id

打开脚本编写代码,为触发器添加监听事件,代码如下:

typescript
@Component
export default class TriggerTest extends Script {

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected onStart(): void {
        //这里在服务端进行示例
        if (SystemUtil.isServer()) {
            //通过上面复制的 guid 获取触发器对象
            const trigger = GameObject.findGameObjectById("2BFB0766") as Trigger;
            //为触发器绑定 有物体进入时 会触发的监听事件
            trigger.onEnter.add(this.onTriggerEnter);
            //为触发器绑定 有物体离开时 会触发的监听事件
            trigger.onLeave.add(this.onTriggerLeave);
        }
    }

    //有物体进入了触发区域,other 为进入触发区域的物体对象
    private onTriggerEnter(other: GameObject) {
        //这里判断一下进入区域的物体是不是一名角色
        if (other instanceof Character) {
            //是的话,转成角色类型
            const character = other as Character;
            //修改角色名称
            character.displayName = "进入区域";
        }
    }

    //有物体离开了触发区域
    private onTriggerLeave(other: GameObject) {
        //这里判断一下离开区域的物体是不是一名角色
        if (other instanceof Character) {
            //是的话,转成角色类型
            const character = other as Character;
            //修改角色名称
            character.displayName = "离开区域";
        }
    }
}
@Component
export default class TriggerTest extends Script {

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected onStart(): void {
        //这里在服务端进行示例
        if (SystemUtil.isServer()) {
            //通过上面复制的 guid 获取触发器对象
            const trigger = GameObject.findGameObjectById("2BFB0766") as Trigger;
            //为触发器绑定 有物体进入时 会触发的监听事件
            trigger.onEnter.add(this.onTriggerEnter);
            //为触发器绑定 有物体离开时 会触发的监听事件
            trigger.onLeave.add(this.onTriggerLeave);
        }
    }

    //有物体进入了触发区域,other 为进入触发区域的物体对象
    private onTriggerEnter(other: GameObject) {
        //这里判断一下进入区域的物体是不是一名角色
        if (other instanceof Character) {
            //是的话,转成角色类型
            const character = other as Character;
            //修改角色名称
            character.displayName = "进入区域";
        }
    }

    //有物体离开了触发区域
    private onTriggerLeave(other: GameObject) {
        //这里判断一下离开区域的物体是不是一名角色
        if (other instanceof Character) {
            //是的话,转成角色类型
            const character = other as Character;
            //修改角色名称
            character.displayName = "离开区域";
        }
    }
}

运行程序后,可以看到当我们的角色进入触发区就会改名为“进入区域”,离开触发区就会改名为“离开区域”:

触发器除了可以检测物体进入的瞬间与离开的瞬间外,还提供给开发者一个很好用的功能,就是判断某个物体是否在触发区域内,使用方法也非常简单,代码如下:

typescript
@Component
export default class TriggerTest extends Script {

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected onStart(): void {
        //这里在服务端进行示例
        if (SystemUtil.isServer()) {
            //通过上面复制的 guid 获取触发器对象
            const trigger = GameObject.findGameObjectById("2BFB0766") as Trigger
            //通过触发器的方法,传入任意一个物体,就会返回 bool 值,代表该物体是否在触发区域内
            const isIn = trigger.checkInArea(this.gameObject)
        }
    }
}
@Component
export default class TriggerTest extends Script {

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected onStart(): void {
        //这里在服务端进行示例
        if (SystemUtil.isServer()) {
            //通过上面复制的 guid 获取触发器对象
            const trigger = GameObject.findGameObjectById("2BFB0766") as Trigger
            //通过触发器的方法,传入任意一个物体,就会返回 bool 值,代表该物体是否在触发区域内
            const isIn = trigger.checkInArea(this.gameObject)
        }
    }
}

1.4 触发器形状

单击 “对象管理器” 面板,选中触发器对象,在触发器的属性面板中可以看到碰撞类型,默认为盒体,也就是立方体,这里也可以修改成球体,效果如图:

2. 使用静态模型自身触发检测

有时候我们需要让物体自身就可以进行触发检测,比如制作拾取物品时。这时就可以使用静态模型本身的触发事件onTouchonTouchEnd 来进行检测:

2.1 添加进入与离开事件

新建一个脚本文件命名为 ModelTouch 将下文代码复制进去。这段代码实现了玩家碰到挂载脚本的物体后就将这个物体隐藏,玩家离开这个物体之后物体重新显示。

typescript
@Component
export default class ModelTouch extends Script {

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected onStart(): void {

        // 将要当前 GameObject 转换为 Model 类型
        const model = this.gameObject as Model;

        // 添加进入模型事件
        model.onTouch.add((other) => {
            if (other instanceof Character) {
                //是的话关闭金币模型显示
                model.setVisibility(false);
            }
        });

        // 添加离开模型事件
        model.onTouchEnd.add((other) => {
            //这里判断一下离开区域的物体是不是一名角色
            if (other instanceof Character) {
                //是的话显示金币模型
                model.setVisibility(true);
            }
        });
    }
}
@Component
export default class ModelTouch extends Script {

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected onStart(): void {

        // 将要当前 GameObject 转换为 Model 类型
        const model = this.gameObject as Model;

        // 添加进入模型事件
        model.onTouch.add((other) => {
            if (other instanceof Character) {
                //是的话关闭金币模型显示
                model.setVisibility(false);
            }
        });

        // 添加离开模型事件
        model.onTouchEnd.add((other) => {
            //这里判断一下离开区域的物体是不是一名角色
            if (other instanceof Character) {
                //是的话显示金币模型
                model.setVisibility(true);
            }
        });
    }
}

2.2 添加模型

接下来,我们拖出一个金币模型当作拾取物,在对象管理器中选中它,并将它的碰撞类型改为 仅开启检测

然后将刚刚编写好的 ModelTouch 脚本拖拽到金币模型下,当作金币模型的子物体:

运行起来,我们控制玩家角色去触碰金币。就可以看到在碰到的瞬间,金币消失不见了,等玩家离开金币它就又显示出来了。