home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 23 / IOPROG_23.ISO / SOFT / DELPHIX.ZIP / Source / DXSprite.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1998-10-06  |  27.1 KB  |  1,059 lines

  1. unit DXSprite;
  2.  
  3. interface
  4.  
  5. {$INCLUDE DelphiXcfg.inc}
  6.  
  7. uses
  8.   Windows, SysUtils, Classes, DXClass, DXDraws, DirectX;
  9.  
  10. type
  11.  
  12.   {  ESpriteError  }
  13.  
  14.   ESpriteError = class(Exception);
  15.  
  16.   {  TSprite  }
  17.  
  18.   TSpriteEngine = class;
  19.  
  20.   TSprite = class
  21.   private
  22.     FEngine: TSpriteEngine;
  23.     FParent: TSprite;
  24.     FList: TList;
  25.     FDeaded: Boolean;
  26.     FDrawList: TList;
  27.     FCollisioned: Boolean;
  28.     FMoved: Boolean;
  29.     FVisible: Boolean;
  30.     FX: Double;
  31.     FY: Double;
  32.     FZ: Integer;
  33.     FWidth: Integer;
  34.     FHeight: Integer;
  35.     procedure Add(Sprite: TSprite);
  36.     procedure Remove(Sprite: TSprite);
  37.     procedure AddDrawList(Sprite: TSprite);
  38.     procedure Collision2;
  39.     procedure Draw;
  40.     function GetClientRect: TRect;
  41.     function GetCount: Integer;
  42.     function GetItem(Index: Integer): TSprite;
  43.     function GetWorldX: Double;
  44.     function GetWorldY: Double;
  45.     procedure SetZ(Value: Integer);
  46.   protected
  47.     procedure DoCollision(Sprite: TSprite; var Done: Boolean); virtual;
  48.     procedure DoDraw; virtual;
  49.     procedure DoMove(MoveCount: Integer); virtual;
  50.     function GetBoundsRect: TRect; virtual;
  51.     function TestCollision(Sprite: TSprite): Boolean; virtual;
  52.   public
  53.     constructor Create(AParent: TSprite); virtual;
  54.     destructor Destroy; override;
  55.     procedure Clear;
  56.     function Collision: Integer;
  57.     procedure Dead;
  58.     procedure Move(MoveCount: Integer);
  59.     property BoundsRect: TRect read GetBoundsRect;
  60.     property ClientRect: TRect read GetClientRect;
  61.     property Collisioned: Boolean read FCollisioned write FCollisioned;
  62.     property Count: Integer read GetCount;
  63.     property Engine: TSpriteEngine read FEngine;
  64.     property Items[Index: Integer]: TSprite read GetItem; default;
  65.     property Moved: Boolean read FMoved write FMoved;
  66.     property Parent: TSprite read FParent;
  67.     property Visible: Boolean read FVisible write FVisible;
  68.     property X: Double read FX write FX;
  69.     property Y: Double read FY write FY;
  70.     property Z: Integer read FZ write SetZ;
  71.     property Width: Integer read FWidth write FWidth;
  72.     property WorldX: Double read GetWorldX;
  73.     property WorldY: Double read GetWorldY;
  74.     property Height: Integer read FHeight write FHeight;
  75.   end;
  76.  
  77.   {  TImageSprite  }
  78.  
  79.   TImageSprite = class(TSprite)
  80.   private
  81.     FAnimCount: Integer;
  82.     FAnimLooped: Boolean;
  83.     FAnimPos: Double;
  84.     FAnimSpeed: Double;
  85.     FAnimStart: Integer;
  86.     FImage: TPictureCollectionItem;
  87.     FPixelCheck: Boolean;
  88.     FTile: Boolean;
  89.     FTransparent: Boolean;
  90.     function GetDrawImageIndex: Integer;
  91.     function GetDrawRect: TRect;
  92.   protected
  93.     procedure DoDraw; override;
  94.     procedure DoMove(MoveCount: Integer); override;
  95.     function GetBoundsRect: TRect; override;
  96.     function TestCollision(Sprite: TSprite): Boolean; override;
  97.   public
  98.     constructor Create(AParent: TSprite); override;
  99.     property AnimCount: Integer read FAnimCount write FAnimCount;
  100.     property AnimLooped: Boolean read FAnimLooped write FAnimLooped;
  101.     property AnimPos: Double read FAnimPos write FAnimPos;
  102.     property AnimSpeed: Double read FAnimSpeed write FAnimSpeed;
  103.     property AnimStart: Integer read FAnimStart write FAnimStart;
  104.     property PixelCheck: Boolean read FPixelCheck write FPixelCheck;
  105.     property Image: TPictureCollectionItem read FImage write FImage;
  106.     property Tile: Boolean read FTile write FTile;
  107.   end;
  108.  
  109.   {  TImageSpriteEx  }
  110.  
  111.   TImageSpriteEx = class(TImageSprite)
  112.   private
  113.     FAngle: Integer;
  114.     FAlpha: Integer;
  115.   protected
  116.     procedure DoDraw; override;
  117.     function GetBoundsRect: TRect; override;
  118.     function TestCollision(Sprite: TSprite): Boolean; override;
  119.   public
  120.     constructor Create(AParent: TSprite); override;
  121.     property Angle: Integer read FAngle write FAngle;
  122.     property Alpha: Integer read FAlpha write FAlpha;
  123.   end;
  124.  
  125.   {  TBackgroundSprite  }
  126.  
  127.   TBackgroundSprite = class(TSprite)
  128.   private
  129.     FImage: TPictureCollectionItem;
  130.     FCollisionMap: Pointer;
  131.     FMap: Pointer;
  132.     FMapWidth: Integer;
  133.     FMapHeight: Integer;
  134.     FTile: Boolean;
  135.     function GetCollisionMapItem(X, Y: Integer): Boolean;
  136.     function GetChip(X, Y: Integer): Integer;
  137.     procedure SetChip(X, Y: Integer; Value: Integer);
  138.     procedure SetCollisionMapItem(X, Y: Integer; Value: Boolean);
  139.     procedure SetMapHeight(Value: Integer);
  140.     procedure SetMapWidth(Value: Integer);
  141.   protected
  142.     procedure DoDraw; override;
  143.     function GetBoundsRect: TRect; override;
  144.     function TestCollision(Sprite: TSprite): Boolean; override;
  145.   public
  146.     constructor Create(AParent: TSprite); override;
  147.     destructor Destroy; override;
  148.     procedure SetMapSize(AMapWidth, AMapHeight: Integer);
  149.     property CollisionMap[X, Y: Integer]: Boolean read GetCollisionMapItem write SetCollisionMapItem;
  150.     property Chips[X, Y: Integer]: Integer read GetChip write SetChip;
  151.     property Image: TPictureCollectionItem read FImage write FImage;
  152.     property MapHeight: Integer read FMapHeight write SetMapHeight;
  153.     property MapWidth: Integer read FMapWidth write SetMapWidth;
  154.     property Tile: Boolean read FTile write FTile;
  155.   end;
  156.  
  157.   {  TSpriteEngine  }
  158.  
  159.   TSpriteEngine = class(TSprite)
  160.   private
  161.     FAllCount: Integer;
  162.     FCollisionCount: Integer;
  163.     FCollisionDone: Boolean;
  164.     FCollisionRect: TRect;
  165.     FCollisionSprite: TSprite;
  166.     FDeadList: TList;
  167.     FDrawCount: Integer;
  168.     FSurface: TDirectDrawSurface;
  169.     FSurfaceRect: TRect;
  170.     procedure SetSurface(Value: TDirectDrawSurface);
  171.   public
  172.     constructor Create(AParent: TSprite); override;
  173.     destructor Destroy; override;
  174.     procedure Dead;
  175.     procedure Draw;
  176.     property AllCount: Integer read FAllCount;
  177.     property DrawCount: Integer read FDrawCount;
  178.     property Surface: TDirectDrawSurface read FSurface write SetSurface;
  179.     property SurfaceRect: TRect read FSurfaceRect;
  180.   end;
  181.  
  182.   {  EDXSpriteEngineError  }
  183.  
  184.   EDXSpriteEngineError = class(Exception);
  185.  
  186.   {  TCustomDXSpriteEngine  }
  187.  
  188.   TCustomDXSpriteEngine = class(TComponent)
  189.   private
  190.     FDXDraw: TCustomDXDraw;
  191.     FEngine: TSpriteEngine;
  192.     procedure DXDrawNotifyEvent(Sender: TCustomDXDraw; NotifyType: TDXDrawNotifyType);
  193.     procedure SetDXDraw(Value: TCustomDXDraw);
  194.   protected
  195.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  196.   public
  197.     constructor Create(AOnwer: TComponent); override;
  198.     destructor Destroy; override;
  199.     procedure Dead;
  200.     procedure Draw;
  201.     procedure Move(MoveCount: Integer);
  202.     property DXDraw: TCustomDXDraw read FDXDraw write SetDXDraw;
  203.     property Engine: TSpriteEngine read FEngine;                
  204.   end;
  205.  
  206.   {  TDXSpriteEngine  }
  207.  
  208.   TDXSpriteEngine = class(TCustomDXSpriteEngine)
  209.   published
  210.     property DXDraw;
  211.   end;
  212.  
  213. implementation
  214.  
  215. uses DXConsts;
  216.               
  217. function Mod2(i, i2: Integer): Integer;
  218. begin
  219.   Result := i mod i2;
  220.   if Result<0 then
  221.     Result := i2+Result;
  222. end;
  223.  
  224. function Mod2f(i: Double; i2: Integer): Double;
  225. begin
  226.   if i2=0 then
  227.     Result := i
  228.   else
  229.   begin
  230.     Result := i-(Trunc(i) div i2*i2);
  231.     if Result<0 then
  232.       Result := i2+Result;
  233.   end;
  234. end;
  235.  
  236. {  TSprite  }
  237.  
  238. constructor TSprite.Create(AParent: TSprite);
  239. begin
  240.   inherited Create;
  241.   FParent := AParent;
  242.   if FParent<>nil then
  243.   begin
  244.     FParent.Add(Self);
  245.     if FParent is TSpriteEngine then
  246.       FEngine := TSpriteEngine(FParent)
  247.     else
  248.       FEngine := FParent.Engine;
  249.     Inc(FEngine.FAllCount);
  250.   end;
  251.  
  252.   FCollisioned := True;
  253.   FMoved := True;
  254.   FVisible := True;
  255. end;
  256.  
  257. destructor TSprite.Destroy;
  258. begin
  259.   Clear;
  260.   if FParent<>nil then
  261.   begin
  262.     Dec(FEngine.FAllCount);
  263.     FParent.Remove(Self);
  264.     FEngine.FDeadList.Remove(Self);
  265.   end;
  266.   FList.Free;
  267.   FDrawList.Free;
  268.   inherited Destroy;
  269. end;
  270.  
  271. procedure TSprite.Add(Sprite: TSprite);
  272. begin
  273.   if FList=nil then
  274.   begin
  275.     FList := TList.Create;
  276.     FDrawList := TList.Create;
  277.   end;
  278.   FList.Add(Sprite);
  279.   AddDrawList(Sprite);
  280. end;
  281.  
  282. procedure TSprite.Remove(Sprite: TSprite);
  283. begin
  284.   FList.Remove(Sprite);
  285.   FDrawList.Remove(Sprite);
  286.   if FList.Count=0 then
  287.   begin
  288.     FList.Free;
  289.     FList := nil;
  290.     FDrawList.Free;
  291.     FDrawList := nil;
  292.   end;
  293. end;
  294.  
  295. procedure TSprite.AddDrawList(Sprite: TSprite);
  296.  
  297.   function CompareInt(i1, i2: Integer): Integer;
  298.   begin
  299.     if i1<i2 then
  300.       Result := -1
  301.     else if i1>i2 then
  302.       Result := 1
  303.     else
  304.       Result := 0;
  305.   end;
  306.  
  307. var
  308.   L, H, I, C: Integer;
  309. begin
  310.   L := 0;
  311.   H := FDrawList.Count - 1;
  312.   while L <= H do
  313.   begin
  314.     I := (L + H) div 2;
  315.     C := CompareInt(TSprite(FDrawList[I]).Z, Sprite.Z);
  316.     if C < 0 then L := I + 1 else
  317.       H := I - 1;
  318.   end;
  319.   FDrawList.Insert(L, Sprite);
  320. end;
  321.  
  322. procedure TSprite.Clear;
  323. begin
  324.   while Count>0 do
  325.     Items[Count-1].Free;
  326. end;
  327.  
  328. function TSprite.Collision: Integer;
  329. var
  330.   i: Integer;
  331. begin
  332.   Result := 0;
  333.   if (FEngine<>nil) and (not FDeaded) and (Collisioned) then
  334.   begin
  335.     with FEngine do
  336.     begin
  337.       FCollisionCount := 0;
  338.       FCollisionDone := False;
  339.       FCollisionRect := Self.BoundsRect;
  340.       FCollisionSprite := Self;
  341.  
  342.       for i:=0 to Count-1 do
  343.         Items[i].Collision2;
  344.  
  345.       Result := FCollisionCount;
  346.     end;
  347.   end;
  348. end;
  349.  
  350. procedure TSprite.Collision2;
  351. var
  352.   i: Integer;
  353. begin
  354.   if Collisioned then
  355.   begin
  356.     if (Self<>FEngine.FCollisionSprite) and OverlapRect(BoundsRect, FEngine.FCollisionRect) and
  357.       FEngine.FCollisionSprite.TestCollision(Self) and TestCollision(FEngine.FCollisionSprite) then
  358.     begin
  359.       Inc(FEngine.FCollisionCount);
  360.       FEngine.FCollisionSprite.DoCollision(Self, FEngine.FCollisionDone);
  361.       if (not FEngine.FCollisionSprite.Collisioned) or (FEngine.FCollisionSprite.FDeaded) then
  362.       begin
  363.         FEngine.FCollisionDone := True;
  364.       end;
  365.     end;
  366.     if FEngine.FCollisionDone then Exit;
  367.     for i:=0 to Count-1 do
  368.       Items[i].Collision2;
  369.   end;
  370. end;
  371.  
  372. procedure TSprite.Dead;
  373. begin
  374.   if (FEngine<>nil) and (not FDeaded) then
  375.   begin
  376.     FDeaded := True;
  377.     FEngine.FDeadList.Add(Self);
  378.   end;
  379. end;
  380.  
  381. procedure TSprite.DoMove;
  382. begin
  383. end;
  384.  
  385. procedure TSprite.DoDraw;
  386. begin
  387. end;
  388.  
  389. procedure TSprite.DoCollision(Sprite: TSprite; var Done: Boolean);
  390. begin
  391. end;
  392.  
  393. function TSprite.TestCollision(Sprite: TSprite): Boolean;
  394. begin
  395.   Result := True;
  396. end;
  397.  
  398. procedure TSprite.Move(MoveCount: Integer);
  399. var
  400.   i: Integer;
  401. begin
  402.   if FMoved then
  403.   begin
  404.     DoMove(MoveCount);
  405.     for i:=0 to Count-1 do
  406.       Items[i].Move(MoveCount);
  407.   end;
  408. end;
  409.  
  410. procedure TSprite.Draw;
  411. var
  412.   i: Integer;
  413. begin
  414.   if FVisible then
  415.   begin
  416.     if FEngine<>nil then
  417.     begin
  418.       if OverlapRect(FEngine.FSurfaceRect, BoundsRect) then
  419.       begin
  420.         DoDraw;
  421.         Inc(FEngine.FDrawCount);
  422.       end;
  423.     end;
  424.  
  425.     if FDrawList<>nil then
  426.     begin
  427.       for i:=0 to FDrawList.Count-1 do
  428.         TSprite(FDrawList[i]).Draw;
  429.     end;
  430.   end;
  431. end;
  432.  
  433. function TSprite.GetBoundsRect: TRect;
  434. begin
  435.   Result := Bounds(Trunc(WorldX), Trunc(WorldY), Width, Height);
  436. end;
  437.  
  438. function TSprite.GetClientRect: TRect;
  439. begin
  440.   Result := Bounds(0, 0, Width, Height);
  441. end;
  442.  
  443. function TSprite.GetCount: Integer;
  444. begin
  445.   if FList<>nil then
  446.     Result := FList.Count
  447.   else
  448.     Result := 0;
  449. end;
  450.  
  451. function TSprite.GetItem(Index: Integer): TSprite;
  452. begin
  453.   if FList<>nil then
  454.     Result := FList[Index]
  455.   else
  456.     raise ESpriteError.CreateFmt(SListIndexError, [Index]);
  457. end;           
  458.  
  459. function TSprite.GetWorldX: Double;
  460. begin
  461.   if Parent<>nil then
  462.     Result := Parent.WorldX+FX
  463.   else
  464.     Result := FX;
  465. end;
  466.  
  467. function TSprite.GetWorldY: Double;
  468. begin
  469.   if Parent<>nil then
  470.     Result := Parent.WorldY+FY
  471.   else
  472.     Result := FY;
  473. end;
  474.  
  475. procedure TSprite.SetZ(Value: Integer);
  476. begin
  477.   if FZ<>Value then
  478.   begin
  479.     FZ := Value;
  480.     if Parent<>nil then
  481.     begin
  482.       Parent.FDrawList.Remove(Self);
  483.       Parent.AddDrawList(Self);
  484.     end;
  485.   end;
  486. end;
  487.  
  488. {  TImageSprite  }
  489.  
  490. constructor TImageSprite.Create(AParent: TSprite);
  491. begin
  492.   inherited Create(AParent);
  493.   FTransparent := True;
  494. end;
  495.  
  496. function TImageSprite.GetBoundsRect: TRect;
  497. var
  498.   dx, dy: Integer;
  499. begin
  500.   dx := Trunc(WorldX);
  501.   dy := Trunc(WorldY);
  502.   if FTile then
  503.   begin
  504.     dx := Mod2(dx, FEngine.SurfaceRect.Right+Width);
  505.     dy := Mod2(dy, FEngine.SurfaceRect.Bottom+Height);
  506.  
  507.     if dx>FEngine.SurfaceRect.Right then
  508.       dx := (dx-FEngine.SurfaceRect.Right)-Width;
  509.  
  510.     if dy>FEngine.SurfaceRect.Bottom then
  511.       dy := (dy-FEngine.SurfaceRect.Bottom)-Height;
  512.   end;
  513.  
  514.   Result := Bounds(dx, dy, Width, Height);
  515. end;
  516.  
  517. procedure TImageSprite.DoMove(MoveCount: Integer);
  518. begin
  519.   FAnimPos := FAnimPos + FAnimSpeed*MoveCount;
  520.  
  521.   if FAnimLooped then
  522.   begin
  523.     if FAnimCount>0 then
  524.       FAnimPos := Mod2f(FAnimPos, FAnimCount)
  525.     else
  526.       FAnimPos := 0;
  527.   end else
  528.   begin
  529.     if FAnimPos>=FAnimCount then
  530.     begin
  531.       FAnimPos := FAnimCount-1;
  532.       FAnimSpeed := 0;
  533.     end;
  534.     if FAnimPos<0 then
  535.     begin
  536.       FAnimPos := 0;
  537.       FAnimSpeed := 0;
  538.     end;
  539.   end;
  540. end;
  541.  
  542. function TImageSprite.GetDrawImageIndex: Integer;
  543. begin
  544.   Result := FAnimStart+Trunc(FAnimPos);
  545. end;
  546.  
  547. function TImageSprite.GetDrawRect: TRect;
  548. begin
  549.   Result := BoundsRect;
  550.   OffsetRect(Result, (Width-Image.Width) div 2, (Height-Image.Height) div 2);
  551. end;
  552.  
  553. procedure TImageSprite.DoDraw;
  554. var
  555.   ImageIndex: Integer;
  556.   r: TRect;
  557. begin
  558.   ImageIndex := GetDrawImageIndex;
  559.   r := GetDrawRect;
  560.   Image.Draw(FEngine.Surface, r.Left, r.Top, ImageIndex);
  561. end;
  562.  
  563. function ImageCollisionTest(suf1, suf2: TDirectDrawSurface; const rect1, rect2: TRect;
  564.   x1,y1,x2,y2: Integer; DoPixelCheck: Boolean): Boolean;
  565.  
  566.   function ClipRect(var DestRect: TRect; const DestRect2: TRect): Boolean;
  567.   begin
  568.     with DestRect do
  569.     begin
  570.       Left := Max(Left, DestRect2.Left);
  571.       Right := Min(Right, DestRect2.Right);
  572.       Top := Max(Top, DestRect2.Top);
  573.       Bottom := Min(Bottom, DestRect2.Bottom);
  574.  
  575.       Result := (Left < Right) and (Top < Bottom);
  576.     end;
  577.   end;
  578.  
  579. type
  580.   PRGB = ^TRGB;
  581.   TRGB = packed record
  582.     R, G, B: Byte;
  583.   end;
  584. var
  585.   ddsd1, ddsd2: DDSURFACEDESC;
  586.   r1, r2: TRect;
  587.   tc1, tc2: DWORD;
  588.   x, y, w, h: Integer;
  589.   P1, P2: Pointer;
  590. begin
  591.   r1 := rect1;
  592.   with rect2 do r2 := Bounds(x2-x1, y2-y1, Right-Left, Bottom-Top);
  593.  
  594.   Result := OverlapRect(r1, r2);
  595.  
  596.   if (suf1=nil) or (suf2=nil) then Exit;
  597.  
  598.   if DoPixelCheck and Result then
  599.   begin
  600.     {  Get Overlapping rectangle  }
  601.     with r1 do r1 := Bounds(Max(x2-x1, 0), Max(y2-y1, 0), Right-Left, Bottom-Top);
  602.     with r2 do r2 := Bounds(Max(x1-x2, 0), Max(y1-y2, 0), Right-Left, Bottom-Top);
  603.  
  604.     ClipRect(r1, rect1);
  605.     ClipRect(r2, rect2);
  606.  
  607.     w := Min(r1.Right-r1.Left, r2.Right-r2.Left);
  608.     h := Min(r1.Bottom-r1.Top, r2.Bottom-r2.Top);
  609.  
  610.     ClipRect(r1, bounds(r1.Left, r1.Top, w, h));
  611.     ClipRect(r2, bounds(r2.Left, r2.Top, w, h));
  612.                                
  613.     {  Pixel check !!!  }
  614.     ddsd1.dwSize := SizeOf(ddsd1);
  615.     if suf1.Lock(r1, ddsd1) then
  616.     begin
  617.       try
  618.         ddsd2.dwSize := SizeOf(ddsd2);
  619.         if (suf1=suf2) or suf2.Lock(r2, ddsd2) then
  620.         begin
  621.           try
  622.             if suf1=suf2 then ddsd2 := ddsd1;
  623.             if ddsd1.ddpfPixelFormat.dwRGBBitCount<>ddsd2.ddpfPixelFormat.dwRGBBitCount then Exit;
  624.                                      
  625.             {  Get transparent color  }
  626.             tc1 := ddsd1.ddckCKSrcBlt.dwColorSpaceLowValue;
  627.             tc2 := ddsd2.ddckCKSrcBlt.dwColorSpaceLowValue;
  628.  
  629.             case ddsd1.ddpfPixelFormat.dwRGBBitCount of
  630.               8 : begin
  631.                     for y:=0 to h-1 do
  632.                     begin
  633.                       P1 := Pointer(Integer(ddsd1.lpSurface)+y*ddsd1.lPitch);
  634.                       P2 := Pointer(Integer(ddsd1.lpSurface)+y*ddsd2.lPitch);
  635.                       for x:=0 to w-1 do
  636.                       begin
  637.                         if (PByte(P1)^<>tc1) and (PByte(P2)^<>tc2) then Exit;
  638.                         Inc(PByte(P1));
  639.                         Inc(PByte(P2));
  640.                       end;
  641.                     end;
  642.                   end;
  643.               16: begin
  644.                     for y:=0 to h-1 do
  645.                     begin
  646.                       P1 := Pointer(Integer(ddsd1.lpSurface)+y*ddsd1.lPitch);
  647.                       P2 := Pointer(Integer(ddsd1.lpSurface)+y*ddsd2.lPitch);
  648.                       for x:=0 to w-1 do
  649.                       begin
  650.                         if (PWord(P1)^<>tc1) and (PWord(P2)^<>tc2) then Exit;
  651.                         Inc(PWord(P1));
  652.                         Inc(PWord(P2));
  653.                       end;
  654.                     end;
  655.                   end;
  656.               24: begin
  657.                     for y:=0 to h-1 do
  658.                     begin
  659.                       P1 := Pointer(Integer(ddsd1.lpSurface)+y*ddsd1.lPitch);
  660.                       P2 := Pointer(Integer(ddsd1.lpSurface)+y*ddsd2.lPitch);
  661.                       for x:=0 to w-1 do
  662.                       begin        
  663.                         with PRGB(P1)^ do if (R shl 16) or (G shl 8) or B<>tc1 then Exit;
  664.                         with PRGB(P2)^ do if (R shl 16) or (G shl 8) or B<>tc2 then Exit;
  665.                         Inc(PRGB(P1));
  666.                         Inc(PRGB(P2));
  667.                       end;
  668.                     end;
  669.                   end;
  670.               32: begin
  671.                     for y:=0 to h-1 do
  672.                     begin
  673.                       P1 := Pointer(Integer(ddsd1.lpSurface)+y*ddsd1.lPitch);
  674.                       P2 := Pointer(Integer(ddsd1.lpSurface)+y*ddsd2.lPitch);
  675.                       for x:=0 to w-1 do
  676.                       begin
  677.                         if (PDWORD(P1)^<>tc1) and (PDWORD(P2)^<>tc2) then Exit;
  678.                         Inc(PDWORD(P1));
  679.                         Inc(PDWORD(P2));
  680.                       end;
  681.                     end;
  682.                   end;
  683.             end;
  684.           finally
  685.             if suf1<>suf2 then suf2.UnLock(ddsd2.lpSurface);
  686.           end;
  687.         end;
  688.       finally
  689.         suf1.UnLock(ddsd1.lpSurface);
  690.       end;
  691.     end;
  692.  
  693.     Result := False;
  694.   end;
  695. end;
  696.  
  697. function TImageSprite.TestCollision(Sprite: TSprite): Boolean;
  698. var
  699.   img1, img2: Integer;
  700.   b1, b2: TRect;
  701. begin
  702.   if (Sprite is TImageSprite) and FPixelCheck then
  703.   begin
  704.     b1 := GetDrawRect;
  705.     b2 := TImageSprite(Sprite).GetDrawRect;
  706.  
  707.     img1 := GetDrawImageIndex;
  708.     img2 := TImageSprite(Sprite).GetDrawImageIndex;
  709.  
  710.     Result := ImageCollisionTest(Image.PatternSurfaces[img1], TImageSprite(Sprite).Image.PatternSurfaces[img2],
  711.       Image.PatternRects[img1], TImageSprite(Sprite).Image.PatternRects[img2],
  712.       b1.Left, b1.Top, b2.Left, b2.Top, True);
  713.   end else
  714.     Result := inherited TestCollision(Sprite);
  715. end;
  716.  
  717. {  TImageSpriteEx  }
  718.  
  719. constructor TImageSpriteEx.Create(AParent: TSprite);
  720. begin
  721.   inherited Create(AParent);
  722.   FAlpha := 255;
  723. end;
  724.  
  725. procedure TImageSpriteEx.DoDraw;
  726. var
  727.   r: TRect;
  728. begin
  729.   r := Bounds(Trunc(WorldX), Trunc(WorldY), Width, Height);
  730.  
  731.   if FAngle and $FF=0 then
  732.   begin
  733.     if FAlpha<255 then
  734.     begin
  735.       Image.DrawAlpha(FEngine.FSurface, r, GetDrawImageIndex, FAlpha)
  736.     end else
  737.     begin
  738.       Image.StretchDraw(FEngine.FSurface, r, GetDrawImageIndex);
  739.     end;
  740.   end else
  741.   begin
  742.     if FAlpha<255 then
  743.     begin
  744.       Image.DrawRotateAlpha(FEngine.FSurface, (r.Left+r.Right) div 2, (r.Top+r.Bottom) div 2,
  745.         Width, Height, GetDrawImageIndex, 0.5, 0.5, FAngle, FAlpha)
  746.     end else
  747.     begin
  748.       Image.DrawRotate(FEngine.FSurface, (r.Left+r.Right) div 2, (r.Top+r.Bottom) div 2,
  749.         Width, Height, GetDrawImageIndex, 0.5, 0.5, FAngle)
  750.     end;
  751.   end;
  752. end;
  753.  
  754. function TImageSpriteEx.GetBoundsRect: TRect;
  755. begin
  756.   Result := FEngine.SurfaceRect;
  757. end;
  758.  
  759. function TImageSpriteEx.TestCollision(Sprite: TSprite): Boolean;
  760. begin
  761.   if Sprite is TImageSpriteEx then
  762.   begin
  763.     Result := OverlapRect(Bounds(Trunc(Sprite.WorldX), Trunc(Sprite.WorldY), Sprite.Width, Sprite.Height),
  764.       Bounds(Trunc(WorldX), Trunc(WorldY), Width, Height));
  765.   end else
  766.   begin
  767.     Result := OverlapRect(Sprite.BoundsRect, Bounds(Trunc(WorldX), Trunc(WorldY), Width, Height));
  768.   end;
  769. end;
  770.  
  771. {  TBackgroundSprite  }
  772.  
  773. constructor TBackgroundSprite.Create(AParent: TSprite);
  774. begin
  775.   inherited Create(AParent);
  776.   Collisioned := False;
  777. end;
  778.  
  779. destructor TBackgroundSprite.Destroy;
  780. begin
  781.   SetMapSize(0, 0);
  782.   inherited Destroy;
  783. end;
  784.  
  785. procedure TBackgroundSprite.DoDraw;
  786. var
  787.   _x, _y, cx, cy, cx2, cy2, c, ChipWidth, ChipHeight: Integer;
  788.   StartX, StartY, EndX, EndY, StartX_, StartY_, OfsX, OfsY, dWidth, dHeight: Integer;
  789.   r: TRect;
  790. begin
  791.   if Image=nil then Exit;
  792.  
  793.   if (FMapWidth<=0) or (FMapHeight<=0) then Exit;
  794.  
  795.   r := Image.PatternRects[0];
  796.   ChipWidth := r.Right-r.Left;
  797.   ChipHeight := r.Bottom-r.Top;
  798.  
  799.   dWidth := (FEngine.SurfaceRect.Right+ChipWidth) div ChipWidth+1;
  800.   dHeight := (FEngine.SurfaceRect.Bottom+ChipHeight) div ChipHeight+1;
  801.  
  802.   _x := Trunc(WorldX);
  803.   _y := Trunc(WorldY);
  804.  
  805.   OfsX := _x mod ChipWidth;
  806.   OfsY := _y mod ChipHeight;
  807.  
  808.   StartX := _x div ChipWidth;
  809.   StartX_ := 0;
  810.  
  811.   if StartX<0 then
  812.   begin
  813.     StartX_ := -StartX;
  814.     StartX := 0;
  815.   end;
  816.  
  817.   StartY := _y div ChipHeight;
  818.   StartY_ := 0;
  819.  
  820.   if StartY<0 then
  821.   begin
  822.     StartY_ := -StartY;
  823.     StartY := 0;
  824.   end;
  825.  
  826.   EndX := Min(StartX+FMapWidth-StartX_, dWidth);
  827.   EndY := Min(StartY+FMapHeight-StartY_, dHeight);
  828.  
  829.   if FTile then
  830.   begin
  831.     for cy:=-1 to dHeight do
  832.     begin
  833.       cy2 := Mod2((cy-StartY+StartY_), FMapHeight);
  834.       for cx:=-1 to dWidth do
  835.       begin
  836.         cx2 := Mod2((cx-StartX+StartX_), FMapWidth);
  837.         c := Chips[cx2, cy2];
  838.         if c>=0 then
  839.           Image.Draw(FEngine.Surface, cx*ChipWidth+OfsX, cy*ChipHeight+OfsY, c);
  840.       end;
  841.     end;
  842.   end else
  843.   begin
  844.     for cy:=StartY to EndY-1 do
  845.       for cx:=StartX to EndX-1 do
  846.       begin
  847.         c := Chips[cx-StartX+StartX_, cy-StartY+StartY_];
  848.         if c>=0 then
  849.           Image.Draw(FEngine.Surface, cx*ChipWidth+OfsX, cy*ChipHeight+OfsY, c);
  850.       end;
  851.   end;
  852. end;
  853.  
  854. function TBackgroundSprite.TestCollision(Sprite: TSprite): Boolean;
  855. var
  856.   b, b1, b2: TRect;
  857.   cx, cy, ChipWidth, ChipHeight: Integer;
  858.   r: TRect;
  859. begin
  860.   Result := True;
  861.   if Image=nil then Exit;
  862.   if (FMapWidth<=0) or (FMapHeight<=0) then Exit;
  863.  
  864.   r := Image.PatternRects[0];
  865.   ChipWidth := r.Right-r.Left;
  866.   ChipHeight := r.Bottom-r.Top;
  867.  
  868.  
  869.  
  870.   b1 := Sprite.BoundsRect;
  871.   b2 := BoundsRect;
  872.  
  873.   IntersectRect(b, b1, b2);
  874.  
  875.   OffsetRect(b, -Trunc(WorldX), -Trunc(WorldY));
  876.   OffsetRect(b1, -Trunc(WorldX), -Trunc(WorldY));
  877.  
  878.   for cy:=(b.Top-ChipHeight+1) div ChipHeight to b.Bottom div ChipHeight do
  879.     for cx:=(b.Left-ChipWidth+1) div ChipWidth to b.Right div ChipWidth do
  880.       if CollisionMap[Mod2(cx, MapWidth), Mod2(cy, MapHeight)] then
  881.       begin
  882.         if OverlapRect(Bounds(cx*ChipWidth, cy*ChipHeight, ChipWidth, ChipHeight), b1) then Exit;
  883.       end;
  884.  
  885.   Result := False;
  886. end;
  887.  
  888. function TBackgroundSprite.GetChip(X, Y: Integer): Integer;
  889. begin
  890.   if (X>=0) and (X<FMapWidth) and (Y>=0) and (Y<FMapHeight) then
  891.     Result := PInteger(Integer(FMap)+(Y*FMapWidth+X)*SizeOf(Integer))^
  892.   else
  893.     Result := -1;
  894. end;
  895.  
  896. type
  897.   PBoolean = ^Boolean;
  898.  
  899. function TBackgroundSprite.GetCollisionMapItem(X, Y: Integer): Boolean;
  900. begin
  901.   if (X>=0) and (X<FMapWidth) and (Y>=0) and (Y<FMapHeight) then
  902.     Result := PBoolean(Integer(FCollisionMap)+(Y*FMapWidth+X)*SizeOf(Boolean))^
  903.   else
  904.     Result := False;
  905. end;
  906.  
  907. function TBackgroundSprite.GetBoundsRect: TRect;
  908. begin
  909.   if FTile then
  910.     Result := FEngine.SurfaceRect
  911.   else
  912.   begin
  913.     if Image<>nil then
  914.       Result := Bounds(Trunc(WorldX), Trunc(WorldY),
  915.         Image.Width*FMapWidth, Image.Height*FMapHeight)
  916.     else
  917.       Result := Rect(0, 0, 0, 0);
  918.   end;
  919. end;
  920.  
  921. procedure TBackgroundSprite.SetChip(X, Y: Integer; Value: Integer);
  922. begin
  923.   if (X>=0) and (X<FMapWidth) and (Y>=0) and (Y<FMapHeight) then
  924.     PInteger(Integer(FMap)+(Y*FMapWidth+X)*SizeOf(Integer))^ := Value;
  925. end;
  926.  
  927. procedure TBackgroundSprite.SetCollisionMapItem(X, Y: Integer; Value: Boolean);
  928. begin
  929.   if (X>=0) and (X<FMapWidth) and (Y>=0) and (Y<FMapHeight) then
  930.     PBoolean(Integer(FCollisionMap)+(Y*FMapWidth+X)*SizeOf(Boolean))^ := Value;
  931. end;
  932.  
  933. procedure TBackgroundSprite.SetMapHeight(Value: Integer);
  934. begin
  935.   SetMapSize(FMapWidth, Value);
  936. end;
  937.  
  938. procedure TBackgroundSprite.SetMapWidth(Value: Integer);
  939. begin
  940.   SetMapSize(Value, FMapHeight);
  941. end;
  942.  
  943. procedure TBackgroundSprite.SetMapSize(AMapWidth, AMapHeight: Integer);
  944. begin
  945.   if (FMapWidth<>AMapWidth) or (FMapHeight<>AMapHeight) then
  946.   begin
  947.     if (AMapWidth<=0) or (AMapHeight<=0) then
  948.     begin
  949.       AMapWidth := 0;
  950.       AMapHeight := 0;
  951.     end;
  952.     FMapWidth := AMapWidth;
  953.     FMapHeight := AMapHeight;
  954.     ReAllocMem(FMap, FMapWidth*FMapHeight*SizeOf(Integer));
  955.     FillChar(FMap^, FMapWidth*FMapHeight*SizeOf(Integer), 0);
  956.  
  957.     ReAllocMem(FCollisionMap, FMapWidth*FMapHeight*SizeOf(Boolean));
  958.     FillChar(FCollisionMap^, FMapWidth*FMapHeight*SizeOf(Boolean), 1);
  959.   end;
  960. end;
  961.  
  962. {  TSpriteEngine  }
  963.  
  964. constructor TSpriteEngine.Create(AParent: TSprite);
  965. begin
  966.   inherited Create(AParent);
  967.   FDeadList := TList.Create;
  968. end;
  969.  
  970. destructor TSpriteEngine.Destroy;
  971. begin
  972.   FDeadList.Free;
  973.   inherited Destroy;
  974. end;
  975.  
  976. procedure TSpriteEngine.Dead;
  977. begin
  978.   while FDeadList.Count>0 do
  979.     TSprite(FDeadList[FDeadList.Count-1]).Free;
  980. end;
  981.  
  982. procedure TSpriteEngine.Draw;
  983. begin
  984.   FDrawCount := 0;
  985.   inherited Draw;
  986. end;
  987.  
  988. procedure TSpriteEngine.SetSurface(Value: TDirectDrawSurface);
  989. begin
  990.   FSurface := Value;
  991.   if FSurface<>nil then
  992.   begin
  993.     FSurfaceRect := Surface.ClientRect;
  994.     Width := FSurfaceRect.Right-FSurfaceRect.Left;
  995.     Height := FSurfaceRect.Bottom-FSurfaceRect.Top;
  996.   end;
  997. end;
  998.  
  999. {  TCustomDXSpriteEngine  }
  1000.  
  1001. constructor TCustomDXSpriteEngine.Create(AOnwer: TComponent);
  1002. begin
  1003.   inherited Create(AOnwer);
  1004.   FEngine := TSpriteEngine.Create(nil);
  1005. end;
  1006.  
  1007. destructor TCustomDXSpriteEngine.Destroy;
  1008. begin                     
  1009.   FEngine.Free;
  1010.   inherited Destroy;
  1011. end;
  1012.  
  1013. procedure TCustomDXSpriteEngine.Notification(AComponent: TComponent;
  1014.   Operation: TOperation);
  1015. begin
  1016.   inherited Notification(AComponent, Operation);
  1017.   if (Operation=opRemove) and (DXDraw=AComponent) then
  1018.     DXDraw := nil;
  1019. end;
  1020.  
  1021. procedure TCustomDXSpriteEngine.Dead;
  1022. begin
  1023.   FEngine.Dead;
  1024. end;
  1025.  
  1026. procedure TCustomDXSpriteEngine.Draw;
  1027. begin
  1028.   if (FDXDraw<>nil) and (FDXDraw.Initialized) then
  1029.     FEngine.Draw;
  1030. end;
  1031.  
  1032. procedure TCustomDXSpriteEngine.Move(MoveCount: Integer);
  1033. begin
  1034.   FEngine.Move(MoveCount);
  1035. end;
  1036.  
  1037. procedure TCustomDXSpriteEngine.DXDrawNotifyEvent(Sender: TCustomDXDraw;
  1038.   NotifyType: TDXDrawNotifyType);
  1039. begin
  1040.   case NotifyType of
  1041.     dxntDestroying: DXDraw := nil;
  1042.     dxntInitialize: FEngine.Surface := Sender.Surface;
  1043.     dxntFinalize  : FEngine.Surface := nil;
  1044.   end;
  1045. end;
  1046.  
  1047. procedure TCustomDXSpriteEngine.SetDXDraw(Value: TCustomDXDraw);
  1048. begin
  1049.   if FDXDraw<>nil then
  1050.     FDXDraw.UnRegisterNotifyEvent(DXDrawNotifyEvent);
  1051.  
  1052.   FDXDraw := Value;
  1053.  
  1054.   if FDXDraw<>nil then
  1055.     FDXDraw.RegisterNotifyEvent(DXDrawNotifyEvent);
  1056. end;
  1057.  
  1058. end.
  1059.