diff --git a/package.json b/package.json index 88f8964..8b4a790 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tankz", - "version": "0.3.0", + "version": "0.4.0", "private": true, "devDependencies": { "ansi-colors": "^1.0.1", diff --git a/src/client/haxe/layout/frames/start.json b/src/client/haxe/layout/frames/start.json index 9315e93..7bbc59c 100644 --- a/src/client/haxe/layout/frames/start.json +++ b/src/client/haxe/layout/frames/start.json @@ -7,21 +7,45 @@ "contentSize": true, "bottomMargin": 15 }, { - "id": "start_1p", + "@type": "haxework.gui.LabelView", "@style": "label", + "fontSize": 20, "topMargin": 15, + "contentSize": true, + "text": "Classic" + }, + { + "id": "classic_1p", "@type": "haxework.gui.ButtonView", "text": "1 Player", "@style": "button" }, { - "id": "start_2p", + "id": "classic_2p", "@type": "haxework.gui.ButtonView", "text": "2 Player", "@style": "button" }, { - "id": "dota", + "@type": "haxework.gui.LabelView", "@style": "label", + "fontSize": 20, "topMargin": 15, + "contentSize": true, + "text": "DotA" + }, + { + "id": "dota_1p", "@type": "haxework.gui.ButtonView", - "text": "DotA", + "text": "1 Player", + "@style": "button" + }, + { + "id": "dota_2p_coop", + "@type": "haxework.gui.ButtonView", + "text": "2 COOP", + "@style": "button" + }, + { + "id": "dota_2p_vs", + "@type": "haxework.gui.ButtonView", + "text": "2 VS", "@style": "button" } ] diff --git a/src/client/haxe/ru/m/tankz/control/HumanControl.hx b/src/client/haxe/ru/m/tankz/control/HumanControl.hx index 0a7e287..25b0e5f 100644 --- a/src/client/haxe/ru/m/tankz/control/HumanControl.hx +++ b/src/client/haxe/ru/m/tankz/control/HumanControl.hx @@ -13,14 +13,13 @@ typedef KeyBinding = Map; class HumanControl extends Control { - public static var TYPE(default, never):ControlType = 'human'; private var keyBinding:KeyBinding; private var moveQueue:Array; private var shotTimer:Timer; public function new(index:Int) { - super({type:TYPE, index:index}); + super({type:Control.HUMAN, index:index}); this.keyBinding = resolve(index); moveQueue = new Array(); Lib.current.stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown); diff --git a/src/client/haxe/ru/m/tankz/render/Render.hx b/src/client/haxe/ru/m/tankz/render/Render.hx index 37625ce..e13468d 100755 --- a/src/client/haxe/ru/m/tankz/render/Render.hx +++ b/src/client/haxe/ru/m/tankz/render/Render.hx @@ -5,12 +5,8 @@ import openfl.Assets; import ru.m.animate.OnceAnimate; import flash.display.DisplayObjectContainer; import ru.m.tankz.core.EntityType; -import flash.display.DisplayObject; -import Type.ValueType; import ru.m.tankz.render.RenderItem; import ru.m.tankz.engine.Engine; -import ru.m.tankz.core.Bullet; -import ru.m.tankz.core.Tank; import flash.display.Sprite; import flash.display.Graphics; import haxework.gui.SpriteView; diff --git a/src/client/haxe/ru/m/tankz/render/RenderItem.hx b/src/client/haxe/ru/m/tankz/render/RenderItem.hx index b023598..9fe3cd7 100644 --- a/src/client/haxe/ru/m/tankz/render/RenderItem.hx +++ b/src/client/haxe/ru/m/tankz/render/RenderItem.hx @@ -1,5 +1,7 @@ package ru.m.tankz.render; +import ru.m.tankz.control.Control; +import flash.display.Sprite; import ru.m.animate.Animate; import ru.m.tankz.core.Eagle; import flash.display.DisplayObject; @@ -114,19 +116,38 @@ class BrickItem extends RenderItem { } -class TankItem extends RenderItem { +class TankItem extends RenderItem { private var type:String; private var hits:Int; + private var tankView:Animate; + public function new(value:Tank) { super(value); - view = new Animate(); + view = new Sprite(); + if (value.playerId.type == Control.HUMAN) { + view.addChild(buildHumanMarkView(value)); + } + tankView = new Animate(); + view.addChild(tankView); redraw(); } + private static function buildHumanMarkView(tank:Tank):DisplayObject { + var view = new Shape(); + view.graphics.beginFill(0x00aa00); + view.graphics.lineStyle(2, 0x00ff00); + view.graphics.drawCircle(0, 0, 23); + view.graphics.endFill(); + view.x = tank.rect.width / 2; + view.y = tank.rect.height / 2; + view.alpha = 0.2; + return view; + } + override public function redraw():Void { - view.frames = getFrames().map(function(s) return Assets.getBitmapData(s)); + tankView.frames = getFrames().map(function(s) return Assets.getBitmapData(s)); } private function getFrames():Array { @@ -160,13 +181,13 @@ class TankItem extends RenderItem { this.hits = h; redraw(); } - view.playing = (value.mx !=0 || value.my != 0); + tankView.playing = (value.mx !=0 || value.my != 0); } override public function dispose():Void { - if (view != null) { - view.dispose(); - view = null; + if (tankView != null) { + tankView.dispose(); + tankView = null; } } } diff --git a/src/client/haxe/ru/m/tankz/view/frames/StartFrame.hx b/src/client/haxe/ru/m/tankz/view/frames/StartFrame.hx index 67f0223..1604343 100644 --- a/src/client/haxe/ru/m/tankz/view/frames/StartFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/frames/StartFrame.hx @@ -12,9 +12,11 @@ import haxework.gui.VGroupView; interface StartFrameLayout { - var start_1p(default, null):ButtonView; - var start_2p(default, null):ButtonView; - var dota(default, null):ButtonView; + var classic_1p(default, null):ButtonView; + var classic_2p(default, null):ButtonView; + var dota_1p(default, null):ButtonView; + var dota_2p_coop(default, null):ButtonView; + var dota_2p_vs(default, null):ButtonView; } @@ -24,29 +26,35 @@ class StartFrame extends VGroupView implements ViewBuilder implements StartFrame public static inline var ID = "start"; public function init() { - start_1p.onPress = this; - start_2p.onPress = this; - dota.onPress = this; + classic_1p.onPress = this; + classic_2p.onPress = this; + dota_1p.onPress = this; + dota_2p_coop.onPress = this; + dota_2p_vs.onPress = this; } public function onPress(view:ButtonView):Void { switch (view.id) { - case 'start_1p': - startGame(ClassicGame.TYPE, 1); - case 'start_2p': - startGame(ClassicGame.TYPE, 2); - case 'dota': - startGame(DotaGame.TYPE, 2); + case 'classic_1p': + startGame(ClassicGame.TYPE, ClassicGame.PLAYER1); + case 'classic_2p': + startGame(ClassicGame.TYPE, ClassicGame.PLAYER2); + case 'dota_1p': + startGame(DotaGame.TYPE, DotaGame.PLAYER1); + case 'dota_2p_coop': + startGame(DotaGame.TYPE, DotaGame.PLAYER2_COOP); + case 'dota_2p_vs': + startGame(DotaGame.TYPE, DotaGame.PLAYER2_VS); } } - private function startGame(type:GameType, humans:Int):Void { + private function startGame(type:GameType, mode:GameMode):Void { switch (type) { case ClassicGame.TYPE: - Provider.set(GameState, ClassicGame.buildState(0, humans)); + Provider.set(GameState, ClassicGame.buildState(0, mode)); Provider.get(IFrameSwitcher).change(LevelFrame.ID); case DotaGame.TYPE: - Provider.set(GameState, DotaGame.buildState(0, humans)); + Provider.set(GameState, DotaGame.buildState(0, mode)); Provider.get(IFrameSwitcher).change(GameFrame.ID); } } diff --git a/src/common/haxe/ru/m/tankz/bot/BotControl.hx b/src/common/haxe/ru/m/tankz/bot/BotControl.hx index b57d05b..c1a010a 100644 --- a/src/common/haxe/ru/m/tankz/bot/BotControl.hx +++ b/src/common/haxe/ru/m/tankz/bot/BotControl.hx @@ -7,14 +7,13 @@ import haxe.Timer; class BotControl extends Control { - public static var TYPE(default, never):ControlType = 'bot'; private var shotTimer:Timer; private var turnRandomTimer:Timer; private var turnTimer:Timer; public function new(index:Int) { - super({type:TYPE, index:index}); + super({type:Control.BOT, index:index}); } override public function onCollision(with:EntityType):Void { diff --git a/src/common/haxe/ru/m/tankz/control/Control.hx b/src/common/haxe/ru/m/tankz/control/Control.hx index 45abfe7..6753d72 100644 --- a/src/common/haxe/ru/m/tankz/control/Control.hx +++ b/src/common/haxe/ru/m/tankz/control/Control.hx @@ -23,6 +23,10 @@ typedef ControlId = { class Control { + public static var NONE(default, never):ControlType = 'none'; + public static var HUMAN(default, never):ControlType = 'human'; + public static var BOT(default, never):ControlType = 'bot'; + public var id:ControlId; public var tankId(default, default):Int; private var handler:ControlHandler; diff --git a/src/common/haxe/ru/m/tankz/game/ClassicGame.hx b/src/common/haxe/ru/m/tankz/game/ClassicGame.hx index 29ba2ea..befb39f 100644 --- a/src/common/haxe/ru/m/tankz/game/ClassicGame.hx +++ b/src/common/haxe/ru/m/tankz/game/ClassicGame.hx @@ -1,5 +1,6 @@ package ru.m.tankz.game; +import ru.m.tankz.control.Control; import haxe.ds.Option; import ru.m.tankz.game.GameState.PlayerState; import ru.m.tankz.game.Game; @@ -12,6 +13,9 @@ class ClassicGame extends Game { public static var HUMAN(default, never):TeamId = 'human'; public static var BOT(default, never):TeamId = 'bot'; + public static var PLAYER1(default, never):GameMode = [{team:HUMAN, type:Control.HUMAN, index:0}]; + public static var PLAYER2(default, never):GameMode = [{team:HUMAN, type:Control.HUMAN, index:0}, {team:HUMAN, type:Control.HUMAN, index:1}]; + private static var HUMAN_LIFE(default, never):Int = 3; private static var BOT_LIFE(default, never):Int = 20; @@ -19,37 +23,22 @@ class ClassicGame extends Game { super(TYPE); } - public static function buildState(level:Int, humans:Int):GameState { + public static function buildState(level:Int, mode:GameMode):GameState { var state = new GameState(); state.type = TYPE; + state.mode = mode; state.level = level; state.teams[HUMAN] = {life: -1, players: new Map(), lose: false}; state.teams[BOT] = {life: BOT_LIFE, players: new Map(), lose: false}; - for (i in 0...humans) { - state.teams[HUMAN].players[i] = { - index:i, - tank:{ - group: HUMAN, - type: '1' - }, - control:{ - type: 'human', - index: i - }, + for (human in mode) { + state.teams[HUMAN].players[human.index] = { + id:human, life:HUMAN_LIFE, }; } - for (i in 0...humans*2+2) { + for (i in 0...mode.length * 2 + 2) { state.teams[BOT].players[i] = { - index:i, - tank:{ - group: BOT, - type: '1' - }, - control:{ - type: 'bot', - index: i - }, + id:{team:BOT, index:i, type:Control.BOT}, life:-1, }; } diff --git a/src/common/haxe/ru/m/tankz/game/DotaGame.hx b/src/common/haxe/ru/m/tankz/game/DotaGame.hx index 3f8071c..6ecd06f 100644 --- a/src/common/haxe/ru/m/tankz/game/DotaGame.hx +++ b/src/common/haxe/ru/m/tankz/game/DotaGame.hx @@ -1,5 +1,6 @@ package ru.m.tankz.game; +import ru.m.tankz.control.Control; import haxe.ds.Option; import ru.m.tankz.game.Game; import ru.m.tankz.game.GameState; @@ -12,52 +13,54 @@ class DotaGame extends Game { public static var RADIANT(default, never):TeamId = 'radiant'; public static var DIRE(default, never):TeamId = 'dire'; + public static var PLAYER1(default, never):GameMode = [ + {team:RADIANT, type:Control.HUMAN, index:0} + ]; + + public static var PLAYER2_COOP(default, never):GameMode = [ + {team:RADIANT, type:Control.HUMAN, index:0}, + {team:RADIANT, type:Control.HUMAN, index:1} + ]; + + public static var PLAYER2_VS(default, never):GameMode = [ + {team:RADIANT, type:Control.HUMAN, index:0}, + {team:DIRE, type:Control.HUMAN, index:0} + ]; + private static var TEAM_SIZE(default, never):Int = 5; public function new() { super(TYPE); } - public static function buildState(level:Int, humans:Int):GameState { + public static function buildState(level:Int, mode:GameMode):GameState { var state = new GameState(); state.type = TYPE; + state.mode = mode; state.level = level; state.teams[RADIANT] = {life: 20, players: new Map(), lose: false}; - state.teams[DIRE] = {life: 20, players: new Map(), lose: false}; + state.teams[DIRE] = {life: 20, players: new Map(), lose: false}; for (i in 0...TEAM_SIZE) { state.teams[RADIANT].players[i] = { - index:i, - tank:{ - group: RADIANT, - type: '1' - }, - control:{ - type: 'bot', - index: i - }, - life:-1, + id: {team:RADIANT, index:i, type:Control.BOT}, + life: -1, }; } for (i in 0...TEAM_SIZE) { state.teams[DIRE].players[i] = { - index:i, - tank:{ - group: DIRE, - type: '1' - }, - control:{ - type: 'bot', - index: i - }, - life:-1, + id: {team:DIRE, index:i, type:Control.BOT}, + life: -1, }; } + for (human in mode) { + state.teams[human.team].players[human.index].id = human; + } return state; } override public function next():Option { state.level++; if (state.level >= config.game.levels) state.level = 0; - return Option.Some(buildState(state.level, 0)); + return Option.Some(buildState(state.level, state.mode)); } } diff --git a/src/common/haxe/ru/m/tankz/game/Game.hx b/src/common/haxe/ru/m/tankz/game/Game.hx index 680149e..95acadc 100644 --- a/src/common/haxe/ru/m/tankz/game/Game.hx +++ b/src/common/haxe/ru/m/tankz/game/Game.hx @@ -23,10 +23,13 @@ import ru.m.tankz.game.Spawner; typedef GameType = String; +typedef GameMode = Array; + typedef TeamId = String; typedef PlayerId = { var team:TeamId; + var type:ControlType; var index:Int; } @@ -75,18 +78,19 @@ class Game implements EngineListener { engine.map.setData(bricks); teams = new Map(); spawners = new Map(); + var humanControlIndex = 0; for (teamConfig in config.teams) { var team = new Team(teamConfig); for (playerState in state.teams.get(team.id).players) { - var player = new Player({team:team.id, index:playerState.index}); + var player = new Player(playerState.id); team.players.push(player); teams.set(team.id, team); - if (playerState.control != null) { - var control = switch (playerState.control.type) { - case HumanControl.TYPE: new HumanControl(playerState.control.index); - case BotControl.TYPE: new BotControl(playerState.control.index); - case 'none': null; - case _: throw 'Unsupported control type: "${playerState.control.type}"'; + if (player.id.type != null) { + var control = switch (player.id.type) { + case Control.HUMAN: new HumanControl(humanControlIndex++); + case Control.BOT: new BotControl(player.id.index); + case Control.NONE: null; + case _: throw 'Unsupported control type: "${player.id.type}"'; } if (control != null) { player.control = control; diff --git a/src/common/haxe/ru/m/tankz/game/GameState.hx b/src/common/haxe/ru/m/tankz/game/GameState.hx index ae192e7..00cdfae 100644 --- a/src/common/haxe/ru/m/tankz/game/GameState.hx +++ b/src/common/haxe/ru/m/tankz/game/GameState.hx @@ -1,23 +1,14 @@ package ru.m.tankz.game; import ru.m.tankz.game.Game; -import ru.m.tankz.config.Config; typedef ControlType = String; -typedef ControId = { - var type:ControlType; - var index:Int; -} - - typedef PlayerState = { - var index:Int; - var tank:TankType; + var id:PlayerId; var life:Int; - var control:ControId; } @@ -30,6 +21,7 @@ typedef TeamState = { class GameState { public var type:GameType; + public var mode:GameMode; public var level:Int; public var teams:Map;