home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Media Share 13
/
mediashare_13.zip
/
mediashare_13
/
ZIPPED
/
PROGRAM
/
WTJ9403.ZIP
/
BARNHART
/
SO_PLAY.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1993-11-21
|
10KB
|
400 lines
// so_play.cpp - Implements the Player class
// Andy Barnhart
// This program is provided as a sample to accompany an article on graphics
// animation using C++
// This seems to work for me and I hope it works for you. No other warranty
// is expressed or implied.
#include <so_all.hpp>
// The states a player can be in to determine which frame to show
// Still or running are slight misnomers sometimes; more specifically,
// while running, the Player goes through "still" state to show the
// "legs straight" bitmap.
#define PL_STILL_R 0 // Still, facing right
#define PL_RUN_R 1 // Running to the right
#define PL_STILL_L 2 // Still, facing left
#define PL_RUN_L 3 // Running to the left
#define PL_JMP_NO 0 // Not jumping
#define PL_JMP_UP 1 // Jumping, and on the way up
#define PL_JMP_DN 2 // Falling (he doesn't really "jump down")
// We look at the screen size in case we need to pan the screen. I added this
// and was disappointed with the speed, so the default size keeps panning
// from being necessary, but I left the pan code in anyway.
extern int WinX, WinY, WinSX, WinSY;
// Create our hero
Player::Player( char *res, int ix, int iy) : ScreenItem( NULL, ix, iy)
{
char aci[36];
int i;
onrungs = FALSE;
still = TRUE;
SOType = TYPE_PLAYER;
// Get some ammo
for ( i =0; i < 3; i++)
shots[i] = new Missile("fireball");
strcpy( aci, res);
// The bitmaps are numbered for the possible Player positions
strcat( aci,"1");
Items[0] = LoadBitmap(hInst, aci);
strcpy( aci, res);
strcat( aci,"2");
Items[1] = LoadBitmap(hInst, aci);
strcpy( aci, res);
strcat( aci,"3");
Items[2] = LoadBitmap(hInst, aci);
strcpy( aci, res);
strcat( aci,"4");
Items[3] = LoadBitmap(hInst, aci);
state = PL_STILL_R;
jmpdir = PL_JMP_DN;
jmpadj = 40;
SelectBM( Items[state]);
}
// Get rid of Player - free up resources
Player::~Player( void)
{
int i;
for ( i =0; i < 3; i++)
delete (shots[i]);
if( Items[0]) DeleteObject( Items[0]);
if( Items[1]) DeleteObject( Items[1]);
if( Items[2]) DeleteObject( Items[2]);
if( Items[3]) DeleteObject( Items[3]);
hbmImage = NULL;
}
// Fire a shot wherever we are faced
void Player::Fire()
{
int i;
// see if we have any ammo available
for( i=0; i < 3; i++)
if( !shots[i]->inuse) break;
if( shots[i]->inuse) return;
// Always fire horizontal from current position to edge of window
switch (state)
{
case PL_STILL_R:
case PL_RUN_R:
shots[i]->Fire( x+width, y + (height/2), GMX-shots[i]->width,
y + (height/2));
break;
case PL_STILL_L:
case PL_RUN_L:
shots[i]->Fire( x, y + (height/2), 0, y + (height/2));
break;
}
}
// Update - with a keystroke value
// This is a fairly complex state machine. There are a couple of minor
// glitches to iron out, but hey - the article is about graphics, not
// complex state machines. If you want to see a glitch, jump up against
// a wall at a lower left corner in the second scene. You won't get
// stuck permenantly. You're welcome to expend your energy working out
// my glitches...
BOOL Player::Update( int keystate)
{
int oldstate;
oldstate = state;
ScreenObj * SOHit = NULL;
ScreenObj * WallHit = NULL;
if( keystate & KEY_RIGHT)
{
if( (state == PL_RUN_R))
state = PL_STILL_R;
else
state = PL_RUN_R;
// Move smaller amounts from a dead stop for precise movement
if( still)
{
x += 4;
still = FALSE;
}
else
x += xinc;
}
else if( keystate & KEY_LEFT)
{
if( state == PL_RUN_L)
state = PL_STILL_L;
else
state = PL_RUN_L;
if( still)
{
x -= 4;
still = FALSE;
}
else
x -= xinc;
}
else if( state == PL_RUN_L)
state = PL_STILL_L;
else if( state == PL_RUN_R)
state = PL_STILL_R;
if( (keystate & KEY_DOWN) && (jmpdir == PL_JMP_UP) )
jmpdir = PL_JMP_DN;
if( (keystate & KEY_UP) && (jmpdir == PL_JMP_NO) )
{
if( ! onrungs)
jmptop = y - (height * 2);
else
jmptop = y - 8;
if( jmptop < 0) jmptop = 0;
jmpdir = PL_JMP_UP;
}
if( jmpdir != PL_JMP_NO)
{
if( jmpdir == PL_JMP_UP)
{
y -= jmpadj;
if(y <= jmptop)
{
if( !onrungs)
jmpdir = PL_JMP_DN;
else
jmpdir = PL_JMP_NO;
y = jmptop;
}
}
else
{
y += jmpadj;
}
}
if( state != oldstate)
SelectBM( Items[state]);
if( (x == oldx) && ( y == oldy) )
still = TRUE;
else
still = FALSE;
if( (state != oldstate) || (! still) )
{
RECT rc;
ScreenObj * SONxt;
int wallbelow = FALSE;
if( y < 0) y = 0;
if( x < 0) x = 0;
if( (y+height) > Background->height) y = Background->height - height;
if( (x + width) > Background->width) x = Background->width - width;
SetRect( &rc);
// we reset then set this value each time through if we are climbing
onrungs = FALSE;
// Look for Walls which we are walking on or will run into during
// this move
for (SONxt = FirstWall(); SONxt != NULL; SONxt = NextWall())
{
if( (SONxt->shown) && (SONxt->InRect( &rc)))
{
if( x != oldx)
{
if( x > oldx)
{
if( ((x + width) > SONxt->x) && ((oldx + width) < SONxt->x))
x = (SONxt->x - width) - 1;
}
else
{
if( (x < (SONxt->x + (SONxt->width * SONxt->wmult)) ) &&
( oldx > (SONxt->x + (SONxt->width * SONxt->wmult)) ))
x = SONxt->x + (SONxt->width * SONxt->wmult) + 1;
}
}
if( y != oldy)
{
if( y > oldy)
{
if( ((y + height) > SONxt->y) && (oldy < SONxt->y) )
{
y = (SONxt->y - height) - 1;
jmpdir = PL_JMP_NO;
// We track this so we know we aren't falling
wallbelow = TRUE;
}
}
else
{
if( (y < (SONxt->y + (SONxt->height * SONxt->hmult)) ) &&
( oldy > (SONxt->y + (SONxt->height * SONxt->hmult)) ))
{
y = SONxt->y + (SONxt->height * SONxt->hmult) + 1;
jmptop = y;
jmpdir = PL_JMP_DN;
}
}
}
}
else if( (SONxt->y == (height +y + 1)))
{
RECT rc;
rc.top = y;
rc.bottom = y + height + 1;
rc.left = x;
rc.right = x + width;
if( SONxt->InRect( &rc) )
wallbelow = TRUE;
}
}
SetRect( &rc);
// See if we hit anything while moving
for( SONxt = Background->Next(); SONxt != NULL; SONxt = SONxt->Next())
{
if( (SONxt != this) && (SONxt->shown) && (SONxt->InRect( &rc)))
{
if( SOHit == NULL)
SOHit = SONxt;
else
{
if( (abs(oldy - SONxt->y) < abs(oldy - SOHit->y) ) ||
(abs(oldx - SONxt->x) < abs(oldx - SOHit->x) ) )
SOHit = SONxt;
}
}
}
// If we hit anything, see what it was
if( SOHit != NULL)
{
int hit;
hit = SOHit->Type();
switch (hit)
{
case TYPE_MISSILE:
case TYPE_HAZARD:
Hit( hit);
break;
// If we hit a prize, we hide it. If you added scoring,
// this is where you could add the Info value from
// the prize to the score
case TYPE_PRIZE:
if( SOHit->shown)
{
SOHit->Show(FALSE);
}
break;
// Exit, stage left! The Info value for a Door is the next
// scene number to go to
case TYPE_DOOR:
{
long next;
next = SOHit->Info;
Move( 0, 0);
InitScene( (int) next);
jmpdir = PL_JMP_DN;
return( TRUE);
}
break;
// If we hit a ladder, set the flag
case TYPE_RUNGS:
onrungs = TRUE;
break;
}
}
// If there is no Wall (floors are horizontal Walls) beneath us and
// we aren't jumping up and aren't on a ladder, then we are falling!
if(( ! wallbelow) && ( jmpdir != PL_JMP_UP) && (!onrungs) )
{
jmpdir = PL_JMP_DN;
}
// Here's that really slow panning action
if( (Background->width > WinX) || (Background->height > WinY) )
{
int oldsx = WinSX;
int oldsy = WinSY;
if( x != oldx)
{
if( x > oldx)
{
if( ( (WinSX + WinX) < Background->width) &&
( x > (WinSX + (WinX / 3 * 2) )) )
{
WinSX += x - (WinSX + (WinX / 3 * 2) );
if( (WinSX + WinX) > Background->width)
WinSX = Background->width - WinX;
}
}
else
{
if( (WinSX > 0) && (x < (WinSX + (WinX / 3) ) ) )
{
WinSX += x - (WinSX + (WinX / 3) );
if( WinSX < 0) WinSX = 0;
}
}
}
if( y != oldy)
{
if( y > oldy)
{
if( ( (WinSY + WinY) < Background->height) &&
( y > (WinSY + (WinY / 3 * 2) )) )
{
WinSY += y - (WinSY + (WinY / 3 * 2) );
if( (WinSY + WinY) > Background->height)
WinSY = Background->height - WinY;
}
}
else
{
if( (WinSY > 0) && (y < (WinSY + (WinY / 3 ) ) ) )
{
WinSY += y - (WinSY + (WinY / 3) );
if( WinSY < 0) WinSY = 0;
}
}
}
if( (oldsx != WinSX) || (oldsy != WinSY) )
{
ScrollWindow( hWnd, oldsx - WinSX, oldsy - WinSY, NULL, NULL);
SetWindowOrg( hDC, WinSX, WinSY);
}
}
Paint();
}
return( TRUE);
}
// This is where we know we have been hit. Currently we just hop up to the upper
// left of the screen. If you want to make this a "real" game, you might track
// lives and use some logic to determine where to place him
BOOL Player::Hit( int type)
{
if(type == TYPE_HAZARD)
{
Move( 0, 0);
WinSX = 0;
WinSY = 0;
InvalidateRect( hWnd, NULL, FALSE);
SetWindowOrg( hDC, WinSX, WinSY);
jmpdir = PL_JMP_DN;
return( TRUE);
}
return( FALSE);
}