[render] update

This commit is contained in:
2018-01-17 21:58:30 +03:00
parent 35404d5732
commit 507320414f
8 changed files with 219 additions and 226 deletions

View File

@@ -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;
}

View File

@@ -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,38 +34,9 @@ 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);
@@ -124,119 +46,49 @@ class Render extends SpriteView implements IRender {
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;
}
}
public function draw(game:Engine):Void {
invalidateLayers(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);
drawMap(game);
drawEntities(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;
}
}
}

View 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';
}
}

View File

@@ -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);
}

View File

@@ -10,24 +10,21 @@ class MobileEntity extends Entity {
public var layer(default, null):Int;
public var speed(default, null):Float;
public var direction(default, default):Direction;
public function new(rect:Rectangle, speed:Float, direction:Direction) {
super(rect);
this.speed = speed;
this.direction = direction;
this.layer = 0;
this.mx = 0;
this.my = 0;
}
public function move(direction:Direction):Void {
if (this.direction != direction) {
if (this.rect.direction != direction) {
this.rect.direction = direction;
this.direction = direction;
}
mx = direction.x * speed;
my = direction.y * speed;
mx = rect.direction.x * speed;
my = rect.direction.y * speed;
}
public function stop():Void {

View File

@@ -28,8 +28,9 @@ class Tank extends MobileEntity {
}
private function set_config(value:TankConfig):TankConfig {
var d = rect.direction;
rect = new Rectangle(rect.x, rect.y, value.width, value.height);
rect.direction = direction;
rect.direction = d;
speed = value.speed;
config = value;
return value;
@@ -38,8 +39,8 @@ class Tank extends MobileEntity {
public function shot():Null<Bullet> {
if (bulletsCounter >= config.bullets) return null;
var bullet = new Bullet(id, config, config.bullet);
bullet.rect.center = rect.center.add(new Point(rect.width / 4 * direction.x, rect.height / 4 * direction.y));
bullet.move(direction);
bullet.rect.center = rect.center.add(new Point(rect.width / 4 * rect.direction.x, rect.height / 4 * rect.direction.y));
bullet.move(rect.direction);
bulletsCounter++;
return bullet;
}

View File

@@ -39,7 +39,7 @@ class Engine {
private function buildTank(index:Int, config:TankConfig, point:SpawnPoint):Tank {
var tank = new Tank(index, config);
tank.rect.center = new Point((point.x + 1) * map.cellWidth, (point.y + 1) * map.cellHeight);
tank.direction = Direction.fromString(point.direction);
tank.rect.direction = Direction.fromString(point.direction);
return tank;
}
@@ -66,8 +66,8 @@ class Engine {
.setObjectId(tank.id)
.setX(tank.rect.x)
.setY(tank.rect.y)
.setDirectionX(tank.direction.x)
.setDirectionY(tank.direction.y)
.setDirectionX(tank.rect.direction.x)
.setDirectionY(tank.rect.direction.y)
);
}
@@ -214,7 +214,7 @@ class Engine {
}
for (other in entities.iterator()) {
if (other != ent) {
if (other != ent && other != null) {
if (other.rect.intersection2(side)) {
//if (ent.rect.intersection(other.rect)) {
var funName = 'collision${ent.type}${other.type}';

View File

@@ -24,6 +24,7 @@ class Brick implements IKey {
public var rect(default, null):Rectangle;
public var cells(default, null):HashMap<Point, GridCell>;
public var broken(get, null):Int;
public var destroyed(get, set):Bool;
public function new(mapConfig:MapConfig, config:BrickConfig, cellX:Int, cellY:Int, cells:HashMap<Point, GridCell>) {
@@ -40,6 +41,16 @@ class Brick implements IKey {
);
}
public function get_broken():Int {
var i:Int = 0;
for (c in cells.iterator()) {
if (c.destroyed) {
i++;
}
}
return i;
}
public function get_destroyed():Bool {
var i = 0;
var result:Bool = false;