Author Topic: WalksOnto doesn't seem to detect walking onto a region  (Read 269 times)

Hi Guys,

I'm afraid I've hit on a wall and I need to ask you for help.

In my game, the player has to walk onto a number of regions in a specific order to solve a puzzle. However, the order changes depending on which region is walked onto first. There are four regions in total and the player can decide from which they are going to start the sequence.

In order to do that I set up four regions in my room and used four region_WalksOnto functions to detect the event of walking onto them. What's more, I've got a counter of how many regions have been walked onto in a correct order (I called it a numberOfTrues) and an array of possible paths (there are four: "1,2,3,4,1", "2,3,4,1,2", "3,4,1,2,3", "4,1,2,3,4"; the numbers represent the IDs of the regions; each path has five values, where each five stands for a whole round). This way I've been able to check if the next region the player walks onto is the next one on the given path. If the player walks on a region that is not correct and breaks the sequence, then the numberOfTrues gets reset to 1 and a new path is selected.

Now, I'm not saying it's the best way of doing it but it seemed to be working fine. At least I thought so until I stopped displaying the current value of numberOfTrues during the game. What I mean is during the development I would use either Display() or a label to show the current values of numberOfTrues or what region had been walked onto. Without displaying those values the game seems to be working randomly... Sometimes it would work fine and the character would recognise that the path has been completed and then it would not. And that happens only when the values are not displayed.

I've tested it now about 30 times... (at this point, even thought it's a game I've made, I am sick of looking at it :) ) and I'm sure it works fine with the values displayed (with the use of Display() or labels) and that it works randomly without.

I'm far from saying that this might be the case, but could it be possible that for some reason AGS may be failing to detect walking onto a region?

Here is the excerpt of my code that handles the walking onto regions plus variables used in them:

Code: Adventure Game Studio
  1. int tablePaths[20];
  2. int pathSelected;
  3. int numberOfTrues = 0;
  4.  
  5. function room_Load()
  6. {  
  7.    //starting from south
  8.   tablePaths[0] = 1;
  9.   tablePaths[1] = 2;
  10.   tablePaths[2] = 3;
  11.   tablePaths[3] = 4;
  12.   tablePaths[4] = 1;
  13.  
  14.   //starting from east
  15.   tablePaths[5] = 2;
  16.   tablePaths[6] = 3;
  17.   tablePaths[7] = 4;
  18.   tablePaths[8] = 1;
  19.   tablePaths[9] = 2;
  20.  
  21.   //starting from north
  22.   tablePaths[10] = 3;
  23.   tablePaths[11] = 4;
  24.   tablePaths[12] = 1;
  25.   tablePaths[13] = 2;
  26.   tablePaths[14] = 3;
  27.  
  28.   //starting from west
  29.   tablePaths[15] = 4;
  30.   tablePaths[16] = 1;
  31.   tablePaths[17] = 2;
  32.   tablePaths[18] = 3;
  33.   tablePaths[19] = 4;
  34.  
  35. }
  36.  
  37.  
  38.  
  39.  
  40. function region1_WalksOnto()
  41. {
  42.  
  43.  
  44.   if(listHasBeenRead == true && tableWalkedAroundThreeTimes == false)
  45.   {
  46.     if(numberOfTrues == 0 && justEnteredKitchen == true)
  47.     {
  48.       pathSelected = 0;
  49.       numberOfTrues++;
  50.     }
  51.    
  52.  
  53.     else
  54.     {
  55.       if(region[1].ID == tablePaths[pathSelected+numberOfTrues])
  56.       {
  57.         numberOfTrues++;
  58.       }
  59.      
  60.       else
  61.       {
  62.         numberOfTrues = 1;
  63.         pathSelected = 0;
  64.       }
  65.     }    
  66.    
  67.     if(justEnteredKitchen == true && numberOfTrues == 2)
  68.     {
  69.       justEnteredKitchen = false;
  70.      
  71.     }
  72.    
  73.   }
  74.  
  75.  
  76.  
  77. }
  78.  
  79. function region2_WalksOnto()
  80. {
  81.  
  82.  
  83.   if(listHasBeenRead == true && tableWalkedAroundThreeTimes == false)
  84.   {
  85.     if(numberOfTrues == 0 && justEnteredKitchen == true)
  86.     {
  87.       pathSelected = 5;
  88.       numberOfTrues++;
  89.     }
  90.    
  91.    
  92.     else
  93.     {
  94.       if(region[2].ID == tablePaths[pathSelected+numberOfTrues])
  95.       {
  96.         numberOfTrues++;
  97.       }
  98.      
  99.       else
  100.       {
  101.         numberOfTrues = 1;
  102.         pathSelected = 5;
  103.       }
  104.     }
  105.    
  106.     if(justEnteredKitchen == true && numberOfTrues == 2)
  107.     {
  108.       justEnteredKitchen = false;
  109.      
  110.     }
  111.    
  112.    
  113.   }
  114.  
  115.  
  116.  
  117.  
  118. }
  119.  
  120. function region3_WalksOnto()
  121. {
  122.  
  123.  
  124.  
  125.   if(listHasBeenRead == true && tableWalkedAroundThreeTimes == false)
  126.   {
  127.     if(numberOfTrues == 0 && justEnteredKitchen == true)
  128.     {
  129.       pathSelected = 10;
  130.       numberOfTrues++;
  131.     }
  132.    
  133.    
  134.    
  135.     else
  136.     {
  137.       if(region[3].ID == tablePaths[pathSelected+numberOfTrues])
  138.       {
  139.         numberOfTrues++;
  140.       }
  141.      
  142.       else
  143.       {
  144.         numberOfTrues = 1;
  145.         pathSelected = 10;
  146.       }
  147.     }
  148.    
  149.     if(justEnteredKitchen == true && numberOfTrues == 2)
  150.     {
  151.       justEnteredKitchen = false;
  152.     }
  153.    
  154.    
  155.   }
  156.    
  157. }
  158.  
  159. function region4_WalksOnto()
  160. {
  161.  
  162.  
  163.   if(listHasBeenRead == true && tableWalkedAroundThreeTimes == false)
  164.   {
  165.     if(numberOfTrues == 0 && justEnteredKitchen == true)
  166.     {
  167.       pathSelected = 15;
  168.       numberOfTrues++;
  169.     }
  170.    
  171.    
  172.     else
  173.     {
  174.       if(region[4].ID == tablePaths[pathSelected+numberOfTrues])
  175.       {
  176.         numberOfTrues++;
  177.       }
  178.      
  179.       else
  180.       {
  181.         numberOfTrues = 1;
  182.         pathSelected = 15;
  183.       }
  184.     }
  185.    
  186.     if(justEnteredKitchen == true && numberOfTrues == 2)
  187.     {
  188.       justEnteredKitchen = false;
  189.     }
  190.  
  191.   }
  192. }
  193.  

P.S.
I know the code inside WalkOnto functions could be put into a separate function but I got bogged down with this problem and haven't got time to do it.

I'm using AGS 3.4.3.

I would appreciate any suggestions as I feel defeated by AGS :)
 
« Last Edit: 25 Mar 2020, 23:08 by Pogwizd »

TheManInBoots

  • Epically wrote function to declare an int
Re: WalksOnto doesn't seem to detect walking onto a region
« Reply #1 on: 26 Mar 2020, 03:57 »
I assume people are hesitant to reply to your thread because it is a lot to read through.
I do not have the time to find out where your scripting problem is, your post is too long.
Maybe you have to take into account that the player can walk onto the same region TWICE, and that messes up the process? (you could avoid that by adding a variable that keeps track if the player walks twice on the same region)
Tbh I actually got carried away by the problem and I had some fun thinking about it, and I will show you how I would script the entire thing you wrote, but in no more than 24 lines and in only one single function :P:

The finished result is in the end, I explained it step by step, in case you wanted to understand what I wrote:
(Note: my variable 'step' corresponds to your 'numberoftrues' and my variable 'plan' corresponds to your 'pathselected')

So first I would create the regions as the first 4 regions of the room, so that their ID numbers correspond (so that their IDs are 1,2,3,4).

Then I would have one int variable "step" that describes on which step you're on
(when step==1 you stepped on the first random region, when step==2 you are on the second random region etc.)

After that I would create  a variable "plan" that describes which number plan you follow.
Because we have 4 different plans:
Plan 1:1,2,3,4,1
Plan 2:2,3,4,1,2
Plan 3:3,4,1,2,3
Plan 4:4,1,2,3,4

So when the player walks on the first region, the variable "plan" is set accordingly
(e.g. player walks on region1 => plan=1;
player walks on region2 => plan=2;)

So to turn it into script, in the region walks onto function you'd write:

Code: Adventure Game Studio
  1. function region1_WalksOnto()
  2. {
  3. function region1_WalksOnto()
  4. {
  5. step  ;//step variable grows by one when walking onto the region, so if it was the first step, now step==1
  6. if(step==1)plan=region[1].ID;//so if this is the first step, the plan number becomes the region number (if region==1, plan=1, if region==2, then plan=2 etc.)
  7. }
  8. }

btw. in line 5 I wrote "step PLUS PLUS;" but annoyingly the plus symbols are constantly being eliminated when posting! :(

You will use the same pattern for all four region functions.
So whenever the player walks onto a region, step grows by 1, and we now we are on the next step.
So now we have to figure out what happens when it's NOT step one but step 2-5 when the player walks onto region 1.
If we are doing the second step==2, than the plan has to b plan 4, when standing on region 1:
Plan 4:4,1,2,3,4
If it's not plan 4, then the pattern is broken, and the whole thing restarts, by simply resetting "step" and "plan" and setting both variables to 0.

So we add to the function
Code: Adventure Game Studio
  1. function region1_WalksOnto()
  2. {
  3. step  ;//I wrote step PLUS PLUS;
  4. if(step==1)plan=region[1].ID;
  5.  
  6. if(step==2&&plan!=4)
  7. {step=0;
  8. plan=0;}
  9. }
  10. }

And then we do that for the rest of the steps, giving us this function:
Spoiler: ShowHide

Code: Adventure Game Studio
  1. function region1_WalksOnto()
  2. {
  3. step  ;// I wrote 'step PLUSPLUS;'
  4. if(step==1)plan=region[1].ID;
  5.  
  6. if(step==2&&plan!=4)
  7. {step=0;
  8. plan=0;}
  9. if(step==3&&plan!=3)
  10. {step=0;
  11. plan=0;}
  12. if(step==4&&plan!=2)
  13. {step=0;
  14. plan=0;}
  15. }


If step==5 then you want to trigger the 'Succesevent' if it's the correct plan, and else reset the entire pattern.
When correctly following the pattern, the last region is the same as the first, so if the player started on region 1 and started plan 1, now he has to be standing on region 1 again, so we add below the rest:
Code: Adventure Game Studio
  1. if(step==5&&plan==region[1].ID)
  2. {player.Say("I can't believe it, I did it!");}
  3. else if(step==5)
  4. {step=0;
  5. plan=0;}
  6.  

Giving us the full function:
Spoiler: ShowHide

Code: Adventure Game Studio
  1. function region1_WalksOnto()
  2. {
  3. step  ;
  4. if(step==1)plan=region[1].ID;
  5.  
  6. if(step==2&&plan!=4)
  7. {step=0;
  8. plan=0;}
  9. if(step==3&&plan!=3)
  10. {step=0;
  11. plan=0;}
  12. if(step==4&&plan!=2)
  13. {step=0;
  14. plan=0;}
  15. if(step==5&&plan==region[1].ID)
  16. {player.Say("I can't believe it, I did it!");}
  17. else if(step==5)
  18. {step=0;
  19. plan=0;}
  20. }
  21.  


And then we need to do that for every other function us well, and adjust the other numbers as well.

Now, how can you write all that in only one single function?
Let's check out the exact numbers for all functions:

For region one, we said, if step==2, then the plan must be plan 4, if step==3, then plan must be plan 3, if step==4, then plan must be plan 2.

For clarity, here I write it as a diagram:
Region 1:
2-4
3-3
4-2

And those are the diagrams for the other regions:
Region 2:
2-1
3-4
4-3

Region 3:
2-2
3-1
4-4

Region 4:
2-3
3-2
4-1

So if you watch those diagrams exactly, you can notice that there is a certain pattern. The right row has the 1,2,3,4 in reverse, while rotating down one digit for each region and beginning at 1 again after 4.

So we can write that in a function. The variable 'requiredplan' describes the plan that each step needs for each region for it to work:
And if you look at the diagrams and look how to calculate it, you get this:

Code: Adventure Game Studio
  1. requiredplan=region[].ID 1-step;//I wrote region[].ID PLUS 1-step
  2. if(requiredplan<1)requiredplan=4-requiredplan;

So notice that I added the if(requiredplan<1) or if(requiredplan<=0) function.
That is so that the rotation of the numbers begins back at 4.

So now you can simply write

Code: Adventure Game Studio
  1. int requiredplan;
  2. requiredplan=region[1].ID 1-step;//I wrote region[1].ID PLUS 1-step
  3. if(requiredplan<1)requiredplan=4-requiredplan;
  4.  
  5. if(plan!=requiredplan)
  6. {step=0;
  7. plan=0;}
And that works for all steps, so you don't need to write a separate if condition for steps 2,3 and 4 anymore.

So checkpoint!, the entire function now would look like this:
Spoiler: ShowHide

Code: Adventure Game Studio
  1. int step;
  2. int plan;
  3. function region1_WalksOnto()
  4. {
  5. step  ;//I wrote step PLUSPLUS
  6. if(step==1)plan=region[1].ID;
  7.  
  8. int requiredplan;
  9. requiredplan=region[1].ID 1-step;//I wrote region[1].ID PLUS 1-step
  10. if(requiredplan<1)requiredplan=4-requiredplan;
  11.  
  12. if(plan!=requiredplan)
  13. {step=0;
  14. plan=0;}
  15.  
  16. if(step==5&&plan==region[1].ID)
  17. {player.Say("I can't believe it, I did it!");}
  18. else if(step==5)
  19. {step=0;
  20. plan=0;}
  21. }


But now, you still have a function for each region. How to you bring all the 4 region function into 1 single function?
By simply letting the function recognize on which region the player character stands, and then run the same function for all 4 regions.
In order to get the current region ID, you need a Region pointer.
You write:

Code: Adventure Game Studio
  1. Region*CurrentRegion;
  2. CurrentRegion=Region.GetAtRoomXY(cJim.x, cJim.y);
  3. int RegionID=CurrentRegion.ID;

So then you implement that in the initial function:
Code: Adventure Game Studio
  1. function region1_WalksOnto()
  2. {
  3. step  ;//I wrote step PLUSPLUS;
  4. if(step==1)plan=RegionID;
  5. }

And then the entire, FINAL function would look like this:
Code: Adventure Game Studio
  1. int step;
  2. int plan;
  3. function AllFourRegions_WalksOnto()
  4. {
  5. step  ;//I wrote step PLUS PLUS
  6. Region*CurrentRegion;
  7. CurrentRegion=Region.GetAtRoomXY(cJim.x, cJim.y);
  8. int RegionID=CurrentRegion.ID;
  9.  
  10. if(step==1)plan=RegionID;
  11.  
  12. int requiredplan;
  13. requiredplan=RegionID 1-step;//I wrote RegionID PLUS 1-step
  14. if(requiredplan<1)requiredplan=4-requiredplan;
  15.  
  16. if(plan!=requiredplan)
  17. {step=0;
  18. plan=0;}
  19.  
  20. if(step==5&&plan==RegionID)
  21. {player.Say("I can't believe it, I did it!");}
  22. else if(step==5)
  23. {step=0;
  24. plan=0;}
  25. }

Now you can use that same universal function for every region.
Notice I changed the name of the function to "AllFourRegions_WalksOnto()"
Because what you can do now, in the room editor, for every function, before clicking on the ellipse "..." button for the WalksOnto function in the Eventspanel, you change that name to "AllFourRegions_WalksOnto". And this way every single region is going to be directed directly to that function, and you don't have to write every function separately for every region anymore.


P.S.: If you already have other regions in the room and do not want to delete them to make the four regions IDs 1,2,3,4, you can simply add a substraction to the formula so that it still works. As long as the region ID's are in a continuous row.
« Last Edit: 27 Mar 2020, 04:31 by TheManInBoots »

Retro Wolf

  • The Viscount of Vaporware
    • Retro Wolf worked on one or more games that was nominated for an AGS Award!
Re: WalksOnto doesn't seem to detect walking onto a region
« Reply #2 on: 26 Mar 2020, 08:53 »
It can sometimes take a while for people to reply to a thread because people live in different parts of the world and could be in bed. Also the original post is nowhere near "too long".

Re: WalksOnto doesn't seem to detect walking onto a region
« Reply #3 on: 26 Mar 2020, 10:28 »
Just a random thought: if everything works properly when you use Display() and doesn't work when you don't, could you try inserting a Wait(1) at the same point where you were using the Display function and see if it works now?

(Disclaimer: I'm still a newbie so this might not make sense, but at least it's quick and easy to try :-D)

TheManInBoots

  • Epically wrote function to declare an int
Re: WalksOnto doesn't seem to detect walking onto a region
« Reply #4 on: 26 Mar 2020, 11:28 »
It can sometimes take a while for people to reply to a thread because people live in different parts of the world and could be in bed. Also the original post is nowhere near "too long".
Well yeah, that too.

At least for me personally it takes a while to work myself into a long script like the one Pogwizd showed and then find the bug. Especially if it's not an obvious bug one might have to recreate it and test it out. That's what I meant when I said it might be too long and not all people might have the time to do it.
« Last Edit: 26 Mar 2020, 12:38 by TheManInBoots »

Retro Wolf

  • The Viscount of Vaporware
    • Retro Wolf worked on one or more games that was nominated for an AGS Award!
Re: WalksOnto doesn't seem to detect walking onto a region
« Reply #5 on: 26 Mar 2020, 13:32 »
OK no worries.

Snarky

  • Global Moderator
  • Global Moderator
  • Mittens Lord
  • Private Insultant
    • Best Innovation Award Winner 2018, for his numerous additions to the AGS open source ecosystem including the new Awards Ceremony client and modules
    • Snarky worked on one or more games that won an AGS Award!
    •  
    • Snarky worked on one or more games that was nominated for an AGS Award!
Re: WalksOnto doesn't seem to detect walking onto a region
« Reply #6 on: 26 Mar 2020, 14:47 »
I'm far from saying that this might be the case, but could it be possible that for some reason AGS may be failing to detect walking onto a region?

Without absolutely ruling anything out, that seems unlikely. And it is particularly unlikely that failing to detect walking onto a region would depend on whether you show the outcome on a label. (As Laura suggests, putting in a Display() call, on the other hand, could theoretically make a difference.)

At a glance, I don't see anything in your code that jumps out as obviously wrong. However, you haven't included the logic that actually detects when numberOfTrues reaches 5 (i.e., the part that appears to be glitching), so it's hard to say. In any case, the code does seem unnecessarily complex, which makes it harder to reason about its behavior and find bugs. So it's a question of to what extent you're prepared to try a different way of doing it.

If it were me, I would start by noticing that all four "different" paths are actually the same, just cycled around (basically, you always have to do one "full loop", but you can start anywhere). If that's a fixed property of the puzzle, it makes things a lot easier, because it doesn't matter "which path" you're on to determine if this was the right step, it only matters which region you came from and which one you're entering. (If, on the other hand, the correct next step at any point depends on where you started from, then you do need to define the paths separately.)

So I'd keep the previous region stored in a variable (updated each time after you enter a new one), and just do a check like:

Code: Adventure Game Studio
  1. int previousRegion=0;
  2. int numberOfTrues = 0;
  3.  
  4. function region1_WalksOnto()
  5. {
  6.   if(previousRegion == 4) // We're on the right path
  7.     numberOfTrues++;
  8.   else // We've taken a wrong turn (or this is the start), start again
  9.     numberOfTrues = 1;
  10.  
  11.   if(numberOfTrues==5)
  12.   {
  13.     // TODO: We've completed a cycle, do something!
  14.   }
  15.  
  16.   previousRegion = 1;
  17. }

(I'm leaving out all the stuff about listHasBeenRead and tableWalkedAroundThreeTimes and justEnteredKitchen, just to check that this part is working.)

Now you could do the same for all the regions, checking which region you came from and thus deciding whether this was a valid step, but given that the logic is always the same, I'd pull it out as a function:

Code: Adventure Game Studio
  1. int previousRegion=0;
  2. int numberOfTrues = 0;
  3.  
  4. void regionChange(int newRegion)
  5. {
  6.   if(newRegion == (previousRegion%4)+1) // We're on the right path
  7.     numberOfTrues++;
  8.   else // We've taken a wrong turn (or this is the start), start again
  9.     numberOfTrues = 1;
  10.  
  11.   if(numberOfTrues==5)
  12.   {
  13.     // TODO: We've completed a cycle, do something!
  14.   }
  15.  
  16.   previousRegion = newRegion;
  17. }
  18.  
  19. function region1_WalksOnto()
  20. {
  21.   regionChange(1);
  22. }
  23.  
  24. function region2_WalksOnto()
  25. {
  26.   regionChange(2);
  27. }
  28.  
  29. function region3_WalksOnto()
  30. {
  31.   regionChange(3);
  32. }
  33.  
  34. function region4_WalksOnto()
  35. {
  36.   regionChange(4);
  37. }
  38.  

Spoiler: ShowHide
This uses the modulo operator, %, in line 6. If you take n % 4, it makes the number n "wrap around" from 0–3: 4 becomes 0 (4%4 == 0), 5 becomes 1, etc. In this case it only affects n==4, ensuring that going from 4 to 1 is detected as a valid step.


You also have to take care that there's no other way to exit these regions that isn't covered, because if so the previousRegion variable won't be properly updated. If it's possible to step out onto some outside region, you would need to handle that as well, probably by setting both previousRegion and numberOfTrues to 0.
« Last Edit: 26 Mar 2020, 14:53 by Snarky »

Re: WalksOnto doesn't seem to detect walking onto a region
« Reply #7 on: 26 Mar 2020, 15:21 »
Personally, I don’t think that my first message was too long, as I believe it’s better to write the whole situation up, so anyone willing to help can get the full picture. Also, I did not expect anyone to get back to me straight away, nor I expected people to leave whatever they were up to just to have a look at my post. I thought it’s voluntary 😉.
Anyway, no matter.

TheManInTheBoots, thanks for your code.

Laura Hunt, thanks for the suggestion, I will give it a go in the evening. If it doesn’t work I won’t judge you because I’m a rookie myself 😉

Snarky, thank you very much for your suggestions. I will give it a proper look in the evening and come back with the results 😊. I'm ready to rewrite the whole thing if necessary because making it work as intended is the priority for me.

PS.

The logic that handles detecting the whole round looks as follows:

Code: Adventure Game Studio
  1. Function room_RepExec()
  2. {
  3.     if(numberOfTrues == 5)
  4.     {
  5.         tableCounter++;
  6.  
  7.         if(tableCounter ==1)
  8.         {
  9.             cCharacter.Say(“One lap done”);
  10.         }
  11.    
  12.         if(tableCounter ==2)
  13.         {
  14.             cCharacter.Say(“Getting there”);
  15.         }
  16.    
  17.         if(tableCounter ==3)
  18.         {
  19.             cCharacter.Say(“Done”);
  20.         }
  21.    
  22.         numberOfTrues = 1;
  23.     }  
  24. }
  25.  

Although, now when I'm looking at it I'm guessing there was no point in putting it into room_RepExec().
« Last Edit: 26 Mar 2020, 15:37 by Pogwizd »

TheManInBoots

  • Epically wrote function to declare an int
Re: WalksOnto doesn't seem to detect walking onto a region
« Reply #8 on: 26 Mar 2020, 18:01 »
Personally, I don’t think that my first message was too long
Oh yes, I don't want to be misunderstood. I don't think your post was too long either, just too long for me to run a proper bug test through it.
That's obviously totally fine if you add a lot of details to it.
Good luck with solving it

Re: WalksOnto doesn't seem to detect walking onto a region
« Reply #9 on: 26 Mar 2020, 23:42 »
Ugh... I've just spent hours watching carefully what was going on in my game. Turns out that the walkable area covering one of the regions was a bit wider than the region itself. So, when I was moving my character a little bit too close to the bottom edge of the region I wasn't triggering the WalkOnto() function.

I've not tested it out yet because I'm about to fall asleep but that I'm pretty sure that's what has been tripping me up (but I might be wrong again ;) ).

Sorry guys, it was just my stupidity ;)

Thank you all for quickly getting back to me your suggestions.
« Last Edit: 26 Mar 2020, 23:44 by Pogwizd »