[common] spawn system

This commit is contained in:
2018-01-22 22:31:45 +03:00
parent ce343148c7
commit 981a4b5bab
14 changed files with 228 additions and 137 deletions

View File

@@ -106,10 +106,14 @@ class BrickItem extends RenderItem<Brick> {
class TankItem extends RenderItem<Tank> {
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 {

View File

@@ -21,7 +21,7 @@ class GameFrame extends VGroupView implements ViewBuilder implements IPacketHand
public static inline var ID = "game";
private var game:Game<Dynamic>;
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);

View File

@@ -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

View File

@@ -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 _:
}
}

View File

@@ -14,9 +14,7 @@ typedef MapConfig = {
var cellHeight:Float;
var gridWidth:Int;
var gridHeight:Int;
var bricks:Array<BrickConfig>;
var points:Array<SpawnPoint>;
}
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<SpawnPoint>;
}
class Config {
public var map(default, null):MapConfig;
public var bricks(default, null):Array<BrickConfig>;
public var tanks(default, null):Array<TankConfig>;
public var teams(default, null):Array<TeamConfig>;
private var pointMap:Map<String, Map<Int, SpawnPoint>>;
private var brickMap:Map<Int, BrickConfig>;
private var tankMap:Map<String, Map<Int, TankConfig>>;
private var tankMap:Map<String, Map<String, TankConfig>>;
private var teamMap:Map<String, TeamConfig>;
public function new(map:MapConfig, bricks:Array<BrickConfig>, tanks:Array<TankConfig>) {
public function new(map:MapConfig, bricks:Array<BrickConfig>, teams:Array<TeamConfig>, tanks:Array<TankConfig>) {
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<Int, SpawnPoint>());
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<Int, TankConfig>());
if (!tankMap.exists(item.group)) tankMap.set(item.group, new Map<String, TankConfig>());
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);
}
}

View File

@@ -10,6 +10,7 @@ import ru.m.tankz.config.Config;
typedef ConfigSource = {
var map: MapConfig;
var bricks: Array<BrickConfig>;
var teams: Array<TeamConfig>;
var tanks: Dynamic<Array<TankConfig>>;
}
@@ -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;
}

View File

@@ -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 {
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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:

View File

@@ -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<ClassicGameSettings> {
class ClassicGame extends Game {
public static var TYPE(default, never):GameType = Type.getClassName(ClassicGame);
@@ -20,36 +13,10 @@ class ClassicGame extends Game<ClassicGameSettings> {
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<TeamId, Team>();
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());
}
}
}

View File

@@ -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<S:GameSettings> implements EngineListener implements ControlListener {
class Spawner {
private var config:TeamConfig;
private var runner:SpawnTask -> Void;
private var queue:Array<SpawnTask>;
private var timer:Timer;
private var indexedPoints:Map<Int, SpawnPoint>;
private var anyPoints:Array<SpawnPoint>;
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<TeamId, Team>;
public var config(default, null):Config;
public var engine(default, null):Engine;
public var settings(default, null):S;
private var spawners:Map<TeamId, Spawner>;
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<TeamId, Team>();
spawners = new Map<TeamId, Spawner>();
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<S:GameSettings> 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:
}
}

View File

@@ -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;
}

View File

@@ -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<Player>;
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 = [];
}
}