//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // al jazari Copyright (c) 2009 Dave Griffiths // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import flash.display.MovieClip; import flash.display.Sprite; import flash.events.MouseEvent; import flash.events.KeyboardEvent; import flash.events.Event; import flash.display.Stage; import flash.display.BitmapData; import flash.ui.Keyboard; import flash.media.Sound; import flash.net.URLRequest; import flash.media.SoundLoaderContext; class BlueCubeTex extends BitmapData { public function new() { super(0,0); } } class YellowCubeTex extends BitmapData { public function new() { super(0,0); } } class ThinkTex extends BitmapData { public function new() { super(0,0); } } // maybe I should have just modulated the colour - dunno how to do that... class BLeftTex extends BitmapData { public function new() { super(0,0); } } class BRightTex extends BitmapData { public function new() { super(0,0); } } class BForwardTex extends BitmapData { public function new() { super(0,0); } } class BBackwardTex extends BitmapData { public function new() { super(0,0); } } class BEmptyTex extends BitmapData { public function new() { super(0,0); } } class BBotNorthTex extends BitmapData { public function new() { super(0,0); } } class BBotSouthTex extends BitmapData { public function new() { super(0,0); } } class BBotEastTex extends BitmapData { public function new() { super(0,0); } } class BBotWestTex extends BitmapData { public function new() { super(0,0); } } class GLeftTex extends BitmapData { public function new() { super(0,0); } } class GRightTex extends BitmapData { public function new() { super(0,0); } } class GForwardTex extends BitmapData { public function new() { super(0,0); } } class GBackwardTex extends BitmapData { public function new() { super(0,0); } } class GEmptyTex extends BitmapData { public function new() { super(0,0); } } class GBotNorthTex extends BitmapData { public function new() { super(0,0); } } class GBotSouthTex extends BitmapData { public function new() { super(0,0); } } class GBotEastTex extends BitmapData { public function new() { super(0,0); } } class GBotWestTex extends BitmapData { public function new() { super(0,0); } } class YLeftTex extends BitmapData { public function new() { super(0,0); } } class YRightTex extends BitmapData { public function new() { super(0,0); } } class YForwardTex extends BitmapData { public function new() { super(0,0); } } class YBackwardTex extends BitmapData { public function new() { super(0,0); } } class YEmptyTex extends BitmapData { public function new() { super(0,0); } } class YBotNorthTex extends BitmapData { public function new() { super(0,0); } } class YBotSouthTex extends BitmapData { public function new() { super(0,0); } } class YBotEastTex extends BitmapData { public function new() { super(0,0); } } class YBotWestTex extends BitmapData { public function new() { super(0,0); } } class RLeftTex extends BitmapData { public function new() { super(0,0); } } class RRightTex extends BitmapData { public function new() { super(0,0); } } class RForwardTex extends BitmapData { public function new() { super(0,0); } } class RBackwardTex extends BitmapData { public function new() { super(0,0); } } class REmptyTex extends BitmapData { public function new() { super(0,0); } } class RBotNorthTex extends BitmapData { public function new() { super(0,0); } } class RBotSouthTex extends BitmapData { public function new() { super(0,0); } } class RBotEastTex extends BitmapData { public function new() { super(0,0); } } class RBotWestTex extends BitmapData { public function new() { super(0,0); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class Vec3 { public var x:Float; public var y:Float; public var z:Float; public function new(px:Float, py:Float, pz:Float) { x=px; y=py; z=pz; } public function Mag() : Float { return Math.sqrt(x*x+y*y+z*z); } public function Lerp(other:Vec3,t:Float) : Vec3 { return new Vec3(x*(1-t) + other.x*t, y*(1-t) + other.y*t, z*(1-t) + other.z*t); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class Button extends Sprite { public var m_Pos:Vec3; public function new(pos:Vec3, size:Vec3, bitmapData:BitmapData, f: Dynamic -> Void ) { super(); graphics.beginBitmapFill(bitmapData); graphics.drawRect(0,0,size.x,size.y); graphics.endFill(); addEventListener(MouseEvent.MOUSE_DOWN, f); x=pos.x; y=pos.y; } public function ChangeBitmap(bitmapData:BitmapData) { graphics.clear(); graphics.beginBitmapFill(bitmapData); graphics.drawRect(0,0,64,64); graphics.endFill(); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class MultiButton extends Button { public var m_State:Int; public var m_Bitmaps:Array; public function new(pos:Vec3, size:Vec3, bitmaps:Array) { super(pos,size,bitmaps[0],Click); m_State=0; m_Bitmaps=bitmaps; } public function SetState(s:Int) { m_State=s; ChangeBitmap(m_Bitmaps[m_State]); } function Click(_) { m_State++; if (m_State>=m_Bitmaps.length) { m_State=0; } ChangeBitmap(m_Bitmaps[m_State]); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class Entity extends Sprite { public var m_Pos:Vec3; public function new(pos:Vec3, bitmapData:BitmapData) { super(); ChangeBitmap(bitmapData); m_Pos=pos; UpdatePos(); } public function MouseDown(f:Dynamic -> Void=null) { addEventListener(MouseEvent.MOUSE_DOWN, f); } public function ChangeBitmap(bitmapData:BitmapData) { graphics.clear(); graphics.beginBitmapFill(bitmapData); graphics.drawRect(0,0,64,64); graphics.endFill(); } public function Pos2PixelPos(pos:Vec3) : Vec3 { // do the nasty iso conversion return new Vec3(250+(pos.x*36-pos.y*26),220+(pos.y*18+pos.x*9)-(pos.z*37),0); } public function UpdatePos() { var pos = Pos2PixelPos(m_Pos); x=pos.x; y=pos.y; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class AnimatedEntity extends Entity { public var m_SrcPos:Vec3; public var m_DestPos:Vec3; public var m_Time:Float; public var m_Speed:Float; public function new(pos:Vec3, bitmapData:BitmapData) { super(pos, bitmapData); m_Time=10; m_Speed=0; } public function MoveTo(pos:Vec3,speed:Float) { m_SrcPos=m_Pos; m_DestPos=pos; m_Time=0; m_Speed=speed; } public function Update(frame:Int, world:World) { if (m_Time<1) { m_Time+=m_Speed; if (m_Time>1) m_Time=1; m_Pos=m_SrcPos.Lerp(m_DestPos,m_Time); UpdatePos(); } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class Cube extends Entity { var m_Trigger:Bool; public function new(trigger:Bool, pos:Vec3) { m_Trigger=trigger; if (m_Trigger) { super(pos, new YellowCubeTex()); } else { super(pos, new BlueCubeTex()); } MouseDown(Flip); } function Flip(_) { m_Trigger=!m_Trigger; if (m_Trigger) ChangeBitmap(new YellowCubeTex()); else ChangeBitmap(new BlueCubeTex()); } public function IsTrigger(): Bool { return m_Trigger; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class PlayerEntity extends Entity { public function new(pos:Vec3) { super(pos, new BlueCubeTex()); } public function Update(frame:Int, world:World) { } public function Handle(e:KeyboardEvent) { if (e.keyCode==Keyboard.LEFT) m_Pos.x+=1; if (e.keyCode==Keyboard.RIGHT) m_Pos.x-=1; if (e.keyCode==Keyboard.UP) m_Pos.y+=1; if (e.keyCode==Keyboard.DOWN) m_Pos.y-=1; UpdatePos(); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class RobotEntity extends AnimatedEntity { var m_Code:Array; var m_NextTime:Int; var m_Tick:Int; var m_PC:Int; var m_LogicalPos:Vec3; var m_Dir:Int; var m_ID:Int; public function new(i:Int, pos:Vec3) { m_ID=i; m_Dir=i; super(pos, GetTex(m_Dir)); m_LogicalPos=pos; m_Code = new Array(); m_NextTime=0; m_Tick=10; m_PC=0; } public function SetCode(c:Array) { m_Code=c; } public function GetCode():Array { return m_Code; } public function GetPos():Vec3 { return m_LogicalPos; } function GetTex(dir:Int): BitmapData { if (m_ID==0) { if (dir==0) return new BBotNorthTex(); if (dir==1) return new BBotEastTex(); if (dir==2) return new BBotSouthTex(); if (dir==3) return new BBotWestTex(); } if (m_ID==1) { if (dir==0) return new RBotNorthTex(); if (dir==1) return new RBotEastTex(); if (dir==2) return new RBotSouthTex(); if (dir==3) return new RBotWestTex(); } if (m_ID==2) { if (dir==0) return new YBotNorthTex(); if (dir==1) return new YBotEastTex(); if (dir==2) return new YBotSouthTex(); if (dir==3) return new YBotWestTex(); } if (m_ID==3) { if (dir==0) return new GBotNorthTex(); if (dir==1) return new GBotEastTex(); if (dir==2) return new GBotSouthTex(); if (dir==3) return new GBotWestTex(); } return null; } override function Update(frame:Int, world:World) { if (frame>m_NextTime) { if (m_PC>=m_Code.length) { m_PC=0; } var moved:Bool = false; if (m_Code.length>0) { if (m_Code[m_PC]==1) { var t:Vec3 = new Vec3(m_LogicalPos.x,m_LogicalPos.y,m_LogicalPos.z); if (m_Dir==0) t.x-=1; if (m_Dir==1) t.y-=1; if (m_Dir==2) t.x+=1; if (m_Dir==3) t.y+=1; // see if there is another robot here if (!world.CheckCube(t)) { moved=true; m_LogicalPos=t; } } if (m_Code[m_PC]==2) { var t:Vec3 = new Vec3(m_LogicalPos.x,m_LogicalPos.y,m_LogicalPos.z); if (m_Dir==0) t.x+=1; if (m_Dir==1) t.y+=1; if (m_Dir==2) t.x-=1; if (m_Dir==3) t.y-=1; // see if there is another robot here if (!world.CheckCube(t)) { moved=true; m_LogicalPos=t; } } if (m_Code[m_PC]==3) m_Dir-=1; if (m_Code[m_PC]==4) m_Dir+=1; if (m_Dir<0) m_Dir=3; if (m_Dir>3) m_Dir=0; ChangeBitmap(GetTex(m_Dir)); if (m_LogicalPos.x<0) m_LogicalPos.x=0; if (m_LogicalPos.y<0) m_LogicalPos.y=0; if (m_LogicalPos.x>=world.m_Width) m_LogicalPos.x=world.m_Width-1; if (m_LogicalPos.y>=world.m_Height) m_LogicalPos.y=world.m_Height-1; if (moved && world.GetCube(m_LogicalPos).IsTrigger()) { world.m_SoundPlayer.Play((cast(m_LogicalPos.y,Int)%4) + m_ID*4); } MoveTo(m_LogicalPos,0.1); } m_PC++; m_NextTime+=m_Tick; } super.Update(frame,world); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class SoundPlayer { var m_Sounds:Array; public function new(sounds:Array) { m_Sounds = []; for (i in 0...sounds.length) { LoadSound(sounds[i]); } } function LoadSound(filename) { var sound: Sound = new Sound(); var req:URLRequest = new URLRequest(filename); var context:SoundLoaderContext = new SoundLoaderContext(8000,true); //sound.addEventListener(Event.COMPLETE, SoundLoaded); sound.load(req,context); m_Sounds.push(sound); } public function Play(id:Int) { if (id; var m_Pos:Vec3; public function new(pos:Vec3) { super(); m_Pos=pos; m_Buttons = []; var bg:Sprite = new Sprite(); bg.graphics.beginBitmapFill(new ThinkTex()); bg.graphics.drawRect(0,0,350,220); bg.x=pos.x; bg.y=pos.y; addChild(bg); BuildButtons(0); } public function BuildButtons(i:Int) { var ba:Array = []; // arg... if (i==0) { ba.push(new BEmptyTex()); ba.push(new BForwardTex()); ba.push(new BBackwardTex()); ba.push(new BLeftTex()); ba.push(new BRightTex()); } if (i==1) { ba.push(new REmptyTex()); ba.push(new RForwardTex()); ba.push(new RBackwardTex()); ba.push(new RLeftTex()); ba.push(new RRightTex()); } if (i==2) { ba.push(new YEmptyTex()); ba.push(new YForwardTex()); ba.push(new YBackwardTex()); ba.push(new YLeftTex()); ba.push(new YRightTex()); } if (i==3) { ba.push(new GEmptyTex()); ba.push(new GForwardTex()); ba.push(new GBackwardTex()); ba.push(new GLeftTex()); ba.push(new GRightTex()); } for (y in 0...2) { for (x in 0...4) { var mb = new MultiButton(new Vec3(50+m_Pos.x+x*64,40+m_Pos.y+y*64,0),new Vec3(64,64,0),ba); m_Buttons.push(mb); addChild(mb); } } } public function ChangeBot(i:Int) { for (i in 0...8) { removeChild(m_Buttons[i]); } m_Buttons=[]; BuildButtons(i); } public function GetCode() : Array { var r:Array = [0,0,0,0,0,0,0,0]; for (i in 0...8) { r[i]=m_Buttons[i].m_State; } return r; } public function SetCode(i:Int,code:Array) { ChangeBot(i); for (i in 0...8) { m_Buttons[i].SetState(code[i]); } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class World extends MovieClip { public var m_Width:Int; public var m_Height:Int; public var m_SoundPlayer:SoundPlayer; var m_Objs:Array; var m_Robots:Array; var m_Code:Code; var m_CurrentRobot:Int; public function new(w:Int, h:Int) { super(); m_Width=w; m_Height=h; m_Objs = new Array(); m_SoundPlayer = new SoundPlayer(["sounds/clap.mp3", "sounds/kick.mp3", "sounds/hh0.mp3", "sounds/hhc.mp3", "sounds/11.mp3", "sounds/12.mp3", "sounds/13.mp3", "sounds/14.mp3", "sounds/21.mp3", "sounds/22.mp3", "sounds/23.mp3", "sounds/24.mp3", "sounds/31.mp3", "sounds/32.mp3", "sounds/33.mp3", "sounds/34.mp3"]); m_CurrentRobot = 0; for (y in 0...h) { for (x in 0...w) { var ob:Cube = new Cube((y+x)%2==0,new Vec3(x,y,0)); m_Objs.push(ob); addChild(ob); } } m_Robots = [new RobotEntity(0,new Vec3(1,1,1)), new RobotEntity(1,new Vec3(6,1,1)), new RobotEntity(2,new Vec3(1,6,1)), new RobotEntity(3,new Vec3(6,6,1))]; for (i in 0...m_Robots.length) { addChild(m_Robots[i]); } m_Robots[0].MouseDown(SwitchRobot0); m_Robots[1].MouseDown(SwitchRobot1); m_Robots[2].MouseDown(SwitchRobot2); m_Robots[3].MouseDown(SwitchRobot3); m_Code = new Code(new Vec3(150,0,0)); addChild(m_Code); } // is it possible to get the object, then id from the event? public function SwitchRobot0(_) { SwitchRobot(0); } public function SwitchRobot1(_) { SwitchRobot(1); } public function SwitchRobot2(_) { SwitchRobot(2); } public function SwitchRobot3(_) { SwitchRobot(3); } public function SwitchRobot(i:Int) { m_CurrentRobot=i; m_Code.SetCode(i,m_Robots[i].GetCode()); } public function GetCube(pos:Vec3) : Cube { return m_Objs[cast(pos.x+pos.y*m_Width,Int)]; } // is there a robot on this cube? public function CheckCube(pos:Vec3) : Bool { for (i in 0...m_Robots.length) { // default == seems to be eq - just identity? if (pos.x == m_Robots[i].GetPos().x && pos.y == m_Robots[i].GetPos().y) return true; } return false; } public function Update(frame:Int) { m_Robots[m_CurrentRobot].SetCode(m_Code.GetCode()); for (i in 0...m_Robots.length) { m_Robots[i].Update(frame,this); } } public function Handle(e:KeyboardEvent) { //m_Player.Handle(e); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class AlJazari extends MovieClip { var m_Frame:Int; var m_World:World; public function new() { super(); m_World = new World(8,8); addChild(m_World); flash.Lib.current.stage.addEventListener("enterFrame",Update); flash.Lib.current.stage.addEventListener(flash.events.KeyboardEvent.KEY_DOWN,OnKeyDown,false); } function OnKeyDown(e:KeyboardEvent) { m_World.Handle(e); } function Update(e:Event) { m_World.Update(m_Frame); m_Frame++; } static function main() { var m:AlJazari = new AlJazari(); flash.Lib.current.addChild(m); } }