TypeError: The thing you want to instantiate must be an object是怎
【故障现象】


跟着B站的视频学小游戏,点击的时候会报错,一直找不到原因
点击的时候会调用这个onOpenSetting方法
onOpenSetting(){
//打开UISetting
UIManager.instance.openDialog(DialogDef.UISetting);
}
然后就会报这个错误:
TypeError: The thing you want to instantiate must be an object
说你想要实例化的东西必须是一个对象
但是我没找到问题,大佬们帮忙看下
【源码】
//UIGame
import { _decorator, Component, Node, director, resources, find, Prefab, instantiate } from 'cc';
import { DialogDef, UIManager } from './UIManagers';
const { ccclass, property } = _decorator;
@ccclass('UIGame')
export class UIGame extends Component {
start() {
}
update(deltaTime: number) {
}
//点击设置时执行的方法:
onOpenSetting(){
//打开UISetting
UIManager.instance.openDialog(DialogDef.UISetting);
}
//点击退出游戏执行的方法:
onExitGame(){
console.log("点击了Exit");
//释放此包中的所有没有用到的资源:
resources.releaseUnusedAssets();
//退出游戏,即回到startup开始界面:
director.loadScene("startup");
}
//暂停游戏执行的方法:
onPauseGame(){
console.log("点击了Pause");
//进行判断,如果当前游戏暂停,则恢复暂停。isPaused表示是否暂停,resume表示恢复暂停。否则暂停游戏。
if(director.isPaused()){
director.resume();
//return可以将代码格式化吗?
return;
}else{
director.pause();
}
}
}
//UIManager
import { find, instantiate, Node, Prefab, resources } from "cc";
//枚举的作用是列举类型中包含的各个值,一般用它来管理多个相同系列的常量(即不能被修改的变量),用于状态的判断。
export enum DialogDef{
UISetting = 'UISetting',
UISkillUpgrade = 'UISkillUpgrade',
}
export class UIManager{
/*
把UIManager设置为单例类。
public表示公开,private表示私有,protected表示只有自己以及继承关系的才可以访问。
*/
private static _instance:UIManager = null;
//static表示这个方法是静态的。并且允许外界通过get来获取这个方法。
static get instance():UIManager{
//如果这个实例为空,则将UIManager实例化。
if (this._instance == null) {
this._instance = new UIManager();
}
return this._instance;
}
//声明uiRoot,类型为节点,初始值为空,用于实例化UIRoot节点。
uiRoot:Node = null;
/*
把加载的数据存放到内存中,避免重复加载。Map()是一种数据结构。
Map 对象存有键值对,其中的键可以是任何数据类型。Map 对象记得键的原始插入顺序。
可以把对象放在Map中,方便后续取用,效率更高。
详细解释可以参考JS文档:https://www.w3school.com.cn/js/js_object_maps.asp
panels是参数,:后面是类型,类型是Map,Map有两个参数,string字符串和Node节点。
*/
panels : Map<string, Node> = new Map();
//打开面板的方法,传入2个参数:name:string表示预制体的名称,bringToTop:Boolean = true表示是否调整预制体的层级:
openPanel(name:string, bringToTop:Boolean = true){
/*
当uiRoot == null时,就是没有实例化时,查找UIRoot并赋值给uiRoot。
通过if语句进行判断,防止重复初始化。
*/
if (this.uiRoot == null) {
this.uiRoot = find("UIRoot");
}
/*
后续执行时,因为resources.load中已经将该资源放入Map,因此这里可以直接取出来利用。
然后再进行激活。
这个方法的目的时进行判断,如果Map中存在Panel,则直接取出,进行实例化,
不再执行resources.load,避免重复加载预制体。
*/
if (this.panels.has(name)) {
//从Map中取出name,name是panel并实例化。
let panel = this.panels.get(name);
//把panel的状态进行激活。
panel.active = true;
//判断是否需要将panel的层级进行提升。
if (bringToTop) {
//当bringToTop为真时,panel.parent.children.length - 1表示panel所有父节点的子节点场层级-1,就是往上移动一个层级。
const index = panel.parent.children.length - 1;
//向上移动一个层级后,将index参数传入,setSiblingIndex表示设置置当前节点在父节点的 children 数组中的位置。
panel.setSiblingIndex(index);
}
//中止函数,不再往下执行。
return;
}
/*
1.加载面板
resources.load可以通过相对路径加载资源。
"ui\prefab" + name表示ui/prefa/这个路径下某个名字的资源,Prefab表示是预制体。
=>表示箭头函数,这里相当于:
function(err:Error, data:Prefab) {}
*/
resources.load("ui/prefab/" + name, Prefab, (err:Error, data:Prefab)=>{
/*
实例化预制体并赋值给panel:
data就是(err:Error,data:Prefab)里面的data,就是从预制体里面取出来的数据。
*/
let panel = instantiate(data);
//在uiRoot节点下增加panel子节点:
this.uiRoot.addChild(panel);
//this.panels.set就是给Map()设置一个键值,内容是name,而这个name就是节点panel。
this.panels.set(name,panel);
if (bringToTop) {
//当bringToTop为真时,panel.parent.children.length - 1表示panel所有父节点的子节点场层级-1,就是往上移动一个层级。
const index = panel.parent.children.length - 1;
//向上移动一个层级后,将index参数传入,setSiblingIndex表示设置置当前节点在父节点的 children 数组中的位置。
panel.setSiblingIndex(index);
}
});
}
//关闭面板的方法:
closePanel(name:string, destory:boolean = false){
//判断面板是否存在,如果不存在,直接中断函数。
if(!this.panels.has(name)){
return;
}
//如果存在,则从Map中取出预制体。
let panel = this.panels.get(name);
/*
如果需要销毁预制体,则聪Map中删除相关预制体,并从父节点移除
0该节点。
是否销毁根据closePanel(name:string, destory:boolean = false)传入的
destory:boolean = false参数决定,如果=true则销毁。这里是false则表示不销毁,
当前代码只是示例。
*/
if (destory) {
this.panels.delete(name);
panel.removeFromParent();
return;
}
//如果不销毁,只是隐藏,则关闭该节点。
panel.active = false;
}
/*打开弹框:
通过名字来获取弹框。怎么获取弹框的名字呢,可以通过enum枚举来定义,然后再从枚举中获取。
*/
openDialog(name:string){
for(let dialogDef in DialogDef){
if (dialogDef == name) {
this.openPanel(name);
} else {
this.closePanel(dialogDef);
}
}
}
//关闭弹框:
CloseDialog(destory: boolean =false){
for (let dialogDef in DialogDef) {
this.closePanel(dialogDef,destory);
}
}
}