エイリアン登場。課題もどんどん登場。
- グローバル変数が増えている
- マジックナンバーもいっぱい
- エイリアンの登場パターンがただのランダム
- エイリアンを倒せない
- エイリアンが減らないので画面上に溢れる
- 他、スコアがでないとか、エイリアンが弾を撃ってこないとか、いっぱい
- コードが400行近くなってきて、このままブログで紹介は厳しいか
以下、コード。
#include <cstdlib> #include <functional> #include <algorithm> #include <vector> #include <GLUT/glut.h> static const int Interval = 100; static const int Width = 320; static const int Height = 240; static int width = Width; static int height = Height; class RGBColor { public: RGBColor() { set(0, 0, 0); } RGBColor(GLdouble r,GLdouble g,GLdouble b) { set(r, g, b); } void set(GLdouble r,GLdouble g,GLdouble b) { rgb[0] = r; rgb[1] = g; rgb[2] = b; } const GLdouble* get() const { return rgb; } void setRed(GLdouble value) { rgb[0] = value; } void setGreen(GLdouble value) { rgb[1] = value; } void setBlue(GLdouble value) { rgb[2] = value; } GLdouble getRed() const { return rgb[0]; } GLdouble getGreen() const { return rgb[1]; } GLdouble getBlue() const { return rgb[2]; } private: GLdouble rgb[3]; }; struct Point { int x; int y; Point() : x(0), y(0) {} Point(int x, int y) : x(x), y(y) {} }; typedef std::vector<Point> Points; struct Vertex : public std::unary_function<const Point&, void> { explicit Vertex(const Point& origin) : origin_(origin) {} void operator() (const Point& point) { glVertex2i(origin_.x + point.x, origin_.y + point.y); } const Point origin_; }; class Shape { public: void addPoint(const Point& point) { points_.push_back(point); } void draw(const Point& position, const RGBColor& color, GLenum mode) { glColor3dv(color.get()); glBegin(mode); std::for_each(points_.begin(), points_.end(), Vertex(position)); glEnd(); glFlush(); } private: Points points_; }; class Object { public: explicit Object(const Point& position) : position_(position) { } const Point& getPosition() const { return position_; } void moveTo(const Point& position) { position_ = position; } void move(const Point& delta) { position_.x += delta.x; position_.y += delta.y; } void erase() { drawWithColor(1, 1, 1); } void drawWithColor(double r, double g, double b) { shape_.draw(position_, RGBColor(r, g, b), GL_POLYGON); } protected: void addPoint(const Point& point) { shape_.addPoint(point); } private: Shape shape_; Point position_; }; class Bullet : public Object { public: explicit Bullet(const Point& point) : Object(point), velocityY_(-10) { addPoint(Point(-3, -5)); addPoint(Point( 0, -10)); addPoint(Point( 3, -5)); addPoint(Point( 0, 0)); } ~Bullet() { erase(); } void move() { erase(); Object::move(Point(0, velocityY_)); draw(); } bool isVisible() const { return (0 <= getPosition().x) && (getPosition().x <= width) && (0 <= getPosition().y) && (getPosition().y <= height); } void draw() { drawWithColor(0, 0, 1); } private: int velocityY_; }; class Ship : public Object { public: Ship() : Object(Point(Width / 2, Height / 2)) { addPoint(Point(-10, 0)); addPoint(Point( 0, -10)); addPoint(Point( 10, 0)); addPoint(Point( 10, 10)); addPoint(Point(-10, 10)); } static const int Delta = 10; void left() { erase(); move(Point(-Delta, 0)); draw(); } void right() { erase(); move(Point(+Delta, 0)); draw(); } void up() { erase(); move(Point(0, -Delta)); draw(); } void down() { erase(); move(Point(0, +Delta)); draw(); } Bullet* fireBullet() { return new Bullet(getPosition()); } void draw() { drawWithColor(0, 0, 1); } }; class Alien : public Object { public: Alien() : Object(Point(20, 20)), velocityX_(5) { addPoint(Point( -5, -5)); addPoint(Point( 5, -5)); addPoint(Point( 10, 0)); addPoint(Point( 5, 5)); addPoint(Point( 2, 2)); addPoint(Point( -2, 2)); addPoint(Point( -5, 5)); addPoint(Point(-10, 0)); } void turn() { velocityX_ = -velocityX_; } void move() { erase(); Object::move(Point(velocityX_, 0)); if((getPosition().x < 0) || (width < getPosition().x)) { turn(); Object::move(Point(0, 10)); } draw(); } void draw() { drawWithColor(1, 0.5, 0); } private: int velocityX_; }; class Aliens { public: void add() { aliens_.push_back(Alien()); } void draw() { std::for_each(aliens_.begin(), aliens_.end(), std::mem_fun_ref(&Alien::draw)); } void move() { std::for_each(aliens_.begin(), aliens_.end(), std::mem_fun_ref(&Alien::move)); } private: std::vector<Alien> aliens_; }; static Ship myShip; static Bullet* myBullet = 0; static Aliens aliens; void display() { glClear(GL_COLOR_BUFFER_BIT); myShip.draw(); aliens.draw(); } void resize(int w, int h) { glViewport(0, 0, w, h); width = w; height = h; glLoadIdentity(); glOrtho(-0.5, w - 0.5, h - 0.5, -0.5, -1.0, 1.0); } void keyboard(unsigned char key, int, int) { switch(key) { case ' ': if(myBullet == 0) { myBullet = myShip.fireBullet(); myBullet->draw(); } break; case 'q': case 'Q': case '?033': std::exit(0); break; default: break; } } void specialKey(int key, int x, int y) { switch(key) { case GLUT_KEY_LEFT: myShip.left(); break; case GLUT_KEY_UP: myShip.up(); break; case GLUT_KEY_RIGHT: myShip.right(); break; case GLUT_KEY_DOWN: myShip.down(); break; default: break; } } void timer(int) { if(myBullet != 0) { myBullet->move(); if( ! myBullet->isVisible()) { delete myBullet; myBullet = 0; } } if((std::rand() % 20) == 0) { aliens.add(); } aliens.move(); glutTimerFunc(Interval, timer, 0); } int main(int argc, char* argv[]) { glutInitWindowPosition(100, 100); glutInitWindowSize(width, height); glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA); glutCreateWindow("to write more comprehensible code"); glutDisplayFunc(display); glutReshapeFunc(resize); glutKeyboardFunc(keyboard); glutSpecialFunc(specialKey); glutTimerFunc(Interval, timer, 0); glClearColor(1.0, 1.0, 1.0, 1.0); glutMainLoop(); return 0; }