0,0 → 1,2383 |
unit colli3DX; |
|
{$include DelphiXcfg.inc} |
|
|
//************************************************************************* |
//* * |
//* TCollisionTester3DX vs 1.3 * |
//* * |
//************************************************************************* |
// |
// This Delphi 4, 5, 6 component is CopyRight: |
// |
// Henrik Fabricius, August 1999, March 2000, June 2002 |
// http://users.cybercity.dk/~bbl6194/delphi3dx.htm |
// E-mail: henrik_og_bodil@vip.cybercity.dk |
// |
// You may use this component for free on the following conditions: |
// 1) this text must remain part of the unit. |
// 2) Any proposals for changes or improvements should be addressed directly to |
// the copyright owner Henrik Fabricius |
// 3) The use of this component is on your own risk. The software is provided |
// as is without any garanties and warranty. The CopyRight Owner is not |
// responsible for any damage or losses of any kind caused by the use of this |
// software or the software it is intended to be used with. |
// |
// To place a link for down-loads of this component on your homepage |
// please place a link to the Delphi3DX page where the latest version |
// is available. |
// |
// To use this component you must have |
// 1) Delphi 4, 5 or 6 |
// 2) MS-DirectX 6.0 or higher |
// 3) the DelphiX components from Hori in Japan |
// |
// MS-DirectX is a trademark of the Microsoft Corporation |
// Delphi 4, 5 and 6 is a trademark of the Inprise Corporation |
// |
// Use this component to check for collisions between 3D objects in |
// Direct3D games. |
// Place your 3D-objects in a world described by : |
// - DXDrawUsed - |
// |
// Group the 3D-objects in series with different material |
// or functional properties |
// The 3D-object series are named by the property: |
// - Indexof3DSeries - |
// 3D-objects are named by the property : |
// - Indexof3Dobject - |
// A 3D-object consist of one or more 3D-elements named by the property : |
// - Indexof3DElement - |
// |
// Surround each of your 3D elements by at least one collision object |
// which must be a member of the following primitives : |
// - box3D - sphere3D - ellipsoid3D - cylinder3D - conus3D - |
// available CollOrientations are : |
// - Symmetric_X - Symmetric_Y - Symmetric_Z - |
// available material properties are : |
// - solid3D - water3D - air3D |
// the size of the small end of the conus is described by the property |
// - PercentLeftatTop - |
// a negative value means that the top is downwards |
// available functional properties are : |
// - Pickable - Shootable - Fixed3DObject |
// Add each object by specifying : |
// - FrameSeries - NextAddMesh - CoverWholeMesh - |
// - IndexOf3DSeries - IndexOf3DObject - IndexOf3DElement - |
// if coverWholeMesh is false then specify a box containing the part of the |
// 3D object which should be covered by the coll object by the commands |
// - BoxPartMin(x,y,z) - BoxPartMax(x,y,z) - |
// Finally add the collision object by executing the command |
// - AddCollisionObject - |
// |
// Bullets are described by the following properties : |
// - BulletRadius - BulletRange - BulletFrame - LongShots - |
// LongShots moves with a unlimited speed reaching the objects immediately |
// |
// The actor is described by : |
// - FrontDistance - HeadRadius - |
// |
// The camera-frame and the bullet-frames move each time the move command |
// is used in the main program. |
// Execute the following commands prior to each move command : |
// - GetOldEyePos - GetOldBulletPos - |
// The collisionTester needs this information to test for a possible collision |
// in between the starting and the ending points of the Eye/bullet |
// |
// Test for collision with the following function calls : |
// - if CollisionTester3DX1.Collision then .. |
// - if CollisionTester3DX1.BulletCollision then .. |
// On collision read the HitLinkNr and the properties of the collision object |
// |
// Destroy 3D collisionObjects by specifying : |
// - NextDestroyNr - IndexOf3DSeries - |
// and the executing command DestroyCollisionObject |
// |
// Initialize the collisionTester with the command : |
// - CollisionTester3DX1.ZeroSetIt - |
// This must always be done when DXDraw is initialized |
// |
// To install the component: |
// 1) place this unit and the dcr file in the same directory as DelphiX |
// 2) In Delphi you must click on Component - Install Component |
// 3) Select the colli3DX.pas file and choose the Samples package to install it |
// 4) Rebuild the library |
// 5) Look for a new icon with a bomb on the page named DelphiX |
// |
// Tutorial programs are available for down-load at |
// http://users.cybercity.dk/~bbl6194/delphi3dx.htm |
// |
// Good Luck |
// Henrik Fabricius |
// |
// |
//**************************************************************************** |
|
|
|
interface |
|
uses |
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, |
StdCtrls, DXClass, DXDraws, |
{$IfDef StandardDX} |
DirectDraw, Direct3D, Direct3DRM; |
{$Else} |
DirectX; |
{$EndIf} |
|
Type |
Tshapes3D = (box3D, sphere3D, ellipsoid3D, cylinder3D, conus3D); |
Tmaterials3D = (solid3D, water3D, air3D); |
TOrientation3D = (symmetric_x, symmetric_y, symmetric_z); |
TFrames3D = Array of Array of IDirect3DRMFrame; |
|
TCollisionTester3DX = class(TComponent) |
private |
{private declarations} |
FDXDrawUsed : TDXDraw; |
FFrameSeries : TFrames3D; |
FNextAddMesh : IDirect3DRMMesh; |
FBulletFrame : IDirect3DRMFrame; |
FBoxPartMin : TD3DVector; |
FBoxPartMax : TD3DVector; |
FOldBulletPosition: TD3DVector; |
FOldEyePosition : TD3DVector; |
|
FNrOfSeries : integer; |
FSeriesIndex : integer; |
FSeriesNr : integer; |
FOrientation3D : TOrientation3D; |
Fshape3D : Tshapes3D; |
Fmaterial3D : Tmaterials3D; |
FPercentLeftAtTop : integer; |
Fbullet_hitLinknr : integer; |
FIndexOf3DObject : integer; |
FIndexOf3DElement : integer; |
FNextDestroyNr : integer; |
FNextAllOfMesh : Boolean; |
FFrontDistance : integer; |
FBulletRange : integer; |
FBulletRadius : integer; |
FHeadRadius : integer; |
FFixed3DObject : Boolean; |
FShootable : Boolean; |
FLongShots : Boolean; |
FPickable : Boolean; |
FCheckAllCollObj : Boolean; |
|
Fcoll_Nr_Objects : Array of integer; |
FSeriesIndex_for_SeriesNr : Array of integer; |
|
FNrinFrameSeries : Array of Array of integer; |
Fcoll_orientation : Array of Array of TOrientation3D; |
Fcoll_shape : Array of Array of Tshapes3D; |
Fcoll_material : Array of Array of Tmaterials3D; |
Fcoll_box_min : Array of Array of TD3DVector; |
Fcoll_box_max : Array of Array of TD3DVector; |
Fcoll_radius : Array of Array of TD3DValue; |
Fcoll_frac_at_top : Array of Array of TD3DValue; |
Fcoll_shootable : Array of Array of boolean; |
Fcoll_Pickable : Array of Array of boolean; |
Fcoll_Fixed3D : Array of Array of boolean; |
Fcoll_objectNr : Array of Array of integer; |
|
procedure SetOrientation3D(Value : TOrientation3D); |
procedure SetShape3D(Value: TShapes3D); |
procedure SetMaterial3D(Value: Tmaterials3D); |
procedure SetPercentLeftatTop(Value: integer); |
procedure SetIndexOf3DObject(Value : integer); |
procedure SetIndexOf3DElement(Value : integer); |
procedure SetIndexOf3DSeries(Value : integer); |
procedure SetNextDestroyNr(Value : Integer); |
procedure SetBulletRadius(Value : Integer); |
procedure SetHeadRadius(Value : Integer); |
procedure SetFrontDistance(Value : Integer); |
procedure SetBulletRange(Value : Integer); |
function add_space_for_one_more : boolean; |
procedure GetTheBox; |
procedure AddBox; |
procedure AddSphere; |
procedure AddCylinder; |
procedure AddConus; |
procedure AddEllipsoid; |
|
procedure MakeNewSeries; |
procedure Destroy_empty_series(SeriesNr : integer); |
function GetSeriesNr(Nr : integer): integer; |
procedure remove_collision_object(seriesNr, Value : integer); |
function CheckForSeriesIndex(indexnow : integer): boolean; |
procedure ListDataForCollObject; |
function coll_test_box(coll_nr : byte; |
old_attacker_position, attacker_position : TD3DVector; |
bullet_radius : TD3DValue; longshot : boolean): boolean; |
function coll_test_cylinder(coll_nr : byte; |
old_attacker_position, attacker_position : TD3DVector; |
bullet_radius : TD3DValue; longshot : boolean): boolean; |
function coll_test_sphere(coll_nr : byte; |
old_attacker_position, |
attacker_position : TD3DVector; |
bullet_radius : TD3Dvalue; longshot : boolean): boolean; |
function coll_test_ellipsoid(coll_nr : byte; |
old_attacker_position, attacker_position : TD3DVector; |
bullet_radius : TD3DValue; longshot : boolean): boolean; |
function coll_test_conus(coll_nr : byte; |
old_attacker_position, attacker_position : TD3DVector; |
bullet_radius : TD3DValue; longshot : boolean): boolean; |
|
protected |
|
public |
Constructor Create(AOwner : TComponent); override; |
destructor Destroy; override; |
|
property DXDrawUsed : TDXDraw write FDXDrawUsed stored false; |
property FrameSeries : TFrames3D write FFrameSeries stored false; |
property NextAddMesh : IDirect3DRMMesh write FNextAddMesh stored false; |
property BulletFrame : IDirect3DRMFrame write FBulletFrame stored false; |
|
procedure ZeroSetIt; |
procedure BoxPartMin(xval, yval, zval: TD3DValue); |
procedure BoxPartMax(xval, yval, zval: TD3DValue); |
procedure GetOldBulletPos; |
procedure GetOldEyePos; |
|
function HitLinkNr: integer; |
function DestroyCollisionObject: boolean; |
procedure AddCollisionObject; |
function Collision: boolean; |
function Bulletcollision: boolean; |
function BulletDead : boolean; |
|
|
published |
|
property BulletRadius : Integer read FBulletRadius write SetBulletRadius |
default 0; |
property BulletRange : Integer read FbulletRange write SetBulletRange |
Default 100; |
property CollisionCheckAll: Boolean read FCheckAllCollObj |
write FCheckAllCollObj Default true; |
property CollOrientation : TOrientation3D read FOrientation3D |
write SetOrientation3D default symmetric_y; |
property CollObjectType : Tshapes3D read Fshape3D write SetShape3D |
default box3D; |
property CollObjMaterial : Tmaterials3D read Fmaterial3D write SetMaterial3D |
default solid3D; |
property CoverWholeMesh : boolean read FNextAllOfMesh |
write FNextAllOfMesh default true; |
Property Fixed3DObject : boolean read FFixed3DObject |
write FFixed3DObject default true; |
property FrontDistance : Integer read FFrontDistance |
write SetFrontDistance default 0; |
property HeadRadius : integer read FHeadRadius write SetHeadRadius |
default 0; |
property IndexOf3DSeries : integer read FSeriesIndex |
write SetIndexOf3DSeries default 0; |
property IndexOf3DObject : integer read FIndexOf3DObject |
write SetIndexOf3DObject default 0; |
property IndexOf3DElement : integer read FIndexOf3DElement |
write SetIndexOf3DElement default 0; |
property NextDestroyNr : Integer read FNextDestroyNr |
write SetNextDestroyNr default 0; |
Property PercentLeftAtTop : integer read FPercentLeftAtTop |
write SetPercentLeftAtTop default 0; |
Property Pickable : Boolean read FPickable write FPickable |
default false; |
Property Shootable : boolean read FShootable write FShootable |
Default false; |
Property LongShots : boolean read FLongShots write FLongShots |
Default false; |
|
|
end; //end of Class |
|
|
|
//Registering of the Component |
Procedure Register; |
|
|
implementation |
|
|
|
procedure Register; |
begin |
//Register the component together with the DelphiX components from Hori |
RegisterComponents('DelphiX', [TCollisionTester3DX]); |
end; //end of Register |
|
|
constructor TCollisionTester3DX.Create(AOwner : TComponent); |
begin |
inherited Create(AOwner); |
//The constructor always clears the storage it allocates for a new object |
//Hence there is no need to initialize fields except to nonzero or nonempty |
//values |
FDXDrawUsed := nil; |
FFrameSeries := nil; |
FNextAddMesh := nil; |
FBulletFrame := nil; |
|
FOrientation3D := symmetric_y; |
FShape3D := box3D; |
FMaterial3D := solid3D; |
FBulletRange := 100; |
FNrOfSeries := 0; |
setlength(FSeriesIndex_for_SeriesNr, 0); |
setlength(FColl_nr_objects, 0); |
setlength(FNrinFrameSeries, 0); |
setlength(Fcoll_shape, 0); |
setlength(Fcoll_box_min, 0); |
setlength(Fcoll_box_max, 0); |
setlength(Fcoll_radius, 0); |
setlength(Fcoll_frac_at_top, 0); |
setlength(Fcoll_objectnr, 0); |
setlength(Fcoll_shootable, 0); |
setlength(Fcoll_pickable, 0); |
setlength(Fcoll_orientation, 0); |
setlength(Fcoll_material, 0); |
setlength(Fcoll_Fixed3D, 0); |
|
end; //end of creation |
|
|
|
|
|
|
|
destructor TCollisionTester3DX.Destroy; |
begin |
//destroy any embedded objects and free resources allocated by the objects |
FnrinFrameSeries := nil; |
Fcoll_shape := nil; |
Fcoll_box_min := nil; |
Fcoll_box_max := nil; |
Fcoll_radius := nil; |
Fcoll_frac_at_top := nil; |
Fcoll_objectnr := nil; |
Fcoll_shootable := nil; |
Fcoll_pickable := nil; |
Fcoll_orientation := nil; |
Fcoll_material := nil; |
Fcoll_Fixed3D := nil; |
FSeriesIndex_for_SeriesNr := nil; |
Fcoll_nr_objects := nil; |
|
inherited Destroy; |
end; //end of Destroy |
|
|
|
|
procedure TCollisionTester3DX.ZeroSetIt; |
begin |
//initialises the dynamic arrays |
FnrinFrameSeries := nil; |
Fcoll_shape := nil; |
Fcoll_box_min := nil; |
Fcoll_box_max := nil; |
Fcoll_radius := nil; |
Fcoll_frac_at_top := nil; |
Fcoll_objectnr := nil; |
Fcoll_shootable := nil; |
Fcoll_pickable := nil; |
Fcoll_orientation := nil; |
Fcoll_material := nil; |
Fcoll_Fixed3D := nil; |
FSeriesIndex_for_SeriesNr := nil; |
Fcoll_nr_objects := nil; |
|
FDXDrawUsed := nil; |
FFrameSeries := nil; |
FNextAddMesh := nil; |
FBulletFrame := nil; |
|
FOrientation3D := symmetric_y; |
FShape3D := box3D; |
FMaterial3D := solid3D; |
FBulletRange := 100; |
FNrOfSeries := 0; |
setlength(FSeriesIndex_for_SeriesNr, 0); |
setlength(FColl_nr_objects, 0); |
setlength(FNrinFrameSeries, 0); |
setlength(Fcoll_shape, 0); |
setlength(Fcoll_box_min, 0); |
setlength(Fcoll_box_max, 0); |
setlength(Fcoll_radius, 0); |
setlength(Fcoll_frac_at_top, 0); |
setlength(Fcoll_objectnr, 0); |
setlength(Fcoll_shootable, 0); |
setlength(Fcoll_pickable, 0); |
setlength(Fcoll_orientation, 0); |
setlength(Fcoll_material, 0); |
setlength(Fcoll_Fixed3D, 0); |
|
end; //end of ZeroSetIt |
|
|
|
|
function TcollisionTester3DX.HitLinkNr: integer; |
begin |
result := Fbullet_hitlinknr; |
end; //end of HitLinkNr |
|
|
|
procedure TCollisionTester3DX.ListDataForCollObject; |
var |
Nr : integer; |
begin |
Nr := FBullet_HitLinkNr; |
|
CollObjectType := Fcoll_shape[FSeriesNr, Nr]; |
CollObjMaterial := Fcoll_material[FSeriesNr, Nr]; |
Fixed3DObject := Fcoll_Fixed3D[FSeriesNr, Nr]; |
CollOrientation := Fcoll_orientation[FSeriesNr, Nr]; |
IndexOf3DObject := Fcoll_objectNr[FSeriesNr, Nr]; |
IndexOf3DSeries := FSeriesIndex; |
IndexOf3DElement := FNrinFrameSeries[FSeriesNr, Nr]; |
Pickable := Fcoll_pickable[FSeriesNr, Nr]; |
Shootable := Fcoll_shootable[FseriesNr, Nr]; |
|
end; //end of ListDataForCollObject |
|
|
|
|
procedure TcollisionTester3DX.SetPercentLeftAtTop(Value : Integer); |
begin |
//value can not be negative |
if (FPercentLeftAtTop <> Value) and (Value >= 0) |
then |
FPercentLeftAtTop := value; |
end; //end of SetPercentLeftAtTop |
|
|
|
|
procedure TcollisionTester3DX.SetOrientation3D(Value : TOrientation3D); |
begin |
if FOrientation3D <> Value |
then |
FOrientation3D := Value; |
end; //end setorientation3D |
|
|
procedure TcollisionTester3DX.SetShape3D(Value : Tshapes3D); |
begin |
if Fshape3D <> Value |
then |
Fshape3D := Value; |
end; //end setshapes3D |
|
|
|
procedure TcollisionTester3DX.SetMaterial3D(Value : Tmaterials3D); |
begin |
if Fmaterial3D <> Value |
then |
Fmaterial3D := Value; |
end; //end setshapes3D |
|
|
|
procedure TCollisionTester3DX.SetIndexOf3DObject(Value : integer); |
begin |
//Index can not be negative |
if (FIndexOf3DObject <> Value) and (Value >= 0) |
then |
FIndexOf3DObject := value; |
end; //end setIndexOf3DObject |
|
|
procedure TCollisionTester3DX.SetIndexOf3DElement(Value : integer); |
begin |
//Index can not be negative |
if (FIndexOf3DElement <> Value) and (Value >= 0) |
then |
FIndexOf3DElement := value; |
end; //end setIndexOf3DElement |
|
|
|
procedure TCollisionTester3DX.SetIndexOf3DSeries(Value : integer); |
begin |
//Index can not be negative |
if (FSeriesIndex <> Value) and (Value >= 0) |
then |
FSeriesIndex := value; |
end; //end of SetIndexOf3DSeries |
|
|
|
|
procedure TCollisionTester3DX.SetNextDestroyNr(Value : integer); |
begin |
//Index can not be negative |
if (FNextDestroyNr <> Value) and (Value >= 0) |
then |
FNextDestroyNr := value; |
end; //end of SetNextDestroyNr |
|
|
|
|
procedure TCollisionTester3DX.SetBulletRadius(Value : Integer); |
begin |
//Radius can not be negative |
if (FBulletRadius <> Value) and (Value >= 0) |
then |
FBulletRadius := value; |
end; //end of SetBulletRadius |
|
|
|
procedure TCollisionTester3DX.SetHeadRadius(Value : Integer); |
begin |
//Radius can not be negative |
if (FHeadRadius <> Value) and (Value >= 0) |
then |
FHeadRadius := value; |
end; //end of SetHeadRadius |
|
|
|
|
procedure TCollisionTester3DX.SetFrontDistance(Value : Integer); |
begin |
//FrontDistance can not be negative |
if (FFrontDistance <> Value) and (Value >= 0) |
then |
FFrontDistance := value; |
end; //end of SetFrontDistance |
|
|
|
|
procedure TCollisionTester3DX.SetBulletRange(Value : Integer); |
begin |
//BulletRange can not be negative |
if (FBulletRange <> Value) and (Value >= 0) |
then |
FBulletRange := value; |
end; //end of SetBulletRange |
|
|
|
|
function TcollisionTester3DX.Add_Space_For_One_More: boolean; |
var |
NewNr : integer; |
begin |
//add space for one more element in the present series |
|
//length of Fcoll_nr_objects and FSeries_nIndex_for_SeriesNr are unchanged |
NewNr := Fcoll_nr_objects[FseriesNr] + 1; |
|
result := true; |
|
try |
SetLength(FNrinFrameSeries[FSeriesNr], NewNr); |
SetLength(Fcoll_shape[FSeriesNr], NewNr); |
SetLength(Fcoll_box_min[FSeriesNr], NewNr); |
SetLength(Fcoll_box_max[FSeriesNr], NewNr); |
SetLength(Fcoll_radius[FSeriesNr], NewNr); |
SetLength(Fcoll_frac_at_top[FSeriesNr], NewNr); |
SetLength(Fcoll_objectnr[FSeriesNr], NewNr); |
SetLength(Fcoll_shootable[FSeriesNr], NewNr); |
SetLength(Fcoll_pickable[FSeriesNr], NewNr); |
SetLength(Fcoll_orientation[FSeriesNr], NewNr); |
SetLength(Fcoll_material[FSeriesNr], NewNr); |
SetLength(Fcoll_Fixed3D[FSeriesNr], NewNr); |
|
except |
on EOutOfMemory do |
begin |
//There is not enough memory available. Free some memory |
dec(NewNr); |
|
copy(FNrinFrameSeries[FseriesNr], 0, NewNr); |
copy(Fcoll_shape[FseriesNr], 0, NewNr); |
copy(Fcoll_box_min[FSeriesNr], 0, NewNr); |
copy(Fcoll_box_max[FSeriesNr], 0, NewNr); |
copy(Fcoll_radius[FSeriesNr], 0, NewNr); |
copy(Fcoll_frac_at_top[FSeriesNr], 0, NewNr); |
copy(Fcoll_objectnr[FSeriesNr], 0, NewNr); |
copy(Fcoll_shootable[FSeriesNr], 0, NewNr); |
copy(Fcoll_pickable[FSeriesNr], 0, NewNr); |
copy(Fcoll_orientation[FSeriesNr], 0, NewNr); |
copy(Fcoll_material[FSeriesNr], 0, NewNr); |
copy(Fcoll_Fixed3D[FSeriesNr], 0, NewNr); |
|
result := false; |
end; |
end; |
|
//update count of objects in series |
Fcoll_nr_objects[FseriesNr] := NewNr; |
|
end; //end of Add_Space_For_One_More |
|
|
|
|
procedure TcollisionTester3DX.MakeNewSeries; |
begin |
inc(FNrOfSeries); |
|
SetLength(FSeriesIndex_for_SeriesNr, FNrOfSeries); |
FSeriesIndex_for_SeriesNr[FNrOfSeries-1] := FSeriesIndex; |
|
SetLength(Fcoll_nr_objects, FNrOfSeries); |
Fcoll_nr_objects[FNrOfSeries-1] := 0; |
|
SetLength(FNrinFrameSeries, FNrOfSeries); |
SetLength(Fcoll_shape, FNrOfSeries); |
SetLength(Fcoll_box_min, FNrOfSeries); |
SetLength(Fcoll_box_max, FNrOfSeries); |
SetLength(Fcoll_radius, FNrOfSeries); |
SetLength(Fcoll_frac_at_top, FNrOfSeries); |
SetLength(Fcoll_objectnr, FNrOfSeries); |
SetLength(Fcoll_shootable, FNrOfSeries); |
SetLength(Fcoll_pickable, FNrOfSeries); |
SetLength(Fcoll_orientation, FNrOfSeries); |
SetLength(Fcoll_material, FNrOfSeries); |
SetLength(Fcoll_Fixed3D, FNrOfSeries); |
end; //end of MakeNewSeries |
|
|
|
|
procedure TcollisionTester3DX.Destroy_Empty_Series(SeriesNr : integer); |
var |
i, j : integer; |
begin |
if seriesNr < (FNrOfSeries - 1) |
then |
begin |
for i := SeriesNr to (FNrOfSeries - 2) do |
begin |
FSeriesIndex_for_SeriesNr[i] := FSeriesIndex_for_SeriesNr[i+1]; |
|
SetLength(FNrinFrameSeries[i], Fcoll_Nr_objects[i+1]); |
for j := 0 to (Fcoll_Nr_objects[i+1] - 1) do |
FNrinFrameSeries[i, j] := FNrinFrameSeries[(i+1), j]; |
|
SetLength(Fcoll_shape[i], Fcoll_Nr_objects[i+1]); |
for j := 0 to (Fcoll_Nr_objects[i+1] - 1) do |
Fcoll_shape[i, j] := Fcoll_shape[(i+1), j]; |
|
SetLength(Fcoll_box_min[i], Fcoll_Nr_objects[i+1]); |
for j := 0 to (Fcoll_Nr_objects[i+1] - 1) do |
Fcoll_box_min[i, j] := Fcoll_box_min[(i+1), j]; |
|
SetLength(Fcoll_box_max[i], Fcoll_Nr_objects[i+1]); |
for j := 0 to (Fcoll_Nr_objects[i+1] - 1) do |
Fcoll_box_max[i, j] := Fcoll_box_max[(i+1), j]; |
|
SetLength(Fcoll_radius[i], Fcoll_Nr_objects[i+1]); |
for j := 0 to (Fcoll_Nr_objects[i+1] - 1) do |
Fcoll_radius[i, j] := Fcoll_radius[(i+1), j]; |
|
SetLength(Fcoll_frac_at_top[i], Fcoll_Nr_objects[i+1]); |
for j := 0 to (Fcoll_Nr_objects[i+1] - 1) do |
Fcoll_frac_at_top[i, j] := Fcoll_frac_at_top[(i+1), j]; |
|
SetLength(Fcoll_objectnr[i], Fcoll_Nr_objects[i+1]); |
for j := 0 to (Fcoll_Nr_objects[i+1] - 1) do |
Fcoll_objectNr[i, j] := Fcoll_objectNr[(i+1), j]; |
|
SetLength(Fcoll_shootable[i], Fcoll_Nr_objects[i+1]); |
for j := 0 to (Fcoll_Nr_objects[i+1] - 1) do |
Fcoll_shootable[i, j] := Fcoll_shootable[(i+1), j]; |
|
SetLength(Fcoll_pickable[i], Fcoll_Nr_objects[i+1]); |
for j := 0 to (Fcoll_Nr_objects[i+1] - 1) do |
Fcoll_pickable[i, j] := Fcoll_pickable[(i+1), j]; |
|
SetLength(Fcoll_orientation[i], Fcoll_Nr_objects[i+1]); |
for j := 0 to (Fcoll_Nr_objects[i+1] - 1) do |
Fcoll_orientation[i, j] := Fcoll_orientation[(i+1), j]; |
|
SetLength(Fcoll_material[i], Fcoll_Nr_objects[i+1]); |
for j := 0 to (Fcoll_Nr_objects[i+1] - 1) do |
Fcoll_material[i, j] := Fcoll_material[(i+1), j]; |
|
SetLength(Fcoll_Fixed3D[i], Fcoll_Nr_objects[i+1]); |
for j := 0 to (Fcoll_Nr_objects[i+1] - 1) do |
Fcoll_Fixed3D[i, j] := Fcoll_Fixed3D[(i+1), j]; |
|
Fcoll_nr_objects[i] := Fcoll_nr_objects[i+1]; |
|
end; |
end; |
|
dec(FNrOfSeries); |
|
FSeriesIndex_For_SeriesNr := copy(FSeriesIndex_for_SeriesNr, 0, FNrOfSeries); |
Fcoll_Nr_Objects := copy(Fcoll_Nr_Objects, 0, FNrOfSeries); |
FNrinFrameSeries := copy(FNrinFrameSeries, 0, FNrOfSeries); |
Fcoll_Shape := copy(Fcoll_Shape, 0, FNrOfSeries); |
Fcoll_Box_Min := copy(Fcoll_Box_Min, 0, FNrOfSeries); |
Fcoll_Box_Max := copy(Fcoll_Box_Max, 0, FNrOfSeries); |
Fcoll_Radius := copy(Fcoll_Radius, 0, FNrOfSeries); |
Fcoll_Frac_At_Top := copy(Fcoll_Frac_At_Top, 0, FNrOfSeries); |
Fcoll_ObjectNr := copy(Fcoll_ObjectNr, 0, FNrOfSeries); |
Fcoll_Shootable := copy(Fcoll_Shootable, 0, FNrOfSeries); |
Fcoll_Pickable := copy(Fcoll_Pickable, 0, FNrOfSeries); |
Fcoll_orientation := copy(Fcoll_orientation, 0, FNrOfSeries); |
Fcoll_Material := copy(Fcoll_Material, 0, FNrOfSeries); |
Fcoll_Fixed3D := copy(Fcoll_Fixed3D, 0, FNrOfSeries); |
end; //end of Destroy_Empty_Series |
|
|
|
|
|
|
|
procedure TcollisionTester3DX.Remove_Collision_Object(SeriesNr, Value : integer); |
var |
i : integer; |
begin |
//Elements in the series which have a higher index than the one removed |
//gets a smaller index which is correct when the main program removes the object |
for i := 0 to (FColl_nr_objects[SeriesNr] - 1) do |
begin |
if FNrinFrameSeries[SeriesNr, i] >= value |
then |
dec(FNrinFrameSeries[SeriesNr, i]); |
end; |
|
for i := Value to (Fcoll_nr_objects[SeriesNr] - 2) do |
begin |
FNrinFrameSeries[SeriesNr, i] := FNrinFrameSeries[SeriesNr, (i+1)]; |
Fcoll_shape[SeriesNr, i] := Fcoll_shape[SeriesNr, (i+1)]; |
Fcoll_box_min[SeriesNr, i] := Fcoll_box_min[SeriesNr, (i+1)]; |
Fcoll_box_max[SeriesNr, i] := Fcoll_box_max[SeriesNr, (i+1)]; |
Fcoll_radius[seriesNr, i] := Fcoll_radius[SeriesNr, (i+1)]; |
Fcoll_frac_at_top[SeriesNr, i] := Fcoll_frac_at_top[SeriesNr, (i+1)]; |
Fcoll_objectnr[SeriesNr, i] := Fcoll_objectnr[SeriesNr, (i+1)]; |
Fcoll_shootable[SeriesNr, i] := Fcoll_shootable[SeriesNr, (i+1)]; |
Fcoll_Pickable[SeriesNr, i] := Fcoll_Pickable[SeriesNr, (i+1)]; |
Fcoll_orientation[SeriesNr, i] := Fcoll_orientation[SeriesNr, (i+1)]; |
Fcoll_material[SeriesNr, i] := Fcoll_material[SeriesNr, (i+1)]; |
Fcoll_Fixed3D[SeriesNr, i] := Fcoll_Fixed3D[SeriesNr, (i+1)]; |
end; |
|
dec(Fcoll_nr_objects[SeriesNr]); |
|
//remember to reduce the length of Fcoll_frame |
FNrinFrameSeries[SeriesNr] := copy(FNrinFrameSeries[SeriesNr], 0, |
Fcoll_nr_objects[SeriesNr]); |
Fcoll_shape[SeriesNr] := copy(Fcoll_shape[SeriesNr], 0, |
Fcoll_nr_objects[SeriesNr]); |
Fcoll_box_min[SeriesNr] := copy(Fcoll_box_min[SeriesNr], 0, |
Fcoll_nr_objects[SeriesNr]); |
Fcoll_box_max[SeriesNr] := copy(Fcoll_box_max[SeriesNr], 0, |
Fcoll_nr_objects[SeriesNr]); |
Fcoll_radius[SeriesNr] := copy(Fcoll_radius[SeriesNr], 0, |
Fcoll_nr_objects[SeriesNr]); |
Fcoll_frac_at_top[SeriesNr] := copy(Fcoll_frac_at_top[SeriesNr], 0, |
Fcoll_nr_objects[SeriesNr]); |
Fcoll_objectnr[SeriesNr] := copy(Fcoll_objectnr[SeriesNr], 0, |
Fcoll_nr_objects[SeriesNr]); |
Fcoll_shootable[SeriesNr] := copy(Fcoll_shootable[SeriesNr], 0, |
Fcoll_nr_objects[SeriesNr]); |
Fcoll_pickable[SeriesNr] := copy(Fcoll_pickable[SeriesNr], 0, |
Fcoll_nr_objects[SeriesNr]); |
Fcoll_material[SeriesNr] := copy(Fcoll_material[SeriesNr], 0, |
Fcoll_nr_objects[FSeriesNr]); |
Fcoll_orientation[SeriesNr] := copy(Fcoll_orientation[SeriesNr], 0, |
Fcoll_nr_objects[FSeriesNr]); |
Fcoll_fixed3D[SeriesNr] := copy(Fcoll_fixed3D[SeriesNr], 0, |
Fcoll_nr_objects[SeriesNr]); |
|
end; //end of Remove_Collision_Object |
|
|
|
|
|
|
|
procedure TCollisionTester3DX.GetTheBox; |
var |
box: TD3DRMBOX; |
begin |
if FNextAllOfMesh |
then |
begin |
FNextAddMesh.GetBox(box); |
FColl_box_min[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := box.min; |
FColl_box_max[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := box.max; |
end |
else |
begin |
FColl_box_min[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := FBoxPartMin; |
FColl_box_max[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := FBoxPartMax; |
end; |
|
end; //end of GetTheBox |
|
|
|
procedure TCollisionTester3DX.BoxPartMin(xval, yval, zval : TD3DValue); |
begin |
FBoxPartMin.x := xval; |
FBoxPartMin.y := yval; |
FBoxPartMin.z := zval; |
end; //end of BoxPartMin |
|
|
|
|
procedure TCollisionTester3DX.BoxPartMax(xval, yval, zval : TD3DValue); |
begin |
FBoxPartMax.x := xval; |
FBoxPartMax.y := yval; |
FBoxPartMax.z := zval; |
end; //end of BoxPartMax |
|
|
|
|
|
procedure TCollisionTester3DX.AddBox; |
begin |
if add_space_for_one_more |
then |
begin |
GetTheBox; |
|
Fcoll_objectnr[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := FIndexOf3DObject; |
Fcoll_shape[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := box3D; |
FNrinFrameSeries[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := FIndexof3Delement; |
Fcoll_radius[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := 0; //not used |
Fcoll_frac_at_top[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := 0; //not used |
Fcoll_material[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := Fmaterial3D; |
Fcoll_orientation[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := Forientation3D; |
Fcoll_shootable[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] -1)] := Fshootable; |
Fcoll_Pickable[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := Fpickable; |
Fcoll_fixed3D[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := FFixed3DObject; |
end; |
end; //end of AddBox |
|
|
|
|
procedure TCollisionTester3DX.AddSphere; |
begin |
if add_space_for_one_more |
then |
begin |
GetTheBox; |
Fcoll_objectnr[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := FIndexOf3DObject; |
Fcoll_shape[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := sphere3D; |
FNrinFrameSeries[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := FIndexof3Delement; |
Fcoll_radius[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := |
(FColl_box_max[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)].x |
- FColl_box_min[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)].x |
+ FColl_box_max[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)].y |
- FColl_box_min[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)].y |
+ FColl_box_max[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)].z |
- FColl_box_min[FSeriesNr, (Fcoll_Nr_objects[FseriesNr] - 1)].z)/2/3; |
Fcoll_frac_at_top[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := 0; //not used |
Fcoll_orientation[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := Forientation3D; |
Fcoll_material[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := Fmaterial3D; |
Fcoll_shootable[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := Fshootable; |
Fcoll_Pickable[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := Fpickable; |
Fcoll_fixed3D[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := FFixed3DObject; |
end; |
|
end; //end of AddSphere |
|
|
|
|
|
procedure TCollisionTester3DX.Addcylinder; |
begin |
//the sphere cowers whole of the 3D-object |
if add_space_for_one_more |
then |
begin |
GetTheBox; |
|
Fcoll_objectnr[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := FIndexOf3DObject; |
Fcoll_shape[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := cylinder3D; |
FNrinFrameSeries[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := FIndexof3Delement; |
case Forientation3D of |
symmetric_x : Fcoll_radius[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := |
(FColl_box_max[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)].y |
- FColl_box_min[FSeriesNr, (Fcoll_Nr_objects[FseriesNr] - 1)].y |
+ FColl_box_max[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)].z |
- FColl_box_min[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)].z)/2/2; |
symmetric_y : Fcoll_radius[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := |
(FColl_box_max[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)].x |
- FColl_box_min[FSeriesNr, (Fcoll_Nr_objects[FseriesNr] - 1)].x |
+ FColl_box_max[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)].z |
- FColl_box_min[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)].z)/2/2; |
symmetric_z : Fcoll_radius[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := |
(FColl_box_max[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)].x |
- FColl_box_min[FSeriesNr, (Fcoll_Nr_objects[FseriesNr] - 1)].x |
+ FColl_box_max[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)].y |
- FColl_box_min[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)].y)/2/2; |
end; |
|
Fcoll_frac_at_top[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := 0; //not used |
Fcoll_orientation[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := Forientation3D; |
Fcoll_material[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := Fmaterial3D; |
Fcoll_shootable[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := Fshootable; |
Fcoll_Pickable[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := Fpickable; |
Fcoll_fixed3D[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := FFixed3DObject; |
end; |
end; //end of Addcylinder |
|
|
|
|
procedure TCollisionTester3DX.Addconus; |
begin |
//the conus cowers whole of or part of the 3D-object |
//fraction_left_at_top = 0 if sharp tip |
if add_space_for_one_more |
then |
begin |
GettheBox; |
|
Fcoll_objectnr[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := FIndexOf3DObject; |
Fcoll_shape[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := conus3D; |
FNrinFrameSeries[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := FIndexof3Delement; |
Fcoll_radius[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := |
(FColl_box_max[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)].x |
- FColl_box_min[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)].x |
+ FColl_box_max[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)].z |
- FColl_box_min[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)].z)/2/2; |
Fcoll_frac_at_top[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := FPercentLeftAtTop/100; |
Fcoll_orientation[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := Forientation3D; |
Fcoll_material[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := Fmaterial3D; |
Fcoll_shootable[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] -1)] := Fshootable; |
Fcoll_Pickable[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := Fpickable; |
Fcoll_fixed3D[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := FFixed3DObject; |
end; |
end; //end of Addconus |
|
|
|
|
procedure TCollisionTester3DX.AddEllipsoid; |
begin |
if add_space_for_one_more |
then |
begin |
GetTheBox; |
Fcoll_objectnr[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := FIndexOf3DObject; |
Fcoll_shape[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := Ellipsoid3D; |
FNrinFrameSeries[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := FIndexof3Delement; |
Fcoll_radius[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := 0; //not used |
Fcoll_frac_at_top[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := 0; //not used |
Fcoll_orientation[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := Forientation3D; |
Fcoll_material[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := Fmaterial3D; |
Fcoll_shootable[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := Fshootable; |
Fcoll_Pickable[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := Fpickable; |
Fcoll_fixed3D[FSeriesNr, (Fcoll_Nr_objects[FSeriesNr] - 1)] := FFixed3DObject; |
end; |
end; //end of AddEllipsoid |
|
|
|
|
|
|
|
function TcollisionTester3DX.GetSeriesNr(Nr : integer): integer; |
var |
NrNow, i : integer; |
begin |
|
if FNrOfSeries = 0 |
then |
NrNow := 0 |
else |
begin |
NrNow := -1; |
for i := 0 to (FNrOfSeries - 1) do |
begin |
if Nr = FSeriesIndex_for_SeriesNr[i] |
then |
NrNow := i; |
end; |
|
if NrNow = -1 |
then |
NrNow := FNrOfSeries; //make new series |
end; |
|
if NrNow = FNrOfSeries |
then |
MakeNewSeries; |
|
|
result := NrNow; |
|
|
end; //end of GetSeriesNr |
|
|
|
|
|
function TcollisionTester3DX.CheckForSeriesIndex(indexnow : integer): boolean; |
var |
i : integer; |
begin |
|
if FNrOfSeries = 0 |
then |
result := false |
else |
begin |
FSeriesNr := -1; |
for i := 0 to (FNrOfSeries - 1) do |
begin |
if indexnow = FSeriesIndex_for_SeriesNr[i] |
then |
FSeriesNr := i; |
end; |
|
result := (FSeriesNr <> -1); |
end; |
|
end; //end of CheckForSeriesIndex |
|
|
|
|
|
procedure TcollisionTester3DX.AddCollisionObject; |
begin |
FSeriesNr := GetSeriesNr(FSeriesIndex); |
|
case Fshape3D of |
box3D : AddBox; |
sphere3D : AddSphere; |
cylinder3D : AddCylinder; |
ellipsoid3D: AddEllipsoid; |
Conus3D : AddConus; |
end; |
|
end; //end of AddCollisionObject |
|
|
|
|
|
function TCollisionTester3DX.DestroyCollisionObject: boolean; |
var |
test_nr : integer; |
begin |
//remove all collision objects connected with the 3D-object |
//with the index FnextDestroyNr |
|
//Check whether series index exists |
if CheckForSeriesIndex(FSeriesIndex) |
then |
begin |
//FSeriesNr was found |
test_nr := 0; |
|
while (test_nr <= (Fcoll_nr_objects[FSeriesNr] - 1)) do |
begin |
if Fcoll_objectnr[FSeriesNr, test_nr] = FnextDestroyNr |
then |
remove_collision_object(FSeriesNr, FnextDestroyNr) |
else |
inc(test_nr); |
end; //end of while loop |
|
//now we have to decrement all Fcoll_objectnr values larger than object_nr |
//because the main program does a similar decrementation when the 3D-object |
//is removed |
|
if Fcoll_nr_objects[FSeriesNr] > 0 |
then |
begin |
//the series is not empty |
for test_nr := 0 to (Fcoll_nr_objects[FSeriesNr] - 1) do |
begin |
if Fcoll_objectnr[FSeriesNr, test_nr] > FNextDestroyNr |
then |
dec(Fcoll_objectnr[FSeriesNr, test_nr]); |
end; |
end |
else |
destroy_empty_Series(FSeriesNr); |
|
|
result := true; //collision object was destroyed |
|
end //end of CheckForSeriesIndex... |
else |
result := false; //unable to destroy |
|
end; //end of DestroyCollisionObject |
|
|
|
|
|
|
function TcollisionTester3DX.coll_test_sphere(coll_nr : byte; |
old_attacker_position, attacker_position : TD3DVector; |
bullet_radius : TD3DValue; longshot : boolean): boolean; |
var |
new_eye, old_eye : TD3DVector; |
dstep, step, center : TD3DVector; |
radius, d0, d1, d2, rod, rod2, t1, t2 : TD3DValue; |
begin |
result := false; |
|
//Get the coordinates of the old eye_position in the actual coll frame |
FFrameSeries[FSeriesIndex, FNrinFrameSeries[FSeriesNr, coll_nr]].InverseTransform |
(old_eye, old_attacker_position); |
|
//Get the coordinates of the eye_position in the actual coll frame |
FFrameSeries[FSeriesIndex, FNrinFrameSeries[FSeriesNr, coll_nr]].InverseTransform |
(new_eye, attacker_position); |
|
center.x := (Fcoll_box_max[FSeriesNr, coll_nr].x |
+ Fcoll_box_min[FSeriesNr, coll_nr].x)/2; |
center.y := (Fcoll_box_max[FSeriesNr, coll_nr].y |
+ Fcoll_box_min[FSeriesNr, coll_nr].y)/2; |
center.z := (Fcoll_box_max[FSeriesNr, coll_nr].z |
+ Fcoll_box_min[FSeriesNr, coll_nr].z)/2; |
|
//radius of sphere enlarged with the radius of the bullet |
//to cover the space where a collision may occure |
radius := Fcoll_radius[FSeriesNr, coll_nr] + bullet_radius; |
|
//eye to center distance |
dstep.x := old_eye.x - center.x; |
dstep.y := old_eye.y - center.y; |
dstep.z := old_eye.z - center.z; |
|
//step in eye position |
step.x := new_eye.x - old_eye.x; |
step.y := new_eye.y - old_eye.y; |
step.z := new_eye.z - old_eye.z; |
|
//collision is only possible when something moves |
if (abs(step.x) < 1e-3) and (abs(step.y) < 1e-3) and (abs(step.z) < 1e-3) |
then |
begin |
result := false; |
exit; |
end; |
|
|
//factors |
d0 := sqr(dstep.x) + sqr(dstep.y) + sqr(dstep.z) - sqr(radius); |
d1 := 2 * (step.x * dstep.x + step.y * dstep.y + step.z * dstep.z); |
d2 := sqr(step.x) + sqr(step.y) + sqr(step.z); |
|
//solving an equation of the second degree |
rod := sqr(d1) - 4 * d2 * d0; |
|
//d2 is never zero |
if rod > 0 |
then |
begin |
rod2 := sqrt(rod); |
t1 := (-d1 - rod2)/2/d2; |
t2 := (-d1 + rod2)/2/d2; |
|
// if longshot then look into all future |
if longshot |
then |
result := (t1 >= 0) or (t2 >= 0) |
else |
begin |
//collision in between the starting and the ending point if |
result := ((t1 >= 0) and (t1 <= 1)) |
or ((t2 >= 0) and (t2 <= 1)); |
end; |
end; |
|
end; //end of coll_test_sphere |
|
|
|
|
function TcollisionTester3DX.coll_test_ellipsoid(coll_nr : byte; |
old_attacker_position, attacker_position : TD3DVector; |
bullet_radius : TD3DValue; longshot : boolean): boolean; |
var |
new_eye, old_eye : TD3DVector; |
dstep, step, center : TD3DVector; |
d0, d1, d2, rod, rod2, t1, t2, a, b, c : TD3DValue; |
begin |
result := false; |
|
//Get the coordinates of the old eye_position in the actual coll frame |
FFrameSeries[FSeriesIndex, FNrinFrameSeries[FSeriesNr, coll_nr]].InverseTransform |
(old_eye, old_attacker_position); |
|
//Get the coordinates of the eye_position in the actual coll frame |
FFrameSeries[FSeriesIndex, FNrinFrameSeries[FSeriesNr, coll_nr]].InverseTransform |
(new_eye, attacker_position); |
|
center.x := (Fcoll_box_max[FSeriesNr, coll_nr].x |
+ Fcoll_box_min[FSeriesNr, coll_nr].x)/2; |
center.y := (Fcoll_box_max[FSeriesNr, coll_nr].y |
+ Fcoll_box_min[FSeriesNr, coll_nr].y)/2; |
center.z := (Fcoll_box_max[FSeriesNr, coll_nr].z |
+ Fcoll_box_min[FSeriesNr, coll_nr].z)/2; |
|
//x, y and z radius of ellipsoid enlarged with the radius of the bullet |
//to cover the space where a collision may occure |
a := (Fcoll_box_max[FSeriesNr, coll_nr].x |
- Fcoll_box_min[FSeriesNr, coll_nr].x)/2 + bullet_radius; |
b := (Fcoll_box_max[FSeriesNr, coll_nr].y |
- Fcoll_box_min[FSeriesNr, coll_nr].y)/2 + bullet_radius; |
c := (Fcoll_box_max[FSeriesNr, coll_nr].z |
- Fcoll_box_min[FSeriesNr, coll_nr].z)/2 + bullet_radius; |
|
//eye to center distance |
dstep.x := old_eye.x - center.x; |
dstep.y := old_eye.y - center.y; |
dstep.z := old_eye.z - center.z; |
|
//step in eye position |
step.x := new_eye.x - old_eye.x; |
step.y := new_eye.y - old_eye.y; |
step.z := new_eye.z - old_eye.z; |
|
//collision is only possible when something moves |
if (abs(step.x) < 1e-3) and (abs(step.y) < 1e-3) and (abs(step.z) < 1e-3) |
then |
begin |
result := false; |
exit; |
end; |
|
|
//factors |
d0 := sqr(b * c * dstep.x) + sqr(a * c * dstep.y) + sqr(a * b * dstep.z) |
- sqr(a * b * c); |
d1 := 2 * (sqr(b * c) * step.x * dstep.x + sqr(a * c) * step.y * dstep.y |
+ sqr(a * b) * step.z * dstep.z); |
d2 := sqr(b * c * step.x) + sqr(a * c * step.y) + sqr(a * b * step.z); |
|
//solving an equation of the second degree |
rod := sqr(d1) - 4 * d2 * d0; |
|
//d2 is never zero |
if rod > 0 |
then |
begin |
rod2 := sqrt(rod); |
t1 := (-d1 - rod2)/2/d2; |
t2 := (-d1 + rod2)/2/d2; |
|
// if longshot then look into all future |
if longshot |
then |
result := (t1 >= 0) or (t2 >= 0) |
else |
begin |
//collision in between the starting and the ending point if |
result := ((t1 >= 0) and (t1 <= 1)) |
or ((t2 >= 0) and (t2 <= 1)); |
end; |
end; |
|
end; //end of coll_test_ellipsoid |
|
|
|
|
|
function TcollisionTester3DX.coll_test_cylinder(coll_nr : byte; |
old_attacker_position, attacker_position : TD3DVector; |
bullet_radius : TD3DValue; longshot : boolean): boolean; |
var |
distance : TD3DValue; |
new_eye, old_eye : TD3DVector; |
dstep, step, center : TD3DVector; |
radius, d0, d1, d2, rod, rod2, t1, t2, xc1, yc1, zc1, xc2, yc2, zc2 : TD3DValue; |
begin |
result := false; |
|
|
//Get the coordinates of the old eye_position in the actual coll frame |
FFrameSeries[FSeriesIndex, FNrinFrameSeries[FSeriesNr, coll_nr]].InverseTransform |
(old_eye, old_attacker_position); |
|
//Get the coordinates of the eye_position in the actual coll frame |
FFrameSeries[FSeriesIndex, FNrinFrameSeries[FSeriesNr, coll_nr]].InverseTransform |
(new_eye, attacker_position); |
|
center.x := (Fcoll_box_max[FSeriesNr, coll_nr].x |
+ Fcoll_box_min[FSeriesNr, coll_nr].x)/2; |
center.y := (Fcoll_box_max[FSeriesNr, coll_nr].y |
+ Fcoll_box_min[FSeriesNr, coll_nr].y)/2; |
center.z := (Fcoll_box_max[FSeriesNr, coll_nr].z |
+ Fcoll_box_min[FSeriesNr, coll_nr].z)/2; |
|
//radius of sphere enlarged with the radius of the bullet |
//to cover the space where a collision may occure |
radius := Fcoll_radius[FSeriesNr, coll_nr] + bullet_radius; |
|
//eye to center distance |
dstep.x := old_eye.x - center.x; |
dstep.y := old_eye.y - center.y; |
dstep.z := old_eye.z - center.z; |
|
//step in eye position |
step.x := new_eye.x - old_eye.x; |
step.y := new_eye.y - old_eye.y; |
step.z := new_eye.z - old_eye.z; |
|
//collision is only possible when something moves |
if (abs(step.x) < 1e-3) and (abs(step.y) < 1e-3) and (abs(step.z) < 1e-3) |
then |
begin |
result := false; |
exit; |
end; |
|
d0 := 1; //just to avoid warnings |
d1 := 1; |
d2 := 1; |
|
|
//The cylinder is alined parallel to the x, y or z axis |
case FOrientation3D of |
symmetric_x : |
begin |
//factors |
d0 := sqr(dstep.y) + sqr(dstep.z) - sqr(radius); |
d1 := 2 * (step.y * dstep.y + step.z * dstep.z); |
d2 := sqr(step.y) + sqr(step.z); |
end; |
symmetric_y : |
begin |
//factors |
d0 := sqr(dstep.x) + sqr(dstep.z) - sqr(radius); |
d1 := 2 * (step.x * dstep.x + step.z * dstep.z); |
d2 := sqr(step.x) + sqr(step.z); |
end; |
symmetric_z : |
begin |
//factors |
d0 := sqr(dstep.x) + sqr(dstep.y) - sqr(radius); |
d1 := 2 * (step.x * dstep.x + step.y * dstep.y); |
d2 := sqr(step.x) + sqr(step.y); |
end; |
end; //end of case FOrientation3D of |
|
|
//solving an equation of the second degree |
rod := sqr(d1) - 4 * d2 * d0; |
|
//d2 is never zero |
if rod >= 0 |
then |
begin |
//only then is the collision possible |
rod2 := sqrt(rod); |
t1 := (-d1 - rod2)/2/d2; |
t2 := (-d1 + rod2)/2/d2; |
|
// if longshot then look into all future |
if longshot |
then |
result := (t1 >= 0) or (t2 >= 0) |
else |
begin |
//collision in between the starting and the ending point if |
result := ((t1 >= 0) and (t1 <= 1)) |
or ((t2 >= 0) and (t2 <= 1)); |
end; |
|
// however the collision also affords that we are within the length of the cylinder |
if result then |
begin |
case FOrientation3D of |
symmetric_x : |
begin |
xc1 := old_eye.x + t1 * step.x; |
xc2 := old_eye.x + t2 * step.x; |
|
|
if longshot |
then |
result := |
(result and (t1 >= 0) and |
(xc1 >= (Fcoll_box_min[FseriesNr, coll_nr].x - bullet_radius)) and |
(xc1 <= (Fcoll_box_max[FseriesNr, coll_nr].x + bullet_radius)) ) |
or |
(result and (t2 >= 0) and |
(xc2 >= (Fcoll_box_min[FseriesNr, coll_nr].x - bullet_radius)) and |
(xc2 <= (Fcoll_box_max[FseriesNr, coll_nr].x + bullet_radius)) ) |
else |
result := |
(result and (t1 >= 0) and (t1 <= 1) and |
(xc1 >= (Fcoll_box_min[FseriesNr, coll_nr].x - bullet_radius)) and |
(xc1 <= (Fcoll_box_max[FseriesNr, coll_nr].x + bullet_radius)) ) |
or |
(result and (t2 >= 0) and (t2 <= 1) and |
(xc2 >= (Fcoll_box_min[FseriesNr, coll_nr].x - bullet_radius)) and |
(xc2 <= (Fcoll_box_max[FseriesNr, coll_nr].x + bullet_radius)) ); |
|
//if collision detected then exit now |
if result then exit; |
|
end; |
symmetric_y : |
begin |
yc1 := old_eye.y + t1 * step.y; |
yc2 := old_eye.y + t2 * step.y; |
|
|
if longshot |
then |
result := |
(result and (t1 >= 0) and |
(yc1 >= (Fcoll_box_min[FseriesNr, coll_nr].y - bullet_radius)) and |
(yc1 <= (Fcoll_box_max[FseriesNr, coll_nr].y + bullet_radius)) ) |
or |
(result and (t2 >= 0) and |
(yc2 >= (Fcoll_box_min[FseriesNr, coll_nr].y - bullet_radius)) and |
(yc2 <= (Fcoll_box_max[FseriesNr, coll_nr].y + bullet_radius)) ) |
else |
result := |
(result and (t1 >= 0) and (t1 <= 1) and |
(yc1 >= (Fcoll_box_min[FseriesNr, coll_nr].y - bullet_radius)) and |
(yc1 <= (Fcoll_box_max[FseriesNr, coll_nr].y + bullet_radius)) ) |
or |
(result and (t2 >= 0) and (t2 <= 1) and |
(yc2 >= (Fcoll_box_min[FseriesNr, coll_nr].y - bullet_radius)) and |
(yc2 <= (Fcoll_box_max[FseriesNr, coll_nr].y + bullet_radius)) ); |
|
//if collision detected then exit now |
if result then exit; |
|
|
end; |
symmetric_z : |
begin |
zc1 := old_eye.z + t1 * step.z; |
zc2 := old_eye.z + t2 * step.z; |
|
|
if longshot |
then |
result := |
(result and (t1 >= 0) and |
(zc1 >= (Fcoll_box_min[FseriesNr, coll_nr].z - bullet_radius)) and |
(zc1 <= (Fcoll_box_max[FseriesNr, coll_nr].z + bullet_radius)) ) |
or |
(result and (t2 >= 0) and |
(zc2 >= (Fcoll_box_min[FseriesNr, coll_nr].z - bullet_radius)) and |
(zc2 <= (Fcoll_box_max[FseriesNr, coll_nr].z + bullet_radius)) ) |
else |
result := |
(result and (t1 >= 0) and (t1 <= 1) and |
(zc1 >= (Fcoll_box_min[FseriesNr, coll_nr].z - bullet_radius)) and |
(zc1 <= (Fcoll_box_max[FseriesNr, coll_nr].z + bullet_radius)) ) |
or |
(result and (t2 >= 0) and (t2 <= 1) and |
(zc2 >= (Fcoll_box_min[FseriesNr, coll_nr].z - bullet_radius)) and |
(zc2 <= (Fcoll_box_max[FseriesNr, coll_nr].z + bullet_radius)) ); |
|
//if collision detected then exit now |
if result then exit; |
end; |
|
end; //end of case |
end; |
|
//exit if a collision occured |
if result then exit; |
end; |
|
|
//the collision may also occur with the end surfaces of the cylinder |
case FOrientation3D of |
symmetric_x : |
begin |
if step.x > 1e-6 |
then |
begin |
//1st end surface |
t1 := (Fcoll_box_min[FseriesNr, coll_Nr].x - old_eye.x)/step.x; |
yc1 := old_eye.y + t1 * step.y; |
zc1 := old_eye.z + t1 * step.z; |
|
distance := sqrt( sqr(yc1 - center.y) + sqr(zc1 - center.z) ); |
|
result := (distance < radius) and (t1 >= 0); |
if not longshot then result := result and (t1 <= 1); |
if result then exit; |
|
//2nd end surface |
t1 := (Fcoll_box_max[FseriesNr, coll_Nr].x - old_eye.x)/step.x; |
yc1 := old_eye.y + t1 * step.y; |
zc1 := old_eye.z + t1 * step.z; |
|
distance := sqrt( sqr(yc1 - center.y) + sqr(zc1 - center.z) ); |
|
result := (distance < radius) and (t1 >= 0); |
if not longshot then result := result and (t1 <= 1); |
if result then exit; |
end; |
end; |
symmetric_y : |
begin |
if step.y > 1e-6 |
then |
begin |
//1st end surface |
t1 := (Fcoll_box_min[FseriesNr, coll_Nr].y - old_eye.y)/step.y; |
xc1 := old_eye.x + t1 * step.x; |
zc1 := old_eye.z + t1 * step.z; |
|
distance := sqrt( sqr(xc1 - center.x) + sqr(zc1 - center.z) ); |
|
result := (distance < radius) and (t1 >= 0); |
if not longshot then result := result and (t1 <= 1); |
if result then exit; |
|
//2nd end surface |
t1 := (Fcoll_box_max[FseriesNr, coll_Nr].y - old_eye.y)/step.y; |
xc1 := old_eye.x + t1 * step.x; |
zc1 := old_eye.z + t1 * step.z; |
|
distance := sqrt( sqr(xc1 - center.x) + sqr(zc1 - center.z) ); |
|
result := (distance < radius) and (t1 >= 0); |
if not longshot then result := result and (t1 <= 1); |
if result then exit; |
end; |
|
end; |
symmetric_z : |
begin |
if step.z > 1e-6 |
then |
begin |
//1st end surface |
t1 := (Fcoll_box_min[FseriesNr, coll_Nr].z - old_eye.z)/step.z; |
xc1 := old_eye.x + t1 * step.x; |
yc1 := old_eye.y + t1 * step.y; |
|
distance := sqrt( sqr(xc1 - center.x) + sqr(yc1 - center.y) ); |
|
result := (distance < radius) and (t1 >= 0); |
if not longshot then result := result and (t1 <= 1); |
if result then exit; |
|
//2nd end surface |
t1 := (Fcoll_box_max[FseriesNr, coll_Nr].z - old_eye.z)/step.z; |
xc1 := old_eye.x + t1 * step.x; |
yc1 := old_eye.y + t1 * step.y; |
|
distance := sqrt( sqr(xc1 - center.x) + sqr(yc1 - center.y) ); |
|
result := (distance < radius) and (t1 >= 0); |
if not longshot then result := result and (t1 <= 1); |
if result then exit; |
end; |
|
end; |
|
|
end; //end of case |
|
end; //end of coll_test_cylinder |
|
|
|
|
|
function TcollisionTester3DX.coll_test_conus(coll_nr : byte; |
old_attacker_position, attacker_position : TD3DVector; |
bullet_radius : TD3DValue; longshot : boolean): boolean; |
var |
height3D, width3D : TD3DValue; |
distance : TD3DValue; |
new_eye, old_eye : TD3DVector; |
dstep, step, center : TD3DVector; |
radius, d0, d1, d2, rod, rod2, t1, t2, xc1, yc1, zc1, xc2, yc2, zc2 : TD3DValue; |
xc, yc, zc, conusfact : TD3DValue; |
begin |
result := false; |
|
//Get the coordinates of the old eye_position in the actual coll frame |
FFrameSeries[FSeriesIndex, FNrinFrameSeries[FSeriesNr, coll_nr]].InverseTransform |
(old_eye, old_attacker_position); |
|
//Get the coordinates of the eye_position in the actual coll frame |
FFrameSeries[FSeriesIndex, FNrinFrameSeries[FSeriesNr, coll_nr]].InverseTransform |
(new_eye, attacker_position); |
|
center.x := (Fcoll_box_max[FSeriesNr, coll_nr].x |
+ Fcoll_box_min[FSeriesNr, coll_nr].x)/2; |
center.y := (Fcoll_box_max[FSeriesNr, coll_nr].y |
+ Fcoll_box_min[FSeriesNr, coll_nr].y)/2; |
center.z := (Fcoll_box_max[FSeriesNr, coll_nr].z |
+ Fcoll_box_min[FSeriesNr, coll_nr].z)/2; |
|
|
//step in eye position |
step.x := new_eye.x - old_eye.x; |
step.y := new_eye.y - old_eye.y; |
step.z := new_eye.z - old_eye.z; |
|
//collision is only possible when something moves |
if (abs(step.x) < 1e-3) and (abs(step.y) < 1e-3) and (abs(step.z) < 1e-3) |
then |
begin |
result := false; |
exit; |
end; |
|
//if FPercentLeftatTop is positiv then the conus is largest at the bottom |
xc := center.x; |
yc := center.y; |
zc := center.z; |
|
width3D := 10; //just to avoid warnings |
height3D := 10; |
|
case FOrientation3D of |
symmetric_x : |
begin |
height3D := Fcoll_box_max[FSeriesNr, coll_nr].x |
- Fcoll_box_min[FSeriesNr, coll_nr].x; |
width3D := (Fcoll_box_max[FSeriesNr, coll_Nr].y |
- Fcoll_box_min[FSeriesNr, coll_nr].y |
+ Fcoll_box_max[FSeriesNr, coll_nr].z |
- Fcoll_box_min[FSeriesNr, coll_nr].z)/2; |
|
//the top of the conus is maller than the bottom of it |
if FPercentLeftatTop >= 0 |
then |
xc := center.x - height3D/2 + 100 * height3D/(100 - FpercentLeftatTop) |
else |
xc := center.x + height3D/2 - 100 * height3D/(100 + FpercentLeftatTop); |
end; //end of symmetric_x |
symmetric_y : |
begin |
height3D := Fcoll_box_max[FSeriesNr, coll_nr].y |
- Fcoll_box_min[FSeriesNr, coll_nr].y; |
width3D := (Fcoll_box_max[FSeriesNr, coll_Nr].x |
- Fcoll_box_min[FSeriesNr, coll_nr].x |
+ Fcoll_box_max[FSeriesNr, coll_nr].z |
- Fcoll_box_min[FSeriesNr, coll_nr].z)/2; |
|
//the top of the conus is maller than the bottom of it |
if FPercentLeftatTop >= 0 |
then |
yc := center.y - height3D/2 + 100 * height3D/(100 - FpercentLeftatTop) |
else |
yc := center.y + height3D/2 - 100 * height3D/(100 + FpercentLeftatTop); |
end; //end of symmetric_y |
symmetric_z : |
begin |
height3D := Fcoll_box_max[FSeriesNr, coll_nr].z |
- Fcoll_box_min[FSeriesNr, coll_nr].z; |
width3D := (Fcoll_box_max[FSeriesNr, coll_Nr].x |
- Fcoll_box_min[FSeriesNr, coll_nr].x |
+ Fcoll_box_max[FSeriesNr, coll_nr].y |
- Fcoll_box_min[FSeriesNr, coll_nr].y)/2; |
|
//the top of the conus is maller than the bottom of it |
if FPercentLeftatTop >= 0 |
then |
zc := center.z - height3D/2 + 100 * height3D/(100 - FpercentLeftatTop) |
else |
zc := center.z + height3D/2 - 100 * height3D/(100 + FpercentLeftatTop); |
end; //end of symmetric_z |
end; //end of case |
|
//mathematically we need the conusfact describing the ratio between the radius of |
//the large end of the conus and the height of the conus |
if width3D > 0 |
then |
conusfact := height3D/2/width3D |
else |
conusfact := 1e9; |
|
//eye to the fictive tip of the conus distance |
dstep.x := old_eye.x - xc; |
dstep.y := old_eye.y - yc; |
dstep.z := old_eye.z - zc; |
|
d0 := 1; //just to avoid warnings |
d1 := 1; |
d2 := 1; |
|
//The conus is aligned parallel to the x, y or z axis |
case FOrientation3D of |
symmetric_x : |
begin |
//factors |
d0 := sqr(dstep.y) + sqr(dstep.z) - sqr(dstep.x * conusfact); |
d1 := 2 * (step.y * dstep.y + step.z * dstep.z |
- sqr(conusfact) * step.x * dstep.x); |
d2 := sqr(step.y) + sqr(step.z) - sqr(conusfact * step.x); |
end; |
symmetric_y : |
begin |
//factors |
d0 := sqr(dstep.x) + sqr(dstep.z) - sqr(dstep.y * conusfact); |
d1 := 2 * (step.x * dstep.x + step.z * dstep.z |
- sqr(conusfact) * step.y * dstep.y); |
d2 := sqr(step.x) + sqr(step.z) - sqr(conusfact * step.y); |
end; |
symmetric_z : |
begin |
//factors |
d0 := sqr(dstep.x) + sqr(dstep.y) - sqr(dstep.z * conusfact); |
d1 := 2 * (step.x * dstep.x + step.y * dstep.y |
- sqr(conusfact) * step.z * dstep.z); |
d2 := sqr(step.x) + sqr(step.y) - sqr(conusfact * step.z); |
end; |
end; //end of case FOrientation3D of |
|
|
//solving an equation of the second degree |
rod := sqr(d1) - 4 * d2 * d0; |
|
//d2 is never zero |
if rod >= 0 |
then |
begin |
//only then is the collision possible |
rod2 := sqrt(rod); |
t1 := (-d1 - rod2)/2/d2; |
t2 := (-d1 + rod2)/2/d2; |
|
// if longshot then look into all future |
if longshot |
then |
result := (t1 >= 0) or (t2 >= 0) |
else |
begin |
//collision in between the starting and the ending point if |
result := ((t1 >= 0) and (t1 <= 1)) |
or ((t2 >= 0) and (t2 <= 1)); |
end; |
|
// however the collision also affords that we are within the length of the conus |
if result then |
begin |
case FOrientation3D of |
symmetric_x : |
begin |
xc1 := old_eye.x + t1 * step.x; |
xc2 := old_eye.x + t2 * step.x; |
|
|
if longshot |
then |
result := |
(result and (t1 >= 0) and |
(xc1 >= (Fcoll_box_min[FseriesNr, coll_nr].x - bullet_radius)) and |
(xc1 <= (Fcoll_box_max[FseriesNr, coll_nr].x + bullet_radius)) ) |
or |
(result and (t2 >= 0) and |
(xc2 >= (Fcoll_box_min[FseriesNr, coll_nr].x - bullet_radius)) and |
(xc2 <= (Fcoll_box_max[FseriesNr, coll_nr].x + bullet_radius)) ) |
else |
result := |
(result and (t1 >= 0) and (t1 <= 1) and |
(xc1 >= (Fcoll_box_min[FseriesNr, coll_nr].x - bullet_radius)) and |
(xc1 <= (Fcoll_box_max[FseriesNr, coll_nr].x + bullet_radius)) ) |
or |
(result and (t2 >= 0) and (t2 <= 1) and |
(xc2 >= (Fcoll_box_min[FseriesNr, coll_nr].x - bullet_radius)) and |
(xc2 <= (Fcoll_box_max[FseriesNr, coll_nr].x + bullet_radius)) ); |
|
//if collision detected then exit now |
if result then exit; |
|
end; |
symmetric_y : |
begin |
yc1 := old_eye.y + t1 * step.y; |
yc2 := old_eye.y + t2 * step.y; |
|
|
if longshot |
then |
result := |
(result and (t1 >= 0) and |
(yc1 >= (Fcoll_box_min[FseriesNr, coll_nr].y - bullet_radius)) and |
(yc1 <= (Fcoll_box_max[FseriesNr, coll_nr].y + bullet_radius)) ) |
or |
(result and (t2 >= 0) and |
(yc2 >= (Fcoll_box_min[FseriesNr, coll_nr].y - bullet_radius)) and |
(yc2 <= (Fcoll_box_max[FseriesNr, coll_nr].y + bullet_radius)) ) |
else |
result := |
(result and (t1 >= 0) and (t1 <= 1) and |
(yc1 >= (Fcoll_box_min[FseriesNr, coll_nr].y - bullet_radius)) and |
(yc1 <= (Fcoll_box_max[FseriesNr, coll_nr].y + bullet_radius)) ) |
or |
(result and (t2 >= 0) and (t2 <= 1) and |
(yc2 >= (Fcoll_box_min[FseriesNr, coll_nr].y - bullet_radius)) and |
(yc2 <= (Fcoll_box_max[FseriesNr, coll_nr].y + bullet_radius)) ); |
|
//if collision detected then exit now |
if result then exit; |
|
|
end; |
symmetric_z : |
begin |
zc1 := old_eye.z + t1 * step.z; |
zc2 := old_eye.z + t2 * step.z; |
|
|
if longshot |
then |
result := |
(result and (t1 >= 0) and |
(zc1 >= (Fcoll_box_min[FseriesNr, coll_nr].z - bullet_radius)) and |
(zc1 <= (Fcoll_box_max[FseriesNr, coll_nr].z + bullet_radius)) ) |
or |
(result and (t2 >= 0) and |
(zc2 >= (Fcoll_box_min[FseriesNr, coll_nr].z - bullet_radius)) and |
(zc2 <= (Fcoll_box_max[FseriesNr, coll_nr].z + bullet_radius)) ) |
else |
result := |
(result and (t1 >= 0) and (t1 <= 1) and |
(zc1 >= (Fcoll_box_min[FseriesNr, coll_nr].z - bullet_radius)) and |
(zc1 <= (Fcoll_box_max[FseriesNr, coll_nr].z + bullet_radius)) ) |
or |
(result and (t2 >= 0) and (t2 <= 1) and |
(zc2 >= (Fcoll_box_min[FseriesNr, coll_nr].z - bullet_radius)) and |
(zc2 <= (Fcoll_box_max[FseriesNr, coll_nr].z + bullet_radius)) ); |
|
//if collision detected then exit now |
if result then exit; |
end; |
|
end; //end of case |
end; |
|
//exit if a collision occured |
if result then exit; |
end; |
|
|
//the collision may also occur with the end surfaces of the cylinder |
case FOrientation3D of |
symmetric_x : |
begin |
if step.x > 1e-6 |
then |
begin |
//1st end surface |
t1 := (Fcoll_box_min[FseriesNr, coll_Nr].x - old_eye.x)/step.x; |
yc1 := old_eye.y + t1 * step.y; |
zc1 := old_eye.z + t1 * step.z; |
|
distance := sqrt( sqr(yc1 - center.y) + sqr(zc1 - center.z) ); |
|
if FPercentLeftatTop >= 0 |
then |
radius := width3D/2 //the large end of the conus is down |
else |
radius := -width3D/2 * FPercentLeftatTop; |
|
radius := radius + bullet_radius; |
|
result := (distance < radius) and (t1 >= 0); |
if not longshot then result := result and (t1 <= 1); |
if result then exit; |
|
//2nd end surface |
t1 := (Fcoll_box_max[FseriesNr, coll_Nr].x - old_eye.x)/step.x; |
yc1 := old_eye.y + t1 * step.y; |
zc1 := old_eye.z + t1 * step.z; |
|
distance := sqrt( sqr(yc1 - center.y) + sqr(zc1 - center.z) ); |
|
if FPercentLeftatTop >= 0 |
then |
radius := width3D/2 * FPercentLeftatTop //the small end of the conus is upwards |
else |
radius := width3D/2; |
|
radius := radius + bullet_radius; |
|
result := (distance < radius) and (t1 >= 0); |
if not longshot then result := result and (t1 <= 1); |
if result then exit; |
end; |
end; |
symmetric_y : |
begin |
if step.y > 1e-6 |
then |
begin |
//1st end surface |
t1 := (Fcoll_box_min[FseriesNr, coll_Nr].y - old_eye.y)/step.y; |
xc1 := old_eye.x + t1 * step.x; |
zc1 := old_eye.z + t1 * step.z; |
|
distance := sqrt( sqr(xc1 - center.x) + sqr(zc1 - center.z) ); |
|
if FPercentLeftatTop >= 0 |
then |
radius := width3D/2 //the large end of the conus is down |
else |
radius := -width3D/2 * FPercentLeftatTop; |
|
radius := radius + bullet_radius; |
|
result := (distance < radius) and (t1 >= 0); |
if not longshot then result := result and (t1 <= 1); |
if result then exit; |
|
//2nd end surface |
t1 := (Fcoll_box_max[FseriesNr, coll_Nr].y - old_eye.y)/step.y; |
xc1 := old_eye.x + t1 * step.x; |
zc1 := old_eye.z + t1 * step.z; |
|
distance := sqrt( sqr(xc1 - center.x) + sqr(zc1 - center.z) ); |
|
if FPercentLeftatTop >= 0 |
then |
radius := width3D/2 * FPercentLeftatTop //the small end of the conus is upwards |
else |
radius := width3D/2; |
|
radius := radius + bullet_radius; |
|
result := (distance < radius) and (t1 >= 0); |
if not longshot then result := result and (t1 <= 1); |
if result then exit; |
end; |
|
end; |
symmetric_z : |
begin |
if step.z > 1e-6 |
then |
begin |
//1st end surface |
t1 := (Fcoll_box_min[FseriesNr, coll_Nr].z - old_eye.z)/step.z; |
xc1 := old_eye.x + t1 * step.x; |
yc1 := old_eye.y + t1 * step.y; |
|
distance := sqrt( sqr(xc1 - center.x) + sqr(yc1 - center.y) ); |
|
if FPercentLeftatTop >= 0 |
then |
radius := width3D/2 //the large end of the conus is down |
else |
radius := width3D/2 * FPercentLeftatTop; |
|
radius := radius + bullet_radius; |
|
result := (distance < radius) and (t1 >= 0); |
if not longshot then result := result and (t1 <= 1); |
if result then exit; |
|
//2nd end surface |
t1 := (Fcoll_box_max[FseriesNr, coll_Nr].z - old_eye.z)/step.z; |
xc1 := old_eye.x + t1 * step.x; |
yc1 := old_eye.y + t1 * step.y; |
|
distance := sqrt( sqr(xc1 - center.x) + sqr(yc1 - center.y) ); |
|
if FPercentLeftatTop >= 0 |
then |
radius := -width3D/2 * FPercentLeftatTop //the small end of the conus is upwards |
else |
radius := width3D/2; |
|
radius := radius + bullet_radius; |
|
result := (distance < radius) and (t1 >= 0); |
if not longshot then result := result and (t1 <= 1); |
if result then exit; |
end; |
|
end; |
|
|
end; //end of case |
|
|
end; //end of coll_test_conus |
|
|
|
|
function TcollisionTester3DX.coll_test_box(coll_nr : byte; |
old_attacker_position, attacker_position : TD3DVector; |
bullet_radius : TD3DValue; longshot : boolean): boolean; |
var |
new_eye, old_eye : TD3DVector; |
step : TD3DVector; |
t1, xc, yc, zc : TD3DValue; |
begin |
result := false; |
|
//Get the coordinates of the old eye_position in the actual coll frame |
FFrameSeries[FSeriesIndex, FNrinFrameSeries[FSeriesNr, coll_nr]].InverseTransform |
(old_eye, old_attacker_position); |
|
//Get the coordinates of the eye_position in the actual coll frame |
FFrameSeries[FSeriesIndex, FNrinFrameSeries[FSeriesNr, coll_nr]].InverseTransform |
(new_eye, attacker_position); |
|
//step in eye position |
step.x := new_eye.x - old_eye.x; |
step.y := new_eye.y - old_eye.y; |
step.z := new_eye.z - old_eye.z; |
|
//collision is only possible when something moves |
if (abs(step.x) < 1e-3) and (abs(step.y) < 1e-3) and (abs(step.z) < 1e-3) |
then |
begin |
result := false; |
exit; |
end; |
|
//check the surfaces which are normal to the x-axis |
if abs(step.x) >= 1E-6 |
then |
begin |
//test 1st surface |
t1 := (Fcoll_box_min[FseriesNr, coll_nr].x - old_eye.x)/step.x; |
//collision point |
zc := old_eye.z + t1 * step.z; |
yc := old_eye.y + t1 * step.y; |
|
//collision if the collision point is close enough to the surface |
result := |
(zc >= (Fcoll_box_min[FseriesNr, coll_nr].z - bullet_radius)) and |
(zc <= (Fcoll_box_max[FseriesNr, coll_nr].z + bullet_radius)) and |
(yc >= (Fcoll_box_min[FseriesNr, coll_nr].y - bullet_radius)) and |
(yc <= (Fcoll_box_max[FseriesNr, coll_nr].y + bullet_radius)); |
|
if longshot |
then result := result and (t1 >= 0) |
else result := result and (t1 >= 0) and (t1 <= 1); |
|
//if collision detected then exit now |
if result then exit; |
|
//test 2nd surface |
t1 := (Fcoll_box_max[FseriesNr, coll_nr].x - old_eye.x)/step.x; |
//collision point |
zc := old_eye.z + t1 * step.z; |
yc := old_eye.y + t1 * step.y; |
|
//collision if the collision point is close enough to the surface |
result := |
(zc >= (Fcoll_box_min[FseriesNr, coll_nr].z - bullet_radius)) and |
(zc <= (Fcoll_box_max[FseriesNr, coll_nr].z + bullet_radius)) and |
(yc >= (Fcoll_box_min[FseriesNr, coll_nr].y - bullet_radius)) and |
(yc <= (Fcoll_box_max[FseriesNr, coll_nr].y + bullet_radius)); |
|
if longshot |
then result := result and (t1 >= 0) |
else result := result and (t1 >= 0) and (t1 <= 1); |
|
//if collision detected then exit now |
if result then exit; |
|
end; //end of step.x <> 0 |
|
|
//check the surfaces which are normal to the y-axis |
if abs(step.y) >= 1E-6 |
then |
begin |
//test 1st surface |
t1 := (Fcoll_box_min[FseriesNr, coll_nr].y - old_eye.y)/step.y; |
//collision point |
xc := old_eye.x + t1 * step.x; |
zc := old_eye.z + t1 * step.z; |
|
//collision if the collision point is close enough to the surface |
result := |
(xc >= (Fcoll_box_min[FseriesNr, coll_nr].x - bullet_radius)) and |
(xc <= (Fcoll_box_max[FseriesNr, coll_nr].x + bullet_radius)) and |
(zc >= (Fcoll_box_min[FseriesNr, coll_nr].z - bullet_radius)) and |
(zc <= (Fcoll_box_max[FseriesNr, coll_nr].z + bullet_radius)); |
|
if longshot |
then result := result and (t1 >= 0) |
else result := result and (t1 >= 0) and (t1 <= 1); |
|
//if collision detected then exit now |
if result then exit; |
|
//test 2nd surface |
t1 := (Fcoll_box_max[FseriesNr, coll_nr].y - old_eye.y)/step.y; |
//collision point |
xc := old_eye.x + t1 * step.x; |
zc := old_eye.z + t1 * step.z; |
|
//collision if the collision point is close enough to the surface |
result := |
(xc >= (Fcoll_box_min[FseriesNr, coll_nr].x - bullet_radius)) and |
(xc <= (Fcoll_box_max[FseriesNr, coll_nr].x + bullet_radius)) and |
(zc >= (Fcoll_box_min[FseriesNr, coll_nr].z - bullet_radius)) and |
(zc <= (Fcoll_box_max[FseriesNr, coll_nr].z + bullet_radius)); |
|
if longshot |
then result := result and (t1 >= 0) |
else result := result and (t1 >= 0) and (t1 <= 1); |
|
//if collision detected then exit now |
if result then exit; |
|
end; //end of step.y <> 0 |
|
|
|
//check the surfaces which are normal to the z-axis |
if abs(step.z) >= 1E-6 |
then |
begin |
//test 1st surface |
t1 := (Fcoll_box_min[FseriesNr, coll_nr].z - old_eye.z)/step.z; |
//collision point |
xc := old_eye.x + t1 * step.x; |
yc := old_eye.y + t1 * step.y; |
|
//collision if the collision point is close enough to the surface |
result := |
(xc >= (Fcoll_box_min[FseriesNr, coll_nr].x - bullet_radius)) and |
(xc <= (Fcoll_box_max[FseriesNr, coll_nr].x + bullet_radius)) and |
(yc >= (Fcoll_box_min[FseriesNr, coll_nr].y - bullet_radius)) and |
(yc <= (Fcoll_box_max[FseriesNr, coll_nr].y + bullet_radius)); |
|
if longshot |
then result := result and (t1 >= 0) |
else result := result and (t1 >= 0) and (t1 <= 1); |
|
//if collision detected then exit now |
if result then exit; |
|
//test 2nd surface |
t1 := (Fcoll_box_max[FseriesNr, coll_nr].z - old_eye.z)/step.z; |
//collision point |
xc := old_eye.x + t1 * step.x; |
yc := old_eye.y + t1 * step.y; |
|
//collision if the collision point is close enough to the surface |
result := |
(xc >= (Fcoll_box_min[FseriesNr, coll_nr].x - bullet_radius)) and |
(xc <= (Fcoll_box_max[FseriesNr, coll_nr].x + bullet_radius)) and |
(yc >= (Fcoll_box_min[FseriesNr, coll_nr].y - bullet_radius)) and |
(yc <= (Fcoll_box_max[FseriesNr, coll_nr].y + bullet_radius)); |
|
if longshot |
then result := result and (t1 >= 0) |
else result := result and (t1 >= 0) and (t1 <= 1); |
|
//if collision detected then exit now |
if result then exit; |
|
end; //end of step.z <> 0 |
|
|
end; //end of coll_test_box |
|
|
|
|
|
|
function TCollisionTester3DX.BulletDead:boolean; |
var |
camera_position, bullet_position : TD3DVector; |
Distance : TD3DValue; |
begin |
FBulletFrame.GetPosition(FDXDrawUsed.Scene, bullet_position); |
FDXDrawUsed.Camera.GetPosition(FDXDrawUsed.Scene, camera_position); |
|
Distance := sqr(Bullet_position.x - camera_position.x) |
+ sqr(Bullet_position.y - camera_position.y) |
+ sqr(Bullet_position.z - camera_position.z); |
|
//remove the bullet if it is beyond the bulletrange or if it is a longshot |
result := (sqrt(Distance) > FBulletRange) or FLongShots; |
|
end; //end of BulletDead |
|
|
|
|
//use this function to check whether the camera or an object in a distance of |
// -from camera- from the camera collides with any collision object |
function TCollisionTester3DX.collision: boolean; |
var |
i : integer; |
camera_position, camera_direction, camera_up : TD3DVECTOR; |
eye_position : TD3DVector; |
begin |
Result := false; |
FBullet_HitlinkNr := -1; |
|
if CheckForSeriesIndex(FSeriesIndex) |
then |
begin |
//The series exists |
if Fcoll_Nr_objects[FSeriesNr] > 0 |
then |
begin |
//The series is not empty |
|
//Get the position of the camera |
FDXDrawUsed.Camera.GetPosition(FDXDrawUsed.Scene, camera_position); |
FDXDrawUsed.camera.GetOrientation(FDXDrawUsed.scene, camera_direction, camera_up); |
//calculate the eye position |
eye_position.x := camera_position.x + FFrontDistance * camera_direction.x; |
eye_position.y := camera_position.y + FFrontDistance * camera_direction.y; |
eye_position.z := camera_position.z + FFrontDistance * camera_direction.z; |
|
//test whether the eye collides with any of the collision objects |
i := 0; |
while (not result) and (i < Fcoll_nr_objects[FSeriesNr]) do //0.. |
begin |
case Fcoll_shape[FSeriesNr, i] of |
box3D : Result := coll_test_box(i, FOldEyePosition, |
eye_position, FHeadRadius, false); |
sphere3D : Result := coll_test_sphere(i, FOldEyePosition, |
eye_position, FHeadRadius, false); |
cylinder3D : Result := coll_test_cylinder(i, FOldEyePosition, |
eye_position, FHeadRadius, false); |
ellipsoid3D: Result := coll_test_ellipsoid(i, FOldEyePosition, |
eye_position, FHeadRadius, false); |
conus3D : Result := coll_test_conus(i, FOldEyePosition, |
eye_position, FHeadRadius, false); |
end; |
|
if result then Fbullet_hitLinkNr := Fcoll_objectnr[FseriesNr, i]; |
inc(i); |
end; |
end; |
end; //end of if checkforseriesIndex |
|
if result |
then |
ListDataForCollObject; |
|
end; //end of collision |
|
|
|
|
|
|
|
//use this function to check whether an object sent from the camera collides |
//with any collision object |
function TCollisionTester3DX.BulletCollision: boolean; |
var |
i: integer; |
bullet_position : TD3DVector; |
begin |
Result := false; |
FBullet_HitLinkNr := -1; |
|
if checkForSeriesIndex(FSeriesIndex) |
then |
begin |
//Series exists |
|
//test whether eye collides with any of the collision objects |
if Fcoll_Nr_objects[FSeriesNr] > 0 |
then |
begin |
//Get position of the bullet |
FBulletFrame.GetPosition(FDXDrawUsed.Scene, bullet_position); |
i := 0; |
|
while (not result) and (i < Fcoll_Nr_objects[FSeriesNr]) do //0.. |
begin |
if FColl_Shootable[FseriesNr, i] or |
(FColl_material[FSeriesNr, i] = solid3D) |
then |
begin |
case Fcoll_shape[FSeriesNr, i] of |
box3D : result := coll_test_box(i, FOldBulletPosition, |
bullet_position, |
FBulletRadius, FLongShots); |
sphere3D : result := coll_test_sphere(i, FOldBulletPosition, |
bullet_position, |
FBulletRadius, FLongShots); |
cylinder3D : result := coll_test_cylinder(i, FOldBulletPosition, |
bullet_position, |
FBulletRadius, FLongShots); |
ellipsoid3D: result := coll_test_ellipsoid(i, FOldBulletPosition, |
bullet_position, |
FBulletRadius, FLongShots); |
conus3D : result := coll_test_conus(i, FOldBulletPosition, |
bullet_position, |
FBulletRadius, FLongShots); |
end; //end case |
end; //end of if.. |
|
if result |
then |
FBullet_HitLinkNr := Fcoll_ObjectNr[FSeriesNr, i]; |
|
inc(i); |
end; //end of while |
|
if result |
then |
ListDataForCollObject; |
|
end; //end if Fcoll_Nr_ob.... |
end; //end if checkForSeriesIndex... |
|
end; //end of bullet_collision |
|
|
|
|
procedure TCollisionTester3DX.GetOldBulletPos; |
begin |
FbulletFrame.GetPosition(FDXDrawUsed.Scene, FOldBulletPosition); |
end; //end of GetOldBulletPos |
|
|
procedure TCollisionTester3DX.GetOldEyePos; |
var |
OldPos, camera_direction, camera_up : TD3DVector; |
begin |
FDXDrawUsed.Camera.GetPosition(FDXDrawUsed.Scene, OldPos); |
FDXDrawUsed.Camera.GetOrientation(FDXDrawUsed.Scene, camera_direction, camera_up); |
|
FOldEyePosition.x := OldPos.x + FFrontDistance * camera_direction.x; |
FOldEyePosition.y := OldPos.y + FFrontDistance * camera_direction.y; |
FOldEyePosition.z := OldPos.z + FFrontDistance * camera_direction.z; |
|
end; //end of GetOldEyePos |
|
|
|
|
|
|
end. |