[render] update
This commit is contained in:
@@ -1,10 +0,0 @@
|
||||
package ru.m.tankz.render;
|
||||
|
||||
import ru.m.tankz.engine.Engine;
|
||||
import haxework.gui.IView;
|
||||
|
||||
|
||||
interface IRender extends IView {
|
||||
public function draw(game:Engine):Void;
|
||||
public function reset():Void;
|
||||
}
|
||||
@@ -1,12 +1,9 @@
|
||||
package ru.m.tankz.render;
|
||||
|
||||
import ru.m.tankz.core.MobileEntity;
|
||||
import flash.display.DisplayObject;
|
||||
import Type.ValueType;
|
||||
import ru.m.tankz.render.RenderItem;
|
||||
import ru.m.tankz.engine.Engine;
|
||||
import ru.m.tankz.core.Entity;
|
||||
import ru.m.tankz.map.Brick;
|
||||
import ru.m.geom.Direction;
|
||||
import flash.geom.Matrix;
|
||||
import openfl.Assets;
|
||||
import ru.m.tankz.core.Bullet;
|
||||
import ru.m.tankz.core.Tank;
|
||||
import flash.display.Sprite;
|
||||
@@ -14,64 +11,18 @@ import flash.display.Graphics;
|
||||
import haxework.gui.SpriteView;
|
||||
|
||||
|
||||
interface IState<T> {
|
||||
public function update(object:T):Bool;
|
||||
}
|
||||
|
||||
class BrickState implements IState<Brick> {
|
||||
private var type:Int;
|
||||
|
||||
public function new() {}
|
||||
|
||||
public function update(object:Brick):Bool {
|
||||
if (type != object.config.type) {
|
||||
type = object.config.type;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class EntityState implements IState<Entity> {
|
||||
private var x:Float;
|
||||
private var y:Float;
|
||||
private var d:Direction;
|
||||
private var type:Int;
|
||||
|
||||
public function new() {}
|
||||
|
||||
public function update(object:Entity):Bool {
|
||||
if (x != object.rect.x || y != object.rect.y || !d.equals(object.rect.direction)) {
|
||||
x = object.rect.x;
|
||||
y = object.rect.y;
|
||||
d = object.rect.direction;
|
||||
return true;
|
||||
}
|
||||
if (Std.is(object, Tank)) {
|
||||
var tank:Tank = cast object;
|
||||
if (tank.config.type != type) {
|
||||
type = tank.config.type;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Render extends SpriteView implements IRender {
|
||||
class Render extends SpriteView {
|
||||
|
||||
private var backgroundLayer:Sprite;
|
||||
private var groundLayer:Sprite;
|
||||
private var entryLayer:Sprite;
|
||||
private var upLayer:Sprite;
|
||||
|
||||
private var layersForUpdate:Map<Sprite, Bool>;
|
||||
private var states:Map<String, IState<Dynamic>>;
|
||||
private var background:Sprite;
|
||||
private var items:Map<String, RenderItem<Dynamic>>;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
layersForUpdate = new Map();
|
||||
backgroundLayer = new Sprite();
|
||||
groundLayer = new Sprite();
|
||||
entryLayer = new Sprite();
|
||||
@@ -83,160 +34,61 @@ class Render extends SpriteView implements IRender {
|
||||
reset();
|
||||
}
|
||||
|
||||
private function invalidateLayers(game:Engine):Void {
|
||||
for (brick in game.map.bricks) {
|
||||
if (!states.exists(brick.key)) {
|
||||
states[brick.key] = new BrickState();
|
||||
}
|
||||
if (states.get(brick.key).update(brick)) {
|
||||
layersForUpdate[groundLayer] = true;
|
||||
layersForUpdate[upLayer] = true;
|
||||
}
|
||||
}
|
||||
layersForUpdate[groundLayer] = true; //ToDo:
|
||||
for (entry in game.entities) {
|
||||
if (!states.exists(entry.key)) {
|
||||
states[entry.key] = new EntityState();
|
||||
}
|
||||
if (states.get(entry.key).update(entry)) {
|
||||
layersForUpdate[entryLayer] = true;
|
||||
}
|
||||
}
|
||||
for (key in game.removedEntities) {
|
||||
if (states.exists(key)) {
|
||||
states.remove(key);
|
||||
layersForUpdate[entryLayer] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function drawBackground(game:Engine):Void {
|
||||
var mapWidth = game.map.gridWidth * game.map.cellWidth;
|
||||
var mapHeight = game.map.gridHeight * game.map.cellHeight;
|
||||
|
||||
if (layersForUpdate[backgroundLayer]) {
|
||||
var g:Graphics = backgroundLayer.graphics;
|
||||
g.clear();
|
||||
g.beginFill(0x000000);
|
||||
g.drawRect(0, 0, mapWidth, mapHeight);
|
||||
g.endFill();
|
||||
if (contentSize) {
|
||||
width = mapWidth;
|
||||
height = mapHeight;
|
||||
}
|
||||
layersForUpdate[backgroundLayer] = false;
|
||||
}
|
||||
}
|
||||
|
||||
private function drawMap(game:Engine):Void {
|
||||
if (layersForUpdate[groundLayer] || layersForUpdate[upLayer]) {
|
||||
groundLayer.graphics.clear();
|
||||
upLayer.graphics.clear();
|
||||
for (brick in game.map.bricks) if (!brick.destroyed) {
|
||||
var g:Graphics = null;
|
||||
if (brick.config.layer < 3) {
|
||||
g = groundLayer.graphics;
|
||||
} else if (brick.config.layer >= 3) {
|
||||
g = upLayer.graphics;
|
||||
}
|
||||
if (g != null) {
|
||||
g.beginBitmapFill(Assets.getBitmapData('resources/images/map/map_${brick.config.type}.png'));
|
||||
g.drawRect(
|
||||
brick.rect.x,
|
||||
brick.rect.y,
|
||||
brick.rect.width,
|
||||
brick.rect.height
|
||||
);
|
||||
for (cell in brick.cells.iterator()) {
|
||||
if (cell.destroyed) {
|
||||
g.beginFill(0x000000);
|
||||
g.drawRect(
|
||||
cell.rect.x,
|
||||
cell.rect.y,
|
||||
cell.rect.width,
|
||||
cell.rect.height
|
||||
);
|
||||
}
|
||||
}
|
||||
g.endFill();
|
||||
}
|
||||
}
|
||||
|
||||
// Debug cells
|
||||
/*var g = groundLayer.graphics;
|
||||
for (c in game.map.grid.cells.iterator()) {
|
||||
var color:Int = 0x000000;
|
||||
if (c.armor == 1) {
|
||||
color = 0xffcc00;
|
||||
} else if (c.armor > 1) {
|
||||
color = 0x606060;
|
||||
} else if (c.layer == 0) {
|
||||
color = 0xffff90;
|
||||
} else if (c.layer == 1) {
|
||||
color = 0x0000ff;
|
||||
}else if (c.layer > 1) {
|
||||
color = 0x00ff00;
|
||||
}
|
||||
g.beginFill(color);
|
||||
g.drawRect(c.rect.x, c.rect.y, c.rect.width, c.rect.height);
|
||||
g.endFill();
|
||||
}
|
||||
layersForUpdate[groundLayer] = false;
|
||||
layersForUpdate[upLayer] = false;*/
|
||||
}
|
||||
}
|
||||
|
||||
public function drawEntities(game:Engine):Void {
|
||||
if (layersForUpdate[entryLayer]) {
|
||||
var g:Graphics = entryLayer.graphics;
|
||||
g.clear();
|
||||
for (ent in game.entities) {
|
||||
var image:String = null;
|
||||
if (Std.is(ent, Tank)) {
|
||||
var tank:Tank = cast ent;
|
||||
image = 'resources/images/tank/${tank.config.group}/tank_${tank.config.group.charAt(0)}${tank.config.type}_${tank.index}-0.png';
|
||||
} else if (Std.is(ent, Bullet)) {
|
||||
var bullet:Bullet = cast ent;
|
||||
image = 'resources/images/bullet/bullet_${bullet.config.piercing > 1 ? 1 : 0}.png';
|
||||
} else {
|
||||
image = 'ERROR'; // ToDo:
|
||||
}
|
||||
var m = new Matrix();
|
||||
if (Std.is(ent, MobileEntity)) {
|
||||
m.rotate(calcRotate(cast(ent, MobileEntity).direction));
|
||||
}
|
||||
m.translate(ent.rect.x, ent.rect.y);
|
||||
g.beginBitmapFill(Assets.getBitmapData(image), m, true, true);
|
||||
g.drawRect(ent.rect.x, ent.rect.y, ent.rect.width, ent.rect.height);
|
||||
g.endFill();
|
||||
}
|
||||
layersForUpdate[entryLayer] = false;
|
||||
var g:Graphics = backgroundLayer.graphics;
|
||||
g.clear();
|
||||
g.beginFill(0x000000);
|
||||
g.drawRect(0, 0, mapWidth, mapHeight);
|
||||
g.endFill();
|
||||
if (contentSize) {
|
||||
width = mapWidth;
|
||||
height = mapHeight;
|
||||
}
|
||||
}
|
||||
|
||||
public function draw(game:Engine):Void {
|
||||
invalidateLayers(game);
|
||||
drawBackground(game);
|
||||
drawMap(game);
|
||||
drawEntities(game);
|
||||
for (brick in game.map.bricks) {
|
||||
if (!items.exists(brick.key)) {
|
||||
items[brick.key] = new BrickItem(brick);
|
||||
if (brick.config.layer > 2) {
|
||||
upLayer.addChild(items[brick.key].view);
|
||||
} else {
|
||||
groundLayer.addChild(items[brick.key].view);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (entity in game.entities) {
|
||||
if (!items.exists(entity.key)) {
|
||||
items[entity.key] = switch (Type.typeof(entity)) {
|
||||
case ValueType.TClass(Tank): cast new TankItem(cast entity);
|
||||
case ValueType.TClass(Bullet): cast new BulletItem(cast entity);
|
||||
case x: null;
|
||||
}
|
||||
entryLayer.addChild(items[entity.key].view);
|
||||
}
|
||||
}
|
||||
for (key in game.removedEntities) {
|
||||
if (items.exists(key)) {
|
||||
var view:DisplayObject = items[key].view;
|
||||
view.parent.removeChild(view);
|
||||
items.remove(key);
|
||||
}
|
||||
}
|
||||
for (item in items) {
|
||||
item.update();
|
||||
}
|
||||
if (background == null) {
|
||||
drawBackground(game);
|
||||
}
|
||||
}
|
||||
|
||||
public function reset():Void {
|
||||
states = new Map<String, IState<Dynamic>>();
|
||||
layersForUpdate[backgroundLayer] = true;
|
||||
}
|
||||
|
||||
private function calcRotate(direction:Direction):Float {
|
||||
return (if (direction == Direction.RIGHT) {
|
||||
0;
|
||||
} else if (direction == Direction.LEFT) {
|
||||
180;
|
||||
} else if (direction == Direction.TOP) {
|
||||
270;
|
||||
} else if (direction == Direction.BOTTOM) {
|
||||
90;
|
||||
} else {
|
||||
0;
|
||||
}) * (Math.PI / 180);
|
||||
items = new Map<String, RenderItem<Dynamic>>();
|
||||
if (background != null) {
|
||||
backgroundLayer.removeChild(background);
|
||||
background = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
131
src/client/haxe/ru/m/tankz/render/RenderItem.hx
Normal file
131
src/client/haxe/ru/m/tankz/render/RenderItem.hx
Normal file
@@ -0,0 +1,131 @@
|
||||
package ru.m.tankz.render;
|
||||
|
||||
import flash.display.DisplayObject;
|
||||
import flash.display.Shape;
|
||||
import ru.m.geom.Direction;
|
||||
import ru.m.geom.Rectangle;
|
||||
import ru.m.tankz.core.Bullet;
|
||||
import ru.m.tankz.map.Brick;
|
||||
import openfl.Assets;
|
||||
import ru.m.tankz.core.Tank;
|
||||
import flash.display.Bitmap;
|
||||
|
||||
|
||||
typedef TRectangle = {
|
||||
var rect(default, null):Rectangle;
|
||||
}
|
||||
|
||||
|
||||
class RenderItem<T:TRectangle> {
|
||||
|
||||
public var value(default, null):T;
|
||||
public var view(default, null):DisplayObject;
|
||||
|
||||
private var bitmap:Bitmap;
|
||||
|
||||
public function new(value:T) {
|
||||
this.value = value;
|
||||
this.bitmap = new Bitmap();
|
||||
this.view = bitmap;
|
||||
redraw();
|
||||
}
|
||||
|
||||
public function redraw():Void {
|
||||
bitmap.bitmapData = Assets.getBitmapData(getImage());
|
||||
}
|
||||
|
||||
public function update():Void {
|
||||
var rect = value.rect;
|
||||
view.rotation = calcRotate(rect.direction);
|
||||
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;
|
||||
}
|
||||
|
||||
private function getImage():String {
|
||||
return 'ERROR';
|
||||
}
|
||||
|
||||
private static function calcRotate(direction:Direction):Float {
|
||||
return (if (direction == Direction.RIGHT) {
|
||||
0;
|
||||
} else if (direction == Direction.LEFT) {
|
||||
180;
|
||||
} else if (direction == Direction.TOP) {
|
||||
270;
|
||||
} else if (direction == Direction.BOTTOM) {
|
||||
90;
|
||||
} else {
|
||||
0;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class BrickItem extends RenderItem<Brick> {
|
||||
|
||||
private var shape:Shape;
|
||||
private var broken:Int;
|
||||
|
||||
public function new(value:Brick) {
|
||||
this.shape = new Shape();
|
||||
super(value);
|
||||
this.view = shape;
|
||||
}
|
||||
|
||||
override public function redraw():Void {
|
||||
var image = Assets.getBitmapData(getImage());
|
||||
var g = shape.graphics;
|
||||
g.clear();
|
||||
if (value.destroyed) return;
|
||||
g.beginBitmapFill(image);
|
||||
g.drawRect(0, 0, value.rect.width, value.rect.height);
|
||||
for (c in value.cells) {
|
||||
if (c.destroyed) {
|
||||
g.beginFill(0x000000);
|
||||
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;
|
||||
if (b != this.broken) {
|
||||
this.broken = b;
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
|
||||
override private function getImage():String {
|
||||
return 'resources/images/map/map_${value.config.type}.png';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class TankItem extends RenderItem<Tank> {
|
||||
|
||||
private var type:Int;
|
||||
|
||||
override private function getImage():String {
|
||||
return 'resources/images/tank/${value.config.group}/tank_${value.config.group.charAt(0)}${value.config.type}_${value.index}-0.png';
|
||||
}
|
||||
|
||||
override public function update():Void {
|
||||
super.update();
|
||||
var t = value.config.type;
|
||||
if (t != this.type) {
|
||||
this.type = t;
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class BulletItem extends RenderItem<Bullet> {
|
||||
|
||||
override private function getImage():String {
|
||||
return 'resources/images/bullet/bullet_${value.config.piercing > 1 ? 1 : 0}.png';
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package ru.m.tankz.view.frames;
|
||||
|
||||
import haxe.Timer;
|
||||
import ru.m.tankz.config.ConfigBundle;
|
||||
import ru.m.tankz.proto.core.GameType;
|
||||
import ru.m.tankz.proto.core.Game;
|
||||
@@ -23,6 +24,7 @@ class GameFrame extends VGroupView implements ViewBuilder implements IPacketHand
|
||||
|
||||
private var engine:Engine;
|
||||
private var controls:Map<Int, PlayerControl>;
|
||||
private var timer:Timer;
|
||||
|
||||
public function init():Void {
|
||||
engine = new Engine();
|
||||
@@ -33,24 +35,33 @@ class GameFrame extends VGroupView implements ViewBuilder implements IPacketHand
|
||||
var game:Game = Provider.get(Game);
|
||||
engine.init(ConfigBundle.get(GameType.CLASSIC, 0));
|
||||
engine.initTanks(game.players);
|
||||
content.addEventListener(Event.ENTER_FRAME, updateGame);
|
||||
content.addEventListener(Event.ENTER_FRAME, redraw);
|
||||
for (index in 0...game.players.length) {
|
||||
var playerId:Int = game.players[index].id;
|
||||
controls.set(playerId, PlayerControl.forPlayer(index, playerId, engine));
|
||||
}
|
||||
Provider.get(IConnection).packetHandler.addListener(this);
|
||||
render.draw(engine);
|
||||
timer = new Timer(10);
|
||||
timer.run = updateEngine;
|
||||
}
|
||||
|
||||
public function onHide():Void {
|
||||
Provider.get(IConnection).packetHandler.removeListener(this);
|
||||
content.removeEventListener(Event.ENTER_FRAME, updateGame);
|
||||
if (timer != null) {
|
||||
timer.stop();
|
||||
timer = null;
|
||||
}
|
||||
content.removeEventListener(Event.ENTER_FRAME, redraw);
|
||||
engine.clear();
|
||||
render.reset();
|
||||
}
|
||||
|
||||
private function updateGame(_):Void {
|
||||
private function updateEngine():Void {
|
||||
engine.update();
|
||||
}
|
||||
|
||||
private function redraw(_):Void {
|
||||
render.draw(engine);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user