C++实现太阳系行星系统

实验楼项目:C++实现太阳系行星系统

关于详细知识跟着实验做比较好

基础知识

做这个项目需要知道一些基础知识:

  1. OpenGL
  2. GLUT

类设计

main.cpp

#include<GL/glut.h>
#include "solarsystem.hpp"

#define WINDOW_X_POS 50
#define WINDOW_Y_POS 50
#define WIDHT 700
#define HEIGHT 700

SolarSystem solarsystem;

void onDisplay(void)
{
    solarsystem.onDisplay();
}

void onUpdate(void)
{
    solarsystem.onUpdate();
}

void onKeyboard(unsigned char key, int x, int y)
{
    solarsystem.onKeyboard(key, x, y);
}

int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
    glutInitWindowPosition(WINDOW_X_POS, WINDOW_Y_POS);
    glutCreateWindow("SolarSystem at Wuhan");
    glutDisplayFunc(onDisplay);
    glutIdleFunc(onUpdate);
    glutKeyboardFunc(onKeyboard);
    glutMainLoop();
    return 0;
}

solarsystem.cpp

#include "solarsystem.hpp"

#define REST 700
#define REST_Z (REST)
#define REST_Y (-REST)

void SolarSystem::onDisplay()
{
    glClear(GL_COLOR_BUFFER_BIT  |  GL_DEPTH_BUFFER_BIT);
    glClearColor(.7f, .7f, .7f, .1f);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(75.0f, 1.0f, 1.0f, 40000000);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(viewX, viewY, viewZ, centerX, centerY, centerZ, upX, upY, upZ);

    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHTING);
    glEnable(GL_DEPTH_TEST);

    for (int i=0; i<STARS_NUM; i++)
        stars[i]->draw();

    glutSwapBuffers();
}

#define TIMEPAST 1

void SolarSystem::onUpdate()
{
    for (int i = 0; i < STARS_NUM; ++i)
        stars[i]->update(TIMEPAST);
    this->onDisplay();
}

#define OFFSET 20

void SolarSystem::onKeyboard(unsigned char key, int x, int y) 
{
    switch (key)    
    {
        case 'w': viewY += OFFSET; break;
        case 's': viewZ += OFFSET; break;
        case 'S': viewZ -= OFFSET; break;
        case 'a': viewX -= OFFSET; break;
        case 'd': viewX += OFFSET; break;
        case 'x': viewY -= OFFSET; break;
        case 'r':
            viewX = 0; viewY = REST_Y; viewZ = REST_Z;
            centerX = centerY = centerZ = 0;
            upX = upY = 0; upZ = 1;
            break;
        case 27: exit(0); break;
        default: break;
    }
}

#define SUN_RADIUS 48.74
#define MER_RADIUS  7.32
#define VEN_RADIUS 18.15
#define EAR_RADIUS 19.13
#define MOO_RADIUS  6.15
#define MAR_RADIUS 10.19
#define JUP_RADIUS 42.90
#define SAT_RADIUS 36.16
#define URA_RADIUS 25.56
#define NEP_RADIUS 24.78

#define MER_DIS   62.06
#define VEN_DIS  115.56
#define EAR_DIS  168.00
#define MOO_DIS   26.01
#define MAR_DIS  228.00
#define JUP_DIS  333.40
#define SAT_DIS  428.10
#define URA_DIS 848.00
#define NEP_DIS 949.10

#define MER_SPEED   87.0
#define VEN_SPEED  225.0
#define EAR_SPEED  365.0
#define MOO_SPEED   30.0
#define MAR_SPEED  687.0
#define JUP_SPEED 1298.4
#define SAT_SPEED 3225.6
#define URA_SPEED 3066.4
#define NEP_SPEED 6014.8

#define SELFROTATE 3

enum STARS
{
    Sun,        // 太阳
    Mercury,    // 水星
    Venus,      // 金星
    Earth,      // 地球
    Moon,       // 月球
    Mars,       // 火星
    Jupiter,    // 木星
    Saturn,     // 土星
    Uranus,     // 天王星
    Neptune,    // 海王星
};

#define SET_VALUE_3(name, value0, value1, value2) \
                   ((name)[0])=(value0), ((name)[1])=(value1), ((name)[2])=(value2)
                   
SolarSystem::SolarSystem()
{
    viewX = 0;
    viewY = REST_Y;
    viewZ = REST_Z;
    centerX = centerY = centerZ = 0;
    upX = upY = 0;
    upZ = 1;

    GLfloat rgbColor[3] = {1, 0, 0};
    stars[Sun]     = new LightPlanet(SUN_RADIUS, 0, 0, SELFROTATE, 0, rgbColor);

    SET_VALUE_3(rgbColor, .2, .2, .5);
    stars[Mercury] = new Planet(MER_RADIUS, MER_DIS, MER_SPEED, SELFROTATE, stars[Sun], rgbColor);

    SET_VALUE_3(rgbColor, 1, .7, 0);
    stars[Venus]   = new Planet(VEN_RADIUS, VEN_DIS, VEN_SPEED, SELFROTATE, stars[Sun], rgbColor);

    SET_VALUE_3(rgbColor, 0, 1, 0);
    stars[Earth]   = new Planet(EAR_RADIUS, EAR_DIS, EAR_SPEED, SELFROTATE, stars[Sun], rgbColor);

    SET_VALUE_3(rgbColor, 1, 1, 0);
    stars[Moon]    = new Planet(MOO_RADIUS, MOO_DIS, MOO_SPEED, SELFROTATE, stars[Earth], rgbColor);

    SET_VALUE_3(rgbColor, 1, .5, .5);
    stars[Mars]    = new Planet(MAR_RADIUS, MAR_DIS, MAR_SPEED, SELFROTATE, stars[Sun], rgbColor);

    SET_VALUE_3(rgbColor, 1, 1, .5);
    stars[Jupiter] = new Planet(JUP_RADIUS, JUP_DIS, JUP_SPEED, SELFROTATE, stars[Sun], rgbColor);

    SET_VALUE_3(rgbColor, .5, 1, .5);
    stars[Saturn]  = new Planet(SAT_RADIUS, SAT_DIS, SAT_SPEED, SELFROTATE, stars[Sun], rgbColor);

    SET_VALUE_3(rgbColor, .4, .4, .4);
    stars[Uranus]  = new Planet(URA_RADIUS, URA_DIS, URA_SPEED, SELFROTATE, stars[Sun], rgbColor);

    SET_VALUE_3(rgbColor, .5, .5, 1);
    stars[Neptune] = new Planet(NEP_RADIUS, NEP_DIS, NEP_SPEED, SELFROTATE, stars[Sun], rgbColor);
}

SolarSystem::~SolarSystem()
{
    for (int i = 0; i < STARS_NUM; ++i)
        delete stars[i];
}

solarsystem.hpp

#include <GL/glut.h>

#include "stars.hpp"

#define STARS_NUM 10

class SolarSystem
{
public:
    SolarSystem();  
    ~SolarSystem();     // 析构函数
    void onDisplay();
    void onUpdate();
    void onKeyboard(unsigned char key, int x, int y);
private:
    Star *stars[STARS_NUM];

    // 定义观察视角的参数
    GLdouble viewX, viewY, viewZ;
    GLdouble centerX, centerY, centerZ;
    GLdouble upX, upY, upZ;
};

stars.cpp

#include "stars.hpp"
#include<cmath>

#define PI 3.1415926

Star::Star(GLfloat radius, GLfloat distance, GLfloat speed, GLfloat selfSpeed, Star *parentStar)
{
    this->radius = radius;
    this->selfSpeed = selfSpeed;
    this->alphaSelf = this->alpha = 0;
    this->distance = distance;
    for (int i = 0; i < 4; ++i)
        this->rgbaColor[i] = 1.0f;
    this->parentStar = parentStar;
    if (speed > 0)
        this->speed = 360.0f / speed;
    else 
        this->speed = 0.0f;
}

void Star::drawStar()
{
    glEnable(GL_LINE_SMOOTH);
    glEnable(GL_BLEND);
    int n = 1440;
    glPushMatrix();
    {   
        if (parentStar != 0 && parentStar->distance > 0)
        {
            glRotatef(parentStar->alpha, 0, 0, 1);
            glTranslatef(parentStar->distance, 0.0, 0.0);
        }
        glBegin(GL_LINES);
        for (int i = 0; i < n; ++i)
            glVertex2f(distance * cos(2 * PI * i / n), distance * sin(2 * PI * i / n));
        glEnd();
        glRotatef(alphaSelf, 0, 0, 1);
        glColor3f(rgbaColor[0], rgbaColor[1],rgbaColor[2]);
        glutSolidSphere(radius, 40, 32);
    }
    glPopMatrix();
}

void Star::update(long timeSpan)
{
    alpha += timeSpan * speed;      // 更新角度
    alphaSelf += selfSpeed;         // 更新自转角度
}

Planet::Planet(GLfloat radius, GLfloat distance, GLfloat speed, GLfloat selfSpeed, Star *parentStar, GLfloat rgbColor[3]): 
Star(radius, distance, speed, selfSpeed, parentStar) 
{
    rgbaColor[0] = rgbColor[0];
    rgbaColor[1] = rgbColor[1];
    rgbaColor[2] = rgbColor[2];
    rgbaColor[3] = 1.0f;
}

void Planet::drawPlanet()
{
    GLfloat mat_ambient[] = {0.0f, 0.0f, 0.5f, 1.0f};
    GLfloat mat_diffuse[] = {0.0f, 0.0f, 0.5f, 1.0f};
    GLfloat mat_specular[] = {0.0f, 0.0f, 1.0f, 1.0f};
    GLfloat mat_emission[] = {rgbaColor[0], rgbaColor[1], rgbaColor[2], rgbaColor[3]};
    GLfloat mat_shininess = 90.0f;

    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);
    glMaterialf(GL_FRONT, GL_SHININESS, mat_shininess);
}

LightPlanet::LightPlanet(GLfloat radius, GLfloat distance, GLfloat speed, GLfloat selfSpeed, Star *parentStar, GLfloat rgbColor[3]):
Planet(radius, distance, speed, selfSpeed, parentStar, rgbColor)
{
    ;
}

void LightPlanet::drawLight()
{
    GLfloat light_position[] = {0.0f, 0.0f, 0.0f, 1.0f};
    GLfloat light_ambient[]  = {0.0f, 0.0f, 0.0f, 1.0f};
    GLfloat light_diffuse[]  = {1.0f, 1.0f, 1.0f, 1.0f};
    GLfloat light_specular[] = {1.0f, 1.0f, 1.0f, 1.0f};

    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
}

stars.hpp

#ifndef stars_hpp
#define stars_hpp

#include<GL/glut.h>

class Star
{
public:
    GLfloat radius;     // 星球的半径
    GLfloat speed, selfSpeed;   // 星球的公转、自转速度
    GLfloat distance;   // 星球的中心与父节点星球中心的距离
    GLfloat rgbaColor[4];   // 星球的颜色
    Star *parentStar;   // 父节点星球
    Star(GLfloat radius, GLfloat distance, GLfloat speed, GLfloat selfSpeed, Star *parentStar);     // 构造函数
    void drawStar();    // 对一般的星球移动、旋转等活动进行绘制
    virtual void draw() { drawStar(); }     // 提供默认实现
    virtual void update(long timeSpan);     // 参数为每次刷新画面时的时间跨度
protected:
    GLfloat alphaSelf, alpha;
};

class Planet : public Star
{
public:
    Planet(GLfloat radius, GLfloat distance, GLfloat speed, GLfloat selfSpeed, Star *parentStar, GLfloat rgbColor[3]); 
    void drawPlanet();      // 增加对具备自身材质的行星绘制材质
    virtual void draw() { drawPlanet(); drawStar(); }   
};

class LightPlanet : public Planet
{
public:
    LightPlanet(GLfloat radius, GLfloat distance, GLfloat speed, GLfloat selfSpeed, Star *parentStar, GLfloat rgbColor[]);
    void drawLight();   // 增加对提供光源的恒星绘制光照
    virtual void draw() { drawLight(); drawPlanet(); drawStar(); }
};

#endif

结果展示

在这里插入图片描述

posted @ 2022-10-14 19:22  astralcon  阅读(238)  评论(0编辑  收藏  举报