www.pudn.com > 实景(图形)聊天室源代码(绝对高水 准,超酷).zip > Sprite.pas
{ *********************************************************************** }
{ }
{ Copular Chat Client v3.0 Source Code }
{ Sprite Libary Unit }
{ }
{ Copyright (c) 1998-2002 SAF Studio }
{ }
{ Author : Niu Yu Ping }
{ Nickname: DecimalOX }
{ Address : Jilin City China }
{ }
{ QICQ : 103106262 }
{ Homepage: www.safree.com }
{ EMail : decimalox@sohu.com }
{ }
{ *********************************************************************** }
unit Sprite;
interface
uses
DXSprite, DXPath, Tools, DXMap, Graphics, Classes, SysUtils;
type
//Sprite's position
TPathPoint = record
X, Y: Double;
end;
//Sprite's talk structor
TTalk = record
Items,Send, Rece: array[0..9] of string; //sentence, sender, reseiver
Life, Face: array[0..9] of Integer; //display time, face index
OnlyOne: array [0..9] of Boolean; //is alone
Count: Integer; //counter of sentences
end;
//TPlayerSprite structor is designed for sprite on the map
TPlayerSprite = class(TImageSprite)
private
FNewY: Double;
FNewX: Double;
FMoved: Boolean;
FCaption: string;
FDegree: Integer;
FHeadID: Integer;
FAnchorY: Integer;
FAnchorX: Integer;
FIsMe: Boolean;
//obstacle map for every sprite is used to find path
OrgObstacle: array [-MapW div 2..MapW div 2, -MapH div 2..MapH div 2] of Boolean;
//check for obstacle on the appointed area
function HasObstacle(StartX, StartY: Integer): Boolean;
procedure SetNewX(const Value: Double);
procedure SetNewY(const Value: Double);
procedure SetMoved(const Value: Boolean);
procedure SetCaption(const Value: string);
procedure SetDegree(const Value: Integer);
procedure SetHeadID(const Value: Integer);
procedure SetAnchorX(const Value: Integer);
procedure SetAnchorY(const Value: Integer);
procedure SetIsMe(const Value: Boolean);
protected
//process collision event
procedure DoCollision(Sprite: TSprite; var Done: Boolean); override;
//process move event
procedure DoMove(MoveCount: Integer); override;
public
PathCala: Boolean;
PathInf: TDXPath;
PathIndex: Integer;
PathCount: Integer;
Path: array [0..100] of TPathPoint;
Talk: TTalk;
property AnchorX: Integer read FAnchorX write SetAnchorX;
property AnchorY: Integer read FAnchorY write SetAnchorY;
property NewX: Double read FNewX write SetNewX;
property NewY: Double read FNewY write SetNewY;
property Moved: Boolean read FMoved write SetMoved;
property Caption: string read FCaption write SetCaption;
property HeadID: Integer read FHeadID write SetHeadID;
property Degree: Integer read FDegree write SetDegree;
property IsMe: Boolean read FIsMe write SetIsMe;
constructor Create(Aparent: TSprite); override;
destructor Destroy; override;
//buile obstacle map
procedure MakeMap(MapEngine: TDXMap);
//move to appointed position
procedure Go(EndX, EndY:Double);
//fill the TTalk items for drawwing
procedure Speak(ASend, ARece, AText: string; AFace: Integer; AOnlyOne: Boolean);
//drop the TTalk item which was timeout
procedure RollTalk;
end;
//TPlayers structor is designed for Online List of Client
TPlayers = class(TComponent)
private
FCount: Integer;
procedure SetCount(const Value: Integer);
public
Items: array [0..200] of TPlayerSprite;
property Count: Integer read FCount write SetCount;
constructor Create(AOwner: TObject); reintroduce;
//Add a new sprite to the online list of client
function Add(ASprite: TSprite; ACaption: string;ADegree: Integer): Integer;
//drop a sprite from the online list of client
procedure Delete(Index: Integer);
//search sprite by caption from online list of client
function FindByCaption(ACaption: string): Integer;
//clear the online list of client
procedure Clear;
//get the caption of the sprite which at the appointed area
function GetSpriteAt(X, Y: Double): string;
end;
implementation
{ TPlayerSprite }
procedure TPlayerSprite.Go(EndX, EndY:Double);
var
I: Integer;
//transform the default coordinate format to custom coordinate format
//the map with new coordinate is most smaller than normal
//so can process the map more faster include all of it's operation
function WorldToMapX(WX: Double): Integer;
begin
Result:=(Trunc(WX) +(MapW div 2)) div DL;
if Result>MapW then
Result:=MapW;
if Result<0 then
Result:=0;
end;
function WorldToMapY(WY: Double): Integer;
begin
Result:=(Trunc(WY)+MapH div 2) div dl;
if Result>MapH then
Result:=MapH;
if Result<0 then
Result:=0;
end;
function MapToWorldX(MX: Integer): Integer;
begin
Result:=MX*DL-MapW div 2+DL div 2;
if Result>MapW div 2 then
Result:=MapW div 2;
if Result<-MapW div 2 then
Result:=-MapW div 2;
end;
function MapToWorldY(MY: Integer):Integer;
begin
Result:=MY*DL-MapH div 2 + DL div 2;
if Result>MapH div 2 then
Result:=MapH div 2;
if Result<-MapH div 2 then
Result:=-MapH div 2;
end;
begin
//create new coordinate of start position and end position
PathInf.FStartPos.x:=WorldToMapX(X);
PathInf.FStartPos.y:=WorldToMapY(Y);
PathInf.FEndPos.x:=WorldToMapX(EndX);
PathInf.FEndPos.y:=WorldToMapY(EndY);
//find path
//DXPath is a third party unit,i have modified a few part in it
if not PathInf.FindPath then
Exit;
PathIndex:=0;
PathCount:=PathInf.DirChangedPointsCount-1;
//copy the path points to temp value
//and DoMove function will move the sprite to end position along the points
for I:=1 to PathCount do
begin
Path[I-1].X:=MapToWorldX(PathInf.DirChangedPointsArr[I].Point.X);
Path[I-1].Y:=MapToWorldY(PathInf.DirChangedPointsArr[I].Point.Y);
end;
end;
destructor TPlayerSprite.Destroy;
begin
PathInf.Free;
PathInf:=nil;
inherited Destroy;
end;
procedure TPlayerSprite.DoCollision(Sprite: TSprite; var Done: Boolean);
begin
inherited;
end;
procedure TPlayerSprite.DoMove(MoveCount: Integer);
var
EngX, EngY: Double;
begin
inherited DoMove(MoveCount);
//animate speed
AnimSpeed := 8/1000;
if PathIndex>=PathCount then
Exit;
NewX:=Path[PathIndex].X;
NewY:=Path[PathIndex].Y;
Moved:=False;
if (X >NewX) then
begin
//calculate the length
X := X - (120/1000)*MoveCount;
//if length less then zero then don't move
if XAVAILABLE_AREA then
begin
AnimStart := 6;
AnimCount := 2;
end;
Moved:=True;
end;
if (XNewX then
X:=NewX;
if NewX-X>AVAILABLE_AREA then
begin
AnimStart := 2;
AnimCount := 2;
end;
Moved:=True;
end;
if Y > NewY then
begin
Y := Y - (120/1000)*MoveCount;
if YAVAILABLE_AREA then
begin
AnimStart := 0;
AnimCount := 2;
end;
Moved:=True;
end;
if Y < NewY then
begin
Y := Y + (120/1000)*MoveCount;
if Y>NewY then
Y:=NewY;
if NewY-Y>AVAILABLE_AREA then
begin
AnimStart := 4;
AnimCount := 2;
end;
Moved:=True;
end;
//if sprite has moved then animate can be played
AnimLooped:=Moved;
//if sprite has already move to new position then go to next postion
if not Moved then
Inc(PathIndex);
//process collision
Collision;
if not FIsMe then
Exit;
//scroll the window and insure self sprite is in the window
EngX := -X+Engine.Width div 2-Width div 2;
EngY := -Y+Engine.Height div 2-Height div 2;
if EngX>MapW div 2 then
Engine.X:=MapW div 2
else
if EngX<-MapW div 2 +Engine.Width then
Engine.X:=-MapW div 2+Engine.Width
else
Engine.X:=EngX;
if EngY>MapH div 2 then
Engine.Y:=MapH div 2
else
if EngY<-MapH div 2 + Engine.Height then
Engine.Y:=-MapH div 2+Engine.Height
else
Engine.Y:=EngY;
end;
procedure TPlayerSprite.SetCaption(const Value: string);
begin
FCaption := Value;
end;
procedure TPlayerSprite.SetMoved(const Value: Boolean);
begin
FMoved := Value;
end;
procedure TPlayerSprite.SetNewX(const Value: Double);
begin
FNewX := Value;
end;
procedure TPlayerSprite.SetNewY(const Value: Double);
begin
FNewY := Value;
end;
constructor TPlayerSprite.Create(Aparent: TSprite);
begin
inherited Create(AParent);
//create PathInf and create digital map with new custom coordinate
PathInf:=TDXPath.Create(MapW div DL, MapH div DL);
Talk.Count:=0;
PathCala:=False;
PathIndex:=-1;
PathCount:=0;
AnchorX:=0;
AnchorY:=0;
x:=0;
y:=0;
Z := 8;
end;
function TPlayerSprite.HasObstacle(StartX, StartY: Integer): Boolean;
var
AX, AY: Integer;
begin
Result:=False;
for AX:=1 to DL do
for AY:=1 to DL do
Result:=Result or OrgObstacle[StartX-MapW div 2+AX-1, StartY-MapH div 2+AY-1];
end;
procedure TPlayerSprite.MakeMap(MapEngine: TDXMap);
var
I, J, K: Integer;
begin
if PathCala then
Exit;
for I:=-MapW div 2 to MapW div 2 do
for J:=-MapH div 2 to MapH div 2 do
OrgObstacle[I, J]:=False;
with MapEngine.Engine.Engine do
for I:=0 to Count-1 do
if (not (Items[I] is TPlayerSprite)) and (not (Items[I] is TDecAcces)) then
for J:=0 to Items[I].Width-1 do
for K:=0 to Items[I].Height-1 do
OrgObstacle[Trunc(Items[I].X+J), Trunc(Items[I].Y+K)]:=True;
for I:=0 to MapH div DL-1 do
for J:=0 to MapW div DL-1 do
PathInf.FObstacle[I, J]:=HasObstacle(J*DL, I*DL);
PathCala:=True;
end;
procedure TPlayerSprite.Speak(ASend, ARece, AText: string; AFace: Integer; AOnlyOne: Boolean);
begin
if Talk.Count>=1 then
RollTalk;
with Talk do
begin
Items[Count]:=AText;
Send[Count]:=Asend;
Rece[Count]:=ARece;
Face[Count]:=AFace;
OnlyOne[Count]:=AOnlyOne;
Life[Count]:=0;
Inc(Count);
end;
end;
procedure TPlayerSprite.RollTalk;
var
I: Integer;
begin
with Talk do
begin
Dec(Count);
for I:=0 to Count-1 do
begin
Items[I]:=Items[I+1];
Send[I]:=Send[I+1];
Rece[I]:=Rece[I+1];
Face[I]:=Face[I+1];
OnlyOne[I]:=OnlyOne[I+1];
Life[I]:=Life[I+1];
end;
end;
end;
procedure TPlayerSprite.SetDegree(const Value: Integer);
begin
FDegree := Value;
end;
procedure TPlayerSprite.SetHeadID(const Value: Integer);
begin
FHeadID := Value;
end;
procedure TPlayerSprite.SetAnchorX(const Value: Integer);
begin
FAnchorX := Value;
end;
procedure TPlayerSprite.SetAnchorY(const Value: Integer);
begin
FAnchorY := Value;
end;
procedure TPlayerSprite.SetIsMe(const Value: Boolean);
begin
FIsMe := Value;
end;
{ TPlayers }
function TPlayers.Add(ASprite: TSprite; ACaption: string; ADegree: Integer): Integer;
begin
Items[FCount]:=TPlayerSprite.Create(ASprite);
with Items[FCount] do
begin
FCaption:=ACaption;
FDegree:=ADegree;
end;
Result:=FCount;
Inc(FCount);
end;
constructor TPlayers.Create(AOwner: TObject);
begin
FCount:=0;
end;
procedure TPlayers.Delete(Index: Integer);
var
I: Integer;
begin
Items[Index].Free;
for I:=Index to FCount-2 do
Items[Index]:=Items[Index+1];
Items[FCount-1]:=nil;
Dec(FCount);
end;
function TPlayers.FindByCaption(ACaption: string): Integer;
var
I: Integer;
begin
Result:=-1;
for I:=0 to FCount-1 do
if LowerCase(Items[I].Caption)=LowerCase(ACaption) then
begin
Result:=I;
Exit;
end;
end;
procedure TPlayers.SetCount(const Value: Integer);
begin
FCount := Value;
end;
procedure TPlayers.Clear;
var
I: Integer;
begin
for I:=0 to FCount-1 do
begin
Items[I].Free;
Items[I]:=nil;
end;
FCount:=0;
end;
function TPlayers.GetSpriteAt(X, Y: Double): string;
var
I: Integer;
begin
Result:='';
for I:=0 to FCount-1 do
if ((Items[I].X-Items[I].Image.Width div 2)X) and ((Items[I].Y+Items[I].Image.Height div 2)>Y)
then
begin
Result:=Items[I].Caption;
Exit;
end;
end;
end.