[client] add RecordFrame

This commit is contained in:
2019-05-07 17:21:01 +03:00
parent a7f286dc42
commit 183c6c16f1
19 changed files with 162 additions and 63 deletions

View File

@@ -69,10 +69,6 @@ class Init {
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

@@ -115,6 +115,7 @@ class Render extends SpriteView implements GameListener implements EngineListene
var item = new BulletItem(bullet);
items.set(bullet.key, item);
entryLayer.addChild(item.view);
item.update();
case BONUS(bonus):
var item = new BonusItem(bonus);
items.set(bonus.key, item);

View File

@@ -17,3 +17,5 @@ views:
$type: ru.m.tankz.view.ResultFrame
- id: settings
$type: ru.m.tankz.view.SettingsFrame
- id: record
$type: ru.m.tankz.view.RecordFrame

View File

@@ -0,0 +1,43 @@
package ru.m.tankz.view;
import haxework.view.frame.FrameSwitcher;
import haxework.view.list.ListView.IListItemView;
import haxework.view.list.VListView;
import haxework.view.VGroupView;
import ru.m.tankz.game.record.GameRecord;
import ru.m.tankz.preset.ClassicGame;
import ru.m.tankz.preset.DeathGame;
import ru.m.tankz.preset.DotaGame;
import ru.m.tankz.storage.RecordStorage;
import ru.m.tankz.view.classic.ClassicGameFrame;
import ru.m.tankz.view.death.DeathGameFrame;
import ru.m.tankz.view.dota.DotaGameFrame;
@:template class RecordFrame extends VGroupView {
public static var ID(default, never):String = "record";
@:view var data:VListView<GameRecord>;
@:provide var recordStorage:RecordStorage;
@:provide var switcher:FrameSwitcher;
@:provide var record:GameRecord;
public function onShow():Void {
data.data = Lambda.array(recordStorage);
}
private function onRecordSelect(item:IListItemView<GameRecord>):Void {
record = item.data;
// ToDo: copy@paste from LevelFrame
switcher.change(switch record.type {
case ClassicGame.TYPE: ClassicGameFrame.ID;
case DotaGame.TYPE: DotaGameFrame.ID;
case DeathGame.TYPE: DeathGameFrame.ID;
case _: StartFrame.ID;
});
}
private function close() {
switcher.change(StartFrame.ID);
}
}

View File

@@ -0,0 +1,20 @@
---
views:
- $type: haxework.view.VGroupView
skinId: container
views:
- $type: haxework.view.LabelView
skinId: text.header
text: Records
- id: data
$type: haxework.view.list.VListView
factory: $code:function() return new haxework.view.list.LabelListItem()
+onItemSelect: $this:onRecordSelect
geometry.margin.top: 20
geometry.size.stretch: true
- $type: haxework.view.HGroupView
skinId: panel
views:
- $type: haxework.view.ButtonView
skinId: button.close
+onPress: $code:close()

View File

@@ -11,13 +11,13 @@ import ru.m.tankz.view.popup.FontPopup;
public static var ID(default, never):String = "start";
@:provide var state:GameState;
@:provide var swicther:FrameSwitcher;
@:provide var switcher:FrameSwitcher;
private var fontPopup:FontPopup;
private function startGame(type:GameType):Void {
state = new GameState(type);
swicther.change(LevelFrame.ID);
switcher.change(LevelFrame.ID);
}
private function choiceFont():Void {

View File

@@ -21,13 +21,17 @@ views:
skinId: button
+onPress: $code:startGame('death')
text: DeathMatch
- $type: haxework.view.ButtonView
skinId: button
+onPress: $code:switcher.change('record')
text: Records
- $type: haxework.view.HGroupView
skinId: panel
views:
- id: settings
$type: haxework.view.ButtonView
skinId: button.settings
+onPress: $code:swicther.change('settings')
+onPress: $code:switcher.change('settings')
- $type: haxework.view.SpriteView
geometry.size.width: 100%
- $type: haxework.view.LabelView

View File

@@ -37,20 +37,20 @@ import ru.m.tankz.view.common.LifeView;
switch event {
case START(state):
refresh(state);
case CHANGE(TEAM_LIFE(team, life)):
if (team.id == ClassicGame.BOT) {
case CHANGE(TEAM_LIFE(teamId, life)):
if (teamId == ClassicGame.BOT) {
bot.life = life;
}
case CHANGE(PLAYER_LIFE(player, life)):
if (player.id == player1Id) {
case CHANGE(PLAYER_LIFE(playerId, life)):
if (playerId == player1Id) {
player1.life = life;
} else if (player.id == player2Id) {
} else if (playerId == player2Id) {
player2.life = life;
}
case CHANGE(PLAYER_SCORE(player, score)):
if (player.id == player1Id) {
case CHANGE(PLAYER_SCORE(playerId, score)):
if (playerId == player1Id) {
player1.score = score;
} else if (player.id == player2Id) {
} else if (playerId == player2Id) {
player2.score = score;
}
case _:

View File

@@ -9,6 +9,8 @@ import ru.m.tankz.game.GameEvent;
import ru.m.tankz.game.GameRunner;
import ru.m.tankz.game.GameState;
import ru.m.tankz.game.IGame;
import ru.m.tankz.game.record.GamePlayer;
import ru.m.tankz.game.record.GameRecord;
import ru.m.tankz.game.record.GameRecorder;
import ru.m.tankz.network.NetworkManager;
import ru.m.tankz.render.Render;
@@ -27,6 +29,7 @@ class GameFrame extends GroupView implements GameListener {
@:provide var network:NetworkManager;
@:provide var soundManager:SoundManager;
@:provide var state:GameState;
@:provide var record:GameRecord;
@:provide("result") var result:GameState;
@:provide var switcher:FrameSwitcher;
@:provide var gameStorage:GameStorage;
@@ -35,6 +38,7 @@ class GameFrame extends GroupView implements GameListener {
private var game:IGame;
private var runner:GameRunner;
private var recorder:GameRecorder;
private var player:GamePlayer;
private function get_render():Render {
throw "Not implemented";
@@ -45,11 +49,16 @@ class GameFrame extends GroupView implements GameListener {
}
public function onShow():Void {
start(state);
if (record != null) {
play(record);
record = null;
} else {
start(state);
}
}
private function start(state:GameState):Void {
game = new Game(state.type);
game = new Game(state);
game.connect(render);
game.engine.connect(render);
game.connect(soundManager);
@@ -66,6 +75,21 @@ class GameFrame extends GroupView implements GameListener {
render.draw(game.engine);
}
private function play(record:GameRecord):Void {
game = new Game(record.state);
game.connect(render);
game.engine.connect(render);
game.connect(soundManager);
//game.connect(this);
if (panel != null) {
game.connect(panel);
}
player = new GamePlayer(game, record);
player.start();
content.addEventListener(Event.ENTER_FRAME, _redraw);
render.draw(game.engine);
}
private function stop():Void {
content.removeEventListener(Event.ENTER_FRAME, _redraw);
if (runner != null) {
@@ -83,7 +107,7 @@ class GameFrame extends GroupView implements GameListener {
switch event {
case GameEvent.COMPLETE(state, winner):
// ToDo:
//recordStorage.save(recorder.record);
recordStorage.save(recorder.record);
result = state;
this.state = switch runner.next() {
case Some(s):

View File

@@ -35,10 +35,10 @@ import ru.m.tankz.view.common.LifeView;
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 CHANGE(TEAM_LIFE(teamId, life)):
getLifeView(teamId).life = life;
case CHANGE(TEAM_SCORE(teamId, score)):
getLifeView(teamId).score = score;
case _:
}
}

View File

@@ -152,8 +152,9 @@ import ru.m.tankz.map.LevelMap;
}
public function dispose():Void {
entities = null;
map = null;
// ToDo: set to null
entities = new Map();
//map = null;
spawnSignal.dispose();
collisionSignal.dispose();
moveSignal.dispose();

View File

@@ -29,13 +29,25 @@ import ru.m.tankz.Type;
@:provide var configBundle:IConfigBundle;
public function new(type:GameType) {
this.type = type;
public function new(state:GameState) {
this.type = state.type;
this.teams = new Map();
this.config = configBundle.get(type);
this.engine = new Engine(config);
this.builder = new EntityBuilder(config);
connect(this);
prepare(state);
}
private function prepare(state:GameState):Void {
var level:LevelConfig = state.level;
var points:Array<SpawnPoint> = level.points != null ? level.points : config.points;
engine.map.setData(level.data);
for (teamConfig in state.preset.teams) {
var teamPoints = points.filter(function(p:SpawnPoint) return p.team == teamConfig.id);
var team:Team = new Team(teamConfig, teamPoints, state.teams[teamConfig.id]);
teams[team.id] = team;
}
}
private function applyPoint(entity:Entity, point:SpawnPoint):Void {

View File

@@ -30,10 +30,10 @@ enum DestroyEvent {
}
enum ChangeEvent {
PLAYER_SCORE(player:Player, value:Int);
PLAYER_LIFE(player:Player, value:Int);
TEAM_SCORE(team:Team, value:Int);
TEAM_LIFE(team:Team, value:Int);
PLAYER_SCORE(playerId:PlayerId, value:Int);
PLAYER_LIFE(playerId:PlayerId, value:Int);
TEAM_SCORE(teamId:TeamId, value:Int);
TEAM_LIFE(teamId:TeamId, value:Int);
}
enum GameEvent {

View File

@@ -23,7 +23,6 @@ class GameRunner implements EngineListener implements GameListener {
private var game(default, null):IGame;
private var gameEventSignal(get, null):Signal<GameEvent>;
private var points:Array<SpawnPoint>;
private var timer:Timer;
@@ -52,13 +51,7 @@ class GameRunner implements EngineListener implements GameListener {
}
public function start(state:GameState):Void {
var level:LevelConfig = state.level;
points = level.points != null ? level.points : game.config.points;
game.engine.map.setData(level.data);
for (teamConfig in state.preset.teams) {
var teamPoints = points.filter(function(p:SpawnPoint) return p.team == teamConfig.id);
var team:Team = new Team(teamConfig, teamPoints, state.teams[teamConfig.id]);
game.teams[team.id] = team;
for (team in game.teams.iterator()) {
for (player in team.players.iterator()) {
var control = controlFactory.build(player.id, AController.fromString(player.config.control));
if (control != null) {
@@ -67,8 +60,6 @@ class GameRunner implements EngineListener implements GameListener {
}
}
team.spawner.runner = spawn;
}
for (team in game.teams.iterator()) {
for (player in team.players.iterator()) {
if (team.tryRespawn(player.id)) {
team.spawner.push(player.id);
@@ -250,20 +241,20 @@ class GameRunner implements EngineListener implements GameListener {
var player = game.getPlayer(playerId);
var team = game.getTeam(playerId.team);
player.state.score += score;
gameEventSignal.emit(GameEvent.CHANGE(PLAYER_SCORE(player, player.state.score)));
gameEventSignal.emit(GameEvent.CHANGE(TEAM_SCORE(team, game.state.getTeamScore(team.id))));
gameEventSignal.emit(GameEvent.CHANGE(PLAYER_SCORE(playerId, player.state.score)));
gameEventSignal.emit(GameEvent.CHANGE(TEAM_SCORE(playerId.team, game.state.getTeamScore(team.id))));
}
private function changeLife(playerId:PlayerId, life:Int):Void {
var player = game.getPlayer(playerId);
player.state.life += life;
gameEventSignal.emit(GameEvent.CHANGE(PLAYER_LIFE(player, player.state.life)));
gameEventSignal.emit(GameEvent.CHANGE(PLAYER_LIFE(playerId, player.state.life)));
}
private function changeTeamLife(teamId:TeamId, life:Int):Void {
var team = game.getTeam(teamId);
team.state.life += life;
gameEventSignal.emit(GameEvent.CHANGE(TEAM_LIFE(team, team.state.life)));
gameEventSignal.emit(GameEvent.CHANGE(TEAM_LIFE(teamId, team.state.life)));
}
public function onGameEvent(event:GameEvent):Void {

View File

@@ -18,13 +18,6 @@ class GamePlayer {
this.data = null;
}
public function onGameEvent(event:GameEvent):Void {
switch event {
case GameEvent.COMPLETE(_, _):
stop();
}
}
public function start():Void {
frame = 0;
data = record.events.slice(0);
@@ -42,15 +35,16 @@ class GamePlayer {
if (event.frame <= frame) {
events++;
game.gameEventSignal.emit(event.event);
switch event {
switch event.event {
case GameEvent.COMPLETE(_, _):
stop();
case _:
}
} else {
break;
}
}
if (event > 0) {
if (events > 0) {
data = data.slice(events);
}
}

View File

@@ -1,5 +1,6 @@
package ru.m.tankz.game.record;
import ru.m.tankz.Type;
import com.hurlant.crypto.extra.UUID;
import com.hurlant.crypto.prng.Random;
@@ -11,11 +12,24 @@ typedef EventItem = {
class GameRecord {
public var id(default, default):String;
public var date(default, default):Date;
public var type(default, default):GameType;
public var presetId(default, default):PresetId;
public var levelId(default, default):LevelId;
public var events(default, default):Array<EventItem>;
public var state(get, null):GameState;
public function new() {
this.id = UUID.generateRandom(new Random()).toString();
this.date = null;
this.events = [];
}
private inline function get_state():GameState {
return new GameState(type, presetId, levelId);
}
public function toString():String {
return 'GameRecord{id=$id,date=$date,type=$type,preset=$presetId,level=$levelId,events=${events.length}}';
}
}

View File

@@ -16,7 +16,10 @@ class GameRecorder implements GameListener {
public function onGameEvent(event:GameEvent):Void {
switch event {
case GameEvent.START(_):
case GameEvent.START(state):
record.type = state.type;
record.presetId = state.presetId;
record.levelId = state.levelId;
start();
case GameEvent.COMPLETE(_, _):
stop();

View File

@@ -1,19 +1,13 @@
package ru.m.tankz.network;
import ru.m.tankz.proto.game.GameChangeProto;
import ru.m.tankz.proto.core.GameProto;
import ru.m.tankz.Type;
import ru.m.tankz.game.Game;
import ru.m.tankz.proto.core.GameProto;
import ru.m.tankz.proto.game.GameChangeProto;
class NetworkGame extends Game {
private static var TAG(default, never):String = 'NetworkGame';
public function new(type:GameType) {
super(type);
}
public function load(proto:GameProto):Void {
L.w(TAG, 'load: ${proto}');
// ToDo:

View File

@@ -163,7 +163,7 @@ presets:
- {<<: *team_human}
- id: bot
spawnInterval: 3000
life: 10
life: 1
players:
- {<<: *bot, index: 0, control: bot-stupid}
- {<<: *bot, index: 1, control: bot-stupid}