:: алгоритмы  и методы :: :: олимпиадные задачи :: :: связь :: :: о сайте ::
Путь: Графика » Эффекты » Пламя
  Алгоритм пламени



Заведем два массива 1 и 2 - один массив будет содержать текущий кадр пламени,а во второй мы будем заносить результаты вычислений. Создадим палитру пламени от 250 до 100 это будет сплошной белый цвет - пламя в очаге. Далее белый, плавно проходя через желтый, перейдет в красный и черный. Эту палитру можете посмотреть если определен Debug.

В чем состоит основа алгоритма - для каждой точки из массива 1, мы делаем следующее : берем сумму всех окружающих ее точек и делим на их количество. Для хорошего качества точек берем 8. Что же получается? Если очаг пламени организовать внизу, т.е. внизу на каждом шаге случайно ставить точки с большим значением, усреденные суммы дадут нужное затухание. Т.к. мы ставим в очаге точки случайно , то появляются красивые языки.

Последовательность действий:

  • Массив 1 содержит текущий кадр пламени.
  • Создаем в массиве 1 внизу случайные очаги ( просто ставим точки)
  • Каждый элемент массива 2 получаем как усреденную сумму, соответствующих элементов окружающий данный в массиве 1
  • Массив 2 копируем на экран
  • Переносим массив 2 в массив 1
  • Переход на начало
Для программы требуется модуль demovga.pas
{.$DEFINE DEBUG} 
Program Fire; 
 
Uses DemoVga,Crt; 
 
Type 
   PFireMem = ^TFireMem; 
   TFireMem = Array[0..201,0..319] Of Byte; 
Var 
   FireMem        : PFireMem; 
   I,J            : Integer; 
   R,G,B,dR,dG,dB : Real; 
 
Procedure PlotFireHead; 
Var 
  I : Integer; 
Begin 
 For I := 0 To 319 Do 
  If Random( 2) = 1 Then Begin 
   FireMem^[ 199] [ I] := 255; 
   FireMem^[ 198] [ I] := 255; 
  End; 
End; 
 
Procedure FireLoop; Assembler; 
Asm 
   Push    DS 
   Les           DI,DBuffer 
   Lds           SI,FireMem 
   Add           SI,320*2 
   Mov           CX,64000 
@@F: 
   Xor           AX,AX 
   Add           AL,[SI-321] 
   Adc           AH,0 
   Add           AL,[SI-320] 
   Adc           AH,0 
   Add           AL,[SI-319] 
   Adc           AH,0 
   Add           AL,[SI-1] 
   Adc           AH,0 
   Add           AL,[SI+1] 
   Adc           AH,0 
   Add           AL,[SI+319] 
   Adc           AH,0 
   Add           AL,[SI+320] 
   Adc           AH,0 
   Add           AL,[SI+321] 
   Adc           AH,0 
   Shr           AX,3 
   Or           AL,AL 
   Jz           @@1 
   Dec           AL 
@@1: 
   Stosb 
   Inc           SI 
   Loop    @@F 
   Pop           DS 
End; 
 
Begin 
 InitDemoPart; 
 GetMem( FireMem, 65000); 
 R := 0; G := 0; B := 0; 
 dR := 0.63; dG := 0.91; dB := 1.5; 
 For I := 1 To 100 Do Begin 
  SetRGBColor( I, Round( R), Round( G), Round( B)); 
  R := R + dR; 
  If I > 30 Then G := G + dG; 
  If I > 60 Then B := B + dB; 
 End; 
 For I := 100 To 250 Do SetRGBColor( I, 60, 60, 60); 
{$IFDEF DEBUG} 
 For I := 1 To 100 Do 
  For J := 1 To 100 Do 
   Mem[$A000: J * 320 + I] := I; 
 ReadKey; 
{$ENDIF} 
 FillChar( FireMem^, 65000, 0); 
 Repeat 
  PlotFireHead; 
  FireLoop; 
  Move( DBuffer^, FireMem^, 64000); 
  Move( DBuffer^, Ptr( $A000, 0)^, 64000-320*4); 
 Until KeyPressed; 
 ReadKey; 
 FreeMem( FireMem, 65000); 
 RestoreDemo; End;