Screen Refresh Problem

BlitzMax Forums/BlitzMax Beginners Area/Screen Refresh Problem

KevMart(Posted 2009) [#1]
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?


KevMart(Posted 2009) [#2]
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?"


Jesse(Posted 2009) [#3]
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.


Midimaster(Posted 2009) [#4]
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.


KevMart(Posted 2009) [#5]
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



Midimaster(Posted 2009) [#6]
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?


KevMart(Posted 2009) [#7]
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.


Jesse(Posted 2009) [#8]
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.


Midimaster(Posted 2009) [#9]
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()?


KevMart(Posted 2009) [#10]
The display.Refresh function contains cls <things to display> flip.


KevMart(Posted 2009) [#11]
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.


Midimaster(Posted 2009) [#12]
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



KevMart(Posted 2009) [#13]
Thanks, Midi. I think I better understand what you are saying. I will give that technique a try.