Program crashes due to text being null. [As3] - arrays

[Fault] exception, information=TypeError: Error #2007: Parameter text must be non-null.
Hello guys, I get this error when I restart my program.
In the main class I have these variables
//random
private var colourArray:Array = new Array("Red","Yellow","Green");
private var len:int = colourArray.length - 1;
private var rand:int;
private var randomItem:String;
private var myText:TextField;
then I have a loop that chest only the collision function
private function Collision():void
{
if (randomItem == ("Red"))
{
if (player.hitTestObject(red))
{
changeColor();
red.removeMe();
}
}
else
if (randomItem == ("Yellow"))
{
if (player.hitTestObject(yellow))
{
changeColor();
yellow.removeMe();
}
}
else
if (randomItem == ("Green"))
{
if (player.hitTestObject(green))
{
changeColor();
green.removeMe();
}
}
}
private function changeColor():void
{
var item:String = colourArray[rand];
colourArray[rand] = colourArray[len];
colourArray[len] = item;
len--;
randomItem = colourArray[rand];
myText.text = randomItem;
if (len < 0)
{
removeChild(player);
removeChild(myText);
colourArray.push("Red");
removeEventListener(Event.ENTER_FRAME, gameLoop)
addEventListener(Event.ENTER_FRAME, checkClicks)
gotoAndStop(1);
}
}
When I try and restart the program it doesn't like ;
randomItem = colourArray[rand];
For some reason.
I have repopulated the array, but I do not understand.
Thank you.
If you need more information please do ask.

You have to store colourArray[rand] elsewhere prior to altering the array. You are lowering its length, then you query the element out of the array, so if your rand points to the last element, it gets kicked out of the array and replaced by NULL, and then you query the array again - the program says hello NULL, I panic. You already store that value in item variable, but don't use it for some weird reason. A fix is replace the randomItem = colourArray[rand]; with randomItem = item;

Related

Generate Random Number Using math.random, But Without Repeats

For a yearly Christmas event for an organization I'm a part of, we usually hold a raffle where people have the opportunity to win free prizes by just attending and getting a number ticket at the door. We use a program written in Flash (Using ActionScript 2.0) that selects a random number utilizing math.random, with some parameters attached to it, as shown below:
//maxNr = 999999999999999;
initRandom = function(){
var nr = Math.ceil(Math.ceil(Math.random()*(maxNr));
var nrString = "";
for( var j=0; j<(maxNr.toString().length-nr.toString().length); j++){
nrString += "0";
}
nrString += nr.toString();
var holder = this.createEmptyMovieClip("holder",1);
for( i=0; i<maxNr.toString().length; i++ ){
var mc = holder.attachMovie("number","n"+i,i+10);
mc._x = i*350;
mc.anim_mc.gotoAndPlay( Math.floor(Math.random()*9) + 1 );
this["iv"+i] = setInterval( this, "revealNumber", 2000 + (500*i), nrString.substr(i,1), i );
}
// scale (if needed) and center
if( holder._width > Stage.width ){
holder._width = Stage.width;
holder._yscale = holder._xscale;
}
holder._x = Stage.width/2 - holder._width/2;
holder._y = 100;
// buttons
back_btn.onRelease = function(){
for(item in holder){
holder[item].removeMovieClip();
}
gotoAndStop("intro");
}
}
revealNumber = function( digit, i ){
clearInterval( this["iv"+i] );
holder["n"+i].gotoAndStop("done");
holder["n"+i]["number_txt"].text = digit;
}
initRandom();
stop();
It's meant to return a random number between 1 and 1000, as defined by:
go_btn.onRelease = function(){
maxNr = Math.max( 1000 , 1 );
gotoAndStop("random");
}
stop();
It was written by a member of our organization who unfortunately passed away during the year, and I have little to no programming knowledge but I am a quick learner and have actually modified some of the code to get to the point it is currently. However, I'm trying to add in a parameter that would disallow the function from repeating a number, ie, excluding an already generated number from being reselected.
I've spent days scouring any resource possible and have only met dead ends.
With the approach currently taken, is it possible to add in this parameter to this existing code, and how can I go about doing that?
Any help, suggestion or reply would be very greatly appreciated!
package
{
public class RandomGenerator
{
private var _st:Number;
private var _en:Number;
private var _len:Number;
private var _pos:Number;
private var _numPos:Number;
private var _myNums:Array;
private var _randNums:Array;
public function RandomGenerator(en:Number, st:Number = 0)
{
_st = st;
_en = en;
// just in case if params order mixup:
if(en < st){
_st = en;
_en = st;
}
_len = _en - _st + 1;
shuffle();
}
public function getNum():Number
{
// if passed last item:
if(_numPos == _len)shuffle();
var myResult:Number = _randNums[_numPos];
_numPos++;
return myResult;
}
private function shuffle():void
{
_numPos = 0;
_randNums = [];
_myNums = [];
// Creating Numbers Array:
var i:Number;
for(i = 0; i<_len; i++){ _myNums[i] = _st + i; }
// Creating shuffled Numbers Array:
i = 0;
while(_myNums.length > 0){
_pos = Math.round(Math.random()*(_myNums.length-1));
_randNums[i] = _myNums[_pos];
i++;
_myNums.splice(_pos,1);
}
}
public function get len():Number
{
return _len;
}
}
}
make an object from this class for example cardGenerator:RandomGenerator = new RandomGenerator(51, 0) and finally you can get random number without repeat with this codes:
for (var i:int = 0; i < cardGenerator.len; i++) {
trace(cardGenerator.getNum());
}
My AS2 is a bit rusty, but I think the following script explains the general idea. You need some registry to record generated numbers so you can skip them next time you generate one. I used the _global object so that this logic transcends even multiple instances of the following script.
// Create an Array to record generated numbers.
// The _global object is always present and can be accessed from anywhere.
if (_global.uniqueNr == undefined)
{
_global.uniqueNr = [];
}
function initRandom()
{
var nr;
do
{
nr = Math.ceil(Math.ceil(Math.random()*(maxNr));
}
while (_global.uniqueNr[nr] == true);
// Record the newly generated number so it would never drop again.
_global.uniqueNr[nr] = true;
// At this point you can be sure that "nr" contains a unique value.

Unity3D: How to go Back or Forward in Array list

I have a gameObject with an ID, the gameObjects are spawned by giving initial ID: 1 , then any after spawned will be +1 so next is ID: 2.
I have two buttons that check current gameObjects ID#, BackOneButton (-1) and PlusOneButton (+1).
Currently it works but only if the array of gameObjects have IDs in order like for example [gameObject-ID:1], [gameObject-ID:2], [gameObject-ID:3]
But since you can self destruct a certain gameObject, here is where the error is --->
Now the array is not in order for example [gameObject-ID:1], [gameObject-ID:3], [gameObject-ID:4]. So if I'm currently in [gameObject-ID:3] and I use the BackOneButton and looks for ID: 2 it won't find it BUT there is ID:1. That's my error, I can't seem to figure out how to handle this.
Basically, How do I handle missing increments and skip over the missing?
Left Button (MinusOneButton)
void ButtonAction_LeftMinusOne()
{
// Get list of all gameObjects and -1 current to switch
string objName = manager.currentObjectTransform.name;
string[] splitArray = objName.Split('_');
string idObjNumber = splitArray[1];
switch (idObjNumber)
{
case "0":
// not supposed to be ID: 0
break;
case "1":
// nothing to go back to, this is ID: 1
break;
default:
// currently in (ID: 2 & Up) second object
int currentID = int.Parse(idObjNumber);
string idBackOne = (currentID - 1).ToString();
GameObject[] allObjInFull = GameObject.FindGameObjectsWithTag("Object");
if (allObjInFull.Length >= 2)
{
for (int i = 0; i < allObjInFull.Length; i++)
{
if (allObjInFull[i].transform.name.Contains(idBackOne))
{
// Set Camera
camera.transform.parent = allObjInFull[i].transform.GetChild(0).GetChild(1);
camera.transform.position = allObjInFull[i].transform.GetChild(0).GetChild(1).position;
camera.transform.rotation = allObjInFull[i].transform.GetChild(0).GetChild(1).rotation;
}
}
}
break;
}
}
Right Button (PlusOneButton)
void ButtonAction_RightPlusOne()
{
// Get list of all objects and +1 current to switch
string objName = manager.currentObjectTransform.name;
string[] splitArray = objName.Split('_');
string idObjNumber = splitArray[1];
switch (idObjNumber)
{
case "0":
// not supposed to be ID: 0
break;
default:
// currently in (ID: 1 & Up) object
int currentID = int.Parse(idObjNumber);
string idPlusOne = (currentID + 1).ToString();
GameObject[] allObjInFull = GameObject.FindGameObjectsWithTag("Object");
if (allObjInFull.Length >= 2)
{
for (int i = 0; i < allObjInFull.Length; i++)
{
if (allObjInFull[i].transform.name.Contains(idPlusOne))
{
// Set Camera
camera.transform.parent = allObjInFull[i].transform.GetChild(0).GetChild(1);
camera.transform.position = allObjInFull[i].transform.GetChild(0).GetChild(1).position;
camera.transform.rotation = allObjInFull[i].transform.GetChild(0).GetChild(1).rotation;
}
}
}
break;
}
}
It would be way better (especially regarding maintenance) and more efficient to have a central manager class with a List<GameObject> where you simply Add and Remove items dynamically. (Since you already seem to have one in manager I would rather extend that one)
public static class ObjectsManager
{
// If you are not concerned about
// capsulation you could ofcourse make this public as well
// but I thought this is cleaner
private static List<GameObject> objects;
// Read-only property
public static int Count
{
get
{
Initialize();
return objects.Count;
}
}
// initialize the list once
// I first had this in e.g. Awake
// but now you can easily use this in multiple scenes
public static void Initialize(bool force reinitialize = false)
{
if(objects != null && ! reinitialize) return;
objects = FindObjectsWithTag("Object").ToList();
}
public static void Add(GameObject newObject)
{
Initialize();
if(objects.Contains(newObject) return;
objects.Add(newObject);
}
public static void Destroy(GameObject toDestroy)
{
Initialize();
if(objects.Contains(toDestroy)
{
objects.Remove(toDestroy);
}
Object.Destroy(toDestroy);
}
public static int IndexOf(GameObject obj)
{
Initialize();
return objects.IndexOf(obj);
}
public static GameObject GetByIndex(int index)
{
Initialize();
// Use modulo to wrap around the index in case
// +1 or -1 exceeds the list ends
// in your case you might not need it
// but I decided to add it to be more flexible
var nextIndex = (index + 1) % objects.Count;
return objects[index];
}
}
Everytime you Instantiate a new object make sure to also call
ObjectsManager.Add(newObject);
and everytime where you destroy an object rather use
ObjectsManager.Destroy(objectToDestroy);
so it is also removed from the list first.
Then you can easily use
var currentIndex = ObjectsManager.IndexOf(certainObject);
to get the current index of an object and simply move through the index (+1, -1)
var nextObject = ObjectsManager.GetByIndex(currentIndex + 1);
var lastObject = Objects manager.GetByIndex(currentIndex - 1);
In case you switch the scene you have reinitialize the list once in order to get rid of null references
ObjectsManager.Initialize(true);
In your example code you would e.g. use something like
void ButtonAction_LeftMinusOne()
{
GameObject currentObject = manager.currentObjectTransform.gameObject;
int currentIndex = ObjectsManager.IndexOf(currentObject);
if(currentIndex < 0)
{
Debug.LogErrorFormat(this, "Object {0} is not in list!", currentObject.name);
return;
}
if(currentIndex == 0)
{
// nothing to do go back to
// Except you want wrap around then simply remove this check
Debug.Log("Already is first object in list", this);
return;
}
GameObject newObject = ObjectsManager.GetByIndex(currentIndex - 1);
Transform childOfNewObject = newObject.GetChild(0).GetChild(1);
// Set Camera
// Using simply SetParent with parameter worldPositionStays=false
// reduces it to one single call
camera.transform.SetParent( childOfNewObject, false);
}
And accordingly
void ButtonAction_RightPlusOne()
{
GameObject currentObject = manager.currentObjectTransform.gameObject;
int currentIndex = ObjectsManager.IndexOf(currentObject);
if(currentIndex < 0)
{
Debug.LogErrorFormat(this, "Object {0} is not in list!", currentObject.name);
return;
}
if(currentIndex == ObjectsManager.Count - 1)
{
// nothing to do go forward to
// Except you want wrap around then simply remove this check
Debug.Log("Already is last object in list", this);
return;
}
GameObject newObject = ObjectsManager.GetByIndex(currentIndex + 1);
Transform childOfNewObject = newObject.GetChild(0).GetChild(1);
// Set Camera
// Using simply SetParent with parameter worldPositionStays=false
// reduces it to one single call
camera.transform.SetParent( childOfNewObject, false);
}

Type Coercion Failed in Action Script 3, getting element from an array

I'm getting this error when I'm getting an element from an array and trying to use some functions on it:
TypeError: Error #1034: Type Coercion failed: cannot convert jogador$
to jogador. at laser/mover_tiro_baixo()
Sorry it's in portuguese, just like the code i'll paste below, but I think you get it: when I retrieve the element from an array it's of type 'jogador$', and if I try to use it as being of 'jogador' it doesn't work. I'm trying to manually force the coercion, as it was trying to convert the object to a DisplayObject (because I'm trying to use the hit test function), but that also didn't work:
TypeError: Error #1034: Type Coercion failed: cannot convert jogador$
to flash.display.DisplayObject. at laser/mover_tiro_baixo()
Code:
package {
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.Event;
import flash.debugger.enterDebugger;
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;
import flash.display.DisplayObject;
public class laser extends MovieClip {
private var velo: Number;
private var meuPalco: Stage;
var dono: MovieClip;
var inimigoTipo: Number;
var Inimigos: Array;
var Dano: Number;
var Tam:Number;
var i:Number;
public function laser(palco: Stage, posX: Number, posY: Number, velocidade: Number, dano: Number, CimaBaixo: Number, Dono: MovieClip, vetJogadores: Array) {
this.dono = Dono;
this.Dano = dano;
if (getClass(this.dono) == "jogador") {
inimigoTipo = 0;
Inimigos = jogador(this.dono).VetorInimigos;
} else {
inimigoTipo = 1;
Inimigos = vetJogadores;
}
this.meuPalco = palco;
this.velo = velocidade;
this.x = posX;
this.y = posY;
if (CimaBaixo == 1) {
this.addEventListener(Event.ENTER_FRAME, mover_tiro_cima);
} else {
this.addEventListener(Event.ENTER_FRAME, mover_tiro_baixo);
}
meuPalco.addChild(this);
}
public function mover_tiro_cima(evt: Event) {
this.y -= velo;
if (inimigoTipo == 0) { // Dono do tiro é o player
var Tam: Number = Inimigos.length;
var i: Number = 0;
while (i < Tam) {
if (this.hitTestObject(Inimigos[i])) {
inimigo(Inimigos[i]).vida.Diminuir(this.Dano);
}
i++;
}
} else { // Dono do tiro é um inimigo
Tam = Inimigos.length;
i = 0;
while (i < Tam) {
if (this.hitTestObject(Inimigos[i])) {
jogador(Inimigos[i]).vida.Diminuir(this.Dano);
}
i++;
}
}
if (this.y <= 0) {
this.removeEventListener(Event.ENTER_FRAME, mover_tiro_cima);
meuPalco.removeChild(this);
}
}
public function mover_tiro_baixo(evt: Event) {
this.y += velo;
if (inimigoTipo == 0) { // Dono do tiro é o player
Tam = Inimigos.length;
i = 0;
while (i < Tam) {
if (this.hitTestObject(Inimigos[i])) {
inimigo(Inimigos[i]).vida.Diminuir(this.Dano);
}
i++;
}
} else { // Dono do tiro é um inimigo
Tam = Inimigos.length;
i = 0;
while (i < Tam) {
if (this.hitTestObject(Inimigos[i])) {
jogador(Inimigos[i]).vida.Diminuir(this.Dano);
}
i++;
}
}
if (this.y <= 0) {
this.removeEventListener(Event.ENTER_FRAME, mover_tiro_baixo);
meuPalco.removeChild(this);
}
}
static function getClass(obj: Object): String {
return String(Class(getDefinitionByName(getQualifiedClassName(obj))));
}
}
}
The error happens everytime the laser tests to see if it's hitting an enemy (hittest) in its functions. mover_tiro_baixo() moves the shot down.
Thanks people!
Edit: The way I create the arrays:
var player1:jogador = new jogador(stage,350,700,10,3,1);
var Jogadores:Array = [jogador];
player1.setJogadores(Jogadores);
var inimigo1:et = new et(stage,100,200,Jogadores);
var inimigo2:et = new et(stage,200,100,Jogadores);
var inimigo3:et = new et(stage,350,450,Jogadores);
var todosInimigos:Array = [inimigo1,inimigo2,inimigo3];
player1.DefinirInimigos(todosInimigos);
I've checked some other stack overflow questions that have similar type conversion errors. Most of the other people with a similar problem were actually filling their array with a Class, rather than objects that were instances of a Class. Are you filling those arrays like this?
for(var i:int = 0; i < 10; i++){
Inimigos.push(jogador); //incorrect
}
If so, that is the reason the problem is happening. This is the correct way to do it:
for(var i:int = 0; i < 10; i++){
Inimigos.push(new jogador()); //correct
}
EDIT:
In the new code you added to the first post, this line seems to be the problem:
var Jogadores:Array = [jogador]; //jogador is a class
Flash Actionscript Arrays cannot be "initialized" to only be able to contain a specific type of object. Actionscript Vectors are capable of that, but not Arrays. That line posted above initializes an array in which the first element is a class, not an object.

store data in array from another class method

i have one method in class call Class1 like
' public void getEventFromUser() {
int event;
Scanner input = new Scanner(System.in);
date.getDateFromUser();
// od.inputday();
// od.inputyear();
time.getTimeFromUser();
System.out.println("Enter description :");
description = input.nextLine();
}'
and i want to execute this method and store in array in another class
like
public void addEvent() {
if (numEvent == maxEvent) {
System.out.println("error…no more room to add events");
} else {
schedule[numEvent]=getEventFromUser();
int count = 0;
while (count < numEvent - 1) {
if (schedule[numEvent].isEqual(schedule[count])) {
isFound = true;
break;
}
count++;
if (isFound == true) {
System.out.println("Event already exists-notadding");
schedule[numEvent] = null;
} else {
schedule[numEvent].setDate();
schedule[numEvent].setTime();
schedule[numEvent].setDescription();
numEvent++;
//schedule[numEvent]=schedule[numEvent].getEventFromUser();
}
}
}
} '
so,how can i do this?
pls give me some solution
getEventFromUser() doesn't return a value, which is why schedule[numEvent]=schedule[numEvent].getEventFromUser() is giving you trouble.
Without knowing a bit more about what you're trying to do, it's hard to say if you should have getEventFromUser() return a value or have getEventFromUser() directly store a value in a field in the class. (I'm guessing the setDate, setTime and setDescription methods do this.)

How to MouseEvent.Click on Multiple Movie Clips in Array

I have an array of Movie Clips that are added to the stage by a timer event. This Movie Clip is called mSquare.Now I wanted to set up a EventListener for the Movie clip so whenever the user clicks on the Movie Clip then it is destroyed, But I am having trouble setting this up since there is an Array of them Added to the stage.
I keep getting this Error:
Cannot access a property or method of a null object reference.
Here is what I got so far:
mSquare.addEventListener(MouseEvent.CLICK, mIsDown);
Now in the mIsDown Function I know I have to go through the array so i tried to set up something like this:
private function mIsDown(e:MouseEvent):void
{
for (var i:int = 0; i < aSquareArray.length; i++)
{
//Get current Square in i loop
var currentSquare:mcSquare = aSquareArray[i];
if ( )
{
trace(currentSquare + "Mouse Is Down");
}
}
}
Also here is how my Square is added to the stage:
private function addSquare(e:TimerEvent):void
{
mSquare = new mcSquare();
stage.addChildAt(mSquare, 0);
mSquare.x = (stage.stageWidth / 2);
mSquare.y = (stage.stageHeight / 2) + 450;
aSquareArray.push(mSquare);
// trace(aSquareArray.length);
}
Any help would be appreciated on what i need to do in order for the user to be able to MOUSE.click or MouseDown for the array of movie clips thanks!
**************** Here is how I am doing it now***************
stage.addEventListener(MouseEvent.MOUSE_DOWN, movieClipHandler);
private function movieClipHandler(e:MouseEvent):void //test
{
mouseIsDown = true;
mSquare.addEventListener(MouseEvent.MOUSE_DOWN, squareIsBeingClicked);
}
private function squareIsBeingClicked(e:MouseEvent):void
{
var square:DisplayObject = e.target as DisplayObject; // HERE is your clicked square
var i:int = aSquareArray.indexOf(square); // and HERE is your index in the array
if (i < 0)
{
// the MC is out of the array
trace("Clicked");
checkSquareIsClicked();
} else
{
// the MC is in the array
}
}
private function checkSquareIsClicked():void
{
for (var i:int = 0; i < aSquareArray.length; i++)
{
var currentSquare:mcSquare = aSquareArray[i];
if (mouseIsDown)
{
aSquareArray.splice(i, 1);
currentSquare.destroySquare();
nLives --;
mouseIsDown = false;
}
}
}
The simplest answer is to use the target property of the event passed into the listener. This way you don't need to traverse the array in order to find what MC was clicked, you get it as target and go. To get the position of the targetted MC in the array, call indexOf function.
private function mIsDown(e:MouseEvent):void
{
var mc:DisplayObject = e.target as DisplayObject; // HERE is your clicked square
var i:int=aSquareArray.indexOf(mc); // and HERE is your index in the array
if (i<0) {
// the MC is out of the array
} else {
// the MC is in the array
}
}

Resources