游戏开发论坛

 找回密码
 立即注册
搜索
查看: 1414|回复: 4

一个问题!

[复制链接]

77

主题

203

帖子

279

积分

中级会员

Rank: 3Rank: 3

积分
279
发表于 2005-3-16 09:06:00 | 显示全部楼层 |阅读模式
2D的火焰效果不用贴图方式,而用程式怎样实现?我看了网上的一些内容,主要是开始时在一条线上加上随机亮点,然后运算,但火焰是红黄色的啊,加上随机亮点能行么?请高手指点!

1

主题

130

帖子

135

积分

注册会员

Rank: 2

积分
135
发表于 2005-3-16 12:25:00 | 显示全部楼层

Re:一个问题!

如果是程序实现的话应该是粒子系统
我没写过2d的,但理论上2d的粒子系统实现应该和3d的差不多,随便说说吧
火焰的实现应该是一个范围内在一定时间放出一堆带alpha的图片,通过速度与加速度来控制这些图片的运动以形成火焰效果,火焰的颜色是越到中间越亮,边沿是呈红色,所以这个图片的色彩应该是RGB(200,80,10)左右,这样在各图片重合处比较少的地方就是红色,而在中央部分由于重合度高,会呈黄色,如果更密集会出现亮白色了

20

主题

398

帖子

398

积分

中级会员

Rank: 3Rank: 3

积分
398
发表于 2005-3-16 14:19:00 | 显示全部楼层

Re:一个问题!

看过一篇文章,使用调色板实现的火焰,不知道对你有没有帮助?

原 文:Fire
译 者:狼舞(天涯游戏工作室)

首先,你需要建立一个调色板。我的思路大概是这样的:
  1)黑色放在最底部(这样可以和顶部的亮光形成高度的色差对比),红色,动态色和黄色往上推移。
  2)为了建立一个256色的调色板,我需要使用几个循环:

  LPDIRECTDRAWPALETTE lpDDPal; // 调色板对象
  PALETTEENTRY mypal[256];   // 保存调色板的颜色值

  好,现在我们可以往里面填数据了。不过,我可不敢保证我的色学观是最好的,这样建立的调色板,只是我的一厢情愿,如果你觉得你可以把些颜色调配得更好,我是没有意见的。

  index = 0;

  srand();
  for (index=95;index<200;index++)
  {
    mypal[index].peRed = index+70;
    mypal[index].peGreen = index+30;
    mypal[index].peBlue = rand()%10;
  }
  for (index = 1; index < 35; index++)
  {
    mypal[index].peRed = index+25;
    mypal[index].peGreen = rand()%10;
    mypal[index].peBlue = rand()%10;
  }
  for (index = 35; index < 55; index++)
  {
    mypal[index].peRed = index+25;
    mypal[index].peGreen = index-25;
    mypal[index].peBlue = rand()%10;
  }
  for (index = 55; index < 95; index++)
  {
    mypal[index].peRed = index+75;
    mypal[index].peGreen = index;
    mypal[index].peBlue = rand()%5;
  }
  for(index = 200; index < 255; index++)
  {
    mypal[index].peRed = index;
    mypal[index].peGreen = index-rand()%25;
    mypal[index].peBlue = rand()%5;
  }

  不过,这是我所找到的最好的化合方法了,哈哈,应该是很漂亮的。尽管简单,但还是浪费了我10多分钟。
  现在,就轮到我们用DirectDraw来建立这个调色板了:

  lpDD->CreatePalette(DDPCAPS_8BIT | DDPCAPS_ALLOW256, mypal, &lpDDPal, NULL);
  lpDDSPrimary->SetPalette(lpDDPal);

  lpDD和lpDDSPrimary不知道是什么东西?不会吧,这可是微软流传给民间的通用取名法啊!
  终于,我们开始做我们伟大工作的第二步了 — 锁定DirectDraw页面,往上面涂东西 — 这可不是乱涂:

  unsigned char *Lock_Back_Buffer (void)
  {
    DDSURFACEDESC ddsd;
    HRESULT ret;
    ddsd.dwSize = sizeof(ddsd);

    ret = DDERR_WASSTILLDRAWING;

    while (ret == DDERR_WASSTILLDRAWING)
      ret = lpDDSBack->Lock(NULL, &ddsd, 0, NULL);

    return (ret == DD_OK ? (unsigned char *)ddsd.lpSurface : NULL);
  }

  别告诉我lpDDSBack你又不知道是什么东西啊。这样我的文章可不好继续下去。来,如果只有部分人不懂,那我也就不管了:

  unsigned char *double_buffer = NULL;
  double_buffer = (unsigned char *)malloc(307200);

  别忘了在你的退出代码中加入:

  (double_buffer); free(fire_buffer);

  这样的代码。
  好了。我们在640X480X8Bit模式下工作了,真是伟大的创举。你太棒了。
  继续,我感到越来越兴奋了。现在的问题是怎么生成火焰?一个像素一个像素的渲染?那是肯定的。但是如果每渲染一次都要更换全屏幕数据的话,让我算算,喔,我的PIII都没有这种性能啊!看来只有看家技了:

  for(x = 1; x < 637; x+=rand()%3)
  {
    if(rand()%2)
      fire_buffer[(480*640) + x] = 255;
    else
      fire_buffer[(480*640) + x] = 0;
  }

  看懂了以上代码了么?我只渲染最底层的一根线的高度。哈哈,这样省事了。可是上面的怎么办?别急,跟我来。我用下面的伪代码表达一下:

  for y = 1, y to screenheight, increment y
    for x = 1, x to screenwidth, increment x
      find our offset - what pixel we are going to start
        averaging around - (Y*ScreenHeight)+x
      add up the surrounding pixels - all eight of them
      divide that total by 8 - hard concept there =)

      now if that value is not 0 - not black
      we decrement it - subtract 1 =)

    end

  Draw to our back buffer

  end

  看不懂,那我用C++代码表达吧:

  int x,y,fireoffset;

  // calculate the bottom line pixels
  for(x = 1; x < 637; x+=rand()%3)
  {
    if(rand()%2)
      fire_buffer[(480*640) + X] = 255;
    else
      fire_buffer[(480*640) + X] = 0;
  }

  // CALCULATE THE SURROUNDING PIXELS
  for(y = 1; y < 480; ++y)
  {
    for(x = 1; x < 640; ++x)
    {
      offset = (y*640) + x; firevalue = ((fire_buffer[fireoffset-640] +
        fire_buffer[fireoffset+640] +
        fire_buffer[fireoffset+1] +
        fire_buffer[fireoffset-1] +
        fire_buffer[fireoffset-641] +
        fire_buffer[fireoffset-639] +
        fire_buffer[fireoffset+641] +
        fire_buffer[fireoffset+639]) / 8); // this can be optimized by a
                          // look up table as I'll show you later

      if(firevalue != 0) // is it black?
      {
        --firevalue;  // Nope. Beam me down Scotty.
        fire_buffer[fireoffset-640] = firevalue; // Plot that new color
                             // on the above pixel
                             // remember the typewriter analogy
      }
    }
  }

  double_buffer = Lock_Back_Buffer(); // Remember this function? Good
  memcpy(double_buffer, fire_buffer, (640*480)); // Copy fire buffer to the screen
  lpddsback->Unlock(NULL);       // Unlock! Important! you have no idear!

  我发现伟大的工作被我们做完一大半了,还有?当然还有,还有什么,别急,看:

  int firelook;
  for (firelook = 0; firelook < 1256; FIRELOOK++)
    FTAB[FIRELOOK] = FIRER >> 3;

  firevalue = ftab[(fire_buffer[fireoffset-640] +
    fire_buffer[fireoffset+640] +
    fire_buffer[fireoffset+1] +
    fire_buffer[fireoffset-1] +
    fire_buffer[fireoffset-641] +
    fire_buffer[fireoffset-639] +
    fire_buffer[fireoffset+641] +
    fire_buffer[fireoffset+639])];

  看懂了吗?fireoffset-640是什么?右上的像素?fireoffset-639是什么?一个上面的像素,但是有一点点在右边,那就是在右上角的像素了。fireoffset+640是什么?下面的像素。我告诉你的仅仅是一个示例,哈,但是你必须得相信我。不过,我怀疑你会被我搞糊涂。不过,你把这篇文章多看几次,想清楚了之后,你的想法就会改变的,你一定会来谢谢我的。

63

主题

871

帖子

891

积分

高级会员

Rank: 4

积分
891
QQ
发表于 2005-3-16 20:39:00 | 显示全部楼层

Re:一个问题!

当前的点 = 她下面相邻一排点的平均

越上去颜色越淡(透明度越大)

77

主题

203

帖子

279

积分

中级会员

Rank: 3Rank: 3

积分
279
 楼主| 发表于 2005-3-17 08:45:00 | 显示全部楼层

Re: 一个问题!

多谢各位前辈的帮忙!!!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-12-24 20:10

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表