[common] add PlayerControl presets

This commit is contained in:
2019-05-30 15:24:26 +03:00
parent c7946ef1da
commit abf944418e
26 changed files with 264 additions and 92 deletions

View File

@@ -16,7 +16,7 @@ class ConfigBundle implements IConfigBundle {
public function get(type:GameType):Config {
if (!_cache.exists(type)) {
var source:ConfigSource = Yaml.parse(Assets.getText('resources/${type}/config.yaml'), Parser.options().useObjects());
_cache.set(type, new Config(type, source.game, source.map, source.bricks, source.presets, source.points, source.tanks, source.bonuses));
_cache.set(type, Config.fromSource(type, source));
}
return _cache.get(type);
}

View File

@@ -8,6 +8,8 @@ class NetworkControl extends HumanControl {
@:provide private var network:NetworkManager;
override public function action(action:TankAction):Void {
network.action(tankId, action);
if (tankId > -1) {
network.action(tankId, action);
}
}
}

View File

@@ -26,6 +26,14 @@ class NetworkGame extends Game {
gameEventSignal.emit(event);
}
override public function start():Void {
var player = Lambda.find(network.game.players, function(player) return player.user.uuid == network.user.uuid);
if (player != null) {
state.controls.push({playerId: [player.team, player.index], control: "human-0"});
}
super.start();
}
override public function dispose():Void {
super.dispose();
network.gameEventSignal.disconnect(onGameEventProto);

View File

@@ -117,7 +117,7 @@ class Render extends SpriteView implements IRender {
case SPAWN(TANK(id, rect, playerId, info)):
var item = new TankRenderItem(rect);
var tankConfig = config.getTank(info.type);
item.color = config.getColor(playerId);
item.color = info.color;
item.skin = tankConfig.skin;
item.hits = info.hits;
item.bonus = info.bonus;

View File

@@ -33,9 +33,10 @@ import ru.m.tankz.view.popup.LevelPopup;
levels.data = [for (i in 0...state.config.game.levels) i];
}
private function start(level:LevelConfig, preset:GamePreset):Void {
private function start(level:LevelConfig, preset:GamePreset, control:ControlPreset):Void {
state.levelId = level.id;
state.presetId = preset.id;
state.controls = control.values;
game = new LocalGame(state);
switcher.change(GameFrame.ID);
}
@@ -61,8 +62,9 @@ import ru.m.tankz.view.popup.LevelPopup;
levelPopup.setData(
level,
state.config.presets,
state.config.controls,
storage.get(state.type)
);
levelPopup.show().then(function(preset) preset != null ? start(level, preset) : {});
levelPopup.show().then(function(result) result != null ? start(level, result.preset, result.control) : {});
}
}

View File

@@ -10,7 +10,7 @@ import ru.m.tankz.game.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;
import ru.m.tankz.proto.core.PlayerProto;
@:template class GameRoomFrame extends VGroupView {
@@ -18,7 +18,7 @@ import ru.m.tankz.proto.core.UserProto;
@:view var start:ButtonView;
@:view var info:TextView;
@:view var players:VListView<UserProto>;
@:view var players:VListView<PlayerProto>;
@:provide var switcher:FrameSwitcher;
@:provide var network:NetworkManager;

View File

@@ -3,18 +3,18 @@ package ru.m.tankz.view.network;
import haxework.view.HGroupView;
import haxework.view.LabelView;
import haxework.view.list.ListView;
import ru.m.tankz.proto.core.UserProto;
import ru.m.tankz.proto.core.PlayerProto;
@:template class PlayerItemView extends HGroupView implements IListItemView<UserProto> {
@:template class PlayerItemView extends HGroupView implements IListItemView<PlayerProto> {
public var item_index(default, default):Int;
public var data(default, set):UserProto;
public var data(default, set):PlayerProto;
@:view var label:LabelView;
private function set_data(value:UserProto):UserProto {
private function set_data(value:PlayerProto):PlayerProto {
data = value;
label.text = '${value.name}';
label.text = '${value.user.name}';
return data;
}

View File

@@ -1,5 +1,6 @@
package ru.m.tankz.view.popup;
import haxework.view.ToggleButtonView;
import haxework.view.ButtonView;
import haxework.view.DataView;
import haxework.view.LabelView;
@@ -7,19 +8,28 @@ import haxework.view.popup.PopupView;
import ru.m.tankz.config.Config;
import ru.m.tankz.game.GameProgress;
@:template class LevelPopup extends PopupView<GamePreset> {
typedef Result = {
var control:ControlPreset;
var preset:GamePreset;
}
@:template class LevelPopup extends PopupView<Result> {
private var level:LevelConfig;
private var progress:GameProgress;
@:view var name:LabelView;
@:view("presets") var presetsView:DataView<GamePreset, ButtonView>;
@:view("controls") var controlsView:DataView<ControlPreset, ToggleButtonView>;
private var control:ControlPreset;
public function setData(level:LevelConfig, presets:Array<GamePreset>, progress:GameProgress):Void {
public function setData(level:LevelConfig, presets:Array<GamePreset>, controls:Array<ControlPreset>, progress:GameProgress):Void {
this.level = level;
this.progress = progress;
name.text = '${level.id}. ${level.name != null ? level.name : "#"}';
presetsView.data = presets;
control = controls[0];
controlsView.data = controls;
}
private function presetViewFactory(index:Int, value:GamePreset):ButtonView {
@@ -32,7 +42,22 @@ import ru.m.tankz.game.GameProgress;
private function onPresetSelect(value:GamePreset):Void {
if (progress.isPresetAvailable(level.id, value.id)) {
close(value);
close({control: control, preset: value});
}
}
private function controlViewFactory(index:Int, value:ControlPreset):ToggleButtonView {
var result = new ToggleButtonView();
result.skinId = 'button.simple.active';
result.on = control == value;
result.text = value.name;
return result;
}
private function onControlSelect(index:Int, value:ControlPreset, view:ToggleButtonView):Void {
control = value;
for (v in controlsView.dataViews) {
v.on = v == view;
}
}
}

View File

@@ -24,6 +24,15 @@ view:
+onPress: $code:reject('close')
- $type: haxework.view.SpriteView
geometry.size.height: 100%
- id: controls
$type: haxework.view.DataView
factory: $this:controlViewFactory
+onItemSelect: $this:onControlSelect
layout:
$type: haxework.view.layout.HorizontalLayout
hAlign: center
margin: 5
skinId: panel
- id: presets
$type: haxework.view.DataView
factory: $this:presetViewFactory

View File

@@ -3,17 +3,6 @@ package ru.m.tankz.bundle;
import ru.m.tankz.config.Config;
import ru.m.tankz.Type;
typedef ConfigSource = {
var game:GameConfig;
var map: MapConfig;
var bricks: Array<BrickConfig>;
var presets: Array<GamePreset>;
var points: Array<SpawnPoint>;
var tanks: Array<TankConfig>;
var bonuses: Array<BonusConfig>;
}
interface IConfigBundle {
public function get(type:GameType):Config;
}

View File

@@ -105,6 +105,29 @@ typedef LevelConfig = {
@:optional var points:Array<SpawnPoint>;
}
typedef PlayerControl = {
var playerId:PlayerId;
var control:String;
@:optional var color:Color;
}
typedef ControlPreset = {
var id:Int;
var name:String;
var values:Array<PlayerControl>;
};
typedef ConfigSource = {
var game:GameConfig;
var map: MapConfig;
var bricks: Array<BrickConfig>;
var presets: Array<GamePreset>;
var controls: Array<ControlPreset>;
var points: Array<SpawnPoint>;
var tanks: Array<TankConfig>;
var bonuses: Array<BonusConfig>;
}
class Config {
public var type(default, null):String;
public var game(default, null):GameConfig;
@@ -112,6 +135,7 @@ class Config {
public var bricks(default, null):Array<BrickConfig>;
public var tanks(default, null):Array<TankConfig>;
public var presets(default, null):Array<GamePreset>;
public var controls(default, null):Array<ControlPreset>;
public var points(default, null):Array<SpawnPoint>;
public var bonuses(default, null):Array<BonusConfig>;
@@ -123,12 +147,17 @@ class Config {
private var teamsMap:Map<TeamId, TeamConfig>;
private var playersMap:Map<String, PlayerConfig>;
public static function fromSource(type:GameType, source:ConfigSource):Config {
return new Config(type, source.game, source.map, source.bricks, source.presets, source.controls, source.points, source.tanks, source.bonuses);
}
public function new(
type:String,
game:GameConfig,
map:MapConfig,
bricks:Array<BrickConfig>,
presets:Array<GamePreset>,
controls:Array<ControlPreset>,
points:Array<SpawnPoint>,
tanks:Array<TankConfig>,
bonuses:Array<BonusConfig>
@@ -138,6 +167,7 @@ class Config {
this.map = map;
this.bricks = bricks;
this.presets = presets;
this.controls = controls;
this.points = points;
this.tanks = tanks;
this.bonuses = bonuses;

View File

@@ -1,5 +1,6 @@
package ru.m.tankz.game;
import haxework.color.Color;
import ru.m.geom.Direction;
import ru.m.geom.Point;
import ru.m.geom.Rectangle;
@@ -43,11 +44,11 @@ class EntityBuilder {
return eagle;
}
public function buildTank(point:EntityPoint, playerId:PlayerId, type:TankType, bonusOff:Bool = false):Tank {
public function buildTank(point:EntityPoint, playerId:PlayerId, type:TankType, color:Color, bonusOff:Bool = false):Tank {
var playerConfig = config.getPlayer(playerId);
var tankConfig = config.getTank(type);
var tank = new Tank(++entityId, buildRect(point, tankConfig.width, tankConfig.height), playerId, tankConfig);
tank.color = config.getColor(playerId);
tank.color = color.zero ? config.getColor(playerId) : color;
if (!bonusOff) {
tank.bonus = Math.random() < playerConfig.bonus;
}

View File

@@ -31,7 +31,8 @@ class EventUtil {
return GameEvent.SPAWN(TANK(tank.id, tank.rect.clone(), tank.playerId, {
type:tank.config.type,
hits:tank.hits,
bonus:tank.bonus
bonus:tank.bonus,
color:tank.color,
}));
}

View File

@@ -55,15 +55,15 @@ import ru.m.tankz.Type;
public function onGameEvent(event:GameEvent):Void {
switch event {
case GameEvent.START(state):
case START(state):
this.state = state;
case GameEvent.COMPLETE(state, winnerId):
case COMPLETE(state, winnerId):
this.state = state;
this.winner = winnerId;
case GameEvent.SPAWN(EAGLE(id, rect, teamId)):
case SPAWN(EAGLE(id, rect, teamId)):
var team = getTeam(teamId);
team.eagleId = id;
case GameEvent.SPAWN(TANK(id, rect, playerId, info)):
case SPAWN(TANK(id, rect, playerId, info)):
var player = getPlayer(playerId);
player.tankId = id;
player.state.tank = info.type;
@@ -79,12 +79,24 @@ import ru.m.tankz.Type;
var team:Team = new Team(teamConfig, teamPoints, state.teams[teamConfig.id]);
teams[team.id] = team;
}
var controlsById:Map<String, PlayerControl> = new Map();
for (control in state.controls) {
controlsById[control.playerId] = control;
}
for (team in teams.iterator()) {
for (player in team.players.iterator()) {
var control = controlFactory.build(player.id, AController.fromString(player.config.control));
var playerControl = controlsById.get(player.id);
if (playerControl != null && !playerControl.color.zero) {
player.state.color = playerControl.color;
}
var controlType:Controller = AController.fromString(playerControl != null ? playerControl.control : player.config.control);
var control = controlFactory.build(player.id, controlType);
if (control != null) {
player.control = control;
player.control.bind(this, engine);
} else {
// ToDo: remove player
player.state.life = 0;
}
}
}

View File

@@ -1,5 +1,6 @@
package ru.m.tankz.game;
import haxework.color.Color;
import ru.m.geom.Position;
import ru.m.geom.Rectangle;
import ru.m.tankz.control.Control;
@@ -9,6 +10,7 @@ typedef TankInfo = {
var type:TankType;
var hits:Int;
var bonus:Bool;
var color:Color;
}
typedef BrickInfo = {

View File

@@ -1,5 +1,6 @@
package ru.m.tankz.game;
import haxework.color.Color;
import ru.m.geom.Line;
import ru.m.geom.Point;
import ru.m.tankz.control.Control;
@@ -58,12 +59,13 @@ class GameRunner extends Game implements EngineListener {
}
}
gameEventSignal.emit(EventUtil.buildBricksSpawn(engine.map));
gameEventSignal.emit(GameEvent.START(state));
gameEventSignal.emit(START(state));
//for (i in 0...10) spawnBonus();
}
private function spawn(task:SpawnTask):Void {
var tank = builder.buildTank(task.point, task.playerId, task.tankType);
var player = getPlayer(task.playerId);
var tank = builder.buildTank(task.point, task.playerId, task.tankType, player.state.color);
engine.spawn(tank);
gameEventSignal.emit(EventUtil.buildTankSpawn(tank));
tank.protect.connect(onTankProtectChange);
@@ -71,15 +73,15 @@ class GameRunner extends Game implements EngineListener {
}
private function onEagleProtectChange(id:Int, state:Bool):Void {
gameEventSignal.emit(GameEvent.CHANGE(EAGLE_PROTECT(id, state)));
gameEventSignal.emit(CHANGE(EAGLE_PROTECT(id, state)));
}
private function onTankProtectChange(id:Int, state:Bool):Void {
gameEventSignal.emit(GameEvent.CHANGE(TANK_PROTECT(id, state)));
gameEventSignal.emit(CHANGE(TANK_PROTECT(id, state)));
}
private function onTankFreezingChange(id:Int, state:Bool):Void {
gameEventSignal.emit(GameEvent.CHANGE(TANK_FREEZE(id, state)));
gameEventSignal.emit(CHANGE(TANK_FREEZE(id, state)));
}
private function checkComplete():Void {
@@ -107,13 +109,13 @@ class GameRunner extends Game implements EngineListener {
for (team in teams.iterator()) {
for (player in team.players) {
if (player.control != null) {
player.control.action(TankAction.STOP);
player.control.action(STOP);
player.control.dispose();
}
}
}
Timer.delay(function() {
gameEventSignal.emit(GameEvent.COMPLETE(state, winner));
gameEventSignal.emit(COMPLETE(state, winner));
}, 3000);
}
@@ -129,11 +131,11 @@ class GameRunner extends Game implements EngineListener {
}
private inline function emitTankMove(tank:Tank):Void {
gameEventSignal.emit(GameEvent.MOVE(TANK(tank.id, {x:tank.rect.x, y:tank.rect.y, direction:tank.rect.direction})));
gameEventSignal.emit(MOVE(TANK(tank.id, {x:tank.rect.x, y:tank.rect.y, direction:tank.rect.direction})));
}
private inline function emitTankChange(tank:Tank):Void {
gameEventSignal.emit(GameEvent.CHANGE(TANK(tank.id, tank.config.type, tank.hits, tank.bonus)));
gameEventSignal.emit(CHANGE(TANK(tank.id, tank.config.type, tank.hits, tank.bonus)));
}
public function onCollision(entity:EntityType, with:EntityType):Void {
@@ -154,14 +156,14 @@ class GameRunner extends Game implements EngineListener {
tank.rect.lean(cell.rect);
emitTankMove(tank);
case [BULLET(bullet), BULLET(other_bullet)]:
gameEventSignal.emit(GameEvent.DESTROY(BULLET(bullet.id)));
gameEventSignal.emit(GameEvent.DESTROY(BULLET(other_bullet.id)));
gameEventSignal.emit(DESTROY(BULLET(bullet.id)));
gameEventSignal.emit(DESTROY(BULLET(other_bullet.id)));
case [BULLET(bullet), CELL(cell)]:
bullet.rect.lean(cell.rect);
gameEventSignal.emit(GameEvent.HIT(CELL(cell.cellX, cell.cellY, buildShot(bullet))));
gameEventSignal.emit(GameEvent.DESTROY(BULLET(bullet.id)));
gameEventSignal.emit(HIT(CELL(cell.cellX, cell.cellY, buildShot(bullet))));
gameEventSignal.emit(DESTROY(BULLET(bullet.id)));
case [TANK(tank), BONUS(bonus)]:
gameEventSignal.emit(GameEvent.DESTROY(BONUS(bonus.id, {tankId: tank.id, score: bonus.config.score})));
gameEventSignal.emit(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 || (!config.game.friendlyFire && tank.playerId.team == bullet.playerId.team)) {
// Nothing
@@ -173,27 +175,27 @@ class GameRunner extends Game implements EngineListener {
tank.bonus = false;
spawnBonus();
}
gameEventSignal.emit(GameEvent.HIT(TANK(tank.id, buildShot(bullet))));
gameEventSignal.emit(HIT(TANK(tank.id, buildShot(bullet))));
emitTankChange(tank);
} else if (tank.config.downgrade != null) {
tank.config = config.getTank(tank.config.downgrade);
gameEventSignal.emit(GameEvent.HIT(TANK(tank.id, buildShot(bullet))));
gameEventSignal.emit(HIT(TANK(tank.id, buildShot(bullet))));
emitTankChange(tank);
} else {
var score = tank.config.score;
if (tank.playerId.team == bullet.playerId.team) {
score = Math.round(score * -0.5);
}
gameEventSignal.emit(GameEvent.DESTROY(TANK(tank.id, buildShot(bullet, score))));
gameEventSignal.emit(DESTROY(TANK(tank.id, buildShot(bullet, score))));
}
}
gameEventSignal.emit(GameEvent.DESTROY(BULLET(bullet.id)));
gameEventSignal.emit(DESTROY(BULLET(bullet.id)));
}
case [BULLET(bullet), EAGLE(eagle)]:
if (!eagle.protect.active) {
gameEventSignal.emit(GameEvent.DESTROY(EAGLE(eagle.id, buildShot(bullet, eagle.score))));
gameEventSignal.emit(DESTROY(EAGLE(eagle.id, buildShot(bullet, eagle.score))));
}
gameEventSignal.emit(GameEvent.DESTROY(BULLET(bullet.id)));
gameEventSignal.emit(DESTROY(BULLET(bullet.id)));
case _:
}
}
@@ -203,7 +205,7 @@ class GameRunner extends Game implements EngineListener {
case TANK(tank):
emitTankMove(tank);
case BULLET(bullet):
gameEventSignal.emit(GameEvent.MOVE(BULLET(bullet.id, {x:bullet.rect.x, y:bullet.rect.y, direction:bullet.rect.direction})));
gameEventSignal.emit(MOVE(BULLET(bullet.id, {x:bullet.rect.x, y:bullet.rect.y, direction:bullet.rect.direction})));
case _:
}
}
@@ -220,7 +222,7 @@ class GameRunner extends Game implements EngineListener {
}
var bonus = builder.buildBonus(point, type);
engine.spawn(bonus);
gameEventSignal.emit(GameEvent.SPAWN(BONUS(bonus.id, bonus.rect.clone(), bonus.config.type)));
gameEventSignal.emit(SPAWN(BONUS(bonus.id, bonus.rect.clone(), bonus.config.type)));
}
private inline function alienTank(team:TeamId):Tank->Bool {
@@ -235,7 +237,7 @@ class GameRunner extends Game implements EngineListener {
upgradeTank(tank);
case "grenade":
for (t in engine.iterTanks(alienTank(tank.playerId.team))) {
gameEventSignal.emit(GameEvent.DESTROY(TANK(t.id, {tankId: tank.id})));
gameEventSignal.emit(DESTROY(TANK(t.id, {tankId: tank.id})));
}
case "helmet":
tank.protect.on(bonus.config.duration);
@@ -243,7 +245,7 @@ class GameRunner extends Game implements EngineListener {
for (t in engine.iterTanks(alienTank(tank.playerId.team))) {
t.freezing.on(bonus.config.duration);
t.stop();
gameEventSignal.emit(GameEvent.STOP(TANK(t.id)));
gameEventSignal.emit(STOP(TANK(t.id)));
}
case "shovel":
// ToDo: protect eagle/area
@@ -255,7 +257,7 @@ class GameRunner extends Game implements EngineListener {
case "gun":
upgradeTank(tank, 5);
case _:
gameEventSignal.emit(GameEvent.DESTROY(TANK(tank.id, {tankId: tank.id}))); // :-D
gameEventSignal.emit(DESTROY(TANK(tank.id, {tankId: tank.id}))); // :-D
}
}
@@ -274,34 +276,34 @@ class GameRunner extends Game implements EngineListener {
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, state.getTeamScore(team.id))));
gameEventSignal.emit(CHANGE(PLAYER_SCORE(playerId, player.state.score)));
gameEventSignal.emit(CHANGE(TEAM_SCORE(playerId.team, state.getTeamScore(team.id))));
}
private function changeLife(playerId:PlayerId, life:Int):Void {
var player = getPlayer(playerId);
player.state.life += life;
gameEventSignal.emit(GameEvent.CHANGE(PLAYER_LIFE(playerId, player.state.life)));
gameEventSignal.emit(CHANGE(PLAYER_LIFE(playerId, player.state.life)));
}
private function changeTeamLife(teamId:TeamId, life:Int):Void {
var team = getTeam(teamId);
team.state.life += life;
gameEventSignal.emit(GameEvent.CHANGE(TEAM_LIFE(teamId, team.state.life)));
gameEventSignal.emit(CHANGE(TEAM_LIFE(teamId, team.state.life)));
}
override public function onGameEvent(event:GameEvent):Void {
super.onGameEvent(event);
switch event {
case GameEvent.START(_):
case START(_):
timer = new Timer(30);
timer.run = update;
case GameEvent.COMPLETE(_, _):
case COMPLETE(_, _):
if (timer != null) {
timer.stop();
timer = null;
}
case GameEvent.ACTION(tankId, SHOT):
case ACTION(tankId, SHOT):
var tank:Tank = cast engine.entities.get(tankId);
var player = getPlayer(tank.playerId);
if (!tank.freezing.active && player.bullets < tank.config.bullets) {
@@ -311,21 +313,21 @@ class GameRunner extends Game implements EngineListener {
bullet.tank = tank;
bullet.move(bullet.rect.direction);
engine.spawn(bullet);
gameEventSignal.emit(GameEvent.SPAWN(BULLET(bullet.id, bullet.rect.clone(), bullet.playerId, bullet.config.piercing)));
gameEventSignal.emit(SPAWN(BULLET(bullet.id, bullet.rect.clone(), bullet.playerId, bullet.config.piercing)));
}
case GameEvent.ACTION(tankId, MOVE(direction)):
case ACTION(tankId, MOVE(direction)):
engine.move(tankId, direction);
case GameEvent.ACTION(tankId, STOP):
gameEventSignal.emit(GameEvent.STOP(TANK(tankId)));
case ACTION(tankId, STOP):
gameEventSignal.emit(STOP(TANK(tankId)));
engine.stop(tankId);
case GameEvent.SPAWN(TANK(_, _, playerId, _)):
case SPAWN(TANK(_, _, playerId, _)):
var control = getPlayer(playerId).control;
if (control != null) {
control.start();
}
case GameEvent.SPAWN(BULLET(_, _, playerId, _)):
case SPAWN(BULLET(_, _, playerId, _)):
getPlayer(playerId).bullets++;
case GameEvent.DESTROY(EAGLE(id, shot)):
case DESTROY(EAGLE(id, shot)):
var eagle:Eagle = engine.getEntity(id);
eagle.death = true;
if (shot.score != 0) {
@@ -333,7 +335,7 @@ class GameRunner extends Game implements EngineListener {
changeScore(tank.playerId, shot.score);
}
checkComplete();
case GameEvent.DESTROY(TANK(id, shot)):
case DESTROY(TANK(id, shot)):
var tank:Tank = engine.getEntity(id);
var team = getTeam(tank.playerId.team);
var player = getPlayer(tank.playerId);
@@ -362,7 +364,7 @@ class GameRunner extends Game implements EngineListener {
changeScore(shooterTank.playerId, shot.score);
}
engine.destroy(id);
case GameEvent.DESTROY(BONUS(id, shot)):
case DESTROY(BONUS(id, shot)):
var bonus:Bonus = engine.getEntity(id);
var tank:Tank = engine.getEntity(shot.tankId);
applyBonus(tank, bonus);
@@ -370,7 +372,7 @@ class GameRunner extends Game implements EngineListener {
changeScore(tank.playerId, shot.score);
}
engine.destroy(id);
case GameEvent.DESTROY(BULLET(id)):
case DESTROY(BULLET(id)):
var bullet:Bullet = engine.getEntity(id);
var player = getPlayer(bullet.playerId);
player.bullets--;
@@ -385,13 +387,13 @@ class GameRunner extends Game implements EngineListener {
if (cell.armor == bullet.config.piercing) {
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)));
gameEventSignal.emit(DESTROY(CELL(brick.id, cell.cellX - brick.cellX * 2, cell.cellY - brick.cellY * 2, shot)));
} else if (cell.armor < bullet.config.piercing) {
var brick = engine.map.getBrick(cell.position);
for (cell in brick.cells) {
engine.destroyCell(cell.cellX, cell.cellY);
}
gameEventSignal.emit(GameEvent.DESTROY(BRICK(brick.id, shot)));
gameEventSignal.emit(DESTROY(BRICK(brick.id, shot)));
}
}
}

View File

@@ -72,6 +72,7 @@ class GameState {
public var type:GameType;
public var presetId:PresetId;
public var levelId:LevelId;
public var controls:Array<PlayerControl>;
public var players:Map<String, PlayerState>;
public var teams:Map<TeamId, TeamState>;
public var preset(get, null):GamePreset;
@@ -81,10 +82,12 @@ class GameState {
@:provide static private var configBundle:IConfigBundle;
@:provide static private var levelBundle:ILevelBundle;
public function new(type:GameType, presetId:PresetId = 0, levelId:Int = 0, state:GameState = null) {
public function new(type:GameType, presetId:PresetId = 0, levelId:Int = 0, state:GameState = null, controls:Array<PlayerControl> = null) {
this.type = type;
this.presetId = presetId;
this.levelId = levelId;
//this.controls = controls == null ? config.controls[0].values : controls;
this.controls = controls == null ? [] : controls;
if (state == null) {
this.teams = new Map();
this.players = new Map();

View File

@@ -2,7 +2,6 @@ syntax = "proto3";
package ru.m.tankz.proto.core;
message UserProto {
string uuid = 1;
string name = 2;
@@ -14,11 +13,17 @@ enum GameStateProto {
ENDED = 2;
}
message PlayerProto {
UserProto user = 1;
string team = 2;
int32 index = 3;
}
message GameProto {
int32 id = 1;
string type = 2;
int32 level = 3;
UserProto creator = 4;
repeated UserProto players = 5;
repeated PlayerProto players = 5;
GameStateProto state = 6;
}

View File

@@ -38,14 +38,15 @@ team:
human: &team_human
id: human
players:
- {<<: *human, index: 0, color: 0xFFFF00, control: human-0}
- {<<: *human, index: 0, color: 0xFFFF00, control: 'null'}
- {<<: *human, index: 1, color: 0x15C040, control: 'null'}
eagle:
score: 0
points:
- {team: human, type: eagle, index: -1, direction: right, x: 12, y: 24}
- {team: human, type: tank, index: 0, direction: top, x: 8, y: 24}
#- {team: human, type: tank, index: 1, direction: top, x: 16, y: 24}
- {team: human, type: tank, index: 1, direction: top, x: 16, y: 24}
- {team: bot, type: tank, index: -1, direction: bottom, x: 0, y: 0}
- {team: bot, type: tank, index: -2, direction: bottom, x: 12, y: 0}
- {team: bot, type: tank, index: -3, direction: bottom, x: 24, y: 0}
@@ -195,3 +196,17 @@ presets:
- {<<: *bot, index: 3, control: bot-hard}
- {<<: *bot, index: 4, control: bot-hard}
- {<<: *bot, index: 5, control: bot-hard}
controls:
- id: 0
name: 1 Player
values:
- playerId: [human, 0]
control: human-0
- id: 1
name: 2 Player
values:
- playerId: [human, 0]
control: human-0
- playerId: [human, 1]
control: human-1

View File

@@ -37,8 +37,6 @@ presets:
teams:
- id: alpha
color: 0xFF4422
players:
- {<<: *player, index: 0, control: human-0}
<<: *team
- id: beta
color: 0xFFD000
@@ -91,3 +89,17 @@ tanks:
skin: pc
bonuses: []
controls:
- id: 0
name: 1 Player
values:
- playerId: [alpha, 0]
control: human-0
- id: 1
name: 2 Player
values:
- playerId: [alpha, 0]
control: human-0
- playerId: [beta, 0]
control: human-1

View File

@@ -41,7 +41,7 @@ team:
id: radiant
color: 0xff4422
players:
- {<<: *player-slow, index: 0, control: human-0, color: 0xff8866}
- {<<: *player-slow, index: 0, control: bot-hard}
- {<<: *player-fast, index: 1, control: bot-hard}
- {<<: *player-slow, index: 2, control: bot-hard}
- {<<: *player-fast, index: 3, control: bot-hard}
@@ -114,3 +114,29 @@ bonuses:
- {type: life}
- {type: shovel, duration: 10}
- {type: star}
controls:
- id: 0
name: 1 Player
values:
- playerId: [radiant, 0]
control: human-0
color: 0xff8866
- id: 1
name: 2 Player Coop
values:
- playerId: [radiant, 0]
control: human-0
color: 0xff8866
- playerId: [radiant, 1]
control: human-1
color: 0xff8866
- id: 2
name: 2 Player VS
values:
- playerId: [radiant, 0]
control: human-0
color: 0xff8866
- playerId: [dire, 0]
control: human-1
color: 0x4294ff

View File

@@ -117,7 +117,7 @@ enum Brush {
var playerId = new PlayerId(point.team, point.index < 0 ? 0 : point.index);
var player = config.getPlayer(playerId);
var tankSpawn = player.tanks[0];
var tank = builder.buildTank(point, playerId, tankSpawn.type, true);
var tank = builder.buildTank(point, playerId, tankSpawn.type, 0, true);
pointEntities[pointKey(point)] = tank;
gameEventSignal.emit(EventUtil.buildTankSpawn(tank));
}

View File

@@ -16,6 +16,6 @@ class ServerConfigBundle implements IConfigBundle {
var path:String = FileSystem.absolutePath('./resources/${type}/config.yaml');
var data:String = File.getContent(path);
var source:ConfigSource = Yaml.parse(data, Parser.options().useObjects());
return new Config(type, source.game, source.map, source.bricks, source.presets, source.points, source.tanks, source.bonuses);
return Config.fromSource(type, source);
}
}

View File

@@ -1,7 +1,14 @@
package ru.m.tankz.server.control;
import ru.m.tankz.Type;
import ru.m.tankz.control.Control;
import ru.m.tankz.control.BaseControlFactory;
class ClientControl extends Control {}
class ServerControlFactory extends BaseControlFactory {
override private function buildHuman(id:PlayerId, index:Int):Control {
return new ClientControl(id);
}
}

View File

@@ -58,9 +58,9 @@ class _GameListener implements GameListener {
.setId(++counter)
.setCreator(user)
.setType(type)
.setLevel(level)
.setPlayers([user]);
.setLevel(level);
var game = new ServerGame(proto);
game.joinUser(user);
games.push(game);
gamesById[game.proto.id] = game;
gamesByCreator[game.proto.creator.uuid] = game;
@@ -71,7 +71,7 @@ class _GameListener implements GameListener {
public function join(gameId:Int, user:UserProto):Void {
if (gamesById.exists(gameId)) {
var game = gamesById[gameId];
game.proto.players.push(user);
game.joinUser(user);
gamesByUser[user.uuid] = game;
changeSignal.emit(game, JOIN(user));
}
@@ -92,7 +92,7 @@ class _GameListener implements GameListener {
delete(gamesByCreator[user.uuid].proto.id);
} else if (gamesByUser.exists(user.uuid)) {
var game = gamesByUser[user.uuid];
game.proto.setPlayers(game.proto.players.filter(function(player) return player.uuid != user.uuid));
game.leaveUser(user);
changeSignal.emit(game, LEAVE(user));
}
}

View File

@@ -1,8 +1,11 @@
package ru.m.tankz.server.game;
import ru.m.tankz.config.Config;
import ru.m.tankz.game.GameRunner;
import ru.m.tankz.game.GameState;
import ru.m.tankz.proto.core.GameProto;
import ru.m.tankz.proto.core.PlayerProto;
import ru.m.tankz.proto.core.UserProto;
import ru.m.tankz.server.control.ServerControlFactory;
class ServerGame extends GameRunner {
@@ -15,4 +18,22 @@ class ServerGame extends GameRunner {
this.controlFactory = new ServerControlFactory();
this.proto = proto;
}
public function joinUser(user:UserProto):Void {
var index = proto.players.length;
var teamId = "human"; // ToDo:
proto.players.push(new PlayerProto().setUser(user).setTeam(teamId).setIndex(index));
}
public function leaveUser(user:UserProto):Void {
proto.setPlayers(proto.players.filter(function(player) return player.user.uuid != user.uuid));
}
override public function start():Void {
state.controls = proto.players.map(function(player):PlayerControl return {
playerId: [player.team, player.index],
control: 'human-0'
});
super.start();
}
}