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) {
? ? ? ?
? ? }
? ? //點擊設置時執(zhí)行的方法:
? ? onOpenSetting(){
? ? ? ? //打開UISetting
? ? ? ? UIManager.instance.openDialog(DialogDef.UISetting);
? ? }
? ? //點擊退出游戲執(zhí)行的方法:
? ? onExitGame(){
? ? ? ? console.log("點擊了Exit");
? ? ? ? //釋放此包中的所有沒有用到的資源:
? ? ? ? resources.releaseUnusedAssets();
? ? ? ? //退出游戲,即回到startup開始界面:
? ? ? ? director.loadScene("startup");
? ? }
? ? //暫停游戲執(zhí)行的方法:
? ? 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";
//枚舉的作用是列舉類型中包含的各個值,一般用它來管理多個相同系列的常量(即不能被修改的變量),用于狀態(tài)的判斷。
export enum DialogDef{
? ? UISetting = 'UISetting',
? ? UISkillUpgrade = 'UISkillUpgrade',
}
export class UIManager{
? ? /*
? ? 把UIManager設置為單例類。
? ? public表示公開,private表示私有,protected表示只有自己以及繼承關系的才可以訪問。
? ? */
? ? private static _instance:UIManager = null;
? ? //static表示這個方法是靜態(tài)的。并且允許外界通過get來獲取這個方法。
? ? static get instance():UIManager{
? ? ? ? //如果這個實例為空,則將UIManager實例化。
? ? ? ? if (this._instance == null) {
? ? ? ? ? ? this._instance = new UIManager();
? ? ? ? }
? ? ? ? return this._instance;
? ? ? ?
? ? }
? ? //聲明uiRoot,類型為節(jié)點,初始值為空,用于實例化UIRoot節(jié)點。
? ? uiRoot:Node = null;
? ? /*
? ? 把加載的數據存放到內存中,避免重復加載。Map()是一種數據結構。
? ? Map 對象存有鍵值對,其中的鍵可以是任何數據類型。Map 對象記得鍵的原始插入順序。
? ? 可以把對象放在Map中,方便后續(xù)取用,效率更高。
? ? 詳細解釋可以參考JS文檔:https://www.w3school.com.cn/js/js_object_maps.asp
? ? panels是參數,:后面是類型,類型是Map,Map有兩個參數,string字符串和Node節(jié)點。
? ? */
? ? 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");
? ? ? ? }
? ? ? ?
? ? ? ? /*
? ? ? ? 后續(xù)執(zhí)行時,因為resources.load中已經將該資源放入Map,因此這里可以直接取出來利用。
? ? ? ? 然后再進行激活。
? ? ? ? 這個方法的目的時進行判斷,如果Map中存在Panel,則直接取出,進行實例化,
? ? ? ? 不再執(zhí)行resources.load,避免重復加載預制體。
? ? ? ? */
? ? ? ? if (this.panels.has(name)) {
? ? ? ? ? ? //從Map中取出name,name是panel并實例化。
? ? ? ? ? ? let panel = this.panels.get(name);
? ? ? ? ? ? //把panel的狀態(tài)進行激活。
? ? ? ? ? ? panel.active = true;
? ? ? ? ? ? //判斷是否需要將panel的層級進行提升。
? ? ? ? ? ? if (bringToTop) {
? ? ? ? ? ? ? ? //當bringToTop為真時,panel.parent.children.length - 1表示panel所有父節(jié)點的子節(jié)點場層級-1,就是往上移動一個層級。
? ? ? ? ? ? ? ? const index = panel.parent.children.length - 1;
? ? ? ? ? ? ? ? //向上移動一個層級后,將index參數傳入,setSiblingIndex表示設置置當前節(jié)點在父節(jié)點的 children 數組中的位置。
? ? ? ? ? ? ? ? panel.setSiblingIndex(index);
? ? ? ? ? ? }
? ? ? ? ? ? //中止函數,不再往下執(zhí)行。
? ? ? ? ? ? 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節(jié)點下增加panel子節(jié)點:
? ? ? ? ? ? this.uiRoot.addChild(panel);
? ? ? ? ? ? //this.panels.set就是給Map()設置一個鍵值,內容是name,而這個name就是節(jié)點panel。
? ? ? ? ? ? this.panels.set(name,panel);
? ? ? ? ? ? if (bringToTop) {
? ? ? ? ? ? ? ? //當bringToTop為真時,panel.parent.children.length - 1表示panel所有父節(jié)點的子節(jié)點場層級-1,就是往上移動一個層級。
? ? ? ? ? ? ? ? const index = panel.parent.children.length - 1;
? ? ? ? ? ? ? ? //向上移動一個層級后,將index參數傳入,setSiblingIndex表示設置置當前節(jié)點在父節(jié)點的 children 數組中的位置。
? ? ? ? ? ? ? ? panel.setSiblingIndex(index);
? ? ? ? ? ? }
? ? ? ? });
? ? }
?
? ? //關閉面板的方法:
? ? closePanel(name:string, destory:boolean = false){
? ? ? ? //判斷面板是否存在,如果不存在,直接中斷函數。
? ? ? ? if(!this.panels.has(name)){
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? //如果存在,則從Map中取出預制體。
? ? ? ? let panel = this.panels.get(name);
? ? ? ? /*
? ? ? ? 如果需要銷毀預制體,則聰Map中刪除相關預制體,并從父節(jié)點移除
? ? ? ?
? ? ? ? 0該節(jié)點。
? ? ? ? 是否銷毀根據closePanel(name:string, destory:boolean = false)傳入的
? ? ? ? destory:boolean = false參數決定,如果=true則銷毀。這里是false則表示不銷毀,
? ? ? ? 當前代碼只是示例。
? ? ? ? */
? ? ? ? if (destory) {
? ? ? ? ? ? this.panels.delete(name);
? ? ? ? ? ? panel.removeFromParent();
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? //如果不銷毀,只是隱藏,則關閉該節(jié)點。
? ? ? ? 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); ? ?
? ? ? ? }
? ? }
}