I studied the part and examples of TRigidbody to understand the collision method.
What I do not understand is how to add an event that happens when two scenes collide.
–
I studied the part and examples of TRigidbody to understand the collision method.
What I do not understand is how to add an event that happens when two scenes collide.
–
Haven’t tried TRigidBody myself, but from the document there’re 3 events that may interest you:
OnCollisionEnter
: Occurs when start collide with another TRigidBodyOnCollisionExit
: Occurs when stop collide with another TRigidBodyOnCollisionStay
: Occurs when still collide with another TRigidBodyYou can for example create a OnCollisionEnter
event for player, and then check TPhysicsCollisionDetails.OtherTransform
to determine if the other TRigidBody belongs to NPC or something else, for example:
TNPC = class(TCastleScene);
TPlayer = class(TCastleScene);
...
procedure TPlayer.CollisionEnter(const CollisionDetails: TPhysicsCollisionDetails);
begin
if CollisionDetails.OtherTransform <> nil then
begin
if CollisionDetails.OtherTransform is TNPC then
{ Do something };
end;
end;
...
constructor TPlayer.Create(AOwner: TComponent);
var
RBody: TRigidBody;
Collider: TBoxCollider;
begin
inherited;
RBody:= TRigidBody.Create(Self);
RBody.Dynamic := False;
RBody.Setup2D;
RBody.OnCollisionEnter := @CollisionEnter;
Collider := TBoxCollider.Create(RBody);
Collider.Size := LocalBoundingBox.Size;
RigidBody := RBody;
end;
...
constructor TNPC.Create(AOwner: TComponent);
var
RBody: TRigidBody;
Collider: TBoxCollider;
begin
inherited;
RBody:= TRigidBody.Create(Self);
RBody.Dynamic := False;
RBody.Setup2D;
Collider := TBoxCollider.Create(RBody);
Collider.Size := LocalBoundingBox.Size;
RigidBody := RBody;
end;
I did not yet analyze your full example code. I would suggest to make an even smaller example code that demonstrates only the problem you have and nothing else. Right now, we cannot run your code (it depends on data we don’t have) and it is hard to debug what is wrong in a non-trivial code we don’t understand I realize that it puts more work on you, but it will also lead to faster + more useful answers.
The box collider size is in 3D, and all 3 sizes must be > 0 (not zero but larger than zero).
Loading a PNG file into TCastleScene
gives you a scene that has the “depth” size = 0. Instead of doing
begin
...
MyBoxCollder.Size := SomeScene.LocalBoundingBox.Size;
end;
do something like this:
var
Size: TVector3;
begin
...
Size := SomeScene.LocalBoundingBox.Size;
Size.Z := Max(0.1, Size.Z);
MyBoxCollder.Size := Size;
`
program Rescue_Island;
{$ifdef MSWINDOWS} {$apptype GUI} {$endif}
uses Classes, SysUtils, StrUtils, Dialogs,
CastleWindow,CastleUtils, CastleUIControls, CastleGLImages, CastleFilesUtils,
CastleKeysMouse, CastleVectors, CastleSoundEngine, CastleTimeUtils, CastleColors,
CastleRectangles, CastleFonts, CastleGLUtils, Generics.Defaults, CastleUIState, CastleComponentSerialize,
Generics.Collections,Math, CastleOnScreenMenu, CastleControls, CastleDownload,CastleSceneCore, CastleScene,
CastleViewport, CastleCameras, CastleTransform,
CastleImages;
type
TAvatar = class;
var
Window: TCastleWindowbase;
Viewport: TCastleViewport;
Background: TCastleScene;
Mouse: TCastleScene;
MouseCursor: TCastleUserInterface;
PlayerScene, NPCScene: TCastleTransform;
Player, NPC: TAvatar;
type
TAvatar = class
WalkLeft, WalkRight, WalkFront, WalkBack, StandIdle: boolean;
WalkLeftAnim, WalkRightAnim, WalkFrontAnim, WalkBackAnim: TCastleScene;
StandIdleAnim: TCastleScene;
Directory: string;
Stand: boolean;
public
Constructor Create;
var
X, Y: single;
end;
procedure SetMouse;
begin
Mouse := TCastleScene.Create(Application);
Viewport.Items.Add(Mouse);
Mouse.Load('castle-data:/mouse-icons.starling-xml#fps:1, anim-naming:strict-underscore');
Mouse.Translation := vector3(Window.MousePosition.X, Window.MousePosition.Y, 5);
end;
procedure LoadPlayer;
var
RBody: TRigidBody;
Collider: TBoxCollider;
Size: TVector3;
begin
PlayerScene := TCastleTransform.Create(Application);
Viewport.Items.Add(PlayerScene);
Player := TAvatar.Create;
Player.StandIdleAnim.Load('castle-data:/characters/john carring/casual/johnstandidle.starling-xml#fps:8,anim-naming:strict-underscore');
Player.StandIdleAnim.Translation := Vector3(0, 0, 1);
Player.StandIdleAnim.Scale := Vector3(0.5, 0.5, 1);
Player.WalkLeftAnim.Load('castle-data:/characters/john carring/casual/johnwalkleft.starling-xml#fps:45,anim-naming:trailing-number');
Player.WalkLeftAnim.Exists:= false;
Player.WalkRightAnim.Load('castle-data:/characters/john carring/casual/johnwalkright.starling-xml#fps:45,anim-naming:trailing-number');
Player.WalkRightAnim.Exists:= false;
PlayerScene.Add(Player.StandIdleAnim);
PlayerScene.Add(Player.WalkLeftAnim);
PlayerScene.Add(Player.WalkRightAnim);
RBody := TRigidBody.Create(PlayerScene);
RBody.Dynamic := false;
RBody.Animated:= true;
RBody.Setup2D;
// RBody.OnCollisionEnter:= @CollisionEnter);
Collider := TBoxCollider.Create(RBody);
Size := PlayerScene.LocalBoundingBox.Size;
Size.Z := Max(0.1, Size.Z);
Collider.Size := Size;
PlayerScene.RigidBody := RBody;
PlayerScene.Translation := Vector3(0, -200, 1);
end;
procedure LoadNPC;
var
RBody: TRigidBody;
Collider: TBoxCollider;
Size: TVector3;
begin
NPCScene := TCastleTransform.Create(Application);
Viewport.Items.Add(NPCScene);
NPC := TAvatar.Create;
NPC.StandIdleAnim.Load('castle-data:/characters/kyley carring/casual/kyleystandidle.starling-xml#fps:8,anim-naming:strict-underscore');
NPC.StandIdleAnim.Translation := Vector3(0, 0, 1);
NPC.StandIdleAnim.Scale := Vector3(0.5, 0.5, 1);
NPCScene.Add(NPC.StandIdleAnim);
RBody := TRigidBody.Create(NPCScene);
RBody.Dynamic := false;
RBody.Animated:= true;
RBody.Setup2D;
// RBody.OnCollisionEnter:= @CollisionEnter);
Collider := TBoxCollider.Create(RBody);
Size := NPCScene.LocalBoundingBox.Size;
Size.Z := Max(0.1, Size.Z);
Collider.Size := Size;
NPCScene.RigidBody := RBody;
NPCScene.Translation := Vector3(200, -200, 1);
end;
constructor TAvatar.Create;
begin
inherited;
StandIdleAnim := TCastleScene.Create(Application);
WalkLeftAnim := TCastleScene.Create(Application);
WalkRightAnim := TCastleScene.Create(Application);
end;
procedure StopWalk;
begin
with Player do
begin
WalkLeft := false;
WalkRight := false;
Player.StandIdleAnim.Exists := true;
Player.WalkLeftAnim.Exists := false;
Player.WalkRightAnim.Exists := false;
end;
end;
Procedure GoLeft;
begin
StopWalk;
Player.StandIdleAnim.Exists := false;
Player.WalkLeftAnim.Exists := true;
Player.WalkLeft := true;
Player.Stand := false;
Player.WalkLeftAnim.PlayAnimation('johnwalkleft-', true);
end;
Procedure StandLeft;
begin
StopWalk;
Player.StandIdleAnim.Exists := true;
Player.WalkLeft := false;
Player.Stand := true;
Player.StandIdleAnim.PlayAnimation('johnstandleft', true);
end;
Procedure GoRight;
begin
StopWalk;
Player.StandIdleAnim.Exists := false;
Player.WalkRightAnim.Exists := true;
Player.WalkRight := true;
Player.Stand := false;
Player.WalkRightAnim.PlayAnimation('johnwalkright-', true);
end;
Procedure StandRight;
begin
StopWalk;
Player.StandIdleAnim.Exists := true;
Player.WalkRight := false;
Player.Stand := true;
Player.StandIdleAnim.PlayAnimation('johnstandright', true);
end;
Procedure StandFront;
begin
StopWalk;
Player.StandIdleAnim.Exists := true;
Player.WalkFront := false;
Player.Stand := true;
Player.StandIdleAnim.PlayAnimation('johnstandfront', true);
end;
procedure WindowUpdate(Container: TUIContainer);
begin
Mouse.Translation := Vector3(Viewport.PositionTo2DWorld(Window.MousePosition, true), 5);
if Player.WalkLeft then Player.X := Player.X - 8;
if Player.WalkRight then Player.X := Player.X + 8;
PlayerScene.Translation := Vector3(Player.X, Player.Y, 1);
end;
procedure WindowPress(Container: TUIContainer; const Event: TInputPressRelease);
begin
if Event.IsKey(keyArrowLeft) then
begin
if Player.Stand then GoLeft else StandLeft;
end;
if Event.IsKey(keyArrowRight) then
begin
if Player.Stand then GoRight else StandRight;
end;
end;
// ---------------------------------------------------------------------------
begin
Window := TCastleWindowBase.Create(Application);
Window.Container.UIReferenceWidth := 1024;
Window.Container.UIReferenceHeight := 768;
Window.Container.UIScaling := usEncloseReferenceSize;
Window.OnUpdate := @WindowUpdate;
Window.OnPress := @WindowPress;
Window.Open;
Viewport := TCastleViewport.Create(Application);
Viewport.Setup2D;
Viewport.FullSize := true;
Viewport.Camera.Orthographic.Width := 1920;
Viewport.Camera.Orthographic.Height := 1080;
Viewport.Camera.Orthographic.Origin := Vector2(0.5, 0.5);
Window.Controls.InsertFront(Viewport);
Background := TCastleScene.Create(Application);
Background.Setup2D;
Background.Load('castle-data:/locations/westbeach1.png');
Background.ProcessEvents := true;
Viewport.Items.Add(Background);
MouseCursor := TCastleUserInterface.Create(Application);
MouseCursor.FullSize := true;
MouseCursor.Cursor := mcstandard;
Window.Controls.InsertFront(MouseCursor);
SetMouse;
LoadPlayer;
Player.Y := -200;
LoadNPC;
Application.Run;
end.
Ok, I made it as small as possible now. If I make it any smaller it won’t work anymore.
I have looked at your examples on collision but don’t know how I can set this up in this code, in the Window Update procedure I guess. So collision between mouse scene and Player and NPC transforms?