[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,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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}';
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user