Copy link to clipboard
Copied
Hello
I am working on a program that has several objects moving over the screen.
Every object is supossed to move differently from the other objects.
What i can´t figure out is how to make an object randomly turn and move the other direction.
Every object on stage now moves towards + X.
Here is my code
import flash.display.Sprite;
import flash.events.Event;
var circArray :Array = new Array()
var j = 0
function drawCircs() {
for (var i = 0; i < 25; i ++) {
var circ :Sprite = new Sprite();
var fill :int = 0xffffff * Math.random();
var alfa :Number = 0.99 * Math.random();
var x0 :int = stage.stageWidth * Math.random();
var y0 :int = 400;
var radius :int = 20;
circArray.push(circ = new Sprite()) //puts the circle sprite in an Array
addChild(circArray
); circArray
.graphics.lineStyle(1); circArray
.graphics.beginFill(fill, alfa); circArray
.graphics.drawCircle(x0, y0, radius); circArray
.graphics.endFill(); circArray
.addEventListener(Event.ENTER_FRAME, move) j += 1
}
}
function move (evt:Event) { //moves every circle sprite individually
var thisCirc = evt.currentTarget
thisCirc.x += Math.random() * 5
thisCirc.y -= Math.random() * 5
}
drawCircs()
Hi again.
I tried your approach but all the circles just kept moving in the same direction while shaking a bit.
Also, for better performance:
- Use vectors instead of arrays;
- Randomize the position of the object itself not the drawing parameters because it will be much harder for you to check for collisions, position the objects precisely, and so on;
- Try to always use only one enterFrame event for the sake of maintenance and performance;
- You used the new keyword when creating the circ object so
...Copy link to clipboard
Copied
Hi.
It's because you are setting random x and y values at every tick for the movement. You have to predefine this values before you start moving your shapes.
I have a suggestion for you where I made some tweaks that I think that will greatly improve performance and achieve the result you want.
You only need to create an extra ActionScript class outside of your FLA. I did this because I wanted every circle to be a Shape, which is lighter than a Sprite. But Shapes are static classes, so we can't add properties to it dynamically. That's why I created a class called Circ to extend Shape but being able to receive dynamic properties.
Main code:
import flash.display.Shape;
import flash.display.DisplayObjectContainer;
var circles:Vector.<Circ> = new Vector.<Circ>();
function generateCircles(total:uint, container:DisplayObjectContainer):void
{
for (var i:uint = 0; i < total; i++)
{
var circ:Circ = new Circ();
circ.graphics.lineStyle(1);
circ.graphics.beginFill(0xffffff * Math.random(), 0xffffff * Math.random());
circ.graphics.drawCircle(0, 0, 20);
circ.graphics.endFill();
circ.x = stage.stageWidth * Math.random();
circ.y = stage.stageHeight;
circ.moveX = -5 + Math.random() * 10;
circ.moveY = -5 + Math.random() * 10;
container.addChild(circ);
circles.push(circ);
}
}
function enterFrameHandler(event:Event):void
{
for (var i:uint = 0, total:uint = circles.length; i < total; i++)
{
var circ:Circ = circles;
if (circ.x < -circ.width * 0.5)
circ.x = stage.stageWidth + circ.width * 0.5;
else if (circ.x > stage.stageWidth + circ.width * 0.5)
circ.x = -circ.width * 0.5;
if (circ.y < -circ.height * 0.5)
circ.y = stage.stageHeight + circ.height * 0.5;
else if (circ.y > stage.stageHeight + circ.height * 0.5)
circ.y = -circ.height * 0.5;
circ.x += circ.moveX;
circ.y += circ.moveY;
}
}
generateCircles(25, this);
stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
Circle.as:
package
{
import flash.display.Shape;
public dynamic class Circ extends Shape
{
public function Circ()
{
}
}
}
Preview:
I hope it helps.
Regards,
JC
Copy link to clipboard
Copied
Hello
Thank you for the answer!
Yes this is almost what i want to do.
To explain my problem better:
Im working on a bigger program or game rather where this code is supossed to be characters moving around on the screen so this is just a test to see how that is done before i put it into my bigger program.
I want the circles to start at y400 and move upwards (At this state they only move towards + X).
Correct me if im wrong but it seems like the program you made they do go both ways but ONLY that way (Either + X or - X) until theyre off screen.
What im looking for is how to make the circles randomly switch what way they are going and continue that way until the direction is changed again.
Im not very good at explaining my problem but I hope you understand
and again Thank you for the help
Copy link to clipboard
Copied
Got it.
But what rule should we apply to make the char change direction? Time, distance travelled, collision?
Copy link to clipboard
Copied
Ive got a rough version of it working but im sure theres a better way to do it. Idealy id like it to happen randomly (say if a variable that changed everytime the circles moved was greater than a certain number).
Heres the way i got it working:
import flash.display.Sprite;
import flash.events.Event;
var circArray :Array = new Array()
var circXArray :Array = new Array()
var circX :int = 5
var circY :int = 5
var circCount :int = 300
var difFlip :int = 500
var div :int = 3
var j = 0
var k = 0
function drawCircs() {
for (var i = 0; i < circCount; i ++) {
var circ :Sprite = new Sprite();
var fill :int = 0xffffff * Math.random();
var alfa :Number = 0.99 * Math.random();
var x0 :int = 400;
var y0 :int = 600;
var radius :int = 20;
circArray.push(circ = new Sprite()); //puts the circle sprite in an Array
addChild(circArray
); circArray
.graphics.lineStyle(1); circArray
.graphics.beginFill(fill, alfa); circArray
.graphics.drawCircle(x0, y0, radius); circArray
.graphics.endFill(); circArray
.addEventListener(Event.ENTER_FRAME, move) circXArray.push(circX)
j += 1
}
}
function move (evt:Event) { //moves every circle sprite individually
var thisCirc = evt.currentTarget
var flip = Math.random() * difFlip
if (flip < difFlip / div) {
circXArray
= -circXArray }
thisCirc.x += circXArray
thisCirc.y -= circY
k += 1
if (k == circCount) {
k = 0
}
}
I dont know how to add a preview of the program like you did either
Copy link to clipboard
Copied
Hi again.
I tried your approach but all the circles just kept moving in the same direction while shaking a bit.
Also, for better performance:
- Use vectors instead of arrays;
- Randomize the position of the object itself not the drawing parameters because it will be much harder for you to check for collisions, position the objects precisely, and so on;
- Try to always use only one enterFrame event for the sake of maintenance and performance;
- You used the new keyword when creating the circ object so there's no need to use it again when pushing this object to the array.
Here is an updated code.
The shapes now move based on their rotation values. At every 2 seconds each shape change its direction. Notice that you can uncomment three lines and change the object to the arrow I used below.
Main code:
import flash.display.DisplayObjectContainer;
import flash.utils.setInterval;
//var objs:Vector.<Arrow> = new Vector.<Arrow>();
var objs:Vector.<Circ> = new Vector.<Circ>();
var interval:uint;
const DEGREES:Number = Math.PI / 180;
function generateObjects(total:uint, container:DisplayObjectContainer):void
{
for (var i:uint = 0; i < total; i++)
{
//var obj:Arrow = new Arrow();
var obj:Circ = new Circ();
obj.x = stage.stageWidth * Math.random();
obj.y = stage.stageHeight;
obj.rotation = -180 + Math.random() * 180;
obj.direction = obj.rotation;
obj.speedX = 2 + Math.random() * 3;
obj.speedY = 2 + Math.random() * 3;
obj.friction = 0.85;
container.addChild(obj);
objs.push(obj);
}
}
function enterFrameHandler(event:Event):void
{
for (var i:uint = 0, total:uint = objs.length; i < total; i++)
{
//var obj:Arrow = objs;
var obj:Circ = objs;
if (obj.x < -obj.width * 0.5)
obj.x = stage.stageWidth + obj.width * 0.5;
else if (obj.x > stage.stageWidth + obj.width * 0.5)
obj.x = -obj.width * 0.5;
if (obj.y < -obj.height * 0.5)
obj.y = stage.stageHeight + obj.height * 0.5;
else if (obj.y > stage.stageHeight + obj.height * 0.5)
obj.y = -obj.height * 0.5;
obj.rotation = lerp(obj.rotation, obj.direction, obj.friction);
obj.x = obj.x + obj.speedX * Math.cos(obj.rotation * DEGREES);
obj.y = obj.y + obj.speedY * Math.sin(obj.rotation * DEGREES);
}
}
function changeDirection():void
{
for (var i:uint = 0, total:uint = objs.length; i < total; i++)
objs.direction = -180 + Math.random() * 180;
}
function lerp(v1:Number, v2:Number, f:Number):Number
{
return f * v1 + (1 - f) * v2;
}
generateObjects(25, this);
stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
interval = setInterval(changeDirection, 2000);
Circ.as code:
package
{
import flash.display.Sprite;
public dynamic class Circ extends Sprite
{
public function Circ()
{
graphics.lineStyle(1);
graphics.beginFill(0xffffff * Math.random(), 0xffffff * Math.random());
graphics.drawCircle(0, 0, 20);
graphics.endFill();
}
}
}
Preview:
(The preview is just a GIF. Please ignore the framerate.)
FLA download: animate_cc_as3_move_shapes.zip - Google Drive .
Please don't hesitate to ask if you have any further questions.
Regards,
JC
Copy link to clipboard
Copied
Hi João,
I know this is an old thread but I was just wondering if there is any way to bounce the object when it hits the edge of the screen so that it keeps moving around the screen?
Something like this gif.
Copy link to clipboard
Copied
Hi.
Sure. Here is a suggestion:
Timeline code:
import flash.display.DisplayObjectContainer;
const TOTAL:uint = 1000;
var objs:Vector.<Circ> = new Vector.<Circ>();
function generateObject(container:DisplayObjectContainer):void
{
var obj:Circ = new Circ();
obj.x = obj.width * 0.5 + Math.random() * (stage.stageWidth - obj.width);
obj.y = obj.height * 0.5 + Math.random() * (stage.stageHeight - obj.height);
obj.speedX = -5 + Math.random() * 5;
obj.speedY = -5 + Math.random() * 5;
container.addChild(obj);
objs.push(obj);
}
function enterFrameHandler(event:Event):void
{
if (objs.length < TOTAL)
generateObject(this);
for (var i:int = objs.length -1; i >= 0; i--)
{
var obj:Circ = objs[i];
var left:Number = obj.width * 0.5;
var right:Number = stage.stageWidth - obj.width * 0.5;
var top:Number = obj.height * 0.5;
var bottom:Number = stage.stageHeight - obj.height * 0.5;
if (obj.x < left)
{
obj.speedX = -obj.speedX;
obj.x = left;
}
else if (obj.x > right)
{
obj.speedX = -obj.speedX;
obj.x = right;
}
else if (obj.y < top)
{
obj.speedY = -obj.speedY;
obj.y = top;
}
else if (obj.y > bottom)
{
obj.speedY = -obj.speedY;
obj.y = bottom;
}
obj.x += obj.speedX;
obj.y += obj.speedY;
}
}
stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
Circ.as code:
package
{
import flash.display.Sprite;
public dynamic class Circ extends Sprite
{
public function Circ()
{
graphics.beginFill(0xffffff * Math.random(), 0xffffff * Math.random());
graphics.drawCircle(0, 0, uint(2 + Math.random() * 4));
graphics.endFill();
}
}
}
I've applied some tweaks just for fun.
I hope this helps.
Regards,
JC
Copy link to clipboard
Copied
Hi João,
Thank you so much for that, the code works great.
I'm now trying to apply it to a specific movieclip instead of generating a vector shape but I'm having trouble modifying the code for this. Are you able to explain how I would change the code to work with a movieclip called obj instead of generating a vector shape?
Thanks
AB
Copy link to clipboard
Copied
Sorry I can't edit my post but was also wondering if there's a way to set the speed of the objects to be between certain numbers?
Copy link to clipboard
Copied
Is there also a way to remove all the objects when you click the mouse and then to restart it again when you reclick?
Copy link to clipboard
Copied
Hi.
You need to select the Movie Clip you want to use in the Library, right-click it, go to Properties... and check Export for ActionScript. The name in the Class field is the one you're gonna use in the code. So you would replace Circ in the code for Rec, for example.
I've applied some changes to the code in some places so now it uses a symbol called Rec that lives in the Library and I've also applied the mouse click interaction.
AS3 code:
import flash.display.DisplayObjectContainer;
import flash.events.MouseEvent;
const TOTAL:uint = 1000;
var container:DisplayObjectContainer = this;
var objs:Vector.<Rec> = new Vector.<Rec>();
var remove:Boolean = true;
function generateObject():void
{
var obj:Rec = new Rec();
obj.x = obj.width * 0.5 + Math.random() * (stage.stageWidth - obj.width);
obj.y = obj.height * 0.5 + Math.random() * (stage.stageHeight - obj.height);
obj.speedX = -5 + Math.random() * 5;
obj.speedY = -5 + Math.random() * 5;
obj.alpha = 0.2 + Math.random() * 0.8;
container.addChild(obj);
objs.push(obj);
}
function enterFrameHandler(event:Event):void
{
if (objs.length < TOTAL)
generateObject();
for (var i:int = objs.length -1; i >= 0; i--)
{
var obj:Rec = objs[i];
var left:Number = obj.width * 0.5;
var right:Number = stage.stageWidth - obj.width * 0.5;
var top:Number = obj.height * 0.5;
var bottom:Number = stage.stageHeight - obj.height * 0.5;
if (obj.x < left)
{
obj.speedX = -obj.speedX;
obj.x = left;
}
else if (obj.x > right)
{
obj.speedX = -obj.speedX;
obj.x = right;
}
else if (obj.y < top)
{
obj.speedY = -obj.speedY;
obj.y = top;
}
else if (obj.y > bottom)
{
obj.speedY = -obj.speedY;
obj.y = bottom;
}
obj.x += obj.speedX;
obj.y += obj.speedY;
}
}
function restart(e:MouseEvent):void
{
if (remove)
{
container.removeChildren();
objs.splice(0, objs.length);
stage.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
else
stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
remove = !remove;
}
stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
stage.addEventListener(MouseEvent.CLICK, restart);
As for putting the speed value between certain numbers, I think that already happens here:
obj.speedX = -5 + Math.random() * 5; // number from -5 to 5
obj.speedY = -5 + Math.random() * 5; // number from -5 to 5
Please let me know.
Copy link to clipboard
Copied
That worked great, I was able to change the code and have it work in my game.
Thanks so much for that and explaining how things work, really helped understand it.
Copy link to clipboard
Copied
That's excellent, André!
Have a nice weekend!
Copy link to clipboard
Copied
Hi, João Cesar...
That's amazing! I need this in HTML5 version, please...
Copy link to clipboard
Copied
Sure.
Example 1:
var root = this;
var container = root.container; // container should be placed at 0,0
var degrees = Math.PI / 180;
var total = 25;
var changeDirectionDelay = 2000;
var libraryLinkage = "Arrow"; // linkage of the symbol in the Library
function main()
{
createjs.Ticker.timingMode = createjs.Ticker.RAF;
generateparticleects(total, container);
root.tickEvent = createjs.Ticker.on("tick", enterFrameHandler);
root.interval = setInterval(changeDirection, changeDirectionDelay);
}
function generateparticleects(total, container)
{
var i = 0;
for (i = 0; i < total; i++)
{
var particle = new lib[libraryLinkage]();
particle.x = lib.properties.width * Math.random();
particle.y = lib.properties.height;
particle.rotation = -180 + Math.random() * 180;
particle.direction = particle.rotation;
particle.speedX = 2 + Math.random() * 3;
particle.speedY = 2 + Math.random() * 3;
particle.friction = 0.85;
container.addChild(particle);
}
}
function enterFrameHandler()
{
var i, particle;
for (i = container.numChildren - 1; i > -1; i--)
{
particle = container.children[i];
if (particle.x < -particle.nominalBounds.width * 0.5)
particle.x = lib.properties.width + particle.nominalBounds.width * 0.5;
else if (particle.x > lib.properties.width + particle.nominalBounds.width * 0.5)
particle.x = -particle.nominalBounds.width * 0.5;
if (particle.y < -particle.nominalBounds.height * 0.5)
particle.y = lib.properties.height + particle.nominalBounds.height * 0.5;
else if (particle.y > lib.properties.height + particle.nominalBounds.height * 0.5)
particle.y = -particle.nominalBounds.height * 0.5;
particle.rotation = lerp(particle.rotation, particle.direction, particle.friction);
particle.x = particle.x + particle.speedX * Math.cos(particle.rotation * degrees);
particle.y = particle.y + particle.speedY * Math.sin(particle.rotation * degrees);
}
}
function changeDirection()
{
var i, particle;
for (i = container.numChildren - 1; i > -1; i--)
container.children[i].direction = -180 + Math.random() * 180;
}
function lerp(v1, v2, f)
{
return f * v1 + (1 - f) * v2;
}
main();
Example 2:
var root = this;
var container = root.container; // container should be placed at 0,0
var total = 1000;
var remove = true;
var w = lib.properties.width;
var h = lib.properties.height;
var libraryLinkage = "Rec"; // linkage of the symbol in the Library
function main()
{
createjs.Touch.enable(stage);
createjs.Ticker.timingMode = createjs.Ticker.RAF;
root.tickEvent = createjs.Ticker.on("tick", enterFrameHandler);
anim_container.addEventListener("click", restart);
}
function generateparticleect()
{
var particle = new lib[libraryLinkage]();
particle.x = particle.nominalBounds.width * 0.5 + Math.random() * (w - particle.nominalBounds.width);
particle.y = particle.nominalBounds.height * 0.5 + Math.random() * (h - particle.nominalBounds.height);
particle.vX = -5 + Math.random() * 5;
particle.vY = -5 + Math.random() * 5;
particle.alpha = 0.2 + Math.random() * 0.8;
container.addChild(particle);
}
function enterFrameHandler()
{
var i;
if (container.numChildren < total)
generateparticleect();
for (i = container.numChildren - 1; i > -1; i--)
{
var particle = container.children[i];
var left = particle.nominalBounds.width * 0.5;
var right = w - particle.nominalBounds.width * 0.5;
var top = particle.nominalBounds.height * 0.5;
var bottom = h - particle.nominalBounds.height * 0.5;
if (particle.x < left)
{
particle.vX = -particle.vX;
particle.x = left;
}
else if (particle.x > right)
{
particle.vX = -particle.vX;
particle.x = right;
}
else if (particle.y < top)
{
particle.vY = -particle.vY;
particle.y = top;
}
else if (particle.y > bottom)
{
particle.vY = -particle.vY;
particle.y = bottom;
}
particle.x += particle.vX;
particle.y += particle.vY;
}
}
function restart()
{
if (remove)
{
container.removeAllChildren();
createjs.Ticker.off("tick", root.tickEvent);
}
else
root.tickEvent = createjs.Ticker.on("tick", enterFrameHandler);
remove = !remove;
}
main();
I hope it helps.
Regards,
JC
Copy link to clipboard
Copied
Hi, João Cesar...
It works great! This is really awesome! And how about to change the speed of movement particles in code example 1 ?