Global Types Problem

Blitz3D Forums/Blitz3D Beginners Area/Global Types Problem

Black Hydra(Posted 2004) [#1]
I'm having trouble with one of my global type collections.

It seems that although I create my movement vector type and set it to have a value, that value is turned null when I run it in another function, despite that my type collection is global.

Hopefully someone might be able to see what I'm doing wrong. I'll post the relevant snippets.

Here is the code I'm using for creating the missle which, in turn, establishes the movement vector.

;Set up the basic missle. It will be run in RunAllMissles()
;Add more code if the missle has explosions, arcing, ect.
Missles.Missle = New Missle
Missles = User\Lasers
Missles\X# = User\X#
Missles\Y# = User\Y#
Missles\Z# = User\Z#
Missles\Speed# = User\Speed#
Missles\ObjectNum = CopyEntity(User\Lasers\ObjectNum)
PositionEntity Missles\ObjectNum, Missles\X#, Missles\Y#, Missles\Z#
Missles\Move = New Vector
Missles\Rotation = New Vector
Missles\Move = ScaleVect(User\Rotation, Sync(Missles\Speed#))
;Please note that when I write the vector to my debug log it is displayed normally.

Now for the code where I run the missle, and also where if I try to read any of the X#, Y# or Z# values of the vector it will cause an error claiming the values haven't been initialized:

Function RunAllMissles(Player.Player)
;This will run every missle

For Missles.Missle = Each Missle
If Missles\ObjectNum > 0
If EntityDistance(Missles\ObjectNum, Player\ObjectNum) < 500
;If the missle is still active then run it
X# = Missles\X# ;+ Missles\Move\X#
Y# = Missles\Y# ;+ Missles\Move\Y#
Z# = Missles\Z# ;+ Missles\Move\Z#
PositionEntity Missles\ObjectNum, X#, Y#, Z#
Else
FreeEntity Missles\ObjectNum
Delete Missles
EndIf
EndIf
Next

End Function


So if anyone has any idea what I might be doing that would cause my global type to simply 'lose' its attatched vector for movement I'd be grateful.

Sorry if my problem isn't clear enough. I can post the entire code if you guys need it, although I doubt any of you want to sift through 300 lines of code...


JKP(Posted 2004) [#2]
Looked at the code briefly and noticed that you assigned have a new Vector to the Move field but then assigned the same field with the output of a function. If your function does not return a Vector type then this could be the problem. At any rate, it is probably creating an unused type.


Black Hydra(Posted 2004) [#3]
ScaleVect() is a function I have that multiplies a vector by a scalar and returns the coresponding vector.

It isn't the problem as it and all my other vector library functions work fine in the other sections of my code.

What I am confused about is if by having a nested type the 'nested' type becomes local accidentally? Or perhaps I am required to do something that I am forgetting.

I run through the missles type collection using a For Each loop. I don't know whether this has anything to do with how I am using that loop. I'm not that experienced with regards to using types so I don't know whether I'm following bad programming practices that would cause this.

I have no idea why my vector is being turned into a null one.


RiverRatt(Posted 2004) [#4]
I think the problem may be with Missles\X# = User\X#,ect...
Whenever I try to asign one type value to another I get
entity must be a type. Mabye asign a variable to User\X# where it is updated like user_x#=User\X#?


Black Hydra(Posted 2004) [#5]
No, that isn't it. The position of the missles is fine. Its just the movement vector isn't copying over, so the missles stay in one place after I've shot them, that is if I comment out the movement code, as with the code in it crashes saying that the movement vector doesn't exist.

Also, when adding in an intialized flag, it seems that none of the missles have been 'initialized' at all! So it is as if the missles type collection doesn't appear to exist for the purposes of the RunAllMissles function, however in the main loop of my program and the function that created the missles it appears normally. But as soon as I try accessing the function in the RunAllMissles it is basically telling me that there is nothing there... Ugh!


Black Hydra(Posted 2004) [#6]
Okay I've done a little more testing. Apparently there isn't a global problem, or function problem.

It now appears that the missles simply aren't being saved at all after they are created. I'm stuck. I now have no idea where the problems are in my code so I'll post all of it. If someone has any clue what I'm screwing up I'd be eternally grateful.

;Include the vector mathematics library
Include "vector.bb"
;Include the blitz basic demo start code
Include "start.bb"

;Setup all non-type global variables
Global CameraHandle = 0
Global ScreenWidth = 640
Global ScreenHeight = 480
;Friction will be used to slow the ship. 1 is no friction, 0 is absolute friction
Global Friction# = .5
;Default Sync
Global SyncRate# = 100
Global Missles.Missle
;--------------------------------
;---------MAIN PROGRAM-----------
;--------------------------------
GameEnds = 0
User.Player = SetupGame()
Repeat
StartSync# = MilliSecs()
;===========

ControlPlayer(User)
UpdateCamera()
;===========

;Use a counter as AI modifications aren't necessary every loop
AICounter = AICounter+1
If AICounter > 5
AICounter = 0
RunAllAI()
EndIf
;The AI is modified every 5 loops. Enemies are controlled every loop, however.
RunAllEnemies()

;===========

RunAllMissles(User)
RunAllExplosions()

;===========

GameEnds = Triggers()

;===========
UpdateWorld
RenderWorld
Flip
;===========
SetSync(StartSync#)
Until GameEnds Or KeyHit(1)
End
;--------------------------------
;================================
;--------------------------------

;TYPES
;Player Type
Type Player
Field X# ;x position
Field Y# ;y position
Field Z# ;z position
Field Move.Vector = New Vector ;vector controlling movement
Field Rotation.Vector = New Vector ;vector controlling current rotation
Field Thrust.Vector = New Vector ;vector controlling the thrusting
Field Manuever# ;regulates the factor by which the object can pivot
Field Speed# ;regulates speed by using this as a maximum value
Field Health ;the players health
Field ObjectNum ;the object number
Field BrushNum ;the brush number holding texture and data
Field AttackReflex ;controls time since last attacking
Field StunReflex ;controls time since recovering from an attack
Field Lasers.Missle = New Missle
End Type

;Enemy Type
Type Enemy
Field X# ;x position
Field Y# ;y position
Field Z# ;z position
Field Move.Vector = New Vector ;vector controlling movement
Field Rotation.Vector = New Vector ;vector controlling current rotation
Field Impulse.Vector = New Vector ;vector controlling AI impulse behavior
Field Speed# ;regulates speed by using this as a maximum value
Field Manuever# ;regulates the factor by which the object can pivot
Field Health ;the enemy's health
Field ObjectNum ;the object number
Field BrushNum ;the brush number holding texture and data
Field AttackReflex ;controls time since last attacking
Field StunReflex ;controls time since recovering from an attack
Field Species ;used to regulate what type of AI actions to take
; 0 = Red (swarming) :: 1 = Blue (sneaker) :: 2 = Green (missler)
Field Projectile.Missle = New Missle ;stores the type of projectile the object uses
Field AI ;This value is used to determine what action the enemy performed
End Type

;Missle Type
;A type used to represent projectile fire
Type Missle
Field X# ;x position
Field Y# ;y position
Field Z# ;z position
Field Move.Vector = New Vector ;vector controlling movement
Field Rotation.Vector = New Vector ;vector controlling rotation (arcing projectile)
Field Speed# ;controls the speed of the missle
Field Maneuverability# ;controls the pivoting capabilities of arcing projectiles
Field ObjectNum ;stores the object number of the projectile
Field BrushNum ;stores the brush number (or texture number) of the projectile
Field Detonate.Explosion = New Explosion ;stores the explosion type of the projectile on impact
Field Damage ;controls the power of the missle
Field Effect ;controls the effect of the missle
Field Reflex ;controls the time since firing the missle
Field Species ;used to regulate what type of movement the missle follows
Field Initialized ;Flag storing whether the missle has been initialized or not
End Type

;Explosion Type
Type Explosion
Field X# ;x position
Field Y# ;y position
Field Z# ;z position
Field Damage ;controls the damage of the explosion
Field Size# ;controls the maximum size of the explosion,speed and duration
Field ObjectNum ;stores the object number of the explosion
Field BrushNum ;stores the brush number of the explosion
Field SoundHandle ;stores the sound handle of the explosion
Field Effect ;controls the effect of the explosion
End Type

;Functions
Function ControlPlayer(User.Player)
;This function acts upon the user input and applies the appropriate
;action
;INPUT
Firing = 0
Thrusting = 0
Strafe = 0
MoveMouse ScreenWidth/2, ScreenHeight/2
If KeyDown(57) Then Firing = 1
If MouseDown(1) Then Thrusting = 1
If MouseDown(2) Then Strafe = 1
;Fire lasers
If Firing = 1 And MilliSecs()-User\AttackReflex > 500
User\AttackReflex = MilliSecs()
;Set up the basic missle. It will be run in RunAllMissles()
;Add more code if the missle has explosions, arcing, ect.
Missles.Missle = New Missle
Missles = User\Lasers
Missles\X# = User\X#
Missles\Y# = User\Y#
Missles\Z# = User\Z#
Missles\Speed# = User\Lasers\Speed#
Missles\ObjectNum = CopyEntity(User\Lasers\ObjectNum)
PositionEntity Missles\ObjectNum, Missles\X#, Missles\Y#, Missles\Z#
Missles\Move = New Vector
Missles\Rotation = New Vector
Missles\Move = ScaleVect(User\Rotation, Sync(Missles\Speed#))
Missles\Initialized = 1
EndIf
;Apply Rotation
If Not Strafe
M# = User\Manuever
;Movement style using mouse speed rather than position
YAng# = WrapAngle(EntityYaw(User\ObjectNum)-M#*MouseXSpeed())
XAng# = WrapAngle(EntityPitch(User\ObjectNum)+M#*MouseYSpeed())
If XAng# > 70 And XAng# < 180 Then XAng# = 70
If XAng# < 290 And XAng# > 180 Then XAng# = 290
RotateEntity User\ObjectNum, XAng#, YAng#, 0
;Set the rotation vector to the current orientation
User\Rotation = AngToVect(WrapAngle(YAng#-90), XAng#)
EndIf

;Add to Thrust Vectors
If Thrusting
If Strafe
;If the player has strafing engines on the thrust vectors will lie perpendicular to the rotation

Else
;For normal movement the thrust vector is simply a magnitude of the rotation vector
User\Thrust = User\Rotation
User\Thrust = ScaleVect(User\Thrust, (Sync(User\Speed#)-VectLength(User\Move))*.025)
EndIf
EndIf

;Calculate and reposition movement
User\Move = ScaleVect(User\Move, 1.0-Sync(Friction#))
;Stop ship if it is moving too slowly
If VectLength(User\Move) < 3*Sync(Friction#) Then User\Move = ScaleVect(User\Move, 0)
User\Move = AddVect(User\Move, User\Thrust)
User\Thrust\X# = 0
User\Thrust\Y# = 0
User\Thrust\Z# = 0
User\X# = User\X# + User\Move\X#
User\Y# = User\Y# + User\Move\Y#
User\Z# = User\Z# + User\Move\Z#
PositionEntity User\ObjectNum, User\X#, User\Y#, User\Z#
;Update Camera
PointEntity CameraHandle, User\ObjectNum
End Function

Function UpdateCamera()
;This function updates the camera


End Function

Function EnemyAI(AI.Enemy)
;This function will be run to determine what the enemies will do
;It will send the result to the ControlEnemy() function

End Function

Function ControlEnemy(Num.Enemy)
;This will control physics for the enemy based on their AI reaction

End Function

Function ControlExplosion(Num.Explosion)
;This will run a specified explosion

End Function

Function RunAllAI()
;This will run all of the specified AI's

End Function

Function RunAllEnemies()
;This will run all of the enemies

End Function

Function RunAllMissles(User.Player)
;This will run every missle

For Missles.Missle = Each Missle
If Missles\ObjectNum > 0 And Missles\Initialized = 1
If EntityDistance(Missles\ObjectNum, User\ObjectNum) < 500
;If the missle is still active then run it
X# = Missles\X# + Missles\Move\X#
Y# = Missles\Y# + Missles\Move\Y#
Z# = Missles\Z# + Missles\Move\Z#
PositionEntity Missles\ObjectNum, X#, Y#, Z#
Else
FreeEntity Missles\ObjectNum
Delete Missles
EndIf
EndIf
Next

End Function

Function RunAllExplosions()
;This will run every explosion

End Function

Function Triggers()
;This function basically checks to see whether the player has reached the goal
;and to see whether the player has died.
;It may serve as a simple template for other triggers in the full version

End Function

Function SetupGame.Player()
;This function sets up the game it is used as a more primitive function which
;will later be used for more advanced world loading commands
;Set up the player object
SeedRnd(MilliSecs())
User.Player = New Player
User\Move = ScaleVect(AngToVect(0, 0), 0)
User\Thrust = ScaleVect(AngToVect(0, 0), 0)
User\Rotation = ScaleVect(AngToVect(0, 0), 1)
User\Health = 6
User\ObjectNum = LoadMesh("spaceship.x")
User\BrushNum = LoadBrush("spaceship.bmp")
PaintEntity User\ObjectNum, User\BrushNum
User\AttackReflex = MilliSecs()
User\StunReflex = MilliSecs()
User\Speed# = 60.0
User\Manuever# = .5
User\Lasers = New Missle
User\Lasers\ObjectNum = LoadSprite("big_spark.bmp")
HideEntity User\Lasers\ObjectNum
User\Lasers\Speed# = 80.0
;Setup Camera stuff
CameraHandle = CreateCamera(User\ObjectNum)
PositionEntity CameraHandle, 0, 0, -30
PointEntity CameraHandle, User\ObjectNum
;Set up some cubes for spacial orientation
For X = 1 To 100
Num = CreateCube()
PositionEntity Num, Rand(300), Rand(300), Rand(300)
Next
Return User
End Function

;////////Sync Functions/////////

Function Sync#(Value#)
;This function will sync a value based on the syncrate
Return Value#/SyncRate#
End Function

Function SetSync(StartSync)
;This will set up the SyncRate values and smooth them with the last sync value
;to prevent jerkiness
If MilliSecs()-StartSync > 1
SyncRate# = (SyncRate#*.5)+((1000.0/(MilliSecs()-StartSync))*.5)
Else
SyncRate# = 1000.0
EndIf
End Function


soja(Posted 2004) [#7]
Show us your ScaleVect function, please.

<EDIT>
Wow, I speak and you obey... 45 seconds earlier! =D
(Ok, ok, you didn't post the ScaleVect function, but you posted enough code that I think I know what the problem is.)

Look here:
;Set up the basic missle. It will be run in RunAllMissles()
;Add more code if the missle has explosions, arcing, ect.
Missles.Missle = New Missle
Missles = User\Lasers
Missles\X# = User\X#
Missles\Y# = User\Y#
Missles\Z# = User\Z#
Missles\Speed# = User\Lasers\Speed#
Missles\ObjectNum = CopyEntity(User\Lasers\ObjectNum)
PositionEntity Missles\ObjectNum, Missles\X#, Missles\Y#, Missles\Z#
Missles\Move = New Vector
Missles\Rotation = New Vector
...

Here you create a new Missle and assign a pointer called Missles to it. But then you assign Missles to the same Missle that User\Lasers points to... and you forget about the one you just Newed! Then you go about "initializing" everything in the old object, replacing the old values that were in User\Lasers. So you end up with a ton of empty Missle objects with un-initialized Vectors and such.

That's what I see anyway. What you should do is put in a debugging function that prints out the values of all your type objects, so you'll always know how many there are and which ones are valid if you have a question.

Also, you don't need to put "New <type>" within your Field declaration. I don't think it does anything at all, but it can be misleading.

One more thing. Not that it matters in your program, but it's spelled "missile". Just in case you write some in-game help text for the user or something.


Black Hydra(Posted 2004) [#8]
I think my problem must be with my understanding of how type structures work.

So your saying that by having the code

Missles = User\Lasers

That I am not making all the data from User\Lasers into my 'newed' missle (figure I might as well be consistant with spelling at this point ;) ) but actually having everything I now assign to missles simply be assigned to User\Lasers?

I'm really confused now. What I wanted was to have the new missles object use all the stuff from user\lasers so that it can use that as a default. And then modify that.

So in essence when I use the New command I am not creating a new object but a new pointer that points to an object? And that when I use code like Missle = User\Laser I am simply moving the pointer to User\Laser not copying over all the data from User\Laser into the new object in Missle?

Would I have to move every variable individually in order to move the contents from one object into another?

Sorry, I'm fairly new at this...


soja(Posted 2004) [#9]
So your saying that by having the code

Missles = User\Lasers

That I am not making all the data from User\Lasers into my 'newed' missle (figure I might as well be consistant with spelling at this point ;) ) but actually having everything I now assign to missles simply be assigned to User\Lasers?

That's correct, because Missles points to the same object as User\Lasers ("Missles = User\Lasers"). You are copying the address to the object, not the object.

So in essence when I use the New command I am not creating a new object but a new pointer that points to an object?

No, that statement is backwards. Whenever you use New, you are creating a new object. However, whenever you use =, you are creating a new variable (or changing an already-initialized one) that points to that object. (For example, in "car1.automobile = New automobile", "car1" is a 32-bit Blitz pointer that points to the actual automobile data object that you just Newed. You can change car1 anytime, or assign another variable to it, ala "car2.automobile = car1".)

And that when I use code like Missle = User\Laser I am simply moving the pointer to User\Laser not copying over all the data from User\Laser into the new object in Missle?

Almost! You are creating a second pointer that points to the same object. Correct, you are not copying the data from User\Laser into the new object.
Would I have to move every variable individually in order to move the contents from one object into another?

Exactly. (Except "copy" would be the better term, instead of move.)
Sorry, I'm fairly new at this...
Don't apologize; you're just like anybody else.


I guess the things to remember are:
1) Whenever you use New, you are creating a new data object from your custom type blueprint. It gets added to the end of the linked list of objects of that type.
2) The only way to reference a type object that you have created are through First <objecttype>, Last <objecttype>, Before <objectptr>, After <objectptr>, <objectptr> = Each <objecttype>, or <objectptr>
2) You can have any number of pointers pointing to any object of their type, or to no object at all. They can change, too.
3) To copy object data, you must copy each field individually.


Black Hydra(Posted 2004) [#10]
Okay I found a major flaw in my vector libraries. While not the source of my current problem, it seems I was using the New statement on all of my vector calls... while it tooks some reworking, now none of my vector math functions actually create any new vectors. Which is good because I assume that would probably bog things down if I had thousands if not millions of vector objects lying around...