我目前的項目是一個簡單的多人遊戲。客戶端和服務器都是用Typescript編寫的。客戶端只處理輸入並呈現遊戲,所有邏輯都在服務器端實現。Typescript:不能從另一個模塊調用函數
服務器代碼與執行的NodeJS和結構類似這樣
main.ts包含一個明確的服務器和服務與客戶端腳本的HTML文件。此外,它設置socket.io,創建一個新的Game實例,併爲每個連接的套接字創建一個新實例
Player
。game.ts導出類
Game
和Player
。Game
實際上只是所有重要數據的容器。它存儲所有玩家的列表以及所有gameObjects的列表。Game
實現方法requestSpawn(...)
,該方法檢查是否可以產生新的gameObject。類Player
只是一個socket.io套接字的包裝。它處理傳入和傳出的消息。如果客戶端嘗試產生GameObject,則會向服務器發送消息併到達存儲在Player
實例中的套接字。然後Player
實例調用requestSpawn
嘗試產生期望的GameObject
。GameObjects.ts導出接口
GameObject
和此接口的各種實現。
遊戲運行是這樣的:
- 一個人的HTML畫布
- 一個新的「REQUESTSPAWN」信息打包發送到
- 一個
Player
實例接收服務器內點擊消息並在其實例上調用requestSpawn
Game
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) {
}
}
眼下工廠實例的更新方法的第一次調用產生一個機器人,在此之後,工廠「睡覺」。機器人在他們的更新方法中什麼都不做。
我想帶領你的眼睛上的兩行代碼: - 在requestSpawn
方法GameObject
用的DeltaTime立即更新= 1
這意味着,產卵後出廠直接,機器人應也會產生。但是這並沒有發生。我在requestSpawn
方法中添加了一個console.log
調用。它成功地打印「只是試圖更新工廠」,但是,沒有任何反應。 所以我認爲更新方法不能正常工作,並且在那裏也添加了一個console.log
調用。這是Factory's
update
方法的第一行,應打印「更新工廠」。但那從來沒有發生過。
我真的很困惑。該方法應該被調用,但不是。雖然它是公開的,但我認爲這個問題可能與訪問權限有關。因此,這是代碼的第二行,我想指出: - 在Factory的構造函數中,我已經註釋掉了對this.update(1)
的調用。
我想,至少自己的構造函數應該能夠調用更新方法。它的確是。當這一行沒有被註釋掉時,更新被調用一次。工廠然後試圖產生一個新的機器人,並在Game
的實例上調用requestSpawn()
。因此,創建了一個新的機器人,並向所有客戶發送一個新機器人。機器人甚至出現在客戶端的瀏覽器選項卡中。
因此很明顯,該方法沒有被調用。一切工作正常,消息解析,工廠更新和機器人創建是正確的。唯一的問題是沒有執行從Game
內更新的所有呼叫。什麼地方出了錯 ?
是的,這工作。多麼令人尷尬的錯誤。謝謝你找到它 – lhk 2013-03-10 20:17:22