Changing x and y values of a Sprite Actionscript 3 - actionscript-3

I'm attempting to change the x and y value of a sprite.
public var panContainer:Sprite = new Sprite();
public var xVal:Number;
public var yVal:Number;
I've created the function:
public function moveContainer(xVal,yVal):void
{
xVal = panContainer.x;
yVal = panContainer.y;
}
Both the variable and function are created within an .as file. I'm attempting to make the function call within a class file called test2.as using a case statement. When the user selects an item from a list box the sprite's x and y values need to change:
switch (event.target.selectedItem.data)
{
case 1 :
panZoomMap.moveContainer(30,30);
break;
The function call, however does nothing at this point. Is this a scope issue? Am I not executing this properly? Thanks in advance for any advise.

It appears that you have your variable assignments backwards, what you want to do is assign the values you get in moveContainer to the x and y properties of panContainer:
public function moveContainer(xVal,yVal):void
{
panContainer.x = xVal;
panContainer.y = yVal;
}

Unless I am reading your question wrong (it is not worded well), you have this backwards
public function moveContainer(xVal,yVal):void
{
panContainer.x = xVal;
panContainer.y = yVal;
}
You were setting your variables to the x,y coords of your object, when you should have been setting your x,y coords to your variables.

I think you are very close, just have it reversed. You are passing in the xVal and yVal into the moveContainer method. so xVal and yVal are the new values. Below should be your function:
public function moveContainer(xVal,yVal):void
{
panContainer.x = xVal;
panContainer.y = yVal;
}
A simple rule of thumb I go by is: values always get assigned into a container to the left of the = sign.
So in the method will assign passed xVal to the panContainer.x property, and yVal to panContainer.y property.

Related

Flash drop and catch game

I am doing a flash mini game that a character need to catch item drop down from top.
The problems i am facing are using timer for those 6 items in an array randomly chose and drop down with random x-axis.
var PointFood:Array = [Melon1,Honey1,Worm1,Clock1,Poison1,Sling1];
//this is the array of items to drop
time = new Timer(60);
//No idea the timer is with frame or second
time.addEventListener(TimerEvent.TIMER,GenerateItem);
time.start();
function GenerateItem(event:TimerEvent):void
{
axis = Math.round(Math.random()*709.7)+44.45;
//this is the random x axis with my scene width
PointFood[i].x = axis;
PointFood[i].y = 0;
if(PointFood[i].y < 600.95)
{
PointFood[i].y += 10;
}
}
//here assign the x and y axis
function ItemType(e:Event):Number
{
i = Math.round(Math.random()*5);
return i;
}
//this is the random for item in array
However the x-axis will be keep changing once the calculation done. Even the items that already exist on screen, their x-axis will also keep changing with the calculation.
Any Solution for this?
There are different ways of dealing with this.
I assume Melon1, Honey1, ... are instances of your own classes.
Add a public property positioned to each of them, like:
public var positioned:Boolean=false;
At the moment your ItemType function just returns a random integer based on the number of objects inside the PointFood array.
Let's integrate a check if the random object is already positioned using it's freshly added positioned property:
function ItemType(e:Event):Number
{
var found:Boolean;
do
{
found = true;
i = Math.round(Math.random() * 5);
if (PointFood[i].positioned)
{
found = false;
}
} while (!found);
return i;
}
Finally modify the GenerateItem function to take the positioned property into account - thus just randomize the position if it's false:
function GenerateItem(event:TimerEvent):void
{
if (PointFood[i].positioned == false)
{
axis = Math.round(Math.random() * 709.7) + 44.45;
//this is the random x axis with my scene width
PointFood[i].positioned = true;
PointFood[i].x = axis;
PointFood[i].y = 0;
}
if (PointFood[i].y < 600.95)
{
PointFood[i].y += 10;
}
}
As a side note:
time = new Timer(60);
means your timer fires every 60 milliseconds - is that the expected behaviour?
Also there might be a little logic problem with your code. As the name GenerateItem implies, I guess this function should just spawn a new object and initialize it's position. Unfortunately it looks like you're abusing this function to do your main game loop as well. I'd recommend splitting this up into two separate functions.

AS3 - Using a For Loop to Update Multiple Points and Their Values in an Array

I'm a bit new with AS3 (but not really with coding) so please forgive my ignorance. I'm creating a small function that will be called by a Main Function to update the position of 52 Pointers that have the x and y position of multiple point objects (empty movie clips). It will also then update two global arrays with those values (one array for the x and one for the y).
The problem is, as there are 52 of them, and they will probably grow in quantity, I'd like to be able to use a FOR function to do it, but I can't seem to be able to figure it out.
I get this error: Access of undefined property _point.
Here is a piece of the code that dream about:
function happyFunc():void
{
var avpointers:int = 52;
var vpointx:Array = new Array();
var vpointy:Array = new Array();
for (aa=0; aa<vpointers; aa++)
{
vpointx[aa] = _point[aa].x;
vpointy[aa] = _point[aa].y;
}
}
And this is the code that I'm stuck with...
function reallySadFunc():void
{
_point1 = localToGlobal(new Point(point1.x,point1.y));
//...
_point52 = localToGlobal(new Point(point52.x,point1.y));
vpointx[0] = _point1.x;
vpointx[1] = _point2.x;
//...
//oh god there are 104 lines of this why do I have to suffer
}
Thank you!
If I read your question correctly, I think this is what you need:
public static const CLIP_COUNT:int = 52;
// ...
private function happyFunc(parentClip:DisplayObjectContainer):void
{
var vpointx:Vector.<Number> = new Vector.<Number>(CLIP_COUNT, true);
var vpointy:Vector.<Number> = new Vector.<Number>(CLIP_COUNT, true);
var clipPoint:Point = new Point ();
var globalPoint:Point;
for (var i:int = 0; i < CLIP_COUNT; i++)
{
var childClip:DisplayObject = parentClip.getChildByName("point" +
(i + 1).toString());
clipPoint.x = childClip.x;
clipPoint.y = childClip.y;
globalPoint = parentClip.localToGlobal(clipPoint);
vpointx[i] = globalPoint.x;
vpointy[i] = globalPoint.y;
}
// do something with vpointx and vpointy - they're local variables
// and will go out of scope unless you declare them as class members
// or somehow return them from this function.
}
This function works by taking the parent display object (the one that contains the 52 movie clips - this could be the Stage) and iterates through them by getting each movie clip by name. The code assumes that your movie clips are called point1, point2, ..., point52.
To speed up the local-to-global coordinate conversion, two Point objects are created and then reused during the for loop to avoid creating many temporary Point instances.
Instead of using Array, use Vector.<Number> - this class has better performance than Array does.

Why doesn't my custom FlxSprite appear on the stage?

I created a custom FlxSprite for a fireball by creating a new class(Fireball.as) and typing "extends FlxSprite" after the class name. In the constructor, it calls a function called "shoot()", which directs it to the target and plays a sound:
private function shoot():void {
dx = target.x - x;
dy = target.y - y;
var norm:int = Math.sqrt(dx * dx + dy * dy);
if (norm != 0) {
dx *= (10 / norm);
dy *= (10 / norm);
}
FlxG.play(soundShoot);
}
Then, I created an array to hold all the fireballs in the game state(PlayState.as):
public var fire:Array = new Array();
Then in my input() function, when someone pushes the mouse button, it pushes a new Fireball in the array:
if (FlxG.mouse.justPressed()) {
fire.push(new Fireball(x, y, FlxG.mouse.x, FlxG.mouse.y));
}
But when I test it, it only plays the sound, but the fireball doesn't show up. I'm guessing that the fireball is somewhere offstage, but how do I fix it?
If it helps, here's the constructor for Fireball.as:
public function Fireball(x:Number, y:Number, tar_x:Number, tar_y:Number) {
dx = 0;
dy = 0;
target = new FlxPoint(tar_x, tar_y);
super(x, y, artFireball);
shoot();
}
I think you must add them to stage.
if (FlxG.mouse.justPressed()) {
var fireball:Fireball = new Fireball(x, y, FlxG.mouse.x, FlxG.mouse.y);
fire.push(fireball);
// This line needs to be changed if you add the fireball to a group,
// or if you add it to the stage from somewhere else
add(fireball);
}
Let me know if it worked for you.
As stated before, the problem was due to not adding the FlxSprite to the Flixel display tree. But also I would advise you to use FlxObject groups instead of a simple Array.
FlxGroups are way better data structure than arrays. For instance they inherit all the methods from a FlxObject, so you can check for collisions directly against the group, also they have specific methods to handle the collection of objects, such as countDead and countAlive (if you make you of the alive attribute), recycle, getFirstDead and so on.
Check it out, you won't be disappointed. :)

AS3 Error #1009: Cannot access a property or method of a null object reference

Basically, I'm trying to make a randomly generated character follow a series of waypoints to get to where he needs to go without walking into walls etc on stage.
I'm doing this by passing an Array of Points from the Engine to the Character's followPath function (this will be on a loop, but I haven't gotten to that stage yet).
A part of this followPath function is to detect when the character is close enough to the waypoint and then move on to the next one. To do this, I'm trying to use Point.distance(p1,p2) to calculate the distance between the currently selected waypoint, and a point that represents the Character's current position.
This is where I'm running into this problem. Trying to update the current (x,y) point position of the Character is proving difficult. For some reason, the Point.setTo function does not seem to exist, despite it being in documentation. As a result, I'm using
currentPos.x = x;
currentPos.y = y;
//update current position point x and y
to try and do this, which is where my 1009 error is coming from.
Here is my full Character class so far:
package {
import flash.display.MovieClip;
import flash.geom.Point;
public class Character extends MovieClip {
public var charType:String;
private var charList:Array = ["oldguy","cloudhead","tvhead","fatguy","speakerhead"];
private var numChars:int = charList.length;
private var wpIndex:int = 0;
private var waypoint:Point;
private var currentPos:Point;
private var wpDist:Number;
private var moveSpeed:Number = 5;
//frame labels we will need: charType+["_walkingfront", "_walkingside", "_walkingback", "_touchon", "_touchonreaction", "_sitting"/"_idle", "_reaction1", "_reaction2", "_reaction3", "_reaction4"]
public function Character() {
trace("new character:");
charType = charList[Math.floor(Math.random()*(numChars))];
//chooses a random character type based on a random number from 0-'numchars'
trace("char type: " + charType);
gotoAndStop(charType+"_walkingfront");
x = 600;
y = 240;
}
public function followPath(path:Array):void {
if(wpIndex > path.length){ //if the path has been finished
gotoAndStop(charType+"_sitting"); //sit down
return;//quit
}
waypoint = path[wpIndex];
//choose the selected waypoint
currentPos.x = x;
currentPos.y = y;
//update current position point x and y
wpDist = Point.distance(currentPos,waypoint);
//calculate distance
if(wpDist < 3){ //if the character is close enough to the waypoint
wpIndex++; //go to the next waypoint
return; //stop for now
}
moveTo(waypoint);
}
public function moveTo(wp:Point):void {
if(wp.x > currentPos.x){
currentPos.x += moveSpeed;
} else if(wp.x < currentPos.x){
currentPos.x -= moveSpeed;
}
if(wp.y > currentPos.y){
currentPos.y += moveSpeed;
} else if(wp.y < currentPos.y){
currentPos.y -= moveSpeed;
}
}
}
}
Can anybody explain to me why this is happening? It's a roadblock that I haven't been able to overcome at this stage.
I'm also curious if anybody can provide information as to why I can't use the phantom Point.setTo method.
You're trying to assign x and y properties of a Point object that doesn't exist.
You have to create your Point:
currentPos = new Point ();
and then assign x and y
The problem is that your are not using the Point constructor first.
When you create a variable that is not a simple data type (Int, Number, String ...) you must call the constructor first and assign properties to the fields of the object only afterwards.
This is because you must initialize an instance of the class Point before accessing it's properties.
The same will be true with any other class.
http://en.wikipedia.org/wiki/Constructor_%28object-oriented_programming%29
"In object-oriented programming, a constructor (sometimes shortened to ctor) in a class is a special type of subroutine called at the creation of an object. It prepares the new object for use.."
Basically, you did not prepare a new Point object.
In this example, during the constructor (public function Character)
public function Character() {
//add these lines (you can omit the zeroes as the default value is zero)
//I added the zeroes to show that the constructor can set the initial values.
wayPoint = new Point(0, 0);
currentPos = new Point(0, 0);
trace("new character:");
charType = charList[Math.floor(Math.random()*(numChars))];
//chooses a random character type based on a random number from 0-'numchars'
trace("char type: " + charType);
gotoAndStop(charType+"_walkingfront");
x = 600;
y = 240;
}
remember every new object identifer references NULL (nothing) until you construct an object or do something like this
var pointA = pointB;
//where pointB is already not null
//You can also check this
if(currentPos != null)
{
currentPos.x = X;
currentPos.y = Y;
}
currentPos will not be null if you use a constructor first.
Good luck.

AS3 OOP Principal, Structure & Organization

Refining my OOP structure, and trying to make the display of code as intuitive as possible,
using basic OOP principals this definitely helps but my craft has only gone so far. I am looking to improve upon my practice:
package
{
import flash.display.*;
import flash.text.*;
public class Button extends Sprite
{
protected var _spr:Sprite = new Sprite();
protected var _tf :TextField = new TextField();
protected var c :Number;
protected var xx :Number;
protected var yy :Number;
protected var w :Number;
protected var h :Number;
protected var t :String;
protected var a :Number;
protected var l :Number;
protected var lC :Number;
function Button
(
_col:Number, //beginFill
_x:Number, _y:Number, _w:Number, _h:Number, //drawRect
_t:String = "", //TextField (optional)
_a:Number = 1, //beginFill (optional)
_l:Number = 0, _lC:Number = 0xFFFFFF //lineStyle (optional)
)
{
c = _col;
xx = _x;
yy = _y;
w = _w;
h = _h;
t = _t;
a = _a;
l = _l;
lC = _lC;
_spr.addChild(_tf);
draw();
}
public function draw ():void
{
_spr.graphics.clear ();
_spr.graphics.lineStyle(l, lC);
_spr.graphics.beginFill(c);
_spr.graphics.drawRect (xx, yy, w, h);
var f:TextFormat = new TextFormat;
f.font = "Arial";
_tf.text = t;
_tf.autoSize = TextFieldAutoSize.LEFT;
_tf.x = xx + w/2 - _tf.textWidth / 2;
_tf.y = yy + h/2 - _tf.textHeight / 1.5;
_tf.width = w - 2;
_tf.height = h - 2;
_tf.alpha = 0.75;
_tf.setTextFormat(f);
_tf.selectable = false;
_tf.mouseEnabled = false;
_spr.graphics.endFill ();
}
/* ----------------------- *
* GETTERS *
* ----------------------- */
//OVERRIDE
override public function get x () :Number {return (xx)}
override public function get y () :Number {return (yy)}
override public function get width () :Number {return (w)}
override public function get height () :Number {return (h)}
//SUPPLEMENTARY
public function get col () :Number {return (c)}
public function get text () :String {return (t)}
public function get line () :Number {return (l)}
public function get lineC () :Number {return (lC)}
public function get getObj () :Sprite {return (_spr)}
/* ----------------------- *
* SETTERS *
* ----------------------- */
//OVERRIDE
override public function set x (_n:Number) :void
{ xx = getObj.x = Math.round(_n - xx) }
override public function set y (_n:Number) :void
{ yy = getObj.y = Math.round(_n - yy) }
override public function set width (_n:Number) :void
{ w = Math.round(_n) }
override public function set height (_n:Number) :void
{ h = Math.round(_n) }
//SUPPLEMENTARY
public function set col (_n:Number) :void
{
c = _n;
draw();
}
public function set text (_s:String) :void
{
t = _s;
draw();
}
public function set line (_n:Number) :void
{
l = _n;
draw();
}
public function set lineC(_n:Number) :void
{
lC = _n;
draw();
}
}
}
From the above Button class, what interpretations can you make about my structure & organization? I have read and followed many articles on how you should perform OOP logically and I think I am ready for some tuning, or criticism rather on my understanding of how a class should be in AS3 (circumstantial i know.)
Some specific questions:
When I instantiate 'Button' from my Main class, should I add it to the stage there or
within the Button Class itself using Super?
Will the "1047" Error ever be fixed? What is a sustainable (or more efficient) work-around besides the ones already mentioned here?: http://curtismorley.com/2008/10/15/actionscript-error-1047-parameter-initializer-unknown-or-is-not-a-compile-time-constant/
In order to update width/height changes, I must call my draw function after modification from outside the Override function for width & height specifically. Is there a proper way to call draw() through the Override functions? No error output was provided, it seems doing so is against the rules though so I am just calling draw() from Main as a hack fix.. Possibly write a function within button tethered to event of a changed property?
If anyone bothered to parse this wall of text, thanks for reading and I appreciate any criticism you may have, harsh or otherwise :)
First, your variable names are not decriptive. If you're going to name your variables "c", "t", "lc", etc., at least put inline comments that describe what they're for. Even if you comment the parameters that populate them lower down, there's unnecessary overhead with what you've done.
If you've done that because of the historically poor code completion in the IDE, use Flash Builder or one of the excellent code editing tools that can help you type out lineColor, textField, etc.
On closer inspection, it looks like you've done this at least partially because you've reversed the normal convention, which is to have parameters to functions not use underscores, whereas private/protected storage should use underscores, but otherwise should have the same name as the public property. Changing your conventions to match the rest of the AS3 world would go a long way to making your code more readable.
If you don't want to lose the underscores in your function parameters, you could use a snippet in FB to make setting the instance variable to a parameter of the same name.
Invalidation is very well understood in ActionScript, so I'm not sure why you have an issue. It looks something like this:
protected function invalidate():void {
_isInvalid = true;
addEventListener(Event.ENTER_FRAME, validate);
}
protected function validate(e:Event):void {
removeEventListener(Event.ENTER_FRAME, validate);
if (_isInvalid) {
draw();
}
_isInvalid = false;
}
Call this everywhere you're now calling draw(), and it will reduce the number of times you have to update the display list.
MPO is that you should not have constructor arguments for View Classes, as this makes it impossible to use them from the timeline.
You'll probably find that if you're open to using the timeline, a lot of this hard work goes away--you simply add the behavior via an AS Class and draw the graphics in the IDE (using things like 9-slice scaling, filters, etc., to minimize maintenance hassle). If you want a button that looks different, you draw a different one, attach your behavior Class, and done.
A lot of people don't realize that it's possible to maintain good OOP while allowing the timeline to take over much of the heavy lifting. Hope this gives you what you want, or at least gives you some search terms you can move forward with. Note if you're interested in knowing more about leveraging the timeline, post back. The links to the source code on that one were eaten when the post was archived.