[common] humans in DotaGame

This commit is contained in:
2018-02-04 21:02:08 +03:00
parent e0ceff68f9
commit 1c9ccf0fb8
12 changed files with 136 additions and 97 deletions

View File

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

View File

@@ -7,21 +7,45 @@
"contentSize": true, "bottomMargin": 15 "contentSize": true, "bottomMargin": 15
}, },
{ {
"id": "start_1p", "@type": "haxework.gui.LabelView", "@style": "label",
"fontSize": 20, "topMargin": 15,
"contentSize": true,
"text": "Classic"
},
{
"id": "classic_1p",
"@type": "haxework.gui.ButtonView", "@type": "haxework.gui.ButtonView",
"text": "1 Player", "text": "1 Player",
"@style": "button" "@style": "button"
}, },
{ {
"id": "start_2p", "id": "classic_2p",
"@type": "haxework.gui.ButtonView", "@type": "haxework.gui.ButtonView",
"text": "2 Player", "text": "2 Player",
"@style": "button" "@style": "button"
}, },
{ {
"id": "dota", "@type": "haxework.gui.LabelView", "@style": "label",
"fontSize": 20, "topMargin": 15,
"contentSize": true,
"text": "DotA"
},
{
"id": "dota_1p",
"@type": "haxework.gui.ButtonView", "@type": "haxework.gui.ButtonView",
"text": "DotA", "text": "1 Player",
"@style": "button"
},
{
"id": "dota_2p_coop",
"@type": "haxework.gui.ButtonView",
"text": "2 COOP",
"@style": "button"
},
{
"id": "dota_2p_vs",
"@type": "haxework.gui.ButtonView",
"text": "2 VS",
"@style": "button" "@style": "button"
} }
] ]

View File

@@ -13,14 +13,13 @@ typedef KeyBinding = Map<Int, TankAction>;
class HumanControl extends Control { class HumanControl extends Control {
public static var TYPE(default, never):ControlType = 'human';
private var keyBinding:KeyBinding; private var keyBinding:KeyBinding;
private var moveQueue:Array<Int>; private var moveQueue:Array<Int>;
private var shotTimer:Timer; private var shotTimer:Timer;
public function new(index:Int) { public function new(index:Int) {
super({type:TYPE, index:index}); super({type:Control.HUMAN, index:index});
this.keyBinding = resolve(index); this.keyBinding = resolve(index);
moveQueue = new Array<Int>(); moveQueue = new Array<Int>();
Lib.current.stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown); Lib.current.stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);

View File

@@ -5,12 +5,8 @@ import openfl.Assets;
import ru.m.animate.OnceAnimate; 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 Type.ValueType;
import ru.m.tankz.render.RenderItem; import ru.m.tankz.render.RenderItem;
import ru.m.tankz.engine.Engine; import ru.m.tankz.engine.Engine;
import ru.m.tankz.core.Bullet;
import ru.m.tankz.core.Tank;
import flash.display.Sprite; import flash.display.Sprite;
import flash.display.Graphics; import flash.display.Graphics;
import haxework.gui.SpriteView; import haxework.gui.SpriteView;

View File

@@ -1,5 +1,7 @@
package ru.m.tankz.render; package ru.m.tankz.render;
import ru.m.tankz.control.Control;
import flash.display.Sprite;
import ru.m.animate.Animate; 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;
@@ -114,19 +116,38 @@ class BrickItem extends RenderItem<Brick, Shape> {
} }
class TankItem extends RenderItem<Tank, Animate> { class TankItem extends RenderItem<Tank, Sprite> {
private var type:String; private var type:String;
private var hits:Int; private var hits:Int;
private var tankView:Animate;
public function new(value:Tank) { public function new(value:Tank) {
super(value); super(value);
view = new Animate(); view = new Sprite();
if (value.playerId.type == Control.HUMAN) {
view.addChild(buildHumanMarkView(value));
}
tankView = new Animate();
view.addChild(tankView);
redraw(); redraw();
} }
private static function buildHumanMarkView(tank:Tank):DisplayObject {
var view = new Shape();
view.graphics.beginFill(0x00aa00);
view.graphics.lineStyle(2, 0x00ff00);
view.graphics.drawCircle(0, 0, 23);
view.graphics.endFill();
view.x = tank.rect.width / 2;
view.y = tank.rect.height / 2;
view.alpha = 0.2;
return view;
}
override public function redraw():Void { override public function redraw():Void {
view.frames = getFrames().map(function(s) return Assets.getBitmapData(s)); tankView.frames = getFrames().map(function(s) return Assets.getBitmapData(s));
} }
private function getFrames():Array<String> { private function getFrames():Array<String> {
@@ -160,13 +181,13 @@ class TankItem extends RenderItem<Tank, Animate> {
this.hits = h; this.hits = h;
redraw(); redraw();
} }
view.playing = (value.mx !=0 || value.my != 0); tankView.playing = (value.mx !=0 || value.my != 0);
} }
override public function dispose():Void { override public function dispose():Void {
if (view != null) { if (tankView != null) {
view.dispose(); tankView.dispose();
view = null; tankView = null;
} }
} }
} }

View File

@@ -12,9 +12,11 @@ import haxework.gui.VGroupView;
interface StartFrameLayout { interface StartFrameLayout {
var start_1p(default, null):ButtonView; var classic_1p(default, null):ButtonView;
var start_2p(default, null):ButtonView; var classic_2p(default, null):ButtonView;
var dota(default, null):ButtonView; var dota_1p(default, null):ButtonView;
var dota_2p_coop(default, null):ButtonView;
var dota_2p_vs(default, null):ButtonView;
} }
@@ -24,29 +26,35 @@ class StartFrame extends VGroupView implements ViewBuilder implements StartFrame
public static inline var ID = "start"; public static inline var ID = "start";
public function init() { public function init() {
start_1p.onPress = this; classic_1p.onPress = this;
start_2p.onPress = this; classic_2p.onPress = this;
dota.onPress = this; dota_1p.onPress = this;
dota_2p_coop.onPress = this;
dota_2p_vs.onPress = this;
} }
public function onPress(view:ButtonView):Void { public function onPress(view:ButtonView):Void {
switch (view.id) { switch (view.id) {
case 'start_1p': case 'classic_1p':
startGame(ClassicGame.TYPE, 1); startGame(ClassicGame.TYPE, ClassicGame.PLAYER1);
case 'start_2p': case 'classic_2p':
startGame(ClassicGame.TYPE, 2); startGame(ClassicGame.TYPE, ClassicGame.PLAYER2);
case 'dota': case 'dota_1p':
startGame(DotaGame.TYPE, 2); startGame(DotaGame.TYPE, DotaGame.PLAYER1);
case 'dota_2p_coop':
startGame(DotaGame.TYPE, DotaGame.PLAYER2_COOP);
case 'dota_2p_vs':
startGame(DotaGame.TYPE, DotaGame.PLAYER2_VS);
} }
} }
private function startGame(type:GameType, humans:Int):Void { private function startGame(type:GameType, mode:GameMode):Void {
switch (type) { switch (type) {
case ClassicGame.TYPE: case ClassicGame.TYPE:
Provider.set(GameState, ClassicGame.buildState(0, humans)); Provider.set(GameState, ClassicGame.buildState(0, mode));
Provider.get(IFrameSwitcher).change(LevelFrame.ID); Provider.get(IFrameSwitcher).change(LevelFrame.ID);
case DotaGame.TYPE: case DotaGame.TYPE:
Provider.set(GameState, DotaGame.buildState(0, humans)); Provider.set(GameState, DotaGame.buildState(0, mode));
Provider.get(IFrameSwitcher).change(GameFrame.ID); Provider.get(IFrameSwitcher).change(GameFrame.ID);
} }
} }

View File

@@ -7,14 +7,13 @@ import haxe.Timer;
class BotControl extends Control { class BotControl extends Control {
public static var TYPE(default, never):ControlType = 'bot';
private var shotTimer:Timer; private var shotTimer:Timer;
private var turnRandomTimer:Timer; private var turnRandomTimer:Timer;
private var turnTimer:Timer; private var turnTimer:Timer;
public function new(index:Int) { public function new(index:Int) {
super({type:TYPE, index:index}); super({type:Control.BOT, index:index});
} }
override public function onCollision(with:EntityType):Void { override public function onCollision(with:EntityType):Void {

View File

@@ -23,6 +23,10 @@ typedef ControlId = {
class Control { class Control {
public static var NONE(default, never):ControlType = 'none';
public static var HUMAN(default, never):ControlType = 'human';
public static var BOT(default, never):ControlType = 'bot';
public var id:ControlId; public var id:ControlId;
public var tankId(default, default):Int; public var tankId(default, default):Int;
private var handler:ControlHandler; private var handler:ControlHandler;

View File

@@ -1,5 +1,6 @@
package ru.m.tankz.game; package ru.m.tankz.game;
import ru.m.tankz.control.Control;
import haxe.ds.Option; import haxe.ds.Option;
import ru.m.tankz.game.GameState.PlayerState; import ru.m.tankz.game.GameState.PlayerState;
import ru.m.tankz.game.Game; import ru.m.tankz.game.Game;
@@ -12,6 +13,9 @@ class ClassicGame extends Game {
public static var HUMAN(default, never):TeamId = 'human'; public static var HUMAN(default, never):TeamId = 'human';
public static var BOT(default, never):TeamId = 'bot'; public static var BOT(default, never):TeamId = 'bot';
public static var PLAYER1(default, never):GameMode = [{team:HUMAN, type:Control.HUMAN, index:0}];
public static var PLAYER2(default, never):GameMode = [{team:HUMAN, type:Control.HUMAN, index:0}, {team:HUMAN, type:Control.HUMAN, index:1}];
private static var HUMAN_LIFE(default, never):Int = 3; private static var HUMAN_LIFE(default, never):Int = 3;
private static var BOT_LIFE(default, never):Int = 20; private static var BOT_LIFE(default, never):Int = 20;
@@ -19,37 +23,22 @@ class ClassicGame extends Game {
super(TYPE); super(TYPE);
} }
public static function buildState(level:Int, humans:Int):GameState { public static function buildState(level:Int, mode:GameMode):GameState {
var state = new GameState(); var state = new GameState();
state.type = TYPE; state.type = TYPE;
state.mode = mode;
state.level = level; state.level = level;
state.teams[HUMAN] = {life: -1, players: new Map(), lose: false}; state.teams[HUMAN] = {life: -1, players: new Map(), lose: false};
state.teams[BOT] = {life: BOT_LIFE, players: new Map(), lose: false}; state.teams[BOT] = {life: BOT_LIFE, players: new Map(), lose: false};
for (i in 0...humans) { for (human in mode) {
state.teams[HUMAN].players[i] = { state.teams[HUMAN].players[human.index] = {
index:i, id:human,
tank:{
group: HUMAN,
type: '1'
},
control:{
type: 'human',
index: i
},
life:HUMAN_LIFE, life:HUMAN_LIFE,
}; };
} }
for (i in 0...humans*2+2) { for (i in 0...mode.length * 2 + 2) {
state.teams[BOT].players[i] = { state.teams[BOT].players[i] = {
index:i, id:{team:BOT, index:i, type:Control.BOT},
tank:{
group: BOT,
type: '1'
},
control:{
type: 'bot',
index: i
},
life:-1, life:-1,
}; };
} }

View File

@@ -1,5 +1,6 @@
package ru.m.tankz.game; package ru.m.tankz.game;
import ru.m.tankz.control.Control;
import haxe.ds.Option; 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;
@@ -12,52 +13,54 @@ class DotaGame extends Game {
public static var RADIANT(default, never):TeamId = 'radiant'; public static var RADIANT(default, never):TeamId = 'radiant';
public static var DIRE(default, never):TeamId = 'dire'; public static var DIRE(default, never):TeamId = 'dire';
public static var PLAYER1(default, never):GameMode = [
{team:RADIANT, type:Control.HUMAN, index:0}
];
public static var PLAYER2_COOP(default, never):GameMode = [
{team:RADIANT, type:Control.HUMAN, index:0},
{team:RADIANT, type:Control.HUMAN, index:1}
];
public static var PLAYER2_VS(default, never):GameMode = [
{team:RADIANT, type:Control.HUMAN, index:0},
{team:DIRE, type:Control.HUMAN, index:0}
];
private static var TEAM_SIZE(default, never):Int = 5; private static var TEAM_SIZE(default, never):Int = 5;
public function new() { public function new() {
super(TYPE); super(TYPE);
} }
public static function buildState(level:Int, humans:Int):GameState { public static function buildState(level:Int, mode:GameMode):GameState {
var state = new GameState(); var state = new GameState();
state.type = TYPE; state.type = TYPE;
state.mode = mode;
state.level = level; state.level = level;
state.teams[RADIANT] = {life: 20, players: new Map(), lose: false}; state.teams[RADIANT] = {life: 20, players: new Map(), lose: false};
state.teams[DIRE] = {life: 20, players: new Map(), lose: false}; state.teams[DIRE] = {life: 20, players: new Map(), lose: false};
for (i in 0...TEAM_SIZE) { for (i in 0...TEAM_SIZE) {
state.teams[RADIANT].players[i] = { state.teams[RADIANT].players[i] = {
index:i, id: {team:RADIANT, index:i, type:Control.BOT},
tank:{
group: RADIANT,
type: '1'
},
control:{
type: 'bot',
index: i
},
life: -1, life: -1,
}; };
} }
for (i in 0...TEAM_SIZE) { for (i in 0...TEAM_SIZE) {
state.teams[DIRE].players[i] = { state.teams[DIRE].players[i] = {
index:i, id: {team:DIRE, index:i, type:Control.BOT},
tank:{
group: DIRE,
type: '1'
},
control:{
type: 'bot',
index: i
},
life: -1, life: -1,
}; };
} }
for (human in mode) {
state.teams[human.team].players[human.index].id = human;
}
return state; return state;
} }
override public function next():Option<GameState> { override public function next():Option<GameState> {
state.level++; state.level++;
if (state.level >= config.game.levels) state.level = 0; if (state.level >= config.game.levels) state.level = 0;
return Option.Some(buildState(state.level, 0)); return Option.Some(buildState(state.level, state.mode));
} }
} }

View File

@@ -23,10 +23,13 @@ import ru.m.tankz.game.Spawner;
typedef GameType = String; typedef GameType = String;
typedef GameMode = Array<PlayerId>;
typedef TeamId = String; typedef TeamId = String;
typedef PlayerId = { typedef PlayerId = {
var team:TeamId; var team:TeamId;
var type:ControlType;
var index:Int; var index:Int;
} }
@@ -75,18 +78,19 @@ class Game implements EngineListener {
engine.map.setData(bricks); engine.map.setData(bricks);
teams = new Map<TeamId, Team>(); teams = new Map<TeamId, Team>();
spawners = new Map<TeamId, Spawner>(); spawners = new Map<TeamId, Spawner>();
var humanControlIndex = 0;
for (teamConfig in config.teams) { for (teamConfig in config.teams) {
var team = new Team(teamConfig); var team = new Team(teamConfig);
for (playerState in state.teams.get(team.id).players) { for (playerState in state.teams.get(team.id).players) {
var player = new Player({team:team.id, index:playerState.index}); var player = new Player(playerState.id);
team.players.push(player); team.players.push(player);
teams.set(team.id, team); teams.set(team.id, team);
if (playerState.control != null) { if (player.id.type != null) {
var control = switch (playerState.control.type) { var control = switch (player.id.type) {
case HumanControl.TYPE: new HumanControl(playerState.control.index); case Control.HUMAN: new HumanControl(humanControlIndex++);
case BotControl.TYPE: new BotControl(playerState.control.index); case Control.BOT: new BotControl(player.id.index);
case 'none': null; case Control.NONE: null;
case _: throw 'Unsupported control type: "${playerState.control.type}"'; case _: throw 'Unsupported control type: "${player.id.type}"';
} }
if (control != null) { if (control != null) {
player.control = control; player.control = control;

View File

@@ -1,23 +1,14 @@
package ru.m.tankz.game; package ru.m.tankz.game;
import ru.m.tankz.game.Game; import ru.m.tankz.game.Game;
import ru.m.tankz.config.Config;
typedef ControlType = String; typedef ControlType = String;
typedef ControId = {
var type:ControlType;
var index:Int;
}
typedef PlayerState = { typedef PlayerState = {
var index:Int; var id:PlayerId;
var tank:TankType;
var life:Int; var life:Int;
var control:ControId;
} }
@@ -30,6 +21,7 @@ typedef TeamState = {
class GameState { class GameState {
public var type:GameType; public var type:GameType;
public var mode:GameMode;
public var level:Int; public var level:Int;
public var teams:Map<TeamId, TeamState>; public var teams:Map<TeamId, TeamState>;