Javascript Typescript:can';t从另一个模块调用函数

Javascript Typescript:can';t从另一个模块调用函数,javascript,typescript,Javascript,Typescript,我目前的项目是一个简单的多人游戏。客户端和服务器都是用Typescript编写的。客户端只处理输入并渲染游戏,所有逻辑都在服务器端实现 服务器代码使用nodejs执行,结构如下 main.ts包含一个express服务器,为html文件提供客户端脚本。此外,它还设置socket.io,创建一个新的游戏实例,并为每个连接的套接字创建一个新的Player实例 game.ts导出类game和Player。游戏实际上只是所有重要数据的容器。它存储所有玩家的列表和所有游戏对象的列表Game实现方法req

我目前的项目是一个简单的多人游戏。客户端和服务器都是用Typescript编写的。客户端只处理输入并渲染游戏,所有逻辑都在服务器端实现

服务器代码使用nodejs执行,结构如下

  • main.ts包含一个express服务器,为html文件提供客户端脚本。此外,它还设置socket.io,创建一个新的游戏实例,并为每个连接的套接字创建一个新的
    Player
    实例

  • game.ts导出类
    game
    Player
    游戏实际上只是所有重要数据的容器。它存储所有玩家的列表和所有游戏对象的列表
    Game
    实现方法
    requestSpawn(…)
    ,该方法检查是否可能生成新的游戏对象。类
    Player
    只是socket.io套接字的包装器。它处理传入和传出的消息。如果客户端试图生成游戏对象,则会向服务器发送一条消息,并到达
    Player
    实例中存储的套接字。
    Player
    实例然后调用
    requestSpawn
    来尝试生成所需的
    GameObject

  • GameObjects.ts导出接口
    GameObject
    和此接口的各种实现

游戏运行方式如下:

  • 一个人在html画布中单击
  • 一个新的“REQUESTSPAWN”消息被打包并发送到服务器
  • Player
    实例接收消息并在其
    Game
    实例上调用
    requestSpawn
  • Game
    实例在正确位置创建正确类型的新
    GameObject
    ,并将其添加到
    GameObjects
  • 这个新的
    GameObject
    现在应该更新了
  • 但事实并非如此。 以下是相关代码:

    game.ts

    import go = module("GameObjects"); 
    import util = module("Utilities");
    
    //...
    
    export class Game {
        private players: Player[];
        public gameObjects:go.GameObject[];
        private gameObjectCounter: number;
    
        constructor() {
            this.players = [];
            this.gameObjectCounter = 0;
            this.gameObjects = [];
            var prev = Date.now();
            var deltaTime = Date.now() - prev;
            setInterval(() =>{ deltaTime = Date.now() - prev; prev = Date.now(); this.update(deltaTime); }, 200);
        }
    
        broadcast(msg: Message) {
            this.players.forEach((player) => { player.send(msg); });
        }
    
        requestSpawn(msg:RequestSpawnMessage, clientID:number): bool {
            var pos = new util.Vector2(msg.x, msg.y);        
            var o: go.GameObject;
            switch (msg.tag) {
                case UID.FACTORY:                                        
                    o = new go.Factory(pos.clone(), this.players[clientID], this.newGameObject());
                case UID.ROBOT:
                    o = new go.Robot(pos.clone(), this.players[clientID], this.newGameObject());
            }
            this.broadcast(new SpawnMessage(msg.tag, o.id, clientID, pos.x, pos.y));
            this.gameObjects.push(o);
            console.log(this.gameObjects);
            o.update(1);
            console.log("tried to update the factory");
            return true;
        }
    
        update(deltaTime){
            this.gameObjects.forEach((object) =>{object.update(deltaTime); });
        }
    
        addPlayer(socket: Socket) {        
            var player = new Player(this, socket, this.players.length);
            this.players.push(player);
        }
        newGameObject() : number {
            return this.gameObjectCounter++;
        }
    }
    
    GameObjects.ts

    export import util = module("Utilities");
    export import s = module("server");
    export import g = module("game");
    
    export interface GameObject{
        tag: g.UID;
        id:number;
        player: g.Player;
        clientId: number;
        pos:util.Vector2;
        getPos():util.Vector2;
        setPos(newPos:util.Vector2);
        // !TODO how to make that const?
        boundingBox: util.Rectangle;
        update(deltaTime:number);
    }
    
    export class Factory implements GameObject {
        tag: g.UID;
        id: number;
        player: g.Player;
        clientId: number;
        server: s.Server;
        //variables for handling the delay between spawning robots
        private current_time: number;
        public delay: number;
        boundingBox: util.Rectangle;
    
        public static dimensions = new util.Vector2(30, 30);
        constructor(pos: util.Vector2, player:g.Player, id: number) {
            this.pos = pos;
            this.tag = g.UID.FACTORY;
            this.player = player;
            this.clientId = this.player.getID();
            this.current_time = 0;
            this.delay = 1;
            this.id = id;
            this.boundingBox = new util.Rectangle(pos, Factory.dimensions.x, Factory.dimensions.y);
            console.log("just created a factory");
            //this.update(1);
        }
    
        pos: util.Vector2;
        getPos() { return this.pos; }
        setPos(pos: util.Vector2) { this.pos = pos; }
    
        public once = true;
        //check if it's time to create a new robot
        public update(deltaTime: number) {
            console.log("updating a factory");
    
            //this code will produce a robot just once, this is handy for development, since there's not so much waiting time
            if (this.once) { this.player.requestSpawn(g.UID.ROBOT, this.pos.x, this.pos.y); console.log("just spawned a robot"); }
            this.once = false;
            /*this.current_time += deltaTime/1000;
            if (this.current_time > this.delay*(Factory.count+1)/(Mine.count+1)) {
                this.current_time = 0;
                this.spawnRobot();
            }*/
        }
    }
    
    
    //this will be the fighting robot meant to destroy enemy factories
    export class Robot implements GameObject{
        tag: g.UID;
        id: number;
        player:g.Player;
        clientId: number;
        game: g.Game;
        boundingBox: util.Rectangle;
        // ! TODO constants should have capital letters.
        public static radius = 15;
        constructor(pos:util.Vector2,player:g.Player,id:number){ 
            this.tag = g.UID.ROBOT;
            this.player=player;
            this.clientId = this.player.getID();
            this.boundingBox = new util.Rectangle(pos, Robot.radius, Robot.radius);
        }
    
        pos:util.Vector2;
        getPos(){return this.pos;}
        setPos(pos:util.Vector2){this.pos=pos;}
    
        //now the robot is moved by keyboard input but soon it will check the gameObjects array and search for the closest enemy,
        //in order to attack it
        public update(deltaTime: number) {
    
        }
    }
    
    现在,工厂实例的update方法的第一次调用生成一个robot,之后工厂“休眠”。机器人在更新方法中什么也不做

    我想引导大家注意两行代码: -在
    requestSpawn
    方法中,
    GameObject
    立即更新为deltaTime=1

    这意味着,在一个工厂诞生之后,机器人也应该诞生。但事实并非如此。我在
    requestSpawn
    方法中添加了
    console.log
    调用。它成功地打印了“只是试图更新一个工厂”,但是,什么也没有发生。 所以我认为update方法工作不正常,并在那里添加了一个
    console.log
    调用。这是
    工厂
    更新
    方法的第一行,应该打印“更新工厂”。但这永远不会发生

    我真的很困惑。应该调用该方法,但它不是。虽然它是公开的,但我认为问题可能与访问权有关。这是第二行代码,我想指出: -在工厂的构造函数中,我注释掉了对
    this.update(1)
    的调用

    我认为至少自己的构造函数应该能够调用update方法。确实如此。当此行未注释掉时,将调用一次update。然后,工厂尝试生成一个新机器人,并在其
    游戏
    实例上调用
    requestSpawn()
    。因此,将创建一个新机器人,并向所有客户端发送一条
    SpawnMessage
    。机器人甚至出现在客户端的浏览器选项卡中


    因此,显然没有调用该方法。一切正常,消息解析、工厂更新和机器人创建都是正确的。唯一的问题是,
    Game
    中的所有更新调用都不会执行。出了什么问题?

    您已经发布了很多代码,可能还有其他问题,但至少有一个问题是您缺少switch语句中的
    break

    switch (msg.tag) {
            case UID.FACTORY:                                        
                o = new go.Factory(pos.clone(), this.players[clientID], this.newGameObject());
            case UID.ROBOT:
                o = new go.Robot(pos.clone(), this.players[clientID], this.newGameObject());
    }
    
    …因此总是创建一个
    机器人
    ,它在其
    更新()方法中不跟踪任何内容。(如果您尝试创建一个
    工厂
    ,您会成功,但随后会通过将一个新的
    机器人
    分配给同一个var
    o
    来立即覆盖它)

    考虑这个简化的例子:

    interface GameObject {
        update():void;
    }
    
    class Factory implements GameObject {
        update():void {
            console.log("Factory");
        }
    }
    
    class Robot implements GameObject {
        update():void {
            console.log("Robot");
        }
    }
    
    class Test {
    
        private o:GameObject;
    
        constructor(index:number){
            switch(index){
                case 1:
                    this.o = new Factory();
                case 2:
                    this.o = new Robot();
            }
            this.o.update();
        }
    }
    
    class BreakTest {
    
        private o:GameObject;
    
        constructor(index:number){
            switch(index){
                case 1:
                    this.o = new Factory();
                    break;
                case 2:
                    this.o = new Robot();
                    break; // Not necessary in final case, but good form IMO.
            }
            this.o.update();
        }
    }
    
    var t = new Test(1);       // Traces 'Robot'
    var tt = new Test(2);      // Traces 'Robot'
    
    var b = new BreakTest(1);  // Traces 'Factory'
    var bt = new BreakTest(2); // Traces 'Robot'
    

    ()

    是的,这很有效。多么令人尴尬的错误。谢谢你找到它