Moving data between types

BlitzPlus Forums/BlitzPlus Programming/Moving data between types

bloos_magoos(Posted 2013) [#1]
each type has its own fields.

These variables are specific to that type itself, and can't be used anywhere else except between the for blah.blah = each blah loop and when you are initializing the variables.

I have my tricky ways to move data between types, but I feel like there is a better way to do it. My current issue is...

What is the best way to check if one object has collided with another?

I can't really do the whole if imagescollide thing, because they are there own types and their x, y and images are of their own type.

What is the best way to go about this?


Midimaster(Posted 2013) [#2]
If you design a variable GLOBAL you can use its field also outside the FOR/EACH loop:


Type Enemy
    Field No%, X%, Y%
End Type


Global Hulk.Enemy=New Enemy

BlaBla

WaitKey()

Function BlaBla()
    Print Hulk\X
End Function


You can also swap this extern type member:

Type Enemy
    Field No%, X%, Y%
End Type


Global Hulk.Enemy

For i%=0 To 9
     loc.Enemy =New Enemy
     loc\X=i*100
     loc\Y=Rnd(99)
     loc\No=i
Next

BlaBla
Print Hulk\X

WaitKey()

Function BlaBla()
    For  loc.Enemy =Each Enemy
          If loc\No=5
               Hulk=loc
         EndIf
    Next
End Function



Yasha(Posted 2013) [#3]
There's no particular requirement that the variable be global, only that it be any valid variable other than the one controlling the For loop. A loop only automatically increments its controlling variable; anything you put anywhere else will stay where it is. (You should avoid using globals unless you actually need global access to a variable name: in Midimaster's example the value should just be returned by the function, since that's all that the global is actually being used for)

You can also put objects straight into variable slots - either local, bank, array, or fields of other objects - as soon as they're created, and not need to loop over them with For at all unless you actually want to loop over the whole list.

Once you have a valid variable containing an object, the fields can be used for any purpose and modified at any time.

So:

Local a.Thing = GetThing()
Local b.Thing = GetThing()

Local dist# = Sqr((a\x - b\x)^2 + (a\y - b\y)^2)
If dist < a\radius Or dist < b\radius Then HandleThingCollision a, b


...is valid, if not especially illuminating.


bloos_magoos(Posted 2013) [#4]
ALright so we're getting somewhere here. My next question is, say I wanted to spawn a new instance of that type somewhere outside the main program, like for example if you press space it'll spawn an enemy or something. Then I wanted to check image collision with another type, the player. What's the best way to do that? I tried declaring the type as global and then creating a new instance in my while wend loop. However, this doesn't work because I get an error or my program crashes.


Yasha(Posted 2013) [#5]
By itself that sounds more or less like a normal way to do things. Perhaps you could post some of your particular code?

I don't know if this is on the right track, but remember that the type of a variable or value only affects what you can do with the whole variable or value; it doesn't place restrictions on what you use its component fields (if any) for - their own type does. So a player, that is an instace of PlayerType, and a bot, that is an instance of EnemyType, can't both be indiscriminately passed to the same comparison function (checking player/player, bot/bot, or player/bot without specifying) - but they can both contain e.g. an image field, and you can check collisions on the image without worrying about what the type of its owner is.

e.g.
Local p.Player = ..., e.Enemy = ...

If ImagesCollide(p\img, p\x, p\y, 0, e\image, e\xpos, e\ypos, 0) Then ...


Using different field names just to visually reinforce that the result of the expression carries no information about how it was obtained: an image is an image regardless of whether it was extracted from a field named img in an object of one type or a field named image in an object of another type.

You could also factor out the common elements into a component type (e.g. "Movable"), that both bots and players might "own" instances of - that way you can just compare two Movables without needing to think about what they actually control. (This is a bit more complicated to implement.) Useful if you want to also have bots colliding with other bots, players hunting both players and bots, etc.


Midimaster(Posted 2013) [#6]
normally you have one player, but a lot of enemies.

Type TPlayer
     Field X%, Y%, Img%
End Type


Type TEnemy
     Field X%, Y%, Img%
End Type

Global Player.TPlayer= New TPlayer

For i%=0 to 9
     Enemy.TEnemy= New TEnemy
Next    



Function CheckAllCollisions()
     For loc.TEnemy =Each TEnemy
          If ImagesCollide(Player\Img, Player\x, Player\y, 0, loc\Img, loc\x , loc\y, 0)
                 Delete loc
          Endif
     Next
End


It is not necessary, that the player is GLOBAL, but it is more easy to understand for beginners....


bloos_magoos(Posted 2013) [#7]
Well basically how i did things was

Type player
field x,y,image
end type

type enemy
field x,y,image
end type

player.player= new player
player\x=100
player\y=100
player\image=loadimage("blfsdjklfaskd.png")

enemy.enemy=new enemy
enemy\x=200
enemy\y=200
enemy\image=loadimage("jkldsfjlkjadf.png")

while not keyhit(1)
cls

for player.player = each player
drawimage player\image,player\x,player\y
player\x=player\x+rnd(-2,2)
next

for enemy.enemy = each enemy
drawimage enemy\image,enemy\x,enemy\y
enemy\y=enemy\y+rnd(-2,2)
next

flip
wend


NOW

That is an extremely and simplified (and pointless) version of what I have so far (if i pasted what I really have it'd be a jumbled mess lol)

SO for my example, what would be the best way to go about checking if the player\image collides with the enemy\image?

I understand that the image handle kinda doesn't even matter, for some reason lol. It's just the x and y for each that I need to check against each other, which raises problems because they are in separate objects and in separate for loops.

How I'd normally go about this is to simply declare a variable and name it like enemyx, and then one for enemyy, then for each iteration of the for next loop I'd make the enemy\x = enemyx, so that I can just check against that variable, not against the field of the enemy.

Thanks a lot for helping though guys


Yasha(Posted 2013) [#8]
raises problems because they are in ... separate for loops


Simplest solution: try nesting your loops:

for player.player = each player
    for enemy.enemy = each enemy
        CheckCollision player\x, player\y, enemy\x, enemy\y     ;(however you do this)
    next
next


So it loops over each player, and on each iteration checks every enemy against it.

This method doesn't scale well (imagine: if you had a thousand of each, that's only two thousand things to draw on screen - not so bad - but a million collision checks), but it should be fine for say fewer than ten players and a couple of hundred enemies. For very large numbers of things you'd use a more complex approach, but no sense in getting complicated until you need it.


Note also that you don't need to combine drawing and collision checking in the same section of code (in fact, it's a good idea to keep them separate). You should use non-nested loops for the drawing, or you'll end up with a lot of redundant overdraw.