【问题标题】:Typescript: can't call function from another module打字稿:无法从另一个模块调用函数
【发布时间】:2013-02-25 05:00:45
【问题描述】:

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

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

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

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

  • GameObjects.ts 导出接口GameObject 以及该接口的各种实现。

游戏是这样运行的:

  1. 一个人在 html-canvas 内点击
  2. 一个新的“REQUESTSPAWN”消息被打包并发送到服务器
  3. Player 实例接收消息并在其Game 实例上调用requestSpawn
  4. Game 实例在正确位置创建一个正确类型的新GameObject,并将其添加到GameObjects 列表中
  5. 现在应该更新这个新的GameObject

事实并非如此。 以下是相关代码:

游戏.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) {

    }
}

现在第一次调用工厂实例的更新方法会生成一个机器人,然后工厂“休眠”。机器人在更新方法中什么都不做。

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

这意味着在生成工厂之后,也应该直接生成机器人。但这不会发生。我在requestSpawn 方法中添加了一个console.log 调用。它成功打印了“刚刚尝试更新工厂”,但没有任何反应。 所以我认为更新方法无法正常工作,并在那里添加了console.log 调用。这是Factory'supdate 方法的第一行,应该打印“更新工厂”。但这永远不会发生。

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

我认为至少自己的构造函数应该能够调用更新方法。的确是。当这一行没有被注释掉时,更新被调用一次。然后工厂尝试生成一个新机器人并在其Game 实例上调用requestSpawn()。结果,创建了一个新机器人,并且SpawnMessage 发送给所有客户端。机器人甚至出现在客户端的浏览器选项卡中。

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

【问题讨论】:

    标签: javascript typescript


    【解决方案1】:

    您已经发布了很多代码,可能还有其他问题,但至少有一个问题是您在 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());
    }
    

    ...因此总是创建一个Robot,它在其update() 方法中没有任何痕迹。 (如果您尝试创建 Factory,您会成功,但随后会立即通过将新的 Robot 分配给相同的 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'
    

    (Ref)

    【讨论】:

    • 是的,这行得通。多么尴尬的错误。感谢您找到它
    猜你喜欢
    • 1970-01-01
    • 2023-03-12
    • 2015-05-09
    • 1970-01-01
    • 2019-04-21
    • 2021-09-06
    • 1970-01-01
    • 2018-06-18
    • 2017-01-16
    相关资源
    最近更新 更多