Having trouble with the script CallRoomScript()

Started by FanOfHumor, Sat 23/04/2022 00:51:49

Previous topic - Next topic

FanOfHumor

I'm having trouble with using callroomscript when calling a function that has integers in it.

I get  errors when trying to call animateoverlay().
Code: ags

function animateoverlay(Overlay* selectedoverlay, int Xposition, int Yposition, int startsprite,int endsprite,  int transparent, int repeatoronce)
{
	selectedoverlay=Overlay.CreateGraphical(Xposition, Yposition, startsprite,transparent);
	selectedoverlay.Remove();
	startsprite+=1;
	if(startsprite!=endsprite)
	{
	      CallRoomScript(animateoverlay(Overlay* selectedoverlay,int Xposition,int Yposition,int startsprite,int endsprite,int transparent,int repeatoronce));
	}	
	else
	{
		if(repeatoronce==repeat)
		{
		  startsprite=0;
		}	
		if(repeatoronce==once)
		{
		  selectedoverlay.Remove();
		}		
	}

At first I tried a simple CallRoomScript(animateoverlay());
But it wasn't enough parameters.
Then I tried CallRoomScript(animateoverlay(Overlay* selectedoverlay,int Xposition,int Yposition,int startsprite,int endsprite,int transparent,int repeatoronce)); ,but it had a parse error in expression near int. 
What am I doing wrong.

Also does anyone know a better way of animating overlays?

Thanks.

Crimson Wizard

#1
What is it you are trying to do with CallRoomScript here, how is it related to animating the overlay?

CallRoomScript is called with 1 parameter: an integer number. You are placing a function call there instead, or so it seems. Are you trying to pass a return value from function animateoverlay into CallRoomScript? Or are you trying to call this function from within the room script?.... I am puzzled.

Also, I think you need to fix the order of the first two lines, like this:
Code: ags

if (selectedoverlay != null)
     selectedoverlay.Remove(); // remove previous overlay if it exists
selectedoverlay=Overlay.CreateGraphical(Xposition, Yposition, startsprite,transparent);


Otherwise your overlay will be removed right after creation.

FanOfHumor

I was assuming that custom functions don't automatically loop.Do they?I haven't actually tested this yet where it gets past the errors so I don't know.I was trying to get it to loop until its finished animating from startsprite to endsprite.So I want the function to loop until a set condition.I did loop a function before but it was only one without any parameters.

Quote
if (selectedoverlay != null)
     selectedoverlay.Remove(); // remove previous overlay if it exists
     selectedoverlay=Overlay.CreateGraphical(Xposition, Yposition, startsprite,transparent);

Thanks that helps some.

Crimson Wizard

#3
Quote from: Pajama Sam on Sat 23/04/2022 01:20:51
I was assuming that custom functions don't automatically loop.Do they?I haven't actually tested this yet where it gets past the errors so I don't know.I was trying to get it to loop until its finished animating from startsprite to endsprite.So I want the function to loop until a set condition.I did loop a function before but it was only one without any parameters.

Ah, okay, that explains your intent.

May you tell, why do you use Overlays for animation? Overlays have to be animated manually in script, but there's also GUI buttons that have Animate command that does everything for you.

If you're positive that you really must animate an overlay, first of all you got to decide if this function will be blocking or non-blocking as they have to be dealt with differently. Are you intending to call this function repeatedly from somewhere, or want the whole animation to happen inside the function, and then return to whatever place you called it?
Why do you pass Overlay pointer in it, does it have any meaning? Problem is, this pointer "selectedoverlay" will be considered a local variable in this function, and any changes to it will be lost as soon as the function ends.

FanOfHumor

I would use overlays for temporary visual animations that are too time consuming to make objects just for something that lasts for a moment.
The function should be non-blocking.I don't know how to do that.
I want the whole animation to happen inside the function.

////////////////////////////////////////////////////////////////////////// (overlay,Xposition,Yposition,startsprite,endsprite,transparent,repeatoronce)
So if I had an overlay called "blah"and I would type animateoverlay(blah    ,320       , 320       ,2             ,13         ,true           ,once)
There are two global integers called repeat and once.
repeat=1
once=0
So if repeatoronce was input as once the function should repeat until it finishes animating and if repeatoronce was input as repeat the function should keep looping forever.Although I don't think I will ever need to repeat it forever.I would at least like for it to run through the sprites once.
The first time the overlay is created its sprite number should equal 2(the startsprite) and add 1 until it reaches 13(endsprite).
You probably already knew all that but at least I hope I made it evinced.

Can't it create the overlay again when it finishes?

Crimson Wizard

#5
Hmm, non-blocking functions are more complicated, because in this case whole animation simply cannot happen inside this function. Instead, you need to call it from "repeatedly_execute" using some timer between calls and condition that tells you that animation is going on. Also you have to store all parameters somewhere, in global variables, while overlay is animating.

To clarify:
1) if the animation is blocking, then whole animation, and its loop, may happen inside one function.
2) if the animation is non-blocking, then the function should only do one step, but be called repeatedly from somewhere else (for example, "repeatedly_execute" or other similar function).

The example of a blocking animation:
Spoiler

Code: ags

Overlay* animateoverlay_blocking(Overlay* selectedoverlay, int Xposition, int Yposition, int startsprite, int endsprite, int transparent, int delay)
{
    // loop while startsprite have not reached endsprite
    while (startsprite != endsprite)
    {
        // destroy previous and create new overlay with a new sprite
        if (selectedoverlay != null)
            selectedoverlay.Remove();
        selectedoverlay = Overlay.CreateGraphical(Xposition, Yposition, startsprite, transparent);
        Wait(delay); // wait some time
        startsprite++; // choose next sprite
    }
    return selectedoverlay;
}


This function may be used like:
Code: ags

    someoverlay = animateoverlay_blocking(someoverlay, 100 /*x*/, 50 /*y*/, 1 /*start sprite*/, 10 /*end sprite*/, true /*transparent*/, 5 /*delay*/);

[close]



For non-blocking animation you need to save the animation's information somewhere first, because it's going to be used repeatedly. If you have only 1 overlay animated at a time, then you just need few global vars to store these, but if you want to have a number of them animating simultaneously, then you need array of those vars. I also suggest creating a custom struct to group these variables.

Following is an example of single animated overlay, but it may be relatively easy expanded into multiple simultaneous overlays:
Code: ags

struct AnimatedOverlay
{
    Overlay *over;
    int x, y;
    int startsprite, endsprite;
    int delay;
    int timer;
    int transparent;
};

AnimatedOverlay animover; // single animated overlay

// This functions starts animation and save parameters
function animateoverlay_begin(int x, int y, int startsprite, int endsprite, int transparent, int delay)
{
    animover.x = x;
    animover.y = y;
    animover.startsprite = startsprite;
    animover.endsprite = endsprite;
    animover.transparent = transparent;
    animover.delay = delay;
    animover.timer = delay; // set timer to delay value
    
    if (animover.over != null)
        animover.over.Remove();
    animover.over = Overlay.CreateGraphical(x, y, startsprite, transparent);
}

// This function continues existing animation (or ends it)
function animateoverlay_step()
{
    if (animover.over == null)
        return; // not active
    
    animover.timer--; // countdown timer
    if (animover.timer > 0)
        return; // delay not finished yet

    // choose next sprite
    animover.startsprite++;
    if (animover.startsprite != animover.endsprite)
    {
        // destroy previous and create new overlay with a new sprite
        animover.over.Remove();
        animover.over = Overlay.CreateGraphical(Xposition, Yposition, startsprite, transparent);
        // start the delay again
        animover.timer = animover.delay;
    }
    else
    {
        // we're done here
        animover.over.Remove(); // optionally remove overlay...
        // if you like to keep it, then remove this command
    }
}


Then you need to place a call to animateoverlay_step() into "repeatedly_execute" (or room's RepExec event).
Code: ags

function repeatedly_execute()
{
    // if animated overlay exists, then do the step
    if (animover.over != null)
        animateoverlay_step();
}


The animation starts like
Code: ags

    animateoverlay_begin(100 /*x*/, 50 /*y*/, 1 /*start sprite*/, 10 /*end sprite*/, true /*transparent*/, 5 /*delay*/);

FanOfHumor

Thanks for showing me all that.

About return;. I'm new to it and the manual confuses me on that part.
To be clear.Return can make it go back to the beginning of the function.Am I
right?

Crimson Wizard

Quote from: Pajama Sam on Sat 23/04/2022 05:57:37
About return;. I'm new to it and the manual confuses me on that part.
To be clear.Return can make it go back to the beginning of the function.Am I
right?

Not to the beginning, but to outside. It returns to the place where you called it from and continues from there. It's the way to return some value, or skip the rest of the function and exit early.

SMF spam blocked by CleanTalk