Help with type instances - yet again. *sigh*

Blitz3D Forums/Blitz3D Beginners Area/Help with type instances - yet again. *sigh*

Irvau(Posted 2015) [#1]
Alright, back again with (yet) another request for help. :|

So, I'm trying to make a little shooter game thingy. As stated in the title, I'm having problems with types. Darn types, they're hard to get a hang of (for me, anyways)... D:

In this case, I'm making enemies to shoot.

To spawn them, I'm using the whole "EnemyPointer.Enemy = New Enemy" deal-io. The enemy type has an entity field that holds the model for the enemy. In order to be able to retrieve the type instance that the entity's associated with, I'm using EntityName() and Handle(EnemyPointer).

As for shooting them, I'm using CameraPick(). In order to detect if it's of the enemy type, I'm using the code found in the last post made by Stevie G in this topic. If it is, then I make it set one of the type instances "IsAlive" variables to false.

Once this variable is false, the update enemies function takes care of the rest. It rolls the entity around until it's flat with the ground - Roll# = 90. Then, it frees the entity from the program.

Well, that's how my game currently is, and I'm having problems with it. The thing is, I spawn in a few enemies, and everything's good. I shoot one, and everything still good. It does it's little rotation thingy and all like it's supposed to. Well, three spawns later, I spawn in another enemy, and this one turns out weird. The enemy spawns spinning, and it won't stop. Even if it "hits the floor" (if Roll# = 90), it still continues to spin. It shouldn't spin, as it hasn't been shot yet, which means "IsAlive" should be true, which means that it shouldn't go through the "if" statement to get to the rotate command. If the enemy is shot, then it sets it's roll back to 0 and replays the whole thing until it reaches 90 degrees, and then it frees the entity. The next spawn is normal, and so are all the other ones, until that designated 4th spawn pops up.

If I spawn multiple enemies, and shoot the last two spawned, then every 3rd and 4th spawn become unlucky, and so on.

This is strange (duh), and I think it *might* have something to do with the handling of the pointer index. However, I'm not too sure.
Help, anyone??

Oh, and hopefully this post is easy to understand. I'm not too sure that it is right now... :/
^_^


Matty(Posted 2015) [#2]
Okay.....if you post a bit of code that would help diagnose the problem.

However....

is it possible that in your spawning routine you forget to set the isalive flag to true?

Are you perhaps parenting the entity to something that is spinning?

Alternatively....perhaps your logic with the 'if' statement is not quite right....

If we see some code then that would make it a little easier....

Hope this is a start...


Floyd(Posted 2015) [#3]
If something is inexplicably spinning then gimbal lock is a possible reason. Be sure pitch never gets close to vertical.

I know the original post said roll rather than pitch. But it's still worth knowing about gimbal lock.


Irvau(Posted 2015) [#4]
Well, gimbal lock isn't the cause here. I set it so that Roll# had to equal 85 in order for the entity to be freed, but it still did the weird thing. :|
Oh, and @Floyd, the rotataion axis doesn't really matter. Heck, just turn the world axis' around a bit and Roll becomes Pitch.

Anyways, here's everything that I have in the code associated with the enemy type:



Aaaaaaaand that should be all of it. I'm pretty sure.


Stevie G(Posted 2015) [#5]
You seem to just be deleting the entity when it's dead, not the type instance with which it is associated? You sure that's all the relevant code? Where is your camerapicking code?

Best to post code which runs (replacing models with primitives as you have done) as it would be easier to see what the problem is.

I find that recycling the type instances is a more efficient way of doing things. Basically create as many instances of the enemy as you'll ever need. When something dies, just hide the entity and set the isalive flag to false. When you spawn a new enemy, instead of creating a new type instance, iterate through the types and find the first one which isn't alive and use that instead. Avoids all the creation and deletion.


Floyd(Posted 2015) [#6]
If EnemyPointer\Roll# = 85 Then FreeEntity(EnemyPointer\Entity)

Another piece of general advice: never depend a floating point variable to have an exact value. Assuming roll starts at 0 and increases in steps of size 1 you would think it eventually hits 85. But that may not be true. It may actually get to something like 85.0001 or 84.99999 and the "=85" test will fail.

So you might test If EnemyPointer\Roll# >= 84.5 ...

Blitz3D unfortunately doesn't have any way to format output for floats. It always rounds the display to six digits. It does the same when converting to a string. This "beautifies" the output, but is misleading. It would display 0.999999999 as 1.0, which may well be what you would rather see. But it makes debugging rather difficult.

Here's an example of small errors and confusing displayed values. x always appears to be 1.0 when it is occasionally 0.99999994, which you could see if enough digits were displayed. Also notice that there are only 8 failures in 100 tests. That's another reason this sort of thing is so baffling. Your code may appear to work because you didn't happen to hit one of the trouble spots.

Graphics 700, 500, 0, 2

x# = 1.0
Print

For n = 1 To 100
	x = 1.0
	x = x / n
	x = x * n  ; In a perfect world x is back where it started, exactly 1.0
	If x <> 1.0
		failures = failures + 1
		Print " n = " + n + "     x = " + x + "     x - 1 = " + (x - 1)    
	End If
Next

Print
Print " Done.    " + failures + " failures."
WaitKey



Matty(Posted 2015) [#7]
That is obviously not the same code to reproduce the problem....for one thing you never call camera pick so picked entity is always going to return the same value....


Irvau(Posted 2015) [#8]
Yeppers, Matty. That's not the original code. Those functions were spread across three bb's. I tried condensing the erroneous code, but it appears that my copying and pasting skills need some work. :/

I tried to make a simpler version that actually works to post here, but I couldn't get the scales right. So, here, sorry for making it hard, but /have the whole project thing/. It isn't too big, shouldn't be much of a problem to look through. I'm pretty sure, anyways.

The main things to focus on are in "Player.bb" and "Entites.bb". The functions to pay attention to *should* be named the same as the ones highlighted above.

And, yes, it is a fan-game thing. :|

Oh, and Floyd, I tried what you said. Guess what? No more weird spawns!! :D Now all I get is a MAV when the enemy's roll equals 85 or so!

EDIT: Removed the link that used to be in between the "/"'s. No need for it anymore, as the problem has been solved already.


Stevie G(Posted 2015) [#9]
You seem to just be deleting the entity when it's dead, not the type instance with which it is associated?


Run it in debug mode and you'll likely get "Entity does not exist".

Try changing this ..

If EnemyPointer\Roll# = 85 Then FreeEntity(EnemyPointer\Entity)


To this ...

If EnemyPointer\Roll# >= 85 Then 
   FreeEntity(EnemyPointer\Entity)
   delete EnemyPointer
Endif



Irvau(Posted 2015) [#10]
Ohhhhhhhhhhhhhhhhhhhhhhhhh...

:D
Thanks Stevie G and Floyd! Those were the two main problems! For one, that integer inconsistency thing. Second, the type instance has to be deleted, because if it isn't, the program will still go through the loop for it even if the entity has been removed. That'll spit out a MAV. So, yeah...

:P

Oh, and thanks also, Stevie G, for that tip on recycling entities. I'll try to use it!

Thanks guys!