www.pudn.com > XParticles.rar > XParticles.pas


unit XParticles; 
//--------------------------------------------------------------------------- 
// XParticles.pas 
// XParticles System                                              Version 1.1 
//--------------------------------------------------------------------------- 
// The contents of this file are subject to the Mozilla Public License 
// Version 1.1 (the "License"); you may not use this file except in 
// compliance with the License. You may obtain a copy of the License at 
// http://www.mozilla.org/MPL/ 
// 
// Software distributed under the License is distributed on an "AS IS" 
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the 
// License for the specific language governing rights and limitations 
// under the License. 
//--------------------------------------------------------------------------- 
 
interface 
 
uses Classes, Types, AsphyreDef, AsphyreImages, AsphyreCanvas, Vectors2, Math, 
     SmoothColorUnit; 
//------------------------------------------------------------------------------ 
const 
  MAX_PARTICLES	= 5000; 
  MAX_PSYSTEMS = 100; 
 
  PI_2 = 1.57079632; 
 
//------------------------------------------------------------------------------ 
type 
  TPatternChangeType = (prFixed, ptInc, ptDec); 
 
//------------------------------------------------------------------------------ 
  TXParticleSprite = record 
    Pattern: integer; 
    PatternType: TPatternChangeType; 
    PatternsPerSec: integer; 
    DrawFx: Cardinal; 
  end; 
 
//------------------------------------------------------------------------------ 
  PXParticle = ^TXParticle; 
  TXParticle = record 
    Location, 
    Displacement: TPoint2; // Start location displacement 
     
	  Velocity: TPoint2; 
	  Gravity: Single; 
     
	  RadialAccel, 
	  TangentialAccel: Single; 
 
    Angle, 
	  AngleDelta: Single; 
 
	  Scale, 
	  ScaleDelta: Single; 
 
	  Color, 
	  ColorDelta: TSmoothColor; 
 
	  Age, 
	  TerminalAge: Single; 
  end; 
 
//------------------------------------------------------------------------------ 
  {TAreaShape = (asRect, asEllipse, asPoint); 
 
//------------------------------------------------------------------------------ 
  TArea = record 
    Rect: TPoint4; 
    Shape: TAreaShape; 
  end; 
 
//------------------------------------------------------------------------------ 
  TSpawnArea = record 
    Area: TArea; 
    InnerArea: TArea; 
  end;} 
   
//------------------------------------------------------------------------------ 
  PXParticleSystemSettings = ^TXParticleSystemSettings; 
  TXParticleSystemSettings = record 
    Sprite: TXParticleSprite; // Pointer to particle image 
	  EmissionRate: integer; // Particles per second 
	  LifeTime: integer; 
 
    //DrawArea: TArea; 
    //SpawnArea: TSpawnArea; 
 
	  ParticleLifeMin, 
	  ParticleLifeMax: integer; 
 
	  Direction, 
	  Spread: Single; 
	  Relative: boolean; 
 
	  SpeedMin, 
	  SpeedMax: Single; 
 
	  GravityMin, 
	  GravityMax: Single; 
 
	  RadialAccelMin, 
	  RadialAccelMax: Single; 
 
	  TangentialAccelMin, 
	  TangentialAccelMax: Single; 
 
	  ScaleStart, 
	  ScaleEnd, 
	  ScaleRnd: Single; 
 
	  SpinStart, 
	  SpinEnd, 
	  SpinRnd: Single; 
 
	  ColorStart, 
	  ColorEnd: Cardinal; 
	  ColorRnd, 
	  AlphaRnd: Single; 
  end; 
 
  //------------------------------------------------------------------------------ 
  TEmitters = array of TPoint; 
  //------------------------------------------------------------------------------ 
  TXParticleSystem = class 
  private 
    FTexture: TAsphyreImage; 
     
    FParticles: array[0..MAX_PARTICLES-1] of TXParticle; 
    FSettings: TXParticleSystemSettings; 
 
    FEmitters: TEmitters; 
     
	  FUpdSpeed, 
	  FResidue: Single; 
 
	  FAge, 
	  FEmissionResidue: Single; 
 
	  FPrevLocation, 
	  FLocation: TPoint2; 
	  FTx, 
    FTy: Single; 
 
	  FParticlesAlive: integer; 
 
    function GetTransposition(): TPoint2; 
  protected 
    procedure UpdateSys(const DeltaTime: integer); 
    procedure RenderSprite(const Sprite: TXParticleSprite; const Canvas: TAsphyreCanvas; 
              const Color: Cardinal; const X, Y, Angle, Scale: Single); 
 
  public 
    constructor Create(const Stream: TStream; const ParticleSprite: TXParticleSprite); overload; 
    constructor Create(PSS: TXParticleSystemSettings); overload; 
 
    property Texture: TAsphyreImage read FTexture write FTexture; 
     
    function SettingsLoadFromStream(const Stream: TStream): boolean; 
    function SettingsSaveFromStream(const Stream: TStream): boolean; 
 
	  procedure Render(Canvas: TAsphyreCanvas); 
	  procedure StartAt(x, y: Single); 
	  procedure Start(); 
	  procedure Stop(KillParticles: boolean = false); 
	  procedure Update(const DeltaTime: integer); 
	  procedure MoveTo(const x, y: Single; MoveParticles: boolean = false); 
	  procedure Transpose(const x, y: Single); 
 
    procedure AddParticle(const x, y: integer); 
 
    procedure AddEmitters(const Emitters: array of TPoint); 
    procedure AddEmittersFromImage(const Image: TAsphyreImage; const Color: Cardinal); 
    procedure RemoveAllEmitters(); 
    procedure ScaleEmitters(Scale: Single); 
 
    property Emitters: TEmitters read FEmitters; 
    property Settings: TXParticleSystemSettings read FSettings write FSettings; 
	  property ParticlesAlive: integer read FParticlesAlive; 
	  property Age: Single read fAge; 
	  property Position: TPoint2 read FLocation; 
	  property Transposition: TPoint2 read GetTransposition; 
  end; 
 
//------------------------------------------------------------------------------ 
  TXParticleManager = class 
  private 
    FCanvas: TAsphyreCanvas; 
 
	  FCount: integer; 
	  FX, 
	  FY: Single; 
	  FItems: array[0..MAX_PSYSTEMS-1] of TXParticleSystem; 
 
    function GetTransposition: TPoint2; 
    function GetItem(id: cardinal): TXParticleSystem; 
    function GetParticlesAlive(): integer; 
  public 
	  constructor Create(); 
 
	  procedure Update(const DeltaTime: integer); 
	  procedure Render(); 
 
	  function SpawnPS(PSS: TXParticleSystemSettings; Texture: TAsphyreImage; X, Y: Single): TXParticleSystem; 
	  function IsPSAlive(PS: TXParticleSystem): boolean; 
 
	  procedure Transpose(X, Y: Single); 
     
    procedure KillPS(PS: TXParticleSystem); 
	  procedure KillAll(); 
 
    property Items[id: cardinal]: TXParticleSystem read GetItem; 
    property Count: integer read FCount; 
    property ParticlesAlive: integer read GetParticlesAlive; 
	  property Transposition: TPoint2 read GetTransposition; 
  published 
    property Canvas: TAsphyreCanvas read FCanvas write FCanvas; 
  end; 
 
//------------------------------------------------------------------------------ 
var 
  RRSeed: integer = 0; 
 
function RandomSingle(const Min, Max: Single): Single; 
 
implementation 
 
uses DXTextures, AsphyreDevices; 
 
//------------------------------------------------------------------------------ 
// Some funtions... 
//------------------------------------------------------------------------------ 
function VecMultSingle(const a: TPoint2; const val: Single): TPoint2; 
begin 
Result.x:= a.x * val; 
Result.y:= a.y * val; 
end; 
//------------------------------------------------------------------------------ 
function VecAngle(const v1,v2: TPoint2): Single; 
begin 
Result:= ArcTan2(v2.y - v1.y, v2.x - v1.x); 
end; 
//------------------------------------------------------------------------------ 
function RandomSingle(const Min, Max: Single): Single; 
var 
  Mi, Ma: Single; 
begin 
Mi:= Min; 
Ma:= Max; 
 
if (Min > Max) then 
  begin 
  Mi:= Max; 
  Ma:= Min; 
  end; 
 
RRSeed:= 214013*RRSeed + 2531011; 
Result:= Mi + (RRSeed shr 16) * (1.0 / 65535.0) * (Ma - Mi); 
end; 
//------------------------------------------------------------------------------ 
 
//------------------------------------------------------------------------------ 
//  TXParticleSystem. 
//------------------------------------------------------------------------------ 
constructor TXParticleSystem.Create(const Stream: TStream; 
              const ParticleSprite: TXParticleSprite); 
begin 
if (Stream = nil){or(ParticleSprite = nil)} then 
  Exit; 
 
Stream.Read(FSettings, SizeOf(TXParticleSystemSettings)); 
 
FSettings.Sprite:= ParticleSprite; 
 
FLocation:= Point2(0.0, 0.0); 
FPrevLocation:= Point2(0.0, 0.0); 
 
FTx:= 0; 
FTy:= 0; 
 
FEmissionResidue:= 0.0; 
FParticlesAlive:= 0; 
FAge:= -2.0; 
FUpdSpeed:= 0.0; 
FResidue:= 0.0; 
SetLength(FEmitters, 0); 
AddEmitters([Point(0, 0)]); 
end; 
//------------------------------------------------------------------------------ 
constructor TXParticleSystem.Create(PSS: TXParticleSystemSettings); 
begin 
FSettings:= PSS; 
 
FLocation:= Point2(0.0, 0.0); 
FPrevLocation:= Point2(0.0, 0.0); 
 
FTx:= 0.0; 
FTy:= 0.0; 
 
FEmissionResidue:= 0.0; 
FParticlesAlive:= 0; 
FAge:= -2.0; 
FUpdSpeed:= 0.0; 
FResidue:= 0.0; 
SetLength(FEmitters, 0); 
AddEmitters([Point(0, 0)]); 
end; 
//------------------------------------------------------------------------------ 
function TXParticleSystem.SettingsLoadFromStream(const Stream: TStream): boolean; 
begin 
if (Stream <> nil) then 
  Result:= (Stream.Read(FSettings, SizeOf(TXParticleSystemSettings)) > 0) 
else 
  Result:= false; 
end; 
//------------------------------------------------------------------------------ 
function TXParticleSystem.SettingsSaveFromStream(const Stream: TStream): boolean; 
begin 
if (Stream <> nil) then 
  Result:= (Stream.Write(FSettings, SizeOf(TXParticleSystemSettings)) > 0) 
else 
  Result:= false; 
end; 
//------------------------------------------------------------------------------ 
procedure TXParticleSystem.Render(Canvas: TAsphyreCanvas); 
var 
  i: integer; 
  Par: PXParticle; 
begin 
if (FParticlesAlive <= 0) then 
  Exit; 
 
for i:= 0 to FParticlesAlive-1 do 
	begin 
  if (i > MAX_PARTICLES-1) then 
    Break; 
   
  Par:= @FParticles[i]; 
  //FSettings.Sprite. 
  RenderSprite(FSettings.Sprite, Canvas, FromSmoothColor(Par.Color), Par.Location.x + FTx, Par.Location.y + FTy, 
    Par.Angle{ * Par.Age}, Par.Scale); 
	end; 
end; 
//------------------------------------------------------------------------------ 
procedure TXParticleSystem.RenderSprite(const Sprite: TXParticleSprite; const Canvas: TAsphyreCanvas; 
   const Color: Cardinal; const X, Y, Angle, Scale: Single); 
var 
  Tex: TAsphyreImage; 
begin 
Tex:= FTexture; 
 
if (Tex = nil)or 
   (X + (Tex.PatternSize.X div 2) < 0)or 
   (Y + (Tex.PatternSize.Y div 2) < 0)or 
   (X - (Tex.PatternSize.X div 2) > Canvas.Device.Width)or 
   (Y - (Tex.PatternSize.Y div 2) > Canvas.Device.Height) then 
  Exit; 
 
//Canvas.Draw(Tex, X, Y, FPattern, FDrawFx); 
Canvas.DrawRot(Tex, X, Y, Angle, Scale, Color, Sprite.Pattern, Sprite.DrawFx); 
end; 
//------------------------------------------------------------------------------ 
procedure TXParticleSystem.Update(const DeltaTime: integer); 
begin 
UpdateSys(DeltaTime); 
{if (FUpdSpeed <= 0.00) then 
  UpdateSys(DeltaTime) 
else 
  begin 
  FResidue:= FResidue + DeltaTime; 
  if (fResidue >= FUpdSpeed) then 
	  begin 
    UpdateSys(DeltaTime); 
		while(FResidue >= FUpdSpeed) do 
      FResidue:= FResidue - FUpdSpeed; 
	  end; 
   end;} 
end; 
//------------------------------------------------------------------------------ 
procedure TXParticleSystem.UpdateSys(const DeltaTime: integer); 
var 
  i: integer; 
	ang, Delta: Single; 
	Par: PXParticle; 
	AccelVec, AccelVec2: TPoint2; 
 
  ParticlesNeeded: Single; 
  ParticlesCreated: integer; 
begin 
Delta:= DeltaTime / 1000; 
 
if (FAge >= 0) then 
	begin 
  FAge:= FAge + DeltaTime; 
  if (fAge >= FSettings.LifeTime) then 
    FAge:= -2.0; 
	end; 
 
// Update all ALIVE particles 
 
i:= 0; 
while i <= FParticlesAlive-1 do 
	begin 
  if (i > MAX_PARTICLES-1) then 
      Break; 
 
  Par:= @FParticles[i]; 
  Inc(i); 
 
  Par.Age:= Par.Age + DeltaTime; 
  if (Par.Age >= Par.TerminalAge) then 
		begin 
    Dec(FParticlesAlive); 
    // Move last particle to the free cell 
    Par^:= FParticles[FParticlesAlive]; 
    Dec(i); 
    Continue; 
		end; 
 
  AccelVec:= VecSub2(Par.Location, VecAdd2(FLocation, Par.Displacement)); 
  AccelVec:= VecNorm2(AccelVec); 
  AccelVec2:= AccelVec; 
  AccelVec:= VecMultSingle(AccelVec, Par.RadialAccel); 
 
  // Rotating... 
  ang:= AccelVec2.x; 
  AccelVec2.x:= -AccelVec2.y; 
  AccelVec2.y:= ang; 
 
  AccelVec2:= VecMultSingle(AccelVec2, Par.TangentialAccel); 
  Par.Velocity:= VecAdd2(Par.Velocity, VecMultSingle(VecAdd2(AccelVec, AccelVec2), DeltaTime)); 
  Par.Velocity.y:= Par.Velocity.y + Par.Gravity * Delta; 
 
  Par.Location:= VecAdd2(Par.Location, VecMultSingle(Par.Velocity, Delta)); 
 
  Par.Angle:= Par.Angle + Par.AngleDelta * DeltaTime; 
 
  Par.Scale:= Par.Scale + Par.ScaleDelta * DeltaTime; 
 
  //Par.Color:= NormSmoothColor(Par.Color + Par.ColorDelta * DeltaTime); 
  Par.Color:= NormSmoothColor(AddSmColors(Par.Color, MultSmColor(Par.ColorDelta, DeltaTime))); 
  end; 
 
 
// Generate NEW particles 
 
if(FAge > -2.0) then 
	begin 
  ParticlesNeeded:= FSettings.EmissionRate * Delta + FEmissionResidue; 
  ParticlesCreated:= Trunc(ParticlesNeeded); 
  FEmissionResidue:= ParticlesNeeded - ParticlesCreated; 
 
  for i:= 0 to ParticlesCreated-1 do 
		begin 
 
    if (FParticlesAlive >= MAX_PARTICLES) then Break; 
 
    AddParticle(0, 0); 
    end; 
  end; 
 
FPrevLocation:= FLocation; 
end; 
//------------------------------------------------------------------------------ 
procedure TXParticleSystem.AddParticle(const x, y: integer); 
var 
	ang: Single; 
	Par: PXParticle; 
 
  r, g, b, a: Single; 
  Pnt: TPoint; 
begin 
if (FParticlesAlive >= MAX_PARTICLES)or(Length(FEmitters) = 0) then Exit; 
 
Par:= @FParticles[FParticlesAlive]; 
 
Par.Age:= 0.0; 
Par.TerminalAge:= RandomSingle(FSettings.ParticleLifeMin, FSettings.ParticleLifeMax); 
 
// Spawn locations 
Par.Location:= 
  VecAdd2(FPrevLocation, VecMultSingle(VecSub2(FLocation, FPrevLocation), RandomSingle(0.0, 1.0))); 
 
Pnt:= FEmitters[Random(Length(FEmitters))]; 
Par.Location.x:= Par.Location.x + Pnt.X + RandomSingle(-1.0, 1.0) + x; 
Par.Location.y:= Par.Location.y + Pnt.Y + RandomSingle(-1.0, 1.0) + y; 
 
Par.Displacement:= VecSub2(FLocation, Par.Location); 
 
//Particles direction and velocity 
ang:= FSettings.Direction - PI_2 + RandomSingle(0.0, FSettings.Spread) - FSettings.Spread / 2.0; 
 
if (FSettings.Relative) then 
  ang:= ang + VecAngle(Point2(0, 0), VecSub2(FPrevLocation, FLocation)) + PI_2; 
Par.Velocity.x:= Cos(ang); 
Par.Velocity.y:= sin(ang); 
Par.Velocity:= VecMultSingle(Par.Velocity, RandomSingle(FSettings.SpeedMin, FSettings.SpeedMax)); 
 
Par.Gravity:= RandomSingle(FSettings.GravityMin, FSettings.GravityMax); 
 
// Accelerations 
Par.RadialAccel:= RandomSingle(FSettings.RadialAccelMin, FSettings.RadialAccelMax); 
Par.TangentialAccel:= RandomSingle(FSettings.TangentialAccelMin, FSettings.TangentialAccelMax); 
 
// SCALE 
Par.Scale:= RandomSingle(FSettings.ScaleStart, 
  FSettings.ScaleStart + (FSettings.ScaleEnd - FSettings.ScaleStart)* FSettings.ScaleRnd); 
Par.ScaleDelta:= (FSettings.ScaleEnd - Par.Scale) / Par.TerminalAge; 
     
// SPIN 
Par.Angle:= RandomSingle(FSettings.SpinStart, 
  FSettings.SpinStart + (FSettings.SpinEnd - FSettings.SpinStart) * FSettings.SpinRnd); 
Par.AngleDelta:= (FSettings.SpinEnd - Par.Angle) / Par.TerminalAge; 
 
// Define start color 
// Par.Color:= ToSmoothColor(FSettings.ColorStart);// + Random(trunc((FSettings.ColorEnd - FSettings.ColorStart) * FSettings.ColorRnd)); 
 
r:= (FSettings.ColorStart and $FF); 
g:= (FSettings.ColorStart shr 8) and $FF; 
b:= (FSettings.ColorStart shr 16) and $FF; 
a:= (FSettings.ColorStart shr 24) and $FF; 
Par.Color:= SmoothRGBA( 
      RandomSingle(r, (r + ((FSettings.ColorEnd and $FF - r) * FSettings.ColorRnd))), 
      RandomSingle(g, (g + (((FSettings.ColorEnd shr 8) and $FF - g) * FSettings.ColorRnd))), 
      RandomSingle(b, (b + (((FSettings.ColorEnd shr 16) and $FF - b) * FSettings.ColorRnd))), 
      RandomSingle(a, (a + (((FSettings.ColorEnd shr 24) and $FF - a) * FSettings.AlphaRnd))), 
      true); 
 
// Define color delta 
// Par.ColorDelta:= FSettings.ColorRnd;//trunc((FSettings.ColorEnd - Par.Color) / Par.TerminalAge); 
Par.ColorDelta:= SmoothRGBA( 
      (FSettings.ColorEnd and $FF - Par.Color.R) / Par.TerminalAge, 
      ((FSettings.ColorEnd shr 8) and $FF  - Par.Color.G) / Par.TerminalAge, 
      ((FSettings.ColorEnd shr 16) and $FF - Par.Color.B) / Par.TerminalAge, 
      ((FSettings.ColorEnd shr 24) and $FF - Par.Color.A) / Par.TerminalAge, 
      false); 
{} 
Inc(FParticlesAlive); 
end; 
//------------------------------------------------------------------------------ 
procedure TXParticleSystem.AddEmitters(const Emitters: array of TPoint); 
var 
  Size, i: integer; 
begin 
for i:= 0 to Length(Emitters)-1 do 
  begin 
  Size:= Length(FEmitters); 
  SetLength(FEmitters, Size+1); 
  FEmitters[Size]:= Emitters[i]; 
  end; 
end; 
//------------------------------------------------------------------------------ 
procedure TXParticleSystem.AddEmittersFromImage(const Image: TAsphyreImage; const Color: Cardinal); 
var 
  x, y, Points: integer; 
begin 
if (not Assigned(Image)) then Exit; 
 
SetLength(FEmitters, 0); 
Points:= 0; 
 
for x := 0 to Image.PatternSize.X - 1 do 
  for y := 0 to Image.PatternSize.Y - 1 do 
    if (Image.Pixels[x, y, 0] = Color) then 
      begin 
      Inc(Points); 
      AddEmitters([Point(x, y)]); 
      end; 
 
// if Image has no emitters 
//if (Points = 0) then 
//  AddEmitters([Point(trunc(FLocation.X), trunc(FLocation.Y))]); 
end; 
//------------------------------------------------------------------------------ 
procedure TXParticleSystem.ScaleEmitters(Scale: Single); 
var 
  i: integer; 
begin 
for i:= 0 to Length(FEmitters)-1 do 
  begin 
  FEmitters[i].X:= Round(FEmitters[i].X * Scale); 
  FEmitters[i].Y:= Round(FEmitters[i].Y * Scale); 
  end; 
end; 
//------------------------------------------------------------------------------ 
procedure TXParticleSystem.RemoveAllEmitters(); 
begin 
SetLength(FEmitters, 0); 
end; 
//------------------------------------------------------------------------------ 
procedure TXParticleSystem.StartAt(X, Y: Single); 
begin 
Stop(); 
MoveTo(x, y); 
Start(); 
end; 
//------------------------------------------------------------------------------ 
procedure TXParticleSystem.Start(); 
begin 
if (Length(FEmitters) = 0) then Exit; 
 
if (FSettings.Lifetime <= -0.9) then 
  FAge:= -1.0 
else 
  fAge:= 0.0; 
   
FResidue:= 0.0; 
end; 
//------------------------------------------------------------------------------ 
procedure TXParticleSystem.Stop(KillParticles: boolean = false); 
begin 
FAge:= -2.0; 
if (KillParticles) then 
  FParticlesAlive:= 0; 
end; 
//------------------------------------------------------------------------------ 
procedure TXParticleSystem.MoveTo(const x, y: Single; MoveParticles: boolean = false); 
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.0) 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 TXParticleSystem.Transpose(const x, y: Single); 
begin 
FTx:= x; 
FTy:= y; 
end; 
//------------------------------------------------------------------------------ 
function TXParticleSystem.GetTransposition(): TPoint2; 
begin 
Result.x:= FTx; 
Result.y:= FTy; 
end; 
//------------------------------------------------------------------------------ 
 
//------------------------------------------------------------------------------ 
// TXParticleManager. 
//------------------------------------------------------------------------------ 
constructor TXParticleManager.Create(); 
begin 
FCount:= 0; 
Fx:= 0.0; 
Fy:= 0.0; 
end; 
//------------------------------------------------------------------------------ 
procedure TXParticleManager.Update(const DeltaTime: integer); 
var 
  i: integer; 
begin 
//for i:= FCount-1  downto 0 do 
for i:= 0 to FCount-1 do 
	begin 
  FItems[i].Update(DeltaTime); 
	if (FItems[i] <> nil)and 
     (FItems[i].Age <= -1.9)and 
     (FItems[i].ParticlesAlive = 0) then 
		begin 
    FItems[i].Free(); 
    FItems[i]:= FItems[FCount-1]; 
    Dec(FCount); 
    end; 
  end; 
end; 
//------------------------------------------------------------------------------ 
procedure TXParticleManager.Render(); 
var 
  i: integer; 
begin 
for i:= 0 to FCount-1 do 
  FItems[i].Render(FCanvas); 
end; 
//------------------------------------------------------------------------------ 
function TXParticleManager.SpawnPS(PSS: TXParticleSystemSettings; 
  Texture: TAsphyreImage;  X, Y: Single): TXParticleSystem; 
begin 
if (FCount >= MAX_PSYSTEMS) then 
  begin 
  Result:= nil; 
  Exit; 
  end; 
   
FItems[FCount]:= TXParticleSystem.Create(PSS); 
FItems[FCount].Texture:= Texture; 
FItems[FCount].StartAt(x, y); 
FItems[FCount].Transpose(FX, FY); 
Result:= FItems[FCount]; 
Inc(FCount); 
end; 
//------------------------------------------------------------------------------ 
function TXParticleManager.IsPSAlive(PS: TXParticleSystem): boolean; 
var 
  i: integer; 
begin 
Result:= false; 
 
for i:= 0 to FCount-1 do 
  if (FItems[i] = PS) then 
    begin 
    Result:= true; 
    Break; 
    end; 
end; 
//------------------------------------------------------------------------------ 
procedure TXParticleManager.Transpose(X, Y: Single); 
var 
  i: integer; 
begin 
for i:= 0 to FCount-1 do 
  FItems[i].Transpose(x, y); 
   
FX:= x; 
FY:= y; 
end; 
//------------------------------------------------------------------------------ 
procedure TXParticleManager.KillPS(PS: TXParticleSystem); 
var 
  i: integer; 
begin 
for i:= 0 to FCount-1 do 
	begin 
	if(FItems[i] = PS) then 
		begin 
    FItems[i].Free(); 
    //FCountList[i]:= FCountList[FCount-1]; 
    Dec(FCount); 
    Break; 
    end; 
  end; 
end; 
//------------------------------------------------------------------------------ 
procedure TXParticleManager.KillAll(); 
var 
  i: integer; 
begin 
for i:=0 to FCount-1 do 
  FItems[i].Free(); 
FCount:= 0; 
end; 
//------------------------------------------------------------------------------ 
function TXParticleManager.GetTransposition: TPoint2; 
begin 
Result.x:= FX; 
Result.y:= FY; 
end; 
//------------------------------------------------------------------------------ 
function TXParticleManager.GetItem(id: cardinal): TXParticleSystem; 
begin 
Result:= FItems[id]; 
end; 
//------------------------------------------------------------------------------ 
function TXParticleManager.GetParticlesAlive(): integer; 
var 
  i: integer; 
begin 
Result:= 0; 
for i:= 0 to FCount - 1 do 
  Result:= Result + FItems[i].ParticlesAlive; 
end; 
//------------------------------------------------------------------------------ 
//------------------------------------------------------------------------------ 
end.