I have a problem in Flash puzzle game. If I create the game in the first frame of my timeline it's working, but if the game has been created (for example) in 5th frame it does'nt work!
It send me this error:
TypeError: Error #1009: Cannot access a property or method of a null
object reference.
at Map() TypeError: Error #2007: Parameter hitTestObject must be non-null.
at flash.display::DisplayObject/_hitTest()
at flash.display::DisplayObject/hitTestObject()
at DragDrop/drop()
dragdrop class
package
{
import flash.display.*;
import flash.events.*;
public class DragDrop extends Sprite
{
var origX:Number;
var origY:Number;
var target:DisplayObject ;
public function DragDrop()
{
// constructor code
origX = x;
origY = y;
addEventListener(MouseEvent.MOUSE_DOWN, drag);
buttonMode = true;
}
function drag(evt:MouseEvent):void
{
stage.addEventListener(MouseEvent.MOUSE_UP, drop);
startDrag();
parent.addChild(this);
}
function drop(evt:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_UP, drop);
stopDrag();
if(hitTestObject(target))
{
visible = false;
target.alpha = 1;
Object(parent).match();
}
x = origX;
y = origY;
}
}
}
I think the problem is in var target! and I don't know how to solve it.
Map.as
enter code here package
{
import flash.display.*;
import flash.events.*;
public class Map extends MovieClip
{
var dragdrops:Array;
public function Map()
{
// constructor code
dragdrops = [tt1];
var currentObject:DragDrop;
for(var i:uint = 0; i < dragdrops.length; i++)
{
currentObject = dragdrops[i];
currentObject.target = getChildByName(currentObject.name + "_target");
}
}
public function match():void
{
}
}
}
Edit:
There are multiple problems with the code. Too many to list, I'm afraid, but the biggest one is:
You're declaring a map, and trying to add your object to it, before your object exists. It doesn't exist until frame 5, so this won't work. I've re-written the code below, but honestly, there is so much wrong with the code that it's just not possible to fix without re-writing significant portions of it.
package
{
import flash.display.*;
import flash.events.*;
public class Map extends MovieClip
{
var dragdrops:Array;
public function Map()
{
// constructor code
dragdrops = new Array();
}
public function addElement(gamepiece:DragDrop):void {
dragdrops.push(gamepiece);
}
public function addChildElements():void {
var currentObject:Object;
for(var i:uint = 0; i < dragdrops.length; i++)
{
currentObject = dragdrops[i];
currentObject.test();
currentObject.target = (currentObject.name + "_target"); // this should work now, but doesn't. Why?
currentObject.target.test();
}
}
public function match():void
{
}
}
}
Then, on frame one, I added:
var map:Map = new Map();
Then, on frame five, I added:
map.addElement(tt1);
map.addChildElements();
This got tt1 added to map, at least, but that's as far as I got. Your problem now is;
currentObject.target = (currentObject.name + "_target");
It's the correct name, now, but it won't add it to target. That's as much as I can do.
It's because your hitTestObject method isn't correctly invoked. This method must be invoked in a Display Object instance to test if another instance of a Display Object hits it:
if (myDisplayObject.hitTestObject(anotherDisplayObject))
{
// do stuff
}
Adobe help about hitTestObject method.
Edit
So you should write you class like that:
package
{
import flash.display.*;
import flash.events.*;
public class DragDrop extends Sprite
{
var origX:Number;
var origY:Number;
var target:DisplayObject;
public function DragDrop()
{
addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event):void {
origX = x;
origY = y;
stage.addEventListener(MouseEvent.MOUSE_DOWN, drag);
buttonMode = true;
}
private function drag(evt:MouseEvent):void
{
stage.addEventListener(MouseEvent.MOUSE_UP, drop);
startDrag();
parent.addChild(this);
}
private function drop(evt:MouseEvent):void
{
target = (evt.target as DisplayObject);
stage.removeEventListener(MouseEvent.MOUSE_UP, drop);
stopDrag();
if(target.hitTestObject(target))
{
visible = false;
target.alpha = 1;
Object(parent).match();
}
x = origX;
y = origY;
}
}
}
Remark
You shouldn't call your variable target, because its the name of a Flash native variable. Rename it targ for example.
Related
Please do forgive me if this is a stupid question, by I really need to know the solution. So here I have a program that generates particles every set distance of space. My program consists of a document class, called supportForce and an object class(of the particle) called TheDot.
In the TheDot object class, I have the following code-
package
{
import flash.display.MovieClip;
import flash.events.Event;
public class TheDot extends MovieClip
{
var base:Object = MovieClip(root);
public function TheDot()
{
this.addEventListener(Event.ENTER_FRAME, eFrame);
}
private function eFrame(event:Event):void
{
if (base.currentFrame == 1){
trace ("G");
}
}
}
}
This code works perfectly (outputs G) until I add the following code into the document class, suportForce, under an ENTER_FRAME event-
var ctX:int = 0,ctY:int = 0,done:Boolean = false;
while (done == false)
{
var dots:TheDot = new TheDot ;
dots.alpha = 0;
dots.x += (25 * ctX);
dots.y += (25 * ctY);
ctX++;
if (ctX == 22 && ctY == 20)
{
done = true;
break;
}
else if (ctX == 22)
{
ctX = 0;
ctY++;
}
stage.addChild(dots);
}
So now, there is an Error #1009: Cannot access a property or method of a null object reference at TheDot/eFrame(). I have declared all the variables in the correct place, and also the functions. Thanks in advance. I have the link to the .fla and .as files in my drive here, do use it if necessary.
https://drive.google.com/folderview?id=0B8QnUfRAn9lKLUVqRjNSRHNpRkU&usp=sharing
FIRST
var dots:TheDot = new TheDot(stage);
public class TheDot extends MovieClip
{
var base:Object;
public function TheDot(stageRef:Stage)
{
base = stageRef;
this.addEventListener(Event.ADDED_TO_STAGE, init);
}
public function init(e:Event) {
this.removeEventListener(Event.ADDED_TO_STAGE, init);
this.addEventListener(Event.ENTER_FRAME, eFrame);
}
private function eFrame(event:Event):void
{
if (base.currentFrame == 1){
trace ("G");
}
}
Try this!
We are making an space impact game. Here are 3 of our classes. Our problem is that when we create our InimigoNoite, they appear all over the game(menus, other levels, etc), instead of only appearing in the Scene that we want. How should we restrict the child to only appear in the CenárioCidade?
We've tried to use gotoandPlay, addChildAt, and also tried to create the Inimigo not in the Main class, but in the Inimigo class itself, but it doesnt appear at all. Please can someone help us? Thank you very much!
KEY.as
package {
import flash.display.Stage;
import flash.events.Event;
import flash.events.KeyboardEvent;
public class Key {
private static var initialized:Boolean = false;
private static var keysDown:Object = new Object();
public static function initialize(stage:Stage) {
if (!initialized) {
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
stage.addEventListener(KeyboardEvent.KEY_UP, keyReleased);
stage.addEventListener(Event.DEACTIVATE, clearKeys);
initialized = true;
}
}
public static function isDown(keyCode:uint):Boolean
{
return Boolean(keyCode in keysDown);
}
private static function keyPressed(event:KeyboardEvent):void {
keysDown[event.keyCode] = true;
}
private static function keyReleased(event:KeyboardEvent):void {
if (event.keyCode in keysDown) {
delete keysDown[event.keyCode];
}
}
private static function clearKeys(event:Event):void {
keysDown = new Object();
}
}
}
INIMIGO NOITE.as
package{
import flash.display.MovieClip;
import flash.events.Event;
import flash.utils.Timer;
public class InimigoNoite extends MovieClip{
var speed:Number;
static var list:Array = new Array();
var balaTimer: Timer;
function InimigoNoite(){
list.push(this);
this.x = 1160;
this.y = 150 + (450-150) * Math.random();
speed = Math.random()*5 + 5;
addEventListener("enterFrame", enterFrame);
var intervalo: Number = Math.random()*500 + 1000;
balaTimer = new Timer(intervalo);
balaTimer.addEventListener("timer", bala);
balaTimer.start();
}
function enterFrame (e:Event){
this.x -= speed;
if(this.x < -100){
matar();
return;
}
if(this.hitTestObject(SpaceImpact.navecnoite)){
matar();
}
}
function matar(){
var explosao = new ExplosaoNoite();
stage.addChild(explosao);
explosao.x = this.x;
explosao.y = this.y;
balaTimer.stop();
balaTimer.removeEventListener("timer",bala);
removeEventListener("enterFrame", enterFrame);
stage.removeChild(this);
for(var i in list){
if(list[i] == this){
delete list[i];
}
}
}
function bala(e:Event){
var b = new BalaInimigo();
b.x = this.x -50;
b.y = this.y;
stage.addChild(b);
}
}
}
MAIN.as
package{
import flash.display.MovieClip;
import flash.events.Event;
import flash.utils.Timer;
public class SpaceImpact extends MovieClip{
static var navecnoite:MovieClip;
var inimigoNoiteTimer:Timer;
function SpaceImpact(){
Key.initialize(stage);
inimigoNoiteTimer = new Timer(8000);
inimigoNoiteTimer.addEventListener("timer", criaInimigo);
inimigoNoiteTimer.start();
}
function criaInimigo(e:Event){
var inimigo = new InimigoNoite();
stage.addChild(inimigo);
addChildAt(inimigo, 3);
}
}
}
You never stop the timer. So your inimigo is created and added every 8seconds.
Stop the timer in criaInimigo and/or use the timerComplete Event
function SpaceImpact(){
Key.initialize(stage);
inimigoNoiteTimer = new Timer(8000,1);
inimigoNoiteTimer.addEventListener(TimerEvent.TIMER_COMPLETE, criaInimigo);
inimigoNoiteTimer.start();
}
function criaInimigo(e:Event){
//inimigoNoiteTimer.stop();//only needed if you use the 'timer'-Event
var inimigo = new InimigoNoite();
stage.addChild(inimigo);
addChildAt(inimigo, 3);
}
Right when you application starts, you are creating a new InimigoNoite every 8 seconds. Since you are adding them to the stage, they will appear over top anything you have on your timeline.
The issue (besides creating them when the application starts and never stopping your timer), is that when you through code use addChild, that child will stay on the screen until it's explicitly removed via removeChild (or one of it's parents are - but since the parent is stage that isn't going to happen).
I see that your have a hit test in the InimigoNoite class that can potentially remove it, but I don't see anywhere else where you remove it (so if the hit test never happens, it will never be removed from the stage regardless of scene).
It seem though that the solution to your problem is more advice on how to architect your application.
Don't use scenes.
Your best bet is to create a class file for each distinct state of your game. So something like this as a basic example:
Main Menu State
Game Play State(either 1 game state that encompasses all levels, or one state for each level - or both - depending on how much functionality changes between levels)
Game Over State
Make your game state class files extend Sprite or MovieClip, and if you want you can even create a new MovieClip in flash pro and attach the class to that (thereby being able to drop visual assets on the timeline).
So then your Main class would just be in charge of managing states (and any anything else that is global to the application)
package{
import flash.display.MovieClip;
import flash.events.Event;
public class SpaceImpact extends MovieClip {
private var menu:Menu; //Assumes you have a Menu.as class file
private var game:MainGame; //MainGame.as file
private var gameOver:GameOver; //GameOver.as file
public function SpaceImpact(){
Key.initialize(stage);
goMenu();
}
public function goMenu(e:Event = null):void {
removeAll();
menu = new Menu();
addChild(menu);
menu.addEventListener(Event.COMPLETE, startGame,false,0,true);
}
private function removeMenu():void {
if(menu){
if(menu.parent) removeChild(menu); //remove it from the screen
menu = null;
}
}
public function startGame(e:Event = null):void {
removeAll();
game = new MainGame();
addChild(game);
game.addEventListener(Event.COMPLETE, gameOver,false,0,true);
}
private function removeGame():void {
if(game){
if(game.parent) removeChild(game); //remove it from the screen
game = null;
}
}
public function gameOver(e:Event = null):void {
removeAll();
gameOver = new GameOver();
addChild(gameOver);
gameOver.addEventListener(Event.COMPLETE, goMenu,false,0,true);
}
private function removeGameOver():void {
if(gameOver){
if(gameOver.parent) removeChild(gameOver); //remove it from the screen
gameOver = null;
}
}
private function removeAll():void {
removeGameOver();
removeMenu();
removeGame();
}
}
}
then, your game state for example:
MainGame.as
package{
import flash.display.MovieClip;
import flash.events.Event;
import flash.utils.Timer;
public class MainGame extends MovieClip {
private var inimigoNoiteTimer:Timer;
public function MainGame() {
this.addEventListener(Event.ADDED_TO_STAGE, addedToStage, false, 0, true); //don't do anything until this object has been added to the screen
}
private function addedToStage(e:Event):void {
this.removeEventListener(Event.ADDED_TO_STAGE, addedToStage);
//start spawning
inimigoNoiteTimer = new Timer(8000);
inimigoNoiteTimer.addEventListener("timer", criaInimigo);
inimigoNoiteTimer.start();
}
function criaInimigo(e:Event){
var inimigo = new InimigoNoite();
addChild(inimigo);
}
//when whatever happens that makes your game finished
function gameComplete():void {
dispatchEvent(new Event(addEventListener.COMPLETE));
}
}
}
So, I have this code:
public function hitTest1(e:Event) : void
{
if (hitTestObject(target.hit)){
gotoAndStop(2,"Scene 1");
removeEventListener(Event.ENTER_FRAME, hitTest1);
}
}
In which target is the object that is going to be hit, and hit is a symbol in a layer over said object. When I run the code I get this error over an over again.
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at com.Mass.basics1::Asteroid/hitTest1()
NOTE: Asteroid is the .as file that contains all of this code.
Here is the rest of the code for reference :
package com.Mass.basics1
{
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.Event;
public class Asteroid extends MovieClip
{
public var target:Cosmo;
private var stageRef:Stage;
private var speed:Number;
// public var ourAsteroid:Asteroid = new Asteroid(stage);
public function Asteroid(stageRef:Stage)
{
this.stageRef = stageRef;
setupAsteroid(true);
addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
addEventListener(Event.ENTER_FRAME, hitTest1);
}
public function hitTest1(e:Event):void
{
if (hitTestObject(target.hit))
{
gotoAndStop(2,"Scene 1");
removeEventListener(Event.ENTER_FRAME, hitTest1);
}
}
public function setupAsteroid(randomizeY:Boolean = false):void
{
//inline conditional, looks complicated but it's not.
y = randomizeY ? Math.random() * stageRef.stageHeight:0;
x = Math.random() * stageRef.stageWidth;
rotation = Math.random() * 360;
scaleX = Math.random();
scaleY = scaleX;
speed = 20 + Math.random() * 10;
}
public function loop(e:Event):void
{
y += speed;
if (y > stageRef.stageHeight)
{
setupAsteroid();
}
}
}
}
So, where is the "target" object? You're just declaring a variable, but not creating the object or setting a reference. It's a public variable, so maybe you are setting a reference somewhere else? In that case, make sure you assign a reference before you are calling hitTest1 function...
I have two classes called Guest and Guest2. I wanted to know is it possible to remove an eventlistener in the Guest class from Guest2 class. Below is the full code. Note: Both class have exactly the same code
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filters.*;
public class Guest extends MovieClip
{
var walkSpeed:Number = 5;
var oldPosX;
var oldPosY;
var myGlow:GlowFilter = new GlowFilter();
public function Guest()
{
addEventListener(MouseEvent.MOUSE_OVER, addGlow);
}
function addGlow(event:MouseEvent):void
{
filters = [myGlow];
addEventListener(MouseEvent.MOUSE_OUT, removeGlow);
addEventListener(MouseEvent.CLICK, ready);
}
function removeGlow(event:MouseEvent):void
{
filters = [];
}
function ready(event:MouseEvent):void
{
filters = [myGlow];
stage.addEventListener(MouseEvent.MOUSE_DOWN, walk);
removeEventListener(MouseEvent.MOUSE_OUT, removeGlow);
**MovieClip(root).Guest02.addEventListener(MouseEvent.CLICK, walkTo);**
}
function walk(event:MouseEvent):void
{
oldPosX = parent.mouseX;
oldPosY = parent.mouseY;
rotation = Math.atan2(oldPosY - y,oldPosX - x) / Math.PI * 180;
filters = [];
stage.removeEventListener(MouseEvent.MOUSE_DOWN, walk);
stage.addEventListener(Event.ENTER_FRAME, loop);
}
function loop(event:Event):void
{
var dx:Number = oldPosX - x;
var dy:Number = oldPosY - y;
var distance:Number = Math.sqrt((dx*dx)+(dy*dy));
if (distance<walkSpeed)
{
// if you are near the target, snap to it
x = oldPosX;
y = oldPosY;
removeEventListener(Event.ENTER_FRAME, loop);
}
else
{
x = x+Math.cos(rotation/180*Math.PI)*walkSpeed;
y = y+Math.sin(rotation/180*Math.PI)*walkSpeed;
}
}
**function walkTo(event:MouseEvent):void
{
_Guest02.removeEventListener(MouseEvent.CLICK, ready);
}**
}
}
As Jake King pointed out already, you might want to revisit your code in terms of object-oriented programming. If you say that both classes share the exact same functionality, why don’t you set up a class Guest and create two instances, e.g. guest1 and guest2.
As for your question regarding the event handlers, you need to store your listener in an instance variable that is either public and can then be accessed from another instance (bad style), or write a dedicated public function that allows for the removal of a listener, while the listener variable is kept private:
public class Guest extends MovieClip
{
private var overListener;
public function Guest()
{
overListener = addEventListener(MouseEvent.MOUSE_OVER, addGlow);
}
public function removeOverListener()
{
if (overListener) {
removeEventListener(MouseEvent.MOUSE_OVER, overListener);
}
}
...
}
If guest1 and guest2 were both instances of Guest and guest1 had a reference to guest2 stored, you could then remove a listener in guest2 from guest1 like so:
guest2.removeOverListener();
After 2 days of trying and searching for an answer I still didn't found it. I keep getting Error #2025: The supplied DisplayObject must be a child of the caller. I'm making a game where if the user hits an enemy, the enemy get destroyed. The code:
My main class
package classes
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.utils.Timer;
public class Main extends MovieClip
{
var enemyTimer:Timer;
public function Main()
{
var user:ship = new ship();
addChild(user);
user.name = "user";
user.initialize();
enemyTimer = new Timer(2000);
enemyTimer.addEventListener("timer", sendEnemy);
enemyTimer.start();
function sendEnemy(e:Event)
{
var badboy:enemy = new enemy();
addChild(badboy);
badboy.initialize();
}
}
}
}
the enemy class
package classes.enemy
{
import flash.display.MovieClip;
import flash.events.Event;
public class Enemy extends MovieClip
{
var speed:Number;
public function initialize()
{
addEventListener("enterFrame", enterFrame);
}
public function Enemy()
{
this.x = 700;
this.y = Math.random()*200 + 50;
speed = Math.random()*5 + 5;
}
function enterFrame(e:Event)
{
this.x -= speed;
if(this.hitTestObject(parent.getChildByName("user")))
{
kill();
}
}
function kill()
{
removeEventListener("enterFrame", enterFrame);
stage.removeChild(this);
}
}
}
The files are in different folders (classes > Main.as & classes.enemy.Enemy.as), don't know if that has anything to do with it.
Any help would be appreciated.
That's probably because you try to remove the Enemy MovieClip from stage, that it is not a (direct) child of.
I suggest you change this:
stage.removeChild(this);
to this:
this.parent.removeChild(this);
When you have a reference to a DisplayObject, like this in this case, you can always remove it from its parent, even if you don't know what that parent is. Or rather, you can remove it if you know it is on the display list, so you could also first check that it is, by doing:
if(this.parent) {
this.parent.removeChild(this);
}
I have got the solution: Just copy and paste the script and create few essentials symbols on stage, and in library; then, check it.
import flash.display.MovieClip;
var myArr:Array = [];
abc.startDrag(true);
var mymc:MovieClip = new MovieClip();
addChild(mymc);
init();
function init()
{
for (var i=0; i<25; i++)
{
var par:Particle = new Particle();
par.x = Math.random() * stage.stageWidth;
par.y = Math.random() * stage.stageHeight;
mymc.addChildAt(par,0);
myArr.push(par);
}
this.addEventListener(Event.ENTER_FRAME, hitTes);
}
function hitTes(e:Event):void
{
for (var j=0; j<myArr.length; j++)
{
if (abc.hitTestObject(myArr[j]))
{
if (myArr[j].parent)
{
myArr[j].parent.removeChild(myArr[j]);
}
}
}
}
I think you misplaced a method. See if this revision helps. (Also note that this does not include any cleanup of objects, which will eventually be a problem.)
package classes
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.utils.Timer;
public class Main extends MovieClip
{
public var enemyTimer:Timer;
public var user:ship = new ship();
public var badboy:enemy = new enemy();
public function Main()
{
user = new ship();
addChild(user);
user.name = "user";
user.initialize();
enemyTimer = new Timer(2000);
enemyTimer.addEventListener("timer", sendEnemy);
enemyTimer.start();
}
// *** I moved this out of the constructor:
public function sendEnemy(e:Event):void
{
badboy = new enemy();
badboy.name = "badboy"; // you probably have to make this unique, though.
addChild(badboy);
badboy.initialize();
}
}
}