From c1ff14111d8cdf2292dd732eb08354edd4da5906 Mon Sep 17 00:00:00 2001 From: shmyga Date: Thu, 16 May 2019 17:13:06 +0300 Subject: [PATCH] [client] update render --- src/client/haxe/ru/m/tankz/render/IRender.hx | 6 +- src/client/haxe/ru/m/tankz/render/Render.hx | 145 ++++++++++-------- .../m/tankz/render/item/BitmapRenderItem.hx | 34 ++++ .../ru/m/tankz/render/item/BonusRenderItem.hx | 22 +++ .../ru/m/tankz/render/item/BrickRenderItem.hx | 54 +++++++ .../m/tankz/render/item/BulletRenderItem.hx | 21 +++ .../ru/m/tankz/render/item/EagleRenderItem.hx | 21 +++ .../ru/m/tankz/render/item/IRenderItem.hx | 13 ++ .../haxe/ru/m/tankz/render/item/RenderItem.hx | 35 +++++ .../ru/m/tankz/render/item/TankRenderItem.hx | 97 ++++++++++++ .../haxe/ru/m/tankz/storage/RecordStorage.hx | 14 +- src/client/haxe/ru/m/tankz/view/GameFrame.hx | 20 +-- .../haxe/ru/m/tankz/view/RecordFrame.hx | 9 +- .../haxe/ru/m/tankz/view/common/RecordView.hx | 8 +- src/common/haxe/ru/m/geom/Position.hx | 7 + src/common/haxe/ru/m/geom/Rectangle.hx | 13 +- src/common/haxe/ru/m/tankz/engine/Engine.hx | 1 - src/common/haxe/ru/m/tankz/game/Game.hx | 1 + src/common/haxe/ru/m/tankz/game/GameEvent.hx | 14 +- src/common/haxe/ru/m/tankz/game/GameRunner.hx | 28 +++- .../haxe/ru/m/tankz/game/record/GameRecord.hx | 16 +- .../ru/m/tankz/game/record/GameRecorder.hx | 8 +- src/common/haxe/ru/m/tankz/map/LevelMap.hx | 4 +- src/common/resources/classic/config.yaml | 2 +- 24 files changed, 479 insertions(+), 114 deletions(-) create mode 100644 src/client/haxe/ru/m/tankz/render/item/BitmapRenderItem.hx create mode 100644 src/client/haxe/ru/m/tankz/render/item/BonusRenderItem.hx create mode 100644 src/client/haxe/ru/m/tankz/render/item/BrickRenderItem.hx create mode 100644 src/client/haxe/ru/m/tankz/render/item/BulletRenderItem.hx create mode 100644 src/client/haxe/ru/m/tankz/render/item/EagleRenderItem.hx create mode 100644 src/client/haxe/ru/m/tankz/render/item/IRenderItem.hx create mode 100644 src/client/haxe/ru/m/tankz/render/item/RenderItem.hx create mode 100644 src/client/haxe/ru/m/tankz/render/item/TankRenderItem.hx create mode 100644 src/common/haxe/ru/m/geom/Position.hx diff --git a/src/client/haxe/ru/m/tankz/render/IRender.hx b/src/client/haxe/ru/m/tankz/render/IRender.hx index 4b189ad..f423eea 100644 --- a/src/client/haxe/ru/m/tankz/render/IRender.hx +++ b/src/client/haxe/ru/m/tankz/render/IRender.hx @@ -1,10 +1,10 @@ package ru.m.tankz.render; import haxework.view.IView; -import ru.m.tankz.engine.IEngine; import ru.m.tankz.game.IGame; -interface IRender extends IView extends GameListener extends EngineListener { - public function draw(game:IEngine):Void; +interface IRender extends IView { + public var game(default, set):IGame; + public function draw():Void; public function reset():Void; } diff --git a/src/client/haxe/ru/m/tankz/render/Render.hx b/src/client/haxe/ru/m/tankz/render/Render.hx index e502d1a..c1b885e 100755 --- a/src/client/haxe/ru/m/tankz/render/Render.hx +++ b/src/client/haxe/ru/m/tankz/render/Render.hx @@ -1,9 +1,9 @@ package ru.m.tankz.render; -import ru.m.geom.Rectangle; import flash.display.DisplayObjectContainer; import flash.display.Graphics; import flash.display.Sprite; +import flash.events.Event; import haxe.Timer; import haxework.view.LabelView; import haxework.view.SpriteView; @@ -14,9 +14,17 @@ import ru.m.geom.Point; import ru.m.tankz.core.EntityType; import ru.m.tankz.engine.IEngine; import ru.m.tankz.game.GameEvent; -import ru.m.tankz.render.RenderItem; +import ru.m.tankz.game.IGame; +import ru.m.tankz.render.item.BonusRenderItem; +import ru.m.tankz.render.item.BrickRenderItem; +import ru.m.tankz.render.item.BulletRenderItem; +import ru.m.tankz.render.item.EagleRenderItem; +import ru.m.tankz.render.item.IRenderItem; +import ru.m.tankz.render.item.TankRenderItem; -class Render extends SpriteView implements IRender { +class Render extends SpriteView implements IRender implements GameListener { + + public var game(default, set):IGame; private var backgroundLayer:Sprite; private var groundLayer:Sprite; @@ -25,7 +33,7 @@ class Render extends SpriteView implements IRender { private var upperLayer:Sprite; private var background:Sprite; - private var items:Map>; + private var items:Map; public function new() { super(); @@ -43,6 +51,13 @@ class Render extends SpriteView implements IRender { reset(); } + private function set_game(value:IGame):IGame { + game = value; + game.connect(this); + game.engine.spawnSignal.connect(onSpawn); + return game; + } + private function drawBackground(engine:IEngine):Void { var g:Graphics = backgroundLayer.graphics; g.clear(); @@ -52,38 +67,25 @@ class Render extends SpriteView implements IRender { setContentSize(engine.map.width, engine.map.height); } - public function draw(game:IEngine):Void { - for (brick in game.map.bricks) if (brick.config.index > 0) { - if (!items.exists(brick.id)) { - var item:RenderItem = switch(brick.config.type) { - case 'ace' | 'bush': new BrickItem(brick); - case 'water': new BrickAnimateItem(brick); - case 'armor' | 'brick': new BrickBreakingItem(brick); - case x: null; - }; - if (item != null) { - items[brick.id] = item; - if (brick.config.layer > 2) { - upLayer.addChild(item.view); - } else { - groundLayer.addChild(item.view); - } - } - } - } + public function draw():Void { for (item in items) { item.update(); } if (background == null) { - drawBackground(game); + drawBackground(game.engine); } } + private function onEnterFrame(event:Event):Void { + draw(); + } + private function clearLayer(layer:DisplayObjectContainer) { while (layer.numChildren > 0) layer.removeChildAt(0); } public function reset():Void { + content.removeEventListener(Event.ENTER_FRAME, onEnterFrame); for (item in items.iterator()) { item.dispose(); } @@ -101,23 +103,23 @@ class Render extends SpriteView implements IRender { public function onSpawn(entity:EntityType):Void { switch entity { case EAGLE(eagle): - var item = new EagleItem(eagle); + var item = new EagleRenderItem(eagle); items.set(eagle.id, item); entryLayer.addChild(item.view); item.update(); case TANK(tank): - var item = new TankItem(tank); + var item = new TankRenderItem(tank); items.set(tank.id, item); entryLayer.addChild(item.view); item.update(); - playAnimate(tank.rect.center, AnimateBundle.tankSpawn()); + playAnimate(item.rect.center, AnimateBundle.tankSpawn()); case BULLET(bullet): - var item = new BulletItem(bullet); + var item = new BulletRenderItem(bullet); items.set(bullet.id, item); entryLayer.addChild(item.view); item.update(); case BONUS(bonus): - var item = new BonusItem(bonus); + var item = new BonusRenderItem(bonus); items.set(bonus.id, item); upperLayer.addChild(item.view); item.update(); @@ -125,25 +127,51 @@ class Render extends SpriteView implements IRender { } } - public function onCollision(entity:EntityType, with:EntityType):Void { - } - - public function onMove(entity:EntityType):Void { - } - - public function onDestroy(entity:EntityType):Void { - } - public function onGameEvent(event:GameEvent):Void { switch event { + case START(_): + for (brick in game.engine.map.bricks) { + var item:IRenderItem = new BrickRenderItem(brick); + items[brick.id] = item; + if (brick.config.layer > 2) { + upLayer.addChild(item.view); + } else { + groundLayer.addChild(item.view); + } + } + content.addEventListener(Event.ENTER_FRAME, onEnterFrame); + case COMPLETE(_, _): + content.removeEventListener(Event.ENTER_FRAME, onEnterFrame); + case MOVE(BULLET(id, position)): + if (items.exists(id)) { + var item = items[id]; + item.move(position); + } + case MOVE(TANK(id, position)): + if (items.exists(id)) { + var item = items[id]; + item.move(position); + cast(item, TankRenderItem).moves = true; + } + case STOP(TANK(id)): + if (items.exists(id)) { + var item = items[id]; + cast(item, TankRenderItem).moves = false; + } + case CHANGE(TANK(id, type, hits, bonus)): + if (items.exists(id)) { + var item:TankRenderItem = cast items[id]; + item.skin = game.config.getTank(type).skin; + item.hits = hits; + item.bonus = bonus; + } case DESTROY(TANK(id, shot)): if (items.exists(id)) { var item = items[id]; entryLayer.removeChild(item.view); - var rect:Rectangle = item.value.rect; - playAnimate(rect.center, AnimateBundle.tankBoom()); + playAnimate(item.rect.center, AnimateBundle.tankBoom()); if (shot.score != 0) { - showScore(rect.center, shot.score); + showScore(item.rect.center, shot.score); } items.remove(id); } @@ -151,38 +179,35 @@ class Render extends SpriteView implements IRender { if (items.exists(id)) { var item = items[id]; entryLayer.removeChild(item.view); - var rect:Rectangle = item.value.rect; + var rect = item.rect; + // move boom var point = rect.center.add(new Point(rect.width * rect.direction.x, rect.height * rect.direction.y)); playAnimate(point, AnimateBundle.bulletBoom()); items.remove(id); } - case DESTROY(BONUS(id, shot)): - if (items.exists(id)) { - var item = items[id]; - upperLayer.removeChild(item.view); - var rect:Rectangle = item.value.rect; - if (shot.score != 0) { - showScore(rect.center, shot.score); - } - items.remove(id); - } case DESTROY(EAGLE(id, shot)): if (items.exists(id)) { var item = items[id]; - var rect:Rectangle = item.value.rect; - playAnimate(rect.center, AnimateBundle.tankBoom()); + playAnimate(item.rect.center, AnimateBundle.tankBoom()); if (shot.score != 0) { - showScore(rect.center, shot.score); + showScore(item.rect.center, shot.score); } + cast(item, EagleRenderItem).death = true; } - case MOVE(TANK(id, position)) | MOVE(BULLET(id, position)): + case DESTROY(BONUS(id, shot)): if (items.exists(id)) { var item = items[id]; - item.value.rect.x = position.x; - item.value.rect.y = position.y; - item.value.rect.direction = position.direction; - item.update(); + upperLayer.removeChild(item.view); + if (shot.score != 0) { + showScore(item.rect.center, shot.score); + } + items.remove(id); } + case DESTROY(CELL(cellX, cellY, shot)): + // ToDo: redraw only cell? + var brick = game.engine.map.getBrick(new Point(cellX, cellY)); + var item:BrickRenderItem = cast items[brick.id]; + item.redraw(brick); case _: } } diff --git a/src/client/haxe/ru/m/tankz/render/item/BitmapRenderItem.hx b/src/client/haxe/ru/m/tankz/render/item/BitmapRenderItem.hx new file mode 100644 index 0000000..d029894 --- /dev/null +++ b/src/client/haxe/ru/m/tankz/render/item/BitmapRenderItem.hx @@ -0,0 +1,34 @@ +package ru.m.tankz.render.item; + +import flash.display.Bitmap; +import flash.display.BitmapData; +import flash.display.DisplayObject; +import flash.display.PixelSnapping; +import openfl.Assets; +import ru.m.geom.Rectangle; + +class BitmapRenderItem extends RenderItem { + public var image(default, set):String; + + private var bitmapData:BitmapData; + private var bitmap:Bitmap; + + public function new(rect:Rectangle) { + super(rect); + this.bitmap = new Bitmap(null, PixelSnapping.AUTO, true); + move(rect.position); + } + + override private function get_view():DisplayObject { + return bitmap; + } + + private function set_image(value:String):String { + if (image != value) { + image = value; + bitmapData = Assets.getBitmapData(image); + bitmap.bitmapData = bitmapData; + } + return image; + } +} diff --git a/src/client/haxe/ru/m/tankz/render/item/BonusRenderItem.hx b/src/client/haxe/ru/m/tankz/render/item/BonusRenderItem.hx new file mode 100644 index 0000000..9d994a7 --- /dev/null +++ b/src/client/haxe/ru/m/tankz/render/item/BonusRenderItem.hx @@ -0,0 +1,22 @@ +package ru.m.tankz.render.item; + +import ru.m.tankz.core.Bonus; +import ru.m.tankz.Type.BonusType; + +class BonusRenderItem extends BitmapRenderItem { + + public var type(default, set):BonusType; + + public function new(bonus:Bonus) { + super(bonus.rect); + type = bonus.config.type; + } + + private function set_type(value:BonusType):BonusType { + if (type != value) { + type = value; + image = 'resources/image/bonus/${type}.png'; + } + return type; + } +} diff --git a/src/client/haxe/ru/m/tankz/render/item/BrickRenderItem.hx b/src/client/haxe/ru/m/tankz/render/item/BrickRenderItem.hx new file mode 100644 index 0000000..d86b465 --- /dev/null +++ b/src/client/haxe/ru/m/tankz/render/item/BrickRenderItem.hx @@ -0,0 +1,54 @@ +package ru.m.tankz.render.item; + +import flash.display.BitmapData; +import flash.display.Shape; +import openfl.Assets; +import openfl.display.DisplayObject; +import ru.m.tankz.map.Brick; +import ru.m.tankz.Type.BrickType; + +class BrickRenderItem extends RenderItem { + + public var type(default, set):BrickType; + + private var image:BitmapData; + private var shape:Shape; + + public function new(brick:Brick) { + super(brick.rect); + this.shape = new Shape(); + this.type = brick.config.type; + redraw(brick); + move(rect.position); + } + + override private function get_view():DisplayObject { + return shape; + } + + private function set_type(value:BrickType):BrickType { + if (type != value) { + type = value; + image = Assets.getBitmapData('resources/image/map/${type}.png'); + } + return type; + } + + public function redraw(brick:Brick):Void { + shape.graphics.clear(); + if (brick.destroyed) return; + if (brick.config.index > 0) { + shape.graphics.beginBitmapFill(image); + if (brick.broken == 0) { + shape.graphics.drawRect(0, 0, brick.rect.width, brick.rect.height); + } else { + for (c in brick.cells) { + if (!c.destroyed) { + shape.graphics.drawRect(c.rect.x - brick.rect.x, c.rect.y - brick.rect.y, c.rect.width, c.rect.height); + } + } + } + shape.graphics.endFill(); + } + } +} diff --git a/src/client/haxe/ru/m/tankz/render/item/BulletRenderItem.hx b/src/client/haxe/ru/m/tankz/render/item/BulletRenderItem.hx new file mode 100644 index 0000000..602fca1 --- /dev/null +++ b/src/client/haxe/ru/m/tankz/render/item/BulletRenderItem.hx @@ -0,0 +1,21 @@ +package ru.m.tankz.render.item; + +import ru.m.tankz.core.Bullet; + +class BulletRenderItem extends BitmapRenderItem { + public var piercing(default, set):Int = -1; + + public function new(bullet:Bullet) { + super(bullet.rect); + piercing = bullet.config.piercing; + } + + private function set_piercing(value:Int):Int { + if (piercing != value) { + piercing = value; + var type = piercing > 0 ? 'piercing' : 'normal'; + image = 'resources/image/bullet/${type}.png'; + } + return piercing; + } +} diff --git a/src/client/haxe/ru/m/tankz/render/item/EagleRenderItem.hx b/src/client/haxe/ru/m/tankz/render/item/EagleRenderItem.hx new file mode 100644 index 0000000..0f0e69b --- /dev/null +++ b/src/client/haxe/ru/m/tankz/render/item/EagleRenderItem.hx @@ -0,0 +1,21 @@ +package ru.m.tankz.render.item; + +import ru.m.tankz.core.Eagle; + +class EagleRenderItem extends BitmapRenderItem { + public var death(default, set):Bool = true; + + public function new(eagle:Eagle) { + super(eagle.rect); + death = false; + } + + private function set_death(value:Bool):Bool { + if (death != value) { + death = value; + var suffix = death ? '-death' : ''; + image = 'resources/image/eagle/eagle${suffix}.png'; + } + return death; + } +} diff --git a/src/client/haxe/ru/m/tankz/render/item/IRenderItem.hx b/src/client/haxe/ru/m/tankz/render/item/IRenderItem.hx new file mode 100644 index 0000000..9f1d304 --- /dev/null +++ b/src/client/haxe/ru/m/tankz/render/item/IRenderItem.hx @@ -0,0 +1,13 @@ +package ru.m.tankz.render.item; + +import flash.display.DisplayObject; +import ru.m.geom.Position; +import ru.m.geom.Rectangle; + +interface IRenderItem { + public var view(get, null):DisplayObject; + public var rect(default, null):Rectangle; + public function move(position:Position):Void; + public function update():Void; + public function dispose():Void; +} diff --git a/src/client/haxe/ru/m/tankz/render/item/RenderItem.hx b/src/client/haxe/ru/m/tankz/render/item/RenderItem.hx new file mode 100644 index 0000000..1d74f7c --- /dev/null +++ b/src/client/haxe/ru/m/tankz/render/item/RenderItem.hx @@ -0,0 +1,35 @@ +package ru.m.tankz.render.item; + +import flash.display.DisplayObject; +import ru.m.geom.Position; +import ru.m.geom.Rectangle; + +class RenderItem implements IRenderItem { + + public var view(get, null):DisplayObject; + + public var rect(default, null):Rectangle; + + public function new(rect:Rectangle) { + this.rect = rect.clone(); + } + + private function get_view():DisplayObject { + throw "Not Implemented"; + } + + public function move(position:Position):Void { + view.x = rect.x = position.x; + view.y = rect.y = position.y; + if (position.direction != null) { + rect.direction = position.direction; + view.rotation = rect.direction.angle; + view.x = rect.x - rect.width * (rect.direction.x + 1) / 2 + rect.width * (rect.direction.y + 1) / 2 + 0.5 * rect.width; + view.y = rect.y - rect.height * (rect.direction.x + 1) / 2 - rect.height * (rect.direction.y + 1) / 2 + 1.5 * rect.height; + } + } + + public function update():Void {} + + public function dispose():Void {} +} diff --git a/src/client/haxe/ru/m/tankz/render/item/TankRenderItem.hx b/src/client/haxe/ru/m/tankz/render/item/TankRenderItem.hx new file mode 100644 index 0000000..9426980 --- /dev/null +++ b/src/client/haxe/ru/m/tankz/render/item/TankRenderItem.hx @@ -0,0 +1,97 @@ +package ru.m.tankz.render.item; + +import flash.display.BitmapData; +import haxework.color.Color; +import haxework.view.utils.BitmapUtil; +import openfl.Assets; +import ru.m.tankz.core.Tank; + +class TankRenderItem extends BitmapRenderItem { + public var color(default, default):Color; + public var skin(default, set):String; + public var hits(default, set):Int; + public var bonus(default, set):Bool; + public var moves(default, set):Bool; + + private var images:Array; + private var frame:Int; + + public function new(tank:Tank) { + super(tank.rect); + color = tank.color; + skin = tank.config.skin; + hits = tank.hits; + bonus = tank.bonus; + move(rect.position); + } + + private function redraw():Void { + var image1 = Assets.getBitmapData('resources/image/tank/${skin}-0.png'); + var image2 = Assets.getBitmapData('resources/image/tank/${skin}-1.png'); + var color1:Color = switch hits { + case 1: 0x869C43; + case 2: 0xDEAF80; + case 3: 0x5EA67A; + case _: color; + } + var color2:Color = color1; + if (bonus) { + color1 = 0xff00aa; + } + if (!color1.zero) { + image1 = BitmapUtil.colorize(image1, color1); + } + if (!color1.zero) { + image2 = BitmapUtil.colorize(image2, color2); + } + images = [ + image1, image1, image1, + image2, image2, image2, + ]; + frame = 0; + bitmap.bitmapData = images[frame]; + } + + private function set_skin(value:String):String { + if (skin != value) { + skin = value; + redraw(); + } + return skin; + } + + private function set_hits(value:Int):Int { + if (hits != value) { + hits = value; + redraw(); + } + return hits; + } + + private function set_bonus(value:Bool):Bool { + if (bonus != value) { + bonus = value; + redraw(); + } + return bonus; + } + + private function set_moves(value:Bool):Bool { + if (moves != value) { + moves = value; + bitmap.bitmapData = images[0]; + } + return moves; + } + + override public function update():Void { + super.update(); + if (moves) { + frame++; + if (frame > images.length - 1) { + frame = 0; + } + bitmap.bitmapData = images[frame]; + } + } +} diff --git a/src/client/haxe/ru/m/tankz/storage/RecordStorage.hx b/src/client/haxe/ru/m/tankz/storage/RecordStorage.hx index 31bcc90..0f5f149 100644 --- a/src/client/haxe/ru/m/tankz/storage/RecordStorage.hx +++ b/src/client/haxe/ru/m/tankz/storage/RecordStorage.hx @@ -14,14 +14,22 @@ import ru.m.tankz.game.record.GameRecord; public function save(record:GameRecord):Void { L.d("RecordStorage", 'save $record'); - write(record.id, record); + write('${record.info.id}.info', record.info); + write(record.info.id, record); } - public function iterator():Iterator { + override public function delete(id:String):Void { + super.delete(id); + super.delete('${id}.info'); + } + + public function iterator():Iterator { var data:DynamicAccess = so.data; for (id in data.keys()) { try { - @yield return read(id); + if (StringTools.endsWith(id, '.info')) { + @yield return read(id); + } } catch (error:Dynamic) { L.w("RecordStorage", 'read ', error); delete(id); diff --git a/src/client/haxe/ru/m/tankz/view/GameFrame.hx b/src/client/haxe/ru/m/tankz/view/GameFrame.hx index c92fbe9..2aa59ee 100644 --- a/src/client/haxe/ru/m/tankz/view/GameFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/GameFrame.hx @@ -1,6 +1,5 @@ package ru.m.tankz.view; -import flash.events.Event; import haxe.ds.Option; import haxework.view.frame.FrameSwitcher; import haxework.view.VGroupView; @@ -51,8 +50,7 @@ import ru.m.tankz.view.game.GameView; private function start(state:GameState):Void { gameView.type = state.type; game = new Game(state); - game.connect(gameView.render); - game.engine.connect(gameView.render); + gameView.render.game = game; game.connect(soundManager); game.connect(this); if (gameView.panel != null) { @@ -63,15 +61,13 @@ import ru.m.tankz.view.game.GameView; game.connect(recorder); runner = new GameRunner(game); runner.start(state); - content.addEventListener(Event.ENTER_FRAME, _redraw); - gameView.render.draw(game.engine); + gameView.render.draw(); } private function play(record:GameRecord):Void { - gameView.type = record.type; + gameView.type = record.info.type; game = new Game(record.state); - game.connect(gameView.render); - game.engine.connect(gameView.render); + gameView.render.game = game; game.connect(soundManager); //game.connect(this); if (gameView.panel != null) { @@ -79,12 +75,10 @@ import ru.m.tankz.view.game.GameView; } player = new GamePlayer(game, record); player.start(); - content.addEventListener(Event.ENTER_FRAME, _redraw); - gameView.render.draw(game.engine); + gameView.render.draw(); } private function stop():Void { - content.removeEventListener(Event.ENTER_FRAME, _redraw); if (runner != null) { runner.dispose(); runner = null; @@ -122,10 +116,6 @@ import ru.m.tankz.view.game.GameView; stop(); } - private function _redraw(_):Void { - gameView.render.draw(game.engine); - } - public function close():Void { switcher.change(LevelFrame.ID); } diff --git a/src/client/haxe/ru/m/tankz/view/RecordFrame.hx b/src/client/haxe/ru/m/tankz/view/RecordFrame.hx index 308181c..93dfda6 100644 --- a/src/client/haxe/ru/m/tankz/view/RecordFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/RecordFrame.hx @@ -10,7 +10,7 @@ import ru.m.tankz.storage.RecordStorage; @:template class RecordFrame extends VGroupView { public static var ID(default, never):String = "record"; - @:view var data:VListView; + @:view var data:VListView; @:provide var recordStorage:RecordStorage; @:provide var switcher:FrameSwitcher; @@ -18,13 +18,12 @@ import ru.m.tankz.storage.RecordStorage; public function onShow():Void { var data = Lambda.array(recordStorage); - data.sort(function(a:GameRecord, b:GameRecord) return Std.int(b.date.getTime() - a.date.getTime())); + data.sort(function(a:GameRecordInfo, b:GameRecordInfo) return Std.int(b.date.getTime() - a.date.getTime())); this.data.data = data; } - private function onRecordSelect(item:IListItemView):Void { - //record = item.data; - //switcher.change(GameFrame.ID); + private function onRecordSelect(item:IListItemView):Void { + } private function close() { diff --git a/src/client/haxe/ru/m/tankz/view/common/RecordView.hx b/src/client/haxe/ru/m/tankz/view/common/RecordView.hx index ab09ce2..7570386 100644 --- a/src/client/haxe/ru/m/tankz/view/common/RecordView.hx +++ b/src/client/haxe/ru/m/tankz/view/common/RecordView.hx @@ -7,20 +7,20 @@ import haxework.view.list.ListView; import ru.m.tankz.game.record.GameRecord; import ru.m.tankz.storage.RecordStorage; -@:template class RecordView extends HGroupView implements IListItemView { +@:template class RecordView extends HGroupView implements IListItemView { @:view var date:LabelView; @:view var type:LabelView; @:view var level:LabelView; @:view var preset:LabelView; public var item_index(default, default):Int; - public var data(default, set):GameRecord; + public var data(default, set):GameRecordInfo; @:provide var recordStorage:RecordStorage; @:provide var switcher:FrameSwitcher; @:provide var record:GameRecord; - private function set_data(value:GameRecord):GameRecord { + private function set_data(value:GameRecordInfo):GameRecordInfo { if (data != value) { data = value; date.text = data.date.toString(); @@ -32,7 +32,7 @@ import ru.m.tankz.storage.RecordStorage; } private function play():Void { - record = data; + record = recordStorage.read(data.id); switcher.change(GameFrame.ID); } diff --git a/src/common/haxe/ru/m/geom/Position.hx b/src/common/haxe/ru/m/geom/Position.hx new file mode 100644 index 0000000..3b64cd2 --- /dev/null +++ b/src/common/haxe/ru/m/geom/Position.hx @@ -0,0 +1,7 @@ +package ru.m.geom; + +typedef Position = { + var x:Float; + var y:Float; + @:optional var direction:Direction; +} diff --git a/src/common/haxe/ru/m/geom/Rectangle.hx b/src/common/haxe/ru/m/geom/Rectangle.hx index 84a498a..f5c0456 100644 --- a/src/common/haxe/ru/m/geom/Rectangle.hx +++ b/src/common/haxe/ru/m/geom/Rectangle.hx @@ -11,6 +11,7 @@ class Rectangle { public var right(get, null):Float; public var top(get, null):Float; public var bottom(get, null):Float; + public var position(get, null):Position; public function new(x:Float, y:Float, width:Float, height:Float) { this.x = x; @@ -58,7 +59,7 @@ class Rectangle { } direction = value; } - return value; + return direction; } public function contain(point:Point):Bool { @@ -85,6 +86,12 @@ class Rectangle { } } + public function clone():Rectangle { + var rect = new Rectangle(x, y, width, height); + rect.direction = direction; + return rect; + } + public function toString():String { return 'Rectangle{x=$x,y=$y,width=$width,height=$height}'; } @@ -104,4 +111,8 @@ class Rectangle { function get_bottom():Float { return y + height; } + + private function get_position():Position { + return {x:x, y:y, direction:direction}; + } } diff --git a/src/common/haxe/ru/m/tankz/engine/Engine.hx b/src/common/haxe/ru/m/tankz/engine/Engine.hx index e8e91b4..9793f03 100755 --- a/src/common/haxe/ru/m/tankz/engine/Engine.hx +++ b/src/common/haxe/ru/m/tankz/engine/Engine.hx @@ -100,7 +100,6 @@ import ru.m.tankz.map.LevelMap; var collision:Bool = false; for (cell in cells) { if (cell.getCollision(entity.layer)) { - entity.rect.lean(cell.rect); collision = true; var with = EntityTypeResolver.of(cell); collisionSignal.emit(entityType, with); diff --git a/src/common/haxe/ru/m/tankz/game/Game.hx b/src/common/haxe/ru/m/tankz/game/Game.hx index 1148b25..29d4fd3 100644 --- a/src/common/haxe/ru/m/tankz/game/Game.hx +++ b/src/common/haxe/ru/m/tankz/game/Game.hx @@ -1,6 +1,7 @@ package ru.m.tankz.game; import ru.m.geom.Point; +import ru.m.geom.Position; import ru.m.tankz.bundle.IConfigBundle; import ru.m.tankz.config.Config; import ru.m.tankz.control.Control; diff --git a/src/common/haxe/ru/m/tankz/game/GameEvent.hx b/src/common/haxe/ru/m/tankz/game/GameEvent.hx index 3abafe6..7e415fe 100644 --- a/src/common/haxe/ru/m/tankz/game/GameEvent.hx +++ b/src/common/haxe/ru/m/tankz/game/GameEvent.hx @@ -1,15 +1,9 @@ package ru.m.tankz.game; -import ru.m.geom.Direction; +import ru.m.geom.Position; import ru.m.tankz.control.Control; import ru.m.tankz.Type; -typedef Position = { - var x:Float; - var y:Float; - @:optional var direction:Direction; -} - enum SpawnEvent { EAGLE(id:Int, position:Position, teamId:TeamId); TANK(id:Int, position:Position, playerId:PlayerId, type:TankType); @@ -41,7 +35,12 @@ enum MoveEvent { BULLET(id:Int, position:Position); } +enum StopEvent { + TANK(id:Int); +} + enum ChangeEvent { + TANK(id:Int, type:TankType, hits:Int, bonus:Bool); PLAYER_SCORE(playerId:PlayerId, value:Int); PLAYER_LIFE(playerId:PlayerId, value:Int); TEAM_SCORE(teamId:TeamId, value:Int); @@ -52,6 +51,7 @@ enum GameEvent { START(state:GameState); SPAWN(event:SpawnEvent); MOVE(event:MoveEvent); + STOP(event:StopEvent); HIT(event:HitEvent); DESTROY(event:DestroyEvent); CHANGE(event:ChangeEvent); diff --git a/src/common/haxe/ru/m/tankz/game/GameRunner.hx b/src/common/haxe/ru/m/tankz/game/GameRunner.hx index 5e21a5d..4ffa69f 100644 --- a/src/common/haxe/ru/m/tankz/game/GameRunner.hx +++ b/src/common/haxe/ru/m/tankz/game/GameRunner.hx @@ -1,10 +1,12 @@ package ru.m.tankz.game; +import ru.m.geom.Direction; import haxe.ds.Option; import haxe.Timer; import haxework.signal.Signal; import ru.m.geom.Line; import ru.m.geom.Point; +import ru.m.geom.Position; import ru.m.tankz.control.Control; import ru.m.tankz.control.Controller; import ru.m.tankz.control.IControlFactory; @@ -55,7 +57,7 @@ class GameRunner implements EngineListener implements GameListener { return { x: (point.x + 1) * game.config.map.cellWidth, y: (point.y + 1) * game.config.map.cellHeight, - direction: point.direction, + direction: Direction.fromString(point.direction), } } @@ -141,6 +143,14 @@ class GameRunner implements EngineListener implements GameListener { } } + 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}))); + } + + private inline function emitTankChange(tank:Tank):Void { + gameEventSignal.emit(GameEvent.CHANGE(TANK(tank.id, tank.config.type, tank.hits, tank.bonus))); + } + public function onCollision(entity:EntityType, with:EntityType):Void { switch entity { case EntityType.TANK(tank): @@ -151,8 +161,13 @@ class GameRunner implements EngineListener implements GameListener { switch [entity, with] { case [TANK(tank), TANK(other_tank)]: tank.rect.lean(other_tank.rect); + emitTankMove(tank); case [TANK(tank), EAGLE(eagle)]: tank.rect.lean(eagle.rect); + emitTankMove(tank); + case [TANK(tank), CELL(cell)]: + 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))); @@ -173,9 +188,11 @@ class GameRunner implements EngineListener implements GameListener { spawnBonus(); } gameEventSignal.emit(GameEvent.HIT(TANK(tank.id, buildShot(bullet)))); + emitTankChange(tank); } else if (tank.config.downgrade != null) { tank.config = game.config.getTank(tank.config.downgrade); gameEventSignal.emit(GameEvent.HIT(TANK(tank.id, buildShot(bullet)))); + emitTankChange(tank); } else { var score = tank.config.score; if (tank.playerId.team == bullet.playerId.team) { @@ -198,7 +215,7 @@ class GameRunner implements EngineListener implements GameListener { public function onMove(entity:EntityType):Void { switch entity { case TANK(tank): - gameEventSignal.emit(GameEvent.MOVE(TANK(tank.id, {x:tank.rect.x, y:tank.rect.y, direction:tank.rect.direction}))); + emitTankMove(tank); case BULLET(bullet): gameEventSignal.emit(GameEvent.MOVE(BULLET(bullet.id, {x:bullet.rect.x, y:bullet.rect.y, direction:bullet.rect.direction}))); case _: @@ -237,6 +254,8 @@ class GameRunner implements EngineListener implements GameListener { case "clock": for (t in game.engine.iterTanks(alienTank(tank.playerId.team))) { t.freezing.on(bonus.config.duration); + t.stop(); + gameEventSignal.emit(GameEvent.STOP(TANK(t.id))); } case "shovel": // ToDo: protect eagle/area @@ -260,6 +279,7 @@ class GameRunner implements EngineListener implements GameListener { } else { tank.hits++; } + emitTankChange(tank); } private function changeScore(playerId:PlayerId, score:Int):Void { @@ -305,6 +325,8 @@ class GameRunner implements EngineListener implements GameListener { } gameEventSignal.emit(GameEvent.SPAWN(BULLET(++entityId, position, tank.playerId))); } + case GameEvent.ACTION(tankId, STOP): + gameEventSignal.emit(GameEvent.STOP(TANK(tankId))); case GameEvent.SPAWN(TANK(_, _, playerId, _)): game.getPlayer(playerId).control.start(); case GameEvent.SPAWN(BULLET(_, _, playerId)): @@ -361,7 +383,7 @@ class GameRunner implements EngineListener implements GameListener { if (cell.armor == bullet.config.piercing) { gameEventSignal.emit(GameEvent.DESTROY(CELL(cell.cellX, cell.cellY, buildShot(bullet)))); } else if (cell.armor < bullet.config.piercing) { - var brick = game.engine.map.getBrick(cell); + var brick = game.engine.map.getBrick(cell.position); for (cell in brick.cells) { gameEventSignal.emit(GameEvent.DESTROY(CELL(cell.cellX, cell.cellY, buildShot(bullet)))); } diff --git a/src/common/haxe/ru/m/tankz/game/record/GameRecord.hx b/src/common/haxe/ru/m/tankz/game/record/GameRecord.hx index bdfc6e3..3b9f988 100644 --- a/src/common/haxe/ru/m/tankz/game/record/GameRecord.hx +++ b/src/common/haxe/ru/m/tankz/game/record/GameRecord.hx @@ -9,27 +9,33 @@ typedef EventItem = { event:GameEvent } -class GameRecord { +class GameRecordInfo { 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 function new() {} +} + +class GameRecord { + public var info(default, null):GameRecordInfo; public var events(default, default):Array; public var state(get, null):GameState; public function new() { - this.id = UUID.generateRandom(new Random()).toString(); - this.date = null; + this.info = new GameRecordInfo(); + this.info.id = UUID.generateRandom(new Random()).toString(); this.events = []; } private inline function get_state():GameState { - return new GameState(type, presetId, levelId); + return new GameState(info.type, info.presetId, info.levelId); } public function toString():String { - return 'GameRecord{id=$id,date=$date,type=$type,preset=$presetId,level=$levelId,events=${events.length}}'; + return 'GameRecord{id=${info.id},date=${info.date},type=${info.type},preset=${info.presetId},level=${info.levelId},events=${events.length}}'; } } diff --git a/src/common/haxe/ru/m/tankz/game/record/GameRecorder.hx b/src/common/haxe/ru/m/tankz/game/record/GameRecorder.hx index 0c47deb..fb5f793 100644 --- a/src/common/haxe/ru/m/tankz/game/record/GameRecorder.hx +++ b/src/common/haxe/ru/m/tankz/game/record/GameRecorder.hx @@ -17,9 +17,9 @@ class GameRecorder implements GameListener { public function onGameEvent(event:GameEvent):Void { switch event { case GameEvent.START(state): - record.type = state.type; - record.presetId = state.presetId; - record.levelId = state.levelId; + record.info.type = state.type; + record.info.presetId = state.presetId; + record.info.levelId = state.levelId; start(); case GameEvent.COMPLETE(_, _): stop(); @@ -30,7 +30,7 @@ class GameRecorder implements GameListener { public function start():Void { frame = 0; - record.date = Date.now(); + record.info.date = Date.now(); Lib.current.stage.addEventListener(Event.ENTER_FRAME, onEnterFrame); } diff --git a/src/common/haxe/ru/m/tankz/map/LevelMap.hx b/src/common/haxe/ru/m/tankz/map/LevelMap.hx index b6b321c..7c7aa35 100755 --- a/src/common/haxe/ru/m/tankz/map/LevelMap.hx +++ b/src/common/haxe/ru/m/tankz/map/LevelMap.hx @@ -62,8 +62,8 @@ class LevelMap { })); } - public function getBrick(cell:GridCell):Brick { - return bricksMap.get(cell.position); + public function getBrick(position:Point):Brick { + return bricksMap.get(position); } public function getPointBrick(point:Point):Brick { diff --git a/src/common/resources/classic/config.yaml b/src/common/resources/classic/config.yaml index 14a65ec..17d93dc 100644 --- a/src/common/resources/classic/config.yaml +++ b/src/common/resources/classic/config.yaml @@ -163,7 +163,7 @@ presets: - {<<: *team_human} - id: bot spawnInterval: 3000 - life: 1 + life: 10 players: - {<<: *bot, index: 0, control: bot-stupid} - {<<: *bot, index: 1, control: bot-stupid}