Updating element position using ENTER_FRAME event - actionscript-3

I have an issue in simple arkanoid game in updating paddle position, I am using following listener to react:
paddle.addEventListener(Event.ENTER_FRAME, movePaddle)
when movePaddle() function is defined in Main everything is working just fine, but when I refactored code and putted movePaddle() functions into Paddle class and changed listener into:
paddle.addEventListener(Event.ENTER_FRAME, paddle.movePaddle)
The result is paddle changing position every frame between the desired one, and some other value
Below movePaddle() function:
public function movePaddle(event:Event):void
{
// DEBUG
trace(this.x);
trace(this.y);
this.x = mouseX - this.width / 2;
if(mouseX < this.width / 2)
{
this.x = 0;
}
// To much to right
if(this.x >= stage.stageWidth - this.width)
{
// To much to left
this.x = stage.stageWidth - this.width;
}
}
Second question:
Is using ENTER_FRAME event good in terms of optimalisation for games ?

As Cameron mentioned, if you move movePaddle() to the Paddle class itself, mouseX and mouseY will refer to the mouse position within the Paddle MovieClip. That is, if the Paddle is at 50,50 on the stage, and the mouse is at 100, 100 on the stage, the mouse coordinates you will receive will be 50,50.
A safer option is to use the mouseX and mouseY values given by the Stage:
public function movePaddle(event:Event):void
{
if(stage != null)
{
x = stage.mouseX - width / 2;
if(stage.mouseX < width / 2)
{
this.x = 0;
}
// To much to right
if(x >= stage.stageWidth - width)
{
// To much to left
x = stage.stageWidth - width;
}
}
}
Another thing I would do is rather than having this line in the Main class:
paddle.addEventListener(Event.ENTER_FRAME, paddle.movePaddle);
I would instead put that in Paddle's constructor like so:
public function Paddle()
{
addEventListener(Event.ENTER_FRAME, movePaddle);
}
As for performance of ENTER_FRAME, this is fine however in a properly structured game I would have a single ENTER_FRAME handler which loops over an Array of game entities and them updates them all by calling a method on each.

Related

How to define the position of a movieclip in relation to that of another of movieclip

I am trying to make a movieclip follow a custom mouse pointer (which is a movieclip) but always stay at a defined postion (in terms of coordinates), a distance away from the mouse pointer on easing to where the mouse pointer is. Below is the code:
import flash.display.MovieClip;
import flash.events.Event;
Mouse.hide();
var mouseCounter:int = 0;
var mouseDelay:int = 5;// how many frames the mouse must stay still before the follow code is run.
var speed:Number = 5;
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
stage.addEventListener(Event.ENTER_FRAME,follow);
// set counter back to zero whenever the mouse is moved.
function mouseMove(e:MouseEvent):void
{
wand.x = stage.mouseX;
wand.y = stage.mouseY;
e.updateAfterEvent();
mouseCounter = 0;
}
function follow(e:Event):void
{
// increment the counter each frame
mouseCounter++;
// now run the follow block if the mouse has been still for enough frames.
if (mouseCounter >= mouseDelay)
{
orb_mc.x -= (orb_mc.x - mouseX) / speed;
orb_mc.y -= (orb_mc.y - mouseY) / speed;
orb_mc.x = mouseX + 46.5;
orb_mc.y = mouseY +50.95;
}
}
The last two lines of codes (26 & 27), is what I used to define the orb_mc's position in relation to the custom mouse pointer which is "wand" however it seems to have resulted in the ease movement of the orb been hampered, so dont know if the positioning code I used is wrong
function follow(e:Event):void
{
// increment the counter each frame
mouseCounter++;
// now run the follow block if the mouse has been still for enough frames.
if (mouseCounter >= mouseDelay)
{
// Do this:
orb_mc.x -= (orb_mc.x - mouseX + 46.5) / speed;
orb_mc.y -= (orb_mc.y - mouseY + 50.95) / speed;
// OR this:
//orb_mc.x = orb_mc.x - (orb_mc.x - mouseX + 46.5) / speed;
//orb_mc.y = orb_mc.y - (orb_mc.y - mouseY + 50.95) / speed;
// but not both.
}
}
You see, once you use one of the increment assignment operators (-=,+=,/=,*=), immediately following that by a regular assignment operator will obviously override any value it had before. You understand that actionscript gets "read" by the computer (this is probably the wrong verbiage but you get my drift) and it reads each block (an area inside a curly brace set { }) from top to bottom. So the very first time that your follow method is called, it is doing 4 things, in order:
increment the counter
evaluate if mouseCounter >= mouseDelay
increments orb_mc x/y coords
assigns orb_mc x/y coords to final destination
It is doing this on the very first time the follow block is read. This is why both acceptable bits of code in my answer do 2 things:
they increment the x/y coords (don't set them to a final value)
they change based on a variable factor (speed)
Glad it's working!

AS3 move towards mouse click

In a side-scroller type game, I want the object to move wherever I click the mouse and then stop at that location. What is the best way to accomplish this? The object can only move on the x-axis so I don't have to worry about moving on the y-axis.
What I would do is set a target x coordinate, then move towards it each frame (or timer tick) based on a constant movement speed.
const moveSpeed:Number = 5;
var targetX:Number = 0;
stage.addEventListener(MouseEvent.CLICK, click);
function click(e:MouseEvent):void {
targetX = mouseX;
addEventListener(Event.ENTER_FRAME, update);
}
function update(e:Event):void {
if (Math.abs(targetX - player.x) < moveSpeed) {
// reached target
player.x = targetX;
} else if (targetX > player.x) {
// move right
player.x += moveSpeed;
} else {
// move left
player.x -= moveSpeed;
}
}
Use tweener:
http://hosted.zeh.com.br/tweener/docs/en-us/
And apply a tween like this:
Tweener.addTween(myObject, {_x:myObject.parent.mouseX, time:1, transition:"linear"});
And you can play with the time and the transition type. Good overview of transition types can be found here:
http://hosted.zeh.com.br/tweener/docs/en-us/misc/transitions.html

I got an Error #1009 saying I Cannot access a property or method of a null object reference. Now what?

So I got that error when trying to run my game. It's a simple little game that revolves around picking up orbiting jerry cans whilst trying to avoid orbiting enemies. So I hit Ctrl+Shft+Enter and found the problem was at line 26 (if (this.y +...) in my Ship Class.
package
{
import flash.display.Sprite;
import flash.events.Event;
public class Ship extends Sprite
{
public function Ship(_x:int,_y:int)
{
this.x = _x;
this.y = _y;
//adds event listener that allows the player to move
addEventListener(Event.ENTER_FRAME, player_move);
}
public function player_move(e:Event)
{
//check if at left or right side of stage
if (this.y - this.height / 2 <= 0)
{
this.y = 50;
}
if (this.y + this.height / 2 >= stage.height - this.height)
{
this.y = 370;
}
if (this.x - this.width / 2 <= 0)
{
this.x = 50;
}
if (this.x + this.width / 2 >= stage.width - this.width)
{
this.x = 500;
}
}
public function left():void
{
//the speed in which the player will move left
this.x -= 10;
}
public function right():void
{
//the speed in which the player will move right
this.x += 10;
}
public function up():void
{
//the speed in which the player will move right
this.y -= 10;
}
public function down():void
{
//the speed in which the player will move right
this.y += 10;
}
}
}
Now what do I do? How do I fix this? I can't find the answer anywhere. I know it has something to do with my Main class as in it, I have stated that if the Player his the enemy, his ship is placed back at his original co-ords.
Any help would be greatly appreciated. Thanks.
Your null object is the stage reference. Every DisplayObject has a reference to the stage, however, this is null until the object is actually on the stage.
The stage is the main container of your application. Everything that is visual in your application will be on the stage in some way. Your main document class will be on the stage, all timeline objects, etc.
Your object is counted as being on stage even if its added to a different container, just as long as that container is on the stage in some way. So to put it in the most basic terms, if the object is somewhere where the user should be able to see it, stage will not be null.
To work around this, you're going to have to add your ENTER_FRAME event listener after your object has been added to the stage. Luckily, you can listen for an event that is fired when this happens.
In the constructor:
addEventListener(Event.ADDED_TO_STAGE, init);
Then add your handler:
private function init(evt:Event){
addEventListener(Event.ENTER_FRAME, player_move);
}
Remember, stage will be null until an object is added to the stage, which is the event we're listening for now. Then, just add your ship to the main game or whichever container it's going in, container.addChild(ship), and if that container is a part of the stage, you should be good to go.

Why isn't it going off stage?

The objective is for the red circle move horizontally to the left and when completely off stage to reappear on the right side.
Why is it that setting the property X in ball.graphics.drawCircle (300, 300, 50); causes the ball to disappear before it reaches the stage left side?
If I leave x being 0 it behaves as I want
Class.
public function RedBall()
{
ball.graphics.beginFill (0xFF0000);
ball.graphics.drawCircle (300, 300, 50);
ball.graphics.endFill();
}
In my main
function update(e:Event):void {
a.ball.x -= 10;
if (a.ball.x < -a.ball.width) {
a.ball.x = stage.stageWidth + a.ball.width;
}
}
I think this probably must be some very obvious errors as I'm beginning to learn AS3 but if needed I can post the whole code.
You are drawing your circle at a point of 300,300, but you are not later accounting for that in your code where you check its position.
You can do one of two things.
Recommended:
Draw the circle at the point of origin, and place the instance of ball at an x of 300.
Alternative:
Use the ball's actual bounds to determine its position:
function update(e: Event): void {
ball.x -= 10;
if (ball.getBounds(stage).x < -ball.width) {
ball.x = stage.stageWidth - ball.getBounds(stage).x;
}
}

AS3: why does the MC "tremble" when selected?

I'm trying to make a simple function to select and drag a MovieClip, without using the startDrag() function.
I have a few MCs on the stage, when mouse down on a MC, I want the MC to move with the mouse. But when I hold the mouse down, the MC starts to "tremble" and I'm not sure why.
I have the code inside each MC for other reasons. Here is what I have so far:
var selectX:Number; //x coordinate of mouse click (to select right point on mc on mouse down)
this.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
this.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
function mouseDownHandler(e:MouseEvent):void {
selectX = this.x - mouseX;
addEventListener(Event.ENTER_FRAME, onEnterFrameHandler);
}
function mouseUpHandler(e:MouseEvent):void {
mouseX2 = mouseX;
removeEventListener(Event.ENTER_FRAME, onEnterFrameHandler);
}
function onEnterFrameHandler(e:Event):void {
this.x = mouseX + selectX + stage.x;
}
This is happening because you are using mouseX of the inside of the movieclip. but when you are trying to set the x of the movieClip it sets the x on the parent movieclip.
e.g.:
mainClip
|-- DragableButton
when you adding DragableButton.x = 100, it is x position insided of the mainClip.
and when your code is taking mouseX inside of the DragableButton, the real mouseX = x + mouseX. and since mouseX inside of the DragableButton is equals e.g. 20, and you adding: selectX = this.x - mouseX -> if you have selectX = 100 - 20. but not 100 - 120 as it should be.
so if you still want to keep to your code change it a bit:
var selectX:Number; //x coordinate of mouse click (to select right point on mc on mouse down)
var mouseX2:Number;
this.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
this.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
function mouseDownHandler(e:MouseEvent):void {
selectX = this.x - parent.mouseX;
// selectX = this.x - stage.mouseX;
addEventListener(Event.ENTER_FRAME, onEnterFrameHandler);
}
function mouseUpHandler(e:MouseEvent):void {
mouseX2 = parent.mouseX;
removeEventListener(Event.ENTER_FRAME, onEnterFrameHandler);
}
function onEnterFrameHandler(e:Event):void {
this.x = parent.mouseX + selectX;
// this.x = stage.mouseX + selectX;
}
p.s. stage.x = 0, it will be always. unless you change the property.
p.s.s. stage is only one and same instance no matter from which MC you are trying to get it.
my suggestion draging would be:
this.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
function mouseDownHandler(e:MouseEvent):void
{
this.startDrag();
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
}
function mouseUpHandler(e:MouseEvent):void
{
this.stopDrag();
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
}
I think the movieclip is trembling because during your drag, your application keeps calling mouseDownHandler, changing the selectX.
Try removing the MOUSE_DOWN event listener. In mouseDownHandler, make that the first thing you do (this is also a good practice for preventing memory leaks). You can add the listener back when you mouse up (and then remove the mouse up listener).
why are you using Event.ENTER_FRAME event (costly), try to use MouseEvent.MOUSE_MOVE like this.
function mouse_move(e:Event)
{
this.x = mouseX + selectX + stage.x;
}
and remove this event handler on mouse up.