5 Commits
0.2.1 ... 0.3.0

Author SHA1 Message Date
59cab68e3e [common] tanks spawn types 2018-02-02 20:53:26 +03:00
f9cb985059 [engine] update collision detect 2018-02-02 17:30:50 +03:00
6f338584eb [render] added animates 2018-02-01 00:05:14 +03:00
f2f860fc9d Merge branch 'develop' 2018-01-31 23:04:38 +03:00
3e65a5ba5d [cap] use master branch in production 2018-01-17 09:16:17 +03:00
21 changed files with 441 additions and 107 deletions

View File

@@ -10,4 +10,4 @@ user = fetch(:user)
server host, ssh_options: { port: 22, user: user, forward_agent: true } server host, ssh_options: { port: 22, user: user, forward_agent: true }
set :tmp_dir, "/home/#{user}/tmp" set :tmp_dir, "/home/#{user}/tmp"
set :branch, 'develop' set :branch, 'master'

View File

@@ -1,6 +1,6 @@
{ {
"name": "tankz", "name": "tankz",
"version": "0.2.1", "version": "0.3.0",
"private": true, "private": true,
"devDependencies": { "devDependencies": {
"ansi-colors": "^1.0.1", "ansi-colors": "^1.0.1",

View File

@@ -12,6 +12,7 @@
<haxelib name="protohx" version="0.4.6"/> <haxelib name="protohx" version="0.4.6"/>
<haxelib name="haxework" version="git"/> <haxelib name="haxework" version="git"/>
<haxelib name="yaml" version="1.3.0"/> <haxelib name="yaml" version="1.3.0"/>
<window fps="30"/>
<window width="1024" height="768" unless="html5"/> <window width="1024" height="768" unless="html5"/>
<haxeflag name="-D" value="swf-gpu"/> <haxeflag name="-D" value="swf-gpu"/>
<haxeflag name="-D" value="native-trace"/> <haxeflag name="-D" value="native-trace"/>

View File

@@ -0,0 +1,73 @@
package ru.m.animate;
import flash.display.PixelSnapping;
import haxe.Timer;
import flash.display.Bitmap;
import flash.display.BitmapData;
class Animate extends Bitmap {
private static var timer:Timer;
private static var instances:Array<Animate> = [];
private static function init():Void {
if (timer == null) {
timer = new Timer(30);
timer.run = updateAll;
}
}
private static function updateAll():Void {
for (instance in instances) {
if (instance.playing) {
instance.update();
}
}
}
private static var a = new BitmapData(1, 1);
public var playing(default, set):Bool;
public var frames(default, set):Array<BitmapData>;
private var index:Int;
public function new(?frames:Array<BitmapData>) {
super(null, PixelSnapping.AUTO, true);
this.frames = frames == null ? [] : frames;
init();
instances.push(this);
}
public function set_frames(value:Array<BitmapData>):Array<BitmapData> {
if (value != null) {
frames = value;
bitmapData = frames[0];
index = 0;
}
return frames;
}
public function set_playing(value:Bool):Bool {
if (playing != value) {
playing = value;
}
return playing;
}
private function update():Void {
if (++index >= frames.length) {
index = 0;
}
var nextBitmapData = frames[index];
x -= (nextBitmapData.width - bitmapData.width) / 2;
y -= (nextBitmapData.height - bitmapData.height) / 2;
bitmapData = nextBitmapData;
}
public function dispose():Void {
if (instances.indexOf(this) > -1) {
instances.remove(this);
}
}
}

View File

@@ -0,0 +1,31 @@
package ru.m.animate;
import promhx.Deferred;
import flash.display.BitmapData;
import promhx.Promise;
class OnceAnimate extends Animate {
private var deferred:Deferred<Animate>;
public function new(frames:Array<BitmapData>) {
super(frames);
}
public function play():Promise<Animate> {
deferred = new Deferred();
playing = true;
return deferred.promise();
}
override private function update():Void {
super.update();
if (index == 0) {
playing = false;
if (deferred != null) {
deferred.resolve(this);
}
}
}
}

View File

@@ -1,5 +1,8 @@
package ru.m.tankz.render; package ru.m.tankz.render;
import ru.m.geom.Point;
import openfl.Assets;
import ru.m.animate.OnceAnimate;
import flash.display.DisplayObjectContainer; import flash.display.DisplayObjectContainer;
import ru.m.tankz.core.EntityType; import ru.m.tankz.core.EntityType;
import flash.display.DisplayObject; import flash.display.DisplayObject;
@@ -19,20 +22,24 @@ class Render extends SpriteView implements EngineListener {
private var groundLayer:Sprite; private var groundLayer:Sprite;
private var entryLayer:Sprite; private var entryLayer:Sprite;
private var upLayer:Sprite; private var upLayer:Sprite;
private var upperLayer:Sprite;
private var background:Sprite; private var background:Sprite;
private var items:Map<String, RenderItem<Dynamic>>; private var items:Map<String, RenderItem<Dynamic, Dynamic>>;
public function new() { public function new() {
super(); super();
items = new Map();
backgroundLayer = new Sprite(); backgroundLayer = new Sprite();
groundLayer = new Sprite(); groundLayer = new Sprite();
entryLayer = new Sprite(); entryLayer = new Sprite();
upLayer = new Sprite(); upLayer = new Sprite();
upperLayer = new Sprite();
contentAsSprite.addChild(backgroundLayer); contentAsSprite.addChild(backgroundLayer);
contentAsSprite.addChild(groundLayer); contentAsSprite.addChild(groundLayer);
contentAsSprite.addChild(entryLayer); contentAsSprite.addChild(entryLayer);
contentAsSprite.addChild(upLayer); contentAsSprite.addChild(upLayer);
contentAsSprite.addChild(upperLayer);
reset(); reset();
} }
@@ -74,7 +81,10 @@ class Render extends SpriteView implements EngineListener {
} }
public function reset():Void { public function reset():Void {
items = new Map<String, RenderItem<Dynamic>>(); for (item in items.iterator()) {
item.dispose();
}
items = new Map();
if (background != null) { if (background != null) {
backgroundLayer.removeChild(background); backgroundLayer.removeChild(background);
background = null; background = null;
@@ -115,18 +125,51 @@ class Render extends SpriteView implements EngineListener {
if (items.exists(tank.key)) { if (items.exists(tank.key)) {
entryLayer.removeChild(items.get(tank.key).view); entryLayer.removeChild(items.get(tank.key).view);
items.remove(tank.key); items.remove(tank.key);
playTankBoom(tank.rect.center);
} }
case EntityType.BULLET(bullet): case EntityType.BULLET(bullet):
if (items.exists(bullet.key)) { if (items.exists(bullet.key)) {
entryLayer.removeChild(items.get(bullet.key).view); entryLayer.removeChild(items.get(bullet.key).view);
items.remove(bullet.key); items.remove(bullet.key);
playBulletBoom(bullet.rect.center.add(new Point(bullet.rect.width * bullet.rect.direction.x, bullet.rect.height * bullet.rect.direction.y)));
} }
case EntityType.EAGLE(eagle): case EntityType.EAGLE(eagle):
if (items.exists(eagle.key)) { if (items.exists(eagle.key)) {
cast(items.get(eagle.key), EagleItem).destoyed = true; cast(items.get(eagle.key), EagleItem).destoyed = true;
items.get(eagle.key).redraw(); items.get(eagle.key).redraw();
playTankBoom(eagle.rect.center);
} }
case _: case _:
} }
} }
private function playBulletBoom(point:Point):Void {
var arr = [
0, 1, 1, 0, 0, 1
];
var frames = [for (i in arr) Assets.getBitmapData('resources/images/bullet/boom/boom-${i}.png')];
var animate = new OnceAnimate(frames);
animate.x = point.x - animate.width / 2;
animate.y = point.y - animate.height / 2;
upperLayer.addChild(animate);
animate.play().then(function(animate) {
upperLayer.removeChild(animate);
animate.dispose();
});
}
private function playTankBoom(point:Point):Void {
var arr = [
0, 1, 2, 3, 4, 4, 4, 1, 4, 4, 7, 7, 8, 9, 9
];
var frames = [for (i in arr) Assets.getBitmapData('resources/images/tank/kaboom/kaboom-${i}.png')];
var animate = new OnceAnimate(frames);
animate.x = point.x - animate.width / 2;
animate.y = point.y - animate.height / 2;
upperLayer.addChild(animate);
animate.play().then(function(animate) {
upperLayer.removeChild(animate);
animate.dispose();
});
}
} }

View File

@@ -1,5 +1,6 @@
package ru.m.tankz.render; package ru.m.tankz.render;
import ru.m.animate.Animate;
import ru.m.tankz.core.Eagle; import ru.m.tankz.core.Eagle;
import flash.display.DisplayObject; import flash.display.DisplayObject;
import flash.display.Shape; import flash.display.Shape;
@@ -17,23 +18,17 @@ typedef TRectangle = {
} }
class RenderItem<T:TRectangle> { class RenderItem<T:TRectangle, D:DisplayObject> {
public var value(default, null):T; public var value(default, null):T;
public var view(default, null):DisplayObject; public var view(default, null):D;
private var bitmap:Bitmap;
public function new(value:T) { public function new(value:T) {
this.value = value; this.value = value;
this.bitmap = new Bitmap(); this.view = null;
this.view = bitmap;
redraw();
} }
public function redraw():Void { public function redraw():Void {}
bitmap.bitmapData = Assets.getBitmapData(getImage());
}
public function update():Void { public function update():Void {
var rect = value.rect; var rect = value.rect;
@@ -42,10 +37,6 @@ class RenderItem<T:TRectangle> {
view.y = rect.y - rect.height * (rect.direction.x + 1) / 2 - rect.height * (rect.direction.y + 1) / 2 + 1.5 * rect.height; 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 { private static function calcRotate(direction:Direction):Float {
return (if (direction == Direction.RIGHT) { return (if (direction == Direction.RIGHT) {
0; 0;
@@ -59,23 +50,42 @@ class RenderItem<T:TRectangle> {
0; 0;
}); });
} }
public function dispose():Void {}
} }
class BrickItem extends RenderItem<Brick> { 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 RenderItem<Brick, Shape> {
private var shape:Shape;
private var broken:Int; private var broken:Int;
public function new(value:Brick) { public function new(value:Brick) {
this.shape = new Shape();
super(value); super(value);
this.view = shape; this.view = new Shape();
redraw();
} }
override public function redraw():Void { override public function redraw():Void {
var image = Assets.getBitmapData(getImage()); var image = Assets.getBitmapData(getImage());
var g = shape.graphics; var g = view.graphics;
g.clear(); g.clear();
if (value.destroyed) return; if (value.destroyed) return;
g.beginBitmapFill(image); g.beginBitmapFill(image);
@@ -98,45 +108,71 @@ class BrickItem extends RenderItem<Brick> {
} }
} }
override private function getImage():String { private function getImage():String {
return 'resources/images/map/map_${value.config.type}.png'; return 'resources/images/map/map_${value.config.type}.png';
} }
} }
class TankItem extends RenderItem<Tank, Animate> {
class TankItem extends RenderItem<Tank> {
private var type:String; private var type:String;
private var hits:Int;
override private function getImage():String { public function new(value:Tank) {
super(value);
view = new Animate();
redraw();
}
override public function redraw():Void {
view.frames = getFrames().map(function(s) return Assets.getBitmapData(s));
}
private function getFrames():Array<String> {
var team = value.playerId.team;
var group = value.config.group; var group = value.config.group;
var index = value.playerId.index; var index = value.playerId.index;
if (group == 'human') group = 'player'; if (team == 'radiant') {
if (group == 'radiant') {
group = 'player';
index = 0; index = 0;
} }
if (group == 'dire') { if (team == 'dire') {
group = 'player';
index = 1; index = 1;
} }
if (group == 'bot') index = 0; if (team == 'human' || team == 'radiant' || team == 'dire') {
return 'resources/images/tank/${group}/tank_${group.charAt(0)}${value.config.type}_${index}-0.png'; group = 'player';
}
if (team == 'bot') {
index = value.hits;
}
return [
'resources/images/tank/${group}/tank_${group.charAt(0)}${value.config.type}_${index}-0.png',
'resources/images/tank/${group}/tank_${group.charAt(0)}${value.config.type}_${index}-1.png',
];
} }
override public function update():Void { override public function update():Void {
super.update(); super.update();
var t = value.config.type; var t = value.config.type;
if (t != this.type) { var h = value.hits;
if (t != this.type || h != this.hits) {
this.type = t; this.type = t;
this.hits = h;
redraw(); redraw();
} }
view.playing = (value.mx !=0 || value.my != 0);
}
override public function dispose():Void {
if (view != null) {
view.dispose();
view = null;
}
} }
} }
class BulletItem extends RenderItem<Bullet> { class BulletItem extends BitmapItem<Bullet> {
override private function getImage():String { override private function getImage():String {
return 'resources/images/bullet/bullet_${value.config.piercing > 1 ? 1 : 0}.png'; return 'resources/images/bullet/bullet_${value.config.piercing > 1 ? 1 : 0}.png';
@@ -144,7 +180,7 @@ class BulletItem extends RenderItem<Bullet> {
} }
class EagleItem extends RenderItem<Eagle> { class EagleItem extends BitmapItem<Eagle> {
public var destoyed(default, default):Bool; public var destoyed(default, default):Bool;

View File

@@ -24,7 +24,7 @@ class LevelFrame extends VGroupView implements ViewBuilder implements LevelFrame
public function onShow():Void { public function onShow():Void {
var state = Provider.get(GameState); var state = Provider.get(GameState);
var c = ConfigBundle.get(state.type).levels; var c = ConfigBundle.get(state.type).game.levels;
levels.data = [for (i in 0...c) i]; levels.data = [for (i in 0...c) i];
} }

View File

@@ -1,4 +1,6 @@
game:
levels: 36 levels: 36
friendlyFire: false
map: map:
cellWidth: 22 cellWidth: 22
@@ -39,6 +41,10 @@ bricks:
teams: teams:
- id: human - id: human
spawnInterval: 0 spawnInterval: 0
tanks:
- group: human
type: 0
rate: 1
points: points:
- type: eagle - type: eagle
index: -1 index: -1
@@ -57,6 +63,19 @@ teams:
direction: top direction: top
- id: bot - id: bot
spawnInterval: 3000 spawnInterval: 3000
tanks:
- group: bot
type: 0
rate: 0.5
- group: bot
type: 1
rate: 0.5
- group: bot
type: 2
rate: 0.5
- group: bot
type: 3
rate: 0.5
points: points:
- type: tank - type: tank
index: -1 index: -1
@@ -107,7 +126,7 @@ tanks:
bullet: bullet:
<<: *bullet <<: *bullet
speed: 9.0 speed: 9.0
bullets: 3 bullets: 2
- type: 3 - type: 3
width: 42 width: 42
@@ -159,4 +178,4 @@ tanks:
speed: 8.0 speed: 8.0
bullets: 1 bullets: 1
score: 400 score: 400
hits: 4 hits: 3

View File

@@ -1,4 +1,6 @@
levels: 36 game:
levels: 2
friendlyFire: true
map: map:
cellWidth: 22 cellWidth: 22
@@ -36,8 +38,24 @@ bricks:
layer: 2 layer: 2
armor: 1 armor: 1
team_tanks: &team_tanks
tanks:
- group: any
type: 0
rate: 0.25
- group: any
type: 1
rate: 0.25
- group: any
type: 2
rate: 0.25
# - group: any
# type: 3
# rate: 0.25
teams: teams:
- id: radiant - <<: *team_tanks
id: radiant
spawnInterval: 0 spawnInterval: 0
points: points:
- type: eagle - type: eagle
@@ -49,28 +67,29 @@ teams:
index: 0 index: 0
x: 0 x: 0
y: 0 y: 0
direction: top direction: right
- type: tank - type: tank
index: 1 index: 1
x: 6 x: 6
y: 10 y: 10
direction: top direction: right
- type: tank - type: tank
index: 2 index: 2
x: 6 x: 6
y: 16 y: 16
direction: top direction: right
- type: tank - type: tank
index: 3 index: 3
x: 6 x: 6
y: 22 y: 22
direction: top direction: right
- type: tank - type: tank
index: 4 index: 4
x: 10 x: 10
y: 28 y: 28
direction: top direction: right
- id: dire - <<: *team_tanks
id: dire
spawnInterval: 0 spawnInterval: 0
points: points:
- type: eagle - type: eagle
@@ -82,27 +101,27 @@ teams:
index: 0 index: 0
x: 38 x: 38
y: 28 y: 28
direction: bottom direction: left
- type: tank - type: tank
index: 1 index: 1
x: 32 x: 32
y: 18 y: 18
direction: bottom direction: left
- type: tank - type: tank
index: 2 index: 2
x: 32 x: 32
y: 12 y: 12
direction: bottom direction: left
- type: tank - type: tank
index: 3 index: 3
x: 32 x: 32
y: 6 y: 6
direction: bottom direction: left
- type: tank - type: tank
index: 4 index: 4
x: 28 x: 28
y: 0 y: 0
direction: bottom direction: left
bullet: &bullet bullet: &bullet
@@ -112,7 +131,7 @@ bullet: &bullet
piercing: 1 piercing: 1
tanks: tanks:
radiant: &tanks any:
- type: 0 - type: 0
width: 36 width: 36
height: 36 height: 36
@@ -130,5 +149,22 @@ tanks:
<<: *bullet <<: *bullet
speed: 8.5 speed: 8.5
bullets: 1 bullets: 1
dire:
- <<: *tanks - type: 2
width: 40
height: 36
speed: 3.0
bullet:
<<: *bullet
speed: 9.0
bullets: 2
- type: 3
width: 42
height: 38
speed: 2.9
bullet:
<<: *bullet
speed: 9.0
piercing: 3
bullets: 2

View File

@@ -0,0 +1,30 @@
0000000000000000000000000000000000004400
0000000000000000000000000000000000004400
0000000000000000000000000000000000004444
0000000000000000000000000000000000004444
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
4444000000000000000000000000000000000000
4444000000000000000000000000000000000000
0044000000000000000000000000000000000000
0044000000000000000000000000000000000000

View File

@@ -18,6 +18,10 @@ class Line {
); );
} }
public function move(point:Point):Line {
return new Line(point1.add(point), point2.add(point));
}
public function setLength(value:Float):Line { public function setLength(value:Float):Line {
var center = this.center; var center = this.center;
var width = point2.x - point1.x; var width = point2.x - point1.x;

View File

@@ -18,6 +18,6 @@ class Point {
} }
public function toString():String { public function toString():String {
return 'Point{x=$x,y=$y}'; return 'Point{x=${Math.round(x * 100) / 100},y=${Math.round(y * 100) / 100}}';
} }
} }

View File

@@ -11,6 +11,7 @@ class BotControl extends Control {
private var shotTimer:Timer; private var shotTimer:Timer;
private var turnTimer:Timer; private var turnTimer:Timer;
private var turnDelayTimer:Timer;
public function new(index:Int) { public function new(index:Int) {
super({type:TYPE, index:index}); super({type:TYPE, index:index});
@@ -18,22 +19,22 @@ class BotControl extends Control {
override public function onCollision(with:EntityType):Void { override public function onCollision(with:EntityType):Void {
switch (with) { switch (with) {
case EntityType.TANK(_): turn(); case EntityType.TANK(_): turnAfter(300);
case EntityType.CELL(_): turn(); case EntityType.CELL(_): turnAfter(300);
case _: case _:
} }
} }
override public function start():Void { override public function start():Void {
//var tank = handler.entities.get(tankId); if (handler == null) return;
//action(TankAction.MOVE(tank.rect.direction)); var tank = handler.entities.get(tankId);
action(TankAction.MOVE(Direction.BOTTOM)); // ToDo: hardcode bot start direction action(TankAction.MOVE(tank.rect.direction));
if (shotTimer == null) { if (shotTimer == null) {
shotTimer = new Timer(1000); shotTimer = new Timer(1000);
shotTimer.run = shot; shotTimer.run = shot;
} }
if (turnTimer == null) { if (turnTimer == null) {
turnTimer = new Timer(3000); turnTimer = new Timer(2000);
turnTimer.run = turn; turnTimer.run = turn;
} }
} }
@@ -53,6 +54,17 @@ class BotControl extends Control {
action(TankAction.SHOT); action(TankAction.SHOT);
} }
public function turnAfter(delay:Int):Void {
if (turnDelayTimer == null) {
turnDelayTimer = new Timer(delay);
turnDelayTimer.run = function() {
turnDelayTimer.stop();
turnDelayTimer = null;
turn();
}
}
}
public function turn():Void { public function turn():Void {
action(TankAction.MOVE(randomDirection())); action(TankAction.MOVE(randomDirection()));
} }

View File

@@ -1,6 +1,11 @@
package ru.m.tankz.config; package ru.m.tankz.config;
typedef GameConfig = {
var levels: Int;
var friendlyFire:Bool;
}
typedef SpawnPoint = { typedef SpawnPoint = {
var type:String; var type:String;
var index:Int; var index:Int;
@@ -41,6 +46,11 @@ typedef TankConfig = { > TankType,
var speed:Float; var speed:Float;
var bullet:BulletConfig; var bullet:BulletConfig;
var bullets:Int; var bullets:Int;
var hits:Int;
}
typedef TankSpawn = { > TankType,
var rate: Float;
} }
@@ -48,13 +58,14 @@ typedef TeamConfig = {
var id:String; var id:String;
var size:Int; var size:Int;
var spawnInterval:Int; var spawnInterval:Int;
var tanks:Array<TankSpawn>;
var points:Array<SpawnPoint>; var points:Array<SpawnPoint>;
} }
class Config { class Config {
public var type(default, null):String; public var type(default, null):String;
public var levels(default, null):Int; public var game(default, null):GameConfig;
public var map(default, null):MapConfig; public var map(default, null):MapConfig;
public var bricks(default, null):Array<BrickConfig>; public var bricks(default, null):Array<BrickConfig>;
public var tanks(default, null):Array<TankConfig>; public var tanks(default, null):Array<TankConfig>;
@@ -64,9 +75,9 @@ class Config {
private var tankMap:Map<String, Map<String, TankConfig>>; private var tankMap:Map<String, Map<String, TankConfig>>;
private var teamMap:Map<String, TeamConfig>; private var teamMap:Map<String, TeamConfig>;
public function new(type:String, levels:Int, map:MapConfig, bricks:Array<BrickConfig>, teams:Array<TeamConfig>, tanks:Array<TankConfig>) { public function new(type:String, game:GameConfig, map:MapConfig, bricks:Array<BrickConfig>, teams:Array<TeamConfig>, tanks:Array<TankConfig>) {
this.type = type; this.type = type;
this.levels = levels; this.game = game;
this.map = map; this.map = map;
this.bricks = bricks; this.bricks = bricks;
this.teams = teams; this.teams = teams;

View File

@@ -1,6 +1,5 @@
package ru.m.tankz.config; package ru.m.tankz.config;
import ru.m.tankz.game.ClassicGame;
import yaml.Parser; import yaml.Parser;
import openfl.Assets; import openfl.Assets;
import yaml.Yaml; import yaml.Yaml;
@@ -8,7 +7,7 @@ import ru.m.tankz.config.Config;
typedef ConfigSource = { typedef ConfigSource = {
var levels:Int; var game:GameConfig;
var map: MapConfig; var map: MapConfig;
var bricks: Array<BrickConfig>; var bricks: Array<BrickConfig>;
var teams: Array<TeamConfig>; var teams: Array<TeamConfig>;
@@ -31,6 +30,6 @@ class ConfigBundle {
tanks.push(item); tanks.push(item);
} }
} }
return new Config(type, source.levels, source.map, source.bricks, source.teams, tanks); return new Config(type, source.game, source.map, source.bricks, source.teams, tanks);
} }
} }

View File

@@ -11,6 +11,7 @@ import ru.m.geom.Direction;
class Tank extends MobileEntity { class Tank extends MobileEntity {
public var playerId(default, null):PlayerId; public var playerId(default, null):PlayerId;
public var config(default, set):TankConfig; public var config(default, set):TankConfig;
public var hits(default, default):Int;
private var bulletsCounter:Int = 0; private var bulletsCounter:Int = 0;
@@ -18,6 +19,7 @@ class Tank extends MobileEntity {
super(new Rectangle(0, 0, config.width, config.height), config.speed, Direction.RIGHT); super(new Rectangle(0, 0, config.width, config.height), config.speed, Direction.RIGHT);
this.playerId = playerId; this.playerId = playerId;
this.config = config; this.config = config;
this.hits = config.hits;
this.layer = 1; this.layer = 1;
} }

View File

@@ -1,5 +1,6 @@
package ru.m.tankz.engine; package ru.m.tankz.engine;
import ru.m.geom.Point;
import ru.m.geom.Line; import ru.m.geom.Line;
import ru.m.tankz.config.Config; import ru.m.tankz.config.Config;
import ru.m.tankz.control.Control; import ru.m.tankz.control.Control;
@@ -30,7 +31,16 @@ class CollisionProcessor implements EngineListener {
public function onSpawn(entity:EntityType):Void {} public function onSpawn(entity:EntityType):Void {}
private function checkTankBullet(tank:Tank, bullet:Bullet):Bool { private function checkTankBullet(tank:Tank, bullet:Bullet):Bool {
return tank.playerId.team != bullet.playerId.team; if (bullet.tankId == tank.id) return false;
return engine.config.game.friendlyFire || tank.playerId.team != bullet.playerId.team;
}
private function hitTank(tank:Tank):Void {
if (tank.hits > 0) {
tank.hits--;
} else {
engine.destroy(tank);
}
} }
public function onCollision(entity:EntityType, with:EntityType):Void { public function onCollision(entity:EntityType, with:EntityType):Void {
@@ -41,7 +51,7 @@ class CollisionProcessor implements EngineListener {
tank1.rect.lean(tank2.rect); tank1.rect.lean(tank2.rect);
case EntityType.BULLET(bullet2): case EntityType.BULLET(bullet2):
if (checkTankBullet(tank1, bullet2)) { if (checkTankBullet(tank1, bullet2)) {
engine.destroy(tank1); hitTank(tank1);
engine.destroy(bullet2); engine.destroy(bullet2);
} }
case EntityType.EAGLE(eagle): case EntityType.EAGLE(eagle):
@@ -54,7 +64,7 @@ class CollisionProcessor implements EngineListener {
case EntityType.TANK(tank2): case EntityType.TANK(tank2):
if (checkTankBullet(tank2, bullet1)) { if (checkTankBullet(tank2, bullet1)) {
engine.destroy(bullet1); engine.destroy(bullet1);
engine.destroy(tank2); hitTank(tank2);
} }
case EntityType.BULLET(bullet2): case EntityType.BULLET(bullet2):
engine.destroy(bullet1); engine.destroy(bullet1);
@@ -134,6 +144,8 @@ class Engine implements ControlHandler {
} }
} }
public function update():Void { public function update():Void {
var newTime:Float = Date.now().getTime(); var newTime:Float = Date.now().getTime();
var d:Float = newTime - time; var d:Float = newTime - time;
@@ -153,10 +165,15 @@ class Engine implements ControlHandler {
}*/ }*/
if (entity.mx != 0 || entity.my != 0) { if (entity.mx != 0 || entity.my != 0) {
entity.rect.x += entity.mx * (d / 30);
entity.rect.y += entity.my * (d / 30);
var side:Line = entity.rect.getSide(entity.rect.direction.reverse()); var side:Line = entity.rect.getSide(entity.rect.direction.reverse());
var step:Point = new Point(entity.rect.direction.x * map.cellWidth / 4, entity.rect.direction.y * map.cellHeight / 4);
var end:Point = side.center.add(new Point(entity.mx * (d / 30), entity.my * (d / 30)));
var c:Int = Math.floor(Math.abs(((end.x - side.center.x) / (map.cellWidth / 4) + (end.y - side.center.y) / (map.cellHeight / 4))));
var isStop:Bool = false;
while (c-- >= 0) {
side = side.move(step);
var cells = map.grid.getCells(side); var cells = map.grid.getCells(side);
var collision:Bool = false; var collision:Bool = false;
@@ -166,6 +183,7 @@ class Engine implements ControlHandler {
collision = true; collision = true;
var with = EntityTypeResolver.of(cell); var with = EntityTypeResolver.of(cell);
for (l in listeners) l.onCollision(entityType, with); for (l in listeners) l.onCollision(entityType, with);
isStop = true;
break; break;
} }
} }
@@ -175,6 +193,7 @@ class Engine implements ControlHandler {
if (other.rect.intersection2(side)) { if (other.rect.intersection2(side)) {
var with = EntityTypeResolver.of(other); var with = EntityTypeResolver.of(other);
for (l in listeners) l.onCollision(entityType, with); for (l in listeners) l.onCollision(entityType, with);
isStop = true;
} }
} }
} }
@@ -195,6 +214,14 @@ class Engine implements ControlHandler {
} }
} }
} }
if (isStop) break;
}
if (!isStop || Std.is(entity, Bullet)) {
entity.rect.x += entity.mx * (d / 30);
entity.rect.y += entity.my * (d / 30);
}
} }
} }
} }

View File

@@ -59,7 +59,7 @@ class ClassicGame extends Game {
override public function next():Option<GameState> { override public function next():Option<GameState> {
if (!state.teams[HUMAN].lose) { if (!state.teams[HUMAN].lose) {
state.level++; state.level++;
if (state.level >= config.levels) state.level = 0; if (state.level >= config.game.levels) state.level = 0;
state.teams[BOT].lose = false; state.teams[BOT].lose = false;
state.teams[BOT].life = BOT_LIFE; state.teams[BOT].life = BOT_LIFE;
for (ps in state.teams[HUMAN].players) { for (ps in state.teams[HUMAN].players) {

View File

@@ -1,5 +1,6 @@
package ru.m.tankz.game; package ru.m.tankz.game;
import haxe.ds.Option;
import ru.m.tankz.game.Game; import ru.m.tankz.game.Game;
import ru.m.tankz.game.GameState; import ru.m.tankz.game.GameState;
@@ -53,4 +54,10 @@ class DotaGame extends Game {
} }
return state; return state;
} }
override public function next():Option<GameState> {
state.level++;
if (state.level >= config.game.levels) state.level = 0;
return Option.Some(buildState(state.level, 0));
}
} }

View File

@@ -54,8 +54,11 @@ class Game implements EngineListener {
return teams.get(playerId.team).players[playerId.index]; return teams.get(playerId.team).players[playerId.index];
} }
private function buildTank(playerId:PlayerId, config:TankConfig, point:SpawnPoint):Tank { private function buildTank(playerId:PlayerId, point:SpawnPoint):Tank {
var tank = new Tank(playerId, config); var types:Array<TankSpawn> = teams[playerId.team].config.tanks;
var type:TankSpawn = types[Math.floor(Math.random() * types.length)];
var tankConfig:TankConfig = config.getTank(type.group, type.type);
var tank = new Tank(playerId, tankConfig);
applyPoint(tank, point); applyPoint(tank, point);
return tank; return tank;
} }
@@ -114,7 +117,7 @@ class Game implements EngineListener {
private function spawn(task:SpawnTask):Void { private function spawn(task:SpawnTask):Void {
getPlayer(task.playerId).tankId = 0; getPlayer(task.playerId).tankId = 0;
if (trySpawn(task.playerId, true)) { if (trySpawn(task.playerId, true)) {
var tank = buildTank(task.playerId, config.getTank(task.playerId.team, '0'), task.point); var tank = buildTank(task.playerId, task.point);
var player:Player = getPlayer(task.playerId); var player:Player = getPlayer(task.playerId);
engine.spawn(tank); engine.spawn(tank);
player.tankId = tank.id; player.tankId = tank.id;