Screen Refresh Problem
BlitzMax Forums/BlitzMax Beginners Area/Screen Refresh Problem
| ||
| When running a game I created, there are moments where the AI is doing some work without player input. The problem is the screen will not update during that process (Windows says "not responding") if I have selected a different window on the desktop, then come back to the game "window". My problem is similar to: http://www.blitzmax.com/Community/posts.php?topic=87560 but I am not using GUI, just a regular Graphics screen. So, if I understand correctly, I cannot use the event interrupt without converting to MaxGUI. I wanted to use a regular Graphics screen for portablility to Linux. Is there any way to solve this without GUI commands? |
| ||
| It appears I am mistaken about at least one thing (at least!). It seems that MaxGUI is available for Linux as well. So, I suppose I could solve this problem by buying that as well.... Still, does anyone know of a way to get around the above mentioned problem without "going GUI?" |
| ||
| That will happen any time a process is taking too long to complete. It is processing a lot of thing in the background and not updating the screen in the process. You need to find a way for the process to take shorter time. Of course that is just a guess. With out any source code, all I can do is speculate. MAXGUI will not really solve it. |
| ||
| Can you devide the AI work in some smaller steps? Between these steps return back to your main loop with a eventuall FLIP. f.e (only pseudo code)
Repeat
AllHardWork
Flip
Forever
Function AllHardWork()
for i=0 to 10000
hardwork(i) ' needs a lot of time
next
End Function
change to....
WorkStep%=0
Repeat
AllHardWork
Flip
Forever
Function AllHardWork()
for i=WorkStep to WorkStep+100
hardwork(i) ' needs a lot of time
next
SaveThisSteps(i)
WorkStep=WorkStep+100
End Function
In the sum the programm will now need more time for AI, but for the user it keeps usable and seems not to stand still. |
| ||
| Here is one of the offending pieces of code. :) This program I created as an exercise to build OOP experience. This game is based on the old "Nukewar" game of '80s fame. In the main loop, the AI selects a base to activate (in this case, an ICBM base). The selected base object is sent to the launch method to handle the process of launching. From the method are several function calls, such as display.Refresh (clears screen and redraws the minimum required stuff--other stuff is drawn within the method), checking for ABM interception, and then selecting a target (from that function there is another call to the graphical display of a nuke blast). This code will repeat as many times as there are missiles. Then it returns to the main loop. Sounds kinda complicated when I hear myself talk about it....
Method P2Launch(base:TIcbmbase)
Local boom:Int = 0
base.basetype = 11 ' now empty base
base.icon = img_icbmempty ' empty base icon
base.visible = 1 ' base now visible to player 1
display.Refresh()
SetColor(210,0,0)
DrawText("Enemy ICBM base activated",column2,row1)
Flip
display.Click() ' click mouse to continue
' missile launch
For Local j:Int = 1 To base.missiles
boom = 1
display.Refresh()
SetColor(210,0,0)
DrawText("ICBM LAUNCHED",column2,row1)
Flip
Delay(1000)
If p1force.abms > 0 ' chance of ABM interception
For Local abm:TAbmbase = EachIn List_p1map
If abm.basetype = 14 ' alert abm base
boom = abm.P1Launch(abm) ' return 0 if abm intercepts missile
Exit
EndIf
Next
EndIf
' find base
If boom = 1
p2select.GetTarget() ' select target to destroy
EndIf
display.Refresh()
Delay(1000)
Next
base.missiles = 0
End Method
|
| ||
| why such long delay times of 1 sec? to keep the computer useable i also isert often delay commands, but more than 5 msecs are seldom useful, or? |
| ||
| The first runthrough of the game went like lightning. The delay is between missile shots so the human player can see what is happening, and stretch the game time a bit. I could use the display.Click routine between shots, but that means a lot of clicking. |
| ||
| but you are stopping the game with the delay. you need to find another way to fire the missiles one second at a time with out stopping the game. one example is to use a millisecond counter: shoottime = millisecs()+1000 loop start . if start < millisecs() ...fire missile ...start = millisecs()+1000 endif . loop end note this is not 100 workable but it should solve it while you don't let your computer run for days. |
| ||
to make a program slower, I would try to add a timer that only jumps into functions and methods a several time a second.
Repeat
if zeit<Millisecs() then
zeit=millisecs()+100
DoMyWork()
endif
Delay 5
Flip
Forever
I never used a Delay() command inside a methode(). This could cause a lot of waiting time, if the methode is called very often. My opinion is, that Methods() and functions() have to return as quick as possible. second question: before your first Delay() you used a Flip(). That's ok. But why don't you use a Flip() between display.resfresh() and second Delay()? |
| ||
| The display.Refresh function contains cls <things to display> flip. |
| ||
| After some experimentation, I have come up with the quickest (but maybe not the best) solution without a massive re-coding effort. Based on the info given by other members (thank you, by the way), I came up with this function: Function TimerWait(seconds:Int) Local timer:Int = MilliSecs() + (seconds * 1000) Repeat FlushKeys() If timer < MilliSecs() Exit EndIf Forever End Function which is called by TimerWait(1) (or however many seconds delay is desired). My tests have shown that using FlushKeys() acts as a "poor programmer's interupt" and brings the screen back to life after clicking another window and returning to the game window. Is this a good way to handle this problem? The difficulty with using the other member's techniques is that the delay was only designed to display a message before moving on to other functions (not to time the call of a function). Maybe I am not explaining it right, but if anyone would like to playtest the game, I will send the folder/files to you. Maybe then others will understand what I am trying to accomplish. |
| ||
| I keep my opinion, that it is the best way to keep the window alive, to care about, that the FLIP command can work every 20-100 msecs. Therefore it is important not to construct loops, or waits or delays longer than 100 msecs. Why not divide a 1 second waiting in 10 parts each 100msecs? And between the 10 parts always a FLIP command
Function TimerWait(seconds:Int)
Local timer:Int = MilliSecs() + (seconds * 1000)
Repeat
Flip
Delay 100
Until MilliSecs()<Timer
End Function
|
| ||
| Thanks, Midi. I think I better understand what you are saying. I will give that technique a try. |