AS3: hitTestObject turning up null for no apparent reason - arrays

I'm currently coding a game, and in one part of the code, it's checking to see if the player is close enough to a monster in mArray for its health bar to appear. I use hitTestObject for this with var i incrementing to go through the list. However, I will randomly get this error message:
TypeError: Error #2007: Parameter hitTestObject must be non-null.
After seeing this for the first time, I put the test all under the conditional if (mArray.length > 0) to make sure the Array() was filled before even attempting the test... but it still occurs at random times. I even used trace(i) to see if it happened on a certain part of the list, but it's completely random each debug session! I know the player portion can't be null since it is on the screen at all times during the hitTest, so I'm at a loss for words right now.
The portion of code in question (nothing else is related to this except for the use of mArray[i] in different places):
for (var i:int = 0; i < mArray.length; i++) {
if (mArray.length > 0) {
trace(i); //my attempt to see if it occurred at a specific incrementation of i
if (player.hitTestObject(mArray[i])) {
mArray[i].healthBar.visible = true;
} else {
mArray[i].healthBar.visible = false;
}
}
}
Again, it works perfectly for everything all of the time except for random cases it gives me the TypeError. Is this just a hiccup in my code, is there some obvious problem that I'm overlooking, or does the code just like to throwback to 2007?
EDIT: The debug session ALWAYS points to the line with if (player.hitTestObject(mArray[i])).

It looks like for some i the mArray[i] has a null value. Either make sure this won't happen when populating the array or just add extra check in hitTestObject line like this:
if (mArray[i] && player.hitTestObject(mArray[i])) { ... }
I don't know your game's architecture but maybe it would be more convenient to move the hitTestObject test into monster class instead of checking it externally. Typical approach is to have each entity to have some kind of "update" method that is executed once in every game loop.

Related

Counting number of times a movieclip loops

I have a 20 frame bouncing ball movieclip “ballAnim” on frame 1 of the stage, and I simply want to count each time “ballAnim” loops playback.
I am inexperienced with actionscript, and I’ve searched and tried a few things to no avail.
Here’s the code from my latest attempt:
import flash.events.Event;
var loopCounter:int;
ballAnim.addEventListener(Event.ENTER_FRAME, addOneLoop);
function addOneLoop(e:Event){
if(ballAnim.currentFrame == 20)
{loopCounter+1}
}
trace(loopCounter);\`
All I get is a single instance of 0. I’ve searched around and I think the problem is that loopCounter is resetting to 0 on every frame because of ENTER_FRAME? I tried addressing this by adding a 2nd keyframe on my actions timeline layer with stop(); (with the movieclip layer spanning both frames underneath) but it doesn’t help.
I’ve read that I might need to use a class, but I’m not sure what that is, and I thought this would be a fairly straightforward thing.
Ok, let's have a class.
Your problem is not understanding the flow of things. If we put it simply, Flash Player executes the movie/application in the infinite loop of recurring phases:
Playheads of playing MovieClips (also, the main timeline) move to the next frame.
Frame scripts are executed.
The whole movie is rendered and the picture is updated on the screen.
Pause till the next frame.
Events are handled.
Ok, the exact order just MIGHT be different (it is possible to figure it out but not important now). The important part is to understand that:
Flash Player is (normally) not a multi-thread environment, the phases follow each other, they never overlap, only one thing at a time happens ever and we are pretty much able to follow, which one.
The script you provided is executed at the "frame scripts" phase and that the ENTER_FRAME event handler doesn't execute until the "event handling" phase kicks in.
So, let's check it:
import flash.events.Event;
// This one returns time (in milliseconds) passed from the start.
import flash.utils.getTimer;
trace("A", getTimer());
ballAnim.addEventListener(Event.ENTER_FRAME, addOneLoop);
// Let's not be lazy and initialize our variables.
var loopCounter:int = 0;
function addOneLoop(e:Event):void
{
trace("BB", getTimer());
// Check the last frame like that because you can
// change the animation and forget to fix the numbers.
if (ballAnim.currentFrame >= ballAnim.totalFrames)
{
trace("CCC", getTimer());
// Increment operation is +=, not just +.
loopCounter += 1;
}
}
trace("DDDD", getTimer());
trace(loopCounter);
Now once you run it, you will get something like this:
A (small number)
DDDD (small number)
0
BB ...
BB ...
(20 times total of BB)
BB ...
CCC ...
BB ...
BB ...
Thus, in order to trace the number of loops happened, you need to output it inside the handler rather than in the frame script:
import flash.events.Event;
import flash.utils.getTimer;
ballAnim.addEventListener(Event.ENTER_FRAME, addOneLoop);
var loopCounter:int = 0;
function addOneLoop(e:Event):void
{
if (ballAnim.currentFrame >= ballAnim.totalFrames)
{
loopCounter += 1;
// This is the very place to track this counter.
trace("The ball did", loopCounter, "loops in", getTimer(), "milliseconds!");
}
}

Detecting collision between an object inside a movie clip that is in an array vs another array of objects

Simply,
I have randomly placed and moving movie clips that will call victims And I Have another set of random Moving movie clips that have an attack animation I will call them assailants.
Victims wander randomly among Assailants an at random times the Assailants will shoot out a lightning bolt movie clip to attack the victims. It is at this point I am attempting to check for a collision between the victims and the assailants lightning Bolts.
Both types are in separate array's and I have before checked an array vs an array without a problem I have also checked static object vs an array objects internal MC without an issue. However I am Stuck when checking array vs array objects internal MC.
Code:
for(var j:int=0;j<NormalBubbleArray.length;j++){
for(var k:int=0;k<LightningStormArray.length;k++){
if(NormalBubbleArray[j].hitTestObject(LightningStormArray[k]).upbolt){
trace("hit")
NormalBubbleArray.removeAt([j]);
LightningStormArray.removeAt([k]);
}
}
}
I have also Tried
if(NormalBubbleArray[j].hitTestObject(LightningStormArray[k]).upbolt)
and 10 other ways to try and write it. Still no luck not sure if its my loop or collision detection at this point. It gives no errors when running so I assume my Syntax is Ok.
Thanks In Advance.
Update: I was tinkering with it and realized I had it wrapped in a try catch so I was not seeing the error. now my issue is this.
for(var j = 0; j<NormalBubbleArray.length;j++){
for(var k = 0; k<LightningStormArray.length;k++){
if((LightningStormArray[k]).upbolt hitTestPoint(NormalBubbleArray [j]), true){
trace("hit")
(NormalBubbleArray [j]).removeEventListener(MouseEvent.MOUSE_MOVE, ChildMouse);
NormalBubbleArray.removeAt([j]);
LightningStormArray.removeAt([k]);
}
}
}
Still Compiles but when it comes time to detect I get The following error in the output.
TypeError: Error #1006: value is not a function.
at BubblesReloaded_fla::MainTimeline/CollisionControl()
Help is appreciated.. I am still tinkering with it.
Got it !
Tricky Devil.
The debuger kept pointing to the hittest line and it had nothing to do with the actual line it hilighted but what was inside the if statment that caused the issue.
var Lstormpoints:int = 0;
for(var j = 0; j<NormalBubbleArray.length;j++){
for(var k = 0; k<LightningStormArray.length;k++){
if(LightningStormArray[k].upbolt.hitTestPoint(NormalBubbleArray [j]), true){
trace("bubble is hit")
NormalBubbleArray [j].removeEventListener(MouseEvent.MOUSE_MOVE, ChildMouse);
NormalBubbleArray [j].gotoAndPlay(10)/// was (NormalBubbleArray [j]).gotoAndPlay(10) // was causing an error
NormalBubbleArray.removeAt([j]);
LightningStormArray.removeAt([k]);
}
}
}
What threw me off was that the debugger kept pointing to the if statement as the error. What I did not catch is it was trying to tell me that it was an error inside the if statement. I figured it out after some heavy tracing I Noticed that it was detecting collision but the Bubble was not acting as if it got hit giving me the illusion that it was not detecting hit. the gotoAndPlay line animates the death and sadly that was the line with the issue.. just happy I got it going.

SWIFT OS X - multiple statements inside a closure statement, a debugging tool?

I am using the following code to filter a large array:
var arrayOfSelectedRowDetails = self.projectRowDetails.filter(
{ $0.projectNumber == self.projectNumberArray[selectedRow] }
)
Normally the code runs fine and I have no issues. But in one scenario (after I have deleted some management objects from the persistent store) and then rerun the code I am getting a EXC_BAD_ACCESS (code = 1, address=0x0) error at runtime.
I have set a break and stepped through the runtime of this statement. It is a large array built from a core data entity (using a fetch statement) - and therefore takes a long time. When I step through the code over the first dozen or so indexes the code runs ok - when i remove the break and let it run it then presents the error.
Is it possible to println() from within the closure statement to assist with debugging? I have tried a number of different syntaxes and cannot get it to work.
Alternatively, is it possible to set an error capture statement within the closure so that the code ceases through a break or an abort() statement?
Fundamentally i am trying to identify the index of the array at the point that the error occurs so that I can get sufficient information to debug the delete function (which is where I think the error is). I do not seem to be able to ascertain the index from the info available to me when the error occurs.
This is the first time I have tried programming in Swift and making use of closures so I am learning as I go. Apologies if I am asking fundamental questions. I have not been able to find a similar question elsewhere here with an answer that works.
You can set an exception breakpoint in Xcode (for an example see here).
Also, I suggest that you move the access to self.projectNumberArray out of the closure:
let pn = self.projectNumberArray[selectedRow]
var arrayOfSelectedRowDetails = self.projectRowDetails.filter(
{ $0.projectNumber == pn }
)
The change might not solve the issue, but it will at least help the debugging.
Lastly, if you want to print the index, the following approach will probably work:
let pn = self.projectNumberArray[selectedRow]
var index = 0
var arrayOfSelectedRowDetails = self.projectRowDetails.filter(
{ println(index++); return $0.projectNumber == pn }
)

Using a loop to assign labels won't work in Actionscript 3. TypeError: Error #1010

I've used this website for many things and found a lot of useful information that has helped me create a randomized quiz mostly. I'm trying to make the code as efficient as possible and that has led me to this error.
I have created an array which uses the .push function to store existing buttons on the stage into the array for future use. The code shown below sets the label of each button correctly.
_buttons[0].label = xmlData.difficulty1.questions[num2].op1.text();
_buttons[1].label = xmlData.difficulty1.questions[num2].op2.text();
_buttons[2].label = xmlData.difficulty1.questions[num2].op3.text();
_buttons[3].label = xmlData.difficulty1.questions[num2].op4.text();
So naturally I wanted to make this a little more efficient and put these in a loop. Based on the logic this SHOULD work but doesn't.
for (var i:Number = 0; i < 4; i++)
{
_buttons[i].label = xmlData.difficulty1.questions[num2].op[i+1].text();
}
This code should simply increment the array counter of _buttons and set the label for each. I mean it's simply the first set of code in a for loop right? However when I run it I get the following error: TypeError: Error #1010: A term is undefined and has no properties.
Now I know for sure that the first set of code works as I have tested it repeatedly but as soon as I decide to put it into that for loop, it fails. Could anyone explain why? Perhaps it's a limitation of the language itself? Maybe I'm missing a command?
Try :
for (var i:Number = 0; i < 4; i++)
{
_buttons[i].label = xmlData.difficulty1.questions[num2]['op'+(i+1)].text();
}
.op[i+1] tries to access a property called 1 under a field called op instead of op1

How to make the program work this way?

So i have a program that does these calculations with numbers. The program is threaded, and the number of threads are specified from the user.
I will give a close example
static void *program_thread(void *thread)
{
bool somevar = true;
if(somevar)
{
work = getwork();
}
dowork(work);
if(condition1 blah blah)
somevar = false; /* disable getwork */
if(condition2)
somevar = true; /* condition was either met or not met, so we request
new work either way */
}
Then with pthreads(and i will skip some code) i do
int main(blah)
{
if (pthread_create(&thr->pth, NULL, program_thread, thread_number)) {
printf("%s","program thread create failed");
return 1;
}
}
Now i will start explaining. The number of threads created are specified from the user, so i do a for loop and create as many threads as i need.
Each thread calls
work = getwork();
Thus getting independant work to do, however the CPU is slow for this kind of job. It tries to compute something by trying 2^32 numbers(which is from 1 to 4 294 967 296)
But my CPU can only do around 3 million numbers per second, and by the time it reaches 4 billion numbers, it's restarted(for new work).
So i then thought of a better method. Instead of each thread getting totally different work, all the threads should get the same work and split the numbers they need to try.
The problem is, that i can't controll what work it get's, so i must fetch
work = getwork();
Before initiating the threads. The question is HOW? Using pthread_create obviously...but then what?
You get more than one way to do it:
split your work package into smaller parts (thus, your getWork returns a new, smaller work)
store your work in a common place, that you access from your thread using a reader-writer pattern
from the pthread API, the 4th parameter is given to your thread, you can do something like the following code :
Work = getWork();
if (pthread_create(&thr->pth, NULL, program_thread, (void*) &work))
...
And your program_thread function would be like that
static void *program_thread(void *pxThread)
{
Work* pWork = (Work*) pxThread;
...
Of course, you need to check the validaty of the pointer and common stuff (in my example, I created it on stack which is most probably a bad idea). Note that your code is givig a thread_number as a pointer, which is usually a bad idea. If you want to have more information transfered to your thread, simply hide it into a structure.
I'm not sure I fully understood your issue, but this could give you some hints most probably. Please note also that when doing multithreading, you need to take into account specific issues like race conditions, concurrent access and more complex lifecycle of objects...

Resources