SOLVED Collision with a specific part of a sprite

Started by Duckbutcher, Sat 29/12/2018 05:41:23

Previous topic - Next topic

Duckbutcher

Hey all, hope you had a good Christmas.

I'm doing a sub-game in which the player controls a big fish swimming around which has to eat smaller fish. It does this by running into them. This is my code for the collision:

Code: ags

if (cEgo.IsCollidingWithChar(cfish)){

  if (cEgo.Loop == 0){ //if facing direction, eg down
    player.ChangeView(194);//change to bite anim
    player.Animate(0, 1, eOnce, eBlock);//play bite anim
    player.ChangeView(101);//returns to original view
  }
    
  if (cEgo.Loop == 1){
    player.ChangeView(194);
    player.Animate(1, 1, eOnce, eBlock);
    player.ChangeView(101);
  }
  
  if (cEgo.Loop == 2){
    player.ChangeView(194);
    player.Animate(2, 1, eOnce, eBlock);
    player.ChangeView(101);
  }
  
  if (cEgo.Loop == 2){
    player.ChangeView(194);
    player.Animate(2, 1, eOnce, eBlock);
    player.ChangeView(101);
  }
  
  cfish.ChangeRoom(-1); //fish disappears



It works fine.

HOWEVER - fishes usually just eat through their mouths and as you can probably guess this interaction plays no matter what part of the big fish sprite my little fish come into contact with.

So here's the question - is there some way to have this interaction only play when the little fish collide with the head area of my big fish? Sort of like assigning a hotspot or region to the sprite.

Thanks for your time, hope you're all having a good one.

eri0o

The easier way would be breaking the bigger fish sprite in two, head and rest.

Slasher

Or

You could play around with and add if cEgo.y in relation to cFish.y

Cassiebsg

Or check which loop your fish is facing and only eat if the loop is facing the small fish... which might end up having to check loop and y position for the fishes... but should work fine.  (nod)
There are those who believe that life here began out there...

Duckbutcher

#4
Quote from: eri0o on Sat 29/12/2018 07:13:15
The easier way would be breaking the bigger fish sprite in two, head and rest.

Actually thought of doing this - using "follow exactly" -  I'm considering it as a last resort if I can't get anything else working as it'd necessitate me redrawing a bunch of art. Cheers for the suggestion!

Slasher, could you elaborate? As I understand it this would involve checking coordinates on the sprite itself rather than the room/screen? Apologies if this is a dumb question.

Quote from: Cassiebsg on Sat 29/12/2018 09:00:38
Or check which loop your fish is facing and only eat if the loop is facing the small fish... which might end up having to check loop and y position for the fishes... but should work fine.  (nod)

This makes sense, I'll have a try!

adm244

You can mark rectangular region that will cover mouth part of the fish and check collisions between it and other fishes (using AABB if sprites are not rotated).
Just store XYs relative to sprite origin point and width, height somewhere for each facing directions.

Mandle

Quote from: Slasher on Sat 29/12/2018 07:15:13
Or

You could play around with and add if cEgo.y in relation to cFish.y

This is how I would do it. Adding extra sprites might get messy and slow.

Khris

You can replace those four blocks with:

Code: ags
  if (player.IsCollidingWithChar(cfish)) {
    player.LockView(194); // change to bite anim
    player.Animate(player.Loop, 1, eOnce, eBlock); // play bite anim
    player.UnlockView();  // returns to original view
  }


I too would use a coordinate check. First, calculate the coordinates of the mouth's bottom center by adding a loop-based offset to the player's position:

Code: ags
  int x = player.x, y = player.y - 20; // base offset
  if (player.Loop == 0) y -= 10;  // down
  else if (player.Loop == 3) y -= 50;  // up
  else if (player.Loop == 1) x -= 40;  // left
  else x += 40;  // right


Now you can use the Pythagorean theorem to calculate the distance between the player's mouth base coords and another fish's base coords.
If distance < x, small fish collides with mouth.

Duckbutcher

Khris, thanks for the shortcut on those initial loops, that's made things a lot simpler and less cluttered.

Quote from: Khris on Sun 30/12/2018 13:18:23

Code: ags
  int x = player.x, y = player.y - 20; // base offset
  if (player.Loop == 0) y -= 10;  // down
  else if (player.Loop == 3) y -= 50;  // up
  else if (player.Loop == 1) x -= 40;  // left
  else x += 40;  // right


Now you can use the Pythagorean theorem to calculate the distance between the player's mouth base coords and another fish's base coords.
If distance < x, small fish collides with mouth.

Yeah sorry, you lost me at Pythagorean Theorem I'm afraid! Can you throw me a quick example? Thanks for your time as always.

Khris

You're going to need x and y distance first:
Code: ags
  int dx = cFish.x - player.x;
  int dy = cFish.y - player.y;


According to the theorem, the distance between player and cFish squared is dx² + dy². Accordingly:
Code: ags
  if (dx * dx + dy * dy < 20 * 20)  // distance is less than 20 pixels

Duckbutcher

Quote from: Khris on Mon 31/12/2018 09:45:59
You're going to need x and y distance first:
Code: ags
  int dx = cFish.x - player.x;
  int dy = cFish.y - player.y;


According to the theorem, the distance between player and cFish squared is dx² + dy². Accordingly:
Code: ags
  if (dx * dx + dy * dy < 20 * 20)  // distance is less than 20 pixels


Got this working great, with a couple of adjustments! Thanks as always Khris, this was more or less exactly what I was after.

SMF spam blocked by CleanTalk