エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

わかりやすいコード・その2

エントリのタイトルはIBM developerWorks : ご指定のページは見つかりませんでしたから。ここで紹介されているゲームを目標にちまちまやっているところです。

ここまで来ました。カーソルキーで上下左右に動いてスペースキーでファイア!
上下に動くのは反則っぽいですが、まぁおいおいということで。

以下、コード。

#include <cstdlib>

#include <GLUT/glut.h>

static const int Interval = 100;
static const int Width    = 320;
static const int Height   = 240;

struct Point
{
    int x;
    int y;

    Point() : x(0), y(0) {}
    Point(int x, int y) : x(x), y(y) {}
};

class Bullet
{
public:
    Bullet(const Point& point) : point_(point), visible_(true)
    {
    }

    ~Bullet()
    {
        erase();
    }

    void move()
    {
        erase();
        point_.y -= 10;
        draw();

        visible_ = point_.y > 0;
    }

    bool visible() const
    {
        return visible_;
    }

    void erase()
    {
        draw(1, 1, 1);
    }

    void draw()
    {
        draw(1, 0, 0);
    }

    void draw(double red, double green, double blue)
    {
        glColor3d(red, green, blue);
        glBegin(GL_LINES);
        glVertex2i(point_.x, point_.y     );
        glVertex2i(point_.x, point_.y - 10);
        glEnd();
        glFlush();
    }

private:
    Point point_;
    bool  visible_;
};

class Ship
{
public:
    Ship() : point_(Width / 2, Height / 2)
    {
    }

    void left()  { erase(); point_.x -= 15; draw(); }
    void right() { erase(); point_.x += 15; draw(); }
    void up()    { erase(); point_.y -= 15; draw(); }
    void down()  { erase(); point_.y += 15; draw(); }

    Bullet* fireBullet()
    {
        new Bullet(point_);
    }

    void erase()
    {
        draw(1, 1, 1);
    }

    void draw()
    {
        draw(0, 0, 1);
    }

    void draw(double red, double green, double blue)
    {
        glColor3d(red, green, blue);
        glBegin(GL_POLYGON);
        glVertex2i(point_.x - 10, point_.y     );
        glVertex2i(point_.x     , point_.y - 10);
        glVertex2i(point_.x + 10, point_.y     );
        glVertex2i(point_.x + 10, point_.y + 10);
        glVertex2i(point_.x - 10, point_.y + 10);
        glEnd();
        glFlush();
    }

private:
    Point point_;
};

static Ship    ship;
static Bullet* bullet = 0;
static int     width  = Width;
static int     height = Height;

void display()
{
    glClear(GL_COLOR_BUFFER_BIT);

    ship.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(bullet == 0)
        {
            bullet = ship.fireBullet();
            bullet->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:  ship.left();  break;
    case GLUT_KEY_UP:    ship.up();    break;
    case GLUT_KEY_RIGHT: ship.right(); break;
    case GLUT_KEY_DOWN:  ship.down();  break;
    default:                           break;
    }
}

void timer(int)
{
    if(bullet != 0)
    {
        bullet->move();

        if( ! bullet->visible())
        {
            delete bullet;
            bullet = 0;
        }
    }

    glutTimerFunc(Interval, timer, 0);
}

int main(int argc, char* argv[])
{
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(width, height);
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA);

    glutCreateWindow("GAME");

    glutDisplayFunc(display);
    glutReshapeFunc(resize);
    glutKeyboardFunc(keyboard);
    glutSpecialFunc(specialKey);
    glutTimerFunc(Interval, timer, 0);

    glClearColor(1.0, 1.0, 1.0, 1.0);

    glutMainLoop();

    return 0;
}