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

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. :)

Related

Object Undefined but it seems to be Defined actionscript

First I am still new to coding so take it easy on me. Bit of back tracking before I show the code. I got a book on how to make games with ActionScript 3, only thing is it mainly works under the assumption your working with Photoshop & Flash Builder together rather than adobe animate/flash. So it has you do things like embed images, and I'm not sure how to change the code to define the images, which is exactly the problem. However at the same time, the stage is coming up as undefined access! I really, I mean how can the stage be undefined... Well any way, Heres an example of one of the Undefined Properties:
///
class BetterScrolling extends Sprite
var ForegroundImage: Class;
var foregroundImage: DisplayObject = ForegroundImage();
var foreground = ForegroundImage;
///
Theres some code in-between.
///
function BetterScrolling(){
foreground.x = -((foreground.width - stage.width) / 2);
foreground.y = -((foreground.height - stage.height) / 2);
}
///
The point of this code is to create a scrolling Background. However I'm kinda complicating it because I have an X and an Y variable, yet I also have a slowed background in addition to my foreground. I will now link to the complete code as is currently, http://pastebin.com/WHg9DGsB Every change in that code I made with a reason in mind, even if it is a stupid one... so please don't be distracted by the other errors that I'm sure are in there... for now just the defining of my images.
There a number of issues that will keep your code from compiling.
Stage is not available when your class loads. Any code that is not inside a function will run when the application is initialized (before anything is even seen on the screen). Your error is because of these lines:
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandHandler);
stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
Those lines are floating in your class declaration when stage does not yet exist.
What you want to do is move that code (and any code that isn't a variable or function definition) into a function. If you want it to run immediately, put it in your constructor (the function named the same as your class). The stage however is also not always available yet in your constructor, so to be safe, you should do the following:
function BetterScrolling() {
if(!stage){
this.addEventListener(Event.ADDED_TO_STAGE, stageReady);
}else{
stageReady();
}
}
function stageReady(e:Event = null):void {
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandHandler);
stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
//any other code that needs the stage and should run as soon as possible
}
You have a bunch of brackets and code that don't seem to belong anywhere. Lines 45 - 71 will not compile properly. Most likely, you want that code in your constructor/stage ready method as well, so adding that in, you would have something like this:
function BetterScrolling() {
if(!stage){
this.addEventListener(Event.ADDED_TO_STAGE, stageReady);
}else{
stageReady();
}
}
function stageReady(e:Event = null):void {
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandHandler);
stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
foreground.x = -((foreground.width - stage.width) / 2);
foreground.y = -((foreground.height - stage.height) / 2);
background.x = -((background.width - stage.width) / 2);
background.y = -((background.height - stage.height) / 2);
cloud.x = -((cloud.width - stage.width) / 2);
cloud.y = -((cloud.height - stage.height) / 2);
character.x = 370
character.y = 320
rightInnerBoundary = (stage.stageWidth / 2) + (stage.stageWidth / 4)
leftInnerBoundary = (stage.stageWidth / 2) + (stage.stageWidth / 4)
topInnerBoundary = (stage.stageHeight / 2) + (stage.stageHeight / 4)
bottomInnerBoundary = (stage.stageHeight / 2) + (stage.stageHeight / 4)
}
You have vars that are blank classes, then you try to instantiate them
var BackgroundImage: Class;
var backgroundImage: DisplayObject = BackgroundImage();
This will cause a runtime error because BackgroundImage is null/undefined. Most likely, you want to export a library object in FlashPro as a class? To do that, right/alt click the object in question in the library, and go to it's properties. Check off 'export for actionscript' and give it a class name. In this case, call it BackgroundImage. Then you replace the above code with:
var backgroundImage:BackgroundImage = new BackgroundImage();
As an aside, it safer to only declare you class vars that reference other objects/classes and instantiate them in the constructor. To change it like that, change the above line to this:
var backgroundImage:BackgroundImage;
Then in your constructor, do:
backgroundImage = new BackgroundImage();
First, DisplayObject.stage property is defined only when the DisplayObject in question is attached to display list. As a general policy, never try to access stage in the constructors. You need to subscribe a certain event that will tell you when stage is really available.
public function IWannaStage()
{
// WRONG
x = stage.stageWidth >> 1;
y = stage.stageHeight >> 1;
// RIGHT
if (stage) onStage();
else addEventListener(Event.ADDED_TO_STAGE, onStage);
}
private function onStage(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, onStage);
// Stage is really available from this point on.
x = stage.stageWidth >> 1;
y = stage.stageHeight >> 1;
}
Second, I think you're trying to create instances incorrectly. If ForegroundImage is a class, then:
A = ForegroundImage; // Wrong, you assign the reference to the class.
B = ForegroundImage(); // Wrong, this actually is type casting.
C = new ForegroundImage(); // Correct way to create a new instance of a class.
D = new ForegroundImage; // If constructor does not need any arguments you can omit brackets.

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 tracking and using coordinates of a rotated object

How does one track and use the coordinates of an object that is rotated on initialization?
Let's say I have a sword that is put on the stage in Main init(); and rotated (adjusted) so that it would look ok together with the character perspective. In another class however, I am making the sword rotate some more on a keypress timer event so to create a 'swing' animation.
All this is done through flashdevelop. I only used CS6 to create the symbols. And as this 'swing' is happening, I want to add another symbol onto the tip of the sword which is a collision point object. It's being added to the stage when the swing starts and removed after every swing. I want this object to follow the very tip of the sword, yet it seems like I can only achieve that it follows the coordinates of the original sword object, as if I hadn't initially modified the rotation of the said sword. I tried to implement GlobalToLocal() and LocalToGlobal() methods, but I don't think I fully understand what is happening with that.
I hope I'm being clear enough of what I'm trying to do. Thank you. This is the relevant code in question. The code is as was before I tried the two mentioned methods and the issue currently is exactly as described before that. Do I want any of those methods or am I just doing something else wrong?
Main initialization:
sword = new Sword();
sword.x = 53;
sword.y = 90;
addChild(sword);
sword.rotationZ = -150;
sword.rotationY = 25;
sword.rotationX = -15;
Coll_Point = new coll_point();
The class that deals with the swing has a method like this:
private function SwingTime(event:Event):void
{
Main.Coll_Point.x = Main.sword.x + Main.sword.width;
Main.Coll_Point.y = Main.sword.y + Main.sword.height;
Main.MazeNr1.addChild(Main.Coll_Point);
if (Main.sword.rotationZ > -330)
Main.sword.rotationZ -= 20;
if (Main.sword.rotationX < 15)
Main.sword.rotationX += 10;
if ((Main.sword.rotationZ == -330) && (Main.sword.rotationX == 15))
{
SwingTimer.stop();
SwingBckTimer.start();
}
}
Edit:
A more holistic version of the code:
public class Main extends MovieClip
{
public static var from_point:Point = null;
public static var to_point:Point = new Point();
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
// Puts everything on the stage here.
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
PlayerInst = new Dorf();
PlayerInst.x = 45;
PlayerInst.y = 51;
addChild(PlayerInst);
sword = new Sword();
sword.x = 53;
sword.y = 90;
sword.rotationZ = -150;
sword.rotationY = 25;
sword.rotationX = -15;
from_point = new Point (Main.sword.width, Main.sword.height);
to_point = sword.localToGlobal(from_point);
addChild(sword);
swordBD = new BitmapData(32, 32, true, 0x0000000000);
swordBD.draw(sword);
Coll_Point = new coll_point();
Coll_PointBD = new BitmapData(2, 2, true, 0x0000000000);
Coll_PointBD.draw(Coll_Point);
}
}
This is how the Main looks like and literally every single object instantiation is added onto the stage this way. Including collision points, background, characters, gradient fills of line of sight radius, etc. And the relevant symbol class goes somewhat like this:
public class Creature extends MovieClip
{
protected var Swing:Boolean;
private var SwingTimer:Timer = new Timer (5, 0);
private var SwingBckTimer:Timer = new Timer (150, 1);
// Constructor.
public function Creature()
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
// Initializer.
private function init(event:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
SwingTimer.addEventListener(TimerEvent.TIMER, SwingTime);
SwingBckTimer.addEventListener(TimerEvent.TIMER, SwingBack);
}
private function SwingAction():void
{
if (Swing == true)
{
SwingTimer.start();
}
}
private function SwingTime(event:Event):void
{
Main.Coll_Point.x = Main.sword.localToGlobal(Main.from_point).x;
Main.Coll_Point.y = Main.sword.localToGlobal(Main.from_point).y;
Main.sword.addChild(Main.Coll_Point);
trace(Main.Coll_Point.x);
trace(Main.Coll_Point.y);
if (Main.sword.rotationZ > -330)
Main.sword.rotationZ -= 20;
if (Main.sword.rotationX < 15)
Main.sword.rotationX += 10;
if ((Main.sword.rotationZ == -330) && (Main.sword.rotationX == 15))
{
SwingTimer.stop();
SwingBckTimer.start();
}
}
private function SwingBack(event:Event):void
{
Main.sword.rotationZ = -150;
Main.sword.rotationX = -15;
//Main.MazeNr1.removeChild(Main.Coll_Point);
}
There is also a rather long update(); function that animates and moves every single object that needs moving.
I think your problem might be in
Main.Coll_Point.x = Main.sword.x + Main.sword.width;
Main.Coll_Point.y = Main.sword.y + Main.sword.height;
Coll_Point expects global coordinates.
The parts + Main.sword.width and + Main.sword.height only work as expected if the sword is not rotated so that height is aligned with the y-axis and width with the x-axis.
You should use localToGlobal() on the position that is local to Main.sword (
Main.sword.width, Main.sword.height) to get the global position that represents the swords rotated tip before you add it as a child.
There are two ways you can approach this (you seem to have somewhat combined both). You can either
Add the Coll_Point as a child to something above the sword in hierarchy (Stage, MazeNr1, ...) and update the position manually every timer callback. You would have to recalculate the position everytime, so take the localToGlobal() from init to your timer function. It won't update if it doesn't get called.
For that you should have this kind of code in the timer callback:
var local:Point = new Point(Main.sword.width, Main.sword.height);
var global:Point = Main.sword.localToGlobal(local);
Main.Coll_Point.x = global.x;
Main.Coll_Point.y = global.y;
Add the point as a child to the sword. This might be a better approach as then the position will be updated automatically. What I did not remember before was that you then give the coordinates in "local" form, so do not use localToGlobal()
Run this once where you create the Collision_Point:
Coll_Point.x = <your x offset>;
Coll_Point.y = <your y offset>;
Main.sword.attachChild(Coll_Point);
Instead of sword height and width you might want to try something like -height and width/2.
Here is a quick (and not the prettiest) picture to demonstrate the problem. Local space is rotated with the object:
The only thing I can imagine to help you with this problem is to have your collision object have the same registration point as the sword. What I mean is that the orientation points should match, and the collision graphic should be moved inside of the sprite so that it matches the position of the top of the sword.
This way you can put the collision object at the very same location of the sword and apply the very same rotation. This way it will move along with the top of the sword and still have hitTest working properly.
I cannot imagine any other way to figure this out as any code will get bounds and positions. But the real thing that matters is the registration point and the top of the sword, which is a graphic thing and cannot be dealt with coding.
I hope you can imagine what I mean - if now, just say and I will provide an image for you :)

AS3 Determining what object overlaps it?

I'm current building a game in as3; the proplem I have right now is when I roll the virtual dice, the player(marker) moves accross the board but what I need to know is: is there a way to find the instance name of the object(box) that the player lands on?
And Sorry my english isn't good.
It depends a lot on how your board is laid out. One way is to put all of the objects your player can land on into an array, then check the player's x and y coordinates to see if they fall inside of each object's box.
For example:
var boardObjects:Array; // This would contain references to all the objects the
// player object might land on. Initialize it, then use boardObjects.add(object)
// on each one until they're all in the array.
// once the player has moved:
for(var i:int = 0; i < boardObjects.size; i++) {
var obj:* = boardObjects[i];
if (player.x >= obj.x && player.x <= obj.x + obj.width) {
if (player.y >= obj.y && player.y <= obj.y + obj.height) {
// If these if statements are all true, the Player's top-left corner
// is inside the object's bounding box. If this is a function,
// here is a good spot to put a return statement.
}
}
}
You may want to calculate it based on the middle of the player rather than their top-left corner, in which case just add half the player's width to their x position and half their height to their y position.
For performance (and avoiding unnecessary code), if it's tile based / dice why not do something like this
private function rollDice(){
var results:Array = [Math.ceil(Math.random() * 6), Math.ceil(Math.random() * 6)] //Accurately simulates two 6 sided dice
dice1.rollAnimation(results[0]);
dice2.rollAnimation(results[1]);
player.position += results[0] + results[1];
}
The board would be an array, and in Player you can use getters/setters to 'wrap' the board like this
private var _position:int = 0;
public function get position():int{
return _position;
}
public function set position(value:int){
_position = value;
while(_position > GameBoard.TILES){
_position -= GameBoard.TILES;
}
x = //Whatever you determine the positioning of the player..
}

How can I use Action Script 3.0 to make random placed Symbols fly by?

I'm trying to make a simple animation with Flash CS4 and Action Script 3.0 to make a number of Symbols fly by from right to left constantly. What I want is that once a symbol has reached the end of the screen it is destroyed and another one is placed at the start position.
I intend to give each symbol a random speed and create a random symbol each time one is 'destroyed'. Any clues where I can start?
As you seem new to flash as a platform I would think writing classes shouldn't be your first port of call when learning ActionScript. Definitely just play about on the timeline for now and learn the basics. As very simple solution to this, I would suggest creating a MovieClip in the library with a class name like 'MyBall'... then paste this onto the first frame of the main timeline et voila.
// Create some variables to store data
var numberOfBalls : int = 20;
var myBalls : Array = [];
var xVelocities : Array = [];
var maxXVelocitySpeed : Number = 5;
var minXVelocitySpeed : Number = 2;
// Add your orginal balls to the stage
for (var i : int = 0; i < numberOfBalls; i++)
{
var myBall : MyBall = new MyBall();
myBall.x = -(Math.random() * stage.stageWidth);
myBall.y = Math.random() * stage.stageHeight;
var xVelocity : Number = minXVelocitySpeed + (Math.random() * (maxXVelocitySpeed - minXVelocitySpeed));
myBalls.push(myBall);
xVelocities.push(xVelocity);
addChild(myBall);
}
// Add a listener for enter frame events
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
//Run this code on every frame to move the balls and reposition them if they are off the stage
function enterFrameHandler(event : Event) : void
{
for each( var myBall : MyBall in myBalls)
{
var ballIndex : int = myBalls.indexOf(myBall);
myBall.x += xVelocity[ballIndex];
if (myBall.x > stage.stageWidth)
{
myBall.x = -(Math.random() * stage.stageWidth);
myBall.y = Math.random() * stage.stageHeight;
}
}
}
First, turn your symbols into MovieClips. Then create a base class MySymbol.as for your symbols, something like:
package {
import flash.display.MovieClip;
import flash.events.Event;
import flash.geom.Point;
public class MySymbol extends MovieClip
{
public var speed:Number; // Pixels moved per frame
public function MySymbol(speed:Number, startPosition:Point)
{
this.speed = speed;
this.addEventListener(Event.ENTER_FRAME, update);
this.x = startPosition.x;
this.y = startPosition.y;
}
private function update():void
{
this.x -= this.speed;
if (this.x < 0 - this.width) { // We're at the left edge
this.removeEventListener(Event.ENTER_FRAME, update);
this.dispatchEvent(new Event(Event.COMPLETE));
}
}
}
}
Then make sure your movie clips are exported for AS3 (the "linkage" option on the item in the library). Make the class name for each item unique (e.g. MySymbol1, MySymbol2), and set the base class to MySymbol.
Your document class might look something like this:
package {
import flash.display.MovieClip;
import flash.events.Event;
import MySymbol; // Not strictly needed
public class DocumentClass extends flash.display.MovieClip
{
private static var SYMBOLS:Array = new Array(MySymbol1, MySymbol2);
public function DocumentClass()
{
// Create five symbols:
for (var i:int = 0; i < 5; i++) {
makeSymbol();
}
}
private function makeSymbol():void
{
// Pick a random symbol from the array:
var symType:Class = SYMBOLS[Math.random() * SYMBOLS.length];
// Construct the new symbol:
var loc:Point = new Point(stage.stageWidth, Math.random() * stage.stageHeight);
var sym:MySymbol = new symType(1 + Math.random() * 30, loc);
// Listen for the object hitting the left edge:
sym.addEventListener(Event.COMPLETE, remakeObject);
this.addChild(sym);
}
private function remakeObject(e:Event):void
{
e.target.removeEventListener(Event.COMPLETE, remakeObject);
this.removeChild(e.target);
// Replace the dead symbol:
makeSymbol();
}
}
}
It is a lot more efficient if instead of destroying and re-creating an object that flies off-stage you re-use the existing one and move it back to the right. But this is an optimization you can implement later, if things become slow.
Note that all the code above is UNTESTED and I have not coded AS3 in a while, so there's likely at least a few bugs in it. Hopefully it will serve as a good enough starting point.
Define a Circle (symbol) class that extends Sprite/Shape and has a velocity variable
Draw a circle (or whatever) with a random color
Math.floor(Math.random() * 0xffffff)
Assign a random value to velocity
minVelocity + Math.floor(Math.random() * velocityRange)
Create a start() method inside the Circle class that registers an enter frame handler
Increment this.y inside the enter frame handler, and dispatch a 'recycleMe' event if y is more than the max value.
Create N instances of Circle, addChild them, and call their start() methods.
listen to 'recycleMe' events on each of them, and reset the value of y from the handler.
Here's a few prompts to get you started.
MovieClips have an x and y property. If you were to add to these numbers over time you would see the MovieClip move along the x and/or y axis of the stage. Look into doing this using the Event.ENTER_FRAME which will allow you to change the values every time the screen is going to update.
Your stage will have a given width (a stageWidth property). You probably want to monitor when your MovieClip's x property is greater than the width of your stage. If it is remove (removeChild) it and add a new one (addChild) and place it back at the start x/y position.