From ba13111a8ef48054f37d74faf613c0988e8b9343 Mon Sep 17 00:00:00 2001 From: shmyga Date: Mon, 27 May 2019 17:59:59 +0300 Subject: [PATCH] [common] GameRunner extend from Game --- .../haxe/ru/m/tankz/network/NetworkGame.hx | 25 +++ .../haxe/ru/m/tankz/network/NetworkManager.hx | 2 +- src/client/haxe/ru/m/tankz/view/ClientView.hx | 8 - src/client/haxe/ru/m/tankz/view/GameFrame.hx | 73 ++++----- src/client/haxe/ru/m/tankz/view/LevelFrame.hx | 4 + .../haxe/ru/m/tankz/view/ResultFrame.hx | 22 ++- .../haxe/ru/m/tankz/view/common/RecordView.hx | 7 +- .../ru/m/tankz/view/network/GameRoomFrame.hx | 11 ++ .../m/tankz/view/network/GameRoomFrame.yaml | 6 + src/common/haxe/ru/m/tankz/bot/BotControl.hx | 2 +- src/common/haxe/ru/m/tankz/bot/BotHelper.hx | 6 +- .../haxe/ru/m/tankz/bot/HardBotControl.hx | 4 +- .../haxe/ru/m/tankz/bot/StupidBotControl.hx | 2 +- src/common/haxe/ru/m/tankz/control/Control.hx | 8 +- src/common/haxe/ru/m/tankz/game/Game.hx | 31 ++-- src/common/haxe/ru/m/tankz/game/GameRunner.hx | 153 ++++++++---------- src/common/haxe/ru/m/tankz/game/IGame.hx | 4 +- .../haxe/ru/m/tankz/game/record/GamePlayer.hx | 12 +- src/common/resources/classic/config.yaml | 2 +- .../haxe/ru/m/tankz/server/game/ServerGame.hx | 4 +- 20 files changed, 202 insertions(+), 184 deletions(-) create mode 100644 src/client/haxe/ru/m/tankz/network/NetworkGame.hx diff --git a/src/client/haxe/ru/m/tankz/network/NetworkGame.hx b/src/client/haxe/ru/m/tankz/network/NetworkGame.hx new file mode 100644 index 0000000..5d01084 --- /dev/null +++ b/src/client/haxe/ru/m/tankz/network/NetworkGame.hx @@ -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); + } +} diff --git a/src/client/haxe/ru/m/tankz/network/NetworkManager.hx b/src/client/haxe/ru/m/tankz/network/NetworkManager.hx index d4f6171..abba077 100644 --- a/src/client/haxe/ru/m/tankz/network/NetworkManager.hx +++ b/src/client/haxe/ru/m/tankz/network/NetworkManager.hx @@ -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; diff --git a/src/client/haxe/ru/m/tankz/view/ClientView.hx b/src/client/haxe/ru/m/tankz/view/ClientView.hx index 4bbb2ff..b22bfdb 100644 --- a/src/client/haxe/ru/m/tankz/view/ClientView.hx +++ b/src/client/haxe/ru/m/tankz/view/ClientView.hx @@ -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):Void { - if (frame.id == StartFrame.ID) { - soundManager.stopAll(); - } - } } diff --git a/src/client/haxe/ru/m/tankz/view/GameFrame.hx b/src/client/haxe/ru/m/tankz/view/GameFrame.hx index f160f79..6bb84b1 100644 --- a/src/client/haxe/ru/m/tankz/view/GameFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/GameFrame.hx @@ -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 { + 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 { diff --git a/src/client/haxe/ru/m/tankz/view/LevelFrame.hx b/src/client/haxe/ru/m/tankz/view/LevelFrame.hx index 6eac9f1..1747404 100644 --- a/src/client/haxe/ru/m/tankz/view/LevelFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/LevelFrame.hx @@ -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; @: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); } diff --git a/src/client/haxe/ru/m/tankz/view/ResultFrame.hx b/src/client/haxe/ru/m/tankz/view/ResultFrame.hx index e8e8fd9..f8378f6 100644 --- a/src/client/haxe/ru/m/tankz/view/ResultFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/ResultFrame.hx @@ -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() { diff --git a/src/client/haxe/ru/m/tankz/view/common/RecordView.hx b/src/client/haxe/ru/m/tankz/view/common/RecordView.hx index 7570386..457bcad 100644 --- a/src/client/haxe/ru/m/tankz/view/common/RecordView.hx +++ b/src/client/haxe/ru/m/tankz/view/common/RecordView.hx @@ -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); } diff --git a/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.hx b/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.hx index 413ee2c..9332be3 100644 --- a/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.hx @@ -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; @: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); } diff --git a/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.yaml b/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.yaml index beea6b8..d996f34 100644 --- a/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.yaml +++ b/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.yaml @@ -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% diff --git a/src/common/haxe/ru/m/tankz/bot/BotControl.hx b/src/common/haxe/ru/m/tankz/bot/BotControl.hx index 8d5f3ca..3b7970d 100644 --- a/src/common/haxe/ru/m/tankz/bot/BotControl.hx +++ b/src/common/haxe/ru/m/tankz/bot/BotControl.hx @@ -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 { diff --git a/src/common/haxe/ru/m/tankz/bot/BotHelper.hx b/src/common/haxe/ru/m/tankz/bot/BotHelper.hx index 9c77cdf..70d4f8e 100644 --- a/src/common/haxe/ru/m/tankz/bot/BotHelper.hx +++ b/src/common/haxe/ru/m/tankz/bot/BotHelper.hx @@ -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 { - for (entity in handler.engine.entities) { + public static function findEagle(team:TeamId, engine:IEngine):Null { + for (entity in engine.entities) { switch (EntityTypeResolver.of(entity)) { case EntityType.EAGLE(eagle): if (eagle.team != team) { diff --git a/src/common/haxe/ru/m/tankz/bot/HardBotControl.hx b/src/common/haxe/ru/m/tankz/bot/HardBotControl.hx index e0e90a6..e50357c 100644 --- a/src/common/haxe/ru/m/tankz/bot/HardBotControl.hx +++ b/src/common/haxe/ru/m/tankz/bot/HardBotControl.hx @@ -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 { diff --git a/src/common/haxe/ru/m/tankz/bot/StupidBotControl.hx b/src/common/haxe/ru/m/tankz/bot/StupidBotControl.hx index c675d6e..909e4a4 100644 --- a/src/common/haxe/ru/m/tankz/bot/StupidBotControl.hx +++ b/src/common/haxe/ru/m/tankz/bot/StupidBotControl.hx @@ -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 { diff --git a/src/common/haxe/ru/m/tankz/control/Control.hx b/src/common/haxe/ru/m/tankz/control/Control.hx index ca882fe..b0c1e6a 100644 --- a/src/common/haxe/ru/m/tankz/control/Control.hx +++ b/src/common/haxe/ru/m/tankz/control/Control.hx @@ -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; } } diff --git a/src/common/haxe/ru/m/tankz/game/Game.hx b/src/common/haxe/ru/m/tankz/game/Game.hx index 045a607..2905eee 100644 --- a/src/common/haxe/ru/m/tankz/game/Game.hx +++ b/src/common/haxe/ru/m/tankz/game/Game.hx @@ -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; public var config(default, null):Config; - public var engine(default, null):IEngine; public var winner(default, null):Null; 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 = 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 = 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(); } } diff --git a/src/common/haxe/ru/m/tankz/game/GameRunner.hx b/src/common/haxe/ru/m/tankz/game/GameRunner.hx index e2f9672..bc26bc1 100644 --- a/src/common/haxe/ru/m/tankz/game/GameRunner.hx +++ b/src/common/haxe/ru/m/tankz/game/GameRunner.hx @@ -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; + 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 { - 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 { - 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 = []; - 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 _: } } diff --git a/src/common/haxe/ru/m/tankz/game/IGame.hx b/src/common/haxe/ru/m/tankz/game/IGame.hx index 6d21b0c..b4dd7df 100644 --- a/src/common/haxe/ru/m/tankz/game/IGame.hx +++ b/src/common/haxe/ru/m/tankz/game/IGame.hx @@ -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; public var config(default, null):Config; - public var engine(default, null):IEngine; public var winner(default, null):Null; 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 { diff --git a/src/common/haxe/ru/m/tankz/game/record/GamePlayer.hx b/src/common/haxe/ru/m/tankz/game/record/GamePlayer.hx index 1c43610..f914e0a 100644 --- a/src/common/haxe/ru/m/tankz/game/record/GamePlayer.hx +++ b/src/common/haxe/ru/m/tankz/game/record/GamePlayer.hx @@ -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; - 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(); diff --git a/src/common/resources/classic/config.yaml b/src/common/resources/classic/config.yaml index 17d93dc..14a65ec 100644 --- a/src/common/resources/classic/config.yaml +++ b/src/common/resources/classic/config.yaml @@ -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} diff --git a/src/server/haxe/ru/m/tankz/server/game/ServerGame.hx b/src/server/haxe/ru/m/tankz/server/game/ServerGame.hx index a8ed68c..f52b355 100644 --- a/src/server/haxe/ru/m/tankz/server/game/ServerGame.hx +++ b/src/server/haxe/ru/m/tankz/server/game/ServerGame.hx @@ -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); } }