⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hgeparticle.pas

📁 完整的Delphi游戏开发控件
💻 PAS
📖 第 1 页 / 共 2 页
字号:

      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 + -