Flash-position of small circle keep changing when i click "Resume" - actionscript-3

I am trying to make small circles moving inside a big circle and also having buttons to pause,resume and reverse it. But when i pause and resume it, it will change the small circle's position but i want it to stay at the original position. Is there anyway to do it? and also is there a way to make reverse the direction when i click?(eg. starting is cw when i click "reverse" it will turn anti-cw and when i click "reverse" again it will go cw)
This is my code for action layer:
var Rec:Number=1;
stage.addEventListener(Event.ENTER_FRAME,EntFrame);
function EntFrame(e:Event):void
{
if (Rec >= 1)
{
CircleL.rotation-= 2;
}
else if(Rec <= -1)
{
CircleL.rotation+=2;
}
}
var twoPI = 2 * Math.PI;
var circleSNum1:Number = Math.random();
var circleSNum2:Number = Math.random();
var circleSNum3:Number = Math.random();
var circleSNum4:Number = Math.random();
var circleSNum5:Number = Math.random();
function randomRange(minNum:Number, maxNum:Number):Number
{
return (Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);
}
var radius = randomRange(10, 90);
function move(event:Event):void{
CircleL.CircleS1.x = Math.cos(circleSNum1 * twoPI) * radius;
CircleL.CircleS1.y = Math.sin(circleSNum1 * twoPI) * radius;
CircleL.CircleS2.x = Math.cos(circleSNum2 * twoPI) * radius;
CircleL.CircleS2.y = Math.sin(circleSNum2 * twoPI) * radius;
CircleL.CircleS3.x = Math.cos(circleSNum3 * twoPI) * radius;
CircleL.CircleS3.y = Math.sin(circleSNum3 * twoPI) * radius;
CircleL.CircleS4.x = Math.cos(circleSNum4 * twoPI) * radius;
CircleL.CircleS4.y = Math.sin(circleSNum4 * twoPI) * radius;
CircleL.CircleS5.x = Math.cos(circleSNum5 * twoPI) * radius;
CircleL.CircleS5.y = Math.sin(circleSNum5 * twoPI) * radius;
}
addEventListener(Event.ENTER_FRAME,move);
Pause.addEventListener(MouseEvent.CLICK, clickPause);
function clickPause(Event:MouseEvent):void{
gotoAndStop("Pause");
Rec=0
}
Resume.addEventListener(MouseEvent.CLICK, clickResume);
function clickResume(Event:MouseEvent):void{
gotoAndStop("Resume");
Rec=1
}
Reverse.addEventListener(MouseEvent.CLICK, clickReverse);
function clickReverse(Event:MouseEvent):void{
gotoAndStop("Reverse");
Rec=-1
}
When i test it is this position
After i click "pause" and "resume" the position of small circle changed

Try removing the Enter Frame event listener when you want to pause and add it back when you need to resume. The enter frame event still triggers even if you call stop(); (gotoAndStop in this case). So the circle still moves even if you can't see it because you've jumped to another frame. When you come back to it (resume) it will look like it moved but it has never stopped.
Pause.addEventListener(MouseEvent.CLICK, clickPause);
function clickPause(Event:MouseEvent):void{
//remove event listener
stage.removeEventListener(Event.ENTER_FRAME,EntFrame);
gotoAndStop("Pause");
Rec=0
}
Resume.addEventListener(MouseEvent.CLICK, clickResume);
function clickResume(Event:MouseEvent):void{
//add event listener
stage.addEventListener(Event.ENTER_FRAME,EntFrame);
gotoAndStop("Resume");
Rec=1
}
Also, try writing your ActionScript in external files and remove it from the time line, also use classes...it's not that hard and will make you a better developer in the end.

Related

Orbiting objects with equal spacing AS3

I have a monster that produces crystals. I want each crystal to orbit the monster, but when there is more than one crystal, I want them to orbit at an equal distance from each other. I've been trying to get this to work using two blocks of code I already have, but each one does something different and i need one block of code that does it all.
This block simply allows an object to orbit another:
orbitRadius = 110;
angle += orbitSpeed;
rad = (angle * (Math.PI / 180));
orbitX = monster.x + orbitRadius * Math.cos(rad);
orbitY = monster.y + orbitRadius * Math.sin(rad);
Here's a video of what it looks like:
https://www.youtube.com/watch?v=ACclpQBsjPo
This block of code arranges crystals around the monster based on the amount of crystals there are:
radius = 110;
angle = ((Math.PI * 2) / targetArray.length) * targetArray.indexOf(this);
orbitX = monster.x - (radius * Math.cos(angle));
orbitY = monster.y - (radius * Math.sin(angle));
And here's this video: https://www.youtube.com/watch?v=TY0mBHc2A8U
I do not know how to both space the crystals equally and make them circle around the monster at the same time. What needs to be done in order to achieve this?
1) Hierarchical way: put crystals into the same container so they spread equally (like you are doing on the second video) then rotate the container.
2) Math way.
Implementation:
public class Orbiter extends Sprite
{
// Pixels.
public var radius:Number = 100;
// Degrees per second.
public var speed:Number = 360;
public var items:Array;
public var lastTime:int;
public function start()
{
stop();
rotation = 0;
items = new Array;
lastTime = getTimer();
addEventListener(Event.ENTER_FRAME, onFrame);
}
public function stop():void
{
items = null;
removeEventListener(Event.ENTER_FRAME, onFrame);
}
public function onFrame(e:Event = null):void
{
var aTime:int = getTimer();
rotation += speed * (aTime - lastTime) / 1000;
lastTime = aTime;
for (var i:int = 0; i < items.length; i++)
{
// Get the object.
var anItem:DisplayObject = items[i];
// Get the object's designated position.
var aPos:Point = getPosition(i);
// Follow the position smoothly.
anItem.x += (aPos.x - anItem.x) / 10;
anItem.y += (aPos.y - anItem.y) / 10;
}
}
private function getPosition(index:int):Point
{
// Calculate the angle with regard to the present items amount.
var anAngle:Number = (rotation - 360 / items.length) * Math.PI / 180;
var result:Point = new Point;
// Figure the position with regard to (x,y) offset.
result.x = x + radius * Math.cos(anAngle);
result.y = y + radius * Math.sin(anAngle);
return result;
}
}
Usage:
var O:Orbiter = new Orbiter;
// Define the offset.
O.x = monster.x;
O.y = monster.y;
// Set radius and rotation speed.
O.radius = 110;
O.speed = 270;
// Enable the rotation processing.
O.start();
// Append items to orbit.
O.items.push(Crystal1);
O.items.push(Crystal2);
O.items.push(Crystal3);
You can change radius and speed any time, as well as add/remove items, thanks to motion smoothing that all will look equally fine.

Flash- circle not rotating inside another circle

I am trying to make the small circles to be able to rotate inside the large circle. But what i got is that the small circles are rotating outside the large circle.
Here is my code:
import flash.events.Event;
import flash.events.MouseEvent;
var Rec:Number=-1;
stage.addEventListener(Event.ENTER_FRAME,EntFrame);
function EntFrame(e:Event):void
{
if (Rec == -1)
{
CircleL.rotation-= 2;
}
}
var cenX = CircleL.x;
var cenY = CircleL.y;
var ccStep = .01;
var twoPI = 2 * Math.PI;
var circleSNum1:Number = Math.random();
var circleSNum2:Number = Math.random();
var circleSNum3:Number = Math.random();
var circleSNum4:Number = Math.random();
var circleSNum5:Number = Math.random();
function randomRange(minNum:Number, maxNum:Number):Number
{
return (Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);
}
var radius1 = randomRange(10, 90);
var radius2 = randomRange(10, 90);
var radius3 = randomRange(10, 90);
var radius4 = randomRange(10, 90);
var radius = randomRange(10, 90);
function move(event:Event):void
{
CircleL.CircleS1.x = cenX + Math.cos(circleSNum1 * twoPI) * radius;
CircleL.CircleS1.y = cenY + Math.sin(circleSNum1 * twoPI) * radius;
CircleL.CircleS2.x = cenX + Math.cos(circleSNum2 * twoPI) * radius2;
CircleL.CircleS2.y = cenY + Math.sin(circleSNum2 * twoPI) * radius2;
CircleL.CircleS3.x = cenX + Math.cos(circleSNum3 * twoPI) * radius3;
CircleL.CircleS3.y = cenY + Math.sin(circleSNum3 * twoPI) * radius3;
CircleL.CircleS4.x = cenX + Math.cos(circleSNum4 * twoPI) * radius4;
CircleL.CircleS4.y = cenY + Math.sin(circleSNum4 * twoPI) * radius4;
CircleL.CircleS5.x = cenX + Math.cos(circleSNum5 * twoPI) * radius1;
CircleL.CircleS5.y = cenY + Math.sin(circleSNum5 * twoPI) * radius1;
}
addEventListener(Event.ENTER_FRAME,move);
Here is how it looks like when I run it:
The problem is likely the way your circles are nested and how you do the calculation.
The .x and .y of a DisplayObject properties are always with respect to the origin of the parent. Looking at your code:
CircleL.CircleS1
CircleL.CircleS2
All the smaller circles have the bigger one as a container. Your calculation however:
cenX + Math.cos(circleSNum1 * twoPI) * radius;
// aka
CircleL.x + Math.cos(circleSNum1 * twoPI) * radius;
starts with adding the coordinates of the parent. This is in contradiction to the above, because "with respect to their parent" already includes the term CircleL.x. You have two options:
Keep the code, but move all the smaller circles outside their parent, so that they are "siblings" of the big circle.
Keep the structure, but change the code to accommodate for that structure and remove the position of the parent from the calculation.

AS3 shooting in multiple directions

i am try trying to make space shooter game in which ship is able to rotate and shoot in all directions, now, i do know basics of trigonometry, but i stuck at this point and my brain seems to be frozen so i seek your help.
I have Ship.as and Turret.as , every ship contains some number of turrets, and this is loop that is responsible to create bullet for each turret on players input and its located in Ship.as.
for (var i:int = 0; i < turrets.length; i++)
{
var _pcos:Number = Math.cos(angle / 180 * Math.PI);
var _psin:Number = Math.sin(angle / 180 * Math.PI);
var bulletX:Number = center.x + turrets[i].distance * _pcos;
var bulletY:Number = center.y + turrets[i].distance * _psin;
var bullet:BulletBase = new bulletClass(bulletX, bulletY, angle);
layerBullets.add(bullet);
bullets.push(bullet);
}
variable center is point positioned in exact center of ships sprite, angle is ships rotation towards mouse, turret.distance is distance from center to turret
This is whats happening in Turret.as
public class Turret extends Point
{
private var ship:Ship;
public var distance:Number;
public var angle:Number;
/**
*
* #param x position with angle 0
* #param y position with angle 0
* #param distance distance from center of ship to turret
*/
public function Turret(x:Number = 0, y:Number = 0, ship:Ship = null)
{
super(x, y);
this.ship = ship;
this.x = x;
this.y = y;
var dx:Number = ship.center.x - x;
var dy:Number = ship.center.y - y;
angle = Math.atan2(dy, dx);
distance = Math.sqrt(dx * dx + dy * dy);
}
Now, what is happening with this code is that bullets seems like they are fired from same direction, only one bullet is behind.
I am not math expert and if anyone knows the answer i would really appreciate it.
var _pcos:Number = Math.cos((turret.angle + angle) / 180 * Math.PI);
var _psin:Number = Math.sin((turret.angle + angle) / 180 * Math.PI);
angle is angle of ship

AS3 - Catch the ball game

I'm making a little app where you can drag and drop a ball. When you hit a sphere with this ball, you get a point and the ball moves to a random cordinate. My problem is that, after you have hitted the sphere the first time, it changes position, but you can hit it again. Here is the code (without the drag and drop)
ball.addEventListener(Event.ENTER_FRAME, hit);
var randX:Number = Math.floor(Math.random() * 540);
var randY:Number = Math.floor(Math.random() * 390);
function hit(event:Event):void
{
if (ball.hitTestObject(s)){ //s is the sphere
s.x = randX + s.width;
s.y = randY + s.width;
}
}
It seems that your randX and randY variables will only get evaluated once.
Therefore, if the hit test for the ball returns true, the x/y coordinates of the sphere will change the first time, but never again. How about trying this:
function hit(event:Event):void
{
if (ball.hitTestObject(s))
{
//s is the sphere
s.x = Math.floor(Math.random() * 540) + s.width;
s.y = Math.floor(Math.random() * 390) + s.height; // note I changed width to height
}
}

Constrain MovieClip drag to a circle

...well, to an incomplete circle.
I have a draggable slider that looks like this:
The blue bar has the instance name track and the pink dot has the instance name puck.
I need the puck to be constrained within the blue area at all times, and this is where my maths failings work against me! So far I have the puck moving along the x axis only like this:
private function init():void
{
zeroPoint = track.x + (track.width/2);
puck.x = zeroPoint-(puck.width/2);
puck.buttonMode = true;
puck.addEventListener(MouseEvent.MOUSE_DOWN,onMouseDown);
}
private function onMouseDown(evt:MouseEvent):void
{
this.stage.addEventListener(MouseEvent.MOUSE_MOVE,onMouseMove);
this.stage.addEventListener(MouseEvent.MOUSE_UP,onMouseUp);
}
private function onMouseUp(evt:MouseEvent):void
{
this.stage.removeEventListener(MouseEvent.MOUSE_MOVE,onMouseMove);
}
private function onMouseMove(evt:MouseEvent):void
{
puck.x = mouseX-(puck.width/2);
//need to plot puck.y using trig magic...
}
My thinking is currently that I can use the radius of the incomplete circle (50) and the mouseX relative to the top of the arc to calculate a triangle, and from there I can calculate the required y position. Problem is, I'm reading various trigonometry sites and still have no idea where to begin. Could someone explain what I need to do as if speaking to a child please?
Edit: The fact that the circle is broken shouldn't be an issue, I can cap the movement to a certain number of degrees in each direction easily, it's getting the degrees in the first place that I can't get my head around!
Edit2: I'm trying to follow Bosworth99's answer, and this is the function I've come up with for calculating a radian to put into his function:
private function getRadian():Number
{
var a:Number = mouseX - zeroPoint;
var b:Number = 50;
var c:Number = Math.sqrt((a^2)+(b^2));
return c;
}
As I see it, the problem you solve is finding the closest point on a circle. Google have a lot of suggestions on this subject.
You can optimise it by first detecting an angle between mouse position and circle center. Use Math.atan2() for that. If the angle is in a gap range, just choose the closest endpoint: left or right.
EDIT1 Here is a complete example of this strategy.
Hope that helps.
import flash.geom.Point;
import flash.events.Event;
import flash.display.Sprite;
var center:Point = new Point(200, 200);
var radius:uint = 100;
var degreesToRad:Number = Math.PI/180;
// gap angles. degrees are used here just for the sake of simplicity.
// what we use here are stage angles, not the trigonometric ones.
var gapFrom:Number = 45; // degrees
var gapTo:Number = 135; // degrees
// calculate endpoints only once
var endPointFrom:Point = new Point();
endPointFrom.x = center.x+Math.cos(gapFrom*degreesToRad)*radius;
endPointFrom.y = center.y+Math.sin(gapFrom*degreesToRad)*radius;
var endPointTo:Point = new Point();
endPointTo.x = center.x+Math.cos(gapTo*degreesToRad)*radius;
endPointTo.y = center.y+Math.sin(gapTo*degreesToRad)*radius;
// just some drawing
graphics.beginFill(0);
graphics.drawCircle(center.x, center.y, radius);
graphics.moveTo(center.x, center.y);
graphics.lineTo(endPointFrom.x, endPointFrom.y);
graphics.lineTo(endPointTo.x, endPointTo.y);
graphics.lineTo(center.x, center.y);
graphics.endFill();
// something to mark the closest point
var marker:Sprite = new Sprite();
marker.graphics.lineStyle(20, 0xFF0000);
marker.graphics.lineTo(0, 1);
addChild(marker);
var onEnterFrame:Function = function (event:Event) : void
{
// circle intersection goes here
var mx:int = stage.mouseX;
var my:int = stage.mouseY;
var angle:Number = Math.atan2(center.y-my, center.x-mx);
// NOTE: in flash rotation is increasing clockwise,
// while in trigonometry angles increase counter clockwise
// so we handle this difference
angle += Math.PI;
// calculate the stage angle in degrees
var clientAngle:Number = angle/Math.PI*180
// check if we are in a gap
if (clientAngle >= gapFrom && clientAngle <= gapTo) {
// we are in a gap, no sines or cosines needed
if (clientAngle-gapFrom < (gapTo-gapFrom)/2) {
marker.x = endPointFrom.x;
marker.y = endPointFrom.y;
} else {
marker.x = endPointTo.x;
marker.y = endPointTo.y;
}
// we are done here
return;
}
// we are not in a gp, calculate closest position on a circle
marker.x = center.x + Math.cos(angle)*radius;
marker.y = center.y + Math.sin(angle)*radius;
}
addEventListener(Event.ENTER_FRAME, onEnterFrame);
EDIT2 Some links
Here are some common problems explained and solved in a brilliantly clear and concise manner: http://paulbourke.net/geometry/ This resource helped me a lot days ago.
Intersection of a line and a circle is a bit of an overkill here, but here it is: http://paulbourke.net/geometry/sphereline/
Rather than trying to move the point along the partial path of the circle, why not fake it and use a knob/dial? Skin it to look like the dot is moving along the path.
Then just set the rotation of the knob to:
var deg:Number = Math.atan2(stage.mouseY - knob.y,stage.mouseX - knob.x) / (Math.PI/180);
// code to put upper/lower bounds on degrees
knob.rotation = deg;
You can test this by throwing it in an enter frame event, but you'll obviously want to put some logic in to control how the knob starts moving and when it should stop.
100% working code.
enter code here
const length:int = 100;
var dragging:Boolean = false;
var tx:int;
var ty:int;
var p1:Sprite = new Sprite();
var p2:Sprite = new Sprite();
p1.graphics.beginFill(0);
p1.graphics.drawCircle(0, 0, 10);
p1.graphics.endFill();
p2.graphics.copyFrom(p1.graphics);
p1.x = stage.stageWidth / 2;
p1.y = stage.stageHeight / 2;
p2.x = p1.x + length;
p2.y = p1.y;
addChild(p1);
addChild(p2);
p2.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
function mouseDown(event:MouseEvent):void
{
dragging = true;
}
function mouseUp(event:MouseEvent):void
{
dragging = false;
}
function mouseMove(event:MouseEvent):void
{
if (dragging)
{
tx = event.stageX - p1.x;
ty = event.stageY - p1.y;
if (tx * tx + ty * ty > length * length)
{
p2.x = p1.x + tx / Math.sqrt(tx * tx + ty * ty) * length;
p2.y = p1.y + ty / Math.sqrt(tx * tx + ty * ty) * length;
}
else
{
p2.x = event.stageX;
p2.y = event.stageY;
}
}
}
Something like this ought to work out:
private function projectLocation(center:point, radius:uint, radian:Number):Point
{
var result:Point = new Point();
//obtain X
result.x = center.x + radius * Math.cos(radian));
//obtain Y
result.y = center.y + radius * Math.sin(radian));
return result;
}
Obviously, modify as needed, but you just need to send in a center point, radius and then a radian (you can obtain with angle * (Math.PI / 180)). You could easily hard code in the first two params if they don't change. What does change is the radian, and that is what you will need to change over time, as your mouse is dragging (defined by the mouseX distance to the center point - positive or negative).
Hopefully that helps get you started -
update
This was how I was working this out - tho its a tad buggy, in that the puck resets to 0 degrees when the sequence starts. That being said, I just saw that - #Nox got this right. I'll post what I was arriving at using my projectLocation function anyways ;)
package com.b99.testBed.knob
{
import com.b99.testBed.Main;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
/**
* ...
* #author bosworth99
*/
public class Knob extends Sprite
{
private var _puck :Sprite;
private var _track :Sprite;
private const DIAMETER :uint = 100;
private const RADIUS :uint = DIAMETER / 2;
public function Knob()
{
super();
init();
}
private function init():void
{
assembleDisplayObjects();
addEventHandlers();
}
private function assembleDisplayObjects():void
{
_track = new Sprite();
with (_track)
{
graphics.beginFill(0xffffff, 1);
graphics.lineStyle(1, 0x000000);
graphics.drawEllipse(-RADIUS, -RADIUS, DIAMETER, DIAMETER);
graphics.endFill();
}
this.addChild(_track);
_track.x = Main.stage.stageWidth / 2;
_track.y = Main.stage.stageHeight / 2;
_puck = new Sprite();
with (_puck)
{
graphics.beginFill(0x2DFE07, 1);
graphics.drawEllipse(-8, -8, 16, 16);
graphics.endFill();
x = _track.x;
y = _track.y - _track.width / 2;
buttonMode = true;
}
this.addChild(_puck);
}
private function addEventHandlers():void
{
Main.stage.addEventListener(MouseEvent.MOUSE_DOWN, activate);
Main.stage.addEventListener(MouseEvent.MOUSE_UP, deactivate);
}
private function deactivate(e:MouseEvent):void
{
Main.stage.removeEventListener(MouseEvent.MOUSE_MOVE, update);
}
private var _origin:uint;
private function activate(e:MouseEvent):void
{
Main.stage.addEventListener(MouseEvent.MOUSE_MOVE, update);
_origin = mouseX;
}
private function update(e:MouseEvent):void
{
var distance:Number;
(mouseX < _origin)? distance = -(_origin - mouseX) : distance = mouseX - _origin;
if(distance > 40){distance = 40};
if(distance < -220){distance = -220};
var angle:Number = distance; //modify?
var radian:Number = angle * (Math.PI / 180);
var center:Point = new Point(_track.x, _track.y);
var loc:Point = projectLocation(center, RADIUS, radian);
_puck.x = loc.x;
_puck.y = loc.y;
}
private function projectLocation(center:Point, radius:uint, radian:Number):Point
{
var result:Point = new Point();
//obtain X
result.x = center.x + radius * Math.cos(radian);
//obtain Y
result.y = center.y + radius * Math.sin(radian);
return result;
}
}
}
Main difference is that I'm obtaining the angle via horizontal (x) movement, and not checking against the cursors angle. Thos, trapping the values manually feels kinda hacky compared to #Nox very good soution. Would of cleaned up had I kept going;)
Nice question - Cheers