📄 hgeparticle.pas
字号:
Par.ColorDelta.R := (FInfo.ColorEnd.R - Par.Color.R) / Par.TerminalAge;
Par.ColorDelta.G := (FInfo.ColorEnd.G - Par.Color.G) / Par.TerminalAge;
Par.ColorDelta.B := (FInfo.ColorEnd.B - Par.Color.B) / Par.TerminalAge;
Par.ColorDelta.A := (FInfo.ColorEnd.A - Par.Color.A) / Par.TerminalAge;
if (FUpdateBoundingBox) then
FBoundingBox.Encapsulate(Par.Location.X,Par.Location.Y);
Inc(FParticlesAlive);
Inc(Par);
end;
end;
FPrevLocation := FLocation;
end;
procedure THGEParticleSystem.Fire;
begin
if (FInfo.Lifetime = -1) then
FAge := -1
else
FAge := 0;
end;
procedure THGEParticleSystem.FireAt(const X, Y: Single);
begin
Stop;
MoveTo(X,Y);
Fire;
end;
function THGEParticleSystem.GetAge: Single;
begin
Result := FAge;
end;
function THGEParticleSystem.GetBoundingBox(out Rect: THGERect): PHGERect;
begin
Rect := FBoundingBox;
Result := @Rect;
end;
function THGEParticleSystem.GetInfo: PHGEParticleSystemInfo;
begin
Result := @FInfo;
end;
function THGEParticleSystem.GetParticlesAlive: Integer;
begin
Result := FParticlesAlive;
end;
procedure THGEParticleSystem.GetPosition(out X, Y: Single);
begin
X := FLocation.X;
Y := FLocation.Y;
end;
procedure THGEParticleSystem.GetTransposition(out X, Y: Single);
begin
X := FTX;
Y := FTY;
end;
function THGEParticleSystem.Implementor: TObject;
begin
Result := Self;
end;
procedure THGEParticleSystem.MoveTo(const X, Y: Single;
const MoveParticles: Boolean);
var
I: Integer;
DX, DY: Single;
begin
if (MoveParticles) then begin
DX := X - FLocation.X;
DY := Y - FLocation.Y;
for I := 0 to FParticlesAlive - 1 do begin
FParticles[I].Location.X := FParticles[I].Location.X + DX;
FParticles[I].Location.Y := FParticles[I].Location.Y + DY;
end;
FPrevLocation.X := FPrevLocation.X + DX;
FPrevLocation.Y := FPrevLocation.Y + DY;
end else begin
if (FAge = -2) then begin
FPrevLocation.X := X;
FPrevLocation.Y := Y;
end else begin
FPrevLocation.X := FLocation.X;
FPrevLocation.Y := FLocation.Y;
end;
end;
FLocation.X := X;
FLocation.Y := Y;
end;
procedure THGEParticleSystem.Render;
var
I: Integer;
Col: Longword;
Par: PHGEParticle;
begin
Par := @FParticles[0];
Col := FInfo.Sprite.GetColor;
for I := 0 to FParticlesAlive - 1 do begin
FInfo.Sprite.SetColor(Par.Color.GetHWColor);
FInfo.Sprite.RenderEx(Par.Location.X + FTX,Par.Location.Y + FTY,
Par.Spin * Par.Age,Par.Size);
Inc(Par);
end;
FInfo.Sprite.SetColor(Col);
end;
procedure THGEParticleSystem.Stop(const KillParticles: Boolean);
begin
FAge := -2;
if (KillParticles) then begin
FParticlesAlive := 0;
FBoundingBox.Clear;
end;
end;
procedure THGEParticleSystem.TrackBoundingBox(const Track: Boolean);
begin
FUpdateBoundingBox := Track;
end;
procedure THGEParticleSystem.Transpose(const X, Y: Single);
begin
FTX := X;
FTY := Y;
end;
procedure THGEParticleSystem.Update(const DeltaTime: Single);
var
I, ParticlesCreated: Integer;
Ang, ParticlesNeeded: Single;
Par: PHGEParticle;
Accel, Accel2, V: THGEVector;
begin
if (FAge >= 0) then begin
FAge := FAge + DeltaTime;
if (FAge >= FInfo.Lifetime) then
FAge := -2;
end;
// update all alive particles
if (FUpdateBoundingBox) then
FBoundingBox.Clear;
Par := @FParticles;
I := 0;
while (I < FParticlesAlive) do begin
Par.Age := Par.Age + DeltaTime;
if (Par.Age >= Par.TerminalAge) then begin
Dec(FParticlesAlive);
Move(FParticles[FParticlesAlive],Par^,SizeOf(THGEParticle));
Continue;
end;
Accel := Par.Location - FLocation;
Accel.Normalize;
Accel2 := Accel;
Accel.Scale(Par.RadialAccel);
// vecAccel2.Rotate(M_PI_2);
// the following is faster
Ang := Accel2.X;
Accel2.X := -Accel2.Y;
Accel2.Y := Ang;
Accel2.Scale(Par.TangentialAccel);
Par.Velocity.Increment((Accel + Accel2) * DeltaTime);
Par.Velocity.Y := Par.Velocity.Y + (Par.Gravity * DeltaTime);
Par.Location.Increment(Par.Velocity * DeltaTime);
Par.Spin := Par.Spin + (Par.SpinDelta * DeltaTime);
Par.Size := Par.Size + (Par.SizeDelta * DeltaTime);
Par.Color := Par.Color + (Par.ColorDelta * DeltaTime);
if (FUpdateBoundingBox) then
FBoundingBox.Encapsulate(Par.Location.X,Par.Location.Y);
Inc(Par);
Inc(I);
end;
// generate new particles
if (FAge <> -2) then begin
ParticlesNeeded := FInfo.Emission * DeltaTime + FEmissionResidue;
ParticlesCreated := Trunc(ParticlesNeeded);
FEmissionResidue := ParticlesNeeded - ParticlesCreated;
Par := @FParticles[FParticlesAlive];
for I := 0 to ParticlesCreated - 1 do begin
if (FParticlesAlive >= MAX_PARTICLES) then
Break;
Par.Age := 0;
Par.TerminalAge := FHGE.Random_Float(FInfo.ParticleLifeMin,FInfo.ParticleLifeMax);
Par.Location := FPrevLocation + (FLocation - FPrevLocation)
* FHGE.Random_Float(0,1);
Par.Location.X := Par.Location.X + FHGE.Random_Float(-2,2);
Par.Location.Y := Par.Location.Y + FHGE.Random_Float(-2,2);
Ang := FInfo.Direction - M_PI_2 + FHGE.Random_Float(0,FInfo.Spread)
- FInfo.Spread / 2;
if (FInfo.Relative) then begin
V := FPrevLocation - FLocation;
Ang := Ang + (V.Angle + M_PI_2);
end;
Par.Velocity.X := Cos(Ang);
Par.Velocity.Y := Sin(Ang);
Par.Velocity.Scale(FHGE.Random_Float(FInfo.SpeedMin,FInfo.SpeedMax));
Par.Gravity := FHGE.Random_Float(FInfo.GravityMin,FInfo.GravityMax);
Par.RadialAccel := FHGE.Random_Float(FInfo.RadialAccelMin,FInfo.RadialAccelMax);
Par.TangentialAccel := FHGE.Random_Float(FInfo.TangentialAccelMin,FInfo.TangentialAccelMax);
Par.Size := FHGE.Random_Float(FInfo.SizeStart,FInfo.SizeStart
+ (FInfo.SizeEnd - FInfo.SizeStart) * FInfo.SizeVar);
Par.SizeDelta := (FInfo.SizeEnd - Par.Size) / Par.TerminalAge;
Par.Spin := FHGE.Random_Float(FInfo.SpinStart,FInfo.SpinStart
+ (FInfo.SpinEnd - FInfo.SpinStart) * FInfo.SpinVar);
Par.SpinDelta := (Finfo.SpinEnd - Par.Spin) / Par.TerminalAge;
Par.Color.R := FHGE.Random_Float(FInfo.ColorStart.R,FInfo.ColorStart.R
+ (FInfo.ColorEnd.R - FInfo.ColorStart.R) * FInfo.ColorVar);
Par.Color.G := FHGE.Random_Float(FInfo.ColorStart.G,FInfo.ColorStart.G
+ (FInfo.ColorEnd.G - FInfo.ColorStart.G) * FInfo.ColorVar);
Par.Color.B := FHGE.Random_Float(FInfo.ColorStart.B,FInfo.ColorStart.B
+ (FInfo.ColorEnd.B - FInfo.ColorStart.B) * FInfo.ColorVar);
Par.Color.A := FHGE.Random_Float(FInfo.ColorStart.A,FInfo.ColorStart.A
+ (FInfo.ColorEnd.A - FInfo.ColorStart.A) * FInfo.ColorVar);
Par.ColorDelta.R := (FInfo.ColorEnd.R - Par.Color.R) / Par.TerminalAge;
Par.ColorDelta.G := (FInfo.ColorEnd.G - Par.Color.G) / Par.TerminalAge;
Par.ColorDelta.B := (FInfo.ColorEnd.B - Par.Color.B) / Par.TerminalAge;
Par.ColorDelta.A := (FInfo.ColorEnd.A - Par.Color.A) / Par.TerminalAge;
if (FUpdateBoundingBox) then
FBoundingBox.Encapsulate(Par.Location.X,Par.Location.Y);
Inc(FParticlesAlive);
Inc(Par);
end;
end;
FPrevLocation := FLocation;
end;
{ THGEParticleManager }
destructor THGEParticleManager.Destroy;
begin
KillAll;
inherited;
end;
procedure THGEParticleManager.GetTransposition(out DX, DY: Single);
begin
DX := FTX;
DY := FTY;
end;
function THGEParticleManager.IsPSAlive(const PS: IHGEParticleSystem): Boolean;
var
I: Integer;
begin
Result := True;
for I := 0 to FNPS - 1 do
if (FPSList[I] = PS) then
Exit;
Result := False;
end;
procedure THGEParticleManager.KillAll;
var
I: Integer;
begin
for I := 0 to FNPS - 1 do
FPSList[I] := nil;
FNPS := 0;
end;
procedure THGEParticleManager.KillPS(const PS: IHGEParticleSystem);
var
I: Integer;
begin
for I := 0 to FNPS - 1 do begin
if (FPSList[I] = PS) then begin
FPSList[I] := FPSList[FNPS - 1];
Dec(FNPS);
Exit;
end;
end;
end;
procedure THGEParticleManager.Render;
var
I: Integer;
begin
for I := 0 to FNPS - 1 do
FPSList[I].Render;
end;
function THGEParticleManager.SpawnPS(const PSI: THGEParticleSystemInfo; const X,
Y: Single): IHGEParticleSystem;
begin
if (FNPS = MAX_PSYSTEMS) then
Result := nil
else begin
FPSList[FNPS] := THGEParticleSystem.Create(PSI);
FPSList[FNPS].FireAt(X,Y);
FPSList[FNPS].Transpose(FTX,FTY);
Result := FPSList[FNPS];
Inc(FNPS);
end;
end;
procedure THGEParticleManager.Transpose(const X, Y: Single);
var
I: Integer;
begin
for I := 0 to FNPS - 1 do
FPSList[I].Transpose(X,Y);
FTX := X;
FTY := Y;
end;
procedure THGEParticleManager.Update(const DT: Single);
var
I: Integer;
begin
I := 0;
while (I < FNPS) do begin
FPSList[I].Update(DT);
if (FPSList[I].GetAge = -2) and (FPSList[I].GetParticlesAlive = 0) then begin
FPSList[I] := FPSList[FNPS - 1];
Dec(FNPS);
Dec(I);
end;
Inc(I);
end;
end;
initialization
Assert(SizeOf(THGEParticleSystemInfo) = 128);
THGEParticleSystem.FHGE := nil;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -