TypeError: The thing you want to instantiate must be an object是怎
【故障現(xiàn)象】


跟著B站的視頻學(xué)小游戲,點(diǎn)擊的時(shí)候會(huì)報(bào)錯(cuò),一直找不到原因
點(diǎn)擊的時(shí)候會(huì)調(diào)用這個(gè)onOpenSetting方法
??onOpenSetting(){
? ? ? ??//打開UISetting
? ? ? ??UIManager.instance.openDialog(DialogDef.UISetting);
? ? }
然后就會(huì)報(bào)這個(gè)錯(cuò)誤:
TypeError: The thing you want to instantiate must be an object
說你想要實(shí)例化的東西必須是一個(gè)對象
但是我沒找到問題,大佬們幫忙看下
【源碼】
//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) {
? ? ? ?
? ? }
? ? //點(diǎn)擊設(shè)置時(shí)執(zhí)行的方法:
? ? onOpenSetting(){
? ? ? ? //打開UISetting
? ? ? ? UIManager.instance.openDialog(DialogDef.UISetting);
? ? }
? ? //點(diǎn)擊退出游戲執(zhí)行的方法:
? ? onExitGame(){
? ? ? ? console.log("點(diǎn)擊了Exit");
? ? ? ? //釋放此包中的所有沒有用到的資源:
? ? ? ? resources.releaseUnusedAssets();
? ? ? ? //退出游戲,即回到startup開始界面:
? ? ? ? director.loadScene("startup");
? ? }
? ? //暫停游戲執(zhí)行的方法:
? ? onPauseGame(){
? ? ? ? console.log("點(diǎn)擊了Pause");
? ? ? ? //進(jìn)行判斷,如果當(dāng)前游戲暫停,則恢復(fù)暫停。isPaused表示是否暫停,resume表示恢復(fù)暫停。否則暫停游戲。
? ? ? ? if(director.isPaused()){
? ? ? ? ? ? director.resume();
? ? ? ? ? ? //return可以將代碼格式化嗎?
? ? ? ? ? ? return;
? ? ? ? }else{
? ? ? ? ? ? director.pause();
? ? ? ? }
? ? }
}
//UIManager
import { find, instantiate, Node, Prefab, resources } from "cc";
//枚舉的作用是列舉類型中包含的各個(gè)值,一般用它來管理多個(gè)相同系列的常量(即不能被修改的變量),用于狀態(tài)的判斷。
export enum DialogDef{
? ? UISetting = 'UISetting',
? ? UISkillUpgrade = 'UISkillUpgrade',
}
export class UIManager{
? ? /*
? ? 把UIManager設(shè)置為單例類。
? ? public表示公開,private表示私有,protected表示只有自己以及繼承關(guān)系的才可以訪問。
? ? */
? ? private static _instance:UIManager = null;
? ? //static表示這個(gè)方法是靜態(tài)的。并且允許外界通過get來獲取這個(gè)方法。
? ? static get instance():UIManager{
? ? ? ? //如果這個(gè)實(shí)例為空,則將UIManager實(shí)例化。
? ? ? ? if (this._instance == null) {
? ? ? ? ? ? this._instance = new UIManager();
? ? ? ? }
? ? ? ? return this._instance;
? ? ? ?
? ? }
? ? //聲明uiRoot,類型為節(jié)點(diǎn),初始值為空,用于實(shí)例化UIRoot節(jié)點(diǎn)。
? ? uiRoot:Node = null;
? ? /*
? ? 把加載的數(shù)據(jù)存放到內(nèi)存中,避免重復(fù)加載。Map()是一種數(shù)據(jù)結(jié)構(gòu)。
? ? Map 對象存有鍵值對,其中的鍵可以是任何數(shù)據(jù)類型。Map 對象記得鍵的原始插入順序。
? ? 可以把對象放在Map中,方便后續(xù)取用,效率更高。
? ? 詳細(xì)解釋可以參考JS文檔:https://www.w3school.com.cn/js/js_object_maps.asp
? ? panels是參數(shù),:后面是類型,類型是Map,Map有兩個(gè)參數(shù),string字符串和Node節(jié)點(diǎn)。
? ? */
? ? panels : Map<string, Node> = new Map();
? ? //打開面板的方法,傳入2個(gè)參數(shù):name:string表示預(yù)制體的名稱,bringToTop:Boolean = true表示是否調(diào)整預(yù)制體的層級:
? ? openPanel(name:string, bringToTop:Boolean = true){
? ? ? ? /*
? ? ? ? 當(dāng)uiRoot == null時(shí),就是沒有實(shí)例化時(shí),查找UIRoot并賦值給uiRoot。
? ? ? ? 通過if語句進(jìn)行判斷,防止重復(fù)初始化。
? ? ? ? */
? ? ? ? if (this.uiRoot == null) {
? ? ? ? ? ? this.uiRoot = find("UIRoot");
? ? ? ? }
? ? ? ?
? ? ? ? /*
? ? ? ? 后續(xù)執(zhí)行時(shí),因?yàn)閞esources.load中已經(jīng)將該資源放入Map,因此這里可以直接取出來利用。
? ? ? ? 然后再進(jìn)行激活。
? ? ? ? 這個(gè)方法的目的時(shí)進(jìn)行判斷,如果Map中存在Panel,則直接取出,進(jìn)行實(shí)例化,
? ? ? ? 不再執(zhí)行resources.load,避免重復(fù)加載預(yù)制體。
? ? ? ? */
? ? ? ? if (this.panels.has(name)) {
? ? ? ? ? ? //從Map中取出name,name是panel并實(shí)例化。
? ? ? ? ? ? let panel = this.panels.get(name);
? ? ? ? ? ? //把panel的狀態(tài)進(jìn)行激活。
? ? ? ? ? ? panel.active = true;
? ? ? ? ? ? //判斷是否需要將panel的層級進(jìn)行提升。
? ? ? ? ? ? if (bringToTop) {
? ? ? ? ? ? ? ? //當(dāng)bringToTop為真時(shí),panel.parent.children.length - 1表示panel所有父節(jié)點(diǎn)的子節(jié)點(diǎn)場層級-1,就是往上移動(dòng)一個(gè)層級。
? ? ? ? ? ? ? ? const index = panel.parent.children.length - 1;
? ? ? ? ? ? ? ? //向上移動(dòng)一個(gè)層級后,將index參數(shù)傳入,setSiblingIndex表示設(shè)置置當(dāng)前節(jié)點(diǎn)在父節(jié)點(diǎn)的 children 數(shù)組中的位置。
? ? ? ? ? ? ? ? panel.setSiblingIndex(index);
? ? ? ? ? ? }
? ? ? ? ? ? //中止函數(shù),不再往下執(zhí)行。
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? /*
? ? ? ? 1.加載面板
? ? ? ? resources.load可以通過相對路徑加載資源。
? ? ? ? "ui\prefab" + name表示ui/prefa/這個(gè)路徑下某個(gè)名字的資源,Prefab表示是預(yù)制體。
? ? ? ? =>表示箭頭函數(shù),這里相當(dāng)于:
? ? ? ? function(err:Error, data:Prefab) {}
? ? ? ? */
? ? ? ? resources.load("ui/prefab/" + name, Prefab, (err:Error, data:Prefab)=>{
? ? ? ? ? ? /*
? ? ? ? ? ? 實(shí)例化預(yù)制體并賦值給panel:
? ? ? ? ? ? data就是(err:Error,data:Prefab)里面的data,就是從預(yù)制體里面取出來的數(shù)據(jù)。
? ? ? ? ? ? */
? ? ? ? ? ? let panel = instantiate(data);
? ? ? ? ? ? //在uiRoot節(jié)點(diǎn)下增加panel子節(jié)點(diǎn):
? ? ? ? ? ? this.uiRoot.addChild(panel);
? ? ? ? ? ? //this.panels.set就是給Map()設(shè)置一個(gè)鍵值,內(nèi)容是name,而這個(gè)name就是節(jié)點(diǎn)panel。
? ? ? ? ? ? this.panels.set(name,panel);
? ? ? ? ? ? if (bringToTop) {
? ? ? ? ? ? ? ? //當(dāng)bringToTop為真時(shí),panel.parent.children.length - 1表示panel所有父節(jié)點(diǎn)的子節(jié)點(diǎn)場層級-1,就是往上移動(dòng)一個(gè)層級。
? ? ? ? ? ? ? ? const index = panel.parent.children.length - 1;
? ? ? ? ? ? ? ? //向上移動(dòng)一個(gè)層級后,將index參數(shù)傳入,setSiblingIndex表示設(shè)置置當(dāng)前節(jié)點(diǎn)在父節(jié)點(diǎn)的 children 數(shù)組中的位置。
? ? ? ? ? ? ? ? panel.setSiblingIndex(index);
? ? ? ? ? ? }
? ? ? ? });
? ? }
?
? ? //關(guān)閉面板的方法:
? ? closePanel(name:string, destory:boolean = false){
? ? ? ? //判斷面板是否存在,如果不存在,直接中斷函數(shù)。
? ? ? ? if(!this.panels.has(name)){
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? //如果存在,則從Map中取出預(yù)制體。
? ? ? ? let panel = this.panels.get(name);
? ? ? ? /*
? ? ? ? 如果需要銷毀預(yù)制體,則聰Map中刪除相關(guān)預(yù)制體,并從父節(jié)點(diǎn)移除
? ? ? ?
? ? ? ? 0該節(jié)點(diǎn)。
? ? ? ? 是否銷毀根據(jù)closePanel(name:string, destory:boolean = false)傳入的
? ? ? ? destory:boolean = false參數(shù)決定,如果=true則銷毀。這里是false則表示不銷毀,
? ? ? ? 當(dāng)前代碼只是示例。
? ? ? ? */
? ? ? ? if (destory) {
? ? ? ? ? ? this.panels.delete(name);
? ? ? ? ? ? panel.removeFromParent();
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? //如果不銷毀,只是隱藏,則關(guān)閉該節(jié)點(diǎn)。
? ? ? ? panel.active = false;
? ? }
? ? /*打開彈框:
? ? 通過名字來獲取彈框。怎么獲取彈框的名字呢,可以通過enum枚舉來定義,然后再從枚舉中獲取。
? ? */
? ? openDialog(name:string){
? ? ? ? for(let ?dialogDef in DialogDef){
? ? ? ? ? ? if (dialogDef == name) {
? ? ? ? ? ? ? ? this.openPanel(name);
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? this.closePanel(dialogDef);
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? //關(guān)閉彈框:
? ? CloseDialog(destory: boolean =false){
? ? ? ? for (let ?dialogDef in DialogDef) {
? ? ? ? ? ? this.closePanel(dialogDef,destory); ? ?
? ? ? ? }
? ? }
}