EntityCollided

Blitz3D Forums/Blitz3D Beginners Area/EntityCollided

Buggy(Posted 2006) [#1]
How do you properly use EntityCollided? I am confused as to what the paramaters are supposed to be.


Stevie G(Posted 2006) [#2]
I don't use the command much but I'm pretty sure this is the correct usage ...

If you set up a scene like so ..

const C_Player = 1
const C_Plane = 2

Player = createsphere()
entitytype Player, C_Player

Plane = createplane()
entitytype Plane , C_Plane
collisions C_Player , C_Plane , 2, 3


Then you would use ...

if entitycollided( Player , C_Plane ) = Plane
  [do stuff]
endif



mindstorms(Posted 2006) [#3]
ususally you want to loop through all of the collisions of an entity, so if it runs into two things the code won't mess up.

for k = 1 to countcollisions(enitity)

  if CollisionEntity(entity,k) = otherentity then 
     ;do whatever you need to do here
  endif
  
  if CollisionEntity(entity,k) = anotherentity then 
      ;do whatever here
  endif
next



I use this to determmine collisions in all of my games, because it lets me do different things for different entities, and dosen't give weird results with multiple collisions.


Buggy(Posted 2006) [#4]
I have tried all of these to no avail.

Why is it that in Paul Gerfen's tutorial, when he demonstrates EntityCollided, he never says
EntityCollided(sphere, CUBE_COL) = blahblahblah

He just says
EntityCollided(sphere, CUBE_COL)

and it works perfectly!

1. I have been told that EntityCollided returns a number and therefore must equal something.

2. I have tried using EntityCollided in every way I can think of (everyone tells me to use it a different way, i.e. "EntityCollided(Goodguy, Goodguy's collision)," "EntityCollided(Goodguy, badguy's collision)," "EntityCollided(Goodguy, badguy) = blahblahblah")) and nothing works - my good guys still run right through their powerups, and bullets still go right through their targets. PLEASE, SOMEONE, TELL ME ONCE AND FOR ALL THE CORRECT WAY TO USE THIS FUNCTION!


Sir Gak(Posted 2006) [#5]
Umm, like this:

entity_that_collided=EntityCollided(entity,type)

where "entity" is what you want to know is being collided with (ie your camera or pivot, or other player character representation) and "type" is what is doing the colliding with you. The "type" here is best illustrated by the following command from the Blitz Help:
EntityType entity,collision_type[,recursive]
Parameters
entity - entity handle
collision_type - collision type of entity. Must be in the range 0-999.
recursive (optional) - true to apply collision type to entity's children. Defaults to false.

Description
Sets the collision type for an entity.

A collision_type value of 0 indicates that no collision checking will occur with that entity. A collision value of 1-999 will mean collision checking will occur.


You have the choice of 1 to 999 for setting types. So, if you decide that bullets are going to be type 1, and doors type 2, walls type 3, enemies type 4, etc, then you can check to see if a collision occurred with any of these, on a per-type basis (ie did a collision occur with a bullet, instead of a wall?). The reason for this variety is that collision checking will have different possibilities via the Collisions command:
Collisions src_type,dest_type,method,response
Parameters
src_type - entity type to be checked for collisions.
dest_type - entity type to be collided with.

method - collision detection method.
1: ellipsoid-to-ellipsoid collisions
2: ellipsoid-to-polygon collisions
3: ellipsoid-to-box collisions

response - what the source entity does when a collision occurs.
1: stop
2: slide1 - full sliding collision
3: slide2 - prevent entities from sliding down slopes


Bullets you may want to come to a full stop when they colide, but if you collide with a wall, you may want to slide.

Finally, the handle that is returned ("entity_that_collided" in my example above) is useful because you won't usually want to know merely that *A* bullet collided, but *WHICH* bullet collided (ie so you can delete it, if nothing else). And, of course, if it's doors you are testing for collision with, then you will want to know *WHICH* door, based on what might lie behind it.
Hope this helps.


Buggy(Posted 2006) [#6]
Question: Can I use Collisions for an entity that doesn't exist yet - like a bullet?

What's wrong with my code then?
For bullet.bullet = Each bullet
		
		entitycollision = EntityCollided(player2\sphere, 3)
		
		If entitycollision > 0
		
			FreeEntity bullet\entity
			Delete bullet
			
			Return
			
		EndIf

Next

By the way, 3 is the bullet's type for collisions.

Also, about mindstorm's method... I don't see how that prevents weird things from happening when 2 things collide at once because Blitz will check one thing at a time, even if you do it the old-fashioned way. Also, since you use n = 1 to CountCollisions(entity), wouldn't that mean that if the player collided with only the wall, CountCollisions would return 1 because the player only hit the wall, but then if a bullet's type is 1 and the wall's type is 3, the player would run into the wall and act like he hit a bullet? I don't see how that method works at all, because it cycles through numbers, but the numbers don't necessarily stand for what the player hit.


Sir Gak(Posted 2006) [#7]
Collisions will set the general parameters of what kind of collision checking are we doing (ie 1: ellipsoid-to-ellipsoid collisions; 2: ellipsoid-to-polygon collisions; 3: ellipsoid-to-box collisions ),

and how to handle such collisions when they occur: (ie 1: stop ; 2: slide1 - full sliding collision ; 3: slide2 - prevent entities from sliding down slopes ).

So, yes, you can set Collisions for an entity that does not yet exist. When you create the entity, you will need to assign to it what type of entity it is (ie bullet=3).

As far as 2 (or more) things colliding at once, collisions are put into a queue (a list). Blitz will automatically set into motion the response that you already assigned via Collisions (ie, stop, slide, etc). Your interest, then, is not how to handle the collision as such, since the Collisions command does that for you, but to determine what else you want to happen as a result of the collision (ie a bullet damages/kills the target entity, etc).

mindstorm's method is good. It allows for the possibility of sorting out what types of collisions occurred (ie collision with an entity of type 1, type 2, type 3, etc.), and allows you to set up what you want to happen on the basis of what KIND of entity you collided with (ie bullet, wall, etc).

Say your player character collides with a wall just as he gets shot with a bullet. The Collisions settings will tell Blitz that, for instance, colliding with the wall will allow you to slide, whereas the bullet hitting will just stop dead in its tracks (heh heh, play on words, dude). Now, regarding the colliding with the wall, say for instance, you don't really want anything special to happen to the player character, but are content to allow him to "slide". However, since a bullet also hit him, now, you have to work on what damage was done. mindstorm's method allows you tp sort through the list of collisions so that you can focus in on the bullet hitting, and have your code do appropriate damage to the player. The code for sorting it all out should look something like this:
For loop=1 to CountCollisions(player_entity)
  which_entity=CollisionEntity (player_entity,loop)
  my_type=GetEntityType (which_entity)
  ;put in code for handling what you want to happen
  ;with entity named which_entity based on which
  ;entity type it is, according to the my_entity that 
  ;was returned from GetEntityType.
Next

So, the logic is as follows:
Step 1:
CountCollisions tells how many collisions there were
(Blitz keeps track of this).
Step 2:
CollisionEntity tells which entity collided.
Step 3:
GetEntityType tells what type entity it was.

Now, you have an identification, not merely that a collision occurred, but which entity did the colliding, and what type entity it is.

Cheers :)


Sledge(Posted 2006) [#8]
Yeah, here's an example of that. It just iterates through the collision list for the blue target and looks at what kind of entity was involved in each collision. If it was the room then the target changes direction; if it was a bullet mesh then the owning instance is indentified (there are undocumented commands that can speed this process up) and it is set to decay while sticking to the target.

It's probably not what you'd do with "bullets" and "targets" in-game (because you'd almost certainly want bullets to interact with the room too) but it does show you how to do different things with the items on a collision list based upon what they are.




Stevie G(Posted 2006) [#9]
Here's something I did a good while back ...

http://www.blitzbasic.com/codearcs/codearcs.php?code=1095

If you take a look at the bullet update function in this ... it'll give you an idea of how it could be done.

One tip would be to always use constants for your collision types ... much more readable ..

Hope this helps.
Stevie


Buggy(Posted 2006) [#10]
Thanks guys. I'm still not sure about EntityCollided, but now I understand mindstorm's method. I had just missed the CollisionEntity line. Thanks again.

Edit: Whoa. I don't know if this is the reason why it wasn't working... well, actually, I know it was the reason why it wasn't working, but I just don't know if it was the only one - I was using player\sphere, when I had actually set player\pivot to do the collisions. And to think, this morning I would have throttled someone if they didn't provide me with a fool-proof solution to my problem!

Well, I guess that wraps it up. God, I'm dumb.


Buggy(Posted 2006) [#11]
Sir Gak, your method is great, but how can I specify which bullet I want deleted after it hits the player? It says, "Variable must be a type" as an error message.

Here's my code:
For collisionnumber = 1 To CountCollisions(player\pivot)
	
		entity = CollisionEntity(player\pivot, collisionnumber)
		
		otherentity = GetEntityType(entity)
		
		Select otherentity
		
			Case 3
			
				FreeEntity bullet\entity
				Delete bullet
				
			Default
			
		End Select
		
	Next			



Stevie G(Posted 2006) [#12]
When you create the bullet store the handle of the type instance in the entityname ...

b.bullet = new bullet
b\Entity = copyentity( bulletmesh?? )
nameentity b\Entity , handle( b )


Then to retreive ...

case 3
   b.bullet = object.bullet( entityname( entity ) )
   freeentity b\entity
   delete b


Stevie


Buggy(Posted 2006) [#13]
Stevie - thanks, but it didn't work because I don't know what "entity" is supposed to represent, and I've never used any of these commands before.


Stevie G(Posted 2006) [#14]
Well, according to YOUR code above ..

entity = CollisionEntity(player\pivot, collisionnumber)


As I mentioned in a post above .. the Tanx game I wrote will give you a good idea of how to handle this.

Stevie


Sledge(Posted 2006) [#15]

Sir Gak, your method is great, but how can I specify which bullet I want deleted after it hits the player?



Stevie - thanks, but it didn't work because I don't know what "entity" is supposed to represent, and I've never used any of these commands before.


My example shows you the longhand ("safe") method, wherein you have to iterate through every bullet instance to find out which one the bullet mesh of the currently considered collision belongs to; Stevie's method cuts that step out by creating a direct link back from each bullet mesh to its owner instance. They are two different ways of getting an answer to the question "which exact instance does this mesh belong to?"


Buggy(Posted 2006) [#16]
Just wondering... could this be not working because my bullet is a sprite?


Buggy(Posted 2006) [#17]
Whew! The code works without using sprites, so I can only assume that sprites cannot collide with anything. Thanks for putting up with me all this time and for the awesome help.

Edit: Actually, the powerups - which were sprites but now are images on scaled-very-thin cubes - work great, but the bullets - using the same method and same code - don't.


Buggy(Posted 2006) [#18]
My bullet/player collisions still don't work! The bullets go right through the player, even though I used the same code that I used for the powerups! Could it be that the bullets are colliding with the player, and not the other way around, or does it not matter?

Please help!


Buggy(Posted 2006) [#19]
It appears that the only time the bullet collisions work is when by a mysterious bug, the player outruns the bullet and hits it. This leads me to believe, as I said above, that there is a difference between the bullets colliding with the player, and the player colliding with the bullets, though it seems stupid to me.


Sledge(Posted 2006) [#20]
Collisions between two moving objects is not really supported that well - ellipsoid-to-ellipsoid can be made to work (see my posted example, above) but notice how the collisions line for the bullets is bullets-to-target not target-to-bullets, even though I only iterate through the target's collision list. If you swap that around (to target-to-bullets) in my example then you will get the same bug, with bullets slipping through the target.

You have a couple of options:
a) Use ellipsoid collision zones to get good collisions between moving objects.

b) Move objecs of each mobile type separately, relative to one another, between multiple updateworlds, and deal with them in isolation. Erm, should work :/

c) Go custom with meshesintersect(). (Potentially slow)

d) Consider if you really need to model the projectyle nature of bullets when a pick might do instead.


Buggy(Posted 2006) [#21]
Sledge, thanks for answering.

1. I've tried ellipsoid collision zones and it still doesn't work because it's target-to-bullets.

2. I'm not quite sure what you're suggesting here.

3. I don't want a major slowdown.

4. I do need to model the projectile nature of bullets because - unlike an FPS - the bullets aren't lightning-quick. They're slow, like bullets in old platformers, and thus allow opponents to dodge.

I think I might try using a For...Each...Next loop to cycle through each bullet and see if it's hit a player, but that's still rather inefficient.


Sledge(Posted 2006) [#22]

I've tried ellipsoid collision zones and it still doesn't work because it's target-to-bullets.


If you can possibly to it the other way around then that looks like the best option.


I'm not quite sure what you're suggesting here.


The problem comes from both parties moving at once, so you could move one party, updateworld and process; then move the other party, updateworld and process... all in one gameloop. That way the in-built collisions system does not have to deal with collisions between two moving objects because one type is always static while the other is moving. There are, however, complexities in managing such a system (bullets would have to be offset while you moved the player, to keep them relatively static, for example) and I would personally do everything to avoid it. But it's an option so I mentioned it for the sake of being complete.


Buggy(Posted 2006) [#23]
Sledge, guess what?! I'm still having friggin' problems with this friggin' code!

I tried:
For bullet.bullet = Each bullet
		
		MoveEntity bullet\entity, 0, 0, -bullet\speed#
		
		For x = 1 To CountCollisions(bullet\entity)
		
			entity = CollisionEntity(bullet\entity, x)
			
			player.player = Object.player(EntityName(entity))
			
				player\health = player\health - 1
			
		Next

And I'm so very close, but it highlights the
player\health = player\health - 1

line, and says "Object does not exist!"

The object does exist, by golly, because I said so! For all of Mark Sibly's godliness, this whole collisions issue really sucks.

Edit: Sledge, what did you use for Ice-Teroids bullets?


Sledge(Posted 2006) [#24]
I never use Object and Handle because they are still undocumented, but maybe Stevie will pop by and give you a definitive verdict on your usage of the commands. I notice in the code posted that you have no Updateworld between moving your bullets and processing collisions - best to move all your bullets, then deal with any collisions afterwards (ie in a separate loop) I think. But yeah, you need Updateworld in there because that is the command that processes all the collisions stuff.


Edit: Sledge, what did you use for Ice-Teroids bullets?


Ice-Teroids uses MeshesIntersect(), slinkily sidestepping any and all collisions issues.


For all of Mark Sibly's godliness, this whole collisions issue really sucks.


It's not so much that it sucks, rather it's geared towards particular things - I mean if you want sliding collision between the player and a static level (and somewhere along the line you generally do) then it's life-savingly brilliant. Given that Blitz3D is a language rather than an engine, the amount of automated collisions stuff you get is really rather sweet; but no, it's not comprehensive and you have to give yourself time to get used to its limitations/foibles. I can only really refer you back to the example I posted, which shows you working collisions between bullets and a moving target - I know having to use spheres is a limitation, but you could use several to construct a more complex collision body if required.

Keep us posted!


Stevie G(Posted 2006) [#25]
I would put in a check before you remove health from the collided entities type instance.

e.g.

If Player <> Null
player\health = player\health - 1
endif

Are all your collidable entities of type player? If they are not then you will need to handle each type serarately.

Are you definately storing the handle in the entityname? We WILL get this working for you ;)

Stevie


Buggy(Posted 2006) [#26]
Stevie, you are a godsend!

I can't believe I'm that STUPID!

I stored the handle in the entityname originally, but then I changed methods so I deleted that line. Then, when I switched back, I forgot all about that vital piece of code. It works great now!

Thanks so much for all of the help, everyone!


Buggy(Posted 2006) [#27]
Whoops. There's a new bug. When someone gets hit with a bullet, it says that "otherentity = GetEntityType(entity)" in the powerup code doesn't work, but getting powerups works fine.


Stevie G(Posted 2006) [#28]
For powerups why not use a simple ...

If entitydistance( Player , powerup ) < 10
[do stuff ]
endif

No need for collisions.

Stevie