Solved: Sitting down on a chair

Started by johanvepa, Tue 19/03/2013 21:18:16

Previous topic - Next topic

johanvepa

A question from a hopeless newbie:

I want cEgo to sit down on a chair.
So I make a function when interacting with the chair resulting in Ego walking to the chair (blocking walk), then setting the chairs view to a picture having ego sitting in it.

So far, so good. The chair now looks like Ego is sitting in it.

But what about Ego himself?
Well, I try to make him invisible by setting his transparency to 100, but he can still walk around, open doors, leave the room etc.
Is there a way to make the transparent Ego rigid while he is "sitting in the chair", or am I missing something real simple here?




Example from my room script. Its working, apart from the invisible poltergeist cEgo stalking around:

Code: AGS

bool isegoseated;

function room_FirstLoad()
 {
 isegoseated = false;  //ego is not sitting down yet
 oChair.SetView(24, 0);  //empty chair
 }


function oChair_Interact()
 {
 if (isegoseated == false)
   {
   cEgo.Walk(147, 123, eBlock, eWalkableAreas);
   cEgo.Transparency = 100;  //ego poltergeist
   oChair.SetView(24, 1); //ego in chair
   isegoseated = true;
   }
 else
   {
   cEgo.Transparency = 0;
   oChair.SetView(24, 0); //ego not in chair
   isegoseated = false;
   }
 }

Cerno

Hi Nanuaraq.

Newbie here myself, so please take this with a grain of salt.

How about changing the character view to a sitting position and place the character on the chair. That way you can still use all the character-related functions and don't have to deal with switching off the character and so on.
If pinpointing the character onto the chair is too difficult, maybe you can make the chair part of the character view and place the whole thing on top of the existing chair.
123  Currently working on: Sibun - Shadow of the Septemplicon

johanvepa

Yeah, I wondered if it could be done by having Ego lockview to a view where he is sitting in the chair. But I guess that still wouldn't stop him walking around. Then I would have Ego in a chair floating around the room?

Having him invisible means I can still use all characterrelated interactions, like eating food on the table, talking to the person next to him, talking to the waitress etc. I just need a function keeping him from walking away from the spot.

Cerno

Okay, I haven't thought about that. Could you overload the interact functions to make him stop walking around? Repeatedly_execute placing him back on his chair position? Loading a different walkable area so that he is stuck?
I'm clearly at the end of my rope here, better wait for the regulars to arrive ;)

I'd still say that changing the character into a sitting view and somehow making him stop whatever he's not supposed to do (like walking around) would be more natural than turning him into an object.

Just out of curiosity: What do you want to do once the character is sitting? Should he be able to interact with the stuff on a table, or is his only option standing up again?
123  Currently working on: Sibun - Shadow of the Septemplicon

Ghost

#4
One simple solution would be to make "isEgoSeated" a global variable and test against it in the global script's "on_mouse_click" function, where all clicks are processed. As long as isEgoSeated, verbs like look and talk might still work, but walk, interact etc could be restricted. This would also allow you to set up generic responses to failed actions instead of having to write them individually ("I can't use that... unless I get off the chair!").

This would be overkill for a single small puzzle, but if you have more than one chair to sit on, or plan to use several scenes where it happens, it's a valid solution.

johanvepa

Well, I got food and a drink for him on a plate that the waitress placed there. Got a neat little function setting the objects' transparencies, so Ego can interact with the food if transparency is 0 (food is on the table) and nothing happening if transparency is 100 (no food). I even got the view to change into an empty plate afterwards. Can't remember all the code, though.

I'll also have him talk to other people.

Anyway, I solved the walking away problem. When interacting with the chair, in addition to "setting the object's view into ego sitting down", I had ego blocking walk to a point beside the chair. Then I placed a hotspot underneath his feet and a function on the hotspot making ego repeatedly walk to that point, but only if he is invisible. It works. the moment He stands up, he becomes visible and walks freely.

Ghost

That's a soltion but you should make really sure that players can't break it with fast clicks or something. Setting a data value and making functionality depend on it can be complicated, but it's usually safer. If it works, however, it sounds like a simpler way indeed  ;-D

johanvepa

Oh, I like simple. Simple is the real me.

I also worked a bit more on it:

I created another view for the character (4 loops, one for each direction, otherwise it doesn't work). This view consist of empty sprites, nothing but transparency there. Then instead of using transparency, I just lockview the character unto that "not there"-view when he is sitting in the chair. This also stops messages popping up when interacting with or looking at the invisible character (Like the "Damn I'm looking good" message). When interacting with the chair again, Ego gets up, and I unlock the view.

It's impossible to break the little holding spell on the lockviewed Ego since he is continuously walking towards the same point. The hotspot is large, too.

johanvepa

#8
Oh, and here's the code:


Code: AGS

function oChair_Interact()
{
if (isegoseated == false)
 {
 cEgo.Walk(147, 123, eBlock, eWalkableAreas);
 cEgo.LockView(25);  //ego not visible and not clickable
 oChair.SetView(24, 1); //ego in chair
 cEgo.Walk(137, 125, eBlock, eWalkableAreas);
 isegoseated = true;
 }
else
 {
 cEgo.UnlockView(); //ego becomes visible and clickable
 oChair.SetView(24, 0); //ego not in chair
 isegoseated = false;
 }
}


function hDontwalk_WalkOn()   //walking on the hotspot that directs him towards the point in front of the chair
{
if (isegoseated == true)
 {
 cEgo.Walk(137, 125, eNoBlock, eWalkableAreas); //since ego is standing on the hotspot he will continuously walk towards this point
 }
}




Khris

You can add an on_mouse_click function to the room script:

Code: ags
function on_mouse_click(MouseButton button) {

  // only intercept left clicks on room
  if (button != eMouseLeft) return;

  int mx = mouse.x, my = mouse.y;

  // if the player isn't sitting in the chair, exit here; leads to default click handling in global script
  // you don't need a view unless you want to animate the chair object, you can change oChair.Graphic
  if (oChair.Graphic != sprite_slot_of_ego_sitting_in_chair) return;

  // at this point, player is in chair

  // check for object under mouse
  int lt = GetLocationType(mx, my);
  if (lt == eLocationObject && Object.GetAtScreen(mx, my) == oFood) return; // default handling for food

  // we can still look at things
  if (mouse.Mode == eModeLookat) return;

  player.Say("I'd have to get up first.");
  ClaimEvent();   // prevent default click handling
}


You can extend this any way you want.

The general idea is to not do stuff that doesn't also happen in the game world, i.e. if the food isn't on the table, don't just set it to be transparent but set the .Visible property to false.
You should never do stuff like continuously send the player to their current coordinates just to prevent them from walking somewhere else. It's really messy and will likely cause problems elsewhere.

And, like I did in my example code, never use variables when you can check something else instead. A view changes while the player sits? Just check the view directly.
The more you use the actual properties of game world objects as far as they are reflected by AGS properties (visibility, current sprite, coordinates, etc.), the more readable and less error-prone your code will be.

Demicrusaius

Maybe you should use RemoveWalkableArea(1); and the Restorewalkablearea(1);
I think having the chair as part of Ego's view, not using transparency and toggling walkable areas upon sitting/standing seems the best & easiest way to go.
It is better to light one small candle than to curse the darkness.

Intense Degree

Quote from: Khris on Wed 20/03/2013 03:31:47
And, like I did in my example code, never use variables when you can check something else instead. A view changes while the player sits? Just check the view directly.
The more you use the actual properties of game world objects as far as they are reflected by AGS properties (visibility, current sprite, coordinates, etc.), the more readable and less error-prone your code will be.

A quick question if I may. (I'm not trying to be clever here, this is an honest question that my feeble mind can't get to grips with!)

By the above logic do we need the variables MX and MY? Or is there a reason not to do the following?

Code: AGS
int lt = GetLocationType(mouse.x, mouse.y);
 if (lt == eLocationObject && Object.GetAtScreen(mouse.x, mouse.y) == oFood) return; // default handling for food


Khris

Even though it is extremely unlikely for the mouse coordinates to change in such short time spans, storing the variables at the time of the click ensures that GetLocationType and Object.GetAtScreen use the same coordinates. The code might be different, the two might be further apart; there might in some cases even be a Wait(1) in between, etc.

The early Maniac Mansion Mania template had a very annoying bug where the game would crash with a null pointer error if you moved the mouse while the player said something after interacting with a character, precisely because the game didn't use the click coords but the current ones and didn't do a != null check for the Character*. It came up in the tech section constantly and was a pain in the ass.

Plus, I'm using very short, local variables. They don't accumulate at the top of my scripts, and they are much faster to type, especially if used several times.

Had I only used the mouse position in one command, I wouldn't have bothered creating them.


johanvepa

#14
Quote from: Khris on Wed 20/03/2013 03:31:47
You can add an on_mouse_click function to the room script:

Code: ags


You can extend this any way you want.

The general idea is to not do stuff that doesn't also happen in the game world, i.e. if the food isn't on the table, don't just set it to be transparent but set the .Visible property to false.
You should never do stuff like continuously send the player to their current coordinates just to prevent them from walking somewhere else. It's really messy and will likely cause problems elsewhere.

And, like I did in my example code, never use variables when you can check something else instead. A view changes while the player sits? Just check the view directly.
The more you use the actual properties of game world objects as far as they are reflected by AGS properties (visibility, current sprite, coordinates, etc.), the more readable and less error-prone your code will be.
[/quote]


Whoa, much too complicated for me. I'm way out on my depth for something as advanced as this. Seeing as I can make it work with my simple tools, I think I prefer it to stay that way, with all due respect, and thank you for your kind help.

Instead of using transparency though, I think using views, loops, and frames of loops, may be much better and simpler. Perhaps also, instead of using bool isEgoseated, I could make do with using a check on what view the chair (or cEgo) is set to.

But what is the problem with having cEgo walk continuously, except for it being "messy"? It works well with me, and I cant really see any error possibilities coming up.

EDIT: I can't seem to make it work if I simply check the view of the chair. I would expect it to be something like this:

[code=AGS]
if (oChair.View == 24, 0, 0)     //if the view of the chair is the view, loop and frame showing cEgo not sitting in the chair
 {                            //then have cEgo walk to the chair and sit down 
 cEgo.Walk(147, 123, eBlock, eWalkableAreas);
 cEgo.LockView(25);  //ego not visible and not clickable
 oChair.SetView(24, 1); //ego in chair
 cEgo.Walk(137, 125, eBlock, eWalkableAreas);
 }



What am I doing wrong here?

Khris

#15
oChair.View is a single number, you can't compare loop and frame all at once like that.
But you don't need to anyway.
Code: ags
if (oChair.View == 24)


Quote from: Nanuaraq on Wed 20/03/2013 19:44:14But what is the problem with having cEgo walk continuously, except for it being "messy"? It works well with me, and I cant really see any error possibilities coming up.
If you want to put a framed picture up on the wall, do you use a nail, or do you hire two guys who hold it in position in turns? It's just extremely bad practice to "solve" issues in such ways. Sure, it might work, but there can always be unforeseen consequences. Technically, the character is moving the entire time, although they're the exact opposite of moving. A module that relies on Character.Moving being correct can screw up everything. So at that point, you have to go back and change the code anyway.
If you just want to kludge this together and don't care about using the proper tools, I won't bother you any longer though :)

johanvepa

Quote from: Khris on Wed 20/03/2013 20:39:17
oChair.View is a single number, you can't compare loop and frame all at once like that.
But you don't need to anyway.
Code: ags
if (oChair.View == 24)


Quote from: Nanuaraq on Wed 20/03/2013 19:44:14But what is the problem with having cEgo walk continuously, except for it being "messy"? It works well with me, and I cant really see any error possibilities coming up.
If you want to put a framed picture up on the wall, do you use a nail, or do you hire two guys who hold it in position in turns? It's just extremely bad practice to "solve" issues in such ways. Sure, it might work, but there can always be unforeseen consequences. Technically, the character is moving the entire time, although they're the exact opposite of moving. A module that relies on Character.Moving being correct can screw up everything. So at that point, you have to go back and change the code anyway.
If you just want to kludge this together and don't care about using the proper tools, I won't bother you any longer though :)

Oh please do bother me. I'm learning a lot from all this. But I have to keep myself entertained too, as I go along. With a learning curve too steep, there won't be time for some fun.

Snarky

Quote from: Nanuaraq on Wed 20/03/2013 19:44:14
Whoa, much too complicated for me. I'm way out on my depth for something as advanced as this.

Actually, Khris's solution is less code than yours, and works in a simpler way (it amounts to: if the player is sitting in the chair, refuse to do any action other than "look," or anything to do with the food). If you spend a couple of minutes to work it out, and look up ClaimEvent() in the manual, you'll see that it's not difficult at all. (You would need to add a way to actually get up from the chair, though. He forgot about that.)

The advice he gave you, that whenever possible it's best to base the programming logic on what's actually going on in the game, is a very good principle to follow as a guide. Having your character walking around invisibly, with a "hologram" appearing to sit in the chair, could cause all kinds of unexpected effects once your game logic becomes more complex.

Also, if walking on a certain hotspot (seems like this should be a region, BTW) causes the character to continuously walk to that spot (i.e. getting stuck), isn't there a risk that he could accidentally walk on it and become stuck even when he's not supposed to be sitting in the chair?

johanvepa

Quote from: Snarky on Wed 20/03/2013 21:35:47
Actually, Khris's solution is less code than yours, and works in a simpler way (it amounts to: if the player is sitting in the chair, refuse to do any action other than "look," or anything to do with the food). If you spend a couple of minutes to work it out, and look up ClaimEvent() in the manual, you'll see that it's not difficult at all. (You would need to add a way to actually get up from the chair, though. He forgot about that.)

The advice he gave you, that whenever possible it's best to base the programming logic on what's actually going on in the game, is a very good principle to follow as a guide. Having your character walking around invisibly, with a "hologram" appearing to sit in the chair, could cause all kinds of unexpected effects once your game logic becomes more complex.

Also, if walking on a certain hotspot (seems like this should be a region, BTW) causes the character to continuously walk to that spot (i.e. getting stuck), isn't there a risk that he could accidentally walk on it and become stuck even when he's not supposed to be sitting in the chair?

Is there a difference between a region and a hotspot for this specific purpose?

Anyway, the risk you mention doesn't happen in the solution I made here. When Ego walks around, he stomps on the hotspot all the time, but it only activates the character.walk command when he's "sitting in the chair". And my game logic isn't more complex than that   :)
Perhaps when it does become complex, I will have to learn more.

Really, I really do appreciate all of your help, and I'm very happy that you're taking the time. This forum is a real gem. I'm sorry if you feel that my not heeding all of your advice is being ungrateful. We have a saying in Denmark: "If you want to hit the treetops, aim for the stars". Without your advice, I wouldn't have gotten halfway to where I am now, even if I don't do everything the "right" way.

And if we're discussing whats simple or not, well, I do think I found a simple solution in just turning the character view "off" and have him stay in the same spot. The solution with turning "off" the mouse click could provide basis for bugs too, yes? I only need to prevent him leaving the room, no more than that. This should keep in principle with the philosophy of whats actually going on in the game.

And thank you for the ClaimEvent pointer. Did look it up, looks very useful.

Ghost

A region is a part of the screen that allows you to check if a character enters, leaves, or is currently standing "in". A hotspot is a part of the screen that can respond to any interaction you write. That's the difference- a hotspot can be used for any "thing" that the player must interact with but that needs no animation, and that cannot be removed. Regions are useful to create screen exits or special effects. So there's quite a difference between them ;)

SMF spam blocked by CleanTalk