#include <GL/glut.
h>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <ctime>
// Camera position and orientation
float cameraX = 0.0f, cameraY = 1.0f, cameraZ = 5.0f;
float lookX = 0.0f, lookY = 0.0f, lookZ = -1.0f;
float angleX = 0.0f, angleY = 0.0f;
// Movement variables
bool keyStates[256] = {false};
float moveSpeed = 0.1f;
float mouseSensitivity = 0.2f;
// Target structure
struct Target {
float x, y, z;
bool active;
};
std::vector<Target> targets;
// Bullet structure
struct Bullet {
float x, y, z;
float dx, dy, dz;
bool active;
};
std::vector<Bullet> bullets;
// Score
int score = 0;
void initTargets() {
srand(time(0));
for (int i = 0; i < 10; ++i) {
Target t;
t.x = (rand() % 20) - 10;
t.y = (rand() % 4) + 0.5f;
t.z = (rand() % 20) - 20;
t.active = true;
targets.push_back(t);
void drawTarget(float x, float y, float z) {
glPushMatrix();
glTranslatef(x, y, z);
glColor3f(1.0f, 0.0f, 0.0f); // Red target
// Draw a simple cube as target
glutSolidCube(0.5f);
glPopMatrix();
void drawBullet(float x, float y, float z) {
glPushMatrix();
glTranslatef(x, y, z);
glColor3f(1.0f, 1.0f, 0.0f); // Yellow bullet
// Draw a small sphere as bullet
glutSolidSphere(0.1f, 10, 10);
glPopMatrix();
void drawCrosshair() {
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0, 100, 0, 100);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_LINES);
// Horizontal line
glVertex2f(48, 50);
glVertex2f(52, 50);
// Vertical line
glVertex2f(50, 48);
glVertex2f(50, 52);
glEnd();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glEnable(GL_DEPTH_TEST);
void fireBullet() {
Bullet b;
b.x = cameraX;
b.y = cameraY;
b.z = cameraZ;
// Direction vector is the camera's look direction
b.dx = lookX * 0.5f;
b.dy = lookY * 0.5f;
b.dz = lookZ * 0.5f;
b.active = true;
bullets.push_back(b);
void updateBullets() {
for (size_t i = 0; i < bullets.size(); ) {
if (!bullets[i].active) {
bullets.erase(bullets.begin() + i);
continue;
}
bullets[i].x += bullets[i].dx;
bullets[i].y += bullets[i].dy;
bullets[i].z += bullets[i].dz;
// Check if bullet hits any target
for (size_t j = 0; j < targets.size(); ++j) {
if (targets[j].active &&
abs(bullets[i].x - targets[j].x) < 0.5f &&
abs(bullets[i].y - targets[j].y) < 0.5f &&
abs(bullets[i].z - targets[j].z) < 0.5f) {
targets[j].active = false;
bullets[i].active = false;
score++;
break;
// Deactivate bullet if it goes too far
if (abs(bullets[i].x) > 50 || abs(bullets[i].y) > 50 || bullets[i].z < -50) {
bullets[i].active = false;
i++;
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
// Set camera position and orientation
gluLookAt(cameraX, cameraY, cameraZ,
cameraX + lookX, cameraY + lookY, cameraZ + lookZ,
0.0f, 1.0f, 0.0f);
// Draw ground
glColor3f(0.5f, 0.5f, 0.5f);
glBegin(GL_QUADS);
glVertex3f(-50.0f, 0.0f, -50.0f);
glVertex3f(-50.0f, 0.0f, 50.0f);
glVertex3f( 50.0f, 0.0f, 50.0f);
glVertex3f( 50.0f, 0.0f, -50.0f);
glEnd();
// Draw targets
for (const Target& t : targets) {
if (t.active) {
drawTarget(t.x, t.y, t.z);
// Draw bullets
for (const Bullet& b : bullets) {
if (b.active) {
drawBullet(b.x, b.y, b.z);
}
}
// Draw crosshair
drawCrosshair();
// Display score
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0, 100, 0, 100);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glColor3f(1.0f, 1.0f, 1.0f);
glRasterPos2f(10, 90);
std::string scoreStr = "Score: " + std::to_string(score);
for (char c : scoreStr) {
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, c);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glEnable(GL_DEPTH_TEST);
glutSwapBuffers();
void reshape(int w, int h) {
if (h == 0) h = 1;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0f, (float)w / (float)h, 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);
void keyboard(unsigned char key, int x, int y) {
keyStates[key] = true;
if (key == 27) { // ESC key
exit(0);
void keyboardUp(unsigned char key, int x, int y) {
keyStates[key] = false;
void mouse(int x, int y) {
static int centerX = 400, centerY = 300;
int deltaX = x - centerX;
int deltaY = y - centerY;
angleY += deltaX * mouseSensitivity;
angleX += deltaY * mouseSensitivity;
// Clamp vertical rotation
if (angleX > 89.0f) angleX = 89.0f;
if (angleX < -89.0f) angleX = -89.0f;
// Calculate new look direction
lookX = sin(angleY * M_PI / 180.0f);
lookY = -sin(angleX * M_PI / 180.0f);
lookZ = -cos(angleY * M_PI / 180.0f) * cos(angleX * M_PI / 180.0f);
// Normalize look vector
float length = sqrt(lookX*lookX + lookY*lookY + lookZ*lookZ);
lookX /= length;
lookY /= length;
lookZ /= length;
// Reset mouse to center of screen
glutWarpPointer(centerX, centerY);
void mouseClick(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
fireBullet();
}
}
void update(int value) {
// Handle movement based on key states
if (keyStates['w']) {
cameraX += lookX * moveSpeed;
cameraZ += lookZ * moveSpeed;
if (keyStates['s']) {
cameraX -= lookX * moveSpeed;
cameraZ -= lookZ * moveSpeed;
if (keyStates['a']) {
// Strafe left
cameraX -= cos(angleY * M_PI / 180.0f) * moveSpeed;
cameraZ += sin(angleY * M_PI / 180.0f) * moveSpeed;
if (keyStates['d']) {
// Strafe right
cameraX += cos(angleY * M_PI / 180.0f) * moveSpeed;
cameraZ -= sin(angleY * M_PI / 180.0f) * moveSpeed;
if (keyStates[' ']) { // Space bar
cameraY += moveSpeed;
if (keyStates['c']) {
cameraY -= moveSpeed;
}
// Keep camera above ground
if (cameraY < 0.5f) cameraY = 0.5f;
updateBullets();
glutPostRedisplay();
glutTimerFunc(16, update, 0); // ~60 FPS
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(800, 600);
glutCreateWindow("Simple FPS Game");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutKeyboardUpFunc(keyboardUp);
glutPassiveMotionFunc(mouse);
glutMouseFunc(mouseClick);
glutTimerFunc(0, update, 0);
// Hide cursor and capture mouse
glutSetCursor(GLUT_CURSOR_NONE);
glutWarpPointer(400, 300);
// Initialize game elements
initTargets();
// Enable depth testing
glEnable(GL_DEPTH_TEST);
glutMainLoop();
return 0;