Page 1 of 1
One time text fade it and out
Posted: Tue Nov 06, 2018 12:05 am
by Clyde
Hey there!
Slowly beginning to do some basic stuff with Hollywood again ...
I would like to fade in a text, have it shown for x seconds and fade it out afterwards. I thought I could use "
DisplayTextObjectFX()" but with the #FADE operation it fades the text in and out in a loop which I cannot control:
Code: Select all
SetFontColor(#RED)
SetFont("times.font", 18)
readyMessageID = CreateTextObject(Nil, "Ready")
Function p_MainLoop()
DisplayTextObjectFX(readyMessageID, #CENTER, #CENTER, {Type = #FADE, Speed = 5, Parameter = #BLACK})
EndFunction
SetInterval(1, p_MainLoop, 40)
While quit = False
WaitEvent
Wend
Basically I have this problems with this code:
1. Speed is a bit unclear. I can't control exact seconds/milliseconds/ticks
2. I cannot set a time where the text stays displayed. And as there is no event when the fade in anim is completed I cannot simply delete this TextObject and replace it by a new one with no FX
3. How to stop the fade in/fade out process after one iteration. It does not help to call it outside the main loop
Any ideas/best practices?
Thanks in advance!
Re: One time text fade it and out
Posted: Tue Nov 06, 2018 3:57 am
by PEB
The problem with your code is that you keep calling the same function over and over again with a fast interval.
This is one way you can adjust it to get what you want:
Code: Select all
EnableLayers()
SetFontColor(#RED)
SetFont("times.font", 18)
readyMessageID = CreateTextObject(Nil, "Ready")
Function p_DisplayReadyText()
DisplayTextObjectFX(readyMessageID, #CENTER, #CENTER, {Type = #FADE, Speed = 5, Parameter = #BLACK})
SetLayerName(0, "ReadyText")
Wait(50)
RemoveLayerFX("ReadyText", {Type = #FADE, Speed = 5, Parameter = #BLACK})
EndFunction
p_DisplayReadyText
Repeat
WaitEvent
Forever
Re: One time text fade it and out
Posted: Tue Nov 06, 2018 10:22 am
by Clyde
Thanks a lot, PEB!
Yeah, I was also worrying about the code is called in my main loop. But I am quite sure I also put
DisplayTextObjectFX() out of the main loop so it was only called once. But I will double check it.
One problem is the the
Wait() command you use. If I understand it correctly it blocks the whole script so while waiting the given amount of time the script would not react to events like keypresses, would it?
I think I also got some fundamental problems with understanding the game loop or better: what to put in the game loop. In the end I want to do a very simple game regarding game mechanics. Now, I know I have to put the graphics display code and retrieving inputs into this game loop (which runs at 25 fps e.g.). So I thought I also have to put these text display stuff in this game loop, either directly (like or did) or through some kind of event which is evaluated in the loop and depending on game state some other function is called. But this seems to be wrong at least for this display fx stuff?
Confusing, but I know it is not Hollywood's fault but my mental capabilities.
Re: One time text fade it and out
Posted: Tue Nov 06, 2018 10:32 pm
by Clyde
Ok, that helped a lot, PEB.
Obviously I was wrong when I said that the behaviour is the same wether I call
DisplayTextObjectFX() inside the main loop or outside. It really works the way I want it when I do it your way.
I've overcome the blocking of
Wait() in using a timeout, so now I use this:
Code: Select all
Function p_DisplayReadyText()
DisplayTextObjectFX(readyMessageID, #CENTER, #CENTER, {Type = #FADE, Speed = 5, Parameter = #BLACK})
SetLayerName(0, "ReadyText")
SetTimeout(1, p_FadeoutReadyText, 5000)
EndFunction
Function p_FadeoutReadyText()
RemoveLayerFX("ReadyText", {Type = #FADE, Speed = 5, Parameter = #BLACK})
EndFunction
Now, I big drawback (for me/this current situation) is, that
DisplayTextObjectFX() and
RemoveLayerFX() are also blocking the script. This means, a keypress event that I want to detect while this functions run (text is faded in and out) is not recognized/handled. It is just handled after this called are completed.
So, is there a way to implement such kind of effect without blocking the script/event handling is possible while they run?
Re: One time text fade it and out
Posted: Tue Nov 06, 2018 11:48 pm
by Clyde
It seems I have to work with "Async = True" and "
AsyncDrawFrame()"!? I created some really ugly code which should do the trick somehow, but I have to reconsider that code as it seems much too complicated for what I want to achive (that is: listening to keypress event while text is faded it/out).
Maybe someone has a slick idea. Will try to tidy up my code tomorrow anyway so I can show my solution (more kind of a hack, though :-/ )
Re: One time text fade it and out
Posted: Wed Nov 07, 2018 10:56 am
by Clyde
Ok, I tidied up my code, but it still a lot. :-/ I hope you understand what I try to achieve anyway and maybe someone has a better approach.
When you run the example hit space when the text fades in.
You can also download the example here:
https://1drv.ms/u/s!AvRgnk1wjp43kuwtrtAxHBTjfwElqg
Code: Select all
SetFontColor(#RED) ;
readyMessageID = CreateTextObject(Nil, "Ready")
doneMessageID = CreateTextObject(Nil, "Done")
fps = 30
timeoutID = Nil
textObject = Nil
EnableLayers()
Function p_DummyForTextFading()
; (unfortunately) needed for setInterval. Otherwise the frame printing loop would not continue
EndFunction
Function p_FadeTextInAsync()
InstallEventHandler({OnKeyUp = p_EventFunc})
SetInterval(2, p_DummyForTextFading, 1000/fps) ; needed, so WaitEvent after AsyncDrawFrame() call continues
textObject = DisplayTextObjectFX(readyMessageID, #CENTER, #CENTER, {Type = #FADE, Speed = 10, Parameter = #BLACK, Async = True})
frames = GetAttribute(#ASYNCDRAW, textObject , #ATTRNUMFRAMES) ; get number of frames to show
For Local k = 1 To frames
If (IsNil(textObject )) Then Break ; if textObject is Nil, we want to stop playing the fade in
AsyncDrawFrame(textObject , k) ; draw frame by frame
; VWait or the like are not suitable to use in this case as it blocks the script so no (keypress) event can be handled while anim
WaitEvent ; needed, so the loop continues (through SetInterval) and listens to keypress events (InstallEventHandler)
Next
If (IsNil(textObject ) = False)
FinishAsyncDraw(textObject ) ; FinishAsyncDraw has to be called
textObject = Nil
EndIf
SetLayerName(0, "ReadyText")
timeoutID = SetTimeout(Nil, p_FadeTextOut, 5000) ; begin to fade out the text after 5 seconds; TODO: make async
EndFunction
Function p_FadeTextOut()
RemoveLayerFX("ReadyText", {Type = #FADE, Speed = 5, Parameter = #BLACK}) ; fade out text
; clear variables (important for checks in p_ShowOtherText()
timeoutID = Nil
textObject = Nil
EndFunction
Function p_ShowOtherText()
If (IsNil(timeoutID) = False) ; clear Timeout if it is still active
ClearTimeout(timeoutID)
timeoutID = Nil
EndIf
If (IsNil(textObject) = False) ; if the text object is still valid ...
CancelAsyncDraw(textObject) ; ... cancel the fade in process
textObject = Nil
Else
If (LayerExists("ReadyText")) Then RemoveLayer("ReadyText")
EndIf
DisplayTextObject(doneMessageID, #CENTER, #CENTER) ; show the other text
EndFunction
Function p_EventFunc(msg) ; Event Handler
Switch msg.action
Case "OnKeyUp":
Switch UpperStr(msg.key)
Case " ": ; when Space bar was hit ...
p_ShowOtherText() ; ... abort fadein anim of previous text and show other text
Case "ESC":
End
EndSwitch
EndSwitch
EndFunction
p_FadeTextInAsync() ; app entry
While quit = False
WaitEvent
Wend
Re: One time text fade it and out
Posted: Thu Nov 08, 2018 8:40 pm
by PEB
Here's another way you can do it:
Code: Select all
SetFontColor(#RED) ;
readyMessageID = CreateTextObject(Nil, "Ready")
setMessageID = CreateTextObject(Nil, "Set")
goMessageID = CreateTextObject(Nil, "Go")
FadeOrder$={readyMessageID, "remove", setMessageID, "remove", goMessageID, "remove"}
MessageVar=0
fps = 30
timeoutID = Nil
textObject = Nil
EnableLayers()
Function p_PrepFade(WhichText, Case$)
If Case$="show"
textObject = DisplayTextObjectFX(WhichText, #CENTER, #CENTER, {Type = #FADE, Speed = 10, Parameter = #BLACK, Async = True})
ElseIf Case$="remove"
textObject = RemoveLayerFX("FadingText", {Type = #FADE, Speed = 10, Parameter = #BLACK, Async = True})
EndIf
frames = GetAttribute(#ASYNCDRAW, textObject , #ATTRNUMFRAMES) ; get number of frames to show
FrameCounter=0
SetInterval(1, p_DoFade, 1000/fps, Case$)
EndFunction
Function p_DoFade(msg)
FrameCounter=FrameCounter+1
AsyncDrawFrame(textObject , FrameCounter) ; draw frame by frame
If FrameCounter=frames
FinishAsyncDraw(textObject)
ClearInterval(1)
If msg.userdata="show"
SetLayerName(0, "FadingText")
SetTimeOut(1, p_NextFade, 2000); This sets how long to wait after Text fades IN
Else
SetTimeOut(1, p_NextFade, 10); This sets how long to wait after Text fades OUT
EndIf
EndIf
EndFunction
Function p_NextFade()
MessageVar=MessageVar+1
If MessageVar>ListItems(FadeOrder$)-1; The list of messages has been completed.
MessageVar=0
EndIf
If GetType(FadeOrder$[MessageVar])=#LIGHTUSERDATA
p_PrepFade(FadeOrder$[MessageVar], "show")
Else
p_PrepFade("none", "remove")
EndIf
EndFunction
ActiveTypingText$="Type During Fade:\n"
TextOut(0, 0, ActiveTypingText$, {Name="ActiveTyping", WordWrap=500})
Function p_ShowTyping(msg)
ActiveTypingText$=ActiveTypingText$..msg.key
SetLayerStyle("ActiveTyping", {Text=ActiveTypingText$})
EndFunction
InstallEventHandler({OnKeyDown = p_ShowTyping})
p_PrepFade(readyMessageID, "show")
Repeat
WaitEvent
Forever
(I don't use #TEXTOBJECT layers in my projects anymore; I prefer to use #TEXTOUT layers instead.)
Re: One time text fade it and out
Posted: Thu Nov 08, 2018 9:57 pm
by Clyde
Wow, this looks very good, PEB. I hope this wasn't too much work for you. :-/ Thanks a lot!
Re: One time text fade it and out
Posted: Sat Nov 10, 2018 4:13 am
by PEB
Happy to help!