[common] add EntityBuilder

This commit is contained in:
2019-05-06 16:21:45 +03:00
parent d11d0ac53f
commit d6b572aead
17 changed files with 205 additions and 66 deletions

View File

@@ -18,6 +18,7 @@ import ru.m.tankz.proto.pack.Response;
import ru.m.tankz.sound.SoundManager;
import ru.m.tankz.storage.GameStorage;
import ru.m.tankz.storage.MultiplayerStorage;
import ru.m.tankz.storage.RecordStorage;
import ru.m.tankz.storage.SettingsStorage;
#if flash
import flash.Lib;
@@ -33,6 +34,7 @@ class Init {
@:provide static var settingsStorage:SettingsStorage;
@:provide static var multiplayerStorage:MultiplayerStorage;
@:provide static var gameStorage:GameStorage;
@:provide static var recordStorage:RecordStorage;
@:provide static var soundManager:SoundManager;
@:provide static var networkManager:NetworkManager;
@:provide static var controlFactory:IControlFactory;
@@ -62,10 +64,15 @@ class Init {
settingsStorage = new SettingsStorage();
multiplayerStorage = new MultiplayerStorage();
gameStorage = new GameStorage();
recordStorage = new RecordStorage();
soundManager = new SoundManager();
controlFactory = new ClientControlFactory();
popupManager = new PopupManager();
for (record in recordStorage) {
L.w("RECORD", '${record.id}. ${record.date}');
}
popupManager.showAnimateFactory = function(v) return new UnFadeAnimate(v, 100);
popupManager.closeAnimateFactory = function(v) return new FadeAnimate(v, 100);

View File

@@ -1,5 +1,6 @@
package ru.m.tankz.render;
import ru.m.tankz.core.EntityType;
import flash.display.DisplayObjectContainer;
import flash.display.Graphics;
import flash.display.Sprite;
@@ -15,7 +16,7 @@ import ru.m.tankz.game.GameEvent;
import ru.m.tankz.game.IGame;
import ru.m.tankz.render.RenderItem;
class Render extends SpriteView implements GameListener {
class Render extends SpriteView implements GameListener implements EngineListener {
private var backgroundLayer:Sprite;
private var groundLayer:Sprite;
@@ -97,6 +98,23 @@ class Render extends SpriteView implements GameListener {
clearLayer(upperLayer);
}
public function onSpawn(entity:EntityType):Void {
switch entity {
case EAGLE(eagle):
var item = new EagleItem(eagle);
items.set(eagle.key, item);
entryLayer.addChild(item.view);
item.update();
case _:
}
}
public function onCollision(entity:EntityType, with:EntityType):Void {
}
public function onMove(entity:EntityType):Void {
}
public function onGameEvent(event:GameEvent):Void {
switch event {
case SPAWN(TANK(tank)):
@@ -110,11 +128,11 @@ class Render extends SpriteView implements GameListener {
items.set(bullet.key, item);
entryLayer.addChild(item.view);
item.update();
case SPAWN(EAGLE(eagle)):
/*case SPAWN(EAGLE(eagle)):
var item = new EagleItem(eagle);
items.set(eagle.key, item);
entryLayer.addChild(item.view);
item.update();
item.update();*/
case SPAWN(BONUS(bonus)):
var item = new BonusItem(bonus);
items.set(bonus.key, item);

View File

@@ -0,0 +1,28 @@
package ru.m.tankz.storage;
import haxe.DynamicAccess;
import haxework.storage.SharedObjectStorage;
import ru.m.tankz.game.record.GameRecord;
@:yield class RecordStorage extends SharedObjectStorage {
private static inline var VERSION = 1;
public function new() {
super('record_${VERSION}');
}
public function save(record:GameRecord):Void {
trace(record.id);
trace(record.date);
trace(record.events);
write(record.id, record);
}
public function iterator():Iterator<GameRecord> {
var data:DynamicAccess<String> = so.data;
for (id in data.keys()) {
@yield return read(id);
}
}
}

View File

@@ -14,6 +14,7 @@ import ru.m.tankz.network.NetworkManager;
import ru.m.tankz.render.Render;
import ru.m.tankz.sound.SoundManager;
import ru.m.tankz.storage.GameStorage;
import ru.m.tankz.storage.RecordStorage;
import ru.m.tankz.view.common.IGamePanel;
class GameFrame extends GroupView implements GameListener {
@@ -28,7 +29,8 @@ class GameFrame extends GroupView implements GameListener {
@:provide var state:GameState;
@:provide("result") var result:GameState;
@:provide var switcher:FrameSwitcher;
@:provide var storage:GameStorage;
@:provide var gameStorage:GameStorage;
@:provide var recordStorage:RecordStorage;
private var game:IGame;
private var runner:GameRunner;
@@ -49,6 +51,7 @@ class GameFrame extends GroupView implements GameListener {
private function start(state:GameState):Void {
game = new Game(state.type);
game.connect(render);
game.engine.connect(render);
game.connect(soundManager);
game.connect(this);
if (panel != null) {
@@ -79,14 +82,15 @@ class GameFrame extends GroupView implements GameListener {
public function onGameEvent(event:GameEvent):Void {
switch event {
case GameEvent.COMPLETE(state, winner):
L.w("RECORD", Std.string(recorder.data));
// ToDo:
//recordStorage.save(recorder.record);
result = state;
this.state = switch runner.next() {
case Some(s):
// ToDo:
var progress = storage.get(game.type);
var progress = gameStorage.get(game.type);
progress.completeLevel(result.levelId, result.presetId);
storage.set(progress);
gameStorage.set(progress);
s;
case None: null;
}

View File

@@ -213,4 +213,13 @@ class Config {
}
return -1;
}
public function getPoint(teamId:TeamId, type:String, index:Int = -1):SpawnPoint {
for (point in points) {
if (point.team == teamId && point.type == type && point.index == index) {
return point;
}
}
return null;
}
}

View File

@@ -1,5 +1,6 @@
package ru.m.tankz.engine;
import ru.m.geom.Direction;
import ru.m.geom.Line;
import ru.m.geom.Point;
import ru.m.tankz.config.Config;
@@ -30,11 +31,24 @@ import ru.m.tankz.map.LevelMap;
public function spawn(entity:Entity):Void {
entities.set(entity.id, entity);
spawnSignal.emit(EntityTypeResolver.of(entity));
}
public function destroy(entity:Entity):Void {
if (entities.exists(entity.id)) {
entities.remove(entity.id);
public function destroy(entityId:Int):Void {
if (entities.exists(entityId)) {
entities.remove(entityId);
}
}
public function move(entityId:Int, direction:Direction):Void {
if (entities.exists(entityId)) {
cast(entities.get(entityId), MobileEntity).move(direction);
}
}
public function stop(entityId:Int):Void {
if (entities.exists(entityId)) {
cast(entities.get(entityId), MobileEntity).stop();
}
}

View File

@@ -1,6 +1,7 @@
package ru.m.tankz.engine;
import haxework.signal.Signal;
import ru.m.geom.Direction;
import ru.m.tankz.config.Config;
import ru.m.tankz.core.Entity;
import ru.m.tankz.core.EntityType;
@@ -12,12 +13,17 @@ interface IEngine {
public var config(default, default):Config;
public var map(default, null):LevelMap;
public var spawnSignal(default, null):Signal1<EntityType>;
public var collisionSignal(default, null):Signal2<EntityType, EntityType>;
public var moveSignal(default, null):Signal1<EntityType>;
public function spawn(entity:Entity):Void;
public function destroy(entity:Entity):Void;
public function move(entityId:Int, direction:Direction):Void;
public function stop(entityId:Int):Void;
public function destroy(entityId:Int):Void;
public function update():Void;
@@ -31,6 +37,7 @@ interface IEngine {
}
interface EngineListener {
public function onSpawn(entity:EntityType):Void;
public function onCollision(entity:EntityType, with:EntityType):Void;
public function onMove(entity:EntityType):Void;
}
}

View File

@@ -0,0 +1,31 @@
package ru.m.tankz.game;
import ru.m.geom.Point;
import ru.m.tankz.config.Config;
import ru.m.tankz.core.Eagle;
import ru.m.tankz.core.Entity;
import ru.m.tankz.Type;
class EntityBuilder {
private var config:Config;
public function new(config:Config) {
this.config = config;
}
private function applyPoint(entity:Entity, point:SpawnPoint):Void {
entity.rect.center = new Point((point.x + 1) * config.map.cellWidth, (point.y + 1) * config.map.cellHeight);
entity.rect.direction = point.direction;
}
public function buildEagle(teamId:TeamId):Eagle {
var eageleConfig = config.getTeam(teamId).eagle;
var eaglePoint = config.getPoint(teamId, "eagle");
var eagle = new Eagle(teamId, eageleConfig);
eagle.color = config.getColor(new PlayerId(teamId, -1));
applyPoint(eagle, eaglePoint);
return eagle;
}
}

View File

@@ -2,7 +2,9 @@ package ru.m.tankz.game;
import ru.m.tankz.bundle.IConfigBundle;
import ru.m.tankz.config.Config;
import ru.m.tankz.control.Control;
import ru.m.tankz.core.EntityType;
import ru.m.tankz.core.Tank;
import ru.m.tankz.engine.Engine;
import ru.m.tankz.engine.IEngine;
import ru.m.tankz.game.GameState;
@@ -21,6 +23,8 @@ import ru.m.tankz.Type;
public var state(default, null):GameState;
private var builder:EntityBuilder;
@:provide var configBundle:IConfigBundle;
public function new(type:GameType) {
@@ -28,6 +32,7 @@ import ru.m.tankz.Type;
this.teams = new Map();
this.config = configBundle.get(type);
this.engine = new Engine(config);
this.builder = new EntityBuilder(config);
connect(this);
}
@@ -46,7 +51,9 @@ import ru.m.tankz.Type;
case GameEvent.COMPLETE(state, team):
this.state = state;
this.winner = team.id;
case GameEvent.SPAWN(EAGLE(eagle)):
case GameEvent.SPAWN(EAGLE(teamId)):
var eagle = builder.buildEagle(teamId);
getTeam(teamId).eagleId = eagle.id;
engine.spawn(eagle);
case GameEvent.SPAWN(TANK(tank)):
engine.spawn(tank);
@@ -55,11 +62,15 @@ import ru.m.tankz.Type;
case GameEvent.SPAWN(BONUS(bonus)):
engine.spawn(bonus);
case GameEvent.DESTROY(TANK(tank, who, wherewith, score)):
engine.destroy(tank);
engine.destroy(tank.id);
case GameEvent.DESTROY(BONUS(bonus, who, score)):
engine.destroy(bonus);
engine.destroy(bonus.id);
case GameEvent.DESTROY(BULLET(bullet)):
engine.destroy(bullet);
engine.destroy(bullet.id);
case GameEvent.ACTION(tankId, MOVE(direction)):
engine.move(tankId, direction);
case GameEvent.ACTION(tankId, STOP):
engine.stop(tankId);
case _:
}
}

View File

@@ -1,14 +1,15 @@
package ru.m.tankz.game;
import ru.m.tankz.control.Control.TankAction;
import ru.m.tankz.control.Control;
import ru.m.tankz.core.Bonus;
import ru.m.tankz.core.Bullet;
import ru.m.tankz.core.Eagle;
import ru.m.tankz.core.Tank;
import ru.m.tankz.core.Bullet;
import ru.m.tankz.map.Grid;
import ru.m.tankz.Type.TeamId;
enum SpawnEvent {
EAGLE(eagle:Eagle);
EAGLE(teamId:TeamId);
TANK(tank:Tank);
BULLET(bullet:Bullet);
BONUS(bonus:Bonus);

View File

@@ -46,22 +46,6 @@ class GameRunner implements EngineListener implements GameListener {
game.engine.update();
}
private function applyAction(tankId:Int, action:TankAction):Void {
if (!game.engine.entities.exists(tankId)) return;
var tank:Tank = cast game.engine.entities.get(tankId);
switch (action) {
case MOVE(direction):
tank.move(direction);
case STOP:
tank.stop();
case SHOT:
var bullet = tank.shot();
if (bullet != null) {
gameEventSignal.emit(GameEvent.SPAWN(BULLET(bullet)));
}
}
}
private function buildTank(task:SpawnTask):Tank {
var player = game.getPlayer(task.playerId);
var tankType:TankType = if (task.tankType != null) {
@@ -110,13 +94,8 @@ class GameRunner implements EngineListener implements GameListener {
team.spawner.push(player.id, player.state.tank);
}
}
var eaglePoint = team.spawner.getPoint("eagle");
if (eaglePoint != null) {
var eagle = new Eagle(team.id, team.config.eagle);
eagle.color = game.config.getColor(new PlayerId(eagle.team, -1));
team.eagleId = eagle.id;
applyPoint(eagle, eaglePoint);
gameEventSignal.emit(GameEvent.SPAWN(EAGLE(eagle)));
if (team.config.eagle != null) {
gameEventSignal.emit(GameEvent.SPAWN(EAGLE(team.id)));
}
}
gameEventSignal.emit(GameEvent.START(state));
@@ -178,6 +157,9 @@ class GameRunner implements EngineListener implements GameListener {
}, 5000);
}
public function onSpawn(entity:EntityType):Void {
}
public function onCollision(entity:EntityType, with:EntityType):Void {
switch entity {
case EntityType.TANK(tank):
@@ -317,8 +299,12 @@ class GameRunner implements EngineListener implements GameListener {
timer.stop();
timer = null;
}
case GameEvent.ACTION(tankId, action):
applyAction(tankId, action);
case GameEvent.ACTION(tankId, SHOT):
var tank:Tank = cast game.engine.entities.get(tankId);
var bullet = tank.shot();
if (bullet != null) {
gameEventSignal.emit(GameEvent.SPAWN(BULLET(bullet)));
}
case GameEvent.SPAWN(TANK(tank)):
game.getPlayer(tank.playerId).control.start();
case GameEvent.DESTROY(EAGLE(eagle, who, wherewith, score)):

View File

@@ -1,8 +1,9 @@
package ru.m.tankz.game;
import ru.m.tankz.game.Game;
import ru.m.tankz.game.IGame;
class GameTracer implements GameListener {
public function new() {
}

View File

@@ -1,6 +0,0 @@
package ru.m.tankz.game.record;
typedef EventItem = {
frame:Int,
event:GameEvent
}

View File

@@ -2,17 +2,20 @@ package ru.m.tankz.game.record;
import flash.events.Event;
import flash.Lib;
import ru.m.tankz.game.record.GameRecord;
class GamePlayer {
private var frame:Int;
private var game:IGame;
private var record:GameRecord;
private var data:Array<EventItem>;
public function new(game:IGame, data:Array<EventItem>) {
public function new(game:IGame, record:GameRecord) {
frame = 0;
this.game = game;
this.data = data;
this.record = record;
this.data = null;
}
public function onGameEvent(event:GameEvent):Void {
@@ -24,6 +27,7 @@ class GamePlayer {
public function start():Void {
frame = 0;
data = record.events.slice(0);
Lib.current.stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
}

View File

@@ -0,0 +1,21 @@
package ru.m.tankz.game.record;
import com.hurlant.crypto.extra.UUID;
import com.hurlant.crypto.prng.Random;
typedef EventItem = {
frame:Int,
event:GameEvent
}
class GameRecord {
public var id(default, default):String;
public var date(default, default):Date;
public var events(default, default):Array<EventItem>;
public function new() {
this.id = UUID.generateRandom(new Random()).toString();
this.date = null;
this.events = [];
}
}

View File

@@ -7,11 +7,11 @@ import ru.m.tankz.game.IGame;
class GameRecorder implements GameListener {
private var frame:Int;
public var data(default, null):Array<EventItem>;
public var record(default, null):GameRecord;
public function new() {
frame = 0;
data = [];
record = new GameRecord();
}
public function onGameEvent(event:GameEvent):Void {
@@ -22,11 +22,12 @@ class GameRecorder implements GameListener {
stop();
case _:
}
data.push({frame: frame, event: event});
record.events.push({frame: frame, event: event});
}
public function start():Void {
frame = 0;
record.date = Date.now();
Lib.current.stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
}

View File

@@ -34,6 +34,14 @@ player:
- {type: bot2, rate: 0.27}
- {type: bot3, rate: 0.15}
team:
human: &team_human
id: human
players:
- {<<: *human, index: 0, color: 0xFFFF00, control: human-0}
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}
@@ -152,12 +160,10 @@ presets:
- id: 0
name: easy
teams:
- id: human
players:
- {<<: *human, index: 0, color: 0xFFFF00, control: human-0}
- {<<: *team_human}
- id: bot
spawnInterval: 3000
life: 10
life: 1
players:
- {<<: *bot, index: 0, control: bot-stupid}
- {<<: *bot, index: 1, control: bot-stupid}
@@ -165,9 +171,7 @@ presets:
- id: 1
name: normal
teams:
- id: human
players:
- {<<: *human, index: 0, color: 0xFFFF00, control: human-0}
- {<<: *team_human}
- id: bot
spawnInterval: 3000
life: 20
@@ -180,9 +184,7 @@ presets:
- id: 2
name: hard
teams:
- id: human
players:
- {<<: *human, index: 0, color: 0xFFFF00, control: human-0}
- {<<: *team_human}
- id: bot
spawnInterval: 1000
life: 30