Is it possible to make two or more hitboxes for one object?

Discussion in 'Programming' started by HAEGOE, Jul 12, 2016.

Tags:
  1. HAEGOE

    HAEGOE Member

    Joined:
    Jun 25, 2016
    Posts:
    38
    [​IMG]
    (the example is Billy Kane from KOF 2002)
    Like this. The red rectangle is attack box and blue ones are hurt boxes.

    Because all I've seen and made had one single hitbox per character, I don't know if that's possible.
    Since this is for fighting game I'm planning, I need to know how to do these :
    - Same image, same hitboxes
    - Different image, different hitboxes
    - I can see all the hitboxes under certain condition(debug mode or something like that)
    - all hitboxes have to be changed when image changes
    - If any of P1's hurt box collides with P2's attack box, The script that makes P1 hurt must be activated and vice versa.
     
  2. Aura

    Aura Guest

  3. Yal

    Yal GMC Memer GMC Elder

    Joined:
    Jun 20, 2016
    Posts:
    3,556
    Don't listen to Aura. The default collision system only allows objects to have one collision mask at a time.

    First of all, you don't need to use boxes per se for your collision masks, you can use the whole sprite ("precise" instead of "rectangle"). It's a bit processing-intensive, but for a fighting game there should only be a handful of objects to check for collisions at a time, so this wouldn't be a big issue, and it would be really easy to implement. You can also combine "precise" and an user defined bounding box to cut off parts of the sprite for the collision mask, e.g. make the hurtbox not extend all the way down a punching hand.

    Another idea is to have 'hurtbox' objects that are spawned with a temporary lifetime and refreshed by their corresponding player, using an 1x1 pixel sprite mask but stretched using image_xscale and image_yscale to be the right size.
     
    SwiftElk likes this.
  4. stainedofmind

    stainedofmind Member

    Joined:
    Jun 20, 2016
    Posts:
    701
    I wouldn't write off mask_index right off hand. @Yal is correct that the default collisions will only realistically allow you to use one mask effectively, however, it is still a viable method if you're controlling collisions yourself. For example, I was previously working on a Castevania 2 remake/sequal/inspired-by game, where in, terrain collision uses a mask that is much larger then enemy collision. A rough example if the code I used was thus:

    Code:
    mask_index = spr_terrain_mask;  // Terrain mask would be a sprite with a mask size of roughly 16 x 24
    
    if (instance_place(x + vsp, y + hsp, obj_solid))
    {
        hsp = 0;
        vsp = 0;
    }
    else
    {
        x += hsp;
        y += vsp;
    }
    
    mask_index = spr_damage_mask; // Damage mask would be a sprite with a mask size of roughly 8 x 24, or whatever.
    
    is_damaged = instance_place(x, y, obj_hazard);
    
    if (is_damage)
    {
        player_damage(1);
    }
    
    mask_index = spr_terrain_mask; // Reset back to the 'default' mask, just incase.
    
    ... Of course, this is a HORRIBLE way to do both movement and damage, but it's just an example, so :p
     
    Phil Strahl likes this.
  5. icuurd12b42

    icuurd12b42 TMC Founder GMC Elder

    Joined:
    Apr 22, 2016
    Posts:
    1,837
    >>Of course, this is a HORRIBLE way to do both movement and damage

    No it's not horrible...

    the first check should be don on the overall sprite either via the collision event of by code

    //In step code
    if (instance_place(x, y, obj_something))
    {
    mask_index = head_spr;
    if (instance_place(x, y, obj_something))
    {
    //blah
    }
    mask_index = arm_spr;
    if (instance_place(x, y, obj_something))
    {
    //blah
    }
    mask_index = legs_spr;
    if (instance_place(x, y, obj_something))
    {
    //blah
    }
    mask_index = -1;
    }

    //in collision event
    mask_index = head_spr;
    if (instance_place(x, y, other.id))
    {
    //blah
    }
    mask_index = arm_spr;
    if (instance_place(x, y, other.id))
    {
    //blah
    }
    mask_index = legs_spr;
    if (instance_place(x, y, other.id))
    {
    //blah
    }
    mask_index = -1;
     
  6. stainedofmind

    stainedofmind Member

    Joined:
    Jun 20, 2016
    Posts:
    701
    @icuurd12b42, I didn't mean the mask swapping being horrible, rather the off the cusp code I provided for movement. The damage code is actually fine now that I think about it.
     
  7. Didjargo

    Didjargo Member

    Joined:
    Jun 21, 2016
    Posts:
    46
    I suggest that you use "Precise Collision Checking" and "Separate Collision Marks" on the character sprites for the hurt boxes. This would actually serve better since the hurt area would be accurate down to the pixel and change with each frame. As for the attack boxes, I find the best way would be to make a separate sprite called "attack_frames_spr" that has all of the same frame numbers and measurements of the character spirte, only all of the frames are blank expect when the character sprite frame has an attack. And the image on the attack_frames_spr would only be the character's fist or weapon (the area that damages the opponent). This sprite should also be set to precise collision checking and separate collision marks.

    make an object for the character (let's call it player_obj), and make an object for their attack range (attack_obj). With the attack_obj, set the sprite to the attack_frames_spr and uncheck the box marked "visible"

    Place the player_obj in the room and in its creation code, write
    with instance_create(x,y,attack_obj)
    master = other.id

    and in the attack_obj's "End step" code, you would write
    image_index = master.image_index
    x = master.x
    y = master.y

    What this all means is that when the game starts, the player_obj will create an attack_obj, and the attack_obj will have the player_obj that spawned it assigned as its "master". to which it will mimic its master's X Y coordinates and it's frame. Whenever the player_obj enters an animation frame with an attack, the attack_obj will enter its own frame with something drawn on it which includes a collision area. Then all you have to do is write the appropriate code for when the player_obj collides with an attack_obj and vise versa. Also, when you write the code for a player_obj colliding with an attack_obj, be sure to first write "if other.id != master" This will prevent the player_obj from getting hurt from its own attack_obj.
     
    DaMuffin likes this.
  8. Aura

    Aura Guest

    Yal pls. I didn't say anything about it allowing two collision masks at a time. What I was talking about is using it to the change the mask depending on the circumstamces. For instance, when it is not attacking, you'd keep it at the regular "hurt" mask. But when it is attacking, you'd switch to the "attack" mask. It's difficult to get it working, but it's not impossible.
     
    Seabass (The Human) likes this.
  9. Paolo Mazzon

    Paolo Mazzon Guest

    It's really not that difficult to implement.
    1. Write a set of scripts that hold rectangle hitboxes (eg; weaponHitBox = createHitbox(x1, y1, x2, y2))
    2. Give both characters an attack hitboxe and a list of hurt hitboxes
    3. Make a script that checks if two given hitboxes are touching using rectangle_in_rectangle
    4. When you attack, check for collisions between all of the other person's hurt boxes and whatever attack hitbox you choose to use
    Since there is only going to be 2 maybe 4 characters, that really wouldn't tax the cpu too bad.
     
  10. kburkhart84

    kburkhart84 Firehammer Games

    Joined:
    Jun 26, 2016
    Posts:
    465
    I think the easiest way to do this is to have separate objects that do the "attack" collisions. Your character would probably use a rectangle for collisions normally in order to keep things smooth(as is taught in platforming tutorials). You can take the exact frames of animation for the attack, and quickly brush out(draw) the parts that would do the attack, and make that a separate sprite, but the same size and origin as the character. You would do this for each attack. Then, when the character does that attack, you spawn an object that uses that drawn out collider sprite(invisible but collideable, maybe drawn in debug mode). Then the characters can test collision for those objects only. The object would need to destroy itself upon finishing the animation. You could likely use a single object that just picks a different sprite based on the attack, and when it is created it would have a variable set(by the character object) that determines the strength of the attach.

    I would keep one object for this, and each character would have "attack" sprites. The sprites would all be separate, and only a few frames depending on how long the attack lasts.

    About creating the sprites for the attacks, you could easily do it with GMStudio's sprite editor. I would duplicate the sprite for the attack first. You might need to cut out frames that are part of the animation but not part of the actual collision portions of the attack, though how you manage that depends on where you create the object. If you do it right at the beginning of the attach, you won't be able to cut out the first frames because you need it to sync up, though the last frames you could cut out while the (example) fighter's fist is coming back, as that part would no longer do any damage. Then, you could easily use whatever drawing tools you like, squares, flood fills, whatever, for each frame of animation, making everything else transparent/empty, but the fist/staff/whatever be the same. You could also make those things any color you want(for debug purposes), but whatever parts that should collide need to be something, while the parts that don't should be transparent.

    Last detail I mention, the sprites for this would need to use pixel perfect collision with this method. Normally we frown on pixel perfect collision, not only due to performance, but because it can make things jittery if you use it form locomotion in platformers, etc... But for this purpose, you need it for accuracy, and since it isn't actually being used for movement at any time, it won't create jitter. You are only using it to confirm collisions for attacks, and you likely only have a few characters going at a time, so performance isn't an issue. In fact, with modern computers, I would honestly say even with more extreme situations the performance is probably fine, though depending on your target PC specs you would want to do some tests before going ahead with it if you DO want extreme situations, especially if you are considering mobile or HTML5 exports.
     
  11. HAEGOE

    HAEGOE Member

    Joined:
    Jun 25, 2016
    Posts:
    38
    So, you're saying that I'll have to use more than two objects? oh well. At least I know what you're saying about sprites for attack hitboxes.
    Pixel perfect part is not what I'm most worried about, since end step can come in handy. the real problem that I think I'll face is that how to make sure both the characters will be hit by the object that is based on their x and y coordinates that is set at the end step. As I know the hit detector will have to go lower that character and hitbox objects in objects list, but I'm not sure if that's right or not.

    That code looks convenient since it can also tell whether one box is completely or partially collides with other, but characters's sprite_index and image_index will fluctuate, and some sprites will have more than 3 hurtboxes.. I'm not sure.
     
  12. TheouAegis

    TheouAegis Member

    Joined:
    Jul 3, 2016
    Posts:
    6,777
    Where did you get that image of Billy with the attack box and hurt boxes overlaid like that?

    Actually I just googled it. Not sure what your source was, but I found a similar picture. And now that I think about it, it kinda does make sense that his hurt box spanned his arms when attacking, because sometimes it seemed really stupid when I'd take damage from something that barely touched me.

    That said, the fact that the hit boxes are always rectangular tells me that it's just as Padio said - you have a database of all the hit boxes for each frame of animation.

    Pretty sure that's how SNK would have done it, too.
     
  13. kburkhart84

    kburkhart84 Firehammer Games

    Joined:
    Jun 26, 2016
    Posts:
    465
    I'm not saying you HAVE to have multiple objects, rather I'm saying that it can be convenient due to the way GMStudio operates to do so. If this were any engine that has objects with a hierarchy system( like Unity for example) where an object can hold several componenets and have child objects(not parent/child like in GMStudio), then I would suggest doing it with that system. And in any case, you can still do it with a single object, that when near the other object, compares hitboxes with hurtboxes. I just find it more convenient seeming to use separate objects, and it could be easier to make changes that way as well, especially if you use just one object with variables to represent all hitboxes and just create instances of it, instead of a bunch of different objects.
     
  14. Paolo Mazzon

    Paolo Mazzon Guest

    Again, not too difficult. You know before the game starts what every possible attack is. You could have something like 3 attacks: a kick, a punch, and a slide, and for each attack you have that one hitbox and list of hurtboxes. You could have all 3 of those in an array/another list and an id to state what set of hitboxes should be used right now. Then when you check collisions, check them for the hitboxes/hurtboxes at that array position.

    My point is that you do not need to involve other objects nor would I use other objects in your situation.
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice