MultiWindowed Adventure Game



Hi All,

This is really for Paul Panks, but the programming technique is
sufficiently general and interesting that I will post it here.

Paul needs the ability to put status information on the screen in a
fixed location. This is difficult to do under Windows and Linux in a
portable fashion, so I am offering an alternate solution: multiple
windows.

Rather than attempting to put the status message at the same point on a
screen that is scrolling by (and whose buffer is at an unknown point
under OSes such as Linux), a cleaner solution is to open up two windows
- one for the normal game (that scrolls) and one for the status window
(that does not scroll, and upon which the game writes status
information to specific spots on the screen). Because the status
window never scrolls, it is easy to control where stuff is written to
it (in a portable fashion) and still provide the usual user interface
in the main game window.

The scheme I am providing uses "memory-mapped files" under Windows and
Linux to create a "shared memory" window through which the program can
exchange data. The idea is as follows:

1. you run a "statusConsole" application whose sole job is to read data
from the shared memory area and write that data to the status window.

2. the main game program writes data to the shared memory block that it
wants the statusConsole application to display in the status window.

This is all fairly straight-forward. The only catch is that the user
has to run both applications (in different console windows) for this
process to work properly. Well, actually, there is one other *big*
catch. Because the two processes have different address spaces, you
cannot pass pointers between the two processes. And HLA strings *are*
pointers, so it's important that you pass the actual string (character)
data between the processes rather than pointers to this character data.
But other than this issue, using the two systems is very
straight-forward.

The following is a sample application that demonstrates this:

----- statusConsole.hhf ------ Header File ------


#if( !@defined( statusConsole_hhf ))
?statusConsole_hhf := true;

const
sharedEBX :text := "(type sharedData_t [ebx])";


// The following macro is used to declare string objects
// in the shared data area. This macro reserves storage
// for the maxlength, length, zero-terminator, and
// character data fields needed by the HLA string format.
// It also reserves some extra storage so we can guarantee
// that the string data is dword-aligned.

#macro sharedStr( _maxLen_ );
char[ (_maxLen_+20) div 4 * 4 ];
#endmacro


// The following data structure is the template for
// the shared memory area. Declare any variables you want
// to pass between the two processes in this record.
//
// Note: no strings and no pointer objects. For string
// objects, use the sharedStr type above and initialize
// these strings in your two processes (see the example
// code for details).

type

sharedData_t:
record

// The current example shares two variables
// between the two processes, a string whose
// length is a maximum of 256 characters and
// an integer value:

statusString :sharedStr(256);
currentScore :int32;

// Put any other shared variables here:

endrecord;

pSharedData_t :pointer to sharedData_t;

#endif


--- statusConsole.hla ---- status program source file ----

program statusConsole;
#include( "stdlib.hhf" )
#include( "console.hhf" )
#include( "w.hhf" )
#include( "statusConsole.hhf" )


static
statusStr :string;

shared :pSharedData_t;
mmFile :mmap;


begin statusConsole;

// The statusConsole program, which must be run first,
// is responsbile for creating the memory-mapped file
// in the file system:

mmFile.create();
mmFile.openNew
(
"advGameSharedData.dat",
@max( @size( sharedData_t ), 4096)
);
mov( mmFile.filePtr, eax );
mov( eax, shared );

// Zero out the shared memory area:

mov( eax, edi );
xor( eax, eax );
mov( @size( sharedData_t ), ecx );
rep.stosb();

// Initialize the string pointers into the shared data area.
// The call to str.init initializes the string you pass
// as the first parameter to the length specified by the
// second parameter. This function returns a pointer to
// the string data that you should store into a local
// STRING variable to use to manipulate that string.

mov( shared, ebx );
str.init( sharedEBX.statusString, 256 );
mov( eax, statusStr );


// Sit in a loop, forever updating the console info

forever

mov( shared, ebx );

// Clearing the screen causes flicker, so you
// may want to do something else here:

console.cls();

// Position the cursor and display the status
// string:

console.gotoxy( 0, 0 );
stdout.put( statusStr );

// Position the cursor and display the current score:

console.gotoxy( 0, 10 );
stdout.put( "Current Score: ", sharedEBX.currentScore );

// Update the display once every 500 ms:

w.Sleep( 500 );

endfor;



end statusConsole;



---- Main Game Program source file -----------

program main;
#include( "stdlib.hhf" )
#include( "console.hhf" )
#include( "statusConsole.hhf" )


static
shared :pSharedData_t;
mmFile :mmap;
statusStr :string;
inputLine :str.strvar( 256 );
statusLine :str.strvar( 300 );




begin main;

// The following code assumes that you've run the
// statusConsole application in a separate window
// *before* executing this program:

mmFile.create();
mmFile.open( "advGameSharedData.dat", fileio.rw );
mov( mmFile.filePtr, eax );
mov( eax, shared );

// Initialize the status line string. Same as
// for the statusConsole app except we also
// initialize the string data with a default
// string.

mov( eax, ebx );
str.init( sharedEBX.statusString, 256 );
mov( eax, statusStr );
str.cpy( "(no status)", statusStr );

// "Play" the game:

forever

stdout.put( "Enter a command (ctrl-C to quit): " );
stdin.gets( inputLine );
str.put( statusLine, "You entered: '", inputLine, "'" nl );

mov( shared, ebx );
str.cpy( statusLine, statusStr );
inc( sharedEBX.currentScore );

endfor;



end main;



To try out this code, compile both modules, open two console windows,
run statusConsole in one window *and then* run the main program in the
other window. When you type lines in the main window, the text should
appear in the status window. If you type enough lines, the main window
will begin to scroll, but the status window will be unaffected.

Of course, there is a lot of clean-up to do here. It would be nice to
automatically run the statusConsole program from the main program (a
quick call to os.system could do that, though getting it to run in a
new window in an OS-independent fashion might be a chore). Also, rather
than simply refreshing the status window every 500 ms, you might also
try passing an "update available" variable to the status window that it
can use to determine when it should update the window. Clearly, the
code could be a bit more robust. I've not tried to run this code under
Linux. It *should* work, but no guarantees).
Cheers,
Randy Hyde

.



Relevant Pages

  • Returning selected items in an open folder
    ... items in an open folder window. ... Dim boo As Boolean ... '-- s1 is a unique string that's part of a specific open folder path. ... Private Sub Form_QueryUnload ...
    (microsoft.public.vb.general.discussion)
  • Code Addendum 01 - gforth: OpenGL Graphics Lesson 27
    ... \ These specify the size/depth of the SDL display surface ... \ Most SDL and OpenGL functions that require string data also require ... \ OpenGL scene generation code functions. ... \ Create an SDL surface and open the display window ...
    (comp.lang.forth)
  • Re: Why doesnt this recursive function return the right value?
    ... ByVal WindowTitle As String, _ ... 'finds the first window where the class name start with ClassName ... Dim sWindowTitle As String ...
    (microsoft.public.excel.programming)
  • Code Addendum 01 - gforth: OpenGL Graphics Lesson 07
    ... \ These specify the size/depth of the SDL display surface ... \ Most SDL and OpenGL functions that require string data also require ... \ OpenGL scene generation code functions. ... \ Create an SDL surface and open the display window ...
    (comp.lang.forth)
  • Code Addendum 01 - gforth: OpenGL Graphics Lesson 18
    ... \ These specify the size/depth of the SDL display surface ... \ Most SDL and OpenGL functions that require string data also require ... \ OpenGL scene generation code functions. ... \ Create an SDL surface and open the display window ...
    (comp.lang.forth)