[common] update Game with GameEvent

This commit is contained in:
2019-04-26 17:28:36 +03:00
parent e9de677ceb
commit 363a48bb1b
13 changed files with 230 additions and 219 deletions

View File

@@ -7,7 +7,8 @@ const dateformat = require('dateformat');
// ToDo: update default in gulp-haxetool // ToDo: update default in gulp-haxetool
FlashPlayer.VERSION = '31'; FlashPlayer.VERSION = '32';
//Haxe.VERSION = '4.0.0-rc.2';
if (Config.SdkDir) { if (Config.SdkDir) {
Sdk.dir = Config.SdkDir; Sdk.dir = Config.SdkDir;
} }

View File

@@ -10,12 +10,12 @@ import promhx.Promise;
import ru.m.animate.Animate; import ru.m.animate.Animate;
import ru.m.animate.OnceAnimate; import ru.m.animate.OnceAnimate;
import ru.m.geom.Point; import ru.m.geom.Point;
import ru.m.tankz.core.EntityType;
import ru.m.tankz.engine.Engine; import ru.m.tankz.engine.Engine;
import ru.m.tankz.game.Game.GameListener;
import ru.m.tankz.game.GameEvent;
import ru.m.tankz.render.RenderItem; import ru.m.tankz.render.RenderItem;
import ru.m.tankz.Type;
class Render extends SpriteView implements EngineListener { class Render extends SpriteView implements GameListener {
private var backgroundLayer:Sprite; private var backgroundLayer:Sprite;
private var groundLayer:Sprite; private var groundLayer:Sprite;
@@ -99,69 +99,58 @@ class Render extends SpriteView implements EngineListener {
clearLayer(upperLayer); clearLayer(upperLayer);
} }
public function onSpawn(entity:EntityType):Void { public function onGameEvent(event:GameEvent):Void {
switch entity { switch event {
case TANK(tank): case SPAWN(TANK(tank)):
var item = new TankItem(tank); var item = new TankItem(tank);
items.set(tank.key, item); items.set(tank.key, item);
entryLayer.addChild(item.view); entryLayer.addChild(item.view);
item.update(); item.update();
playAnimate(tank.rect.center, AnimateBundle.tankSpawn()); playAnimate(tank.rect.center, AnimateBundle.tankSpawn());
case BULLET(bullet): case SPAWN(BULLET(bullet)):
var item = new BulletItem(bullet); var item = new BulletItem(bullet);
items.set(bullet.key, item); items.set(bullet.key, item);
entryLayer.addChild(item.view); entryLayer.addChild(item.view);
item.update(); item.update();
case EAGLE(eagle): case SPAWN(EAGLE(eagle)):
var item = new EagleItem(eagle); var item = new EagleItem(eagle);
items.set(eagle.key, item); items.set(eagle.key, item);
entryLayer.addChild(item.view); entryLayer.addChild(item.view);
item.update(); item.update();
case BONUS(bonus): case SPAWN(BONUS(bonus)):
var item = new BonusItem(bonus); var item = new BonusItem(bonus);
items.set(bonus.key, item); items.set(bonus.key, item);
upperLayer.addChild(item.view); upperLayer.addChild(item.view);
item.update(); item.update();
case _: case DESTROY(TANK(tank, who, wherewith, score)):
}
}
public function onCollision(entity:EntityType, with:EntityType):Void {
switch [entity, with] {
case [BULLET(_), EAGLE(eagle)]:
if (eagle.death) {
playAnimate(eagle.rect.center, AnimateBundle.tankBoom());
}
case _:
}
}
public function onDestroy(entity:EntityType):Void {
switch entity {
case TANK(tank):
if (items.exists(tank.key)) { if (items.exists(tank.key)) {
entryLayer.removeChild(items.get(tank.key).view); entryLayer.removeChild(items.get(tank.key).view);
items.remove(tank.key); items.remove(tank.key);
playAnimate(tank.rect.center, AnimateBundle.tankBoom()); playAnimate(tank.rect.center, AnimateBundle.tankBoom());
if (tank.config.score > 0) { if (score != 0) {
showScore(tank.rect.center, tank.config.score); showScore(tank.rect.center, score);
} }
} }
case BULLET(bullet): case DESTROY(BULLET(bullet)):
if (items.exists(bullet.key)) { if (items.exists(bullet.key)) {
entryLayer.removeChild(items.get(bullet.key).view); entryLayer.removeChild(items.get(bullet.key).view);
items.remove(bullet.key); items.remove(bullet.key);
var point = bullet.rect.center.add(new Point(bullet.rect.width * bullet.rect.direction.x, bullet.rect.height * bullet.rect.direction.y)); var point = bullet.rect.center.add(new Point(bullet.rect.width * bullet.rect.direction.x, bullet.rect.height * bullet.rect.direction.y));
playAnimate(point, AnimateBundle.bulletBoom()); playAnimate(point, AnimateBundle.bulletBoom());
} }
case BONUS(bonus): case DESTROY(BONUS(bonus, who, score)):
if (items.exists(bonus.key)) { if (items.exists(bonus.key)) {
upperLayer.removeChild(items.get(bonus.key).view); upperLayer.removeChild(items.get(bonus.key).view);
items.remove(bonus.key); items.remove(bonus.key);
if (bonus.config.score > 0) { if (score != 0) {
showScore(bonus.rect.center, bonus.config.score); showScore(bonus.rect.center, score);
} }
} }
case DESTROY(EAGLE(eagle, who, wherewith, score)):
playAnimate(eagle.rect.center, AnimateBundle.tankBoom());
if (score != 0) {
showScore(eagle.rect.center, score);
}
case _: case _:
} }
} }
@@ -176,7 +165,6 @@ class Render extends SpriteView implements EngineListener {
upperLayer.removeChild(animate); upperLayer.removeChild(animate);
} }
animate.dispose(); animate.dispose();
return null;
}); });
} }

View File

@@ -5,10 +5,8 @@ import flash.media.Sound;
import flash.media.SoundChannel; import flash.media.SoundChannel;
import flash.media.SoundTransform; import flash.media.SoundTransform;
import openfl.utils.Assets; import openfl.utils.Assets;
import ru.m.tankz.control.HumanControl;
import ru.m.tankz.game.Game; import ru.m.tankz.game.Game;
import ru.m.tankz.game.GameEvent; import ru.m.tankz.game.GameEvent;
import ru.m.tankz.game.GameState;
class SoundManager implements GameListener { class SoundManager implements GameListener {
private static var TAG(default, never):String = 'SoundManager'; private static var TAG(default, never):String = 'SoundManager';
@@ -76,44 +74,33 @@ class SoundManager implements GameListener {
channels.remove(event.currentTarget); channels.remove(event.currentTarget);
} }
public function onGameStart(state:GameState):Void {
play('start');
}
public function onGameChange(state:GameState):Void {
}
public function onGameComplete(state:GameState):Void {
}
public function onGameEvent(event:GameEvent):Void { public function onGameEvent(event:GameEvent):Void {
// ToDo: switch event {
/*switch event { case START(state):
case SPAWN_BULLET(player): play('start');
// ToDo: case SPAWN(BULLET(bullet)):
if (Std.is(player.control, HumanControl)) { if (false /* ToDo: human tank */) {
play('shot'); play('shot');
} }
case HIT_TANK(player, target): case SPAWN(BONUS(bonus)):
play('bonus_add');
case HIT(TANK(tank, who, wherewith)):
play('bullet_hit'); play('bullet_hit');
case DESTROY_TANK(player, target): case DESTROY(TANK(tank, who, wherewith, score)):
// ToDo: if (true /* ToDo: human tank */) {
if (Std.is(target.control, HumanControl)) {
play('boom_player'); play('boom_player');
} else { } else {
play('boom_bot'); play('boom_bot');
} }
case DESTROY_EAGLE(player, eagleTeamId): case DESTROY(EAGLE(eagle, who, wherewith, score)):
play('boom_player'); play('boom_player');
case SPAWN_BONUS(bonus): case DESTROY(BONUS(bonus, who, score)):
play('bonus');
case TAKE_BONUS(player, bonus):
if (bonus.type == 'life') { if (bonus.type == 'life') {
play('live'); play('live');
} else { } else {
play('bonus_get'); play('bonus_get');
} }
case _: case _:
}*/ }
} }
} }

View File

@@ -1,8 +1,8 @@
package ru.m.tankz.view.classic; package ru.m.tankz.view.classic;
import ru.m.tankz.game.GameEvent;
import haxework.view.LabelView; import haxework.view.LabelView;
import haxework.view.VGroupView; import haxework.view.VGroupView;
import ru.m.tankz.game.GameEvent;
import ru.m.tankz.game.GameState; import ru.m.tankz.game.GameState;
import ru.m.tankz.preset.ClassicGame; import ru.m.tankz.preset.ClassicGame;
import ru.m.tankz.Type.PlayerId; import ru.m.tankz.Type.PlayerId;
@@ -19,15 +19,12 @@ import ru.m.tankz.view.common.LifeView;
private var player1Id:PlayerId = new PlayerId(ClassicGame.HUMAN, 0); private var player1Id:PlayerId = new PlayerId(ClassicGame.HUMAN, 0);
private var player2Id:PlayerId = new PlayerId(ClassicGame.HUMAN, 1); private var player2Id:PlayerId = new PlayerId(ClassicGame.HUMAN, 1);
public function onGameStart(state:GameState):Void { public function refresh(state:GameState):Void {
level.text = 'Level ${state.levelId}'; level.text = 'Level ${state.levelId}';
}
public function onGameChange(state:GameState):Void {
bot.life = state.getTeamLife(ClassicGame.BOT); bot.life = state.getTeamLife(ClassicGame.BOT);
player1.life = state.getPlayerLife(player1Id); player1.life = state.getPlayerLife(player1Id);
player1.score = state.getPlayerScore(player1Id); player1.score = state.getPlayerScore(player1Id);
if (true) { if (state.getPlayerLife(player2Id) > 0) {
player2.visible = true; player2.visible = true;
player2.life = state.getPlayerLife(player2Id); player2.life = state.getPlayerLife(player2Id);
player2.score = state.getPlayerScore(player2Id); player2.score = state.getPlayerScore(player2Id);
@@ -36,11 +33,27 @@ import ru.m.tankz.view.common.LifeView;
} }
} }
public function onGameComplete(state:GameState):Void {
}
public function onGameEvent(event:GameEvent):Void { public function onGameEvent(event:GameEvent):Void {
switch event {
case START(state):
refresh(state);
case CHANGE(TEAM_LIFE(team, life)):
if (team.id == ClassicGame.BOT) {
bot.life = life;
}
case CHANGE(PLAYER_LIFE(player, life)):
if (player.id == player1Id) {
player1.life = life;
} else if (player.id == player2Id) {
player2.life = life;
}
case CHANGE(PLAYER_SCORE(player, score)):
if (player.id == player1Id) {
player1.score = score;
} else if (player.id == player2Id) {
player2.score = score;
}
case _:
}
} }
} }

View File

@@ -45,7 +45,7 @@ class GameFrame extends GroupView implements GameListener {
private function start(state:GameState):Void { private function start(state:GameState):Void {
game = new Game(state.type); game = new Game(state.type);
game.engine.connect(render); game.connect(render);
game.connect(soundManager); game.connect(soundManager);
game.connect(this); game.connect(this);
if (panel != null) { if (panel != null) {
@@ -71,26 +71,23 @@ class GameFrame extends GroupView implements GameListener {
render.reset(); render.reset();
} }
public function onGameStart(state:GameState):Void {}
public function onGameChange(state:GameState):Void {}
public function onGameComplete(state:GameState):Void {
result = state;
this.state = switch game.next() {
case Some(s):
// ToDo:
var progress = storage.get(game.type);
progress.completeLevel(result.levelId, result.presetId);
storage.set(progress);
s;
case None: null;
}
stop();
switcher.change(ResultFrame.ID);
}
public function onGameEvent(event:GameEvent):Void { public function onGameEvent(event:GameEvent):Void {
switch event {
case GameEvent.COMPLETE(state, winner):
result = state;
this.state = switch game.next() {
case Some(s):
// ToDo:
var progress = storage.get(game.type);
progress.completeLevel(result.levelId, result.presetId);
storage.set(progress);
s;
case None: null;
}
stop();
switcher.change(ResultFrame.ID);
case _:
}
} }
public function onHide():Void { public function onHide():Void {

View File

@@ -4,7 +4,6 @@ import haxework.view.HGroupView;
import haxework.view.ImageView; import haxework.view.ImageView;
import haxework.view.LabelView; import haxework.view.LabelView;
import openfl.Assets; import openfl.Assets;
import ru.m.tankz.game.GameState.PlayerState;
import ru.m.tankz.game.GameState; import ru.m.tankz.game.GameState;
@:template class LifeView extends HGroupView { @:template class LifeView extends HGroupView {
@@ -51,7 +50,7 @@ import ru.m.tankz.game.GameState;
override public function update():Void { override public function update():Void {
super.update(); super.update();
if (state != null) { if (state != null && currentState != null) {
var tankConfig = currentState.config.getTank(state.tank); var tankConfig = currentState.config.getTank(state.tank);
tank = tankConfig == null ? 'ba' : tankConfig.skin; tank = tankConfig == null ? 'ba' : tankConfig.skin;
color = currentState.config.getColor(state.id); color = currentState.config.getColor(state.id);

View File

@@ -4,7 +4,6 @@ import haxework.view.DataView;
import haxework.view.LabelView; import haxework.view.LabelView;
import haxework.view.VGroupView; import haxework.view.VGroupView;
import ru.m.tankz.game.GameEvent; import ru.m.tankz.game.GameEvent;
import ru.m.tankz.game.GameState.PlayerState;
import ru.m.tankz.game.GameState; import ru.m.tankz.game.GameState;
import ru.m.tankz.view.common.IGamePanel; import ru.m.tankz.view.common.IGamePanel;
import ru.m.tankz.view.common.LifeView; import ru.m.tankz.view.common.LifeView;
@@ -14,22 +13,15 @@ import ru.m.tankz.view.common.LifeView;
@:view var level:LabelView; @:view var level:LabelView;
@:view var players:DataView<PlayerState, LifeView>; @:view var players:DataView<PlayerState, LifeView>;
public function onGameStart(state:GameState):Void { public function onGameEvent(event:GameEvent):Void {
level.text = 'Level ${state.levelId}'; switch event {
players.data = Lambda.array(state.players); case START(state):
} level.text = 'Level ${state.levelId}';
players.data = Lambda.array(state.players);
public function onGameChange(state:GameState):Void { case _:
for (view in players.views) { for (view in players.views) {
view.toUpdate(); view.toUpdate();
}
} }
} }
public function onGameComplete(state:GameState):Void {
}
public function onGameEvent(event:GameEvent):Void {
}
} }

View File

@@ -5,6 +5,7 @@ import haxework.view.LabelView;
import ru.m.tankz.game.GameEvent; import ru.m.tankz.game.GameEvent;
import ru.m.tankz.game.GameState; import ru.m.tankz.game.GameState;
import ru.m.tankz.preset.DotaGame; import ru.m.tankz.preset.DotaGame;
import ru.m.tankz.Type.TeamId;
import ru.m.tankz.view.common.IGamePanel; import ru.m.tankz.view.common.IGamePanel;
import ru.m.tankz.view.common.LifeView; import ru.m.tankz.view.common.LifeView;
@@ -14,22 +15,31 @@ import ru.m.tankz.view.common.LifeView;
@:view var dire:LifeView; @:view var dire:LifeView;
@:view var level:LabelView; @:view var level:LabelView;
public function onGameStart(state:GameState):Void { public function refresh(state:GameState):Void {
level.text = 'Level ${state.levelId}'; level.text = 'Level ${state.levelId}';
}
public function onGameChange(state:GameState):Void {
radiant.life = state.getTeamLife(DotaGame.RADIANT); radiant.life = state.getTeamLife(DotaGame.RADIANT);
radiant.score = state.getTeamScore(DotaGame.RADIANT); radiant.score = state.getTeamScore(DotaGame.RADIANT);
dire.life = state.getTeamLife(DotaGame.DIRE); dire.life = state.getTeamLife(DotaGame.DIRE);
dire.score = state.getTeamScore(DotaGame.DIRE); dire.score = state.getTeamScore(DotaGame.DIRE);
} }
public function onGameComplete(state:GameState):Void { private inline function getLifeView(teamId:TeamId):LifeView {
return switch teamId {
case DotaGame.RADIANT: radiant;
case DotaGame.DIRE: dire;
case _: null;
}
} }
public function onGameEvent(event:GameEvent):Void { public function onGameEvent(event:GameEvent):Void {
switch event {
case START(state):
refresh(state);
case CHANGE(TEAM_LIFE(team, life)):
getLifeView(team.id).life = life;
case CHANGE(TEAM_SCORE(team, score)):
getLifeView(team.id).score = score;
case _:
}
} }
} }

View File

@@ -12,9 +12,7 @@ import ru.m.tankz.map.Grid;
import ru.m.tankz.map.LevelMap; import ru.m.tankz.map.LevelMap;
interface EngineListener { interface EngineListener {
public function onSpawn(entity:EntityType):Void;
public function onCollision(entity:EntityType, with:EntityType):Void; public function onCollision(entity:EntityType, with:EntityType):Void;
public function onDestroy(entity:EntityType):Void;
} }
@:yield @:dispatcher(EngineListener) class Engine { @:yield @:dispatcher(EngineListener) class Engine {
@@ -35,14 +33,10 @@ interface EngineListener {
public function spawn(entity:Entity):Void { public function spawn(entity:Entity):Void {
entities.set(entity.id, entity); entities.set(entity.id, entity);
var type = EntityTypeResolver.of(entity);
spawnSignal.emit(type);
} }
public function destroy(entity:Entity):Void { public function destroy(entity:Entity):Void {
if (entities.exists(entity.id)) { if (entities.exists(entity.id)) {
var type = EntityTypeResolver.of(entity);
destroySignal.emit(type);
entities.remove(entity.id); entities.remove(entity.id);
} }
} }

View File

@@ -1,5 +1,6 @@
package ru.m.tankz.game; package ru.m.tankz.game;
import ru.m.tankz.game.GameEvent.ChangeEvent;
import haxe.ds.Option; import haxe.ds.Option;
import haxe.Timer; import haxe.Timer;
import ru.m.geom.Point; import ru.m.geom.Point;
@@ -19,13 +20,10 @@ import ru.m.tankz.game.Spawner;
import ru.m.tankz.Type; import ru.m.tankz.Type;
interface GameListener { interface GameListener {
public function onGameStart(state:GameState):Void;
public function onGameChange(state:GameState):Void;
public function onGameComplete(state:GameState):Void;
public function onGameEvent(event:GameEvent):Void; public function onGameEvent(event:GameEvent):Void;
} }
@:dispatcher(GameListener) class Game implements IGame implements EngineListener { @:dispatcher(GameListener) class Game implements IGame implements EngineListener implements GameListener {
private static var TAG(default, never):String = "Game"; private static var TAG(default, never):String = "Game";
@@ -47,6 +45,7 @@ interface GameListener {
this.config = configBundle.get(type); this.config = configBundle.get(type);
this.engine = new Engine(config); this.engine = new Engine(config);
engine.connect(this); engine.connect(this);
connect(this);
} }
public function action(tankId:Int, action:TankAction):Void { public function action(tankId:Int, action:TankAction):Void {
@@ -60,16 +59,16 @@ interface GameListener {
case SHOT: case SHOT:
var bullet = tank.shot(); var bullet = tank.shot();
if (bullet != null) { if (bullet != null) {
engine.spawn(bullet); gameEventSignal.emit(GameEvent.SPAWN(BULLET(bullet)));
} }
} }
} }
public function getTeam(teamId:TeamId):Team { public inline function getTeam(teamId:TeamId):Team {
return teams[teamId]; return teams[teamId];
} }
public function getPlayer(playerId:PlayerId):Player { public inline function getPlayer(playerId:PlayerId):Player {
return teams[playerId.team].players[playerId.index]; return teams[playerId.team].players[playerId.index];
} }
@@ -132,11 +131,10 @@ interface GameListener {
eagle.color = config.getColor(new PlayerId(eagle.team, -1)); eagle.color = config.getColor(new PlayerId(eagle.team, -1));
team.eagleId = eagle.id; team.eagleId = eagle.id;
applyPoint(eagle, eaglePoint); applyPoint(eagle, eaglePoint);
engine.spawn(eagle); gameEventSignal.emit(GameEvent.SPAWN(EAGLE(eagle)));
} }
} }
gameStartSignal.emit(state); gameEventSignal.emit(GameEvent.START(state));
gameChangeSignal.emit(state);
} }
private function spawn(task:SpawnTask):Void { private function spawn(task:SpawnTask):Void {
@@ -147,11 +145,10 @@ interface GameListener {
var tank = buildTank(task); var tank = buildTank(task);
player.tankId = tank.id; player.tankId = tank.id;
player.state.tank = tank.config.type; player.state.tank = tank.config.type;
engine.spawn(tank); gameEventSignal.emit(GameEvent.SPAWN(TANK(tank)));
gameChangeSignal.emit(state);
} }
private function checkComplete() { private function checkComplete():Void {
var actives:Array<TeamId> = []; var actives:Array<TeamId> = [];
for (team in teams.iterator()) { for (team in teams.iterator()) {
if (team.isAlive) { if (team.isAlive) {
@@ -180,22 +177,10 @@ interface GameListener {
} }
} }
Timer.delay(function() { Timer.delay(function() {
//gameChangeSignal.emit(state); gameEventSignal.emit(GameEvent.COMPLETE(state, getTeam(winner)));
gameCompleteSignal.emit(state);
}, 5000); }, 5000);
} }
public function onSpawn(entity:EntityType):Void {
switch entity {
case TANK(tank):
getPlayer(tank.playerId).control.start();
case BULLET(bullet):
getPlayer(bullet.playerId).state.shots++;
gameEventSignal.emit(GameEvent.SPAWN(BULLET(bullet)));
case _:
}
}
public function onCollision(entity:EntityType, with:EntityType):Void { public function onCollision(entity:EntityType, with:EntityType):Void {
switch entity { switch entity {
case EntityType.TANK(tank): case EntityType.TANK(tank):
@@ -209,14 +194,12 @@ interface GameListener {
case [TANK(tank), EAGLE(eagle)]: case [TANK(tank), EAGLE(eagle)]:
tank.rect.lean(eagle.rect); tank.rect.lean(eagle.rect);
case [BULLET(bullet), BULLET(other_bullet)]: case [BULLET(bullet), BULLET(other_bullet)]:
engine.destroy(bullet); gameEventSignal.emit(GameEvent.DESTROY(BULLET(bullet)));
engine.destroy(other_bullet); gameEventSignal.emit(GameEvent.DESTROY(BULLET(other_bullet)));
case [BULLET(bullet), CELL(cell)]: case [BULLET(bullet), CELL(cell)]:
engine.destroy(bullet);
gameEventSignal.emit(GameEvent.HIT(CELL(cell, bullet.tank, bullet))); gameEventSignal.emit(GameEvent.HIT(CELL(cell, bullet.tank, bullet)));
gameEventSignal.emit(GameEvent.DESTROY(BULLET(bullet)));
case [TANK(tank), BONUS(bonus)]: case [TANK(tank), BONUS(bonus)]:
applyBonus(tank, bonus);
engine.destroy(bonus);
gameEventSignal.emit(GameEvent.DESTROY(BONUS(bonus, tank, bonus.config.score))); gameEventSignal.emit(GameEvent.DESTROY(BONUS(bonus, tank, bonus.config.score)));
case [BULLET(bullet), TANK(tank)]/* | [TANK(tank), BULLET(bullet)]*/: case [BULLET(bullet), TANK(tank)]/* | [TANK(tank), BULLET(bullet)]*/:
if (bullet.tankId == tank.id || (!engine.config.game.friendlyFire && tank.playerId.team == bullet.playerId.team)) { if (bullet.tankId == tank.id || (!engine.config.game.friendlyFire && tank.playerId.team == bullet.playerId.team)) {
@@ -234,54 +217,20 @@ interface GameListener {
tank.config = engine.config.getTank(tank.config.downgrade); tank.config = engine.config.getTank(tank.config.downgrade);
gameEventSignal.emit(GameEvent.HIT(TANK(tank, bullet.tank, bullet))); gameEventSignal.emit(GameEvent.HIT(TANK(tank, bullet.tank, bullet)));
} else { } else {
engine.destroy(tank); var score = tank.config.score;
gameEventSignal.emit(GameEvent.DESTROY(TANK(tank, bullet.tank, bullet, tank.config.score))); if (tank.playerId.team == bullet.playerId.team) {
score = Math.round(score * -0.5);
}
gameEventSignal.emit(GameEvent.DESTROY(TANK(tank, bullet.tank, bullet, score)));
} }
} }
engine.destroy(bullet); gameEventSignal.emit(GameEvent.DESTROY(BULLET(bullet)));
} }
case [BULLET(bullet), EAGLE(eagle)]: case [BULLET(bullet), EAGLE(eagle)]:
engine.destroy(bullet);
if (!eagle.protect.active) { if (!eagle.protect.active) {
eagle.death = true; gameEventSignal.emit(GameEvent.DESTROY(EAGLE(eagle, bullet.tank, bullet, eagle.score)));
if (bullet.playerId.team != eagle.team) {
getPlayer(bullet.playerId).state.score += eagle.score;
}
checkComplete();
gameChangeSignal.emit(state);
gameEventSignal.emit(GameEvent.DESTROY(EAGLE(eagle, bullet.tank, bullet, eagle.config.score)));
} }
case _: gameEventSignal.emit(GameEvent.DESTROY(BULLET(bullet)));
}
}
public function onDestroy(entity:EntityType):Void {
switch (entity) {
case BULLET(bullet):
var tank:Tank = bullet.tank;
if (tank != null) tank.onDestroyBullet();
case TANK(tank):
var team = getTeam(tank.playerId.team);
var player = getPlayer(tank.playerId);
player.control.stop();
player.tankId = 0; //ToDo: ?
team.onDestroy(player.id);
var respawn:Bool = team.tryRespawn(player.id);
if (respawn) {
team.spawner.push(player.id);
}
if (!team.isAlive) {
checkComplete();
}
if (tank.bonus) {
spawnBonus();
}
// ToDo:
/*if (playerId != null) {
getPlayer(playerId).state.frags++;
getPlayer(playerId).state.score += tank.config.score * (tank.playerId.team == playerId.team ? 0 : 1);
}*/
gameChangeSignal.emit(state);
case _: case _:
} }
} }
@@ -308,9 +257,6 @@ interface GameListener {
public function dispose():Void { public function dispose():Void {
engine.dispose(); engine.dispose();
gameStartSignal.dispose();
gameChangeSignal.dispose();
gameCompleteSignal.dispose();
gameEventSignal.dispose(); gameEventSignal.dispose();
} }
@@ -319,23 +265,22 @@ interface GameListener {
var bonus = new Bonus(bonusConfig); var bonus = new Bonus(bonusConfig);
bonus.rect.x = Math.round(Math.random() * engine.map.width / engine.map.cellWidth) * engine.map.cellWidth; bonus.rect.x = Math.round(Math.random() * engine.map.width / engine.map.cellWidth) * engine.map.cellWidth;
bonus.rect.y = Math.round(Math.random() * engine.map.height/ engine.map.cellHeight) * engine.map.cellHeight; bonus.rect.y = Math.round(Math.random() * engine.map.height/ engine.map.cellHeight) * engine.map.cellHeight;
engine.spawn(bonus);
gameEventSignal.emit(GameEvent.SPAWN(BONUS(bonus))); gameEventSignal.emit(GameEvent.SPAWN(BONUS(bonus)));
} }
inline private function alienTank(team:TeamId):Tank->Bool { private inline function alienTank(team:TeamId):Tank->Bool {
return function(tank:Tank):Bool return team != tank.playerId.team; return function(tank:Tank):Bool return team != tank.playerId.team;
} }
private function applyBonus(tank:Tank, bonus:Bonus):Void { private function applyBonus(tank:Tank, bonus:Bonus):Void {
switch (bonus.config.type) { switch (bonus.config.type) {
case "life": case "life":
getPlayer(tank.playerId).state.life++; changeLife(tank.playerId, 1);
case "star": case "star":
upgradeTank(tank); upgradeTank(tank);
case "grenade": case "grenade":
for (t in engine.iterTanks(alienTank(tank.playerId.team))) { for (t in engine.iterTanks(alienTank(tank.playerId.team))) {
engine.destroy(t); gameEventSignal.emit(GameEvent.DESTROY(TANK(t, tank, null, 0)));
} }
case "helmet": case "helmet":
tank.protect.on(bonus.config.duration); tank.protect.on(bonus.config.duration);
@@ -353,15 +298,11 @@ interface GameListener {
case "gun": case "gun":
upgradeTank(tank, 5); upgradeTank(tank, 5);
case _: case _:
engine.destroy(tank); // :-D gameEventSignal.emit(GameEvent.DESTROY(TANK(tank, null, null, 0))); // :-D
} }
if (bonus.config.score > 0) {
getPlayer(tank.playerId).state.score += bonus.config.score;
}
gameChangeSignal.emit(state);
} }
public function upgradeTank(tank:Tank, level:Int = 1):Void { private function upgradeTank(tank:Tank, level:Int = 1):Void {
if (tank.config.upgrade != null) { if (tank.config.upgrade != null) {
while (level-- > 0 && tank.config.upgrade != null) { while (level-- > 0 && tank.config.upgrade != null) {
tank.config = config.getTank(tank.config.upgrade); tank.config = config.getTank(tank.config.upgrade);
@@ -371,7 +312,83 @@ interface GameListener {
} }
} }
public function hitTank(tank:Tank):Void { private function changeScore(playerId:PlayerId, score:Int):Void {
var player = getPlayer(playerId);
var team = getTeam(playerId.team);
player.state.score += score;
gameEventSignal.emit(GameEvent.CHANGE(PLAYER_SCORE(player, player.state.score)));
gameEventSignal.emit(GameEvent.CHANGE(TEAM_SCORE(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(player, 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(team, team.state.life)));
}
public function onGameEvent(event:GameEvent):Void {
switch event {
case GameEvent.SPAWN(EAGLE(eagle)):
engine.spawn(eagle);
case GameEvent.SPAWN(TANK(tank)):
engine.spawn(tank);
getPlayer(tank.playerId).control.start();
case GameEvent.SPAWN(BULLET(bullet)):
engine.spawn(bullet);
case GameEvent.SPAWN(BONUS(bonus)):
engine.spawn(bonus);
case GameEvent.DESTROY(EAGLE(eagle, who, wherewith, score)):
eagle.death = true;
if (score != 0) {
changeScore(who.playerId, score);
}
checkComplete();
case GameEvent.DESTROY(TANK(tank, who, wherewith, score)):
engine.destroy(tank);
var team = getTeam(tank.playerId.team);
var player = getPlayer(tank.playerId);
player.control.stop();
player.tankId = 0; //ToDo: ?
team.onDestroy(player.id);
if (player.state.life > 0) {
changeLife(player.id, -1);
} else if (team.state.life > 0) {
changeTeamLife(team.id, -1);
}
var respawn:Bool = team.tryRespawn(player.id);
if (respawn) {
team.spawner.push(player.id);
}
if (!team.isAlive) {
checkComplete();
}
if (tank.bonus && wherewith != null) {
spawnBonus();
}
if (score != 0) {
changeScore(who.playerId, score);
}
case GameEvent.DESTROY(CELL(cell, who, wherewith)):
case GameEvent.DESTROY(BONUS(bonus, who, score)):
engine.destroy(bonus);
applyBonus(who, bonus);
if (score != 0) {
changeScore(who.playerId, score);
}
case GameEvent.DESTROY(BULLET(bullet)):
engine.destroy(bullet);
var tank:Tank = bullet.tank;
if (tank != null) {
tank.onDestroyBullet();
}
case _:
}
} }
} }

View File

@@ -23,17 +23,21 @@ enum DestroyEvent {
TANK(tank:Tank, who:Tank, wherewith:Bullet, score:Int); TANK(tank:Tank, who:Tank, wherewith:Bullet, score:Int);
CELL(cell:GridCell, who:Tank, wherewith:Bullet); CELL(cell:GridCell, who:Tank, wherewith:Bullet);
BONUS(bonus:Bonus, who:Tank, score:Int); BONUS(bonus:Bonus, who:Tank, score:Int);
BULLET(bullet:Bullet);
} }
enum ChangeEvent { enum ChangeEvent {
SCORE(player:Player, value:Int); PLAYER_SCORE(player:Player, value:Int);
PLAYER_LIFE(player:Player, value:Int); PLAYER_LIFE(player:Player, value:Int);
TEAM_SCORE(team:Team, value:Int);
TEAM_LIFE(team:Team, value:Int); TEAM_LIFE(team:Team, value:Int);
} }
enum GameEvent { enum GameEvent {
START(state:GameState);
SPAWN(event:SpawnEvent); SPAWN(event:SpawnEvent);
HIT(event:HitEvent); HIT(event:HitEvent);
DESTROY(event:DestroyEvent); DESTROY(event:DestroyEvent);
CHANGE(event:ChangeEvent); CHANGE(event:ChangeEvent);
COMPLETE(state:GameState, winner:Team);
} }

View File

@@ -1,9 +1,24 @@
package ru.m.tankz.game; package ru.m.tankz.game;
import haxework.signal.Signal;
import ru.m.tankz.control.Control;
import ru.m.tankz.engine.Engine; import ru.m.tankz.engine.Engine;
import ru.m.tankz.control.Control.TankAction; import ru.m.tankz.game.Game;
import ru.m.tankz.Type;
interface IGame { interface IGame {
public var engine(default, null):Engine; public var engine(default, null):Engine;
public var gameEventSignal(default, null):Signal<GameEvent>;
public function connect(listener:GameListener):Void;
public function disconnect(listener:GameListener):Void;
public function start(state:GameState):Void;
public function action(tankId:Int, action:TankAction):Void; public function action(tankId:Int, action:TankAction):Void;
public function getTeam(teamId:TeamId):Team;
public function getPlayer(playerId:PlayerId):Player;
} }

View File

@@ -37,14 +37,8 @@ class Team {
return result; return result;
} }
public function onDestroy(playerId:PlayerId) { public function onDestroy(playerId:PlayerId):Void {
active--; active--;
var player:Player = players[playerId.index];
if (player.state.life > 0) {
player.state.life--;
} else {
state.life--;
}
} }
// ToDo: eagle state? // ToDo: eagle state?