草庐IT

c++ - 停止喷涂并保持原位

coder 2024-02-23 原文

// #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;
}

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

它是这样工作的:

这是我希望它的工作方式:

最佳答案

用公式

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;

预览:

关于c++ - 停止喷涂并保持原位,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53833514/

有关c++ - 停止喷涂并保持原位的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  3. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  4. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  5. += 的 Ruby 方法 - 2

    有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

  6. ruby - 使用 Ruby Daemons gem 检测停止 - 2

    我正在使用rubydaemongem。想知道如何向停止操作添加一些额外的步骤?希望我能检测到停止被调用,并向其添加一些额外的代码。任何人都知道我如何才能做到这一点? 最佳答案 查看守护程序gem代码,它似乎没有用于此目的的明显扩展点。但是,我想知道(在守护进程中)您是否可以捕获守护进程在发生“停止”时发送的KILL/TERM信号...?trap("TERM")do#executeyourextracodehereend或者你可以安装一个at_exit钩子(Hook):-at_exitdo#executeyourextracodehe

  7. ruby - Sinatra + Heroku + Datamapper 使用 dm-sqlite-adapter 部署问题 - 2

    出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t

  8. ruby - 如何保持我不常用的编程语言技能 - 2

    关闭。这个问题是off-topic.它目前不接受答案。想改进这个问题吗?Updatethequestion所以它是on-topic用于堆栈溢出。关闭11年前。Improvethisquestion我不经常使用ruby​​-通常它加起来相当于每两个月或更长时间编写一次脚本。我的大部分编程都是使用C++进行的,这与ruby​​有很大不同。由于我与ruby​​之间的差距如此之大,我总是忘记语言的基本方面(比如解析文本文件和其他简单的东西)。我想每天练习一些基本的东西,我想知道是否有一些我可以订阅的网站,并且会向我发送当天的Ruby问题或类似的东西。有人知道这样的站点/Internet服务吗?

  9. ruby - Ruby 中字符串运算符 + 和 << 的区别 - 2

    我是Ruby和这个网站的新手。下面两个函数是不同的,一个在函数外修改变量,一个不修改。defm1(x)x我想确保我理解正确-当调用m1时,对str的引用被复制并传递给将其视为x的函数。运算符当调用m2时,对str的引用被复制并传递给将其视为x的函数。运算符+创建一个新字符串,赋值x=x+"4"只是将x重定向到新字符串,而原始str变量保持不变。对吧?谢谢 最佳答案 String#+::str+other_str→new_strConcatenation—ReturnsanewStringcontainingother_strconc

  10. ruby - rails 3.2.2(或 3.2.1)+ Postgresql 9.1.3 + Ubuntu 11.10 连接错误 - 2

    我正在使用PostgreSQL9.1.3(x86_64-pc-linux-gnu上的PostgreSQL9.1.3,由gcc-4.6.real(Ubuntu/Linaro4.6.1-9ubuntu3)4.6.1,64位编译)和在ubuntu11.10上运行3.2.2或3.2.1。现在,我可以使用以下命令连接PostgreSQLsupostgres输入密码我可以看到postgres=#我将以下详细信息放在我的config/database.yml中并执行“railsdb”,它工作正常。开发:adapter:postgresqlencoding:utf8reconnect:falsedat

随机推荐