0

私の現在のプロジェクトはシンプルなマルチプレイヤーゲームです。クライアントとサーバーの両方がTypescriptで書かれています。クライアントは入力を処理してゲームをレンダリングするだけで、すべてのロジックはサーバー側に実装されます。

サーバーコードはnodejsで実行され、次のように構成されます

  • main.tsにはエクスプレスサーバーが含まれており、クライアント側のスクリプトでhtmlファイルを提供します。さらに、socket.ioをセットアップし、Gameの新しいインスタンスを作成し、Player接続するソケットごとにの新しいインスタンスを作成します。

  • game.tsはクラスGameとをエクスポートしますPlayer。これGameは、実際にはすべての重要なデータの単なるコンテナです。すべてのプレーヤーのリストとすべてのgameObjectのリストが格納されます。新しいgameObjectが生成される可能性があるかどうかをチェックGameするメソッドを実装します。requestSpawn(...)このクラスPlayerは、socket.ioソケットの単なるラッパーです。着信メッセージと発信メッセージを処理します。クライアントがGameObjectを生成しようとすると、メッセージがサーバーに送信され、Playerインスタンスに格納されているソケットに到着します。次に、Playerインスタンスは呼び出しrequestSpawnて、目的のを生成しようとしますGameObject

  • GameObjects.tsは、インターフェイスGameObjectとこのインターフェイスのさまざまな実装をエクスポートします。

ゲームは次のように実行されます。

  1. 人がhtml-canvas内をクリックします
  2. 新しい「REQUESTSPAWN」メッセージがパッケージ化され、サーバーに送信されます
  3. Playerインスタンスはメッセージを受信し、そのインスタンスを呼び出しますrequestSpawnGame
  4. GameインスタンスはGameObject、正しいタイプの新しいものを正しい位置に作成し、それを次のリストに追加します。GameObjects
  5. この新しい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メソッドの最初の呼び出しでロボットが生成され、その後、ファクトリが「スリープ」します。ロボットは更新方法で何もしません。

コードの2行に注目したいと思います。-requestSpawnメソッドでGameObjectは、はdeltaTime=1ですぐに更新されます。

つまり、ファクトリをスポーンした直後に、ロボットもスポーンする必要があります。しかし、それは起こりません。メソッドconsole.log内に呼び出しを追加しました。requestSpawn「ファクトリを更新しようとしました」と正常に印刷されますが、それでも何も起こりません。そのため、updateメソッドが正しく機能していないと想定し、console.logそこにも呼び出しを追加しました。これはメソッドの最初の行であり、Factory's update「ファクトリの更新」と出力する必要があります。しかし、それは決して起こりません。

本当に戸惑いました。メソッドを呼び出す必要がありますが、そうではありません。公開宣言ですが、アクセス権に関係があるのではないかと思いました。これが2行目のコードです。指摘したいのは次のとおりです。-Factoryのコンストラクターで、への呼び出しをコメントアウトしましたthis.update(1)

少なくとも、非常に独自のコンストラクターがupdateメソッドを呼び出すことができるはずだと思いました。確かにそうです。この行がコメントアウトされていない場合、updateが1回呼び出されます。次に、ファクトリは新しいロボットを生成しようとしrequestSpawn()、そのインスタンスを呼び出しますGame。その結果、新しいロボットが作成されSpawnMessage、すべてのクライアントに送信されます。ロボットはクライアントのブラウザタブにも表示されます。

したがって、メソッドが呼び出されないことは明らかです。すべてが正常に機能し、メッセージの解析、ファクトリの更新、ロボットの作成は正しく行われます。唯一の問題は、内部から更新するためのすべての呼び出しがGame実行されないことです。何が悪かったのか ?

4

1 に答える 1

2

あなたはたくさんのコードを投稿しました、そして他の問題があるかもしれません、しかし少なくとも1つはあなたがbreakあなたのswitchステートメントに欠けているということです...

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に新しいものを割り当ててすぐに上書きします)。Roboto

この単純化された例を考えてみましょう。

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'

参照

于 2013-03-10T10:16:30.047 に答える