as3 - How to access child's child? - actionscript-3

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

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

Arrange Z-index of movieclip and sprite in Actionscript AS3

I found this piece of code which apparently sets the 'z-index' of a child object, however I have a movieclip on the stage and a sprite which is being generated from the actions class. I understand they have to be within the same parent? but have no idea how to do this.
parent.setChildIndex(childObject, i)
My pie chart sprite is called into being with this function...
this.graphics.clear();
this.graphics.lineStyle(3, 0xFFFFFF);
this.graphics.beginFill(0xFF0000, 0.5);
this.drawSegment(this, stage.stageWidth/2, stage.stageHeight/2, piesize, wedge1start, wedge1end);
this.drawSegment(this, stage.stageWidth/2, stage.stageHeight/2, piesize, wedge1end, wedge2end);
this.drawSegment(this, stage.stageWidth/2, stage.stageHeight/2, piesize, wedge2end, wedge3end);
this.drawSegment(this, stage.stageWidth/2, stage.stageHeight/2, piesize, wedge3end, wedge4end);
this.graphics.endFill();
public function drawSegment(target:Sprite, x:Number, y:Number, r:Number, aStart:Number, aEnd:Number, step:Number = 1):void {
// More efficient to work in radians
var degreesPerRadian:Number = Math.PI / 180;
aStart *= degreesPerRadian;
aEnd *= degreesPerRadian;
step *= degreesPerRadian;
// Draw the segment
target.graphics.moveTo(x, y);
for (var theta:Number = aStart; theta < aEnd; theta += Math.min(step, aEnd - theta)) {
target.graphics.lineTo(x + r * Math.cos(theta), y + r * Math.sin(theta));
}
target.graphics.lineTo(x + r * Math.cos(aEnd), y + r * Math.sin(aEnd));
target.graphics.lineTo(x, y);
}
currently I just plonked my movieclip on the stage but I'm going to guess I need to call the movieclip from the actions class as well. I think I can manage that but can't figure out how to first create a parent and then call those 2 children into it.
Thanks for any help
You need to wrap those two graphics into two separate Sprite objects. Those two objects can be added to stage (or this in your case, I don't know what is it). So you will have a parent object with two children objects. Then you can swap them.
Working with graphics disables your option to swap them. It's a single object in which you are drawing.
So you just need to wrap those graphics into another child:
var drawings:Sprite = new Sprite();
drawings.graphics.clear(); // instead of this.graphics.clear()
drawings.graphics.lineStyle(3, 0xFFFFFF);
this.drawSegment(drawings, stage.stageWidth/2 ...) // pass DRAWINGS instead of this
this.addChild(drawings);
This way you have wrapped all those graphics and added them to this. Now you can use:
this.swapChildren(drawings, otherChild); // swaps two objects
this.setChildIndex(drawings, 5); // sets index for drawings only

AS#3 target ignoring parent movieClip

I changed the question as its seems to be a problem with target not registering children mc/ or nested MovieClips.
var box:Box = new Box();
ground.push(box);
levelPlane.addEventListener(MouseEvent.MOUSE_DOWN, onOver);
box.x = box.width /2* (x + y);
box.y = box.height/2 * (x - y);
levelPlane.addChild(box);
function onOver(e:MouseEvent):void{
var tree1:Tree1 = new Tree1();
addChild(tree1)
trace(e.target.x);
tree.x = e.target.x;
}
How Do i target the movieclips(BOX) inside of the main MovieClip(levelPlane)?
imagine i have nested 10 boxes inside a MovieClip Called "levelPlane" i want to click on any of the boxes to add another Mc on the box i clicked x,y location.
If I understand correctly, you are trying to place the newly created movie clip on top of the other, but they are not within the same coordinate space. The target's coordinates must be translated to tree1's coordinate space, for both of them to have the same position:
var tree1:Tree1 = new Tree1();
addChild(tree1);
var global:Point = e.target.parent.localToGlobal(new Point (e.target.x, e.target.y));
var local:Point = globalToLocal(global);
tree1.x = local.x;
tree1.y = local.y;
The Event.currentTarget property refers to the current object processing the event, i.e., the listener object. If you want reference to the object which dispatched the event, use e.target

ActionScript 3 - Tweening rotateAroundExternalPoint

i'm unsuccessfully trying to rotate a rectangle around an external point while tweening. i'm trying to lock the top of the red rectangle to the line while it tweens from left to right and rotates from 0º to 90º.
alt text http://www.freeimagehosting.net/uploads/0b937c92e6.png
the image above shows 3 states of the tween. state 1 shows the red rectangle at the start of the line with no angle. state 2 shows the red rectangle has tweened half way along the line with an angle of 45º that is also half the total angle of 90º. state 3 shows the final position of the tween where the red rectangle has an angle of 90º and is placed at the edge of the line.
it seems the problem i'm experiencing is that while tweening, the rotation causes the top of the red rectangle to lose sync with the black line.
here is my code that doesn't work, but hopefully will give you a clearer picture of what i'm attempting.
var angle:Number = 90;
var previousAngle:Number = 0;
var distanceObject:Object = new Object();
distanceObject.distance = line.width;
distanceTween = new Tween(distanceObject, "distance", None.easeNone, 0, distanceObject.distance, 5, true);
distanceTween.addEventListener(TweenEvent.MOTION_CHANGE, tweenHandler);
function tweenHandler(evt:TweenEvent):void
{
var angleShift:Number = (angle / distance) * distanceObject.distance;
//1:tween RedBox position
redBox.x = line.x + line.width * distanceObject.distance;
//2:tween RedBox angle
var externalPointMatrix:Matrix = redBox.transform.matrix;
MatrixTransformer.rotateAroundExternalPoint(externalPointMatrix, 0 + redBox.width * distanceObject.distance, 0, angleShift - previousAngle);
redBox.transform.matrix = externalPointMatrix;
previousAngle = angleShift;
}
I don't think you have specified the problem well enough for a generic solution. There are 3 things changing here: x, y and rotation. Each of these is calculated as a result of a point on the rectangle (the blue "x" in your diagram) that changes over time. That means the thing you need to focus on first is the point on the rectangle that changes over time. Next you need to know that the x and y can be calculated using that point along with the rotation.
So break it down into steps.
find the location of the "x" point on the line
rotate the object
find the location of the "x" point wrt to the rectangle
based on the angle of rotation and the known location of the "x" point calculate the x and y position of the rectangle (SOHCAHTOA)
Here is some code to illustrate:
package
{
import com.greensock.TweenNano;
import flash.display.Sprite;
import flash.events.Event;
[SWF(width='500', height='300', backgroundColor='#ffffff', frameRate='30')]
public class BoxAnim extends Sprite
{
private static const LINE_WIDTH:int = 350;
private static const RECT_WIDTH:int = 150;
private static const RECT_HEIGHT:int = 100;
private static const FINAL_ROTATION:Number = Math.PI/2;
public var point:Number;
private var line:Sprite;
private var rect:Sprite;
private var cross:Sprite;
public function BoxAnim()
{
addEventListener(Event.ADDED_TO_STAGE, addedToStage);
}
private function addedToStage(event:Event):void
{
line = new Sprite();
addChild(line);
line.graphics.lineStyle(10, 0x0);
line.graphics.lineTo(LINE_WIDTH, 0);
line.x = 50;
line.y = 175;
rect = new Sprite();
addChild(rect);
rect.graphics.lineStyle(4, 0xFF0000);
rect.graphics.beginFill(0xFF0000, 0.5);
rect.graphics.drawRect(0, 0, RECT_WIDTH, RECT_HEIGHT);
rect.x = 50;
rect.y = 175;
cross = new Sprite();
addChild(cross);
cross.graphics.lineStyle(5, 0x41a9f4);
cross.graphics.moveTo(-5, -5);
cross.graphics.lineTo(5, 5);
cross.graphics.moveTo(5, -5);
cross.graphics.lineTo(-5, 5);
cross.x = 50;
cross.y = 175;
point = 0;
TweenNano.to(this, 3, {point: 1, onUpdate: tick});
}
private function tick():void
{
// first calculate where the point should be on the line
cross.x = (point * LINE_WIDTH) + line.x;
// calculate the angle of rotation
var rotationRadians:Number = (point * FINAL_ROTATION);
rect.rotation = rotationRadians*180/Math.PI;
// calculate where on the rectangle the point would be
var rectCrossX:Number = (point * RECT_WIDTH);
// use trig to find the x & y points
rect.x = cross.x - Math.cos(rotationRadians)*rectCrossX;
rect.y = cross.y - Math.sin(rotationRadians)*rectCrossX;
}
}
}
I'm just using the variable point as a percentage that goes from 0 to 1. I then scale it to find the position of the "x" point on the line. Scale it again to figure out the rotation. Scale it again to find where it lies along the top of the rectangle. Then trig solves the location of the corner of the rectangle wrt the point.