Making the character walk to objects per default.

Started by SwanOnARedCouch, Sat 01/10/2016 12:24:49

Previous topic - Next topic

SwanOnARedCouch

Hello everyone!
Very recently, I started making a little point and click adventure. With little to no expirience. But so far, everything worked out pretty good. I have the first room with a bunch of hotspots and the first proper object. That's where I started struggling.
I have read quite a lot of posts in here, where people had problems with making the character walk to objects. I know how to do that, but, and this might be the actual problem, I am very lazy. So I was wondering if there is a more effective way then putting in the walk to command for every single possible interaction.
I tried using the "Any click on object" thing, but this apparently gets executed after the actual interaction. Is there a way of solving this in order to save time? Maybe a code that can be included in the Global Script, that makes the character always walk to any object first?
I also have the same issue with the character facing both objects and hotspots, but I assume the solution is - granted there is one - is similar.

Thanks in advance!
(Please keep in mind, that I have no knowledge about coding, so you might need to explain stuff a bit more.)

Jack

Have a look at unhandled_event in the manual. This is where all clicks end up which are not handled in any other way first. You'll still need to programatically estimate where the player character should stand, as the desired position relative to the object will probably change depending on where that object is in the room. Designing walkable areas to suit this would also help.

SwanOnARedCouch

Thanks for the fast reply, but I'm uncertain if that's what I was looking for.
I had a look at unhandled_event and ended up pretty confused. (This is my first time using anything more complicated than RPG Maker.) As far as I understood it, this command 'jumps into action' if the player clicks something that I have not (yet) have included a response to. Or am I completley wrong? Could you maybe provide me with an example?
Or maybe I should ask more specifically?:
Let's say, I have a room with three objects in it. For each object I have scripted something for the three basic interactions (look, interact and talk). I did not script something to make the character walk to the object first. Now I could add that for every object and interaction, which would make a total of nine, even though it would be three that repeat themselves. Still it seems kinda tedious, especially in the long run.
Ideally, I would want a piece of code that makes the player walk to any object without me adding anymore scripts. A piece of code that has to be re-used once for every object, wouldn't be as ideal, but still a great time-saver.

Mandle

Isn't there a generic object name like Object[0] or something that counts as a global interaction with any object?

Jack

Quote from: SwanOnARedCouch on Sat 01/10/2016 16:24:21
As far as I understood it, this command 'jumps into action' if the player clicks something that I have not (yet) have included a response to. Or am I completley wrong? Could you maybe provide me with an example?

No, that's about the gist of it. Executing it would go something like this:

Code: ags

function unhandled_event (int what, int type)
{
  if ((what == 2) && (type == 1))  // runs only on "interact with object"
  {
    Object*obj = Object.GetAtScreenXY(mouse.x, mouse.y);
    if (obj != null)
      cEgo.WalkTo(obj.X, obj.Y, eNoBlock, eWalkableAreas);
  }  
}


This would mean though that you will have to handle all your interactions through unhandled_event, executing specific code after you have identified which object was clicked. There is "automatically walk to hotspots in look mode" (in general settings), but as the name suggests it works only in look mode.

SwanOnARedCouch

#5
I'm having some problems with the code.
First, I got an Error saying that "WalkTo" is not a public member of "Character". I changed "WalkTo" into "Walk To", but I don't know if that solved it, because I got a new Error.
Apparently, the editor expects a normal bracket somewhere in this line:
Code: ags
 if (obj != null)

I couldn't figure out where though, so I couldn't start the game.

Little Addition:
If I put "Walk" instead of "WalkTo" (or "Walk To") in, I get a very weird Error, saying that it's missing a } and the function is still open. However, it says that error occurs on line -10. How is that possible?

Khris

I assume you want the player to behave just like she does for hotspots? As in a blocking walk to the object right before the event function?
You can do this by editing the GlobalScript's on_mouse_click function.

Assuming you're using the Default Game template, you should have this in there:
Code: ags
  else if (button == eMouseLeft) {
    ProcessClick(mouse.x, mouse.y, mouse.Mode );
  }

You need to replace that with:
Code: ags
  else if (button == eMouseLeft) {
    
    int mx = mouse.x; int my = mouse.y;
    if (GetLocationType(mx, my) == eLocationObject) { 
      Object *o = Object.GetAtScreenXY(mx, my);
      int x = o.X + Game.SpriteWidth[o.Graphic] / 2;
      int y = o.Y;
      player.Walk(x, y, eBlock);
      player.FaceObject(o, eBlock);
      o.RunInteraction(mouse.Mode);
    }
    else ProcessClick(mouse.x, mouse.y, mouse.Mode );
  }



Edit: fixed code

SwanOnARedCouch

Wow, thanks!
The character now moves to the object and faces it, but they interact with themself instead of the object. I suppose its because they are covering up the object? Also sometimes they move over to a hotspot and interacts with it instead. That happens when the mouse moves over a hotspot.
Is there a way to ensure interaction with the object that was clicked on and not the thing the mouse is pointig at after clicking?

CaesarCub

Maybe by changing line 12 of the previous code with:

Code: ags

    ProcessClick(mx, my, mouse.Mode );


You will be using the old mouse coordinates and not the ones where the mouse actually is.

SwanOnARedCouch

That worked, thanks a lot! Now the character isn't wandering off anymore. But they still interact with themselves when covering an object. I don't necessarily need interactions with the player character, so maybe that can be deactivated? Or is there a way where I can keep it?

Jack

Quote from: SwanOnARedCouch on Mon 03/10/2016 10:53:00
I'm having some problems with the code.

Oh yeah, screwed up a few things there. Like, the if (obj != null) statement needs { and } surrounding the cEgo command, and I wrote WalkTo, when the real command is Walk. But Khris' solution is preferable, hooking into on_mouse_click. You will probably additionally want to check which mode the mouse cursor is in so that you can limit to certain interactions only (Mouse.Mode == eModeInteract). This is based on some assumptions about your interface so you may or may not need it. Also, once you determine that this is an object that you want to walk to, you can probably skip the processclick and go directly to your scripted interactions where you will check which object it is and act accordingly. For this reason you should probably place such a block in every room script, otherwise the global script version of on_mouse_click will get large and messy. There are better ways than duplicating the code but I think that will get a bit ambitious for one post.

But it might go:

Code: ags

      else if (button == eMouseLeft)
      {
        int mx = mouse.x; int my = mouse.y;
        if ((Mouse.Mode == eModeInteract) && (GetLocationType(mx, my) == eLocationObject))
        {
          Object *o = Object.GetAtScreenXY(mx, my);
          int x = o.X + Game.SpriteWidth[o.Graphic] / 2;
          player.Walk(x, o.Y, eBlock);
          player.FaceObject(o, eBlock);

          switch (o.ID)
          {
            case 0: vaseInteraction(); // this is a user-defined function in the room script
            case 1: andSoForth();
          }
        } else {
          ProcessClick(mx, my, mouse.Mode);
        }
      }


Switch is a new feature and may not be in the AGS version you're using. It's a neater way to do a bunch of if...else if checks.

Clickable character can be disabled in general settings, but if you want a clickable character, the above method should still work.

Khris

Sorry, I was half asleep already ;)
You need to call
Code: ags
o.RunInteraction(mouse.Mode);
I fixed the code in my previous post.

SwanOnARedCouch

YAY! It worked! Khris' new code did the trick. It also started the interactions on the player character, but since I don't really need them, I removed them and now it works just fine.
Thank you all so much!
One last question: Can a variation of this code be used to make the character face hotspots after walking towards them? In that case all my problems would be solved.

Khris

#13
When I fixed my code I also added an "else" here:
Code: ags
else ProcessClick(mouse.x, mouse.y, mouse.Mode);

So a click will *either* run the object's interaction *or* process the click as usual, but not both. You shouldn't have to remove the player's interactions.

Anyway, to do the same for hotspots, you can try this:
Code: ags
  else if (button == eMouseLeft) {
    
    int mx = mouse.x; int my = mouse.y;
    int lt = GetLocationType(mx, my);
    if (lt == eLocationObject) { 
      Object *o = Object.GetAtScreenXY(mx, my);
      player.Walk(o.X + Game.SpriteWidth[o.Graphic] / 2, o.Y, eBlock);
      player.FaceObject(o, eBlock);
      o.RunInteraction(mouse.Mode);
    }
    else if (lt == eLocationHotspot) { 
      Hotspot *h = Hotspot.GetAtScreenXY(mx, my);
      player.Walk(h.WalkToX, h.WalkToY, eBlock);
      player.FaceLocation(h.WalkToX, h.WalkToY, eBlock);
      h.RunInteraction(mouse.Mode);
    }
    else ProcessClick(mx, my, mouse.Mode);
  }

SwanOnARedCouch

But doesn't
Code: ags
      player.FaceLocation(h.WalkToX, h.WalkToY, eBlock);

Make the player face the WalkTo point? Which they are already standing on? Because currently, the character seems to face a rather random direction.

Khris

Right, what you can do is place the walkto point a few pixels outside the walkable area. That way the player will get as close as they can, then turn to face in the direction of the walkto point.
The alternative is to remove the FaceLocation command and turn the player appropriately in the hotspot's interaction function.

SwanOnARedCouch

I didn't even consider placing the WalkTo points outside of the walkable areas. It was a bit tricky first, but it works out fine.
You can consider my questions answered and my problems solved :-D
Thank you!

SMF spam blocked by CleanTalk