Character interactions with objects/hotspots.

Started by Brian925, Thu 07/12/2017 04:14:15

Previous topic - Next topic

Brian925

I'm using the default AGS template with VIEW 1 and VIEW 2 default views for walking and talking. Right now I'm trying to get my character to click an object (video game controller) and that would make my character sit down in front of the TV and start playing video games. My first instinct is to create a loop of him shifting while sitting in a new view(3), creating a hotspot over the controller and having the any click option call out to
Code: ags
character.ChangeView(3);


I tried this and nothing happened. Is there a simple way to get the character to interact with a hotspot that took him out of the walk cycle and into an animation of him sitting? Thanks.

Snarky

I think there's a bit more to it than that, but first of all: is your character name "character"? (I doubt it, because I think it's a reserved name in AGS.) When you have a function like Character.ChangeView(), you have to replace "Character" with the name of your character (or some other pointer, like player). For example, cGuybrush.ChangeView(3); or player.ChangeView(3);

Also, you know how you can give the each view a name? You can use those names instead of just the view number in the code, which makes it easier to follow when you read. Compare:

Code: ags
character.ChangeView(3);


and

Code: ags
cBob.ChangeView(BOB_VIDEOGAMING);


Reading the first version, you can't tell what's going on. In the second version, it's self-explanatory.

Khris

There are two separate issues here. The first is to get AGS to do anything at all when you click the controller. To make sure this is happening, the function that contains your code has to be linked to the hotspot event. How to do this is explained in the manual's tutorial: http://www.adventuregamestudio.co.uk/manual/acintro3.htm (bottom half)

Just put a Display("It works"); inside the function for now. Also, I'd probably use the "interact with hotspot" event, not "any click on hotspot". How is your game's interface set up? Are you using the BASS template? Or the Default one?

Once that works, you can focus on the script commands; you'll want to not just set the character's view but also .Animate() them. In this case, LockView() is a better choice. Again, this is explained in the manual, in the "Character" section, on the page for "Animate" (i.e. easy to find once you have a basic grasp of the manual's structure).


Finally. When you are about to open a topic here, take a few seconds to think about how likely it is that somebody else has already had the exact same problem. Chances are, there's at least one existing thread about any common beginner's issue. Try to find that first, before hitting that "New Topic" button.

Brian925

apologies for anything already posted; i tried to navigate the board and didn't find anything based on my keywords. maybe i need to learn the terminology a bit.

Thanks for the advice though, it worked well. I managed to get my guy to sit down using:
Code: ags
function oController_AnyClick()
{
  cBob.ChangeView(2);
  cBob.ChangeRoom(1, 540, 320);
cBob.Animate(1, 5,  eOnce, eNoBlock);
}


This successfully got my character to sit in front of the tv and play the game. Now i would like him to get up and walk in the original first View instead of the second if the walking option is clicked. I added this code in, but it told me it could not be nested?
Code: ags
function AnyClick ()
{
cBob.ChangeView(2);
}


So, in my character's code, this is what i have in its entirety for this function.
Code: ags
function oController_AnyClick()
{
  cBob.ChangeView(2);
  cBob.ChangeRoom(1, 540, 320);
cBob.Animate(1, 5,  eOnce, eNoBlock);

function AnyClick()
{
  cBob.ChangeView(1);
}


Any help is appreciated!

Khris

You basically ignored everything I said / asked in my post (except for the last bit, it seems). If you don't want my help, that's fine, but at least say so instead of casually skipping over my post completely.

Brian925

wasnt my intention to skip over, you were just a couple steps ahead of what i had processed. I'll re read and try with the advice.


Snarky

Quote from: Brian925 on Fri 15/12/2017 02:32:22
So, in my character's code, this is what i have in its entirety for this function.
Code: ags
function oController_AnyClick()
{
  cBob.ChangeView(2);
  cBob.ChangeRoom(1, 540, 320);
cBob.Animate(1, 5,  eOnce, eNoBlock);

function AnyClick()
{
  cBob.ChangeView(1);
}


Any help is appreciated!

There are three problems with this code:

1. You're missing the end-curly-bracket } at the end of oController_AnyClick(). That's why it's complaining about nested functions: you're trying to declare function AnyClick() inside another function.
2. When do you want function AnyClick() to be called, and how do you expect this to happen?
3. Line 5, cBob.Animate(), is wrongly indented. This is just a matter of formatting, but it's an important part of writing code, and it's better to get into the right habits from the start. If you'd been consistent about this, maybe you would have spotted problem 1 yourself.

Points 1 and 2 make me wonder if you really understand what a function is, and how the syntax works.

Brian925

1. The end bracket was an oversight, thanks for the catch.
2. I was trying to make it so the character would sit in front of the TV until any click happened, and then he'd return to the original walking view. Since the click was not associated with an object, I wasn't sure if I needed to declare a new function or not.
3. Noted. Organization is clutch.


After considering Khris' post, I changed the code to this:
Code: ags
function oController_Interact()
{

cBob.LockView(2);
cBob.Animate(1, 5, eRepeat, eNoBlock, eForwards);
cBob.UnlockView();


}

I thought the Repeat/Once and ENoBlock and eBlock options would enable me to loop the view while allowing a button press to return the sitting view to the walk cycle view.
eRepeat and eNoBlock seems to skip the View 2 animation altogether and return to View 1 facing a different direction. Hopefully I'm more on the right track now.


As far as function and syntax, I'm still learning. I understand that a function is called out and the brackets hold the action associated. I just didn't know if I needed to create a different function when I needed a mouseclick without an object.

Snarky

#8
You're still not indenting the code correctly. Here's how it should be formatted:

Code: ags
function oController_Interact()
{
  cBob.LockView(2);
  cBob.Animate(1, 5, eRepeat, eNoBlock, eForwards);
  cBob.UnlockView();
}


The rule is really very simple: between the { and } brackets, you indent by one level (which is usually two spaces in AGS). You align the matching brackets vertically with each other. All together, this makes up a code block. If you have another block inside this block (for example after an if-statement, or the body of a loop), you indent it by another level. For example:

Code: ags
function oController_Interact()
{
  cBob.Say("Let's see... Do I feel like playing computer games right now?");
  if(bobWantsToPlayComputerGames)
  {
    cBob.LockView(2);
    cBob.Animate(1, 5, eRepeat, eNoBlock, eForwards);
    cBob.UnlockView();
  }
  else
  {
    cBob.Say("Nah!");
  }
}


Except that if you have a block with only one line of code (like the else-block here), you don't need the curly brackets, so you can just write:

Code: ags
function oController_Interact()
{
  cBob.Say("Let's see... Do I feel like playing computer games right now?");
  if(bobWantsToPlayComputerGames)
  {
    cBob.LockView(2);
    cBob.Animate(1, 5, eRepeat, eNoBlock, eForwards);
    cBob.UnlockView();
  }
  else
    cBob.Say("Nah!");
}


See? Easy!

Quote from: Brian925 on Fri 15/12/2017 23:24:05
2. I was trying to make it so the character would sit in front of the TV until any click happened, and then he'd return to the original walking view. Since the click was not associated with an object, I wasn't sure if I needed to declare a new function or not.

[...]

I just didn't know if I needed to create a different function when I needed a mouseclick without an object.

Well, there are ways to make sure a function is called on any click even if it's not over an object, but it's a little more involved. You can't just name the function AnyClick() and expect AGS to automatically call it. AGS doesn't for the most part understand or care about your function names. There are a few built-in names with special meaning, but usually you have to make sure the function is hooked up to an event, or called from some other function. In this case, you could for example call it from the on_mouse_click() function (on_mouse_click() is one of those built-in functions, and automatically gets called any time the mouse is clicked). However, you would need to keep track of when to call it, since you don't want this to happen on any mouse click anywhere in the game.

There's an easier way, which doesn't require a separate function. First, let's see why your function doesn't quite work. It's because when you call cBob.Animate() with eNoBlock, that function doesn't block (logically enough). This means the program immediately goes on to the next line, where you unlock Bob's view. When that happens, Bob reverts to the standard standing/walking view, and the animation is interrupted.

So you do need it to block during the animation. Unfortunately, Animate() can't take something like eBlockUntilMouseClick as an option, but what you can do is insert a WaitMouseKey() line between the Animate() and UnlockView() calls:

Code: ags
function oController_Interact()
{
  cBob.LockView(2);
  cBob.Animate(1, 5, eRepeat, eNoBlock, eForwards);
  WaitMouseKey(GetGameSpeed()*60); // Blocks for one minute, or until player presses a mouse button or keyboard key
  cBob.UnlockView();
}


This does almost what you specified. It will block until a user clicks a mouse button... or a keyboard key... and it will time out automatically after a minute. (You can make the duration longer, but the maximum is about 13:40 at the default game speed.)

Maybe that's good enough for you. If not, you would have to write it some other, more complicated, way. Or you could use the code I recently wrote for exactly this situation. Create a new script, copy that code into it, and call it like this:

Code: ags
function oController_Interact()
{
  cBob.LockView(2);
  cBob.Animate(1, 5, eRepeat, eNoBlock, eForwards);
  BlockMouse(); // Blocks until player clicks a mouse button
  cBob.UnlockView();
}

Brian925

All super helpful information. I always wondered why single line commands seemed to be floating sometimes like they were completely separate from their preceding statements. I think I need to get familiar with the built in functions. There might be a lot of things there are commands for that I'm not aware of. 

SMF spam blocked by CleanTalk