units fight
RTS的な、ユニット同士の近接戦闘をイメージして作ってみました。
青いユニットがプレーヤー、緑のユニットが敵のイメージです。
画面上をクリックするとユニットが追加できます。
@author H.Horiuchi
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Graphics;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
[SWF(width = 465, height = 465, frameRate = 30, backgroundColor = "#ffffff")]
/**
* RTS的な、ユニット同士の近接戦闘をイメージして作ってみました。
* 青いユニットがプレーヤー、緑のユニットが敵のイメージです。
* 画面上をクリックするとユニットが追加できます。
* @author H.Horiuchi
*/
public class Main extends Sprite
{
private var movers1:Vector.<Mover> = new Vector.<Mover>();
private var movers2:Vector.<Mover> = new Vector.<Mover>();
private var board:BitmapData;
private var mdata1:BitmapData;
private var mdata2:BitmapData;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
mdata1 = create_bitmapdata1();
mdata2 = create_bitmapdata2();
for (var i:int = 0; i < 10; i++) {
movers1.push(new Mover(random_point(20, 445, 20, 200), Math.PI / 2, mdata1, 200, 10));
movers2.push(new Mover(random_point(20, 445, 265, 445), -Math.PI / 2, mdata2, 200, 10));
}
board = new BitmapData(this.stage.stageWidth, this.stage.stageHeight);
var screen:Bitmap = new Bitmap(board);
this.addChild(screen);
draw_movers();
this.stage.addEventListener(MouseEvent.CLICK, add_mover);
this.addEventListener(Event.ENTER_FRAME, on_enter_frame);
}
private function create_bitmapdata1():BitmapData
{
var base:Sprite = new Sprite();
base.graphics.lineStyle(1, 0, 1, true);
base.graphics.beginFill(0x3333ff);
base.graphics.drawRoundRect(1, 1, 38, 38, 30);
base.graphics.endFill();
var data:BitmapData = new BitmapData(40, 40, true, 0);
data.draw(base);
return data;
}
private function create_bitmapdata2():BitmapData
{
var base:Sprite = new Sprite();
base.graphics.lineStyle(1, 0, 1, true);
base.graphics.beginFill(0x33ff33);
base.graphics.drawRoundRect(1, 1, 38, 38, 20);
base.graphics.endFill();
var data:BitmapData = new BitmapData(40, 40, true, 0);
data.draw(base);
return data;
}
private function add_mover(event:MouseEvent):void
{
var x:Number = event.stageX;
if (x < 20) x = 20;
if (x > 445) x = 445;
var y:Number = event.stageY;
if (y <= this.stage.stageHeight / 2) {
if (y < 20) y = 20;
if (y > 200) y = 200;
movers1.push(new Mover(new Point(x, y), Math.PI / 2, mdata1, 200, 10));
trace("movers1 pushd.");
} else {
if (y < 265) y = 265;
if (y > 445) y = 445;
movers2.push(new Mover(new Point(x, y), -Math.PI / 2, mdata2, 200, 10));
trace("movers2 pushd.");
}
}
private function draw_movers():void
{
board.lock();
board.fillRect(board.rect, 0xFFFFFFFF);
//var g:Graphics = this.graphics;
//g.lineStyle(1);
var draw_mover:Function = function(m:Mover, i:int, v:Vector.<Mover>):void {
var p:Point = new Point(m.position.x - m.data.width / 2, m.position.y - m.data.height / 2);
board.copyPixels(m.data, m.data.rect, p, null, null, true);
//g.moveTo(m.position.x, m.position.y);
//var append:Point = Point.polar(30, m.angle);
//g.lineTo(m.position.x + append.x, m.position.y + append.y);
}
movers1.forEach(draw_mover);
movers2.forEach(draw_mover);
//board.draw(this);
board.unlock();
}
private function on_enter_frame(event:Event):void
{
// move
var next_movers1:Vector.<Mover> = move_movers(movers1, movers2);
var next_movers2:Vector.<Mover> = move_movers(movers2, movers1);
movers1 = next_movers1;
movers2 = next_movers2;
// attack
attack_movers(movers1, movers2);
attack_movers(movers2, movers1);
draw_movers();
if (movers2.length == 0 || movers1.length == 0) {
this.removeEventListener(Event.ENTER_FRAME, on_enter_frame);
var message:String = ((movers2.length == 0)? "player": "enemy") + " is WIN!";
var tf:TextField = new TextField();
tf.autoSize = TextFieldAutoSize.CENTER;
var format:TextFormat = new TextFormat();
format.size = 36;
format.bold = true;
tf.defaultTextFormat = format;
tf.text = message;
tf.x = (this.stage.stageWidth - tf.width) / 2;
tf.y = this.stage.stageHeight/ 2 - tf.height;
this.addChild(tf);
}
}
private function move_movers(target:Vector.<Mover>, opponent:Vector.<Mover>):Vector.<Mover>
{
var nexts:Vector.<Mover> = new Vector.<Mover>();
var center:Point = new Point(this.stage.stageWidth / 2, this.stage.stageHeight / 2);
for each (var m:Mover in target) {
var distance:Number = 300;
var length:Number = 2;
var angle:Number = get_angle(m.position, center);
for each (var o:Mover in opponent) {
var a:Number = get_angle(m.position, o.position);
var d:Number = Point.distance(m.position, o.position);
if (Math.abs(m.angle - a) < Math.PI / 6 && d < distance) {
distance = d;
length = 3;
angle = a;
} else if (Math.abs(m.angle - a) < Math.PI / 2 && d < distance * 2 / 3) {
distance = d * 3 / 2;
length = 2;
angle = a;
} else if (d < distance / 3) {
distance = d * 3;
length = 1;
angle = a;
}
}
if (length >= distance - 20) {
length = distance - 20;
}
var new_m:Mover = m.copy(m.position);
new_m.position = new_m.position.add(Point.polar(length, angle));
new_m.angle = angle;
nexts.push(new_m);
}
return nexts;
}
private function attack_movers(target:Vector.<Mover>, opponent:Vector.<Mover>):void
{
for each (var m:Mover in target) {
var nearest_index:int = -1;
var distance:Number = 20;
opponent.forEach(function(o:Mover, index:int, v:Vector.<Mover>):void {
var d:Number = Point.distance(m.position, o.position);
if (d < distance) {
nearest_index = index;
distance = d;
}
});
if (nearest_index >= 0) {
if (!opponent[nearest_index].damaged(m)) {
trace("unit dead.");
opponent.splice(nearest_index, 1);
}
}
}
}
private function get_angle(start:Point, target:Point):Number
{
return Math.atan2(target.y - start.y, target.x - start.x);
}
private function random_point(x_min:int, x_max:int, y_min:int, y_max:int):Point
{
return new Point(
rand(x_max - x_min) + x_min,
rand(y_max - y_min) + y_min
);
}
/**
* get random number in [0 to max).
* @param max
* @return random number
*/
private function rand(max:int):int
{
return Math.floor(Math.random() * max);
}
}
}
import flash.display.BitmapData;
import flash.geom.Point;
class Mover
{
public var position:Point;
public var angle:Number;
public var data:BitmapData;
public var max_hit_point:int;
public var now_hit_point:int;
public var attack:int;
public var defence:int;
public var range:int;
public function Mover(p:Point, angle:Number, data:BitmapData, hp:int, att:int, def:int = 0, r:int = 1):void
{
this.position = p;
this.angle = angle;
this.data = data;
this.max_hit_point = hp;
this.now_hit_point = hp;
this.attack = att;
this.defence = def;
this.range = r;
}
public function copy(p:Point):Mover
{
var copy:Mover = new Mover(p, this.angle, this.data, this.max_hit_point, this.attack, this.defence, this.range);
copy.now_hit_point = this.now_hit_point;
return copy;
}
public function damaged(enemy:Mover):Boolean
{
this.now_hit_point -= enemy.attack - this.defence;
return this.is_alive();
}
public function is_alive():Boolean
{
return this.now_hit_point > 0;
}
}