Monthly Archive for September, 2008

Arctic Isometrics…

Playing with isometrics.
Coded an engine, and two isometric object classes used to create simple or complex isometric objects.
Incredibly simple to use.
In the process of adding slanted objects and debating adding curves…
Will post some code if there’s enough interest.
Click to restart and randomize colours.




Vote in HexoSearch Vote for this on HexoSearch!

Objects avoiding the mouse…

Going through some old FLA’s and remember reading some tutorials on this a while back, the one on Spoono was floating around in my bookmarks.
Upgraded the code to AS3, optimized it and created the AvoiderUtil class.
Code below.



AvoiderUtil Class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.arcticcode.greenFlames.geom
{
	public class AvoiderUtil
	{
		public static function CheckObjects(
										Diameter:Number,
										diamX:Number,
										diamY:Number,
										obj:Object,
										startX:Number,
										startY:Number
									  ):void
		{
			//Position of the virtual circle
			var diamX:Number = diamX;
			var diamY:Number = diamY;
			//Diameter of virtual circle
			var diam:Number = Diameter;
			//Position of object avoiding
			//the virtual circle
			var stX:Number = startX;
			var stY:Number = startY;
			//Calculate the distance
			//between the X/Y of virtual circle
			//and obj's X/Y
			var dx:Number = diamX - obj.x;
			var dy:Number = diamY - obj.y;
			var dist:Number = Math.sqrt(dx * dx + dy * dy);
			//calculate and set the position of the
			//object avoiding the vistual circle
			obj.x = (obj.x - dx / dist * diam / dist) + ((stX - obj.x) / 2);
			obj.y = (obj.y - dy / dist * diam / dist) + ((stY - obj.y) / 2);
		}
	}
}

To use:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package
{
	import com.arcticcode.greenFlames.components.MemFpsCount;
	import com.arcticcode.greenFlames.geom.AvoiderUtil;
 
	import flash.display.Sprite;
	import flash.events.TimerEvent;
	import flash.ui.Mouse;
	import flash.utils.Timer;
	[SWF(width=600,height=400,backgroundColor=0xFFFFFF)]
	public class Avoider extends Sprite
	{
		private var _objects:Array;
		private var _positions:Array;
		private var _t:Timer = new Timer(25);
		private var rowCount:uint = 10;
 
		public function Avoider()
		{
			init();
		}
		private function init():void
		{
			var _fm:MemFpsCount = new MemFpsCount();
			addChild(_fm);
 
			_objects = new Array();
			_positions = new Array();
			for(var i:uint = 0;i<160;i++)
			{
				var box:Sprite = drawBox();
				box.x = 50 + (Math.floor(i / rowCount) * 33);
				box.y = 50 + ( ( i % rowCount ) * 33 );;
				addChild(box);
				_objects.push(box);
				_positions.push({x:box.x,y:box.y});
			}
 
			_t.addEventListener(TimerEvent.TIMER,onTimer);
			_t.start();
		}
		private function drawBox():Sprite
		{
			var box:Sprite = new Sprite();
			box.graphics.beginFill(0x5B9FDE, 0.85);
			box.graphics.drawRect(-5,-5,10,10);
			box.graphics.endFill();
			return box;
		}
		private function onTimer(e:TimerEvent):void
		{
			for(var i:uint=0;i<_objects.length;i++)
			{
				AvoiderUtil.CheckObjects(1000,mouseX,mouseY,_objects[i],_positions[i].x,_positions[i].y);
			}
			e.updateAfterEvent();
		}
	}
}
Vote in HexoSearch Vote for this on HexoSearch!

Changing the point of rotation on a display object…

An answer to a question on the Newgrounds BBS.
[Edit turns out he did not understand the concepts of changing the point of rotation on object and simply replied with 'i do not wish to add a movieclip to a parent']
Click the square to change it’s point of rotation. Explanation below.





How to.
Add you display object to a parent display object, via Actionscript or via the Flash IDE.

Add a mouse event listener to your child display object.

when the event is fired, take the current X position of the child, add this to the mouseX of the child minus the X position of the child, then it needs to be negative. Repeat for Y. The code is easier to understand…

Code form:

1
2
var dx:Number = -(square.x + (square.mouseX - square.x));
var dy:Number = -(square.y + (square.mouseY - square.y));

You then tween the X/Y position of the square to these values, add an onComplete function to the tween, which starts a timer to rotate the parent display object.

A tween is not needed just set the X/Y to those values and start the timer or call a function etc…
Although with a tween you can see the movement to the new point of rotation.
I have provided code with and without Tweener, for those interested in Tweener click HERE

Without Tweener:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package
{
	import caurina.transitions.Tweener;
 
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
	[SWF(width=600,height=400,backgroundColor=0xFFFFFF)]
	public class Main extends Sprite
	{
		private var squareParent:Sprite = new Sprite();
		private var square:Sprite = new Sprite();
		private var rotationTimer:Timer = new Timer(1000/stage.frameRate);
 
		public function Main():void
		{
			init();
		}
		private function init():void
		{
			square.graphics.beginFill(0x5B9FDE);
			square.graphics.drawRect(-50,-50,100,100);
			square.graphics.endFill();
 
			squareParent.x = stage.stageWidth*0.5;
			squareParent.y = stage.stageHeight*0.5;
			squareParent.graphics.beginFill(0x000000);
			squareParent.graphics.drawRect(-100,-100,200,200);
			squareParent.graphics.endFill();
 
			squareParent.addChild(square);
			addChild(squareParent);
 
			rotationTimer.addEventListener(TimerEvent.TIMER, onTimerTick);
			square.addEventListener(MouseEvent.CLICK,onClick);
		}
		private function onClick(e:MouseEvent):void
		{
			var dx:Number = -(square.x + (square.mouseX - square.x));
			var dy:Number = -(square.y + (square.mouseY - square.y));
			square.x = -(dx);
			square.y = -(dy);
 
			rotationTimer.start();
		}
		private function onTimerTick(e:TimerEvent):void
		{
			squareParent.rotation+=6;
			if(squareParent.rotation/90 == Math.round(squareParent.rotation / 90))
			{
				rotationTimer.stop();
			}
			e.updateAfterEvent();
		}
	}
}

With Tweener:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package
{
	import caurina.transitions.Tweener;
 
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
	[SWF(width=600,height=400,backgroundColor=0xFFFFFF)]
	public class Main extends Sprite
	{
		private var squareParent:Sprite = new Sprite();
		private var square:Sprite = new Sprite();
		private var rotationTimer:Timer = new Timer(1000/stage.frameRate);
 
		public function Main():void
		{
			init();
		}
		private function init():void
		{
			square.graphics.beginFill(0x5B9FDE);
			square.graphics.drawRect(-50,-50,100,100);
			square.graphics.endFill();
 
			squareParent.x = stage.stageWidth*0.5;
			squareParent.y = stage.stageHeight*0.5;
			squareParent.graphics.beginFill(0x000000);
			squareParent.graphics.drawRect(-100,-100,200,200);
			squareParent.graphics.endFill();
 
			squareParent.addChild(square);
			addChild(squareParent);
 
			rotationTimer.addEventListener(TimerEvent.TIMER, onTimerTick);
			square.addEventListener(MouseEvent.CLICK,onClick);
		}
		private function onClick(e:MouseEvent):void
		{
			var dx:Number = -(square.x + (square.mouseX - square.x));
			var dy:Number = -(square.y + (square.mouseY - square.y));
			//square.x = -(dx);
			//square.y = -(dy);
 
			Tweener.addTween(square, {x:(dx), y:(dy), time:1, onComplete:tweenComplete});
		}
		private function tweenComplete():void
		{
			rotationTimer.start();
		}
		private function onTimerTick(e:TimerEvent):void
		{
			squareParent.rotation+=6;
			if(squareParent.rotation/90 == Math.round(squareParent.rotation / 90))
			{
				rotationTimer.stop();
			}
			e.updateAfterEvent();
		}
	}
}
Vote in HexoSearch Vote for this on HexoSearch!

Amoeba’s, I think…

After playing around with curves, i decided to create something that was a bit more organic.

Tweening joined and filled curves was cool except for the fact that when the points are randomly moved the curves may intersect and it can be quite ugly sometimes, expecially when they intersect more than once.

So what to do, create an Amoeba class which will randomly move each point but keep it within some set boundries.

Click to start / restart, space to pause




And here’s the code, the Amoeba class…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package com.arcticcode.greenFlames.graphics.abstract
{
	import com.arcticcode.greenFlames.geom.LWPoint;
        import com.arcticcode.greenFlames.graphics.Curves.QuadBez;
 
	import flash.display.Sprite;
 
	public class Amoeba extends Sprite
	{
		private var _w:Number;
		private var _h:Number;
		private var _vx:Number=0;
		private var _vy:Number=0;
		private var points:Array;
		private var bounds:Array;
		private var vpoints:Array;
		private var i:uint = 0;
		private var friction:Number = 0.95;
		private var _cI:Object = {c1:0,c2:0xFFFFFF,t:4,f:0};
 
		public function get vx():Number
		{
			return _vx;
		}
		public function set vx(value:Number):void
		{
			_vx = value;
		}
		public function get vy():Number
		{
			return _vy;
		}
		public function set vy(value:Number):void
		{
			_vy = value;
		}
 
		public function Amoeba(width:Number=100,height:Number=100,fillColour:uint=0xFFFFFF, lineColour:uint=0x000000, lineThickness:Number=4)
		{
			_w = width;
			_h = height;
			_cI.c1 = lineColour;
			_cI.t = lineThickness;
			_cI.f = fillColour;
			init();
		}
		private function init():void
		{
			points = new Array();
			points[0] = new LWPoint(Math.random()*_w/2,Math.random()*-_h/2);
			points[1] = new LWPoint(Math.random()*_w/2,Math.random()*_h/2);
			points[2] = new LWPoint(Math.random()*-_w/2,Math.random()*_h/2);
			points[3] = new LWPoint(Math.random()*-_w/2,Math.random()*-_h/2);
 
			vpoints = new Array();
			vpoints[0] = new LWPoint(0,0);
			vpoints[1] = new LWPoint(0,0);
			vpoints[2] = new LWPoint(0,0);
			vpoints[3] = new LWPoint(0,0);
 
			bounds = new Array();
			bounds[0] = {min: new LWPoint(0,-_w/2), max:new LWPoint(_w/2,0)};
			bounds[1] = {min: new LWPoint(0,0), max:new LWPoint(_w/2,_h/2)};
			bounds[2] = {min: new LWPoint(-_w/2,0), max:new LWPoint(0,_h/2)};
			bounds[3] = {min: new LWPoint(-_w/2,-_h/2), max:new LWPoint(0,0)};
		}
		public function draw():void
		{
			for(i=0;i<points.length;i++)
			{
				var _a:LWPoint = vpoints[i];
				_a.x += Math.random() * 0.2 - 0.1;
				_a.y += Math.random() * 0.2 - 0.1;
				_a.x *= friction;
				_a.y *= friction;
				var _b:LWPoint = points[i];
				checkBounds(bounds[i].min.x,bounds[i].max.x,bounds[i].min.y,bounds[i].max.y,_b,_a);
				_b.x += _a.x;
				_b.y += _a.y;
				QuadBez.draw(this.graphics,points,{c1:_cI.c1,c2:_cI.c2,la:1,t:_cI.t,f:_cI.f,fa:1},true);
			}
		}
		private function checkBounds(minX:Number,maxX:Number,minY:Number,maxY:Number,cp:LWPoint,vp:LWPoint):void
		{
			if(cp.x < minX)
			{
				vp.x *= -1;
			}
			else if(cp.x > maxX)
			{
				vp.x *= -1;
			}
			if(cp.y < minY)
			{
				vp.y *= -1;
			}
			else if(cp.y > maxY)
			{
				vp.y *= -1;
			}
		}
	}
}

To use:

1
2
3
4
5
var myAmoeba:Amoeba = new Amoeba(width,height,fillColour,lineColour,lineThickness);
addChild(myAmoeba);
//Use this on any Timer / EnterFrame function to make it come to life =P.
//just make sure to draw when adding it to the  stage otherwise you will not see it.
myAmoeba.draw();

One class you may need is the LWPoint class, this is a simple class i use to hold x/y and vx/vy values.
You are free to use you own methods just update the Amoeba class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package com.arcticcode.greenFlames.geom
{
	public class LWPoint
	{
		private var _x:Number;
		private var _y:Number;
		private var _vx:Number;
		private var _vy:Number;
		public function LWPoint(x:Number=0,y:Number=0)
		{
 
 
			this._x = x;
			this._y = y;
		}
		public function set x(val:Number):void
		{
			_x = val;
		}
		public function get x():Number
		{
			return _x;
		}
		public function set y(val:Number):void
		{
			_y = val;
		}
		public function get y():Number
		{
			return _y;
		}
		public function set vx(val:Number):void
		{
			_vx = val;
		}
		public function get vx():Number
		{
			return _vx;
		}
		public function set vy(val:Number):void
		{
			_vy = val;
		}
		public function get vy():Number
		{
			return _vy;
		}
	}
}

And finally the last class you will need is the QuadBez which handles drawing the curves.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package com.arcticcode.greenFlames.graphics.Curves
{
	import flash.display.Graphics;
 
	public class QuadBez
	{
		private static var i:uint=0;
		private static var _points:Array;
		private static var _controlY:Number;
		private static var _controlX:Number;
		private static var _midpointX:Number;
		private static var _midpointY:Number;
		private static var _colourInfo:Object = {c1:null,c1:null,f:null,fa:null,t:null,la:null};
		private static var _join:Boolean;
		private static var _g:Graphics;
 
		public function QuadBez()
		{
 
		}
		public static function draw(g:Graphics, points:Array=null, colourInfo:Object=null, joined:Boolean=true):void
		{
			_g = g;
			_points = points;
			_midpointX = (points[0].x + points[points.length-1].x) / 2;
			_midpointY = (points[0].y + points[points.length-1].y) / 2;
			_colourInfo.c1 = colourInfo.c1;
			_colourInfo.c2 = colourInfo.c2;
			_colourInfo.t = colourInfo.t;
			_colourInfo.f = colourInfo.f;
			_colourInfo.fa = colourInfo.fa;
			_colourInfo.la = colourInfo.la;
			_join = joined;
			_g.clear();
			drawQuadBez(_colourInfo.c1,_colourInfo.t,_colourInfo.la,{_f:_colourInfo.f,_fa:_colourInfo.fa});
			drawQuadBez(_colourInfo.c2,0,0.3,{_f:null,_fa:null});
 
		}
		private static function drawQuadBez(_c:uint,_t:Number,_la:Number,fill:Object):void
		{
			_g.lineStyle(_t,_c,_la);
			if(fill._f!=null)_g.beginFill(fill._f,fill._fa);
			_g.moveTo(_midpointX,_midpointY);
			for(i = 0;i < _points.length - 1;i++)
			{
				_controlX = (_points[i].x + _points[i + 1].x) / 2;
				_controlY = (_points[i].y + _points[i + 1].y) / 2;
				_g.curveTo(_points[i].x,_points[i].y, _controlX, _controlY);
			}
			if(_join)
			{
				_g.curveTo(_points[i].x,_points[i].y,_midpointX,_midpointY);
			}
			_g.endFill();
		}
	}
}

To use:

1
2
3
4
5
6
7
8
9
10
11
var points:Array = new Array();
for(var i:uint=0;i<5;i++)
{
	var p:LWPoint = new LWPoint(Math.random()*stage.stageWidth,Math.random()*stage.stageHeight);
	points.push(p);
}
//Colour Info object:
//c1:line colour, c2:inner line colour, t-thickness, f-fill colour, fa-fill alpha, la-line alpha
//usually easier to create an object then reference it within this method and change 
// the paramters you want to be changed e.g. colour - colourInfo.c1 = 0x5B9FDE
QuadBez.draw(this.graphics,points,{c1:0x000000,c2:0xFFFFFF,f:0xFFFFFF,la:1,fa:1,t:4},true);

And there you have it.
If anyone wants to improve on this feel free to do so, just post a comment with your code :)

Vote in HexoSearch Vote for this on HexoSearch!