How to do collision detection between tentacle and player?

Started by xboxown, Wed 21/06/2023 04:04:19

Previous topic - Next topic

xboxown

  Hey guys,

I have one other question to ask. I want when the tentacle collides with the player it is considered game over. The player is crushed and dies out. How do I make the collision detection for that? Another thing, how do I replace a character in the map, add another character in the map and make that new character after reaching its destination disappear and be removed from the map?

I will explain. I have a Frail Stalagmite. It comes into two part. One is the full frail stalagmite, once the tentacle hits it, the full stalagmite is replaced with broken stalagmite one and another piece is added and falls down to the water and disappears once it hits the water.

Khris

First of all, you don't need to use a (global) character for everything. Rooms have (local) objects, so unless you need walking animations, those are fine.

Next, you can do a simple coordinate check. Since the tentacles only move sideways, you only need to compare the x coordinates of the tentacle and the stalactite.

Again inside repeatedly_execute:

Code: ags
  int dist = cTentacle.x - (oStalactite.X + Game.SpriteWidth[oStalactite.Graphic] / 2);
  if (dist < 0) dist = -dist;
  if (dist < 20 && oStalactite.Y == 123) { // adjust these numbers, replace 123 with proper Y coordinate
    oStalactiteTip.Move(oStalactiteTip.X, 10000, eNoBlock);
  }
  // tip reaches water
  if (oStalactiteTip.Y >= 250) {
    oStalactite.StopMoving();
    oStalactite.Visible = false;
  }
Objects are positioned using their bottom left corner, so we add half the sprite width to get to the center and compare that to the tentacle by checking whether the difference is below a threshold.

As for the piece breaking off, just start with the stalactite already in pieces. This way you simply need to move the tip object down and not replace anything.

(once again the code might now work as-is and is primarily meant to show a way how this can be done in general)

xboxown

You are genius! I wish I thought of it like that! It is even more realistic this way! Thank you!

xboxown

Quote from: Khris on Wed 21/06/2023 06:31:51First of all, you don't need to use a (global) character for everything. Rooms have (local) objects, so unless you need walking animations, those are fine.

Next, you can do a simple coordinate check. Since the tentacles only move sideways, you only need to compare the x coordinates of the tentacle and the stalactite.

Again inside repeatedly_execute:

Code: ags
  int dist = cTentacle.x - (oStalactite.X + Game.SpriteWidth[oStalactite.Graphic] / 2);
  if (dist < 0) dist = -dist;
  if (dist < 20 && oStalactite.Y == 123) { // adjust these numbers, replace 123 with proper Y coordinate
    oStalactiteTip.Move(oStalactiteTip.X, 10000, eNoBlock);
  }
  // tip reaches water
  if (oStalactiteTip.Y >= 250) {
    oStalactite.StopMoving();
    oStalactite.Visible = false;
  }
Objects are positioned using their bottom left corner, so we add half the sprite width to get to the center and compare that to the tentacle by checking whether the difference is below a threshold.

As for the piece breaking off, just start with the stalactite already in pieces. This way you simply need to move the tip object down and not replace anything.

(once again the code might now work as-is and is primarily meant to show a way how this can be done in general)


Visible and graphics are producing error. There is no way of making the character disappear as a command.

Khris

1. please do not quote the entire post; you can click the Reply button at the bottom.

2. in my code, oStalactite is an Object, not a Character. Please show your code and error messages as they appear, ideally verbatim.

3. once again: the code might not work as-is and is primarily meant to show a way how this can be done in general; there's no way around studying the manual and familiarizing yourself with the AGS scripting language.

xboxown

Quote1. please do not quote the entire post; you can click the Reply button at the bottom.

Apologies for that. Not doing it again.

Quote2. in my code, oStalactite is an Object, not a Character. Please show your code and error messages as they appear, ideally verbatim.

OK...this is the source code modified:

Code: ags
int dist = cTentacle.x - (cStalagmiteTip.x+ Game.SpriteWidth[cStalagmiteTip.Frame] / 2);
   if (dist < 0) dist = -dist;
  // Display(String.Format("%d", dist));
   if (dist<10) { // adjust these numbers, replace 123 with proper Y coordinate
    Display("Uh oh...look like that tentacle hit something it should not have hit!!");
    cStalagmiteTip.Walk(cStalagmiteTip.x, 80, eBlock, eAnywhere);
    }
    // tip reaches water
    if (cStalagmiteTip.y >= 64) {
      cStalagmiteTip.StopMoving();
      cStalagmiteTip.ChangeRoom(1, 0, 0, eDirectionDown);
      Display("The stalagmite falls and sinks into the ocean. The monster shrieks in pain....");
      cSeaMonster.LockView(VWROARINGMONSTER);
      cSeaMonster.Animate(false,  5, eOnce);
      cSeaMonster.UnlockView(eStopMoving);
    }

I couldn't make it invisible so I decided to make a void room and just the unwanted characters there where the player can never visit as means of destroying them.

Quote3. once again: the code might not work as-is and is primarily meant to show a way how this can be done in general; there's no way around studying the manual and familiarizing yourself with the AGS scripting language.

Yeah, for sure, I can read the manual. If I am stuck though, I will post here in hopes great people like you :D well take their time to help me out. But you are right, I should read the manual and try hard to figure it out on myself first. Best to way to learn, right?

Thank you so much for helping me and replying my to plea. I appreciate your time and effort, especially since it is coming out of your time to helping a stranger like me.

Crimson Wizard

Quote from: xboxown on Wed 21/06/2023 22:48:48I couldn't make it invisible so I decided to make a void room and just the unwanted characters there where the player can never visit as means of destroying them.

You can move NPCs to a non-existant rooms too. cSeaMonster.ChangeRoom(-1) will work.

Other ways to hide characters are:
* moving behind room edges, like cSeaMonster.x = -1000;
* cSeaMonster.Transparency = 100;
* cSeaMonster.on = false; but I think this requires to enable a backwards compatibility option, because "on" variable was not ported to the modern scripting API.

xboxown

I understood what Khris was doing. Add a new object and then use the object for the room. I just checked youtube and learned now how to add object.

I did and reused his code again:

Code: ags
if (dist<10) { // adjust these numbers, replace 123 with proper Y coordinate
    Display("Uh oh...look like that tentacle hit something it should not have hit!!");
    oStalagmiteTip.Move(oStalagmiteTip.X, 1000, eNoBlock);
    }
    // tip reaches water
    if (cStalagmiteTip.y >= 200) {
      oStalagmiteTip.StopMoving();
      oStalagmiteTip.Visible=false;
      //cStalagmiteTip.ChangeRoom(1, 0, 0, eDirectionDown);
      Display("The stalagmite falls and sinks into the ocean. The monster shrieks in pain....");
      cSeaMonster.LockView(VWROARINGMONSTER);
      cSeaMonster.Animate(false,  5, eOnce);
      cSeaMonster.UnlockView(eStopMoving);
      
    }
  }

Problem now..the thing does not move at all. I don't know what mistake I made here.

Crimson Wizard

Quote from: xboxown on Wed 21/06/2023 23:29:13Problem now..the thing does not move at all. I don't know what mistake I made here.

You probably need to re-add eAnywhere to Move.

Khris

Indeed, and it's room_RepExec instead of repeatedly_execute for room scripts.

xboxown

Aaah! Actually it is under repeated exec:




function room_RepExec()

This the entire code in case I made a bug somewhere.

Code: ags
function room_RepExec()
{
  if (!SeaMonsterAttack)
  {
    // Not close to the monster
    cTentacle.x = cSeaMonster.x - 47;
    cSecondTentacle.x = cSeaMonster.x + 57;
    if (IsTimerExpired(1)) {
      int newX, diff;
      do {
        newX = Random(160) + 40; // range 40 - 200
        diff = newX - cSeaMonster.x; if (diff < 0) diff = -diff;
      } while (diff < 30); // move by at least 30 pixels
      cSeaMonster.Move(newX, cSeaMonster.y, eNoBlock, eAnywhere);
      SetTimer(1, (Random(5) + 5) * GetGameSpeed()); // 5 - 10 seconds
    }
  }
  else if (SeaMonsterAttack)
  {
    if (!oStalagmiteTip.Moving)
    {
      cSeaMonster.Say("ROOOAAARR");
      // swing tentacle
      cRobotLE.Say("Eeeeeek!!");
      cRobotLE.Walk(cRobotLE.x,  cRobotLE.y+24, eBlock, eWalkableAreas);
      // Close to the monster
      cSeaMonster.LockView(VWROARINGMONSTER);
      cSeaMonster.Animate(false,  5, eOnce);
      cSeaMonster.UnlockView(eStopMoving);
      cTentacle.LockView(VWRAISINGTENTACLE);
      cTentacle.Animate(false,  15, eOnce);
      cTentacle.UnlockView(eStopMoving);
      cSecondTentacle.LockView(VWRAISINGTENTACLE);
      cSecondTentacle.Animate(false,  20, eOnce);
      cSecondTentacle.UnlockView(eStopMoving);
      cTentacle.y=cTentacle.y+48;
      cTentacle.LockView(VWSWINGTENTACLE);
      cTentacle.Animate(false,  20, eOnce);
      cTentacle.UnlockView(eStopMoving);
      cSecondTentacle.y=cSecondTentacle.y+48;
      cSecondTentacle.LockView(VWSWINGTENTACLE);
      cSecondTentacle.Animate(false,  25, eOnce);
      cSecondTentacle.UnlockView(eStopMoving);
      cSecondTentacle.y=cSecondTentacle.y-48;
      cTentacle.y=cTentacle.y-48;
   // if (cTentacle.x>=75 && cTentacle.x<=85)
    //{
      // Here monster dies and be replaced with a body log.
     // Display("The tentancle damages the frail ....");
   // }
    }
   int dist = cTentacle.x - (cStalagmiteTip.x+ Game.SpriteWidth[cStalagmiteTip.Frame] / 2);
   if (dist < 0) dist = -dist;
  // Display(String.Format("%d", dist));
   if (dist<10) { // adjust these numbers, replace 123 with proper Y coordinate
    Display("Uh oh...look like that tentacle hit something it should not have hit!!");
    oStalagmiteTip.Move(oStalagmiteTip.X, 1000, eNoBlock);
    }
    // tip reaches water
    if (oStalagmiteTip.Y >= 200) {
      oStalagmiteTip.StopMoving();
      oStalagmiteTip.Visible=false;
      //cStalagmiteTip.ChangeRoom(1, 0, 0, eDirectionDown);
      Display("The stalagmite falls and sinks into the ocean. The monster shrieks in pain....");
      cSeaMonster.LockView(VWROARINGMONSTER);
      cSeaMonster.Animate(false,  5, eOnce);
      cSeaMonster.UnlockView(eStopMoving);
      
    }
  }
}


Khris

That's fine, I was referring to the function's name not the event's. You still didn't add eAnywhere though, line 57 in that snippet needs to be
Code: ags
  oStalagmiteTip.Move(oStalagmiteTip.X, 1000, eNoBlock, eAnywhere);

xboxown

I did. It gave me an error that I added an extra parameter block that does not exist with object. Here let me show you the error message via screenshot:



Snarky

The problem is that you're missing the speed parameter, so the eNoBlock gets interpreted as the speed, and then eAnywhere gets interpreted as the blocking parameter, and is an illegal value for it.

For this kind of error, you should consult the built-in help. There's a quick-help tooltip when you edit the parameters or hover the mouse over the function that tells you the right format, or if you press F1 it should bring you to the relevant article in the manual.

xboxown

OOOH! Speed?! I didn't know that! Thanks for the tip!

xboxown

Hmmmm....it fixed the run-time error. But it still did not move.

Code: ags
oStalagmiteTip.Move(oStalagmiteTip.X, 1000,10,  eNoBlock, eAnywhere);

Khris

Try replacing
Code: ags
  if (dist<10)
with
Code: ags
  if (dist < 10 && !oStalagmiteTip.Moving)

Also, basic debugging. You have already done this yourself:
Code: ags
 // Display(String.Format("%d", dist));
Just keep doing that to check values and whether lines run at all, etc.

You might also want to fix the indentation, it's all over the place currently which makes debugging much harder.

SMF spam blocked by CleanTalk