是否可以在纯 JavaScript 中为游戏中的单独实例存储静态对象数组?

Is it possible store static array of objects for separate instances in game in pure JavaScript?

我有 class StdObject。我的目标是将其作为 superclass 并为继承自此 StdObject-class 的每个 classes 实例存储对象为每个对象存储数组。将调用 getAll() 存储为静态方法似乎更有意义。

class StdObject {
    static objs = [];

    //When creating new objects, these properties 
    //are used/set by default
    constructor(x=null,y=0,width=10,height=10,speed=0.4) {                   
        if (x == null) x = Math.floor(Math.random() * canvas_width);
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.speed = speed;
        this.friction = 0.3;    
        this.color = '#000000'; 
        this.gravity = 0;    
        this.constructor.addObj(); //Add this instance to the array
    }

    //Update is here if no update() is created in classes
    //the extends this class
    update() {};
        
    //Render the objects to the canvas as rectangle
    //If another shape should be used, just create a render() in that class
    //to overwrite this method
    render() {      
        ctx.clearRect(this.x, this.y, this.width, this.height);  
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.width, this.height);       
    }

    //Adds an object to objects array objs
    static addObj() {
        this.objs.push(this);
    }

    //Gets a specific object in array objs
    static getObj(index) {
        return this.objs[index];
    }

    //Get all objects (StdObject.getAll() is called instead of the actual class used)
    //because there are no inheritance when static methods are used.
    static getAll() {
        console.log(this);
        console.log('ALL OBJECTS=');
        console.log(this.objs);
        return this.objs;
    }

}

class Ball extends StdObject {
    constructor(x,y,width,height,speed) {
        super(x,y,width,height,speed);      
        this.angle = 0;
        this.shoot = 0;
        this.moving = false;
        this.speed = 0;
        this.radius = 7;
    }

    update() {
       //Move, update of positions for these balls etc
    }

    render() {
        //Update to canvas
    }
}

class Enemy extends StdObject {
    constructor(x,y,width,height,speed) {
        super(x,y,width,height,speed);      
        this.angle = 0;
        this.shoot = 0;
        this.moving = false;
        this.speed = 0;
    }

    update() {
       //Move, update of positions for these enemies etc
    }

    render() {
        //Update to canvas
    }
}

在游戏循环中我想做这样的事情:

var obl = StdObject.getAll().length;

function gameLoop() {
    let i;
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    for(i=0;i<obl;i++) {
        StdObject.getObj[i].update();
    }

    for(i=0;i<obl;i++) {
        StdObject.getObj[i].render();          
    }
    
    window.requestAnimationFrame(gameLoop);
}

问题是 StdObject.getObj[i].update();StdObject.getObj[i].render(); 没有引用对象的实际实例(它们引用了 StdObject class 中静态数组内部的对象) .因此我得到错误

Uncaught TypeError:无法在 gameLoop

读取未定义的属性(读取 'update')

这可以用静态方法解决吗?(创建一个对象的实例只是为了检索该对象的所有实例是没有意义的。)

(是的,我知道我可以存储一个包含所有对象数组的全局变量,然后循环遍历它们并调用 update() 和 render() )

代码存在多个问题。

  1. 您正在尝试将函数作为数组调用,但它应该作为函数调用,StdObject.getObj(i).render() 而不是 StdObject.getObj[i].render();
  2. 在构造函数中创建实例时,它没有在数组 objs 中正确注册。

class StdObject {
            static objs = [];
            //When creating new objects, these properties 
            //are used/set by default
            constructor(x=null,y=0,width=10,height=10,speed=0.4) {                   
                if (x == null) x = Math.floor(Math.random() * canvas_width);
                this.x = x;
                this.y = y;
                this.width = width;
                this.height = height;
                this.speed = speed;
                this.friction = 0.3;    
                this.color = '#000000'; 
                this.gravity = 0;    
                StdObject.addObj(this); //Add this instance to the array
            }
        
            //Update is here if no update() is created in classes
            //the extends this class
            update() {};
                
            //Render the objects to the canvas as rectangle
            //If another shape should be used, just create a render() in that class
            //to overwrite this method
            render() {      
                ctx.clearRect(this.x, this.y, this.width, this.height);  
                ctx.fillStyle = this.color;
                ctx.fillRect(this.x, this.y, this.width, this.height);       
            }
        
            //Adds an object to objects array objs
            static addObj(obj) 
            {
                StdObject.objs.push(obj);
            }
        
            //Gets a specific object in array objs
            static getObj(index) {
                return this.objs[index];
            }
        
            //Get all objects (StdObject.getAll() is called instead of the actual class used)
            //because there are no inheritance when static methods are used.
            static getAll() {
                console.log(this);
                console.log('ALL OBJECTS=');
                console.log(this.objs);
        
                return this.objs;
            }
        
        }
        
        class Ball extends StdObject {
            constructor(x,y,width,height,speed) {
                super(x,y,width,height,speed);      
                this.angle = 0;
                this.shoot = 0;
                this.moving = false;
                this.speed = 0;
                this.radius = 7;
            }
        
            update() {
               //Move, update of positions for these balls etc
                console.log('Ball update');
            }
        
            render() {
                //Update to canvas
                console.log('Ball render');
            }
        }
        
        class Enemy extends StdObject {
            constructor(x,y,width,height,speed) {
                super(x,y,width,height,speed);      
                this.angle = 0;
                this.shoot = 0;
                this.moving = false;
                this.speed = 0;
            }
        
            update() {
               //Move, update of positions for these enemies etc
            console.log('update enemy');
            }
        
            render() {
                //Update to canvas
                console.log('render enemy');
            }
        }
        
        
        
        var enemy = new Enemy(100,100,10,10,0.4);
        var ball = new Ball(100,100,10,10,0.4);
        
        const ctx = document.getElementById('canvas').getContext('2d');
        
        function gameLoop() 
        {
        var obl = StdObject.getAll().length;
        
            let i;
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            for(i=0;i<obl;i++) {
                StdObject.getObj(i).update();
            }
        
            for(i=0;i<obl;i++) {
                StdObject.getObj(i).render();          
            }
            
            window.requestAnimationFrame(gameLoop);
        }
        
        gameLoop();