Adventure Game Studio

AGS Support => Beginners' Technical Questions => Topic started by: Duckbutcher on Sat 29/12/2018 05:41:23

Title: SOLVED Collision with a specific part of a sprite
Post by: Duckbutcher on Sat 29/12/2018 05:41:23
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) Select

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.
Title: Re: Collision with a specific part of a sprite
Post by: eri0o on Sat 29/12/2018 07:13:15
The easier way would be breaking the bigger fish sprite in two, head and rest.
Title: Re: Collision with a specific part of a sprite
Post by: 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
Title: Re: Collision with a specific part of a sprite
Post by: 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)
Title: Re: Collision with a specific part of a sprite
Post by: Duckbutcher on Sat 29/12/2018 09:06:07
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!
Title: Re: Collision with a specific part of a sprite
Post by: adm244 on Sun 30/12/2018 08:47:10
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.
Title: Re: Collision with a specific part of a sprite
Post by: Mandle on Sun 30/12/2018 11:52:50
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.
Title: Re: Collision with a specific part of a sprite
Post by: Khris on Sun 30/12/2018 13:18:23
You can replace those four blocks with:

Code (ags) Select
  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) Select
  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.
Title: Re: Collision with a specific part of a sprite
Post by: Duckbutcher on Mon 31/12/2018 04:17:23
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) Select
  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.
Title: Re: Collision with a specific part of a sprite
Post by: Khris on Mon 31/12/2018 09:45:59
You're going to need x and y distance first:
Code (ags) Select
  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) Select
  if (dx * dx + dy * dy < 20 * 20)  // distance is less than 20 pixels
Title: Re: Collision with a specific part of a sprite
Post by: Duckbutcher on Thu 03/01/2019 04:25:03
Quote from: Khris on Mon 31/12/2018 09:45:59
You're going to need x and y distance first:
Code (ags) Select
  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) Select
  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.