[common] GameRunner extend from Game

This commit is contained in:
2019-05-27 17:59:59 +03:00
parent 94b19a1c26
commit ba13111a8e
20 changed files with 202 additions and 184 deletions

View File

@@ -0,0 +1,25 @@
package ru.m.tankz.network;
import ru.m.tankz.proto.core.GameProto;
import ru.m.tankz.game.GameState;
import ru.m.tankz.game.Game;
class NetworkGame extends Game {
private var network:NetworkManager;
public function new(network:NetworkManager) {
super(new GameState(network.game.type, 0, network.game.level));
this.network = network;
network.gameSignal.connect(onGameChange);
}
private function onGameChange(game:GameProto):Void {
}
override public function dispose():Void {
super.dispose();
network.gameSignal.disconnect(onGameChange);
}
}

View File

@@ -1,10 +1,10 @@
package ru.m.tankz.network;
import ru.m.tankz.proto.core.UserProto;
import haxework.signal.Signal;
import ru.m.connect.IConnection;
import ru.m.tankz.control.Control;
import ru.m.tankz.proto.core.GameProto;
import ru.m.tankz.proto.core.UserProto;
import ru.m.tankz.proto.game.GameChangeProto;
import ru.m.tankz.proto.pack.CreateGameRequest;
import ru.m.tankz.proto.pack.JoinGameRequest;

View File

@@ -4,7 +4,6 @@ import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import haxework.resources.IResources;
import haxework.view.frame.FrameSwitcher;
import haxework.view.IView;
import ru.m.tankz.sound.SoundManager;
@:template class ClientView extends FrameSwitcher {
@@ -16,7 +15,6 @@ import ru.m.tankz.sound.SoundManager;
public function init():Void {
resources.text.put('version', '${Const.VERSION}');
switcher = this;
onSwitch.connect(onFrameSwitch);
}
public function launch():Void {
@@ -31,10 +29,4 @@ import ru.m.tankz.sound.SoundManager;
});
change(StartFrame.ID);
}
private function onFrameSwitch(frame:IView<Dynamic>):Void {
if (frame.id == StartFrame.ID) {
soundManager.stopAll();
}
}
}

View File

@@ -3,9 +3,7 @@ package ru.m.tankz.view;
import haxe.ds.Option;
import haxework.view.frame.FrameSwitcher;
import haxework.view.VGroupView;
import ru.m.tankz.game.Game;
import ru.m.tankz.game.GameEvent;
import ru.m.tankz.game.GameRunner;
import ru.m.tankz.game.GameState;
import ru.m.tankz.game.IGame;
import ru.m.tankz.game.record.GamePlayer;
@@ -15,6 +13,7 @@ import ru.m.tankz.network.NetworkManager;
import ru.m.tankz.sound.SoundManager;
import ru.m.tankz.storage.GameStorage;
import ru.m.tankz.storage.RecordStorage;
import ru.m.tankz.Type;
import ru.m.tankz.view.game.GameView;
@:template class GameFrame extends VGroupView implements GameListener {
@@ -28,28 +27,16 @@ import ru.m.tankz.view.game.GameView;
@:provide var soundManager:SoundManager;
@:provide var state:GameState;
@:provide var record:GameRecord;
@:provide("result") var result:GameState;
@:provide("next") var nextState:GameState;
@:provide var switcher:FrameSwitcher;
@:provide var gameStorage:GameStorage;
@:provide var recordStorage:RecordStorage;
private var game:IGame;
private var runner:GameRunner;
@:provide var game:IGame;
private var recorder:GameRecorder;
private var player:GamePlayer;
public function onShow():Void {
if (record != null) {
play(record);
record = null;
} else {
start(state);
}
}
private function buildGame(state:GameState):Void {
gameView.type = state.type;
game = new Game(state);
gameView.type = game.type;
soundManager.config = game.config;
gameView.render.config = game.config;
game.connect(gameView.render);
@@ -57,28 +44,16 @@ import ru.m.tankz.view.game.GameView;
if (gameView.panel != null) {
game.connect(gameView.panel);
}
}
private function start(state:GameState):Void {
buildGame(state);
// ToDo:
if (!Std.is(game, GamePlayer)) {
recorder = new GameRecorder();
game.connect(recorder);
}
game.connect(this);
recorder = new GameRecorder();
game.connect(recorder);
runner = new GameRunner(game);
runner.start(state);
}
private function play(record:GameRecord):Void {
buildGame(record.state);
player = new GamePlayer(game, record);
player.start();
game.start();
}
private function stop():Void {
if (runner != null) {
runner.dispose();
runner = null;
}
if (game != null) {
game.dispose();
game = null;
@@ -88,19 +63,21 @@ import ru.m.tankz.view.game.GameView;
public function onGameEvent(event:GameEvent):Void {
switch event {
case GameEvent.COMPLETE(state, _):
case GameEvent.COMPLETE(state, winner):
// ToDo:
recordStorage.save(recorder.record);
result = state;
this.state = switch runner.next() {
if (recorder != null) {
recordStorage.save(recorder.record);
}
this.state = state;
nextState = switch next(winner) {
case Some(s):
// ToDo:
var progress = gameStorage.get(game.type);
progress.completeLevel(result.levelId, result.presetId);
progress.completeLevel(state.levelId, state.presetId);
gameStorage.set(progress);
s;
case None:
new GameState(state.type, state.presetId, 0);
null;
}
stop();
switcher.change(ResultFrame.ID);
@@ -108,8 +85,22 @@ import ru.m.tankz.view.game.GameView;
}
}
// ToDo:
private function next(winner:TeamId):Option<GameState> {
for (rule in game.config.game.complete) {
if (rule.team != null && rule.team != winner) {
return Option.None;
}
}
var level = state.levelId + 1;
if (level >= game.config.game.levels) level = 0;
return Option.Some(new GameState(game.type, state.presetId, level, state));
}
public function onHide():Void {
stop();
soundManager.stopAll();
recorder = null;
}
public function close():Void {

View File

@@ -7,7 +7,9 @@ import haxework.view.LabelView;
import haxework.view.VGroupView;
import ru.m.tankz.bundle.ILevelBundle;
import ru.m.tankz.config.Config;
import ru.m.tankz.game.GameRunner;
import ru.m.tankz.game.GameState;
import ru.m.tankz.game.IGame;
import ru.m.tankz.storage.GameStorage;
import ru.m.tankz.Type;
import ru.m.tankz.view.popup.LevelPopup;
@@ -19,6 +21,7 @@ import ru.m.tankz.view.popup.LevelPopup;
@:view var levels:DataView<LevelId, ButtonView>;
@:provide var state:GameState;
@:provide var game:IGame;
@:provide var switcher:FrameSwitcher;
@:provide var levelBundle:ILevelBundle;
@:provide var storage:GameStorage;
@@ -33,6 +36,7 @@ import ru.m.tankz.view.popup.LevelPopup;
private function start(level:LevelConfig, preset:GamePreset):Void {
state.levelId = level.id;
state.presetId = preset.id;
game = new GameRunner(state);
switcher.change(GameFrame.ID);
}

View File

@@ -5,7 +5,9 @@ import haxework.view.DataView;
import haxework.view.frame.FrameSwitcher;
import haxework.view.LabelView;
import haxework.view.VGroupView;
import ru.m.tankz.game.GameRunner;
import ru.m.tankz.game.GameState;
import ru.m.tankz.game.IGame;
import ru.m.tankz.view.common.LifeView;
@:template class ResultFrame extends VGroupView {
@@ -17,28 +19,32 @@ import ru.m.tankz.view.common.LifeView;
@:provide var frames:FrameSwitcher;
@:provide var state:GameState;
@:provide("result") var resultState:GameState;
@:provide("next") var nextState:GameState;
@:provide var game:IGame;
private function playerViewFactory(index:Int, player:PlayerState) {
var view = new LifeView();
var playerConfig = resultState.config.getPlayer(player.id);
var playerConfig = state.config.getPlayer(player.id);
var tankType = playerConfig.tanks[0].type;
var tankConfig = resultState.config.getTank(tankType);
var tankConfig = state.config.getTank(tankType);
view.tank = tankConfig == null ? 'ba' : tankConfig.skin;
view.color = resultState.getPlayerColor(player.id);
view.color = state.getPlayerColor(player.id);
view.life = player.frags;
view.score = player.score;
return view;
}
public function onShow() {
resultView.data = Lambda.array(resultState.players);
levelLabel.text = 'Level ${resultState.levelId}';
nextButton.visible = state != null;
resultView.data = Lambda.array(state.players);
levelLabel.text = 'Level ${state.levelId}';
nextButton.visible = nextState != null;
}
private function next() {
frames.change(GameFrame.ID);
if (nextState != null) {
game = new GameRunner(nextState);
frames.change(GameFrame.ID);
}
}
private function close() {

View File

@@ -1,5 +1,7 @@
package ru.m.tankz.view.common;
import ru.m.tankz.game.record.GamePlayer;
import ru.m.tankz.game.IGame;
import haxework.view.frame.FrameSwitcher;
import haxework.view.HGroupView;
import haxework.view.LabelView;
@@ -18,7 +20,7 @@ import ru.m.tankz.storage.RecordStorage;
@:provide var recordStorage:RecordStorage;
@:provide var switcher:FrameSwitcher;
@:provide var record:GameRecord;
@:provide var game:IGame;
private function set_data(value:GameRecordInfo):GameRecordInfo {
if (data != value) {
@@ -32,7 +34,8 @@ import ru.m.tankz.storage.RecordStorage;
}
private function play():Void {
record = recordStorage.read(data.id);
var record = recordStorage.read(data.id);
game = new GamePlayer(record);
switcher.change(GameFrame.ID);
}

View File

@@ -1,27 +1,38 @@
package ru.m.tankz.view.network;
import haxework.view.ButtonView;
import haxework.view.frame.FrameSwitcher;
import haxework.view.list.VListView;
import haxework.view.TextView;
import haxework.view.VGroupView;
import ru.m.tankz.game.IGame;
import ru.m.tankz.network.NetworkGame;
import ru.m.tankz.network.NetworkManager;
import ru.m.tankz.proto.core.GameProto;
import ru.m.tankz.proto.core.GameStateProto;
import ru.m.tankz.proto.core.UserProto;
@:template class GameRoomFrame extends VGroupView {
public static inline var ID = "game_room";
@:view var start:ButtonView;
@:view var info:TextView;
@:view var players:VListView<UserProto>;
@:provide var switcher:FrameSwitcher;
@:provide var network:NetworkManager;
@:provide var game:IGame;
private function refresh(game:GameProto):Void {
if (game != null) {
start.visible = game.creator.uuid == network.user.uuid;
info.text = '[${game.creator.name}] ${game.type} ${game.level} (${game.players.length})';
players.data = game.players;
if (game.state == GameStateProto.STARTED) {
this.game = new NetworkGame(network);
switcher.change(GameFrame.ID);
}
} else {
Timer.delay(function() switcher.change(GameListFrame.ID), 1);
}

View File

@@ -9,6 +9,12 @@ views:
geometry.margin.bottom: 20
skinId: text.header
text: Game Room
- id: start
$type: haxework.view.ButtonView
skinId: button.simple
text: Start
+onPress: $code:network.startGame()
visible: false
- id: info
$type: haxework.view.LabelView
geometry.size.width: 100%

View File

@@ -12,7 +12,7 @@ class BotControl extends Control {
private var tank(get, null):Tank;
private inline function get_tank():Tank {
return handler == null ? null : handler.engine.getEntity(tankId);
return handler == null ? null : engine.getEntity(tankId);
}
override public function stop():Void {

View File

@@ -4,13 +4,13 @@ import ru.m.geom.Direction;
import ru.m.tankz.core.Eagle;
import ru.m.tankz.core.Entity;
import ru.m.tankz.core.EntityType;
import ru.m.tankz.game.IGame;
import ru.m.tankz.engine.IEngine;
import ru.m.tankz.Type;
class BotHelper {
public static function findEagle(team:TeamId, handler:IGame):Null<Eagle> {
for (entity in handler.engine.entities) {
public static function findEagle(team:TeamId, engine:IEngine):Null<Eagle> {
for (entity in engine.entities) {
switch (EntityTypeResolver.of(entity)) {
case EntityType.EAGLE(eagle):
if (eagle.team != team) {

View File

@@ -56,7 +56,7 @@ class HardBotControl extends BotControl {
}
var enemy:Tank = null;
var distance:Float = Math.POSITIVE_INFINITY;
for (entity in handler.engine.entities.iterator()) {
for (entity in engine.entities.iterator()) {
switch EntityTypeResolver.of(entity) {
case TANK(t):
if (t.playerId.team != tank.playerId.team) {
@@ -82,7 +82,7 @@ class HardBotControl extends BotControl {
}
private function calcTurn():Void {
var eagle:Eagle = BotHelper.findEagle(playerId.team, handler);
var eagle:Eagle = BotHelper.findEagle(playerId.team, engine);
if (eagle != null && Math.random() > 0.5) {
turn(BotHelper.getDirectionTo(tank, eagle));
} else {

View File

@@ -45,7 +45,7 @@ class StupidBotControl extends BotControl {
private function calcTurn():Void {
if (handler == null || tank == null) return;
var eagle:Eagle = BotHelper.findEagle(playerId.team, handler);
var eagle:Eagle = BotHelper.findEagle(playerId.team, engine);
if (eagle != null && Math.random() > 0.5) {
turn(BotHelper.getDirectionTo(tank, eagle));
} else {

View File

@@ -1,8 +1,9 @@
package ru.m.tankz.control;
import ru.m.tankz.game.GameEvent;
import ru.m.geom.Direction;
import ru.m.tankz.core.EntityType;
import ru.m.tankz.engine.IEngine;
import ru.m.tankz.game.GameEvent;
import ru.m.tankz.game.IGame;
import ru.m.tankz.Type;
@@ -17,13 +18,15 @@ class Control {
public var playerId(default, null):PlayerId;
public var tankId(default, default):Int;
private var handler:IGame;
private var engine:IEngine;
public function new(playerId:PlayerId) {
this.playerId = playerId;
}
public function bind(handler:IGame):Void {
public function bind(handler:IGame, engine:IEngine):Void {
this.handler = handler;
this.engine = engine;
}
public function action(action:TankAction):Void {
@@ -41,5 +44,6 @@ class Control {
public function dispose():Void {
stop();
handler = null;
engine = null;
}
}

View File

@@ -6,8 +6,6 @@ import ru.m.tankz.bundle.IConfigBundle;
import ru.m.tankz.config.Config;
import ru.m.tankz.core.Entity;
import ru.m.tankz.core.EntityType;
import ru.m.tankz.engine.Engine;
import ru.m.tankz.engine.IEngine;
import ru.m.tankz.game.GameEvent;
import ru.m.tankz.game.GameState;
import ru.m.tankz.game.IGame;
@@ -20,34 +18,18 @@ import ru.m.tankz.Type;
public var type(default, null):GameType;
public var teams(default, null):Map<TeamId, Team>;
public var config(default, null):Config;
public var engine(default, null):IEngine;
public var winner(default, null):Null<TeamId>;
public var state(default, null):GameState;
private var builder:EntityBuilder;
@:provide var configBundle:IConfigBundle;
public function new(state:GameState) {
this.type = state.type;
this.state = state;
this.teams = new Map();
this.config = configBundle.get(type);
this.engine = new Engine(config);
this.builder = new EntityBuilder(config);
connect(this);
prepare(state);
}
private function prepare(state:GameState):Void {
var level:LevelConfig = state.level;
var points:Array<SpawnPoint> = level.points != null ? level.points : config.points;
engine.map.setData(level.data);
for (teamConfig in state.preset.teams) {
var teamPoints = points.filter(function(p:SpawnPoint) return p.team == teamConfig.id);
var team:Team = new Team(teamConfig, teamPoints, state.teams[teamConfig.id]);
teams[team.id] = team;
}
}
private function applyPosition(entity:Entity, position:Position):Void {
@@ -83,8 +65,17 @@ import ru.m.tankz.Type;
}
}
public function start():Void {
var level:LevelConfig = state.level;
var points:Array<SpawnPoint> = level.points != null ? level.points : config.points;
for (teamConfig in state.preset.teams) {
var teamPoints = points.filter(function(p:SpawnPoint) return p.team == teamConfig.id);
var team:Team = new Team(teamConfig, teamPoints, state.teams[teamConfig.id]);
teams[team.id] = team;
}
}
public function dispose():Void {
gameEventSignal.dispose();
engine.dispose();
}
}

View File

@@ -1,7 +1,6 @@
package ru.m.tankz.game;
import haxe.ds.Option;
import haxework.signal.Signal;
import ru.m.geom.Line;
import ru.m.geom.Point;
import ru.m.tankz.control.Control;
@@ -12,52 +11,50 @@ import ru.m.tankz.core.Bullet;
import ru.m.tankz.core.Eagle;
import ru.m.tankz.core.EntityType;
import ru.m.tankz.core.Tank;
import ru.m.tankz.engine.Engine;
import ru.m.tankz.engine.IEngine;
import ru.m.tankz.game.GameEvent;
import ru.m.tankz.game.IGame;
import ru.m.tankz.game.Spawner;
import ru.m.tankz.Type;
import ru.m.Timer;
class GameRunner implements EngineListener implements GameListener {
class GameRunner extends Game implements EngineListener {
@:provide var controlFactory:IControlFactory;
private var game(default, null):IGame;
private var gameEventSignal(get, null):Signal<GameEvent>;
public var engine(default, null):IEngine;
private var timer:Timer;
private var builder:EntityBuilder;
public function new(game:IGame) {
this.game = game;
this.builder = new EntityBuilder(this.game.config);
this.game.connect(this);
this.game.engine.connect(this);
}
private inline function get_gameEventSignal():Signal<GameEvent> {
return game.gameEventSignal;
public function new(state:GameState) {
super(state);
this.builder = new EntityBuilder(config);
this.engine = new Engine(config);
this.engine.connect(this);
}
private function update():Void {
game.engine.update();
engine.update();
}
public function dispose():Void {
override public function dispose():Void {
super.dispose();
if (timer != null) {
timer.stop();
timer = null;
}
game.disconnect(this);
game.engine.disconnect(this);
engine.dispose();
}
public function start(state:GameState):Void {
for (team in game.teams.iterator()) {
override public function start():Void {
super.start();
engine.map.setData(state.level.data);
for (team in teams.iterator()) {
for (player in team.players.iterator()) {
var control = controlFactory.build(player.id, AController.fromString(player.config.control));
if (control != null) {
player.control = control;
player.control.bind(game);
player.control.bind(this, engine);
}
}
team.spawner.runner = spawn;
@@ -69,30 +66,19 @@ class GameRunner implements EngineListener implements GameListener {
if (team.config.eagle != null) {
var point = team.spawner.getPoint("eagle");
var eagle = builder.buildEagle(point, team.id);
game.engine.spawn(eagle);
engine.spawn(eagle);
gameEventSignal.emit(EventUtil.buildEagleSpawn(eagle));
eagle.protect.connect(onEagleProtectChange);
}
}
gameEventSignal.emit(EventUtil.buildBricksSpawn(game.engine.map));
gameEventSignal.emit(EventUtil.buildBricksSpawn(engine.map));
gameEventSignal.emit(GameEvent.START(state));
//for (i in 0...10) spawnBonus();
}
public function next():Option<GameState> {
for (rule in game.config.game.complete) {
if (rule.team != null && rule.team != game.winner) {
return Option.None;
}
}
var level = game.state.levelId + 1;
if (level >= game.config.game.levels) level = 0;
return Option.Some(new GameState(game.type, game.state.presetId, level, game.state));
}
private function spawn(task:SpawnTask):Void {
var tank = builder.buildTank(task.point, task.playerId, task.tankType);
game.engine.spawn(tank);
engine.spawn(tank);
gameEventSignal.emit(EventUtil.buildTankSpawn(tank));
tank.protect.connect(onTankProtectChange);
tank.freezing.connect(onTankFreezingChange);
@@ -112,10 +98,10 @@ class GameRunner implements EngineListener implements GameListener {
private function checkComplete():Void {
var actives:Array<TeamId> = [];
for (team in game.teams.iterator()) {
for (team in teams.iterator()) {
if (team.isAlive) {
if (team.eagleId > 0) {
if (!cast(game.engine.entities[team.eagleId], Eagle).death) {
if (!cast(engine.entities[team.eagleId], Eagle).death) {
actives.push(team.id);
}
} else {
@@ -132,15 +118,15 @@ class GameRunner implements EngineListener implements GameListener {
}
private function complete(winner:TeamId):Void {
for (team in game.teams.iterator()) {
for (team in teams.iterator()) {
for (player in team.players) {
player.control.action(TankAction.STOP);
player.control.dispose();
}
}
Timer.delay(function() {
gameEventSignal.emit(GameEvent.COMPLETE(game.state, winner));
}, 5000);
gameEventSignal.emit(GameEvent.COMPLETE(state, winner));
}, 3000);
}
public function onSpawn(entity:EntityType):Void {
@@ -165,7 +151,7 @@ class GameRunner implements EngineListener implements GameListener {
public function onCollision(entity:EntityType, with:EntityType):Void {
switch entity {
case EntityType.TANK(tank):
var control = game.getPlayer(tank.playerId).control;
var control = getPlayer(tank.playerId).control;
if (control != null) control.onCollision(with);
case _:
}
@@ -189,7 +175,7 @@ class GameRunner implements EngineListener implements GameListener {
case [TANK(tank), BONUS(bonus)]:
gameEventSignal.emit(GameEvent.DESTROY(BONUS(bonus.id, {tankId: tank.id, score: bonus.config.score})));
case [BULLET(bullet), TANK(tank)]/* | [TANK(tank), BULLET(bullet)]*/:
if (bullet.tankId == tank.id || (!game.config.game.friendlyFire && tank.playerId.team == bullet.playerId.team)) {
if (bullet.tankId == tank.id || (!config.game.friendlyFire && tank.playerId.team == bullet.playerId.team)) {
// Nothing
} else {
if (!tank.protect.active) {
@@ -202,7 +188,7 @@ class GameRunner implements EngineListener implements GameListener {
gameEventSignal.emit(GameEvent.HIT(TANK(tank.id, buildShot(bullet))));
emitTankChange(tank);
} else if (tank.config.downgrade != null) {
tank.config = game.config.getTank(tank.config.downgrade);
tank.config = config.getTank(tank.config.downgrade);
gameEventSignal.emit(GameEvent.HIT(TANK(tank.id, buildShot(bullet))));
emitTankChange(tank);
} else {
@@ -238,14 +224,14 @@ class GameRunner implements EngineListener implements GameListener {
}
private function spawnBonus():Void {
var type = game.config.bonuses[Math.floor(Math.random() * game.config.bonuses.length)].type;
var type = config.bonuses[Math.floor(Math.random() * config.bonuses.length)].type;
var point = {
x: Math.floor(Math.random() * (game.engine.map.gridWidth - 1)),
y: Math.floor(Math.random() * (game.engine.map.gridHeight - 1)),
x: Math.floor(Math.random() * (engine.map.gridWidth - 1)),
y: Math.floor(Math.random() * (engine.map.gridHeight - 1)),
direction: "right",
}
var bonus = builder.buildBonus(point, type);
game.engine.spawn(bonus);
engine.spawn(bonus);
gameEventSignal.emit(GameEvent.SPAWN(BONUS(bonus.id, bonus.rect.clone(), bonus.config.type)));
}
@@ -260,22 +246,22 @@ class GameRunner implements EngineListener implements GameListener {
case "star":
upgradeTank(tank);
case "grenade":
for (t in game.engine.iterTanks(alienTank(tank.playerId.team))) {
for (t in engine.iterTanks(alienTank(tank.playerId.team))) {
gameEventSignal.emit(GameEvent.DESTROY(TANK(t.id, {tankId: tank.id})));
}
case "helmet":
tank.protect.on(bonus.config.duration);
case "clock":
for (t in game.engine.iterTanks(alienTank(tank.playerId.team))) {
for (t in engine.iterTanks(alienTank(tank.playerId.team))) {
t.freezing.on(bonus.config.duration);
t.stop();
gameEventSignal.emit(GameEvent.STOP(TANK(t.id)));
}
case "shovel":
// ToDo: protect eagle/area
var team:Team = game.teams[tank.playerId.team];
var team:Team = teams[tank.playerId.team];
if (team.eagleId > 0) {
var eagle:Eagle = cast(game.engine.entities[team.eagleId], Eagle);
var eagle:Eagle = cast(engine.entities[team.eagleId], Eagle);
eagle.protect.on(bonus.config.duration);
}
case "gun":
@@ -288,7 +274,7 @@ class GameRunner implements EngineListener implements GameListener {
private function upgradeTank(tank:Tank, level:Int = 1):Void {
if (tank.config.upgrade != null) {
while (level-- > 0 && tank.config.upgrade != null) {
tank.config = game.config.getTank(tank.config.upgrade);
tank.config = config.getTank(tank.config.upgrade);
}
} else {
tank.hits++;
@@ -297,26 +283,27 @@ class GameRunner implements EngineListener implements GameListener {
}
private function changeScore(playerId:PlayerId, score:Int):Void {
var player = game.getPlayer(playerId);
var team = game.getTeam(playerId.team);
var player = getPlayer(playerId);
var team = getTeam(playerId.team);
player.state.score += score;
gameEventSignal.emit(GameEvent.CHANGE(PLAYER_SCORE(playerId, player.state.score)));
gameEventSignal.emit(GameEvent.CHANGE(TEAM_SCORE(playerId.team, game.state.getTeamScore(team.id))));
gameEventSignal.emit(GameEvent.CHANGE(TEAM_SCORE(playerId.team, state.getTeamScore(team.id))));
}
private function changeLife(playerId:PlayerId, life:Int):Void {
var player = game.getPlayer(playerId);
var player = getPlayer(playerId);
player.state.life += life;
gameEventSignal.emit(GameEvent.CHANGE(PLAYER_LIFE(playerId, player.state.life)));
}
private function changeTeamLife(teamId:TeamId, life:Int):Void {
var team = game.getTeam(teamId);
var team = getTeam(teamId);
team.state.life += life;
gameEventSignal.emit(GameEvent.CHANGE(TEAM_LIFE(teamId, team.state.life)));
}
public function onGameEvent(event:GameEvent):Void {
override public function onGameEvent(event:GameEvent):Void {
super.onGameEvent(event);
switch event {
case GameEvent.START(_):
timer = new Timer(10);
@@ -327,38 +314,38 @@ class GameRunner implements EngineListener implements GameListener {
timer = null;
}
case GameEvent.ACTION(tankId, SHOT):
var tank:Tank = cast game.engine.entities.get(tankId);
var player = game.getPlayer(tank.playerId);
var tank:Tank = cast engine.entities.get(tankId);
var player = getPlayer(tank.playerId);
if (!tank.freezing.active && player.bullets < tank.config.bullets) {
var rect = tank.rect;
var point = rect.center.add(new Point(rect.width / 4 * rect.direction.x, rect.height / 4 * rect.direction.y));
var bullet = builder.buildBullet(point, rect.direction, player.id, tank.config.type);
bullet.tank = tank;
bullet.move(bullet.rect.direction);
game.engine.spawn(bullet);
engine.spawn(bullet);
gameEventSignal.emit(GameEvent.SPAWN(BULLET(bullet.id, bullet.rect.clone(), bullet.playerId, bullet.config.piercing)));
}
case GameEvent.ACTION(tankId, MOVE(direction)):
game.engine.move(tankId, direction);
engine.move(tankId, direction);
case GameEvent.ACTION(tankId, STOP):
gameEventSignal.emit(GameEvent.STOP(TANK(tankId)));
game.engine.stop(tankId);
engine.stop(tankId);
case GameEvent.SPAWN(TANK(_, _, playerId, _)):
game.getPlayer(playerId).control.start();
getPlayer(playerId).control.start();
case GameEvent.SPAWN(BULLET(_, _, playerId, _)):
game.getPlayer(playerId).bullets++;
getPlayer(playerId).bullets++;
case GameEvent.DESTROY(EAGLE(id, shot)):
var eagle:Eagle = game.engine.getEntity(id);
var eagle:Eagle = engine.getEntity(id);
eagle.death = true;
if (shot.score != 0) {
var tank:Tank = game.engine.getEntity(shot.tankId);
var tank:Tank = engine.getEntity(shot.tankId);
changeScore(tank.playerId, shot.score);
}
checkComplete();
case GameEvent.DESTROY(TANK(id, shot)):
var tank:Tank = game.engine.getEntity(id);
var team = game.getTeam(tank.playerId.team);
var player = game.getPlayer(tank.playerId);
var tank:Tank = engine.getEntity(id);
var team = getTeam(tank.playerId.team);
var player = getPlayer(tank.playerId);
player.control.stop();
player.tankId = 0; //ToDo: ?
team.onDestroy(player.id);
@@ -378,44 +365,44 @@ class GameRunner implements EngineListener implements GameListener {
spawnBonus();
}
if (shot.score != 0) {
var shooterTank:Tank = game.engine.getEntity(shot.tankId);
var shooterTank:Tank = engine.getEntity(shot.tankId);
changeScore(shooterTank.playerId, shot.score);
}
game.engine.destroy(id);
engine.destroy(id);
case GameEvent.DESTROY(BONUS(id, shot)):
var bonus:Bonus = game.engine.getEntity(id);
var tank:Tank = game.engine.getEntity(shot.tankId);
var bonus:Bonus = engine.getEntity(id);
var tank:Tank = engine.getEntity(shot.tankId);
applyBonus(tank, bonus);
if (shot.score != 0) {
changeScore(tank.playerId, shot.score);
}
game.engine.destroy(id);
engine.destroy(id);
case GameEvent.DESTROY(BULLET(id)):
var bullet:Bullet = game.engine.getEntity(id);
var player = game.getPlayer(bullet.playerId);
var bullet:Bullet = engine.getEntity(id);
var player = getPlayer(bullet.playerId);
player.bullets--;
var side:Line = bullet.rect.getSide(bullet.rect.direction.reverse()).move(
// ToDo: move
new Point(bullet.rect.direction.x * 5, bullet.rect.direction.y * 5)
);
var cells = game.engine.map.grid.getCells(side.setLength(game.engine.map.grid.cellWidth * 3));
var cells = engine.map.grid.getCells(side.setLength(engine.map.grid.cellWidth * 3));
for (cell in cells) {
if (cell.armor > 0) {
var shot = buildShot(bullet);
if (cell.armor == bullet.config.piercing) {
game.engine.destroyCell(cell.cellX, cell.cellY);
var brick = game.engine.map.getBrick(cell.position);
engine.destroyCell(cell.cellX, cell.cellY);
var brick = engine.map.getBrick(cell.position);
gameEventSignal.emit(GameEvent.DESTROY(CELL(brick.id, cell.cellX - brick.cellX * 2, cell.cellY - brick.cellY * 2, shot)));
} else if (cell.armor < bullet.config.piercing) {
var brick = game.engine.map.getBrick(cell.position);
var brick = engine.map.getBrick(cell.position);
for (cell in brick.cells) {
game.engine.destroyCell(cell.cellX, cell.cellY);
engine.destroyCell(cell.cellX, cell.cellY);
}
gameEventSignal.emit(GameEvent.DESTROY(BRICK(brick.id, shot)));
}
}
}
game.engine.destroy(id);
engine.destroy(id);
case _:
}
}

View File

@@ -2,14 +2,12 @@ package ru.m.tankz.game;
import haxework.signal.Signal;
import ru.m.tankz.config.Config;
import ru.m.tankz.engine.IEngine;
import ru.m.tankz.Type;
interface IGame extends GameListener {
public var type(default, null):GameType;
public var teams(default, null):Map<TeamId, Team>;
public var config(default, null):Config;
public var engine(default, null):IEngine;
public var winner(default, null):Null<TeamId>;
public var state(default, null):GameState;
@@ -24,6 +22,8 @@ interface IGame extends GameListener {
public function getTeam(teamId:TeamId):Team;
public function getPlayer(playerId:PlayerId):Player;
public function start():Void;
}
interface GameListener {

View File

@@ -4,21 +4,21 @@ import flash.events.Event;
import flash.Lib;
import ru.m.tankz.game.record.GameRecord;
class GamePlayer {
class GamePlayer extends Game {
private var frame:Int;
private var game:IGame;
private var record:GameRecord;
private var data:Array<EventItem>;
public function new(game:IGame, record:GameRecord) {
public function new(record:GameRecord) {
super(record.state);
frame = 0;
this.game = game;
this.record = record;
this.data = null;
}
public function start():Void {
override public function start():Void {
super.start();
frame = 0;
data = record.events.slice(0);
Lib.current.stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
@@ -34,7 +34,7 @@ class GamePlayer {
for (event in data) {
if (event.frame <= frame) {
events++;
game.gameEventSignal.emit(event.event);
gameEventSignal.emit(event.event);
switch event.event {
case GameEvent.COMPLETE(_, _):
stop();

View File

@@ -163,7 +163,7 @@ presets:
- {<<: *team_human}
- id: bot
spawnInterval: 3000
life: 10
life: 1
players:
- {<<: *bot, index: 0, control: bot-stupid}
- {<<: *bot, index: 1, control: bot-stupid}

View File

@@ -1,11 +1,10 @@
package ru.m.tankz.server.game;
import ru.m.tankz.game.Game;
import ru.m.tankz.game.GameRunner;
import ru.m.tankz.game.GameState;
import ru.m.tankz.proto.core.GameProto;
class ServerGame extends Game {
class ServerGame extends GameRunner {
public var runner(default, null):GameRunner;
public var proto(default, null):GameProto;
@@ -13,6 +12,5 @@ class ServerGame extends Game {
public function new(proto:GameProto) {
super(new GameState(proto.type, 0, proto.level));
this.proto = proto;
runner = new GameRunner(this);
}
}