Jump to content

  • Log In with Google      Sign In   
  • Create Account


#ActualBeerNutts

Posted 01 November 2012 - 01:17 PM

mypel16000,

You should check out my Old Blog (also linked in my sig). I detail the steps for making a top-down 2d game similar to what you are suggesting (player starts in map, enemies spawn from an "Enemy Spawn", bullets shooting everywhere).

(Here's the link to the entry on adding enemies to my game: Click Here)

In general, my Enemy Spawn's are considered an item, and I update it like this:

BOOL SmashPcItem::Update(void)
{

	// Release Enemies into the level
	if (mpItemDetails->Type == "EnemySpawn")
	{
		if (mu32NumReleaseLeft && (mu32LastRelease + mpItemDetails->u32ReleaseRate < timeGetTime()))
		{
			SmashPcEnemy *pEnemy;
			mu32LastRelease = timeGetTime();
			mu32NumReleaseLeft--;
			// Create an enemy
			pEnemy = new SmashPcEnemy(mGameData, mpApp, mpSpace,
				  mpBody->p, mpItemDetails->u32EnemyLevel);
			// Check if this enemy should release something
			mGameData.AddActiveEnemy(pEnemy);
		}
	}
	return mbActive;
}

Which basically says, if there are still enemies to release, and if it's time to release a new enemy, then create a new enemy, and add him to the list of active enemies. Here's what the enemies actually do (the full Enemy class here):
/******************************************************************************
*
* SmashPcEnemy() - Creates a player, and places him in the space
*
******************************************************************************/
SmashPcEnemy::SmashPcEnemy(SmashPcData &GameData,
							 sf::RenderWindow *pApp, cpSpace *pSpace,
							 cpVect Location, U32 u32Level) :
PhysicalObject(pApp, pSpace, "Gfx/blueenemy.bmp", "",
			   Location, PI/2.0f, 0.0f, TRUE),
mu32Health(20*u32Level),
mu32LastFire(timeGetTime()),
mu32LastMoveUpdate(0),
mGameData(GameData)
{
	printf("Enemy created!\n");
	// Set the Velocity limit to our fake movement
mpBody->v_limit = ENEMY_SPEED;
	mpShape->collision_type = ENEMY_COL_TYPE;
	mpShape->layers = ENEMY_PLAYER_LAYER;
mpShape->data = (void *)this;
// Create Collision handler here
cpSpaceAddCollisionHandler(mpSpace, ENEMY_COL_TYPE, BULLET_COL_TYPE, SmashPcEnemy::BulletCollision, NULL, NULL, NULL, NULL);
	// Sound notifying a player has spawned
	GameSound::Play("EnemySpawn");
}
/******************************************************************************
*
* ~SmashPcEnemy() - Removes a player
*
******************************************************************************/
SmashPcEnemy::~SmashPcEnemy()
{
}
/******************************************************************************
*
* Update() - Do enemy things
*
******************************************************************************/
void SmashPcEnemy::Update(cpBody *pPlayerBody)
{
	U32 u32Time = timeGetTime();
	// check if we need to update the movement
	if (mu32LastMoveUpdate + ENEMY_UPDATE_MOVE < u32Time)
	{
		cpFloat Angle = atan2(pPlayerBody->p.y - mpBody->p.y,
							  pPlayerBody->p.x - mpBody->p.x);
		// add randomization to angle
		cpFloat RandomDegrees = (cpFloat)(((S32)rand() % 20) - 10);
		Angle += (RandomDegrees*PI)/180.0f;
		cpBodySetAngle(mpBody, Angle);
		// Change force towards player
		mForce = cpv(ENEMY_FORCE*cos(Angle), ENEMY_FORCE*sin(Angle));
		//mpBody->f = cpv(ENEMY_FORCE*cos(Angle), ENEMY_FORCE*sin(Angle));
		mu32LastMoveUpdate = u32Time;
	}
	mpBody->f = mForce;
	if (mu32LastFire + ENEMY_REFIRE_TIME < u32Time)
	{
		SmashPcData::tBulletList BulletList;
		mGameData.GetBulletList(BulletList);
		SmashPcBullet *pBullet = new SmashPcBullet(mpApp, BulletList[0],
				  mpBody, mpSpace, FALSE);
		mGameData.AddActiveBullet(pBullet);
		mu32LastFire = u32Time;
	}
}
/******************************************************************************
*
* NotifyHit() - Notify the enemy it has been hit by a bullet
*
******************************************************************************/
void SmashPcEnemy::NotifyHit(SmashPcBullet *pBullet)
{
	if (mu32Health < pBullet->GetDamage())
	{
		// Enemy Dead
		mu32Health = 0;
		// Play dead sound
	}
	else
	{
		GameSound::Play("PlayerHit");
		mu32Health -= pBullet->GetDamage();
	}
	pBullet->SetDead();
}
/******************************************************************************
*
* BulletCollision() - Callback for when Enemy hits a bullet
*
******************************************************************************/
int SmashPcEnemy::BulletCollision(cpArbiter *arb, struct cpSpace *space, void *data)
{
	SmashPcBullet *pBullet;
	SmashPcEnemy *pEnemy;
	cpShape *pBulletShape, *pEnemyShape;
	cpArbiterGetShapes(arb, &pEnemyShape, &pBulletShape);
	pEnemy = reinterpret_cast<SmashPcEnemy*>(pEnemyShape->data);
	pBullet = reinterpret_cast<SmashPcBullet*>(pBulletShape->data);
	// We have the enemy that hit, and the bullet he hit
	pEnemy->NotifyHit(pBullet);
	return 0;
}

I updated my enemies later on to make them a little smarter and to shoot better, but you get the picture.

#1BeerNutts

Posted 01 November 2012 - 01:15 PM

mypel16000,

You should check out my Old Blog (also linked in my sig). I detail the steps for making a top-down 2d game similar to what you are suggesting (player starts in map, enemies spawn from an "Enemy Spawn", bullets shooting everywhere).

(Here's the link to the entry on adding enemies to my game: Click Here)


In general, my Enemy Spawn's are considered an item, and I update it like this:

BOOL SmashPcItem::Update(void)
{

    // Release Enemies into the level
    if (mpItemDetails->Type == "EnemySpawn")
    {
	    if (mu32NumReleaseLeft && (mu32LastRelease + mpItemDetails->u32ReleaseRate < timeGetTime()))
	    {
		    SmashPcEnemy *pEnemy;
		    mu32LastRelease = timeGetTime();
		    mu32NumReleaseLeft--;
		    // Create an enemy
		    pEnemy = new SmashPcEnemy(mGameData, mpApp, mpSpace,
				  mpBody->p, mpItemDetails->u32EnemyLevel);
		    // Check if this enemy should release something
		    mGameData.AddActiveEnemy(pEnemy);
	    }
    }
    return mbActive;
}

Which basically says, if there are still enemies to release, and if it's time to release a new enemy, then create a new enemy, and add him to the list of active enemies. Here's what the enemies actually do (the full Enemy class here):
/******************************************************************************
*
* SmashPcEnemy() - Creates a player, and places him in the space
*
******************************************************************************/
SmashPcEnemy::SmashPcEnemy(SmashPcData &GameData,
							 sf::RenderWindow *pApp, cpSpace *pSpace,
							 cpVect Location, U32 u32Level) :
PhysicalObject(pApp, pSpace, "Gfx/blueenemy.bmp", "",
			   Location, PI/2.0f, 0.0f, TRUE),
mu32Health(20*u32Level),
mu32LastFire(timeGetTime()),
mu32LastMoveUpdate(0),
mGameData(GameData)
{
    printf("Enemy created!\n");
    // Set the Velocity limit to our fake movement
mpBody->v_limit = ENEMY_SPEED;
    mpShape->collision_type = ENEMY_COL_TYPE;
    mpShape->layers = ENEMY_PLAYER_LAYER;
mpShape->data = (void *)this;
// Create Collision handler here
cpSpaceAddCollisionHandler(mpSpace, ENEMY_COL_TYPE, BULLET_COL_TYPE, SmashPcEnemy::BulletCollision, NULL, NULL, NULL, NULL);
    // Sound notifying a player has spawned
    GameSound::Play("EnemySpawn");
}
/******************************************************************************
*
* ~SmashPcEnemy() - Removes a player
*
******************************************************************************/
SmashPcEnemy::~SmashPcEnemy()
{
}
/******************************************************************************
*
* Update() - Do enemy things
*
******************************************************************************/
void SmashPcEnemy::Update(cpBody *pPlayerBody)
{
    U32 u32Time = timeGetTime();
    // check if we need to update the movement
    if (mu32LastMoveUpdate + ENEMY_UPDATE_MOVE < u32Time)
    {
	    cpFloat Angle = atan2(pPlayerBody->p.y - mpBody->p.y,
							  pPlayerBody->p.x - mpBody->p.x);
	    // add randomization to angle
	    cpFloat RandomDegrees = (cpFloat)(((S32)rand() % 20) - 10);
	    Angle += (RandomDegrees*PI)/180.0f;
	    cpBodySetAngle(mpBody, Angle);
	    // Change force towards player
	    mForce = cpv(ENEMY_FORCE*cos(Angle), ENEMY_FORCE*sin(Angle));
	    //mpBody->f = cpv(ENEMY_FORCE*cos(Angle), ENEMY_FORCE*sin(Angle));
	    mu32LastMoveUpdate = u32Time;
    }
    mpBody->f = mForce;
    if (mu32LastFire + ENEMY_REFIRE_TIME < u32Time)
    {
	    SmashPcData::tBulletList BulletList;
	    mGameData.GetBulletList(BulletList);
	    SmashPcBullet *pBullet = new SmashPcBullet(mpApp, BulletList[0],
				  mpBody, mpSpace, FALSE);
	    mGameData.AddActiveBullet(pBullet);
	    mu32LastFire = u32Time;
    }
}
/******************************************************************************
*
* NotifyHit() - Notify the enemy it has been hit by a bullet
*
******************************************************************************/
void SmashPcEnemy::NotifyHit(SmashPcBullet *pBullet)
{
    if (mu32Health < pBullet->GetDamage())
    {
	    // Enemy Dead
	    mu32Health = 0;
	    // Play dead sound
    }
    else
    {
	    GameSound::Play("PlayerHit");
	    mu32Health -= pBullet->GetDamage();
    }
    pBullet->SetDead();
}
/******************************************************************************
*
* BulletCollision() - Callback for when Enemy hits a bullet
*
******************************************************************************/
int SmashPcEnemy::BulletCollision(cpArbiter *arb, struct cpSpace *space, void *data)
{
    SmashPcBullet *pBullet;
    SmashPcEnemy *pEnemy;
    cpShape *pBulletShape, *pEnemyShape;
    cpArbiterGetShapes(arb, &pEnemyShape, &pBulletShape);
    pEnemy = reinterpret_cast<SmashPcEnemy*>(pEnemyShape->data);
    pBullet = reinterpret_cast<SmashPcBullet*>(pBulletShape->data);
    // We have the enemy that hit, and the bullet he hit
    pEnemy->NotifyHit(pBullet);
    return 0;
}

PARTNERS