|
root / delphi / HADP_Mar1997 / fishtank / factory / Bio_Fish.pas Created by zope. Last modified 2004-07-15 01:38:33. |
| Filename | Bio_Fish.pas |
|---|---|
| Size | 8778 |
| Content-type | text/plain |
| |
//==============================================================================
// Unit: Bio_Fish
//
// Purpose: Declare TBiolifeFish, a concrete "default" fish which derives its
// properties from the BioLife table.
//
// Copyright: 1997, Palladion Software
//==============================================================================
unit Bio_Fish;
interface
uses
SysUtils,
Classes,
Graphics,
ExtCtrls,
Fish,
DBCtrls;
type
//----------------------------------------------------------------------------
// Class: TBiolifeFish
//
// Purpose: Concrete fish class, deriving all properties (except speed) from
// the BioLife table entry for the same name.
//
// Note: This class uses the GOF pattern "Flyweight" for sharing
// "specific" information (common name, bitmap, etc.).
//----------------------------------------------------------------------------
TBiolifeFish = class( TFish )
private
FTableIndex : integer;
FHorizontalSpeed : integer;
FVerticalSpeed : integer;
protected
// Implement inherited abstract methods.
function GetCommonName : string; override;
function GetScientificName : string; override;
function GetWidth : integer; override;
function GetHeight : integer; override;
function GetBitmap : TBitmap; override;
function GetAsString : string; override;
// Property implementation methods.
function GetSpeciesId : integer;
public
constructor Create( aSpeciesId : integer );
procedure Swim( var X : integer; var Y : integer;
maxX, maxY : integer ); override;
property SpeciesId : integer
read GetSpeciesId;
function Clone : TFish; override;
end;
function BiolifeFish_Builder( aPersistentState : string ) : TFish;
implementation
uses
DB,
DBTables;
type
//----------------------------------------------------------------------------
// Cache entry for shared "specific" data
//----------------------------------------------------------------------------
TSpeciesRecord = class
SpeciesId : integer;
CommonName : string;
ScientificName : string;
Height : integer;
Width : integer;
Image : TImage;
destructor Destroy;
end;
destructor TSpeciesRecord.Destroy;
begin
Image.Free;
end;
var
//----------------------------------------------------------------------------
// Cache for shared "specific" data, indexed by speciesId.
//----------------------------------------------------------------------------
TheSpeciesList : TStringList;
//----------------------------------------------------------------------------
// Query for looking up shared "specific" data, parameterized by speciesId.
//----------------------------------------------------------------------------
qrySpecies : TQuery;
dtsSpecies : TDataSource;
imgGraphic : TDBImage;
//------------------------------------------------------------------------------
// TBiolifeFish implementation.
//------------------------------------------------------------------------------
constructor TBiolifeFish.Create( aSpeciesId : integer );
var
strSpeciesId : string;
specRec : TSpeciesRecord;
gf : TGraphicField;
ms : TMemoryStream;
begin
strSpeciesId := IntToStr( aSpeciesId );
if not TheSpeciesList.Find( strSpeciesId, FTableIndex ) then
begin
specRec := TSpeciesRecord.Create;
try
with specRec, qrySpecies do
begin
Close;
Params[0].AsInteger := aSpeciesId;
Open;
if ( RecordCount <> 1 ) then
raise EFishError.CreateFmt( 'Invalid species id: %d',
[ aSpeciesid ] );
SpeciesId := aSpeciesId;
CommonName := FieldByName( 'Common_Name' ).AsString;
ScientificName := FieldByName( 'Species Name' ).AsString;
Width := FieldByName( 'Length (cm)' ).AsInteger;
Image := TImage.Create( Nil );
Image.Picture.Assign( imgGraphic.Picture );
(*
gf := FieldByName( 'Graphic' ) as TGraphicField;
ms := TMemoryStream.Create;
gf.SaveToStream( ms );
Image.Picture.Bitmap.LoadFromStream( ms );
ms.Free;
*)
Height := Trunc( Image.Height * Width / Image.Width );
Image.Height := Height;
Image.Width := Width;
Close;
end;
except
on E : Exception do
begin
specRec.Free;
raise;
end;
end;
FTableIndex := TheSpeciesList.AddObject( strSpeciesId, specRec );
end;
//
// We lack information for setting "real" speeds here.
//
FHorizontalSpeed := Random( 11 ) - 5;
FVerticalSpeed := Random( 11 ) - 5;
end;
function TBiolifeFish.GetCommonName : string;
begin
Result := TSpeciesRecord(
TheSpeciesList.Objects[ FTableIndex ] ).CommonName;
end;
function TBiolifeFish.GetScientificName : string;
begin
Result := TSpeciesRecord(
TheSpeciesList.Objects[ FTableIndex ] ).ScientificName;
end;
function TBiolifeFish.GetWidth : integer;
begin
Result := TSpeciesRecord( TheSpeciesList.Objects[ FTableIndex ] ).Width;
end;
function TBiolifeFish.GetHeight : integer;
begin
Result := TSpeciesRecord( TheSpeciesList.Objects[ FTableIndex ] ).Height;
end;
function TBiolifeFish.GetBitmap : TBitmap;
begin
Result := TSpeciesRecord(
TheSpeciesList.Objects[ FTableIndex ] ).Image.Picture.Bitmap;
end;
function TBiolifeFish.GetSpeciesId : integer;
begin
Result := TSpeciesRecord( TheSpeciesList.Objects[ FTableIndex ] ).SpeciesId;
end;
procedure TBiolifeFish.Swim( var X : integer; var Y : integer;
maxX, maxY : integer );
begin
X := X + FHorizontalSpeed;
if ( X <= 0 ) or ( X + Width >= maxX ) or ( Random( 100 ) < 5 ) then
FHorizontalSpeed := - FHorizontalSpeed;
Y := Y + FVerticalSpeed;
if ( Y <= 0 ) or ( Y + Height >= maxY ) or ( Random( 100 ) < 5 ) then
FVerticalSpeed := - FVerticalSpeed;
end;
function TBiolifeFish.Clone : TFish;
begin
Result := TBiolifeFish.Create( FTableIndex );
end;
function TBiolifeFish.GetAsString : string;
begin
Result := IntToStr( SpeciesId ) + ','
+ IntToStr( FHorizontalSpeed ) + ','
+ IntToStr( FVerticalSpeed );
end;
function BiolifeFish_Builder( aPersistentState : string ) : TFish;
var
comma : integer;
aSpeciesId : integer;
bioFish : TBiolifeFish;
begin
comma := Pos( ',', aPersistentState );
if ( comma = 0 ) then
raise EFishError.Create( 'Invalid BiolifeFish entry.' );
aSpeciesId := StrToInt( Copy( aPersistentState, 1, comma - 1 ) );
bioFish := TBiolifeFish.Create( aSpeciesId );
Delete( aPersistentState, 1, comma );
comma := Pos( ',', aPersistentState );
if ( comma = 0 ) then
begin
bioFish.Free;
raise EFishError.Create( 'Invalid BiolifeFish entry.' );
end;
with bioFish do
begin
FHorizontalSpeed := StrToInt( Copy( aPersistentState, 1, comma-1 ) );
FVerticalSpeed := StrToInt( Copy( aPersistentState, comma+1, 999 ) );
end;
Result := bioFish;
end;
procedure Setup;
begin
TheSpeciesList := TStringList.Create;
qrySpecies := TQuery.Create( nil );
with qrySpecies do
begin
DatabaseName := 'DBDEMOS';
SQL.Add( 'SELECT * FROM BioLife b' );
SQL.Add( ' WHERE b."Species No" = :SpeciesId' );
Prepare;
end;
dtsSpecies := TDataSource.Create( nil );
dtsSpecies.Dataset := qrySpecies;
imgGraphic := TDBImage.Create( nil );
imgGraphic.Datasource := dtsSpecies;
imgGraphic.DataField := 'Graphic';
end;
//------------------------------------------------------------------------------
// Flush the cache and free it on unload.
//------------------------------------------------------------------------------
procedure Cleanup;
var
iSpecies : integer;
specRec : TSpeciesRecord;
begin
imgGraphic.Free;
dtsSpecies.Free;
qrySpecies.Free;
for iSpecies := TheSpeciesList.Count - 1 downto 0 do
begin
specRec := TSpeciesRecord( TheSpeciesList.Objects[ iSpecies ] );
TheSpeciesList.Objects[ iSpecies ] := Nil;
specRec.Free;
end;
TheSpeciesList.Free;
end;
initialization
Setup;
TFish.RegisterBuilder( TBiolifeFish.ClassName, @BiolifeFish_Builder );
finalization
Cleanup;
end.