Алгоритм пламени.
Заведем два массива 1 и 2 - один массив будет содержать текущий кадр пламени,а во второй мы будем заносить результаты вычислений. Создадим палитру пламени от 250 до 100 это будет сплошной белый цвет - пламя в очаге. Далее белый, плавно проходя через желтый, перейдет в красный и черный. Эту палитру можете посмотреть если определен Debug.
В чем состоит основа алгоритма - для каждой точки из массива 1, мы делаем следующее : берем сумму всех окружающих ее точек и делим на их количество. Для хорошего качества точек берем 8. Что же получается? Если очаг пламени организовать внизу, т.е. внизу на каждом шаге случайно ставить точки с большим значением, усреденные суммы дадут нужное затухание. Т.к. мы ставим в очаге точки случайно , то появляются красивые языки.
Последовательность действий:
- Массив 1 содержит текущий кадр пламени.
- Создаем в массиве 1 внизу случайные очаги ( просто ставим точки)
- Каждый элемент массива 2 получаем как усреденную сумму, соответствующих элементов окружающий данный в массиве 1
- Массив 2 копируем на экран
- Переносим массив 2 в массив 1
- Переход на начало
{.$DEFINE DEBUG} Program Fire; Uses DemoVga,Crt,Effect; 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;