home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
mnth0108.zip
/
Timur
/
vol1n8.txt
< prev
next >
Wrap
Text File
|
1994-03-25
|
10KB
|
233 lines
The Body Electric
Those pink checkerboards just had to go. Representing
different building types by colored patterns is not my idea
of an intuitive user interface, so this month I introduce
bitmaps to enhance the combat map.
To facilitate bitmap programming, a new BITMAP module has
been added. All bitmaps are loaded from the executable's
resources and stored in a memory presentation space. From
there, they are displayed with a GpiBitBlt() call.
The game now allows you to move a 'Mech across the playing
field. The 'Mech starts out at location (0,0) and can be
moved one hex at a time. Simply click on a nearby hexagon,
and the 'Mech will either turn to face it or move onto it.
In BattleTech, each sixty-degree turn is one movement point,
and a 'Mech can only move forward or backward. The current
version of this game does not keep track of movement points
or turns, however.
During targetting, the source hexagon is always taken to be
the 'Mech, so once you click with the left mouse button, the
targetting line is automatically drawn to the mouse pointer.
BITMAP
------
This new module provides generic bitmap support for the
entire game. All bitmaps are stored in the same memory
presentation space.
BitmapLoad() loads a bitmap and returns a bitmap handle if it
succeeds. It also initializes the module when first called.
Note all the WinMessageBox() calls to indicate an error. A
more advanced error handler will be included in a future
version.
BitmapDraw() draws a bitmap on the client window. Most
bitmaps in this game are irregular in shape. The bitmap
itself is always rectangular, but the image it holds usually
is not. For instance, a bitmap of a terrain is hexagonal.
The four corners are part of the bitmap, but not part of the
image.
Thus there is a problem. Some bitmap pixels must be drawn
over the screen, and others should not overwrite anything.
In other words, only a portion of the rectangular bitmap
should be drawn. The rest should be ignored.
By using a bitmap mask, this effect can be achieved. The
mask is the same size and shape as the original bitmap and is
drawn at the same location, but it contains only two colors:
white and black. The black portions are where the true image
exists in original bitmap. The white areas are where the
background image should show through. It is important to
remember that wherever the mask is white, the original bitmap
should be black.
The mask is logically-AND'ed with the screen. The black
portions of the mask erase the screen, and the white portions
leave the screen unaltered. Then the original bitmap is
logically-OR'ed onto the screen over the mask.
If the mask bitmap handle is NULLHANDLE, then no masking
operation is performed. This is handy for times when the
background is already known to be black.
GAME
----
Most of the window-related variables have been moved to a new
module, WINDOW. However, all of the code is tentatively
still here. See the discussion of WINDOW for details.
The window procedure has been updated only to reflect changes
in the other modules. For instance, WM_CREATE now calls
MechInit() to initialize the MECH module.
HEXES
-----
The biggest change in this module is the technique used to
draw the combat map. The addition of bitmap support
necessitated an update of the drawing functions. Also, the
routines which support the different terrains have been moved
to a separate module, TERRAIN.
The following two methods were previously used to draw the
combat map:
1. The client window is painted black. For each hexagon, the
current color and pattern is set, and an area bracket is
started. A hexagon is drawn, the bracket is closed, and OS/2
fills in the rest.
2. Similar to the first method, except that the client window
is painted with the color and pattern of the default terrain
(in this case, clear ground). A black hexagonal grid is
overlaid. Only the hexagons which differ from the default
are then painted.
Beginning this month, a third technique comes into play:
3. The client window is once again painted black, the color
of the hexagonal grid. The inside of each hexagon is painted
without redrawing the hexagon itself.
The window procedure should take no longer than 1/10th of a
second to process any message, otherwise it blocks the
message queue for too long. Unfortunately, drawing the
entire combat map can take several seconds.
One solution is to move HexDrawMap() into a separate thread.
This may solve the queue problem, but the combat map still
takes too long to draw. Method #2 works well as long as the
combat field is mostly of clear ground, which is not always
the case.
The proper technique would be to use WinQueryWindowRect() to
determine the hexagons which need to be redrawn. This
function returns a rectangle that outlines the region of the
client window which has been invalidated. A function similar
to HexLocate() could be used to find the four hexagons that
lie on the corners of that rectangle. Then HexDrawMap()
would read:
for (hi.c=iStartC; hi.c<=iEndC; hi.c++)
for (hi.r=iStartR; hi.r<=iEndR; hi.r++)
HexFillDraw(hi);
The individual hexagons, however, still take a long time to
draw. There are a few potential solutions to this problem.
Look for these and other speed enhancements in future
articles:
1. Draw all hexagons of a given terrain at once, thereby
avoiding multiple calls to GpiSetColor() and GpiSetPattern().
2. Use a different technique for drawing filled polygons. I
have not explored all the possibilities yet, so there may be
other Gpi functions which work better.
3. Use bitmaps for all the terrains. The GpiBitBlt()
function might be faster than area-bracket fills.
Two new defines, XLAG and YLAG, represent the horizontal and
vertical spacing between the hexagons on the hex map. The
default value of two produces a spacing of one pixel. These
defines only affect HexCoord(), HexMidpoint(), and
HexLocate(), since these are the only functions which
maintain a link between screen coordinates and hex indices.
WINDOW_WIDTH and WINDOW_HEIGHT also use XLAG and YLAG to
determine the size of the client window needed to display the
entire hex map.
MECH
----
This month introduces a user-controlled 'Mech, supported by
the MECH module. This module initializes the 'Mech's
position and orientation in MechInit() and changes them in
MechMove(). MechInit() also loads the bitmaps representing
the 'Mech in all six orientations.
MechMove() has to determine whether the 'Mech needs to be
rotated or moved. First, it rejects any target hexagon which
is not adjacent to the 'Mech. Then, it calculates the
direction to that hexagon. If this value is different from
the current orientation, the 'Mech is rotated and redrawn.
Otherwise, it is moved to the new position.
If you wish to move the 'Mech to a hexagon on its left or
right side, click on the target hex once to rotate the 'Mech
and again to move him. However, do not click the mouse twice
too quickly. This action is registered as a double-click,
which means that OS/2 does not send two WM_BUTTON1DOWN
messages. Rather, it sends one WM_BUTTON1DOWN followed by a
WM_BUTTON1DBLCLK.
MENU
----
Changes in the header file for this module eliminate the need
for MenuInit(), since this function did nothing but
initialize global variables. A separate if-statment in
MainCommand() allows this function to handle any number of
terrains without a code change. The only other change to this
module is the inclusion of my address in the "About..."
dialog box.
TERRAIN
-------
This module encapsulates all the terrain-related code and
data which was once in HEXES. There are eleven terrain
types, and each one has a set of attributes listed in
structure TERRAIN. Function TerrainInit() initializes the
array of terrain data, ater[], with pre-defined constants. A
configuration file will eventually be created to store
information on all the terrains.
Function TerrainIdFromMenu() returns the terrain ID (a number
from 0 to 10) which maps to a given IDM_TER_xxx value. In
previous versions of this game, the terrain ID was the same
as the menu ID listed in file RESOURCE.H.
WINDOW
------
This module does not contain any code yet, but its purpose is
to localize most of the presentation-manager specific
features of this game. In the distant future, there might be
interest in porting this game to other platforms. Separating
the operating system specific code early on will make
cross-platform development much easier.
Next Month
----------
There are a few quirks and minor bugs in this code which have
yet to be fixed. The mouse is never captured during
targetting. Clicking on the client window will not bring it
into focus. The info box is not hidden when the main window
is minimized. These and other problems will be addressed in
the next installment.
I would also like to make a formal request for volunteer
translators. As you know, multilingual support is one of the
goals of this project. I expect to have a few dozen
single-line strings (most of them error messages) which need
to be translated into as many foriegn languages as possible.
Anyone out there interested in lending a hand?