Professional Documents
Culture Documents
website: http://media-it.blogspot.com/2008/02/speed-typing-game.html
License:
CREATIVE COMMONS Attribution-Noncommercial-Share Alike 3.0 Germany
You may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://creativecommons.org/licenses/by-nc-sa/3.0/de/deed.de
• Namensnennung.
Sie müssen den Namen des Autors/Rechteinhabers in der von ihm
festgelegten Weise nennen.
#endif
main.h — Printed on 29.12.2008, 13:29:14 — Page 1
#ifndef MAIN_H_
#define MAIN_H_
class game
{
public:
Game();
virtual ~Game();
};
void initRendering(void);
#endif
main.cpp — Printed on 29.12.2008, 13:28:56 — Page 1
/******************************************************
* Kai Kajus Noack *
* Project: "Game: SpongeBob's Words" *
* Date: 2008-01-20 *
******************************************************/
#include <iostream>
#include <stdlib.h>
#include <GL/glut.h>
#include <GL/gl.h>
#include "text3d.h"
// selbstdefinierte Konstanten
#include "const.h"
// zum Dateieinlesen
#include <fstream>
#include <iomanip>
// für Casting int zu String
#include <sstream>
#include <string>
// für Texturen
#include "imageloader.h"
// der Timer
#include <time.h>
// trigonometrische Funktionen
#include <math.h>
// Objekt: Wort (Spielelement)
#include "Word.h"
// vektor-klasse zum zeichnen
#include <vector>
#include "vec3f.h"
// Seitenfläche Alpha-Würfel
struct Cube {
Face top;
Face bottom;
Face left;
Face right;
Face front;
Face back;
};
// Timer-Variablen
int minutes, sek, recentTime;
// Spielzeit in Sekunden
clock_t startTime, endTime;
// Spielzeit
int countDownTime = COUNTDOWN;
string timeSpent;
// Statistisch mitzählen
int charCounter = 0;
int wordCounter = 0;
int wordFalse = 0;
int wordRight = 0;
// Punkte speichern
int scoreInt = 0;
string score;
string createNewWord(void) {
// initialisieren eines Random (notwendig für nä. Fkt.aufruf)
srand ( time(NULL) );
// generate random number
randomNr = rand() % WORTANZAHL;
// zu lange Wörter ggf. kürzen
if((alleWoerter[randomNr]).length()>=(unsigned)MAXWORTLAENGE) {
return (alleWoerter[randomNr]).substr(0,MAXWORTLAENGE-1);
}
return allWords[randomNr];
}
void resetInputState(void) {
// bisherige Eingaben löschen
eingabewort.clear();
for (int j = 0; j < MAXWORTLAENGE; j++) {
keyboardInput[j] = '\0';
}
// Position des Wortes auf Bildschirm zurücksetzen
wort->resetWordPos();
}
// Textur-Loader
GLuint loadTexture(Image *image) {
GLuint texture;
main.cpp — Printed on 29.12.2008, 13:28:56 — Page 6
glGenTextures(1, &texture);
// Textur den Bilddaten zuordnen
glBindTexture(GL_TEXTURE_2D, texture);
// Mappen des Bildes auf die Textur (Bild nach OpenGL laden)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image->width, image->height, 0, GL_RGB,
GL_UNSIGNED_BYTE, image->pixels); //The actual pixel data
// Textur-ID zurückgeben
return texture;
}
// 3D-Text bereinigen
void cleanup() {
t3dCleanup();
}
// Rendern vorbereiten
void initRendering() {
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHT1);
glEnable(GL_NORMALIZE);
glShadeModel(GL_SMOOTH);
glEnable(GL_FOG);
glClearColor(0.1f, 0.1f, 0.15f, 1);
// Initialisierung der 3D-Schriften
t3dInit();
image = loadBMP("img/spongebob.bmp");
_textureIdSponge = loadTexture(image);
delete image;
}
typedef struct {
double Xpos;
double Ypos;
double Zpos;
double Xmov;
double Zmov;
double Red;
main.cpp — Printed on 29.12.2008, 13:28:56 — Page 7
double Green;
double Blue;
double Direction;
double Acceleration;
double Deceleration;
double Scalez;
bool Visible;
}PARTICLES;
PARTICLES Particle[ParticleCount];
void initParticles() {
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glCreateParticles();
}
void paintFlyingCube() {
// Optional:
// Rotes ambientes Licht neben Würfel hinzufügen
// GLfloat ambientColor[] = {0.2f, 0.2f, 0.2f, 1.0f};
// glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientColor);
// GLfloat lightColor1[] = {1.5f, 0.5f, 0.5f, 1.0f};
// GLfloat lightPos1[] = {2.0f, 0.0f, 2.0f, 1.0f};
// glLightfv(GL_LIGHT1, GL_DIFFUSE, lightColor1);
// glLightfv(GL_LIGHT1, GL_POSITION, lightPos1);
glPushMatrix();
glTranslatef(-8.0f, 0.0f, 0.0f);
glRotatef(_angle, 0.0f, 1.0f, 0.0f);
glColor3f(1.0f, 1.0f, 0.0f);
main.cpp — Printed on 29.12.2008, 13:28:56 — Page 9
glBegin(GL_QUADS);
// Smooth Shading (für jeden Punkt eine eigene Normale!)
// Front
glNormal3f(-1.0f, 0.0f, 1.0f);
glVertex3f(-1.5f+offsetX, -1.0f, 1.5f);
glNormal3f(1.0f, 0.0f, 1.0f);
glVertex3f(1.5f+offsetX, -1.0f, 1.5f);
glNormal3f(1.0f, 0.0f, 1.0f);
glVertex3f(1.5f+offsetX, 1.0f, 1.5f);
glNormal3f(-1.0f, 0.0f, 1.0f);
glVertex3f(-1.5f+offsetX, 1.0f, 1.5f);
// Rechts
glNormal3f(1.0f, 0.0f, -1.0f);
glVertex3f(1.5f+offsetX, -1.0f, -1.5f);
glNormal3f(1.0f, 0.0f, -1.0f);
glVertex3f(1.5f+offsetX, 1.0f, -1.5f);
glNormal3f(1.0f, 0.0f, 1.0f);
glVertex3f(1.5f+offsetX, 1.0f, 1.5f);
glNormal3f(1.0f, 0.0f, 1.0f);
glVertex3f(1.5f+offsetX, -1.0f, 1.5f);
// Hinten
glNormal3f(-1.0f, 0.0f, -1.0f);
glVertex3f(-1.5f+offsetX, -1.0f, -1.5f);
glNormal3f(-1.0f, 0.0f, -1.0f);
glVertex3f(-1.5f+offsetX, 1.0f, -1.5f);
glNormal3f(1.0f, 0.0f, -1.0f);
glVertex3f(1.5f+offsetX, 1.0f, -1.5f);
glNormal3f(1.0f, 0.0f, -1.0f);
glVertex3f(1.5f+offsetX, -1.0f, -1.5f);
// Links
glNormal3f(-1.0f, 0.0f, -1.0f);
glVertex3f(-1.5f+offsetX, -1.0f, -1.5f);
glNormal3f(-1.0f, 0.0f, 1.0f);
glVertex3f(-1.5f+offsetX, -1.0f, 1.5f);
glNormal3f(-1.0f, 0.0f, 1.0f);
glVertex3f(-1.5f+offsetX, 1.0f, 1.5f);
glNormal3f(-1.0f, 0.0f, -1.0f);
glVertex3f(-1.5f+offsetX, 1.0f, -1.5f);
glEnd();
glPopMatrix();
int blitzZaehler = 0;
void blitzen() {
// Blitz-Effekt im Hintergrund
if (0==blitzZaehler%2) glClearColor(2.0f, 2.0f, 2.0f, 1);
else glClearColor(0.1f, 0.1f, 0.15f, 1);
blitzZaehler++;
// auf 5 Blitze beschränken
if (blitzZaehler>MAXBLITZE) {
blitz = false;
blitzZaehler=0;
glClearColor(0.1f, 0.1f, 0.15f, 1);
}
}
// Startbildschirm:
if (startScreen) {
switch (key) {
case 27: // Escape
cleanup();
exit(0);
break;
case '1':
gamemode = "countdown";
startScreen = false;
break;
case '2':
gamemode = "training";
startScreen = false;
break;
default:
cout << "falsche Eingabe" << endl;
}
resetInputState();
}
// Spiel läuft:
else if (!gameOver) {
charCounter++;
switch (key) {
case 27: // Escape
cleanup();
exit(0);
break;
case '\r':
checkUserInput();
break;
default:
keyboardInput[inputChar] = key;
main.cpp — Printed on 29.12.2008, 13:28:56 — Page 11
eingabewort = keyboardInput;
inputChar++;
}
// Eingabe ist zu lang
if ((unsigned)inputChar>wort->name.length()) {
score = setScore(-1);
resetInputState();
inputChar = 0;
}
}
// wenn GameOver aktiv ist:
else {
switch (key) {
case 27: // Escape
cleanup();
exit(0);
break;
// Neustart des Spiels via Enter-Taste
case '\r':
// Neu-Initialisierungen
charCounter = 0;
wordCounter = 0;
wordFalse = 0;
wordRight = 0;
scoreInt = 0;
score = setScore(0);
countDownTime = COUNTDOWN;
startTime = clock();
offsetX = 1.0f;
startScreen = true;
gameOver = false;
resetInputState();
break;
}
}
}
// Konvertierung
double convertRADtoANGLE(double rad) {
double angle0 = rad * 2 * PI / 360;
return angle0;
}
// Zahl runden
double Round(double Zahl, unsigned int Stellen) {
Zahl *= pow(10, Stellen);
if (Zahl >= 0)
Zahl = floor(Zahl + 0.5);
else
Zahl = ceil(Zahl - 0.5);
Zahl /= pow(10, Stellen);
return Zahl;
}
if (psychomode) {
double r = 20.0f;
double tiefeC = 8.0f;
int stepF = 90;
glColor3f(1.0f,0.0f,0.0f);
glPushMatrix();
glTranslatef(0.0f,0.0f,-20.0f);
// eine interessante Rotation der Box
glRotatef(_angle2, cos(convertRADtoANGLE(_angle)), 0.5f, 1.0f);
if(gamemode=="training") {
if (sek >= 60) {
sek = 0;
main.cpp — Printed on 29.12.2008, 13:28:56 — Page 15
minutes++;
}
if (sek < 10) outTime << "Time " << minutes << ":0" << sek << endl;
else {
outTime << "Time " << minutes << ":" << sek << endl;
}
}
else if (gamemode=="countdown") {
outTime << "Time: " << countDownTime << endl;
}
timeSpent = outTime.str();
}
glBegin(GL_QUADS);
glNormal3f(0.0, 1.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(0.0f, 0.0f, 3.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(0.0f, 0.0f, 0.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(3.0f, 0.0f, 0.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(3.0f, 0.0f, 3.0f);
glEnd();
glDisable(GL_TEXTURE_2D);
glPopMatrix();
glEnable(GL_FOG);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -8.0f);
// Licht einstellen
GLfloat ambientColor[] = {0.4f, 0.4f, 0.4f, 1.0f};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientColor);
GLfloat lightColor0[] = {0.6f, 0.6f, 0.6f, 1.0f};
GLfloat lightPos0[] = {-0.5f, 0.5f, 1.0f, 0.0f};
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor0);
glLightfv(GL_LIGHT0, GL_POSITION, lightPos0);
// SPIELENDE
if (gameOver) {
// kalkuliere Punkte + Statistik
double result;
if (scoreInt <= 0) result = 0;
else result = double(COUNTDOWN)/double(scoreInt);
showGameOver(result);
}
// SPIELSTART
else if (startScreen) {
showStartScreen();
}
// SPIEL LÄUFT!
main.cpp — Printed on 29.12.2008, 13:28:56 — Page 17
else {
// bewege das Wort
moveAndPaintWord(wort->name);
// zeige bereits eingebenes Wort
showKeyboardInput();
// Grafikelemente zeichnen
paintFog();
paintFloor();
paintSpongebob();
paintFlyingCube();
paintAlphaCube();
glutSwapBuffers();
}
glutDisplayFunc(drawScene);
glutKeyboardFunc(handleKeypress);
glutReshapeFunc(handleResize);
glutTimerFunc(25, update, 0);
// schreibe Timer-Startzeit
startTime = clock();
// weitere Initialisierungen
initParticles();
initCube(_cube);
glutMainLoop();
return 0;
}
text3d.h — Printed on 29.12.2008, 13:30:14 — Page 1
/* File for "Drawing Text" lesson of the OpenGL tutorial on
* www.videotutorialsrock.com
*/
#ifndef TEXT_3D_H_INCLUDED
#define TEXT_3D_H_INCLUDED
#include <string>
#endif
text3d.cpp — Printed on 29.12.2008, 13:29:58 — Page 1
/* File for "Drawing Text" lesson of the OpenGL tutorial on
* www.videotutorialsrock.com
*/
#include <fstream>
#include <math.h>
#ifdef __APPLE__
#include <OpenGL/OpenGL.h>
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include "text3d.h"
namespace {
//Converts a four-character array to an integer, using little-endian form
int toInt(const char* bytes) {
return int(((unsigned char)bytes[3] << 24) |
((unsigned char)bytes[2] << 16) |
((unsigned char)bytes[1] << 8) |
(unsigned char)bytes[0]);
}
~auto_array() {
if (!isReleased && array != NULL) {
delete[] array;
}
}
T* get() const {
return array;
}
T &operator*() const {
return *array;
}
T* operator->() const {
return array;
}
T* release() {
isReleased = true;
return array;
}
T* operator+(int i) {
return array + i;
}
T &operator[](int i) {
return array[i];
}
text3d.cpp — Printed on 29.12.2008, 13:29:58 — Page 4
};
class T3DFont {
private:
float spaceWidth;
float widths[94];
GLuint displayListId2D;
GLuint displayListId3D;
public:
//Loads the specified font file into a new T3DFont object
T3DFont(ifstream &input) {
char buffer[8];
input.read(buffer, 8);
if (input.fail()) {
throw T3DLoadException("Invalid font file");
}
input.read(buffer, 5);
spaceWidth = toFloat(buffer);
displayListId2D = glGenLists(94);
displayListId3D = glGenLists(94);
for(int i = 0; i < 94; i++) {
input.read(buffer, 5);
float scale = toFloat(buffer) / 65536;
input.read(buffer, 2);
float width = scale * toUShort(buffer);
input.read(buffer, 2);
float height = scale * toUShort(buffer);
scale /= height;
widths[i] = width / height;
input.read(buffer, 2);
unsigned short numVerts = toUShort(buffer);
auto_array<float> verts(new float[2 * numVerts]);
float* verts2 = verts.get();
for(int j = 0; j < numVerts; j++) {
input.read(buffer, 2);
verts2[2 * j] = scale * ((int)toUShort(buffer) - 32768);
input.read(buffer, 2);
verts2[2 * j + 1] =
scale * ((int)toUShort(buffer) - 32768);
}
glNormal3f(0, 0, 1);
input.read(buffer, 2);
text3d.cpp — Printed on 29.12.2008, 13:29:58 — Page 5
unsigned short opcode = toUShort(buffer);
switch(opcode) {
case OP_TRIANGLES:
glBegin(GL_TRIANGLES);
break;
case OP_TRIANGLE_STRIP:
glBegin(GL_TRIANGLE_STRIP);
break;
default:
throw T3DLoadException("Invalid font file");
}
while(true) {
input.read(buffer, 2);
opcode = toUShort(buffer);
switch(opcode) {
case OP_TRIANGLES:
glEnd();
glBegin(GL_TRIANGLES);
break;
case OP_TRIANGLE_STRIP:
glEnd();
glBegin(GL_TRIANGLE_STRIP);
break;
case OP_END_PART:
goto BreakOuter;
default:
glVertex3f(verts2[2 * opcode],
verts2[2 * opcode + 1],
0);
break;
}
if (--limit == 0) {
glEndList();
throw T3DLoadException("Invalid font file");
}
}
BreakOuter:
glEnd();
glEndList();
input.read(buffer, 2);
opcode = toUShort(buffer);
switch(opcode) {
case OP_TRIANGLES:
glBegin(GL_TRIANGLES);
text3d.cpp — Printed on 29.12.2008, 13:29:58 — Page 6
break;
case OP_TRIANGLE_STRIP:
glBegin(GL_TRIANGLE_STRIP);
break;
default:
throw T3DLoadException("Invalid font file");
}
limit = 10000;
while(true) {
input.read(buffer, 2);
opcode = toUShort(buffer);
switch(opcode) {
case OP_TRIANGLES:
glEnd();
glBegin(GL_TRIANGLES);
break;
case OP_TRIANGLE_STRIP:
glEnd();
glBegin(GL_TRIANGLE_STRIP);
break;
case OP_NORMAL:
input.read(buffer, 2);
float angle;
angle = toUShort(buffer) *
PI_TIMES_2_OVER_65536;
float x, y;
x = cos(angle);
y = sin(angle);
glNormal3f(x, y, 0);
break;
case OP_END_PART:
goto BreakOuter2;
default:
if (opcode < numVerts) {
glVertex3f(verts2[2 * opcode],
verts2[2 * opcode + 1],
0);
}
else {
glVertex3f(verts2[2 * (opcode - numVerts)],
verts2[2 * (opcode - numVerts) +
1],
-1);
}
break;
}
if (--limit == 0) {
glEndList();
throw T3DLoadException("Invalid font file");
}
}
BreakOuter2:
glEnd();
glPopMatrix();
glEndList();
}
if (input.fail()) {
throw T3DLoadException("Invalid font file");
}
input.read(buffer, 1);
text3d.cpp — Printed on 29.12.2008, 13:29:58 — Page 7
if (!input.eof()) {
throw T3DLoadException("Invalid font file");
}
}
void draw2D(char c) {
if (c >= 33 && c <= 126) {
glCallList(displayListId2D + c - '!');
}
}
void draw3D(char c) {
if (c >= 33 && c <= 126) {
glCallList(displayListId3D + c - '!');
}
}
float width(char c) {
if (c >= 33 && c <= 126) {
return widths[c - 33];
}
else {
return spaceWidth;
}
}
};
void draw2D(char c) {
font->draw2D(c);
}
void draw3D(char c) {
font->draw3D(c);
}
glPopMatrix();
}
glPushMatrix();
if (vAlign >= 0) {
int numLines = 1;
for(int i = 0; str[i] != '\0'; i++) {
if (str[i] == '\n') {
numLines++;
}
}
glPopMatrix();
glShadeModel(shadeModel);
if (normalsWereNormalized) {
glEnable(GL_NORMALIZE);
}
else {
glDisable(GL_NORMALIZE);
}
}
}
void t3dInit() {
if (font == NULL) {
ifstream input;
input.open("charset", istream::binary);
font = new T3DFont(input);
input.close();
}
}
void t3dCleanup() {
delete font;
}
if (wasCulling) {
glEnable(GL_CULL_FACE);
}
}
glPushMatrix();
glScalef(1, 1, depth);
draw(str.c_str(), hAlign, vAlign, lineHeight, draw3D);
glPopMatrix();
if (!wasCulling) {
glDisable(GL_CULL_FACE);
}
glFrontFace(frontFace);
}
#ifndef IMAGE_LOADER_H_INCLUDED
#define IMAGE_LOADER_H_INCLUDED
//Represents an image
class Image {
public:
Image(char* ps, int w, int h);
~Image();
/* An array of the form (R1, G1, B1, R2, G2, B2, ...) indicating the
* color of each pixel in image. Color components range from 0 to 255.
* The array starts the bottom-left pixel, then moves right to the end
* of the row, then moves up to the next column, and so on. This is the
* format in which OpenGL likes images.
*/
char* pixels;
int width;
int height;
};
#endif
imageloader.cpp — Printed on 29.12.2008, 13:27:33 — Page 1
/* File for "Fog" lesson of the OpenGL tutorial on
* www.videotutorialsrock.com
*/
#include <assert.h>
#include <fstream>
#include "imageloader.h"
Image::~Image() {
delete[] pixels;
}
namespace {
//Converts a four-character array to an integer, using little-endian form
int toInt(const char* bytes) {
return (int)(((unsigned char)bytes[3] << 24) |
((unsigned char)bytes[2] << 16) |
((unsigned char)bytes[1] << 8) |
(unsigned char)bytes[0]);
}
~auto_array() {
if (!isReleased && array != NULL) {
delete[] array;
}
}
T* get() const {
return array;
}
T &operator*() const {
return *array;
}
T* operator->() const {
return array;
}
T* release() {
isReleased = true;
return array;
}
T* operator+(int i) {
return array + i;
}
T &operator[](int i) {
return array[i];
}
};
}
input.close();
return new Image(pixels2.release(), width, height);
}
vec3f.h — Printed on 29.12.2008, 13:30:52 — Page 1
/* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* File for "Alpha Blending" lesson of the OpenGL tutorial on
* www.videotutorialsrock.com
*/
#ifndef VEC3F_H_INCLUDED
#define VEC3F_H_INCLUDED
#include <iostream>
class Vec3f {
private:
float v[3];
public:
Vec3f();
Vec3f(float x, float y, float z);
#endif
vec3f.cpp — Printed on 29.12.2008, 13:30:28 — Page 1
/* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* File for "Alpha Blending" lesson of the OpenGL tutorial on
* www.videotutorialsrock.com
*/
#include <math.h>
#include "vec3f.h"
Vec3f::Vec3f() {
#include "const.h"
using namespace std;
class Word {
public:
int id;
string name; //[MAXWORTLAENGE];
float posX;
float posY;
float posZ;
float angle;
Word(string strWord);
virtual ~Word();
string getWord();
string createNewWord(void);
void initWordlist(void);
void moveWord(void);
float getRandomNr(int min, int max);
void resetWordPos(void);
};
#endif /*WORD_H_*/
Word.cpp — Printed on 29.12.2008, 13:31:09 — Page 1
#include <cstring>
#include <iostream>
#include <stdlib.h>
#include "Word.h"
Word::Word(string strWord) {
name = strWord;
posX = getRandomNr(-15, 15);
// posY = getRandomNr(-5, 10);
posY = 0.0f;
posZ = -20.0f;
angle = 5.0f;
}
Word::~Word()
{
}
string Word::getWord() {
cout << "transfered word: " << name << endl;
return name;
};
void Word::resetWordPos(void) {
posX = getRandomNr(-15, 15);
// posY = getRandomNr(-5, 10);
posY = 0.0f;
posZ = -20.0f;
angle = getRandomNr(0, 5);
}
Projekt: Spielentwicklung in OpenGL - „SpongeBob’s Words“
Student: Kai Kajus Noack
Datum: 2008-01-20
1. Einleitung
Das von mir entwickelte Spiel „SpongeBob’s Words” stellt dem Spieler die Aufgabe, aus dem
Hintergrund anfliegende Wörter korrekt mit der Tastatur einzugeben. Dabei stören ihn diverse
grafische Objekte, indem sie ihm die Sicht auf die Wörter versperren. Am Ende des Spiels wird der
Spieler mit einer statistischen Auswertung belohnt, die ihm Fehlerquotient und die Anschläge pro
Minute angibt.
Datei Beschreibung
const.h enthält alle Konstanten des Spiels
imageloader.cpp + .h Funktionalität zum Laden einer Bitmap-Datei
main.cpp + .h Spielfunktionalität und OpenGL-Zeichnen
text3d.cpp + .h 3D-Text-Zeichner
vec3f.cpp + .h Vektorklassen
Word.cpp + .h Word-Spielobjekt
wordlist.txt stellt abzufragende Wörter bereit
charset (Byte-Datei) enthält Code zur Darstellung des 3D-Textes
img/floor.bmp Textur für den Untergrund des Spiels
img/spongebob.bmp Textur für Spongebob-Elemente
3. Benutzereingaben im Spiel
• a-z - Eingabe der Buchstaben
• Enter - Eingegebenes Wort bestätigen
- Neustart des Spiels (bei Game Over)
• Esc - Verlassen des Spiels
Seite 1 von 4
4. Effekte, Elemente und Techniken
Sämtlicher Code wurde von mir in den Cpp- und Header-Dateien ausführlich kommentiert und ist
leicht nachvollziehbar. Trotzdem möchte ich kurz auf die im Spiel eingebauten Effekte, Elemente und
Techniken eingehen. Die nachfolgende Grafik zeigt einen Großteil davon:
Die main()-Methode in der main.cpp nimmt zu Beginn die Initialisierungen für alle Elemente des Spiels
vor und definiert die Handler-Methoden. In der initRendering() werden die Texturen geladen und
sämtliche Schalter für Licht, Tiefentest, Shade-Modell, Normalen und Nebel aktiviert. In der
drawScene() befinden sich die Anweisungen, ob Start- oder GameOver-Screen oder das laufende
Spiel gezeichnet werden soll.
Zeit + Punkte
Diese Elemente sind dynamisch, werden mithilfe der text3d-Klasse gezeichnet und befinden sich stets
im Vordergrund, da ich vor dem Zeichnen den GL_DEPTH_TEST ausschalte. Farblich habe ich sie rot
hervorgehoben, damit sie während des Spiels leicht erkennbar sind.
Für das Funktionieren des Timers und der Punkt-Anzeige sind verschiedene Zähl-, Timer- und String-
Variablen sowie Stringstreams (für das Casten von Integer zu String) nötig geworden.
Partikeleffekt
Für den Partikeleffekt habe ich Elemente aus einem Tutorial von videotutorialsrock.com genutzt und
diese implementiert. Jeder Partikel ist ein Objekt mit Positions-, Farb-, Geschwindigkeits- und Größen-
Eigenschaften, die über die Methode glCreateParticles() zu Beginn des Spiels festgelegt und mit der
glUpdateParticles() während des Spiels modifiziert werden. Die glDrawParticles() zeichnet die
Partikelobjekte nach dem Update der Partikeldaten mit den neuen Werten. Die y-Position wurde von
mir im Übrigen so verändert, dass die Partikel sich weniger stark in der Höhe, sondern sich in der
Breite des „Himmels“ des Spiels verteilen.
Seite 2 von 4
Übrigens wird der Würfel im Spielverlauf mit den richtigen Eingaben des Spielers größer skaliert und
bewegt sich auf ihn zu.
Anfliegendes Wort
Für jedes Wort wird ein Objekt „Word“ erstellt, mit zufälligen Positions-Parametern für die x-Ebene.
Der Text wird über die text3d-Klasse gezeichnet. Die Zeilenhöhe und -breite sowie die Texttiefe sind
über die Methode t3dDraw3D() frei wählbar. Die 3D-Buchstaben werden aus der Byte-Datei charset
ausgelesen und in der text3d-Klasse als Schriftart (Font) verwendet.
Jedes Wort kommt aus dem Hintergrund. Wenn es jedoch hinter dem Spieler verschwindet, es also
den Sichtbereich verlässt, erscheint es wieder von Neuem im Hintergrund. Alle zweitausend mög-
lichen Wörter werden aus der wordlist.txt eingelesen (vgl. Methode initWordlist), in der main-Klasse in
ein Array gelegt und dort weiter genutzt. Über eine Zufallszahl wird eins der Wörter ausgewählt und an
die zeichnende Methode und an die Methoden der Spiellogik übergeben.
Nebeleffekt
Der Nebel wird in der Methode paintFog() angeschaltet, dessen Farbe bestimmt sowie Start- und
Endwert in Richtung z-Achse gesetzt. In dieser Methode verbirgt sich übrigens auch der geheime
psychomode, der mit der Tastatureingabe „000“ de-/aktiviert werden kann. Für diesen Modus habe ich
mir die Sinus- und Cosinusfunktionen zu Hilfe genommen und ein kronenartiges, rotierendes Objekt
geschaffen. Dieser Modus ist sehr farbenfroh ☺
Seite 3 von 4
Start-Screen
Wie auch bei den anderen Text-Zeichnungen wird hier die
Methode t3dDraw3D() verwendet und zuvor muss, wie bereits ein
paar Mal aufgeführt, der Nebel ausgeschaltet werden.
Weitere Methoden:
- update() dynamisiert die Werte der Objekte
- convertRADtoANGLE() konvertiert Radianz-Werte in Winkel
- Round() rundet auf die angegebene Anzahl an Nachkommastellen
- handleResize() beachtet die Veränderung der Fenstergröße.
5. Fazit
Es hat wirklich Spaß gemacht, ein funktionierendes Spiel mit Logik und Grafik zu entwerfen, auch
wenn ich dafür 15 Tage Arbeit, also etwa 70-80 Stunden investieren musste. Der Mehraufwand
entstand, da C++ bisher nicht Bestandteil unseres Studiums war.
Ich freue mich sehr, dass „Spongebob’s Words!“ gut bei den Kommilitonen ankommt und dazu anregt,
das Spiel mehr als nur einmal zu spielen.
Online:
http://www.videotutorialsrock.com/
http://www.cplusplus.com/reference/
http://www.swiftless.com/tutorials/opengl/opengltuts.html
http://www-h.eng.cam.ac.uk/help/tpl/languages/C++/FAQ.html
Ressourcen:
Aus www.videotutorialsrock.com wurden entnommen:
- charset
- imageloader.cpp
- text3d.cpp
- vec3f.cpp
Seite 4 von 4