{------------------------------------------------------------------------------} { Unit Name: sprite Purpose : The basic class for sprites Author : Vesa Lappalainen Date : 03.11.1999 Changed : 5.11.1999 - Avaruuteen Spriteille oma lista, jossa on kaikki avaruudessa olevat spritet - Törmäysten tunnistaminen ja reagointi - lisätty vielä törmäysten takia oma lista : FDead, johon siirreään ne Spritet, jotka ovat TSpriteSpace.UnJoin -metodilla ilmoittautuneet kuolevansa. Lista tyhjennetään kun jokainen Sprite on saanut mahdollisuuden reagoida toisen kanssa. - vastaavasti jokainen sprite pitää liitää Sprite-listaan Join-metodilla (TSprite.Create-tekee tämän). 14.11.1999 - äly (TBrain). Jokaisella TSpritella voi olla vain yksi äly ja kukin äly voi ohjata vain yhtä spriteä. Sprite tulee toimeen ilmankin älyä Äly saa ensin tarkistaa törmäyksen, jos ei tarkista, niin sitten itse sprite saa tehdä homman. Samoin React menee ensin älylle, jos ei käsitellä, niin Sprite saa käsitellä ToDo : - kannattaisi tehdä mielluumin ensin suorakaide ja piste tyypit ja näille operaatiot. Vähenisi nuo joku.x tutkiskelut. - muunnosmatriisin voisi ujuttaa avaruuteen, jolloin mukaan saisi vaikka kolmiulotteisuuden } {------------------------------------------------------------------------------} unit sprite; interface uses Classes,graphics,extctrls; type TSpriteSpace = class; TBrain = class; TSprite = class(TComponent) private Fx: double; Fy: double; Fw: double; Fh: double; FParent : TSpriteSpace; FBrain: TBrain; procedure Setx(const Value: double); procedure Sety(const Value: double); procedure Seth(const Value: double); procedure Setw(const Value: double); function GetParent: TSpriteSpace; function GetIx: integer; function GetIy: integer; procedure SetBrain(const Value: TBrain); function TakeBrain : TBrain; virtual; function GetIh: integer; function GetIw: integer; public constructor Create(AOwner:TComponent); override; destructor Destroy; override; function DoJob : boolean; virtual; function IsHit(sprite:TSprite):boolean; virtual; function React(sprite:TSprite):boolean; virtual; function ReactTo(sprite:TSprite):boolean; virtual; function PaintTo(canvas:TCanvas):boolean; virtual; property Parent : TSpriteSpace read GetParent; property Brain : TBrain read FBrain write SetBrain; published property x:double read Fx write Setx; property y:double read Fy write Sety; property h:double read Fh write Seth; property w:double read Fw write Setw; property ix : integer read GetIx; property iy : integer read GetIy; property iw : integer read GetIw; property ih : integer read GetIh; end; TBrain = class private FOwner: TSprite; procedure SetOwner(const Value: TSprite); public constructor Create(AOwner:TSprite); virtual; destructor Destroy; override; function DoJob : boolean; virtual; function IsHit(sprite:TSprite):boolean; virtual; function React(sprite:TSprite):boolean; virtual; function ReactTo(sprite:TSprite):boolean; virtual; property Owner : TSprite read FOwner write SetOwner; end; TSpriteSpace = class(TPanel) private bitmap : TBitmap; PaintBox : TPaintBox; timer : TTimer; FSprites : TList; FKill : Tlist; FRemove : Tlist; procedure SetInterval(const Value: integer); function GetInterval: integer; function GetRunning: boolean; procedure SetRunning(const Value: boolean); procedure DoTimer(sender: TObject); protected procedure Display; virtual; procedure SpacePaint(sender: TObject); virtual; procedure SpaceResize(sender: TObject); virtual; procedure ReDraw; virtual; public constructor Create(AOwner:TComponent); override; destructor Destroy; override; property Sprites : TList read FSprites; procedure Join(s:TSprite); virtual; procedure UnJoin(s:TSprite; LicenceToKill:boolean); virtual; published property Interval : integer read GetInterval write SetInterval; property Running : boolean read GetRunning write SetRunning; end; implementation { TSprite } constructor TSprite.Create(AOwner: TComponent); begin inherited; x := 0; y := 0; h := 20; w := 20; if ( AOwner is TSpriteSpace ) then begin FParent := TSpriteSpace(AOwner); Parent.Join(self); end; end; destructor TSprite.Destroy; begin if ( Assigned(Brain) ) then Brain.Free; inherited; end; function TSprite.DoJob: boolean; begin Result := false; end; function TSprite.GetIh: integer; begin Result := Round(h); end; function TSprite.GetIw: integer; begin Result := Round(w); end; function TSprite.GetIx: integer; begin Result := Round(x); end; function TSprite.GetIy: integer; begin Result := Round(y); end; function TSprite.GetParent: TSpriteSpace; begin Result := FParent; end; function TSprite.IsHit(sprite: TSprite): boolean; begin Result := false; if ( Brain <> nil ) and ( Brain.IsHit(sprite) ) then begin Result := true; exit; end; if ( x + w < sprite.x ) then exit; if ( x > sprite.x + sprite.w ) then exit; if ( y + h < sprite.y ) then exit; if ( y > sprite.y + sprite.h ) then exit; Result := true; end; function TSprite.PaintTo(canvas: TCanvas): boolean; begin Result := false; end; function TSprite.React(sprite: TSprite): boolean; begin if ( Brain <> nil ) and ( Brain.React(sprite) ) then begin Result := true; exit; end; Result := sprite.ReactTo(self); end; function TSprite.ReactTo(sprite: TSprite): boolean; begin if ( Brain <> nil ) and ( Brain.ReactTo(sprite) ) then begin Result := true; exit; end; Result := false; end; procedure TSprite.SetBrain(const Value: TBrain); begin if ( Brain = value ) then exit; if ( Brain <> nil ) then Brain.Free; // Del old brains FBrain := Value; if ( Brain = nil ) then exit; Brain.Owner := self; end; procedure TSprite.Seth(const Value: double); begin Fh := Value; end; procedure TSprite.Setw(const Value: double); begin Fw := Value; end; procedure TSprite.Setx(const Value: double); begin Fx := Value; end; procedure TSprite.Sety(const Value: double); begin Fy := Value; end; function TSprite.TakeBrain: TBrain; begin Result := Brain; FBrain := nil; end; { TBrain } constructor TBrain.Create(AOwner: TSprite); begin inherited Create; Owner := AOwner; end; destructor TBrain.Destroy; begin if ( Owner <> nil ) then begin Owner.TakeBrain; FOwner := nil; end; inherited; end; function TBrain.DoJob: boolean; begin Result := false; end; function TBrain.IsHit(sprite: TSprite): boolean; begin Result := false; end; function TBrain.React(sprite: TSprite): boolean; begin Result := false; end; function TBrain.ReactTo(sprite: TSprite): boolean; begin Result := false; end; procedure TBrain.SetOwner(const Value: TSprite); begin if ( Owner = Value ) then exit; if ( FOwner <> nil ) then FOwner.TakeBrain; // Old owner looses these brains FOwner := Value; if ( Owner = nil ) then exit; Owner.Brain := self; // Owner take's care of deleting old brains end; { TSpriteSpace } constructor TSpriteSpace.Create(AOwner: TComponent); begin Timer := TTimer.Create(self); inherited; bitmap := TBitmap.Create; PaintBox := TPaintBox.Create(self); FSprites := TList.Create; FKill := TList.Create; FRemove := TList.Create; OnResize := SpaceResize; PaintBox.Parent := self; PaintBox.OnPaint := SpacePaint; Timer.OnTimer := DoTimer; Interval := 50; end; destructor TSpriteSpace.Destroy; begin Sprites.Free; FKill.Free; FRemove.Free; bitmap.Free; PaintBox.Free; Timer.Free; inherited; end; procedure TSpriteSpace.SpaceResize(sender:TObject); begin bitmap.Width := Width; bitmap.Height := Height; Paintbox.Width := Width; Paintbox.Height := Height; ReDraw; end; procedure TSpriteSpace.Display; begin PaintBox.Canvas.Draw(0,0,bitmap); end; procedure TSpriteSpace.ReDraw; var i:integer; s:TSprite; begin bitmap.Canvas.Brush.Color := Color; bitmap.Canvas.Rectangle(0,0,bitmap.Width,bitmap.Height); for i:=0 to Sprites.Count-1 do begin s := Sprites[i]; s.PaintTo(bitmap.canvas); end; Display; end; procedure TSpriteSpace.DoTimer(sender:TObject); var n,i,j:integer; s,s1:TSprite; begin n := 0; for i:=0 to Sprites.Count-1 do begin s := Sprites[i]; if s.DoJob then inc(n); end; if ( n = 0 ) then exit; for i:=0 to Sprites.Count-1 do begin s := Sprites[i]; for j:=i+1 to Sprites.Count-1 do begin s1 := Sprites[j]; if s.IsHit(s1) then s.React(s1); end; end; for i:=0 to FRemove.Count-1 do begin Sprites.Remove(FRemove[i]); end; for i:=0 to FKill.Count-1 do begin s := FKill[i]; s.Free; end; FRemove.Clear; FKill.Clear; ReDraw; end; procedure TSpriteSpace.SpacePaint(sender:TObject); begin Display; end; procedure TSpriteSpace.Setinterval(const Value: integer); begin Timer.Interval := Value; end; function TSpriteSpace.GetInterval: integer; begin Result := Timer.Interval; end; function TSpriteSpace.GetRunning: boolean; begin Result := Timer.Enabled; end; procedure TSpriteSpace.SetRunning(const Value: boolean); begin Timer.Enabled := Value; end; procedure TSpriteSpace.Join(s: TSprite); begin Sprites.Add(s); end; procedure TSpriteSpace.UnJoin(s: TSprite; LicenceToKill:boolean); begin if LicenceToKill and ( FKill.IndexOf(s) < 0 ) then FKill.Add(s); FRemove.Add(s); end; end.