Hi everyone.
In my mini-game, that I'm stubbornly handling INSIDE the actual game (because of an arcane and obscure reason), I have a little problem with the function AreThingsOverlapping.
When the Hero and a closed treasure box are overlapping I want the trasure box to open with an animation (with also floating scored points) and then add the score and consider that specific box as already collected (until the next game)
Ok, here's my piece of code (in room_RepExec())
if(AreThingsOverlapping(ISLANDHERO, 1000) && oScrigno1.Graphic==457) // 'Closed' sprite
{if(Scrigno1==false) // The box haven't been opened, GameDoOnceOnly is not suitable for my purpose
{oScrigno1.SetView(17, 0, 0); // The 'opening' view
if(!oScrigno1.Animating) // The box isn't animating
{oScrigno1.Animate(0, 6, eOnce, eNoBlock, eForwards);} // Start the animation
}
}
if(oScrigno1.Graphic==465) // 'Opened' sprite && final frame of the animation
{if(Scrigno1==false)
{Scrigno1=true; // The box have been opened
punteggio=punteggio+400;} //add score
}
Actually all the stuff (animation and scoring) begins when the hero and the treasure are NO MORE overlapping.
If I just stand in front of (overlapping) the treasure nothing happens, until I leave (outside the sprite border)... ???
I want the stuff running even if the hero is still overlapping the treasure.
What am I doing wrong?
What's the thing I don't understand?
Thank You all in advance.
EDIT: Modified the layout hopefully in a tidier way
I have no idea what the problem is but in a case like this what I do is check all components individually.
function Room_RepExec() {
// insert this at top
lblDebug.Text = String.Format("ATO return value: %d", AreThingsOverlapping(player.ID, oScrigno1.ID + 1000));
return;
....
}
Now put a label on the status bar or a similar GUI and call it "lblDebug".
Btw, your way of indentation is really weird and confusing and I head to reindent everything to have an actual look at the code. And to show code, you can use the code tags: [code] ... [/code]
Also, I take it there are going to be several of these chests; I'd really use generic code instead of copy-pasting it several times.
Ok, I inserted your code at the top:
lblDebug.Text = String.Format("ATO return value: %d", AreThingsOverlapping(ISLANDHERO, 1000));
without the 'return', because leaving that there will completely freeze the room (I have several things happening in room_RepExec).
It returned several values from 0 (non-overlapping) to 20 (I was in the middle of the treasure box) to 0 again (when I walked to the right 'leaving' the treasure).
Then the animation started.
I'm clueless...
Slightly OT:
For the 'generic' code, I used INFORM6 (Object based) before beginning with AGS and I'm actually wondering if it is possible to have some sort of "Classes of Objects" like in Inform, to have a thinner coding...
Something like this:
Class TREASURES
---properties---
---functions conditions---
---attributes---
;
then I could have in my code something like this
if(AreThingsOverlapping(ISLANDHERO, OBJECT))
{if(OBJECT ofClass TREASURES)
{blah blah blah my code;}
}
This once for EVERY object that is a children of the Class!
There is a 'simple' way to do things like this in AGS or I do need some advanced scripting knowledge?
EDIT:
I changed the 'debug line' into this:
lblDebug.Text = String.Format("ANIM return value: %d", oScrigno1.Animating);
and it continuosly returned 1 while standing in front of the 'frozen' treasure box, I left to the right, it returned 0 and the animation started.
So apparently AGS continuosly trigger the animation despite of my code.
Now I'm looking deeper into the code...
I should have realized this sooner but I know what the problem is.
It's actually a quirk in the engine.
The Object.Animating flag doesn't get set to true as soon as Object.Animating() is called.
When an object is supposed to be animated, AGS first adds the animation delay to the individual delay of each frame (usually 0), then displays each anim frame for that many game frames.
This means that the second frame of the animations is only displayed several loops after the .Animate() call, and I guess only at this point is .Animating set to true.
As a result, the animation gets started over and over again each loop, with each call canceling the previous one due to eNoBlock.
So as soon as you leave the area near the chest, the animation can actually start without being interrupted again.
Regarding the class question: you can use structs in AGS as in custom Objects that can have functions and variables as members.
You can also add functions to existing objects using an extender function.
In this case however, a simple array should do the job.
// top of room script
int open_state[];
// inside room_Load
open_state = new int[Room.ObjectCount];
// inside room_RepExec
int i;
while (i < Room.ObjectCount) {
if (!open_state[i] && AreThingsOverlapping(player.ID, object[i].ID + 1000)) {
open_state[i] = 1;
object[i].SetView(17, 0, 0);
object[i].Animate(0, 6, eOnce, eNoBlock);
}
if (open_state[i] == 1 && object[i].Graphic == 465) {
open_state[i] = 2;
punteggio += 400;
}
i++;
}
Indeed, the animation was triggered over and over....
Now that you helped me to address the problem I modified my lines into
if(AreThingsOverlapping(ISLANDHERO, 1000) && oScrigno1.Graphic==457)
{if(Scrigno1==false)
{if(!oScrigno1.Animating)
{oScrigno1.SetView(17, 0, 0);
oScrigno1.Animate(0, 6, eOnce, eNoBlock, eForwards);
}
if(oScrigno1.Graphic==465)
{if(Scrigno1==false)
{Scrigno1=true;
punteggio=punteggio+400;
}
}
}
}
and it work just as we expected. ^_^
I will go deep into your coding suggestion to figure it out completely before simply copying and pasteing into my code.
That really look like a useful slimming diet for my code! LOL
Many thanks Khris.
I'm surprised that this does work because as far as I can see you moved things around a but didn't solve the original problem. The animation should still be called every loop.
You're also testing for Scrigno1 being false a second time within the first test.
I figured out that it was firstly a matter of 'order of things', the biggest issue I had with AGS is that I was used to think 'one game loop after every action' (with IF the game do just one loop after each command/action you input) and not 40 loops per second!!
So with AGS the order in which you put conditions is much more relevant than ever because 40 different values can change in about a second giving you the feeling that nothing happened! lol (from time to time I forget about this thing...)
IMO is not that strange that this actually works, following the game loop:
if(AreThingsOverlapping(ISLANDHERO, 1000) && oScrigno1.Graphic==457)
//Ok, now we are overlapping so:
{if(Scrigno1==false) //not yet collected
{if(!oScrigno1.Animating) //not yet animating
{oScrigno1.SetView(17, 0, 0);
oScrigno1.Animate(0, 6, eOnce, eNoBlock, eForwards);
}
//I set the view and trigger the animation AFTER checking if an animation has been
//triggered the loop before, in this order the conditions prevent AGS to trigger the
//animation again during the next game loop.
//In the code used before I was setting the view BEFORE checking .Animating
//so the animation triggered the loop before stopped due to the .SetView call and
//not due to the frame delay.
Smooth... or not?
EDIT:
While testing I realized that opening the chest doesn't give points anymore, so I moved the scoring part of the script out from the AreThingsOverlapping call and ended with this:
if(AreThingsOverlapping(ISLANDHERO, 1000) && oScrigno1.Graphic==457)
{if(Scrigno1==false)
{if(!oScrigno1.Animating)
{oScrigno1.SetView(17, 0, 0);
oScrigno1.Animate(0, 6, eOnce, eNoBlock, eForwards);
}
}
}
if(oScrigno1.Graphic==465 && Scrigno1==false)
{Scrigno1=true;
punteggio=punteggio+400;
}
Now all seems well.
Right, it didn't even occur to me that .SetView sets .Animating to false.
Good job, and I'm sure you'll quickly to get used to the timing differences.
That indentation however... :=
I looked into that code you suggested me, the one using a dynamic array, and I ended up with this lines to handle all the treasures (Scrigno del tesoro) and money bags (Sacco di dobloni) and eventually other kinds of collectible valuables I might insert... just with adding a few lines!
in room_RepExec()
int totale;
while (totale < Room.ObjectCount)
{if(Tesori[totale]==0 && AreThingsOverlapping(ISLANDHERO, object[totale].ID+1000))
{if(object[totale].Graphic==457) //Scrigno del tesoro
{Tesori[totale]=1;
object[totale].SetView(17, 0, 0);
object[totale].Animate(0, 6, eOnce, eNoBlock);
}
if(Tesori[totale]==1)
{Tesori[totale]=2;
punteggio += 400;
}
if(object[totale].Graphic==466) //Sacco di dobloni
{Tesori[totale]=1;
object[totale].SetView(18, 0, 0);
object[totale].Animate(0, 6, eOnce, eNoBlock, eForwards);
}
if (Tesori[totale]==1)
{Tesori[totale]=2;
punteggio += 50;
}
}
totale++;
}
I was sort of scared approaching arrays in the past, they always looked complicated to me, but with your bit of code I think I understood them a little bit more...
And the code I came up with it's cool!
lol
Quote from: Khris on Tue 24/01/2012 22:28:04
That indentation however... :=
What's wrong with my indentation?
I always used this kind (also in INFORM6) and had no problems at all, actually, you are the first that comment on it... O_o
I think it's very clear and 'space' saving (I know that the empty lines doesn't affect the source code size, but affects how many times I have to scroll my window to check if all it's ok! lol)
See:
(http://i458.photobucket.com/albums/qq310/Miglioshin/GAMHFLB/Esempiodiindentazione.jpg)
EDIT:I looked further more into the code and I managed to streamline it a little bit more:
int totale;
while (totale < Room.ObjectCount)
{if(Tesori[totale]==0 && AreThingsOverlapping(ISLANDHERO, object[totale].ID+1000))
{if(object[totale].Graphic==457) //Scrigno del tesoro
{Tesori[totale]=1;
object[totale].SetView(17, 0, 0);
object[totale].Animate(0, 6, eOnce, eNoBlock);
punteggio+=400;
}
if(object[totale].Graphic==466) //Sacco di dobloni
{Tesori[totale]=1;
object[totale].SetView(18, 0, 0);
object[totale].Animate(0, 6, eOnce, eNoBlock, eForwards);
punteggio+=50;
}
}
totale++;
}
This works good! And it will work as it is even if I add more trasures! And since I'm allowed to use 40 objects per room this will be 1 second slow in the worst case! :o
This is AMAZING! 8)
Many thanks again Khris!!
About the indentation:
I have seen all kinds of different styles but yours is the only one so far where the if, the if's {} and their contents all have their own level of indentation.
I just think that those two are the most readable:
if (...) {
command1();
command2();
}
or
if (...)
{
command1();
command2();
}
But it's your code so whatever makes you happy :)
Quote from: Miglioshin on Thu 26/01/2012 15:43:40And since I'm allowed to use 40 objects per room this will be 1 second slow in the worst case! :o
Not at all; processing the entire loop only takes a fraction of a millisecond, even if it had to process hundreds of objects.
Imagine any blocking function (without any Wait() commands) would always take one game loop to process; that way the game's speed would fluctuate all the time, depending on which room you're in.
AGS doesn't work like Inform at all; each game loop, after all functions have been processed and the new screen has been drawn, AGS actually waits until the current game loops ends, otherwise most games would be impossible to control.
Quote from: Khris on Thu 26/01/2012 22:09:25
Quote from: Miglioshin on Thu 26/01/2012 15:43:40And since I'm allowed to use 40 objects per room this will be 1 second slow in the worst case! :o
Not at all; processing the entire loop only takes a fraction of a millisecond, even if it had to process hundreds of objects.
AGS doesn't work like Inform at all; each game loop, after all functions have been processed and the new screen has been drawn, AGS actually waits until the current game loops ends, otherwise most games would be impossible to control.
Oh... I see... so AGS goes far beyond my first thoughts on it... :o
VERY FAR BEYOND...
:=