停止喷涂并保持在原位

时间:2018-12-18 12:55:43

标签: c++ visual-studio opengl

// #include loads up library files, the order can matter
// generally load glut.h last
#include <stdio.h>  // this library is for standard input and output
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include "glut.h"// this library is for glut the OpenGL Utility Toolkit

//this defines a constant for the array size
#define SPRAYSIZE 500

// the properties of a spray particle are defined in a struct 
struct sprayParticle {
    float x = 0; // current position  x
    float y = 0; // current position  y
    float startx = 0; // birth position  x
    float starty = 0; // birth position y
    int startTime; // a birthtime in frames when it will be born
    int startRange = 100; // the maximum time at which a birth can happen
    bool started = false; // tracks whether the particle has benn born or not
    float speed = 0.1;
    float radius;
    float startxd = 0; // starting direction vector x value
    float startyd = 0; // startingdirection vestor y value
    float xd = 0;  //  current direction vector x value
    float yd = 0;  // current direction vector x value
    float alpha = 1.0; // transparency
};

int winWidth = 1000, winHeight = 1000;
int counter = 0;
time_t t;
sprayParticle spray[SPRAYSIZE];

float angle = 90; // the angle of the spray: 0 degrees is to the left, 
// 90 degrees straight up, 180 to the right etc
float sprayWidth = 30;// the width of the spray in degrees
float sprayCenterX, sprayCenterY;
//variables for spray colour, set once per spray
float fr = 1; float fg = 1;  float fb = 1;
// the gravity vector
float gx = 0;
float gy = -0.0005;
// the position of thepartcle ystem emitter, wher the rocket should be drawn
float rocketstartx = winWidth - 100, rocketstarty = winHeight - 100;

void init() {
    glClearColor(0.0, 0.0, 0.0, 0.0); // set what colour you want the background to be
    glMatrixMode(GL_PROJECTION); // set the matrix mode, we will look at this later
    gluOrtho2D(0.0, winWidth, 0.0, winHeight);
}

void circle(double radius, double xc, double yc) {
    int i;
    double angle = 2 * 3.1415 / 20; // circle is drawn using 20 line.
    double circle_xy[40][2];
    circle_xy[0][0] = radius + xc;
    circle_xy[0][1] = yc;
    glBegin(GL_POLYGON);
    for (i = 1; i < 20; i++) {
        circle_xy[i][0] = radius * cos(i *angle) + xc;
        circle_xy[i][1] = radius * sin(i * angle) + yc;
        glVertex2f(circle_xy[i - 1][0], circle_xy[i - 1][1]);
        glVertex2f(circle_xy[i][0], circle_xy[i][1]);
    }
    glEnd();
}

void normalise(int i) {
    float mag;
    mag = sqrt((spray[i].xd*spray[i].xd) + (spray[i].yd*spray[i].yd));
    spray[i].xd = spray[i].xd / mag;
    spray[i].yd = spray[i].yd / mag;
}

// we calculate the direction vector of the current particle from the global 
variable angle and spread
void setDirectionVector(int i) {
    float minAngle, maxAngle, range, newangle;
    double newAngleInRadians; // variable 
    int rangeInt;
    minAngle = angle - (sprayWidth / 2.0); // calc the minimum angle the particle could move along
    maxAngle = angle + (sprayWidth / 2.0); // calc the maximum angle
    range = maxAngle - minAngle;
    rangeInt = (int)(range*100.0);
    newangle = minAngle + ((float)(rand() % rangeInt) / 100.0); // generate a random angle between mi and max angles
    newAngleInRadians = (double)(newangle / 360.0)*(2 * 3.1415); // convert it to radians
    spray[i].xd = (float)cos(newAngleInRadians);// calc the diection vector x value
    spray[i].yd = (float)sin(newAngleInRadians);// calc the diection vector y value
}

void initspray() {
    for (int i = 0; i < SPRAYSIZE; i++) {
        spray[i].x = winWidth / 2; // set current start x position
        spray[i].y = 100;// set current start y position
        spray[i].startx = spray[i].x; spray[i].starty = spray[i].y;// set start x and y position
        spray[i].speed = 0.1 + (float)(rand() % 150) / 1000.0;// speed is 0.1 to 0.25
        spray[i].startTime = rand() % spray[i].startRange;// set birth time
        spray[i].radius = (float)(rand() % 15); // random radius
        setDirectionVector(i);// set the current direction vector
        spray[i].startxd = spray[i].xd; spray[i].startyd = spray[i].yd; // set start direction vector to current
    }
    // set colour of spray 
    fr = 0.5 + (float)(rand() % 500) / 1000.0;
    fg = 0.5 + (float)(rand() % 500) / 1000.0;
    fb = 0.5 + (float)(rand() % 500) / 1000.0;
}

void drawsprayParticle(int i) {
    glLineWidth(2);
    if (!spray[i].started) {
        if (counter == spray[i].startTime) {
            spray[i].started = true;
        }
    }
    if (spray[i].started) {
        glColor4f(fr, fg, fb, spray[i].alpha); // white particiles
        circle(spray[i].radius, spray[i].x, spray[i].y);
        spray[i].x = spray[i].x + (spray[i].xd*spray[i].speed);
        spray[i].y = spray[i].y + (spray[i].yd*spray[i].speed);
        // this produces a direction vector that is a little longer than 1
        spray[i].yd = spray[i].yd + gy;
        // so the normalise the vector to make length 1
        normalise(i);
        // reduce transparency
        spray[i].alpha -= 0.00015;
    }
    if (spray[i].x<0 || spray[i].x>winWidth + 500 || spray[i].y<0 || spray[i].y>winHeight) {
        spray[i].x = spray[i].startx; spray[i].y = spray[i].starty; //rocketstartx
        spray[i].xd = spray[i].startxd; spray[i].yd = spray[i].startyd;
        spray[i].alpha = 1.0;
    }
}

void drawspray() {
    // draw each spray particle 
    for (int i = 0; i < SPRAYSIZE; i++) {
        drawsprayParticle(i);
    }
    // increment rocket position
    rocketstartx += 0.2;
    // if the rocket is oof the screen more nad 500 pixels to the right the rest it to 0
    if (rocketstartx > winWidth + 500) { rocketstartx = 0; }
    counter++;
}

// This is the display function it is called when ever you want to draw something
void display() {
    glClear(GL_COLOR_BUFFER_BIT); // clear the screen using the background colour
    glColor3f(1.0, 1.0, 1.0); // set colour to white
    drawspray();
    glFlush(); // force all drawing to finish   
}

// This is the idle function it is called whenever the program is idle
void idle() {
    display();
}

// As with many programming languages the main() function is the entry point for execution of the program
int main(int argc, char** argv) {
    srand((unsigned)time(&t));
    // initialise first spray work
    initspray();
    glutInit(&argc, argv);  //perform the GLUT initialization
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA); // more initialisation
    glutInitWindowSize(winWidth, winHeight); // set window position
    glutInitWindowPosition(0, 0); // set window size
    glutCreateWindow("Fire"); // create a display with a given caption for the title bar
    glEnable(GL_BLEND); //Enable blending.
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    init(); // call init function defined above
    glutIdleFunc(idle); //  define what function to call when the program is idle
    glutDisplayFunc(display); // define what function to call to draw 
    glutMainLoop();
    // this line exits the program
    return 0;
}

上面的原始代码通常会创建一个喷泉,在整个屏幕上喷射粒子,但是我更改了喷射的大小和范围,因此可以创建火焰。问题是我无法阻止粒子的扩散,并且粒子一直在向上移动。我希望它保持在原位。

它是这样工作的: Before

这是我希望其工作的方式: After

1 个答案:

答案 0 :(得分:2)

使用公式

spray[i].x = spray[i].x + (spray[i].xd*spray[i].speed);
spray[i].y = spray[i].y + (spray[i].yd*spray[i].speed);
点到原点线性的距离增加。您必须按时间降低速度才能平稳地接近极限位置。

例如

spray[i].speed *= 0.9992f;

当然,当点在其原点“重新开始”时,您必须保持速度(spray[i].speed)。如果该点的速度或该点的alpha值低于阈值,则该点也必须“重新启动”:

void drawsprayParticle(int i) {
    glLineWidth(2);
    if (!spray[i].started) {
        if (counter == spray[i].startTime) {
            spray[i].started = true;
        }
    }

    if (spray[i].started) {
        glColor4f(fr, fg, fb, spray[i].alpha); // white particles
        circle(spray[i].radius, spray[i].x, spray[i].y);
        spray[i].x = spray[i].x + (spray[i].xd*spray[i].speed);
        spray[i].y = spray[i].y + (spray[i].yd*spray[i].speed);
        // this produces a direction vector that is a little longer than 1
        spray[i].yd = spray[i].yd + gy;
        // so the normalize the vector to make length 1
        normalise(i);
        // reduce transparency
        spray[i].alpha -= 0.0003;
        spray[i].speed *= 0.9992f;
    }

    if ( spray[i].x<0 || spray[i].x>winWidth + 500 ||
         spray[i].y<0 || spray[i].y>winHeight ||
         spray[i].alpha < 1.0f/256.0f ||
         spray[i].speed < 0.04f ) {

        spray[i].x = spray[i].startx; spray[i].y = spray[i].starty; 
        spray[i].xd = spray[i].startxd; spray[i].yd = spray[i].startyd;
        spray[i].alpha = 1.0;
        spray[i].speed = 0.1 + (float)(rand() % 150) / 1000.0;
    }
}

这是一种经验算法,因此您必须尝试使用​​这些值才能获得所需的效果。

我还增加了起始范围:int startRange = 1300;

预览: