Jump to content

Photo

Placeholder tutorial: collisions!


1 reply to this topic

#1 ggn OFFLINE  

ggn

    Stargunner

  • 1,357 posts
  • Location:Athens, Greece

Posted Thu Dec 14, 2017 3:20 AM

I got asked about this via private message and while I think it's a great idea, this is mostly raptor specific and unfortunately I have almost zero knowledge about raptor itself! So I'll just drop some hints here. Your mission, should you choose to accept it, is to take these hints, read the raptor docs, experiment, make some example projects and report back with your findings. Any relevant knowledge to this topic in the replies will be added to this first post here.
 
Generally about collisions: two of the most frequent ways to check for collisions between two objects are: 1) check each pixel of one object with each pixel of the other and see if they match in coordinates, 2) Check the boundaries of an object with the boundaries of the other object, and see if they intersect.
 
The first one gives more accurate results but it takes a lot more time to execute. So usually collisions are handed using method 2, or so called bounding boxes. In a nutshell we wrap the two objects we want to check with boxes - then it's much easier to check if the boxes intersect - just by checking the coordinates of the edges of the boxes will do. This is often a very good compromise, much faster, and allows you to tune the gameplay better.

Looking at the shootbang project we can see a reference to rhit command. Reading the quickref doc we find that:
 

rhit (<source first object>, <source last object>, <target first object>, <target last object>) will return 1 (hit has occurred) if anything within the specified range has collided. This is only a general indication of a collision and further interrogation via the 'was_hit' variable will let you know which object has actually collided with any of the source  objects.  The values of damage variables of the source objects is deducted from the target objects.  raptor can be set to automatically kill an object when its  hitpoint variable  reaches -1 (dead) by setting the object variable 'remhit' to 'cd_remove' (1) The collision check will only work on objects that have their 'colchk' variable set to 'can_hit' (1), objects that are set to 'cant_hit' (-1) will be  skipped.

 
So this tells us that when we call rhit it will check one range of objects with another range of objects for collision. So if we have objects 5-10 defined as bullets and 20-40 defined as enemies, "result=rhit(5,10,20,40)" will check if the bullets hit any enemy objects. However, result will only tell us if at least one collision happened. After we get a collision we'll need to check each suspect's was_hit property to see which one(s) collided. So, to copy/paste and simplify some stuff from shootbang:
 
    IF RHIT(bullet_start_object,bullet_end_object,enemy_start_object,enemy_end_object)=1 THEN
        ' Something was hit, so check each object for fine grained collision
 
        FOR i=bullet_start_object TO bullet_end_object
            IF RGETOBJ(enemy1+i,R_sprite_was_hit)<>-1 THEN     
                'this particular enemy was hit, do something about it!
            ENDIF
        NEXT i
    ENDIF
An important quote from the raptor manual is this: The sprite_was_hit flag needs to be reset before another collision test occurs.

Right, so how do we define the hitboxes? Let's turn to our good "friend", rapinit.s:

R_sprite_coffx: Collision box x offset - pixel distance from centre of sprite
R_sprite_coffy: Collision box y offset - pixel distance from centre of sprite
R_sprite_hbox: Width of collision box in pixels
R_sprite_vbox: Height of collision box in pixels

But why don't we just define the hitbox to be exactly the object's dimensions? Why do we need extra fields for this? Well, imagine if you have an object of 32x32 but your sprite is actually 26x12 and the rest of the pixels are blank. Oops! If you then use a 32x32 hitbox then your object will collide outside the area the viewer perceives as the border of the sprite - not fair! Another example is bullet hell shooters. In that case you will deliberately want to make the hitbox much smaller so your ship actually has a chance of dodging the tens of bullets on screen all coming at you at a breakneck pace.

And to check if a collision happened to this object we have:

R_sprite_was_hit: Did the sprite collide with another? Set to not hit to begin with, used later to flag collisions

Some more advanced stuff:

R_sprite_remhit: What to do if a collision is detected.
R_sprite_bboxlink: Bounding box for collision detect 'single'. Or address of table

Edited by ggn, Fri Jan 5, 2018 12:16 AM.


#2 CyranoJ ONLINE  

CyranoJ

    Quadrunner

  • 5,320 posts
  • RAPTOR in LOCAL
  • Location:Adelaide, SA

Posted Thu Dec 14, 2017 4:13 AM

And if the object is an odd shape, eg, something like T or H, then you can use multiple bounding boxes instead of a single one to mask out areas on the sprite.

 

You can also use the offset values to shift the bounding box off-center of the sprite. A practical example would be a 16x16 pointer arrow, where only the top left would need to 'collide'. You could shift the box -7 (x) and -7 (y) and then make the hitbox 2 pixels wide to cover the corner 4 pixels of the sprite.





Reply to this topic



  


0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users