Hi!
How can I add methods to DesignedComponents after loading them in code?
For instance
Button1 := DesignedComponent (‘Button1’) as TCastleButton;
I would like to add a small delay so when I click a button it takes for instance 2 seconds before the action is performed.
The idea is that when I give a command to a transform (scene sprite) there will be a small delay before it actually responds.
To register events on components, follow engine examples/templates like “3D Model Viewer” template:
procedure TStateMain.Start;
begin
inherited;
{ Find components, by name, that we need to access from code }
ButtonStopAnimation := DesignedComponent('ButtonStopAnimation') as TCastleButton;
{ Assign OnClick handler to buttons }
ButtonStopAnimation.OnClick := @ClickStopAnimation;
end;
procedure TStateMain.ClickStopAnimation(Sender: TObject);
begin
....
end;
To run something with delay, use a variable controlling the timeout. That is,
-
add a variable like TimeToDoSomething: TFloatTime
-
when user clicks a button, do TimeToDoSomething := 2.0
(delay in 2 seconds)
-
in state Update
method decrease it , and watch when it drops to zero, like
procedure TStateMain.Update(const SecondsPassed: Single; var HandleInput: Boolean);
begin
inherited;
if TimeToDoSomething > 0 then
begin
TimeToDoSomething := TimeToDoSomething - SecondsPassed;
if TimeToDoSomething <= 0 then
begin
// do something ...
end;
end;
end;
Thanks!
And if I want to run a sequence of events and only execute the next event when the previous one is finished?
For instance: a character sprite is walking off screen and the screen has to fade out before the next location and sprites are loaded?
And if I want to run a sequence of events and only execute the next event when the previous one is finished?
Depends. If you want to do that in a simple way - just create two timeouts. E.g. adding to @michalis example:
procedure TStateMain.Update(const SecondsPassed: Single; var HandleInput: Boolean);
begin
inherited;
if TimeToDoSomething > 0 then
begin
TimeToDoSomething := TimeToDoSomething - SecondsPassed;
if TimeToDoSomething <= 0 then
begin
StartSomeAnimation; // it should check if the animation started already not to start it twice
TimeToDoSomethingNext := TimeToDoSomethingNext - SecondsPassed;
if TimeToDoSomethingNext <= 0 then
begin
ChangeLocation;
end;
end;
end;
Note, that while simple, this is not the best solution for a larger scale. There you’ll have to create some event manager otherwise you’ll drown in timeouts and ifs. But this is not an easy task, so if you don’t plan to significantly extend the usecase, I’d go with the simple solution.
Thanks.
I don’t want to make this too difficult ( I have problems enough already with the screen coordination) so this is a fine approach.
For an action following fading out a screen I think I should use a routine that has no countdown but executes after all screen colors are faded to black?
I’m not sure if I follow. If you have “fade out” animation and loading starts at its end, then indeed, you can do without the second timer (sorry, I think I’ve misunderstood your first post). As in:
procedure TStateMain.Update(const SecondsPassed: Single; var HandleInput: Boolean);
begin
inherited;
if TimeToDoSomething > 0 then
begin
if SceneIsFadingOut then
begin
TimeToFadeOut := TimeToFadeOut - SecondsPassed;
SetFadedColors(1 - TimeToFadeOut / FadeOutTimeout);
if TimeToDoSomething <= 0 then
StartLoading;
end;
end;
Thanks.
I will try this out as soon I have finally sorted out the screen coordination problems.