[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

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

View File

@@ -1,5 +1,6 @@
package ru.m.tankz.game;
import ru.m.tankz.game.GameEvent.ChangeEvent;
import haxe.ds.Option;
import haxe.Timer;
import ru.m.geom.Point;
@@ -19,13 +20,10 @@ import ru.m.tankz.game.Spawner;
import ru.m.tankz.Type;
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;
}
@: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";
@@ -47,6 +45,7 @@ interface GameListener {
this.config = configBundle.get(type);
this.engine = new Engine(config);
engine.connect(this);
connect(this);
}
public function action(tankId:Int, action:TankAction):Void {
@@ -60,16 +59,16 @@ interface GameListener {
case SHOT:
var bullet = tank.shot();
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];
}
public function getPlayer(playerId:PlayerId):Player {
public inline function getPlayer(playerId:PlayerId):Player {
return teams[playerId.team].players[playerId.index];
}
@@ -132,11 +131,10 @@ interface GameListener {
eagle.color = config.getColor(new PlayerId(eagle.team, -1));
team.eagleId = eagle.id;
applyPoint(eagle, eaglePoint);
engine.spawn(eagle);
gameEventSignal.emit(GameEvent.SPAWN(EAGLE(eagle)));
}
}
gameStartSignal.emit(state);
gameChangeSignal.emit(state);
gameEventSignal.emit(GameEvent.START(state));
}
private function spawn(task:SpawnTask):Void {
@@ -147,11 +145,10 @@ interface GameListener {
var tank = buildTank(task);
player.tankId = tank.id;
player.state.tank = tank.config.type;
engine.spawn(tank);
gameChangeSignal.emit(state);
gameEventSignal.emit(GameEvent.SPAWN(TANK(tank)));
}
private function checkComplete() {
private function checkComplete():Void {
var actives:Array<TeamId> = [];
for (team in teams.iterator()) {
if (team.isAlive) {
@@ -180,22 +177,10 @@ interface GameListener {
}
}
Timer.delay(function() {
//gameChangeSignal.emit(state);
gameCompleteSignal.emit(state);
gameEventSignal.emit(GameEvent.COMPLETE(state, getTeam(winner)));
}, 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 {
switch entity {
case EntityType.TANK(tank):
@@ -209,14 +194,12 @@ interface GameListener {
case [TANK(tank), EAGLE(eagle)]:
tank.rect.lean(eagle.rect);
case [BULLET(bullet), BULLET(other_bullet)]:
engine.destroy(bullet);
engine.destroy(other_bullet);
gameEventSignal.emit(GameEvent.DESTROY(BULLET(bullet)));
gameEventSignal.emit(GameEvent.DESTROY(BULLET(other_bullet)));
case [BULLET(bullet), CELL(cell)]:
engine.destroy(bullet);
gameEventSignal.emit(GameEvent.HIT(CELL(cell, bullet.tank, bullet)));
gameEventSignal.emit(GameEvent.DESTROY(BULLET(bullet)));
case [TANK(tank), BONUS(bonus)]:
applyBonus(tank, bonus);
engine.destroy(bonus);
gameEventSignal.emit(GameEvent.DESTROY(BONUS(bonus, tank, bonus.config.score)));
case [BULLET(bullet), TANK(tank)]/* | [TANK(tank), BULLET(bullet)]*/:
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);
gameEventSignal.emit(GameEvent.HIT(TANK(tank, bullet.tank, bullet)));
} else {
engine.destroy(tank);
gameEventSignal.emit(GameEvent.DESTROY(TANK(tank, bullet.tank, bullet, tank.config.score)));
var score = 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)]:
engine.destroy(bullet);
if (!eagle.protect.active) {
eagle.death = true;
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)));
gameEventSignal.emit(GameEvent.DESTROY(EAGLE(eagle, bullet.tank, bullet, eagle.score)));
}
case _:
}
}
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);
gameEventSignal.emit(GameEvent.DESTROY(BULLET(bullet)));
case _:
}
}
@@ -308,9 +257,6 @@ interface GameListener {
public function dispose():Void {
engine.dispose();
gameStartSignal.dispose();
gameChangeSignal.dispose();
gameCompleteSignal.dispose();
gameEventSignal.dispose();
}
@@ -319,23 +265,22 @@ interface GameListener {
var bonus = new Bonus(bonusConfig);
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;
engine.spawn(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;
}
private function applyBonus(tank:Tank, bonus:Bonus):Void {
switch (bonus.config.type) {
case "life":
getPlayer(tank.playerId).state.life++;
changeLife(tank.playerId, 1);
case "star":
upgradeTank(tank);
case "grenade":
for (t in engine.iterTanks(alienTank(tank.playerId.team))) {
engine.destroy(t);
gameEventSignal.emit(GameEvent.DESTROY(TANK(t, tank, null, 0)));
}
case "helmet":
tank.protect.on(bonus.config.duration);
@@ -353,15 +298,11 @@ interface GameListener {
case "gun":
upgradeTank(tank, 5);
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) {
while (level-- > 0 && tank.config.upgrade != null) {
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);
CELL(cell:GridCell, who:Tank, wherewith:Bullet);
BONUS(bonus:Bonus, who:Tank, score:Int);
BULLET(bullet:Bullet);
}
enum ChangeEvent {
SCORE(player:Player, value:Int);
PLAYER_SCORE(player:Player, value:Int);
PLAYER_LIFE(player:Player, value:Int);
TEAM_SCORE(team:Team, value:Int);
TEAM_LIFE(team:Team, value:Int);
}
enum GameEvent {
START(state:GameState);
SPAWN(event:SpawnEvent);
HIT(event:HitEvent);
DESTROY(event:DestroyEvent);
CHANGE(event:ChangeEvent);
COMPLETE(state:GameState, winner:Team);
}

View File

@@ -1,9 +1,24 @@
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.control.Control.TankAction;
import ru.m.tankz.game.Game;
import ru.m.tankz.Type;
interface IGame {
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 getTeam(teamId:TeamId):Team;
public function getPlayer(playerId:PlayerId):Player;
}

View File

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