Randomly change movement direction

Community Beginner ,
Jan 12, 2018 Jan 12, 2018

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()

TOPICS
ActionScript

Views

832

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct Answer

Adobe Community Professional , Jan 12, 2018 Jan 12, 2018
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 ...

Likes

Translate

Translate
Adobe Community Professional ,
Jan 12, 2018 Jan 12, 2018

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:

animate_cc_as3_move_shapes_randomly.gif

I hope it helps.

Regards,

JC

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Jan 12, 2018 Jan 12, 2018

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

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Community Professional ,
Jan 12, 2018 Jan 12, 2018

Copy link to clipboard

Copied

Got it.

But what rule should we apply to make the char change direction? Time, distance travelled, collision?

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Jan 12, 2018 Jan 12, 2018

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

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Community Professional ,
Jan 12, 2018 Jan 12, 2018

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.)

animate_cc_as3_move_shapes_randomly.gif

FLA download: animate_cc_as3_move_shapes.zip - Google Drive .

Please don't hesitate to ask if you have any further questions.

Regards,

JC

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Oct 29, 2020 Oct 29, 2020

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.

bounce.gif

 

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Community Professional ,
Oct 30, 2020 Oct 30, 2020

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

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Oct 30, 2020 Oct 30, 2020

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

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Oct 30, 2020 Oct 30, 2020

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?

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Oct 31, 2020 Oct 31, 2020

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?

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Community Professional ,
Oct 31, 2020 Oct 31, 2020

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.

image.png

 

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.

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Nov 01, 2020 Nov 01, 2020

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.

 

 

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Community Professional ,
Nov 01, 2020 Nov 01, 2020

Copy link to clipboard

Copied

LATEST

That's excellent, André!

 

Have a nice weekend!

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines