I have an animation where a character reaches down to pick up something on the ground, but I can't make the object disappear at just the right moment. The animation is too long and I wish it could know exactly which frame the frame where the object is taken is in, to make a call just at that moment so that it disappears at the right moment. I've sometingh like that:
function oCacerolas_PickUp()
{
cPerxeo.Walk(1037, 938, eBlock, eWalkableAreas);
cPerxeo.FaceDirection(eDirectionUpRight);
cPerxeo.LockView(3);
cPerxeo.Animate(0, 0, eOnce, eBlock);
Wait(2);
oCacerolas.Visible=false;
player.AddInventory(iCacerolas);
cPerxeo.Say("I've the pans with me!!!.");
cPerxeo.LockView(1);
cPerxeo.UnlockView();
cPerxeo.FaceDirection(eDirectionUpRight);
}
The solution is to run animation non-blocking and then wait until it finishes right in the same function.
If you will additionally check for the current frame, you will know when to do object changes.
cPerxeo.LockView(3);
cPerxeo.Animate(0, 0, eOnce, eNoBlock); // notice eNoBlock
while (cPerxeo.Animating)
{
if (cPerxeo.Frame == SOME_FRAME)
oCacerolas.Visible=false;
Wait(1); // Wait lets engine to update and redraw the scene
}
cPerxeo.UnlockView();
player.AddInventory(iCacerolas);
cPerxeo.Say("I've the pans with me!!!.");
I also removed unnecessary LockView(1), and moved UnlockView right to where animation completes.
Note that if cPerxeo is a player character, you could just write player everywhere. This is recommended to do, in case something changes about the character, or you will have a game where player character may be switched for any reason.
If you are going to have a lot of items picked up like that, I may also suggest to write a global function that does most things. This way you will be able to reduce code duplication - that is write the basic algorithm once, and then just call it with some parameters.
For example:
in GlobalScript.asc
function PickupObject(Object *obj, InventoryItem *itemToAdd, eDirection dirToFace)
{
player.FaceDirection(dirToFace);
player.LockView(3);
player.Animate(0, 0, eOnce, eNoBlock);
while (player.Animating)
{
if (player.Frame == SOME_FRAME)
obj.Visible=false;
Wait(1); // Wait lets engine to update and redraw the scene
}
player.UnlockView();
player.AddInventory(itemToAdd);
}
in GlobalScript.ash (header)
import function PickupObject(Object *obj, InventoryItem *itemToAdd, eDirection dirToFace);
Then in the room script you may do this:
function oCacerolas_PickUp()
{
player.Walk(1037, 938, eBlock, eWalkableAreas);
PickupObject(oCacerolas, iCacerolas, eDirectionUpRight);
player.Say("I've the pans with me!!!.");
}
function oAnotherObject_PickUp()
{
player.Walk(1037, 938, eBlock, eWalkableAreas);
PickupObject(oAnotherObject, iAnotherObject, eDirectionDown);
player.Say("I got AnotherObject!");
}
You may add more parameters to this, or reuse existing ones for other purposes. For example, you may use dirToFace parameter to select an animation loop: this will let you to play different animations depending on which direction the character is facing.
oh my god! Thanks!! What a complete answer!