By Zevan | January 17, 2009
Actionscript:
-
[SWF(width=500, height=500, backgroundColor=0x000000, frameRate=30)]
-
-
for (var i:int = 0; i<10; i++){
-
// draggable ellipse
-
var dot:Sprite = drag(createSprite("Ellipse", -10, -10, 20, 20));
-
dot.x = Math.random() * stage.stageWidth ;
-
dot.y = Math.random() * stage.stageHeight ;
-
}
-
-
for (i = 0; i<10; i++){
-
-
var box:Sprite = drag(spin(createSprite("Rect", -20, -20, 40, 40, 0xFF0000), Math.random()*5 + 1));
-
box.x = Math.random() * stage.stageWidth ;
-
box.y = Math.random() * stage.stageHeight ;
-
}
-
-
-
// createSprite can create ellipses or rectangles
-
function createSprite(shape:String, xp:Number, yp:Number, w:Number, h:Number, col:uint=0x444444):Sprite {
-
var s:Sprite = new Sprite();
-
s.graphics.beginFill(col);
-
// trick from a previous post
-
s.graphics["draw" + shape](xp, yp, w, h);
-
addChild(s);
-
return s;
-
}
-
-
// drag and spin add listeners to an untyped target and return that target for easy function nesting
-
function drag(target:*):*{
-
target.addEventListener(MouseEvent.MOUSE_DOWN, function(evt:MouseEvent){ evt.currentTarget.startDrag(); });
-
return target;
-
}
-
-
function spin(target:*, speed:Number):*{
-
target.addEventListener(Event.ENTER_FRAME, function(evt:Event){ evt.currentTarget.rotation+=speed; });
-
return target;
-
}
-
-
stage.addEventListener(MouseEvent.MOUSE_UP, function(){ stopDrag() });
The above will create some draggable circles and some rotating draggable rects... but that's not really the point....
When prototyping and just playing around I write functions that take an Object as an argument, alter that Object in some way and pass that some Object out as a return value.... this makes it so I can write things like this:
Actionscript:
-
drag(spin(createSprite("Rect", -20, -20, 40, 40, 0xFF0000), Math.random()*5 + 1));
Readability can be a problem so... consider that before using this for anything...
By Zevan | January 15, 2009
Actionscript:
-
var currentState:String = "";
-
-
var functionList:Vector.<Function> = new Vector.<Function>();
-
-
function clearFunctions():void{
-
functionList = new Vector.<Function>();
-
}
-
function addFunction(f:Function):Function {
-
functionList.push(f);
-
return addFunction;
-
}
-
-
function removeFunction(f:Function):void {
-
for (var i:int = 0 ; i<functionList.length; i++){
-
if (f == functionList[i]){
-
functionList.splice(i, 1);
-
}
-
}
-
}
-
-
function runProgram():void {
-
-
currentState = "current: ";
-
-
for (var i:int = 0; i<functionList.length; i++){
-
functionList[i]();
-
}
-
-
trace(currentState);
-
}
-
-
function one():void{
-
currentState += " one";
-
}
-
-
function two():void {
-
currentState += " two";
-
}
-
-
function three():void {
-
currentState += " three";
-
}
-
-
function dot():void{
-
currentState += ".";
-
-
}
-
-
// test it:
-
addFunction(one);
-
addFunction(two);
-
addFunction(three);
-
-
runProgram();
-
-
removeFunction(one);
-
-
runProgram();
-
-
addFunction(dot)(dot)(dot);
-
-
runProgram();
-
-
clearFunctions();
-
-
addFunction(dot)(dot)(dot);
-
-
addFunction(three)(two)(one)(dot)(dot)(dot);
-
-
runProgram();
-
-
/* outputs:
-
current: one two three
-
current: two three
-
current: two three...
-
current: ... three two one...
-
*/
This is a very quick implementation of a pattern that I use sometimes. The idea of this pattern is very simple and can easily be implemented in OOP or procedural style programming. The idea is to have a Vector/Array of functions or Class instances. Loop through this Vector/Array and run each function (or a given method of each Class instance). During runtime your client code can alter this list to change what the program does.
I use this technique for games quite often. All enemies get added to an enemy list - this list is looped through and each enemies run() method is called. If an enemy dies it dispatches an event that tells the enemy manager to remove it from the list. Some pseudo code:
Actionscript:
-
function onMainLoop():void{
-
if (!paused){
-
-
runWorld();
-
runKeys();
-
runChar();
-
-
enemyManager.runEnemies();
-
-
runPickups();
-
-
}else{
-
// show pause screen
-
}
-
}
-
-
//... inside EnemyManager class
-
function onRunEnemies():void{
-
for (var i:int = 0; i<enemyList.length; i++){
-
enemyList[i].run(i);
-
}
-
}
I use the same technique for pickups (coins, lives etc....).
I first used this technique in Director with a list of parent scripts.
I'm aware of other more refined patterns that are meant to do similar things, but for small to medium sized apps this has worked very nicely for me.
Also posted in Vector, arrays | Tagged actionscript, flash |
By Zevan | January 14, 2009
Actionscript:
-
[SWF(width=400, height=400, backgroundColor=0xCCCCCC, frameRate=30)]
-
-
var canvas:BitmapData = new BitmapData(400, 400, true, 0xCCCCCC);
-
var eraser:BitmapData = new BitmapData(400, 400, true, 0x22CCCCCC);
-
addChild(new Bitmap(canvas));
-
-
var circle:Shape = Shape(addChild(new Shape()));
-
with (circle.graphics) beginFill(0x000000), drawCircle(0,0,20);
-
-
addEventListener(Event.ENTER_FRAME, onLoop);
-
-
function onLoop(evt:Event):void {
-
canvas.copyPixels(eraser, eraser.rect, new Point(0,0), null, null, true);
-
circle.x = mouseX;
-
circle.y = mouseY;
-
-
canvas.draw(circle, circle.transform.matrix);
-
}
Create trails by slowly erasing the background with copyPixels(). The first time I ever saw this technique was back when setpixel.com contained a bunch of great director experiments by Charles Foreman (creator of iminlikewithyou.com).
At some point last semester I showed iminlikewithyou hamster battle to my undergrad students towards the end of class.... probably one of the funniest moments of that class.
Also posted in BitmapData | Tagged actionscript, flash |
By Zevan | January 13, 2009
Actionscript:
-
var circle:Shape = Shape(addChild(new Shape()));
-
with(circle.graphics) beginFill(0xCCCCCC), drawCircle(0,0,100);
-
circle.x = stage.stageWidth / 2;
-
circle.y = stage.stageHeight / 2;
-
-
var charWorld:MovieClip = MovieClip(addChild(new MovieClip()));
-
charWorld.x = circle.x ;
-
charWorld.y = circle.y - 100 - 10
-
charWorld.thetaSpeed = 0;
-
charWorld.theta = -Math.PI / 2;
-
-
var char:MovieClip = MovieClip(charWorld.addChild(new MovieClip))
-
with(char.graphics) beginFill(0x000000), drawRect(-10,-10,10,10);
-
char.posY = 0;
-
char.velY = 0;
-
-
addEventListener(Event.ENTER_FRAME, onRunChar);
-
function onRunChar(evt:Event):void {
-
-
char.velY += 1;
-
char.posY += char.velY;
-
-
charWorld.thetaSpeed *= .6;
-
charWorld.theta += charWorld.thetaSpeed;
-
-
if (key[Keyboard.UP]){
-
if (char.y == 0){
-
char.velY = -10;
-
}
-
}
-
-
if (key[Keyboard.RIGHT]){
-
charWorld.thetaSpeed = .1;
-
}
-
-
if (key[Keyboard.LEFT]){
-
charWorld.thetaSpeed = -.1;
-
}
-
-
if (char.posY> 0){
-
char.posY = 0;
-
}
-
-
char.y = char.posY;
-
-
charWorld.x = circle.x + 100 * Math.cos(charWorld.theta);
-
charWorld.y = circle.y + 100 * Math.sin(charWorld.theta);
-
charWorld.rotation = Math.atan2(circle.y- charWorld.y, circle.x - charWorld.x) / Math.PI * 180 - 90;
-
}
-
-
var key:Object = new Object();
-
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyPressed);
-
stage.addEventListener(KeyboardEvent.KEY_UP, onKeyReleased);
-
function onKeyPressed(evt:KeyboardEvent):void {
-
key[evt.keyCode] = true;
-
key.keyCode = evt.keyCode;
-
}
-
-
function onKeyReleased(evt:KeyboardEvent):void {
-
key[evt.keyCode] = false
-
}
For some reason I felt like posting the swf.... have a look here.
This is one that's been kicking around in my head for awhile - finally got around to writing it. It creates a circle and a small black box. The box walks and jumps on the circle with key input (left arrow, right arrow and up arrow).
There's an odd trick going on here. Basically, the box (or char) movieClip is nested inside another clip. Within this clip (charWorld) the box moves on the y axis (jumping/up key). The charWorld clip orbits around the circle and rotates toward the center of the circle - sine/cosine are used for the orbit so the left and the right keys control the speed of theta.
Also posted in motion | Tagged actionscript, flash |