[render] add protect view

This commit is contained in:
2019-05-17 16:10:10 +03:00
parent 96e608c36f
commit 11f8fc6190
17 changed files with 133 additions and 340 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "tankz",
"version": "0.10.0",
"version": "0.11.0",
"private": true,
"devDependencies": {
"dateformat": "^3.0.3",

View File

@@ -1,13 +1,8 @@
package ru.m.tankz.render;
import haxework.view.utils.BitmapUtil;
import haxework.color.Color;
import flash.display.BitmapData;
import openfl.Assets;
import ru.m.animate.Animate;
import ru.m.animate.OnceAnimate;
import ru.m.tankz.core.Tank;
import ru.m.tankz.Type;
class AnimateBundle {
@@ -44,27 +39,4 @@ class AnimateBundle {
length: 5
})]);
}
public static function tankFrames(tank:Tank):Array<Frame> {
var color:Color = switch (tank.hits) {
case 1: 0x869C43;
case 2: 0xDEAF80;
case 3: 0x5EA67A;
case _: tank.color;
}
var colors:Array<Color> = [color, color];
if (tank.bonus) {
colors[1] = 0xff00aa;
}
return [for (i in 0...2) ({
image: BitmapUtil.colorize(Assets.getBitmapData('resources/image/tank/${tank.config.skin}-${i}.png'), colors[i]),
length: 3
})];
}
public static function bonusFrames(type:BonusType):Array<Frame> {
var image = Assets.getBitmapData('resources/image/bonus/${type}.png');
var empty = new BitmapData(image.width, image.height, true, 0x00000000);
return [{image: image, length: 15}, {image: empty, length: 15}];
}
}

View File

@@ -167,6 +167,16 @@ class Render extends SpriteView implements IRender implements GameListener {
item.hits = hits;
item.bonus = bonus;
}
case CHANGE(TANK_PROTECT(id, state)):
if (items.exists(id)) {
var item:TankRenderItem = cast items[id];
item.protect = state;
}
case CHANGE(EAGLE_PROTECT(id, state)):
if (items.exists(id)) {
var item:EagleRenderItem = cast items[id];
item.protect = state;
}
case DESTROY(TANK(id, shot)):
if (items.exists(id)) {
var item = items[id];

View File

@@ -1,301 +0,0 @@
package ru.m.tankz.render;
import haxework.view.utils.BitmapUtil;
import flash.display.Bitmap;
import flash.display.DisplayObject;
import flash.display.Shape;
import flash.display.Sprite;
import openfl.Assets;
import ru.m.animate.Animate;
import ru.m.geom.Rectangle;
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.map.Brick;
import ru.m.tankz.Type.BrickType;
typedef TRectangle = {
var rect(default, null):Rectangle;
}
class RenderItem<T:TRectangle, D:DisplayObject> {
public var value(default, null):T;
public var view(default, null):D;
public function new(value:T) {
this.value = value;
this.view = null;
}
public function redraw():Void {}
public function update():Void {
var rect = value.rect;
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 dispose():Void {}
}
class BitmapItem<T:TRectangle> extends RenderItem<T, Bitmap> {
public function new(value:T) {
super(value);
this.view = new Bitmap();
redraw();
}
override public function redraw():Void {
view.bitmapData = Assets.getBitmapData(getImage());
}
private function getImage():String {
return 'ERROR';
}
}
class BrickItem extends BitmapItem<Brick> {
private var type:BrickType;
public function new(value:Brick) {
super(value);
redraw();
}
override public function update():Void {
super.update();
var t = value.config.type;
if (t != type) {
type = t;
view.visible = t != 'none';
redraw();
}
}
override private function getImage():String {
return 'resources/image/map/${value.config.type}.png';
}
}
class BrickAnimateItem extends AnimateItem<Brick> {
public function new(value:Brick) {
super(value);
redraw();
}
override public function redraw():Void {
view.frames = [for (i in 0...2) ({
image: Assets.getBitmapData('resources/image/map/${value.config.type}-${i}.png'),
length: 15
})];
view.playing = true;
}
}
class BrickBreakingItem extends RenderItem<Brick, Shape> {
private var broken:Int;
private var type:BrickType;
public function new(value:Brick) {
super(value);
this.view = new Shape();
redraw();
}
override public function redraw():Void {
var image = Assets.getBitmapData(getImage());
var g = view.graphics;
g.clear();
if (value.destroyed) return;
if (value.config.index > 0) {
g.beginBitmapFill(image);
//g.drawRect(0, 0, value.rect.width, value.rect.height);
for (c in value.cells) {
if (!c.destroyed) {
g.drawRect(c.rect.x - value.rect.x, c.rect.y - value.rect.y, c.rect.width, c.rect.height);
}
}
g.endFill();
}
}
override public function update():Void {
super.update();
var b = value.broken;
var t = value.config.type;
if (b != broken || t != type) {
broken = b;
type = t;
redraw();
}
}
private function getImage():String {
return 'resources/image/map/${value.config.type}.png';
}
}
class AnimateItem<T:TRectangle> extends RenderItem<T, Animate> {
public function new(value:T) {
super(value);
view = new Animate();
}
override public function dispose():Void {
view.dispose();
}
}
class TankItem extends RenderItem<Tank, Sprite> {
private var type:String;
private var hits:Int;
private var protected:Bool;
private var frozen:Bool;
private var tankView:Animate;
private var protectView:Animate;
public function new(value:Tank) {
super(value);
view = new Sprite();
tankView = new Animate();
view.addChild(tankView);
protectView = AnimateBundle.tankProtect();
protectView.visible = false;
view.addChild(protectView);
redraw();
}
override public function redraw():Void {
tankView.frames = AnimateBundle.tankFrames(value);
if (value.protect.active) {
protectView.x = (tankView.frames[0].image.width - protectView.frames[0].image.width) / 2;
protectView.y = (tankView.frames[0].image.height - protectView.frames[0].image.height) / 2;
protectView.playing = true;
protectView.visible = true;
} else {
protectView.playing = false;
protectView.visible = false;
}
}
private function getFrames():Array<String> {
var frame0 = 'resources/image/tank/${value.config.skin}-0.png';
var frame1 = 'resources/image/tank/${value.config.skin}-1.png';
return [frame1, frame0];
}
override public function update():Void {
super.update();
var t = value.config.type;
var h = value.hits;
var p = value.protect.active;
var f = value.freezing.active;
if (t != type || h != hits || p != protected || f != frozen) {
this.type = t;
this.hits = h;
this.protected = p;
this.frozen = f;
redraw();
}
tankView.playing = !value.freezing.active && (value.mx !=0 || value.my != 0);
}
override public function dispose():Void {
if (tankView != null) {
tankView.dispose();
tankView = null;
}
}
}
class BulletItem extends BitmapItem<Bullet> {
override private function getImage():String {
var type:String = 'normal';
if (value.config.piercing > 0) type = 'piercing';
return 'resources/image/bullet/${type}.png';
}
}
class EagleItem extends RenderItem<Eagle, Sprite> {
private var eagleView:Bitmap;
private var protectView:Animate;
private var death:Bool;
private var protected:Bool;
public function new(value:Eagle) {
super(value);
view = new Sprite();
eagleView = new Bitmap();
view.addChild(eagleView);
protectView = AnimateBundle.tankProtect();
protectView.visible = false;
view.addChild(protectView);
redraw();
}
override public function update():Void {
super.update();
var d = value.death;
var p = value.protect.active;
if (d != death || p != protected) {
death = d;
protected = p;
redraw();
}
}
private function getImage():String {
var suffix = value.death ? '-death' : '';
return 'resources/image/eagle/eagle${suffix}.png';
}
override public function redraw():Void {
var image = Assets.getBitmapData(getImage());
if (!value.color.zero) {
image = BitmapUtil.colorize(image, value.color);
}
eagleView.bitmapData = image;
if (value.protect.active) {
protectView.x = (image.width - protectView.frames[0].image.width) / 2;
protectView.y = (image.height - protectView.frames[0].image.height) / 2;
protectView.playing = true;
protectView.visible = true;
} else {
protectView.playing = false;
protectView.visible = false;
}
}
}
class BonusItem extends AnimateItem<Bonus> {
public function new(value:Bonus) {
super(value);
redraw();
}
override public function redraw():Void {
var image = Assets.getBitmapData('resources/image/bonus/${value.config.type}.png');
view.frames = AnimateBundle.bonusFrames(value.config.type);
view.playing = true;
}
}

View File

@@ -16,7 +16,6 @@ class BitmapRenderItem extends RenderItem {
public function new(rect:Rectangle) {
super(rect);
this.bitmap = new Bitmap(null, PixelSnapping.AUTO, true);
move(rect.position);
}
override private function get_view():DisplayObject {

View File

@@ -6,10 +6,12 @@ import ru.m.tankz.Type;
class BonusRenderItem extends BitmapRenderItem {
public var type(default, set):BonusType;
private var d = 0.1;
public function new(rect:Rectangle, type:BonusType) {
super(rect);
this.type = type;
move(rect.position);
}
private function set_type(value:BonusType):BonusType {
@@ -19,4 +21,12 @@ class BonusRenderItem extends BitmapRenderItem {
}
return type;
}
override public function update():Void {
super.update();
view.alpha += d;
if (view.alpha < 0 || view.alpha > 1.5) {
d = -d;
}
}
}

View File

@@ -1,10 +1,10 @@
package ru.m.tankz.render.item;
import ru.m.geom.Point;
import flash.display.BitmapData;
import flash.display.Shape;
import openfl.Assets;
import openfl.display.DisplayObject;
import ru.m.geom.Point;
import ru.m.geom.Rectangle;
import ru.m.tankz.Type.BrickType;

View File

@@ -8,6 +8,7 @@ class BulletRenderItem extends BitmapRenderItem {
public function new(rect:Rectangle, piercing:Int) {
super(rect);
this.piercing = piercing;
move(rect.position);
}
private function set_piercing(value:Int):Int {

View File

@@ -1,13 +1,43 @@
package ru.m.tankz.render.item;
import flash.display.DisplayObject;
import flash.display.Sprite;
import ru.m.animate.Animate;
import ru.m.geom.Rectangle;
class EagleRenderItem extends BitmapRenderItem {
public var death(default, set):Bool = true;
public var protect(default, set):Bool;
private var container:Sprite;
private var protectView:Animate;
public function new(rect:Rectangle) {
super(rect);
container = new Sprite();
container.addChild(bitmap);
protectView = AnimateBundle.tankProtect();
protectView.visible = false;
container.addChild(protectView);
death = false;
move(rect.position);
}
override private function get_view():DisplayObject {
return container;
}
private function set_protect(value:Bool):Bool {
if (protect != value) {
protect = value;
if (protect) {
protectView.x = (bitmapData.width - protectView.frames[0].image.width) / 2;
protectView.y = (bitmapData.height - protectView.frames[0].image.height) / 2;
}
protectView.visible = protect;
protectView.playing = protect;
}
return protect;
}
private function set_death(value:Bool):Bool {

View File

@@ -1,9 +1,12 @@
package ru.m.tankz.render.item;
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.display.BitmapData;
import haxework.color.Color;
import haxework.view.utils.BitmapUtil;
import openfl.Assets;
import ru.m.animate.Animate;
import ru.m.geom.Rectangle;
class TankRenderItem extends BitmapRenderItem {
@@ -12,15 +15,27 @@ class TankRenderItem extends BitmapRenderItem {
public var hits(default, set):Int;
public var bonus(default, set):Bool;
public var moves(default, set):Bool;
public var protect(default, set):Bool;
private var container:Sprite;
private var images:Array<BitmapData>;
private var frame:Int;
private var protectView:Animate;
public function new(rect:Rectangle) {
super(rect);
container = new Sprite();
container.addChild(bitmap);
protectView = AnimateBundle.tankProtect();
protectView.visible = false;
container.addChild(protectView);
move(rect.position);
}
override private function get_view():DisplayObject {
return container;
}
private function redraw():Void {
var image1 = Assets.getBitmapData('resources/image/tank/${skin}-0.png');
var image2 = Assets.getBitmapData('resources/image/tank/${skin}-1.png');
@@ -72,6 +87,19 @@ class TankRenderItem extends BitmapRenderItem {
return bonus;
}
private function set_protect(value:Bool):Bool {
if (protect != value) {
protect = value;
if (protect) {
protectView.x = (images[0].width - protectView.frames[0].image.width) / 2;
protectView.y = (images[0].height - protectView.frames[0].image.height) / 2;
}
protectView.visible = protect;
protectView.playing = protect;
}
return protect;
}
private function set_moves(value:Bool):Bool {
if (moves != value) {
moves = value;

View File

@@ -20,10 +20,15 @@ class Eagle extends Entity {
this.team = team;
this.config = config;
this.death = false;
this.protect = new Modificator();
this.protect = new Modificator(id);
}
private inline function get_score():Int {
return config != null ? config.score : 0;
}
override public function dispose() {
super.dispose();
protect.dispose();
}
}

View File

@@ -18,4 +18,6 @@ class Entity {
public function toString():String {
return '$type($id)';
}
public function dispose() {}
}

View File

@@ -1,26 +1,37 @@
package ru.m.tankz.core;
import haxe.Timer;
import haxework.signal.Signal;
class Modificator {
class Modificator extends Signal2<Int, Bool> {
public var id(default, default):Int;
public var active(default, default):Bool;
private var timer:Timer;
public function new() {
public function new(id) {
super();
this.id = id;
active = false;
}
override public function connect(receiver:Int->Bool->Void):Void {
super.connect(receiver);
receiver(id, active);
}
public function on(seconds:Float):Void {
off();
active = true;
timer = Timer.delay(off, Std.int(seconds * 1000));
emit(id, true);
}
public function off():Void {
if (timer != null) {
timer.stop();
timer = null;
emit(id, false);
}
active = false;
}

View File

@@ -17,8 +17,8 @@ class Tank extends MobileEntity {
public function new(id:Int, rect:Rectangle, playerId:PlayerId, config:TankConfig) {
super(id, rect, config.speed, Direction.RIGHT);
this.protect = new Modificator();
this.freezing = new Modificator();
this.protect = new Modificator(id);
this.freezing = new Modificator(id);
this.playerId = playerId;
this.config = config;
this.layer = 1;
@@ -39,4 +39,10 @@ class Tank extends MobileEntity {
super.move(direction);
}
}
override public function dispose() {
super.dispose();
protect.dispose();
freezing.dispose();
}
}

View File

@@ -140,7 +140,10 @@ import ru.m.tankz.map.LevelMap;
}
public function dispose():Void {
// ToDo: set to null
for (entity in allEntities) {
entity.dispose();
}
allEntities = new Map();
entities = new Map();
//map = null;
spawnSignal.dispose();

View File

@@ -58,6 +58,9 @@ enum StopEvent {
enum ChangeEvent {
TANK(id:Int, type:TankType, hits:Int, bonus:Bool);
TANK_PROTECT(id:Int, state:Bool);
TANK_FREEZE(id:Int, state:Bool);
EAGLE_PROTECT(id:Int, state:Bool);
PLAYER_SCORE(playerId:PlayerId, value:Int);
PLAYER_LIFE(playerId:PlayerId, value:Int);
TEAM_SCORE(teamId:TeamId, value:Int);

View File

@@ -1,7 +1,5 @@
package ru.m.tankz.game;
import ru.m.tankz.map.Grid.GridCell;
import ru.m.tankz.map.Brick;
import haxe.ds.Option;
import haxe.Timer;
import haxework.signal.Signal;
@@ -21,6 +19,7 @@ import ru.m.tankz.engine.IEngine;
import ru.m.tankz.game.GameEvent;
import ru.m.tankz.game.IGame;
import ru.m.tankz.game.Spawner;
import ru.m.tankz.map.Brick;
import ru.m.tankz.Type;
class GameRunner implements EngineListener implements GameListener {
@@ -85,6 +84,7 @@ class GameRunner implements EngineListener implements GameListener {
var eagle = builder.buildEagle(++entityId, point, team.id);
game.engine.spawn(eagle);
gameEventSignal.emit(GameEvent.SPAWN(EAGLE(eagle.id, eagle.rect, eagle.team)));
eagle.protect.connect(onEagleProtectChange);
}
}
var bricks = game.engine.map.bricks.map(function(item:Brick):BrickInfo {
@@ -115,6 +115,20 @@ class GameRunner implements EngineListener implements GameListener {
var tank = builder.buildTank(++entityId, task.point, task.playerId, task.tankType);
game.engine.spawn(tank);
gameEventSignal.emit(GameEvent.SPAWN(TANK(tank.id, tank.rect.clone(), tank.playerId, {type:tank.config.type, hits:tank.hits, bonus:tank.bonus})));
tank.protect.connect(onTankProtectChange);
tank.freezing.connect(onTankFreezingChange);
}
private function onEagleProtectChange(id:Int, state:Bool):Void {
gameEventSignal.emit(GameEvent.CHANGE(EAGLE_PROTECT(id, state)));
}
private function onTankProtectChange(id:Int, state:Bool):Void {
gameEventSignal.emit(GameEvent.CHANGE(TANK_PROTECT(id, state)));
}
private function onTankFreezingChange(id:Int, state:Bool):Void {
gameEventSignal.emit(GameEvent.CHANGE(TANK_FREEZE(id, state)));
}
private function checkComplete():Void {