NOGDUS

Blogs => Regretfulone's Blog => Topic started by: Regretfulone on May 12, 2010, 10:06:03 PM



Title: Computer Programming 2 Final Project
Post by: Regretfulone on May 12, 2010, 10:06:03 PM
Soooo I have to make a project with some kid who basically cheated through the whole class. Sadly I have to split the work evenly with him but I feel like he really doesn't know how to code very well. I have decided to let him do the graphics and focus on the main character and hope that satisfies my teacher haha.

Ok so the project we are working on is a vertical scrolling shooter game. The main character is going to be a fighter pilot and you will "fly" forward through the level shooting down the enemies to gain money and points. I am going to be working on the mechanical stuff behind the scenes like collision tests and making sure that the pilot can't go off the screen. The more daunting task I need to complete is writing the AI for the enemy pilots that will come on to the screen at certain points. I also feel like it might be a little difficult to figure out when to bring the enemy pilots onto the screen and how. Suggestion would be appreciated if anyone has any.

P.S. the project is all in c++ using allegro for graphics


Title: Re: Computer Programming 2 Final Project
Post by: Richard Marks on May 12, 2010, 10:55:35 PM
I can hack up a tiny demo for the enemies for you.
But not today. gotta go to work now.
ttyl.


Title: Re: Computer Programming 2 Final Project
Post by: Richard Marks on May 15, 2010, 08:03:27 PM
Okay, so I haven't gotten around to writing a demo of code for you Sam.
However, I did write this up.
Perhaps it will help you.

The game world is split along the Y axis into N "logical sectors".
Each logical sector is split into D "zones" along the X axis.
Each logical sector is (L * the height of your game screen) pixels high.
Each zone is (your game screen width / D) pixels wide.

N = number of waves of enemies (including a boss wave).
D = enemy density: the higher the number, the more enemies will be on screen at one time.
L = length of wave: the higher the number, the more enemies will be in the wave.



So now we have an unseen tile map, or grid of tiles.
   
Code:
const int SW = 320; // game screen is 320 pixels wide
const int SH = 200; // game screen is 200 pixels high

const int L = 24; // waves will be 24x the game screen height long
const int D = 10; // waves will have no more than 10 columns of enemies
const int N = 5;  // 4 standard enemy waves followed by 1 end-mission boss wave

const int ZoneSize = SW / D; // width of a zone
const int SectorSize = L * SH; // height of a sector

// place an enemy:

int enemyZone = D / 2; // center zone
int enemySector = 1; // first sector

float startX = 0.0f; // enemy starts at the ZSO (see below)
float startY = 0.0f;

// ZSO (Zone Sector Origin)

// find the zone origin (the absolute X position)
float enemyZO = (enemyZone * ZoneSize);

// find the sector origin
float enemySO = (enemySector * SectorSize);

// the position of the enemy is at vector ZSO + Start
float enemyX = enemyZO + startX;

// remember that we must negate the sector origin so that
// the enemies are placed farther away from the player as
// the numbes get larger for sectors
// (Remember: sector 1 is closest to the player)
float enemyY = (enemySO * -1.0f) + startY;

That is essentially the idea for how to handle the starting locations of the enemies.
I might write a demonstration of the technique, but right now my time is limited.
Good luck, and have fun. Feel free to ask questions.


Title: Re: Computer Programming 2 Final Project
Post by: Regretfulone on May 15, 2010, 10:53:37 PM
Thanks Richard! that definitely helped get me on the right track. I can see how you would use that to help split up enemies and where they start and stuff like that. I'll try and work that into some code that works with the project :)


Title: Re: Computer Programming 2 Final Project
Post by: Richard Marks on May 15, 2010, 11:26:30 PM
Glad you could understand that!  ;D

To create a mission, we will define a text file with the following format:
   
M {version}
{LDN}
{enemy 1}
{enemy 2}
{enemy N}

      
The file starts with a capital M. If this is not the case, the load will fail.
The {version} will let you tell the mission spec at load time.
   
Where {LDN} is a definition with this data:
      
<Wave Length> <Enemy Density> <Number of Waves>
      
Where {enemy #} is a definition with this data:
      
<Enemy Type> <Start Vector> <Normalized Direction Vector> <Speed> <Zone> <Sector>
   
An example mission file with 7 enemies in a "flying V formation" is shown below.
The enemies are in the 2nd sector in the center 7 zones.
comments are lines starting with a # sign.

Code:
M 1.0
# demo1.m
# Vertical Shooter Mission File
# (C) 2010, Richard Marks <ccpsceo@gmail.com>
# "Flying V Formation" Example
#####################################################################

# LDN
# waves will be 24x the game screen height long
# waves will have no more than 10 columns of enemies
# 4 standard enemy waves followed by 1 end-mission boss wave
LDN 24 10 5

# Enemies
# <Enemy Type> <Start Vector> <Normalized Direction Vector> <Speed> <Zone> <Sector>
E 0 0.0 0.0 0.0 1.0 4.0 2 2
E 0 66.0 66.0 0.0 1.0 4.0 3 2
E 0 132.0 132.0 0.0 1.0 4.0 4 2
E 1 200.0 200.0 0.0 1.0 4.0 5 2
E 0 266.0 132.0 0.0 1.0 4.0 6 2
E 0 332.0 66.0 0.0 1.0 4.0 7 2
E 0 400.0 0.0 0.0 1.0 4.0 8 2

Below is a really quick hack to show one way you can load the mission file.
It makes use of only C style text parsing techniques, and not using any C++ STL confusion (which ironically can make things more confusing by NOT using the STL..oh well. it works, and its just a hack anyway)

Code:
#include <cstdio>
#include <cstdlib>
#include <cstring>

bool LoadMissionFile(const char* fileName)
{
FILE* fp = fopen(fileName, "rb");
if (!fp)
{
printf("Error: Cannot open File %s!\n", fileName);
return false;
}

// validate file type
unsigned int fid[2] = {0};
fread(fid, sizeof(unsigned int), 2, fp);
if (!(fid[0] == 0x2E31204D && fid[1] == 0x0A0D2B30))
{
printf("Error: File ID Invalid!\n\nID Found: %08X %08X", fid[0], fid[1]);
return false;
}
// close and reopen file in text mode
fp = freopen(fileName, "r", fp);

// read lines
char lineBuffer[0x1000]; int lines = 0, comments = 0;
printf("BEGIN\n");
while(fgets(lineBuffer, sizeof(lineBuffer), fp))
{
// strip newline character from the end of the line
int lineLength = strlen(lineBuffer);
if ('\n' == lineBuffer[lineLength - 1])
{
lineBuffer[lineLength - 1] = '\0';
}
// ignore comments (lines that start with #)
char firstChar = lineBuffer[0];
if ('#' == firstChar)
{
comments++;
lines++;
}
else
{
printf("%4d:%s\n", lines++, lineBuffer);

if ('E' == firstChar)
{
// enemy data in this line
// parse it out
// we expect 8 pieces of data,
// we can easily validate this by counting the number of spaces in the line
// if there are not 7 spaces, we don't have the right data and should bail out
// of the parser.
int spaces = 0;
for (int i = 2; i < lineLength; i++)
{
if (' ' == lineBuffer[i])
{
spaces++;
}
}
if (spaces != 7)
{
printf("Error: Malformed Data for Enemy Definition in Line %d\n", lines - 1);
return false;
}

// tokenize the line
char* token = strtok(lineBuffer, " ");
int n = 0;
while(token)
{
switch(n)
{
case 0:
{
// enemy type
unsigned char enemyType = (unsigned char)atoi(token);
printf("\tType: %d\n", (int)enemyType);
} break;
case 1:
{
// X starting coordinate
float enemyStartX = atof(token);
printf("\tStart X: %f\n", enemyStartX);
} break;
case 2:
{
// Y starting coordinate
float enemyStartY = atof(token);
printf("\tStart Y: %f\n", enemyStartY);
} break;
case 3:
{
// direction vector X
float enemyDX = atof(token);
printf("\tDirection Vector X: %f\n", enemyDX);
} break;
case 4:
{
// direction vector Y
float enemyDY = atof(token);
printf("\tDirection Vector Y: %f\n", enemyDY);
} break;
case 5:
{
// speed
float enemySpeed = atof(token);
printf("\tSpeed: %f\n", enemySpeed);
} break;
case 6:
{
// zone
unsigned char enemyZone = (unsigned char)atoi(token);
printf("\tZone: %d\n", (int)enemyZone);
} break;
case 7:
{
// sector
unsigned char enemySector = (unsigned char)atoi(token);
printf("\tSector: %d\n", (int)enemySector);
} break;
default: break;
}
token = strtok(0, " ");
n++;
}

}

if ('L' == firstChar)
{
// LDN data in this line
// parse it out
}
}
}
printf("END\nLines: %d Comments: %d", lines, comments);

fclose(fp);
return true;
}

int main(int argc, char* argv[])
{
if (!LoadMissionFile("mission1.m"))
{
printf("Load Failed.\n");
}

while('\n'!=fgetc(stdin));
return 0;
}

One thing to note about the code above, is that it performs validation on the file.
Which means that it properly handles if the file you are trying to load is improperly formatted, and/or not a mission file.
Some good techniques to learn are hidden in there.

Have fun man. I gotta go to bed now. got work in the morning.

(edit) Oh yeah, atached is an image showing the flying V formation if you were curious.