This commit is contained in:
2015-08-12 16:00:41 +03:00
parent 64d36c6924
commit 3eee4db51b
10 changed files with 211 additions and 217 deletions

View File

@@ -1,4 +1,4 @@
package ru.m.tankz.game; package ru.m.tankz.engine;
import ru.m.tankz.core.Direction; import ru.m.tankz.core.Direction;
import ru.m.tankz.core.Tank.TankAction; import ru.m.tankz.core.Tank.TankAction;
@@ -6,7 +6,7 @@ import flash.ui.Keyboard;
import ru.m.tankz.core.PlayerTank; import ru.m.tankz.core.PlayerTank;
import ru.m.tankz.core.ITank; import ru.m.tankz.core.ITank;
class ClientTankz extends Tankz { class ClientEngine extends Engine {
public var personId(default, default):Int; public var personId(default, default):Int;

View File

@@ -1,8 +1,8 @@
package ru.m.tankz.render; package ru.m.tankz.render;
import haxework.gui.IView; import haxework.gui.IView;
import ru.m.tankz.game.ITankz; import ru.m.tankz.engine.IEngine;
interface IRender extends IView { interface IRender extends IView {
public function draw(game:ITankz):Void; public function draw(game:IEngine):Void;
} }

View File

@@ -3,7 +3,7 @@ package ru.m.tankz.render;
import flash.display.Sprite; import flash.display.Sprite;
import flash.display.Graphics; import flash.display.Graphics;
import haxework.gui.SpriteView; import haxework.gui.SpriteView;
import ru.m.tankz.game.ITankz; import ru.m.tankz.engine.IEngine;
class Render extends SpriteView implements IRender { class Render extends SpriteView implements IRender {
@@ -18,7 +18,7 @@ class Render extends SpriteView implements IRender {
contentAsSprite.addChild(tankLayer); contentAsSprite.addChild(tankLayer);
} }
public function draw(game:ITankz):Void { public function draw(game:IEngine):Void {
var mapWidth = game.map.gridWidth * game.map.cellWidth; var mapWidth = game.map.gridWidth * game.map.cellWidth;
var mapHeight = game.map.gridHeight * game.map.cellHeight; var mapHeight = game.map.gridHeight * game.map.cellHeight;

View File

@@ -4,7 +4,7 @@ import ru.m.tankz.core.MobileEntity;
import ru.m.tankz.core.Direction; import ru.m.tankz.core.Direction;
import ru.m.tankz.proto.GameObjectType; import ru.m.tankz.proto.GameObjectType;
import ru.m.tankz.proto.GameChangeType; import ru.m.tankz.proto.GameChangeType;
import ru.m.tankz.game.ClientTankz; import ru.m.tankz.engine.ClientEngine;
import protohx.Message; import protohx.Message;
import ru.m.tankz.proto.GameUpdateResponse; import ru.m.tankz.proto.GameUpdateResponse;
import ru.m.core.connect.IConnection; import ru.m.core.connect.IConnection;
@@ -22,27 +22,27 @@ class GameFrame extends VGroupView implements ViewBuilder implements IPacketHand
public static inline var ID = "game"; public static inline var ID = "game";
private var game:ClientTankz; private var engine:ClientEngine;
public function init():Void { public function init():Void {
game = new ClientTankz(); engine = new ClientEngine();
} }
public function onShow():Void { public function onShow():Void {
var person = Provider.get(GameData).person; var person = Provider.get(GameData).person;
var persons = Provider.get(GameData).game.persons; var persons = Provider.get(GameData).game.persons;
name.text = person.name; name.text = person.name;
game.personId = person.id; engine.personId = person.id;
game.init(persons, DEFAULT.CONFIG); engine.init(persons, DEFAULT.CONFIG);
content.addEventListener(Event.ENTER_FRAME, updateGame); content.addEventListener(Event.ENTER_FRAME, updateGame);
Provider.get(IConnection).packetHandler.addListener(this); Provider.get(IConnection).packetHandler.addListener(this);
render.draw(game); render.draw(engine);
} }
public function onHide():Void { public function onHide():Void {
Provider.get(IConnection).packetHandler.removeListener(this); Provider.get(IConnection).packetHandler.removeListener(this);
content.removeEventListener(Event.ENTER_FRAME, updateGame); content.removeEventListener(Event.ENTER_FRAME, updateGame);
game.clear(); engine.clear();
} }
private function updateGame(_):Void { private function updateGame(_):Void {
@@ -56,7 +56,7 @@ class GameFrame extends VGroupView implements ViewBuilder implements IPacketHand
case GameChangeType.DIRECTION: case GameChangeType.DIRECTION:
switch (change.objectType) { switch (change.objectType) {
case GameObjectType.TANK: case GameObjectType.TANK:
for (tank in game.tanks) { for (tank in engine.tanks) {
if (tank.id == change.objectId) { if (tank.id == change.objectId) {
tank.direction = new Direction(change.directionX, change.directionY); tank.direction = new Direction(change.directionX, change.directionY);
break; break;
@@ -66,7 +66,7 @@ class GameFrame extends VGroupView implements ViewBuilder implements IPacketHand
case GameChangeType.MOVED: case GameChangeType.MOVED:
switch (change.objectType) { switch (change.objectType) {
case GameObjectType.TANK: case GameObjectType.TANK:
for (tank in game.tanks) { for (tank in engine.tanks) {
if (tank.id == change.objectId) { if (tank.id == change.objectId) {
tank.x = change.x; tank.x = change.x;
tank.y = change.y; tank.y = change.y;
@@ -77,7 +77,7 @@ class GameFrame extends VGroupView implements ViewBuilder implements IPacketHand
case GameChangeType.APPEND: case GameChangeType.APPEND:
switch (change.objectType) { switch (change.objectType) {
case GameObjectType.BULLET: case GameObjectType.BULLET:
for (tank in game.tanks) { for (tank in engine.tanks) {
if (tank.id == change.parentObjectId) { if (tank.id == change.parentObjectId) {
tank.bullets.push(new MobileEntity(0, change.x, change.y, 0, new Direction(change.directionX, change.directionY))); tank.bullets.push(new MobileEntity(0, change.x, change.y, 0, new Direction(change.directionX, change.directionY)));
break; break;
@@ -86,7 +86,7 @@ class GameFrame extends VGroupView implements ViewBuilder implements IPacketHand
} }
} }
} }
render.draw(game); render.draw(engine);
} }
public function onPacket(packet:Message):Void {} public function onPacket(packet:Message):Void {}

View File

@@ -1,4 +1,4 @@
package ru.m.tankz.game; package ru.m.tankz.engine;
import ru.m.tankz.proto.Person; import ru.m.tankz.proto.Person;
import ru.m.tankz.core.Direction; import ru.m.tankz.core.Direction;
@@ -10,7 +10,7 @@ import ru.m.tankz.map.TankzMap;
import ru.m.tankz.core.ITank; import ru.m.tankz.core.ITank;
import ru.m.tankz.map.ITankzMap; import ru.m.tankz.map.ITankzMap;
class Tankz implements ITankz { class Engine implements IEngine {
public var config(default, default):TankzConfig; public var config(default, default):TankzConfig;
public var map(default, null):ITankzMap; public var map(default, null):ITankzMap;

View File

@@ -1,11 +1,11 @@
package ru.m.tankz.game; package ru.m.tankz.engine;
import ru.m.tankz.proto.Person; import ru.m.tankz.proto.Person;
import ru.m.tankz.config.TankzConfig; import ru.m.tankz.config.TankzConfig;
import ru.m.tankz.core.ITank; import ru.m.tankz.core.ITank;
import ru.m.tankz.map.ITankzMap; import ru.m.tankz.map.ITankzMap;
interface ITankz { interface IEngine {
public var config(default, default):TankzConfig; public var config(default, default):TankzConfig;
public var map(default, null):ITankzMap; public var map(default, null):ITankzMap;
public var tanks(default, null):Array<ITank>; public var tanks(default, null):Array<ITank>;

View File

@@ -71,6 +71,14 @@ message JoinGameResponse {
required Game game = 1; required Game game = 1;
} }
message LeaveGameRequest {
required int32 game_id = 1;
}
message LeaveGameResponse {
required Game game = 1;
}
message StartGameRequest { message StartGameRequest {
} }

View File

@@ -1,12 +0,0 @@
package ru.m.tankz.server.game;
import ru.m.tankz.game.ITankz;
class Game {
private var tankz:ITankz;
public function new() {
}
}

View File

@@ -0,0 +1,170 @@
package ru.m.tankz.server.game;
import ru.m.tankz.proto.ExitGameResponse;
import ru.m.tankz.proto.GameObjectType;
import ru.m.tankz.proto.GameChangeType;
import ru.m.tankz.proto.GameUpdateResponse;
import ru.m.tankz.proto.GameChange;
import ru.m.tankz.proto.StartGameResponse;
import ru.m.tankz.core.Direction;
import ru.m.tankz.server.session.Thread;
import ru.m.tankz.config.TankzConfig.DEFAULT;
import ru.m.tankz.engine.Engine;
import ru.m.tankz.proto.CreateGameResponse;
import ru.m.tankz.proto.LeaveGameResponse;
import ru.m.tankz.proto.JoinGameResponse;
import ru.m.tankz.server.session.Session;
import protohx.Message;
import ru.m.tankz.proto.Person;
import ru.m.tankz.proto.GameState;
import ru.m.tankz.proto.Game;
import ru.m.tankz.engine.IEngine;
/**
*
**/
class NekoTimer {
private var sleep:Float;
private var stopped:Bool;
public function new(time_ms:Int) {
this.sleep = time_ms / 1000.0;
this.stopped = false;
Thread.create(function() {
while (!stopped) {
Sys.sleep(sleep);
try {
run();
} catch (error:Dynamic) {
trace(error);
}
}
});
}
public dynamic function run() {}
public function stop() {
stopped = true;
}
}
/**
*
**/
typedef ObjectState = {
var x:Float;
var y:Float;
var d:Direction;
}
/**
*
**/
class GameManager {
public static var byGameId:Map<Int, GameManager> = new Map<Int, GameManager>();
public static var byPersonId:Map<Int, GameManager> = new Map<Int, GameManager>();
private static var idCounter:Int = 0;
public var game(default, null):Game;
public var engine(default, null):IEngine;
private var timer:NekoTimer;
public function new(person:Person) {
game = new Game()
.setId(idCounter++)
.setState(GameState.READY)
.setCreator(person);
game.addPersons(person);
byGameId.set(game.id, this);
byPersonId.set(person.id, this);
broadcast(new CreateGameResponse().setGame(game));
}
public function broadcast(packet:Message) {
for (person in game.persons) {
var session = Session.sessions.get(person.id);
session.send(packet);
}
}
public function join(person:Person) {
game.addPersons(person);
byPersonId.set(person.id, this);
broadcast(new JoinGameResponse().setGame(game));
}
public function leave(person:Person) {
game.setPersons(game.persons.filter(function(p) return p.id != person.id));
byPersonId.remove(person.id);
if (game.persons.length == 0 || person.id == game.creator.id) {
stop();
} else {
broadcast(new LeaveGameResponse().setGame(game));
}
}
public function start() {
game.setState(GameState.STARTED);
engine = new Engine();
engine.init(game.persons, DEFAULT.CONFIG);
timer = new NekoTimer(30);
timer.run = update;
broadcast(new StartGameResponse().setGame(game));
}
public function stop() {
game.setState(GameState.ENDED);
byGameId.remove(game.id);
for (p in game.persons) byPersonId.remove(p.id);
if (timer != null) {
timer.stop();
timer = null;
}
broadcast(new ExitGameResponse());
}
private function update() {
var states = new Map<Int, ObjectState>();
for (tank in engine.tanks) {
states.set(tank.id, {
x: tank.x,
y: tank.y,
d: tank.direction
});
}
engine.update();
var changes = new Array<GameChange>();
for (tank in engine.tanks) {
if (states.exists(tank.id)) {
var state = states.get(tank.id);
if (state.d != tank.direction) {
changes.push(new GameChange()
.setType(GameChangeType.DIRECTION)
.setObjectType(GameObjectType.TANK)
.setObjectId(tank.id)
.setDirectionX(tank.direction.x)
.setDirectionY(tank.direction.y)
);
}
if (state.x != tank.x || state.y != tank.y) {
changes.push(new GameChange()
.setType(GameChangeType.MOVED)
.setObjectType(GameObjectType.TANK)
.setObjectId(tank.id)
.setX(tank.x)
.setY(tank.y)
);
}
}
}
if (changes.length > 0) {
broadcast(new GameUpdateResponse().setChanges(changes));
}
}
}

View File

@@ -1,5 +1,6 @@
package ru.m.tankz.server.session; package ru.m.tankz.server.session;
import ru.m.tankz.server.game.GameManager;
import ru.m.tankz.proto.GameObjectType; import ru.m.tankz.proto.GameObjectType;
import ru.m.tankz.proto.GameChangeType; import ru.m.tankz.proto.GameChangeType;
import ru.m.tankz.proto.GameChange; import ru.m.tankz.proto.GameChange;
@@ -7,8 +8,8 @@ import ru.m.tankz.config.TankzConfig.DEFAULT;
import ru.m.tankz.proto.GameUpdateResponse; import ru.m.tankz.proto.GameUpdateResponse;
import haxe.Timer; import haxe.Timer;
import ru.m.tankz.core.Direction; import ru.m.tankz.core.Direction;
import ru.m.tankz.game.Tankz; import ru.m.tankz.engine.Engine;
import ru.m.tankz.game.ITankz; import ru.m.tankz.engine.IEngine;
import ru.m.tankz.proto.GameActionType; import ru.m.tankz.proto.GameActionType;
import ru.m.tankz.proto.GameActionRequest; import ru.m.tankz.proto.GameActionRequest;
import ru.m.tankz.proto.ExitGameResponse; import ru.m.tankz.proto.ExitGameResponse;
@@ -38,180 +39,9 @@ import protohx.Message;
import ru.m.core.connect.IConnection; import ru.m.core.connect.IConnection;
import sys.net.Socket; import sys.net.Socket;
class NekoTimer {
private var sleep:Float;
private var stopped:Bool;
public function new(time_ms:Int) {
this.sleep = time_ms / 1000.0;
this.stopped = false;
Thread.create(function() {
while (!stopped) {
Sys.sleep(sleep);
try {
run();
} catch (error:Dynamic) {
trace(error);
}
}
});
}
public dynamic function run() {}
public function stop() {
stopped = true;
}
}
typedef ObjectState = {
var x:Float;
var y:Float;
var d:Direction;
}
class GameCenter {
private var game_id:Int = 0;
private var games:Map<Int, Game>;
private var created:Map<Int, Int>;
private var persons:Map<Int, Int>;
public var running:Map<Int, ITankz>;
private var timers:Map<Int, NekoTimer>;
public function new() {
games = new Map<Int, Game>();
created = new Map<Int, Int>();
persons = new Map<Int, Int>();
running = new Map<Int, ITankz>();
timers = new Map<Int, NekoTimer>();
}
public function getReadyGames():Array<Game> {
return Lambda.array(games).filter(function(g) return g.state == GameState.READY);
}
public function getCreatedGame(peronsId:Int):Game {
return games.get(created.get(peronsId));
}
public function getPersonGameId(personId:Int):Int {
return persons.get(personId);
}
public function createGame(person:Person):Game {
var game:Game = new Game()
.setId(game_id++)
.setState(GameState.READY)
.setCreator(person);
games.set(game.id, game);
created.set(person.id, game.id);
join(person, game.id);
return game;
}
public function join(person:Person, gameId:Int):Game {
exit(person.id);
var game:Game = games.get(gameId);
game.addPersons(person);
persons.set(person.id, gameId);
return game;
}
public function exit(personId:Int):Void {
if (persons.exists(personId)) {
var game:Game = games.get(persons.get(personId));
for (person in game.persons) if (person.id == personId) {
game.persons.remove(person);
if (game.persons.length == 0) {
games.remove(game.id);
if (timers.exists(game.id)) {
timers.get(game.id).stop();
timers.remove(game.id);
}
}
break;
}
persons.remove(personId);
}
}
public function start(gameId:Int):Void {
if (games.exists(gameId)) {
var game:Game = games.get(gameId);
game.setState(GameState.STARTED);
var tankz = new Tankz();
tankz.init(game.persons, DEFAULT.CONFIG);
running.set(gameId, tankz);
var timer = new NekoTimer(30);
timer.run = buildUpdater(gameId, tankz);
timers.set(gameId, timer);
broadcast(gameId, new StartGameResponse().setGame(game));
}
}
private function buildUpdater(gameId:Int, tankz:ITankz):Void->Void {
return function() {
var states = new Map<Int, ObjectState>();
for (tank in tankz.tanks) {
states.set(tank.id, {
x: tank.x,
y: tank.y,
d: tank.direction
});
}
tankz.update();
var changes = new Array<GameChange>();
for (tank in tankz.tanks) {
if (states.exists(tank.id)) {
var state = states.get(tank.id);
if (state.d != tank.direction) {
trace("DDD");
changes.push(new GameChange()
.setType(GameChangeType.DIRECTION)
.setObjectType(GameObjectType.TANK)
.setObjectId(tank.id)
.setDirectionX(tank.direction.x)
.setDirectionY(tank.direction.y)
);
}
if (state.x != tank.x || state.y != tank.y) {
changes.push(new GameChange()
.setType(GameChangeType.MOVED)
.setObjectType(GameObjectType.TANK)
.setObjectId(tank.id)
.setX(tank.x)
.setY(tank.y)
);
}
}
}
if (changes.length > 0) {
broadcast(gameId, new GameUpdateResponse().setChanges(changes));
}
}
}
public function broadcast(gameId:Int, packet:Message):Void {
var game = games.get(gameId);
if (game != null) {
for (person in game.persons) {
var session = Session.sessions.get(person.id);
if (session != null) {
session.send(packet);
}
}
}
}
}
class Session implements IConnectionHandler implements IPacketHandler { class Session implements IConnectionHandler implements IPacketHandler {
private static var games:GameCenter = new GameCenter();
public static var sessions:Map<Int, Session> = new Map<Int, Session>(); public static var sessions:Map<Int, Session> = new Map<Int, Session>();
public var account(default, null):Account; public var account(default, null):Account;
@@ -254,7 +84,8 @@ class Session implements IConnectionHandler implements IPacketHandler {
public function onDisconnected():Void { public function onDisconnected():Void {
if (person != null) { if (person != null) {
games.exit(person.id); var game = GameManager.byPersonId.get(person.id);
if (game != null) game.leave(person);
} }
} }
@@ -292,31 +123,28 @@ class Session implements IConnectionHandler implements IPacketHandler {
} }
public function onGamesRequest(packet:GamesRequest):Void { public function onGamesRequest(packet:GamesRequest):Void {
connection.send(new GamesResponse().setGames(games.getReadyGames())); var games = Lambda.array(Lambda.map(GameManager.byGameId, function(gm) return gm.game));
connection.send(new GamesResponse().setGames(games));
} }
public function onCreateGameRequest(packet:CreateGameRequest):Void { public function onCreateGameRequest(packet:CreateGameRequest):Void {
var game:Game = games.createGame(person); new GameManager(person);
connection.send(new CreateGameResponse().setGame(game));
} }
public function onJoinGameRequest(packet:JoinGameRequest):Void { public function onJoinGameRequest(packet:JoinGameRequest):Void {
var game:Game = games.join(person, packet.gameId); GameManager.byGameId.get(packet.gameId).join(person);
connection.send(new JoinGameResponse().setGame(game));
} }
public function onStartGameRequest(packet:StartGameRequest):Void { public function onStartGameRequest(packet:StartGameRequest):Void {
var game:Game = games.getCreatedGame(person.id); GameManager.byPersonId.get(person.id).start();
games.start(game.id);
} }
public function onExitGameRequest(packet:ExitGameRequest):Void { public function onExitGameRequest(packet:ExitGameRequest):Void {
games.exit(person.id); GameManager.byPersonId.get(person.id).leave(person);
connection.send(new ExitGameResponse());
} }
public function onGameActionRequest(packet:GameActionRequest):Void { public function onGameActionRequest(packet:GameActionRequest):Void {
var game:ITankz = games.running.get(games.getPersonGameId(person.id)); var game:IEngine = GameManager.byPersonId.get(person.id).engine;
for (tank in game.tanks) { for (tank in game.tanks) {
if (tank.id == person.id) { if (tank.id == person.id) {
switch (packet.type) { switch (packet.type) {