Here are two different methods of moving objects in random patterns, making them seem to wander around.
(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.) (Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)
The one on the left is based on a brownian movement tutorial that uses variable velocities. The one on the right is based on a post about random circular movement. The latter is much more interesting, as the dot will rotate around an imaginary circle, and then after a random interval, the circle radius will change, and the dot will start on a new path around the new adjacent imaginary circle.
I think both methods are great, it just depends on what you want to use.
Here’s the code for the left method (brownian):
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
| // settings
var numDots:uint = 20;
var defaultDotSize:uint = 5;
var maxSpeed:Number = 0.5;
var dampen:Number = 0.95;
// make dots
function makeDots():void {
// create desired number of dots
for (var dotNum:uint=0; dotNum<numDots; dotNum++){
var c1:Number = randomColor();
var c2:Number = randomColor();
// create dot
var thisDot:MovieClip = new MovieClip();
thisDot.graphics.beginFill(c1, .9);
thisDot.graphics.lineStyle(defaultDotSize/3, c2, .9);
thisDot.graphics.drawCircle(defaultDotSize, defaultDotSize, defaultDotSize);
thisDot.graphics.endFill();
thisDot.alpha = 0.5;
addChild(thisDot);
// coordinates
thisDot.x = Math.random() * stage.stageWidth;
thisDot.y = Math.random() * stage.stageHeight;
// initial velocity
thisDot.vx = 0;
thisDot.vy = 0;
// dot animation
thisDot.addEventListener(Event.ENTER_FRAME, animateDot);
}
}
makeDots();
// animation function
function animateDot(e:Event):void{
var thisDot:Object = e.target;
// apply randomness to velocity
thisDot.vx += dampen*(Math.random() * maxSpeed - maxSpeed/2);
thisDot.vy += dampen*(Math.random() * maxSpeed - maxSpeed/2);
// keep dot inside stage
if(thisDot.x+thisDot.width >= stage.stageWidth)
thisDot.vx = -maxSpeed;
else if(thisDot.x <= 0)
thisDot.vx = maxSpeed;
else if(thisDot.y+thisDot.height >= stage.stageHeight)
thisDot.vy = -maxSpeed;
else if(thisDot.y <= 0)
thisDot.vy = maxSpeed;
// apply velocity
thisDot.x += thisDot.vx;
thisDot.y += thisDot.vy;
}
function randomColor():Number{
return Math.floor(Math.random() * 16777215);
} |
Here’s the code for the right method (circular):
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
| // settings
var numDots:int = 20;
var defaultDotSize:uint = 5;
var step:int = 1;
var maxRadius:int = 50;
var minRadius:int = 5;
var minInterval:int = 400;
var maxInterval:int = 1200;
function makeDots():void {
// create desired number of dots
for (var dotNum:uint=0; dotNum<numDots; dotNum++){
var c1:Number = randomColor();
var c2:Number = randomColor();
// create dot
var thisDot:MovieClip = new MovieClip();
thisDot.graphics.beginFill(c1, .9);
thisDot.graphics.lineStyle(defaultDotSize/3, c2, .9);
thisDot.graphics.drawCircle(defaultDotSize, defaultDotSize, defaultDotSize);
thisDot.graphics.endFill();
thisDot.alpha = 0.5;
addChild(thisDot);
// dot properties
thisDot.radius = Math.random() * (maxRadius - minRadius) + minRadius;
thisDot.centerX = Math.random() * (stage.stageWidth - thisDot.radius*2 - thisDot.width*2) + thisDot.radius + thisDot.width;
thisDot.centerY = Math.random() * (stage.stageHeight - thisDot.radius*2 - thisDot.height*2) + thisDot.radius + thisDot.height;
thisDot.rotationIncrement = (dotNum%2==0?1:-1) * 360 / (2*Math.PI*thisDot.radius/step);
thisDot.currentRotation = thisDot.rotationIncrement;
var radians:Number = Math.PI/180*thisDot.currentRotation;
var vy = Math.sin(radians);
var vx = Math.cos(radians);
thisDot.y = thisDot.centerY + vy*thisDot.radius;
thisDot.x = thisDot.centerX + vx*thisDot.radius;
thisDot.intrvl = setInterval(swapInterval, Math.random()*(maxInterval-minInterval)+minInterval, thisDot);
// dot animation
thisDot.addEventListener(Event.ENTER_FRAME, animateDot);
}
}
makeDots();
// animation function
function animateDot(e:Event):void{
var thisDot:Object = e.target;
thisDot.currentRotation += thisDot.rotationIncrement;
var radians:Number = Math.PI/180*thisDot.currentRotation;
var vy = Math.sin(radians);
var vx = Math.cos(radians);
thisDot.y = thisDot.centerY + vy*thisDot.radius;
thisDot.x = thisDot.centerX + vx*thisDot.radius;
// keep dot inside stage
if(thisDot.x + thisDot.width > stage.stageWidth || thisDot.x < 0 || thisDot.y + thisDot.height > stage.stageHeight || thisDot.y < 0)
thisDot.rotationIncrement *= -1;
}
// creates new point to rotate around
function swap(thisDot:Object):void{
// pick a new random length for the radius
var newRadius:Number = Math.random()*(maxRadius-minRadius)+minRadius;
// determine new center based on old center, dot's current position and new radius
var xd:Number = thisDot.centerX-thisDot.x;
var yd:Number = thisDot.centerY-thisDot.y;
var ratio:Number = (thisDot.radius+newRadius)/thisDot.radius;
thisDot.centerX = thisDot.centerX-xd*ratio;
thisDot.centerY = thisDot.centerY-yd*ratio;
thisDot.radius = newRadius;
// rotate the opposite direction around new point
var dir:int = thisDot.rotationIncrement>0 ? 1 : -1;
thisDot.rotationIncrement = dir* -1 * 360 / (2*Math.PI*thisDot.radius/step);
thisDot.currentRotation -= 180;
}
// random interval to change the point of rotation
function swapInterval(thisDot:Object){
clearInterval(thisDot.intrvl);
thisDot.intrvl = setInterval(swapInterval, Math.random()*(maxInterval-minInterval)+minInterval, thisDot);
swap(thisDot);
}
function randomColor():Number{
return Math.floor(Math.random() * 16777215);
} |
Here’s a quick and dirty way to create a neat explosion effect. There’s alot of particles on the screen, so it can get resource-intensive if you create too many instances.
click the movie to create the animation.
(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)
Here’s the entire code:
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
| // settings
const PARTICLE_MULT = 200;
const PARTICLE_MAX_SIZE = 2;
const PARTICLE_SPEED = 10;
// detects mouse clicks
stage.addEventListener(MouseEvent.CLICK, stageClicked);
function stageClicked(e:MouseEvent){
explosion(e.target.mouseX, e.target.mouseY);
}
// explosion function
function explosion(x1:Number, y1:Number):void{
var particle_qty:Number = Math.random() * (PARTICLE_MULT/2) + (PARTICLE_MULT/2);
for(var i:int=0; i<particle_qty; i++){
var pSize:Number = Math.random() * (PARTICLE_MAX_SIZE-1) + 1;
var pAlpha:Number = Math.random();
// draw the particle
var p:Sprite = new Sprite();
p.graphics.beginFill(0xFF0000);
p.graphics.drawCircle(0,0,pSize);
// create a movieclip so we can add properties to it
var particle:MovieClip = new MovieClip();
particle.addChild(p);
particle.x = x1;
particle.y = y1;
particle.alpha = pAlpha;
// choose a direction and speed to send the particle
var pFast:int = Math.round(Math.random() * 0.75);
particle.pathX = (Math.random() * PARTICLE_SPEED - PARTICLE_SPEED/2) +
pFast * (Math.random() * 10 - 5);
particle.pathY = (Math.random() * PARTICLE_SPEED - PARTICLE_SPEED/2) +
pFast * (Math.random() * 10 - 5);
// this event gets triggered every frame
particle.addEventListener(Event.ENTER_FRAME, particlePath);
addChild(particle);
}
}
// moves the particle
function particlePath(e:Event):void{
e.target.x += e.target.pathX;
e.target.y += e.target.pathY;
e.target.alpha -= 0.005;
// removes the particle from stage when its alpha reaches zero
if(e.target.alpha <= 0){
e.target.removeEventListener('enterFrame', particlePath);
e.target.parent.removeChild(e.target);
}
} |
I’ll go through the parts of the code:
1
2
3
4
5
6
7
8
9
10
| // settings
const PARTICLE_MULT = 200;
const PARTICLE_MAX_SIZE = 2;
const PARTICLE_SPEED = 10;
// detects mouse clicks
stage.addEventListener(MouseEvent.CLICK, stageClicked);
function stageClicked(e:MouseEvent){
explosion(e.target.mouseX, e.target.mouseY);
} |
The particle quantity is decided by the constant PARTICLE_MULT. The minimum number of particles is PARTICLE_MULT / 2. The maximum is PARTICLE_MULT. So if it is set to 200, you will see anywhere from 100-200 particles per explosion. Then we add an event listener to see when the user clicks the screen. This will fire the stageClicked function, which calls the explosion function at the cursor’s click position.
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
| // explosion function
function explosion(x1:Number, y1:Number):void{
var particle_qty:Number = Math.random() * (PARTICLE_MULT/2) + (PARTICLE_MULT/2);
for(var i:int=0; i<particle_qty; i++){
var pSize:Number = Math.random() * (PARTICLE_MAX_SIZE-1) + 1;
var pAlpha:Number = Math.random();
// draw the particle
var p:Sprite = new Sprite();
p.graphics.beginFill(0xFF0000);
p.graphics.drawCircle(0,0,pSize);
// create a movieclip so we can add properties to it
var particle:MovieClip = new MovieClip();
particle.addChild(p);
particle.x = x1;
particle.y = y1;
particle.alpha = pAlpha;
// choose a direction and speed to send the particle
var pFast:int = Math.round(Math.random() * 0.75);
particle.pathX = (Math.random() * PARTICLE_SPEED - PARTICLE_SPEED/2) +
pFast * (Math.random() * 10 - 5);
particle.pathY = (Math.random() * PARTICLE_SPEED - PARTICLE_SPEED/2) +
pFast * (Math.random() * 10 - 5);
// this event gets triggered every frame
particle.addEventListener(Event.ENTER_FRAME, particlePath);
addChild(particle);
}
} |
This creates the explosion particles. It just calculates the quantity, then loops through and creates a particle with a random alpha and size ranging from 1 to PARTICLE_MAX_SIZE. It draws a sprite, and then adds the sprite to a MovieClip. The mc is necessary so that we can add the pathX and pathY properties to it. The pathing portion of the function is kinda gangster, so I’m not going to explain it. The pFast variable pretty much makes the explosion path look more randomized by making about 25% of the particles move faster than the others.
44
45
46
47
48
49
50
51
52
53
54
55
| // moves the particle
function particlePath(e:Event):void{
e.target.x += e.target.pathX;
e.target.y += e.target.pathY;
e.target.alpha -= 0.005;
// removes the particle from stage when its alpha reaches zero
if(e.target.alpha <= 0){
e.target.removeEventListener('enterFrame', particlePath);
e.target.parent.removeChild(e.target);
}
} |
This is pretty simple. Every frame, this event gets triggered, so your movie framerate will affect the speed of these explosions (mine is set to 30). When the particle alpha reaches 0, it is removed from the stage. Removing the event listener is important.
This is a pretty simple way of doing it. Let me know if you have any suggestions!
(Update: I’ve updated the itemRenderer so you can make any row bold, not just the last row. Thanks Pedro.)
I haven’t been using Flex for very long (or Flash’s built-in components for that matter), so I’m not too familiar with their capabilities and shortcomings. I became frustrated when I learned that it is far more difficult to style a specific DataGrid row than it is to style a column.
So here’s the dilemma: I have a DataGrid filled with info, and the final row is a sum of the numbers above it. Seems like a very useful application, but I was unable to find any direct help from other blogs or forums.
(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)
I created an extension to DataGridItemRenderer, and simply referenced it in my DataGrid instance by defining its itemRenderer. As you can see, each item has a custom field called “fontWeight”.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| <mx:DataGrid itemRenderer="dgir">
<mx:dataProvider>
<mx:Array>
<mx:Object Name="Apples" Value="4" fontWeight="normal"/>
<mx:Object Name="Oranges" Value="3" fontWeight="normal"/>
<mx:Object Name="Pears" Value="6" fontWeight="normal"/>
<mx:Object Name="Cherries" Value="7" fontWeight="normal"/>
<mx:Object Name="Total" Value="20" fontWeight="bold"/>
</mx:Array>
</mx:dataProvider>
<mx:columns>
<mx:DataGridColumn dataField="Name"/>
<mx:DataGridColumn dataField="Value"/>
</mx:columns>
</mx:DataGrid> |
The DataGridItemRenderer extension overrides the function validateNow to check the data field named “fontWeight”. Here’s the code from the extension:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| package{
import mx.controls.DataGrid;
import mx.controls.dataGridClasses.DataGridItemRenderer;
public class dgir extends DataGridItemRenderer{
public function dgir(){
super();
}
override public function validateNow():void{
if (listData)
setStyle('fontWeight', DataGrid(listData.owner).dataProvider[listData.rowIndex].fontWeight);
super.validateNow();
}
}
} |