Rotate object around centre? - actionscript-3

I'm working on a project and need a wheel that rotates with mouse movement, I've made the wheel rotate with the mouse, but it rotates around the corner, not the center.
What code can I add to this to make it rotate around the center?
This is the code I'm using so far:
var dx : Number;
var dy : Number;
stage.addEventListener( Event.ENTER_FRAME, checkMouse );
function checkMouse( evt : Event ) : void
{
dx = mouseX - rota.x;
dy = mouseY - rota.y;
rota.rotation = (Math.atan2(dy, dx) * 180 / Math.PI);
}

You'll only ever be rotating an object around its origin, and the origin can't be moved. However, you can move a child object to rest at the center of its parent's origin. When rotating the parent, the child appears to move around its own center.
Programmatically, if wheel is a child of rota, you'd do the following...
wheel.x = -wheel.width/2;
wheel.y = -wheel.height/2;
rota.rotation = (Math.atan2(dy, dx) * 180 / Math.PI)

Related

How to create smooth motion for a mouse follower along a predefined path?

I want to make a tracing game. I want my circle to follow the path as the user traces the letter (path of the letter). The user can not go back to the area which is already traced
import flash.events.Event;
import flash.geom.Point;
var i: Number;
var size: int = 80;
var down: Boolean = false;
var up: Boolean = true;
var inside: Boolean = true;
var outside: Boolean = true;
var circle: Shape = new Shape();
stage.addEventListener(Event.ENTER_FRAME, loop);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseup);
char.addEventListener(MouseEvent.MOUSE_DOWN, mousedown);
function loop(e: Event) {
if (down == true) {
// Checks if mouse pointer is on path i.e 'S' alphabet
if (s.hitTestPoint(stage.mouseX, stage.mouseY, true)) {
inside = true;
outside = true;
var point: Point = maskobj.globalToLocal(new Point(stage.mouseX, stage.mouseY));
var point2: Point = new Point();
//Checks if mouse pointer is completely outside of drawn area
for (i = 0; i < 2 * Math.PI; i += (2 * Math.PI) / 10) {
point2.x = stage.mouseX + (size / 3) * Math.cos(i);
point2.y = stage.mouseY + (size / 3) * Math.sin(i);
if ((maskobj.hitTestPoint(point2.x, point2.y, true))) {
outside = false;
break;
}
}
//Checks if mouse pointer is completely inside drawn area
for (i = 0; i < 2 * Math.PI; i += (2 * Math.PI) / 10) {
point2.x = stage.mouseX + (size / 3) * Math.cos(i);
point2.y = stage.mouseY + (size / 3) * Math.sin(i);
if (!(maskobj.hitTestPoint(point2.x, point2.y, true))) {
inside = false;
break;
}
}
//Character will be moved only if mouse position not to far from current position
if (outside == false) {
if (inside == false) {
//Increases drawn area by drawing a circle shape in 'maskobj' MovieClip
circle.graphics.beginFill(0x0000ff);
circle.graphics.drawCircle(point.x, point.y, size);
circle.graphics.endFill();
maskobj.addChild(circle);
//Moves character to new position
char.x = stage.mouseX;
char.y = stage.mouseY;
}
}
}
}
}
function mouseup(e: MouseEvent): void {
up = true;
down = false;
}
function mousedown(e: MouseEvent): void {
down = true;
up = false;
}
When I trace the path,the motion is not smooth. Can someone please suggest a way to make the motion smooth OR suggest another way to achieve the same. Thank you in advance.
I've created a drawing game before that allowed the user to draw a path.
Not sure why Wicked's answer was down-voted, as the first thing you need to do is to use the highest frame rate that you can get away with. The higher the frame rate, the smoother your curve.
I see that your code draws a circle at the current position if the conditions are met. It might be better to draw a line from the last point.x/point.y to the current one instead of just a circle, so that you don't have any holes in your path.
I couldn't get around the fact that the line was jagged (a series of straight lines) as it was being drawn, but as soon as the user lifted their finger I was able to take the points along the line they had drawn and replace them with a smooth bezier Path (a series of simple bezier curves), which worked well. You could also do this on-the-fly once you have 3 points (you need 3 points to draw a curve).
Here is a good reference on how to achieve this, with theory and code samples. See further down the page for bezier paths. You'll need to convert to AS3, but it shouldn't be difficult.
Another tip is to do as little calculation as possible within the ENTER_FRAME. You could pre-calculate the two values used by your loops (2 * Math.PI) and ((2 * Math.PI) / 10) as these are constants. You could also calculate (size/3) once at the top of the function, and especially pre-calculate the 10 values for Math.sin(i) and Math.cos(i) and store them in an Array (basically a LUT - Look Up Table) as these are the heaviest math ops you're doing.
My final tip is that your code doesn't check if the point being drawn is very close to the last point that was drawn. I would recommend you do this, and only draw a point after the mouse has moved a minimum distance (e.g. 2 pixels). Otherwise you could get the mouse sitting still in one spot and your code is drawing circle upon circle on top of itself needlessly.
Try increasing the FPS in your document to atleast double what you currently have
Modify>Document...>Frame Rate

as3 - How do I make an object rotate to the crosshair instead of the mouse?

I placed the arm movieclip instance inside of the player movieclip instance. The crosshair instance is placed in the player movieclip's parent.
I'm trying to get the arm to rotate by following the crosshair. I tried using mouseX and mouseY and that seemed to work except I want the arm to follow the crosshair, not the mouse. The crosshair is placed in the player movieclip's parent so I use MovieClip(parent), so I put this code in the player class' enterframe:
var dx = MovieClip(parent).crosshair.x - arm.x;
var dy = MovieClip(parent).crosshair.y - arm.y;
var angle = Math.atan2(dy, dx) / Math.PI * 180;
arm.rotation = angle;
However when I do this, the arm does not rotate at all. What am I supposed to be doing?
The crosshair is an instance that is outside the movieclip and has the instance name of "crosshair". It's not a variable.
The code for the crosshair is inside player's parent's enterframe:
crosshair.x += (mouseX - crosshair.x) / 5;
crosshair.y += (mouseY - crosshair.y) / 5;
You need to convert the coords inside player MovieClip to the coords in the same system that the crosshair MovieClip using localToGlobal and globalToLocalmethods.
An example code:
this.addEventListener(Event.ENTER_FRAME, rotateArm);
var crosshair:MovieClip = MovieClip(this.parent).crosshair;
//---Rotate arm function
function rotateArm(evt:Event):void{
//---Move crosshair
moveCrossHair();
//---Convert the local Point to global Point
var point:Point = new Point(this.arm.x, this.arm.y);
var parentPoint:Point = this.parent.globalToLocal(this.localToGlobal(point));
var dx:Number = crosshair.x - parentPoint.x;
var dy:Number = crosshair.y - parentPoint.y;
var angle:Number = Math.atan2(dy, dx) / Math.PI * 180;
this.arm.rotation = angle;
}
//---Move crosshair function
function moveCrossHair():void{
crosshair.x += (this.parent.mouseX - crosshair.x) / 5;
crosshair.y += (this.parent.mouseY - crosshair.y) / 5;
}
Here you have a working example, it was built with Flash Pro but I've included a xfl example.
Download Example

as3 - How to access child's child?

I dispatched an event for a bullet to spawn on the page. However the bullet should be located in the area where the page's child child should be. There is a Page One MovieClip, which has a child named player and the player's child is gun. So I'm trying to keep the location and rotation of the bullet the same as the player's gun. So I need to access Page One's child's child. The player and the turret are using instance names and not variables.
I tried this code, but the bullet spawns in the page but will not spawn itself on the turret's location. This event is located in the PageOne class.
function fire(e:Event)
{
var b:Bullet = new Bullet();
b.rotation = player.turret.rotation;
b.x = player.turret.x + player.turret.width * Math.cos(player.turret.rotation / 180 * Math.PI);
b.y = player.turret.y + player.turret.width * Math.sin(player.turret.rotation / 180 * Math.PI);
addChild(b);
}
You can access to the turret child. The problem is that you need to convert the coords inside the turret MovieClip to the coords inside the PageOne MovieClip:
var b: Bullet = new Bullet();
var turretpoint:Point = new Point(player.turret.width, 0);
var pagepoint: Point = this.globalToLocal(player.turret.localToGlobal(turretpoint));
b.rotation = (player.scaleX > 0) ? player.turret.rotation : 180 - player.turret.rotation;
b.x = pagepoint.x;
b.y = pagepoint.y;
addChild(b);

How do I constrain a turret's movements?

I have a turret I want to constrain rotation with the turret rotating and facing the mouse, so it doesn't go over the maximum rotation and stops rotating if you reach the maximum point. and does not go lower than minimum degrees when it reaches minimum degrees, but the max and min angles change depending on the side the mouse is facing.
When the mouse goes on the right side of the turret, aka mouseX is greater than turret's x position.
the turret will change scaleX and the turret turns to the right and has constrained aiming rotation between 120 degrees and -160.
when the turret faces left, aka the mouseX is less than the turret's x position. the turret will switch scaleX and turn to the left. then, the constrained aiming rotation switches to between 70 degrees and -20 degerees.
Here is my code, I'm new to calculating rotations and degrees so I think I got it completely wrong, because the turret doesn't rotate at all unless i remove the code. I need help on fixing the code. Thanks!
function update(e:Event)
{
//make the turret face the mouse
if (parent != null)
{
var dx = parent.mouseX - x;
var dy = parent.mouseY - y;
var angle = Math.atan2(dy, dx)/Math.PI * 180;
//this is supposed to constrain the rotation if the mouse is bigger than turret's x
//position, else constrain it the other way, this part of the code doesnt work.
//this code makes it so the turret is unable rotate at all
//if i remove the code, the turret can rotate freely though.
if(mouseX > x)
{
angle=Math.min(angle,120);
angle=Math.max(angle,-160);
}
else
{
angle=Math.min(angle,-20);
angle=Math.max(angle,70);
}
rotation = angle;
}
}
You haven't specified how update is being called. If it's called by (say) a mouse move event, you can get the mouse coords directly from the event.
Here is another version which works for me using that technique. Script is in the timeline of the 'turret' movieclip.
function update(e:MouseEvent)
{
//make the turret face the mouse
if (parent != null)
{
var dx = e.stageX - x;
var dy = e.stageY - y;
var angle = Math.atan2(dy,dx) / Math.PI * 180;
//this is supposed to constrain the rotation if the mouse is bigger than turret's x
//position, else constrain it the other way, this part of the code doesnt work.
//this code makes it so the turret is unable rotate at all
//if i remove the code, the turret can rotate freely though.
if (mouseX > x)
{
angle = Math.min(angle,120);
angle = Math.max(angle,-160);
}
else
{
angle = Math.min(angle,-20);
angle = Math.max(angle,70);
}
rotation = angle;
}
}
stage.addEventListener(MouseEvent.MOUSE_MOVE, update);

ActionScript applying rotation of sprite to startDrag()'s rectangle bounds

from my main class i call to create a sprite and add it to the stage
private function addSwatch(evt:MouseEvent):void
{
if (stage.getObjectsUnderPoint(mousePoint()).length == 0)
{
var swatchSide:Number = 100;
var newSwatch:Sprite = new Swatch(0 - swatchSide/2, 0 - swatchSide/2, swatchSide, swatchSide);
newSwatch.x = mouseX;
newSwatch.y = mouseY;
addChild(newSwatch);
}
}
i've added a swatch sprite to the stage which, when dragged, is contained within set boundaries.
this.startDrag(false, swatchBounds());
...
private function swatchBounds():Rectangle
{
var stageBounds = new Rectangle (
0 - defaultSwatchRect.x,
0 - defaultSwatchRect.y,
stage.stageWidth - defaultSwatchRect.width,
stage.stageHeight - defaultSwatchRect.height
);
return stageBounds;
}
if the square sprite is scaled, the following returned rectangle boundary works
private function swatchBounds():Rectangle
{
var stageBounds = new Rectangle (
0 - defaultSwatchRect.x * swatchObject.scaleX,
0 - defaultSwatchRect.y * swatchObject.scaleY,
stage.stageWidth - defaultSwatchRect.width * swatchObject.scaleX,
stage.stageHeight - defaultSwatchRect.height * swatchObject.scaleY
);
return stageBounds;
}
now i'm trying to include the square sprites rotation into the mix. math certainly isn't my forté, but i feel i'm on the write track. however, i just can't seem to wrap my head around it to get it right
private function swatchBounds():Rectangle
{
var stageBounds = new Rectangle (
0 - defaultSwatchRect.x * swatchObject.scaleX * Math.cos(defaultSwatchRect.x * swatchObject.rotation),
0 - defaultSwatchRect.y * swatchObject.scaleY * Math.sin(defaultSwatchRect.y * swatchObject.rotation),
stage.stageWidth - defaultSwatchRect.width * swatchObject.scaleX * Math.cos(defaultSwatchRect.width * swatchObject.rotation),
stage.stageHeight - defaultSwatchRect.height * swatchObject.scaleY * Math.sin(defaultSwatchRect.height * swatchObject.rotation)
);
return stageBounds;
}
My idea is that instead of using complicated trig, just get the bounding rect of swatchObject using swatchObject.getRect() and then create your stageBounds based on that. It should be more than good enough for your purposes.
If that is not what you want, I can help you figure out the math.
And sorry, I can't really give you a function until I figure out what defaultSwatchRect is - where its x and y is and what it's supposed to do.
Another thing you may want to keep in mind for the future: the Math functions (cos, sin) expect the angle in radians, whereas the .rotation property is in degrees, so you must convert before using.