diff --git a/src/client/haxe/ru/m/tankz/render/RenderItem.hx b/src/client/haxe/ru/m/tankz/render/RenderItem.hx index 290fbfc..984d794 100644 --- a/src/client/haxe/ru/m/tankz/render/RenderItem.hx +++ b/src/client/haxe/ru/m/tankz/render/RenderItem.hx @@ -106,10 +106,14 @@ class BrickItem extends RenderItem { class TankItem extends RenderItem { - private var type:Int; + private var type:String; override private function getImage():String { - return 'resources/images/tank/${value.config.group}/tank_${value.config.group.charAt(0)}${value.config.type}_${value.index}-0.png'; + var group = value.config.group; + var index = value.playerId.index; + if (group == 'human') group = 'player'; + if (group == 'bot') index = 0; + return 'resources/images/tank/${group}/tank_${group.charAt(0)}${value.config.type}_${index}-0.png'; } override public function update():Void { diff --git a/src/client/haxe/ru/m/tankz/view/frames/GameFrame.hx b/src/client/haxe/ru/m/tankz/view/frames/GameFrame.hx index b929ea0..7f5415f 100755 --- a/src/client/haxe/ru/m/tankz/view/frames/GameFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/frames/GameFrame.hx @@ -21,7 +21,7 @@ class GameFrame extends VGroupView implements ViewBuilder implements IPacketHand public static inline var ID = "game"; - private var game:Game; + private var game:Game; private var timer:Timer; public function init():Void { @@ -29,12 +29,9 @@ class GameFrame extends VGroupView implements ViewBuilder implements IPacketHand public function onShow():Void { game = new ClassicGame(ConfigBundle.get(ClassicGame.TYPE, 0)); - game.start({ - humans: 1, - bots: 3, - }); - game.setControl('player', 0, PlayerControl.forPlayer(0)); - //game.setControl('player', 1, PlayerControl.forPlayer(1)); + game.start(); + game.setControl({team:'human', index:0}, PlayerControl.forPlayer(0)); + game.setControl({team:'human', index:1}, PlayerControl.forPlayer(1)); content.addEventListener(Event.ENTER_FRAME, redraw); Provider.get(IConnection).packetHandler.addListener(this); render.draw(game.engine); diff --git a/src/client/resources/config/config.yaml b/src/client/resources/config/config.yaml index ac21f52..ab91b0a 100644 --- a/src/client/resources/config/config.yaml +++ b/src/client/resources/config/config.yaml @@ -3,33 +3,7 @@ map: cellHeight: 22 gridWidth: 26 gridHeight: 26 - bricks: null - points: - - type: player - index: 0 - x: 8 - y: 24 - direction: top - - type: player - index: 1 - x: 16 - y: 24 - direction: top - - type: bot - index: 0 - x: 0 - y: 0 - direction: bottom - - type: bot - index: 1 - x: 12 - y: 0 - direction: bottom - - type: bot - index: 2 - x: 24 - y: 0 - direction: bottom + bricks: [] bricks: # border @@ -61,6 +35,46 @@ bricks: layer: 2 armor: 1 +teams: + - id: human + size: 2 + spawnInterval: 0 + points: + - type: eagle + index: -1 + x: 12 + y: 24 + direction: top + - type: tank + index: 0 + x: 8 + y: 24 + direction: top + - type: tank + index: 1 + x: 16 + y: 24 + direction: top + - id: bot + size: 6 + spawnInterval: 1000 + points: + - type: tank + index: -1 + x: 0 + y: 0 + direction: bottom + - type: tank + index: -1 + x: 12 + y: 0 + direction: bottom + - type: tank + index: -1 + x: 24 + y: 0 + direction: bottom + bullet: &bullet width: 12 height: 12 @@ -68,7 +82,7 @@ bullet: &bullet piercing: 1 tanks: - player: + human: - type: 0 width: 36 height: 36 diff --git a/src/common/haxe/ru/m/tankz/bot/Bot.hx b/src/common/haxe/ru/m/tankz/bot/Bot.hx index ccb217b..0eeaa98 100644 --- a/src/common/haxe/ru/m/tankz/bot/Bot.hx +++ b/src/common/haxe/ru/m/tankz/bot/Bot.hx @@ -1,11 +1,9 @@ package ru.m.tankz.bot; +import ru.m.tankz.core.EntityType; import ru.m.tankz.control.Control; import ru.m.geom.Direction; import haxe.Timer; -import ru.m.tankz.map.Grid.GridCell; -import ru.m.tankz.core.Tank; -import Type.ValueType; class Bot extends Control { @@ -17,10 +15,10 @@ class Bot extends Control { super(); } - override public function onCollision(with:Dynamic):Void { - switch (Type.typeof(with)) { - case ValueType.TClass(Tank): turn(); - case ValueType.TClass(GridCell): turn(); + override public function onCollision(with:EntityType):Void { + switch (with) { + case EntityType.TANK(_): turn(); + case EntityType.CELL(_): turn(); case _: } } diff --git a/src/common/haxe/ru/m/tankz/config/Config.hx b/src/common/haxe/ru/m/tankz/config/Config.hx index ca7d68a..72894dd 100644 --- a/src/common/haxe/ru/m/tankz/config/Config.hx +++ b/src/common/haxe/ru/m/tankz/config/Config.hx @@ -14,9 +14,7 @@ typedef MapConfig = { var cellHeight:Float; var gridWidth:Int; var gridHeight:Int; - var bricks:Array; - var points:Array; } typedef BrickConfig = { @@ -35,7 +33,7 @@ typedef BulletConfig = { typedef TankConfig = { var group:String; - var type:Int; + var type:String; var width:Float; var height:Float; var speed:Float; @@ -44,48 +42,57 @@ typedef TankConfig = { } +typedef TeamConfig = { + var id:String; + var size:Int; + var spawnInterval:Int; + var points:Array; +} + + class Config { public var map(default, null):MapConfig; public var bricks(default, null):Array; public var tanks(default, null):Array; + public var teams(default, null):Array; - private var pointMap:Map>; private var brickMap:Map; - private var tankMap:Map>; + private var tankMap:Map>; + private var teamMap:Map; - public function new(map:MapConfig, bricks:Array, tanks:Array) { + public function new(map:MapConfig, bricks:Array, teams:Array, tanks:Array) { this.map = map; this.bricks = bricks; + this.teams = teams; this.tanks = tanks; init(); } private function init() { - pointMap = new Map(); - for (item in map.points) { - if (!pointMap.exists(item.type)) pointMap.set(item.type, new Map()); - pointMap.get(item.type).set(item.index, item); - } brickMap = new Map(); for (item in bricks) { brickMap.set(item.type, item); } + teamMap = new Map(); + for (team in teams) { + teamMap.set(team.id, team); + } tankMap = new Map(); for (item in tanks) { - if (!tankMap.exists(item.group)) tankMap.set(item.group, new Map()); + if (!tankMap.exists(item.group)) tankMap.set(item.group, new Map()); tankMap.get(item.group).set(item.type, item); } } - public function getSpawnPoint(type:String, index:Int):SpawnPoint { - return pointMap.get(type).get(index); - } - public function getBrick(type:Int):BrickConfig { return brickMap.get(type); } - public function getTank(group:String, type:Int):TankConfig { + public function getTeam(id:String):TeamConfig { + return teamMap.get(id); + } + + public function getTank(group:String, type:String):TankConfig { return tankMap.get(group).get(type); } } diff --git a/src/common/haxe/ru/m/tankz/config/ConfigBundle.hx b/src/common/haxe/ru/m/tankz/config/ConfigBundle.hx index 7c04983..d8e8b3e 100644 --- a/src/common/haxe/ru/m/tankz/config/ConfigBundle.hx +++ b/src/common/haxe/ru/m/tankz/config/ConfigBundle.hx @@ -10,6 +10,7 @@ import ru.m.tankz.config.Config; typedef ConfigSource = { var map: MapConfig; var bricks: Array; + var teams: Array; var tanks: Dynamic>; } @@ -41,7 +42,7 @@ class ConfigBundle { tanks.push(item); } } - return new Config(source.map, source.bricks, tanks); + return new Config(source.map, source.bricks, source.teams, tanks); case _: return null; } diff --git a/src/common/haxe/ru/m/tankz/control/Control.hx b/src/common/haxe/ru/m/tankz/control/Control.hx index 202630b..c7d7ce8 100644 --- a/src/common/haxe/ru/m/tankz/control/Control.hx +++ b/src/common/haxe/ru/m/tankz/control/Control.hx @@ -1,5 +1,6 @@ package ru.m.tankz.control; +import ru.m.tankz.core.EntityType; import ru.m.geom.Direction; @@ -27,7 +28,7 @@ class Control { } } - public function onCollision(with:Dynamic):Void { + public function onCollision(with:EntityType):Void { } diff --git a/src/common/haxe/ru/m/tankz/core/Bullet.hx b/src/common/haxe/ru/m/tankz/core/Bullet.hx index 0d53235..b0f68e2 100644 --- a/src/common/haxe/ru/m/tankz/core/Bullet.hx +++ b/src/common/haxe/ru/m/tankz/core/Bullet.hx @@ -7,12 +7,12 @@ import ru.m.geom.Direction; class Bullet extends MobileEntity { - public var team(default, null):TeamId; + public var playerId(default, null):PlayerId; public var tankId(default, null):Int; public var config(default, null):BulletConfig; public function new(tank:Tank) { - this.team = tank.team; + this.playerId = tank.playerId; this.config = tank.config.bullet; super(new Rectangle(0, 0, config.width, config.height), config.speed, Direction.RIGHT); this.tankId = tank.id; diff --git a/src/common/haxe/ru/m/tankz/core/Tank.hx b/src/common/haxe/ru/m/tankz/core/Tank.hx index 49bb3ba..8e9bc16 100755 --- a/src/common/haxe/ru/m/tankz/core/Tank.hx +++ b/src/common/haxe/ru/m/tankz/core/Tank.hx @@ -9,16 +9,14 @@ import ru.m.geom.Direction; class Tank extends MobileEntity { - public var team(default, null):TeamId; - public var index(default, null):Int; + public var playerId(default, null):PlayerId; public var config(default, set):TankConfig; private var bulletsCounter:Int = 0; - public function new(index:Int, team:TeamId, config:TankConfig) { + public function new(playerId:PlayerId, config:TankConfig) { super(new Rectangle(0, 0, config.width, config.height), config.speed, Direction.RIGHT); - this.index = index; - this.team = team; + this.playerId = playerId; this.config = config; this.layer = 1; } diff --git a/src/common/haxe/ru/m/tankz/engine/Engine.hx b/src/common/haxe/ru/m/tankz/engine/Engine.hx index 940d9f1..1a36dc3 100755 --- a/src/common/haxe/ru/m/tankz/engine/Engine.hx +++ b/src/common/haxe/ru/m/tankz/engine/Engine.hx @@ -30,7 +30,7 @@ class CollisionProcessor implements EngineListener { public function onSpawn(entity:EntityType):Void {} private function checkTankBullet(tank:Tank, bullet:Bullet):Bool { - return tank.team != bullet.team; + return tank.playerId.team != bullet.playerId.team; } public function onCollision(entity:EntityType, with:EntityType):Void { @@ -116,7 +116,7 @@ class Engine { case TankAction.MOVE(direction): tank.move(direction); case TankAction.LEVEL_UP(level): - tank.config = config.getTank('player', Std.int(Math.min(tank.config.type + level, 3))); + tank.config = config.getTank('player', Std.string(Std.int(Math.min(Std.parseInt(tank.config.type) + level, 3)))); case TankAction.STOP: tank.stop(); case TankAction.SHOT: diff --git a/src/common/haxe/ru/m/tankz/game/ClassicGame.hx b/src/common/haxe/ru/m/tankz/game/ClassicGame.hx index 908b9f6..4156886 100644 --- a/src/common/haxe/ru/m/tankz/game/ClassicGame.hx +++ b/src/common/haxe/ru/m/tankz/game/ClassicGame.hx @@ -1,18 +1,11 @@ package ru.m.tankz.game; -import ru.m.tankz.control.Control; import ru.m.tankz.bot.Bot; import ru.m.tankz.game.Game; import ru.m.tankz.config.Config; -typedef ClassicGameSettings = { > GameSettings, - var humans:Int; - var bots:Int; -} - - -class ClassicGame extends Game { +class ClassicGame extends Game { public static var TYPE(default, never):GameType = Type.getClassName(ClassicGame); @@ -20,36 +13,10 @@ class ClassicGame extends Game { super(TYPE, config); } - override public function start(settings:ClassicGameSettings):Void { - super.start(settings); - var humans = new Team('player', settings.humans, 3); - for (index in 0...humans.size) { - var player = new Player(humans.id, index); - humans.players.push(player); - } - var bots = new Team('bot', settings.bots, 20); - for (index in 0...bots.size) { - var bot = new Player(bots.id, 0, new Bot()); - bot.control.bind(this); - bots.players.push(bot); - } - teams = new Map(); - teams.set(humans.id, humans); - teams.set(bots.id, bots); - - for (player in humans.players) { - var point:SpawnPoint = config.getSpawnPoint(humans.type, 0); - var tank = buildTank(0, humans.id, config.getTank(humans.type, 0), point); - engine.spawn(tank); - player.tankId = tank.id; - } - - for (player in bots.players) { - var index = bots.players.indexOf(player); - var point:SpawnPoint = config.getSpawnPoint(bots.type, index); - var tank = buildTank(0, bots.id, config.getTank(bots.type, 0), point); - engine.spawn(tank); - player.tankId = tank.id; + override public function start():Void { + super.start(); + for (player in teams.get('bot').players) { + setControl(player.id, new Bot()); } } } diff --git a/src/common/haxe/ru/m/tankz/game/Game.hx b/src/common/haxe/ru/m/tankz/game/Game.hx index f326772..0291df4 100644 --- a/src/common/haxe/ru/m/tankz/game/Game.hx +++ b/src/common/haxe/ru/m/tankz/game/Game.hx @@ -1,5 +1,6 @@ package ru.m.tankz.game; +import haxe.Timer; import ru.m.tankz.core.EntityType; import ru.m.geom.Direction; import ru.m.geom.Point; @@ -9,43 +10,142 @@ import ru.m.tankz.core.Tank; import ru.m.tankz.engine.Engine; typedef GameType = String; -typedef TeamId = Int; + +typedef TeamId = String; + +typedef PlayerId = { + var team:TeamId; + var index:Int; +} -typedef GameSettings = {} +typedef SpawnTask = { + var point:SpawnPoint; + var playerId:PlayerId; +} -class Game implements EngineListener implements ControlListener { +class Spawner { + + private var config:TeamConfig; + private var runner:SpawnTask -> Void; + private var queue:Array; + private var timer:Timer; + + private var indexedPoints:Map; + private var anyPoints:Array; + private var index:Int; + + public function new(config:TeamConfig, runner:SpawnTask -> Void) { + this.config = config; + this.runner = runner; + queue = []; + indexedPoints = new Map(); + anyPoints = []; + for (point in config.points) { + if (point.type == 'tank') { + if (point.index > -1) { + indexedPoints.set(point.index, point); + } else { + anyPoints.push(point); + } + } + } + } + + public function push(playerId:PlayerId):Void { + var point:SpawnPoint = null; + if (indexedPoints.exists(playerId.index)) { + point = indexedPoints.get(playerId.index); + } else { + point = anyPoints[index++]; + if (index >= anyPoints.length) index = 0; + } + if (point != null) { + queue.push({playerId:playerId, point:point}); + run(); + } + } + + private function run():Void { + if (timer == null) { + timer = new Timer(config.spawnInterval); + timer.run = spawn; + } + } + + private function spawn():Void { + if (queue.length == 0) { + if (timer != null) { + timer.stop(); + timer = null; + } + } else { + runner(queue.shift()); + } + } +} + + +class Game implements EngineListener implements ControlListener { public var type(default, null):GameType; public var teams(default, null):Map; public var config(default, null):Config; public var engine(default, null):Engine; - public var settings(default, null):S; + private var spawners:Map; public function new(type:GameType, config:Config) { this.type = type; this.config = config; this.engine = new Engine(config); + engine.listeners.push(this); } - private function buildTank(index:Int, teamId:TeamId, config:TankConfig, point:SpawnPoint):Tank { - var tank = new Tank(index, teamId, config); + public function getPlayer(playerId:PlayerId):Player { + return teams.get(playerId.team).players[playerId.index]; + } + + private function buildTank(playerId:PlayerId, config:TankConfig, point:SpawnPoint):Tank { + var tank = new Tank(playerId, config); tank.rect.center = new Point((point.x + 1) * engine.map.cellWidth, (point.y + 1) * engine.map.cellHeight); tank.rect.direction = Direction.fromString(point.direction); return tank; } - public function start(settings:S):Void { - this.settings = settings; + public function start():Void { + teams = new Map(); + spawners = new Map(); + for (teamConfig in config.teams) { + var team = new Team(teamConfig); + for (index in 0...team.config.size) { + var player = new Player({team:team.id, index:index}); + team.players.push(player); + teams.set(team.id, team); + } + spawners.set(team.id, new Spawner(team.config, spawn)); + } + + for (team in teams) { + for (player in team.players) { + var point = team.config.points[0]; + spawners.get(team.id).push(player.id); + } + } } - public function setControl(teamType:String, index:Int, control:Control):Void { + private function spawn(task:SpawnTask):Void { + var tank = buildTank(task.playerId, config.getTank(task.playerId.team, '0'), task.point); + var player:Player = teams.get(task.playerId.team).players[task.playerId.index]; + player.tankId = tank.id; + engine.spawn(tank); + } + + public function setControl(playerId:PlayerId, control:Control):Void { for (team in teams.iterator()) { - if (team.type == teamType) { - L.w('XXX', 'players: ${team.players}'); - var player = team.players[index]; + if (team.id == playerId.team) { + var player = team.players[playerId.index]; if (player.control != null) { player.control.dispose(); } @@ -62,11 +162,20 @@ class Game implements EngineListener implements ControlListener } public function onCollision(entity:EntityType, with:EntityType):Void { - + switch (entity) { + case EntityType.TANK(tank): + var control = getPlayer(tank.playerId).control; + if (control != null) control.onCollision(with); + case x: + } } public function onDestroy(entity:EntityType):Void { - + switch (entity) { + case EntityType.TANK(tank): + spawners.get(tank.playerId.team).push(tank.playerId); + case x: + } } diff --git a/src/common/haxe/ru/m/tankz/game/Player.hx b/src/common/haxe/ru/m/tankz/game/Player.hx index 4dc81e3..af78f4e 100644 --- a/src/common/haxe/ru/m/tankz/game/Player.hx +++ b/src/common/haxe/ru/m/tankz/game/Player.hx @@ -6,14 +6,12 @@ import ru.m.tankz.game.Game; class Player { - public var index(default, null):Int; - public var team(default, null):TeamId; + public var id(default, null):PlayerId; public var tankId(default, set):Int; public var control(default, set):Control; - public function new(team:TeamId, index:Int, control:Control=null) { - this.team = team; - this.index = index; + public function new(id:PlayerId, control:Control=null) { + this.id = id; this.control = control; } diff --git a/src/common/haxe/ru/m/tankz/game/Team.hx b/src/common/haxe/ru/m/tankz/game/Team.hx index 21aca40..49bf57c 100644 --- a/src/common/haxe/ru/m/tankz/game/Team.hx +++ b/src/common/haxe/ru/m/tankz/game/Team.hx @@ -1,5 +1,6 @@ package ru.m.tankz.game; +import ru.m.tankz.config.Config.TeamConfig; import ru.m.tankz.game.Player; import ru.m.tankz.game.Game; @@ -7,18 +8,14 @@ import ru.m.tankz.game.Game; class Team { public var id(default, null):TeamId; - public var type(default, null):String; - public var size(default, null):Int; - public var life(default, default):Int; + public var config(default, null):TeamConfig; public var players(default, null):Array; private static var i:Int = 0; - public function new(type:String, size:Int, life:Int) { - this.id = ++i; - this.type = type; - this.size = size; - this.life = life; + public function new(config:TeamConfig) { + this.id = config.id; + this.config = config; this.players = []; } }