[SOLVED] Function to quickly script Open\Close Doors

Started by LostTrainDude, Thu 13/09/2012 01:54:24

Previous topic - Next topic

LostTrainDude

I've searched a bit on the forum, but didn't find anything.

I'm trying to get better at scripting (which I'm kinda poor at) by learning how do some modules posted here work and by creating some new functions from scratch.

Given the premise that I'm using the "common way" to animate a "door opening" - 2 sprites: one becames invisible, the other becames visible - I don't actually know how to write a function that can automatize this Invisible\Visible switching and let it work with whatever object I want.

I'll post some "concept" code that I would like to actually realize. Of course, "Object1" and "Object2" are completely made up :)

Code: AGS

//Code in GlobalScript.asc
function VisibleSwitch(Object1, Object2)
{
  if (Object1.Visible == true) {
    Object1.Visible = false;
    Object2.Visible = true;
  } else if (Object1.Visible == false) {
    Object1.Visible = true;
    Object2.Visible = false;
  }
}


I seem not to get how to actually consider 2 Objects, it's like I could use a that along with a this keyword.
Sorry if this is quite silly, but I could actually learn a lot from this simple issue :)

Thanks a lot in advance!

EDIT:

Ok. I had the solution under my eyes and didn't notice it. Here I post the correct code for this function.

Code: AGS

//Code in Globalscript.asc
function VisibleSwitch(Object* ob1, Object* ob2)
{
  if ((ob1.Visible == true) && (ob2.Visible == false)) {
    ob1.Visible = false;
    ob2.Visible = true;
  } else if ((ob1.Visible == false) && (ob2.Visible == true)) {
    ob1.Visible = true;
    ob2.Visible = false;
  }
}


I forgot to actually NAME the variables within the function. That was it! Shame on me!

Just in case:
Code: AGS

//Code in Globalscript.ash

import function VisibleSwitch(Object* ob1, Object* ob2);
"We do not stop playing because we grow old, we grow old because we stop playing."

Khris

Or the short version:

Code: ags
function VisibleSwitch(Object* ob1, Object* ob2)
{
  ob1.Visible = !ob1.Visible;  // switch first object
  ob2.Visible = !ob1.Visible;  // set second to opposite of first
}


Just for reference, the other way to change a door's appearance is to change the object's .Graphic.

LostTrainDude

#2
Thanks a lot for this further explanation :)

Anyway I must tell that, even if I get the sense of the code you wrote "as a whole", I would like to see if I get the whole "explanation".

Whenever the function is called, it checks the 2 given parameters' visiblity.
So that:

  • If ob1 is not visible, sets it visible
  • If ob1 is not visible, sets ob2 visible
The bottom line, then, should be that: if I can see ob1 as visible, it's because ob2 is not. The correct execution of this function, obviously, depends by the fact that when it's called, one of the two objects has to be not visible.

Do I get it right?
Thanks a lot for your help :)
"We do not stop playing because we grow old, we grow old because we stop playing."

Crimson Wizard

#3
Quote from: LostTrainDude on Thu 13/09/2012 13:59:37
Anyway I must tell that, even if I get the sense of the code you wrote "as a whole", I would like to see if I get the whole "explanation".

Whenever the function is called, it checks the 2 given parameters' visiblity.
So that:

  • If ob1 is not visible, sets it visible
  • If ob1 is not visible, sets ob2 visible
If you are seeking an accurate explanation, it would rather be:

  • make obj1 visibility opposite to what it is now
  • make obj2 visibility opposite to what obj1 visibility became

Or, more formal and expanded:

  • If ob1 is visible, make it not visible; otherwise (if it is not visible) make it visible
  • If ob1 is NOW visible, make obj2 be not visible; otherwise (if obj1 is not visible) make obj2 be visible

Quoteif I can see ob1 as visible, it's because ob2 is not.
No, it's opposite:
if I can see obj2 as visible it's because obj1 is not.

QuoteThe correct execution of this function, obviously, depends bye the fact that when it's called, one of the two objects has to be not visible.
This is too incorrect. The function may be called with any initial states, it will set object states to properly opposite ones.
That is because the second line will be executed with obj1 visibility already changed.

LostTrainDude

Quote from: Crimson Wizard on Thu 13/09/2012 14:18:04
Or, more formal and expanded:

  • If ob1 is visible, make it not visible; otherwise (if it is not visible) make it visible
  • If ob1 is NOW visible, make obj2 be not visible; otherwise (if obj1 is not visible) make obj2 be visible

Then maybe I should interpret the '!' as an "opposite-marker" rather than a "simple" 'NOT'
That 'NOW' you wrote, actually poked me in the eyes as the two lines of code are executed sequentially. I can't think of a more basic rule of programming! Shame on me! (again) :)

Quote from: Crimson Wizard on Thu 13/09/2012 14:18:04
if I can see obj2 as visible it's because obj1 is not.

This is because the expression has a "right to left" associativity, right?

Quote from: Crimson Wizard on Thu 13/09/2012 14:18:04
The function may be called with any initial states, it will set object states to properly opposite ones.
That is because the second line will be executed with obj1 visibility already changed.

Maybe I've explained myself wrong, I spoke out of context. I'll try again.

Considering that:

  • The function has to be triggered by the player's interaction
  • The parameters are used for two door sprites that have to be alternatively visible in the room
I've tested two situations:

  • If I set the two doors to be both not visible
I won't be able to see any of the two as I enter the room

  • If I set them to be both visible
If I call the function this way:

Code: AGS

//room script
function oCDoor1_Interact() //Closed Door sprite
{
  VisibleSwitch(oODoor1, oCDoor1);
}

function oODoor1_Interact() //Opened Door sprite
{
 VisibleSwitch(oODoor1, oCDoor1); 
}


or this way:

Code: AGS

function oCDoor1_Interact()
{
  VisibleSwitch(oCDoor1, oODoor1);
}

function oODoor1_Interact()
{
 VisibleSwitch(oODoor1, oCDoor1);
}


What I get is:

  • first I see the closed door
  • it disappears on the second time I click on it, while the opened one appears
  • if I click on the opened one, it diappears while the closed one appears again
  • the closed one disappears correctly on the first click, from now on
While if I call the function this way:

Code: AGS

function oCDoor1_Interact()
{
  VisibleSwitch(oCDoor1, oODoor1);
}

function oODoor1_Interact()
{
 VisibleSwitch(oCDoor1, oODoor1);
}


or this way:

Code: AGS

function oCDoor1_Interact()
{
  VisibleSwitch(oODoor1, oCDoor1);
}

function oODoor1_Interact()
{
 VisibleSwitch(oCDoor1, oODoor1);
}


I get what I want, that is:

  • first I see the closed door
  • it disappears on click, while the opened one appears
  • if I click on the opened one, it diappears while the closed one appears again

I apologize if I'm overthinking this, or if I'm contradicting myself while trying to learn deeply :) Please feel free to let me notice of both!
"We do not stop playing because we grow old, we grow old because we stop playing."

monkey0506

#5
Just to further complicate the matter, I'd say you should scrap the second object and just stick to one. In the sprite manager make sure that the open door sprite is an odd number (you can right click and change the sprite number if you need to) and then make sure that the closed door sprite is the very next number (so it's even).

So, for example, if you delete oCDoor1 then you could rename oODoor1 to just oDoor1. You would set its graphic to the closed door sprite, and its visibility to true. Then, at the top of the room script you could add these functions:

Code: ags
bool IsOpen(this Object*)
{
  return ((this.Graphic % 2) == 1); // % is the modulo (or remainder) operator - if dividing by two has a remainder, the result is odd, so the door is open
}

void Open(this Object*)
{
  if (this.IsOpen()) return; // if the door is already open, ignore
  this.Graphic++; // otherwise, increase the graphic to the closed door sprite
}

void Close(this Object*)
{
  if (!this.IsOpen()) return; // if the door is NOT open (it is already closed), ignore
  this.Graphic--; // otherwise, decrease the graphic to the open door sprite
}

void ToggleOpen(this Object*)
{
  if (this.IsOpen()) this.Close(); // if door is open, call Close
  else this.Open(); // else door is closed, call Open
}


With these functions, you can now call them like this:

Code: ags
function oDoor1_Interact()
{
  oDoor1.ToggleOpen(); // toggle between open and closed door
}

Crimson Wizard

#6
Now, wait wait there, monkey, let's not complicate the matter anymore further for now, ok? :D
One step at a time, otherwise my head will burst too.

Quote from: LostTrainDude on Thu 13/09/2012 17:54:30
Then maybe I should interpret the '!' as an "opposite-marker" rather than a "simple" 'NOT'
Well, NOT ('!') is a boolean (logical) operand that gives boolean (logical) opposite value.
It works very simple, but you should get used to it.

For bool variables that simply changes them from TRUE to FALSE and back.
For integer (numbers) that work so:
- any number other than 0 (that counts as TRUE) is transformed into FALSE;
- 0 (which counts as FALSE) is transformed into TRUE.
Uh, just to ensure this is clear, that means:
- number 10 is different from 0, this means it is treated as TRUE. Therefore the result of !10 is FALSE.
- number -22 is different from 0, this means it is treated as TRUE. Therefore the result of !(-22) is FALSE.
- number 0 is treated as FALSE. Therefore the result of !0 is TRUE.

In this case "Visible" is an Object's propery of type bool, so it is either TRUE or FALSE. The NOT operator (!) applied to 'Visible' gives opposite value (FALSE for TRUE and TRUE for FALSE).



Quote from: LostTrainDude on Thu 13/09/2012 17:54:30
Quote from: Crimson Wizard on Thu 13/09/2012 14:18:04
if I can see obj2 as visible it's because obj1 is not.

This is because the expression has a "right to left" associativity, right?

Well, that too, but I'd say that's because the obj1 visibility is being set first depending only on its own value, and obj2 visibility is being set after that based on obj1 value. So, obj2 visibility depends on obj1 (but obj1 actually do not depend on obj2).


Quote from: LostTrainDude on Thu 13/09/2012 17:54:30
Quote from: Crimson Wizard on Thu 13/09/2012 14:18:04
The function may be called with any initial states, it will set object states to properly opposite ones.
That is because the second line will be executed with obj1 visibility already changed.

Maybe I've explained myself wrong, I spoke out of context. I'll try again.
<...>
[many examples here]
<...>
I apologize if I'm overthinking this, or if I'm contradicting myself while trying to learn deeply :) Please feel free to let me notice of both!

Allright... ugh... my answer was too formal and I was speaking strictly of function execution without any context.
Let's say this: the exact visibilities after the function was executed are ofcourse different depending on what they were before the function call.
What I meant is simply this: as a result of function they will be opposite regardless of initial state. Ofcourse that "opposite" may mean that either first is on and second is off or vice versa depending on preliminary state.

So, to simplify things, set your objects one visible and another not visible, depending on what starting condition you are aiming. Either door is opened or it is closed, no third option, otherwise there will be glitch when the function is called for the very first time, which is unacceptable.

Oh, hopefully that won't complicate things, but I'd just want to note this: if both objects are made initially visible they will be both visible, just one will be drawn afront of other making an illusion that only one is shown. That is defined by so called "Z"-value (the order of drawing), in AGS that's controlled by Object's Baseline property, which I won't discuss here to save our minds, it is a separate question.

//--------------------------------
Now, when (if) that is clear, you may check monkey_05_06's solution which is to use only one object and change it's graphic, which is actually better in my opinion.

Just a small tip: make sure you BOTH sprites are of the same size, possibly "open" state having extra empty space to compensate the differenece, otherwise your door will visually (but not really) change position when changing state.

SMF spam blocked by CleanTalk