Recent

Author Topic: Castle Game Engine (Cross Platform) - Need Help with Drawing a Raycast Vector  (Read 15995 times)

michalis

  • Full Member
  • ***
  • Posts: 143
    • Castle Game Engine
Hi, unfortunately I get an error about "Identifier not found TMyMesh" when I do this code

...

Does anyone know what I am doing wrong now?

Your unit GameViewPlay does not use the unit GameMyMesh. The compiler doesn't know the identifier TMyMesh. You need to use the unit GameMyMesh in unit GameViewPlay .

Also, I see you just copy-pasted the code doing "UnlitMeshParent.Add(MyMesh);" (from my example https://github.com/castle-engine/castle-engine/blob/master/examples/research_special_rendering_methods/test_rendering_opengl_capabilities/code/gameviewmain.pas#L83 ) into your code. This will not work -- there is no thing called "UnlitMeshParent" in your code. You need to either define it, or add to the viewport like "MyViewport.Items.Add(MyMesh)".

You will also still have to set the AvatarTransform on TMyMesh. Without this, that code will fail, AvatarTransform will be nil.

Overall: You are repeating the pattern from the previous threads on CGE forum :

- you are trying to solve this by "trial and error", pasting things in your code without understanding. Please follow the Pascal learning resources we pointed out ( https://castle-engine.io/learn_pascal ) to learn how to use units, how they can use one another.

- you do not research the reason behind compilation errors, it seems you immediately paste them into the forum. Instead of reading about the related Pascal concepts and trying to solve them. As we suggested earlier, if you're not sure about some concept, try to experiment on a simpler application too.
« Last Edit: February 19, 2024, 02:38:44 pm by michalis »

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
Oh yeah, I caught on that I was copy pasting that line without understand it and fixed that, but I still stand by the examples not using GameMyMesh for example, so why should I?

If the original example compiles fine the way it is, then there is something very suspicious about having to do it a different way for no good reason.

Code of GameViewMain.Pas of the test_rendering_opengl_capabilities project for reference, note the lack of GameMyMesh under the uses section:

Code: Pascal  [Select][+][-]
  1. {
  2.   Copyright 2023-2023 Michalis Kamburelis.
  3.  
  4.   This file is part of "Castle Game Engine".
  5.  
  6.   "Castle Game Engine" is free software; see the file COPYING.txt,
  7.   included in this distribution, for details about the copyright.
  8.  
  9.   "Castle Game Engine" is distributed in the hope that it will be useful,
  10.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12.  
  13.   ----------------------------------------------------------------------------
  14. }
  15.  
  16. { Main view, where most of the application logic takes place. }
  17. unit GameViewMain;
  18.  
  19. interface
  20.  
  21. uses Classes,
  22.   CastleVectors, CastleComponentSerialize, CastleScene, CastleCameras,
  23.   CastleUIControls, CastleControls, CastleKeysMouse, CastleGLImages, CastleViewport,
  24.   CastleTransform, CastleGLUtils;
  25.  
  26. type
  27.   { Main view, where most of the application logic takes place. }
  28.   TViewMain = class(TCastleView)
  29.   published
  30.     { Components designed using CGE editor.
  31.       These fields will be automatically initialized at Start. }
  32.     LabelFps, LabelGlInformation: TCastleLabel;
  33.     ScenePhong: TCastleScene;
  34.     MainViewport: TCastleViewport;
  35.     WalkNavigation: TCastleWalkNavigation;
  36.     UnlitMeshParent: TCastleTransform;
  37.   private
  38.     DrawableImage: TDrawableImage;
  39.   public
  40.     constructor Create(AOwner: TComponent); override;
  41.     procedure Start; override;
  42.     procedure Stop; override;
  43.     procedure Update(const SecondsPassed: Single; var HandleInput: Boolean); override;
  44.     procedure RenderOverChildren; override;
  45.   end;
  46.  
  47. var
  48.   ViewMain: TViewMain;
  49.  
  50. implementation
  51.  
  52. uses SysUtils,
  53.   CastleLoadGltf, CastleRectangles, CastleImages,
  54.   CastleBoxes, CastleColors, CastleRenderContext, CastleUtils, X3DLoad,
  55.   GameMyMesh;
  56.  
  57. { TViewMain ----------------------------------------------------------------- }
  58.  
  59. constructor TViewMain.Create(AOwner: TComponent);
  60. begin
  61.   inherited;
  62.   DesignUrl := 'castle-data:/gameviewmain.castle-user-interface';
  63. end;
  64.  
  65. procedure TViewMain.Start;
  66. var
  67.   MyMesh: TMyMesh;
  68. begin
  69.   inherited;
  70.  
  71.   LabelGlInformation.Caption :=
  72.     'OpenGL capabilities requested: ' + CapabilitiesStr[TGLFeatures.RequestCapabilities] + NL +
  73.     '(see log for the details about context)';
  74.  
  75.   { Load ScenePhong.Url with temporary GltfForcePhongMaterials set to true.
  76.     We want to test Phong shading works in ForceFixedFunction too. }
  77.   GltfForcePhongMaterials := true;
  78.   ScenePhong.Url := 'castle-data:/sample_3d.gltf';
  79.   GltfForcePhongMaterials := false;
  80.  
  81.   DrawableImage := TDrawableImage.Create('castle-data:/texture_alpha.png');
  82.  
  83.   MyMesh := TMyMesh.Create(FreeAtStop);
  84.   UnlitMeshParent.Add(MyMesh);
  85.  
  86.   MainViewport.AddScreenEffect(LoadNode('castle-data:/screen_effect_frame.x3dv'));
  87. end;
  88.  
  89. procedure TViewMain.Stop;
  90. begin
  91.   FreeAndNil(DrawableImage);
  92.   inherited;
  93. end;
  94.  
  95. procedure TViewMain.Update(const SecondsPassed: Single; var HandleInput: Boolean);
  96. begin
  97.   inherited;
  98.   { This virtual method is executed every frame (many times per second). }
  99.   Assert(LabelFps <> nil, 'If you remove LabelFps from the design, remember to remove also the assignment "LabelFps.Caption := ..." from code');
  100.   LabelFps.Caption := 'FPS: ' + Container.Fps.ToString;
  101.  
  102.   WalkNavigation.MouseLook := buttonRight in Container.MousePressed;
  103. end;
  104.  
  105. procedure TViewMain.RenderOverChildren;
  106. begin
  107.   inherited;
  108.   { Do some direct drawing, to test this API works with ForceFixedFunction too. }
  109.   DrawRectangle(FloatRectangle(10, 10, 50, 50), Green);
  110.   DrawableImage.Draw(100, 10);
  111.  
  112.   { Render DrawableImage again, forcing alpha testing }
  113.   DrawableImage.Alpha := acTest;
  114.   DrawableImage.Draw(400, 10);
  115.   DrawableImage.Alpha := acAuto;
  116.  
  117.   FallbackFont.Print(700, 10, Red, 'Another sample text');
  118. end;
  119.  
  120. end.

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
Oh, you meant to include it under the "uses" section, to use other units, because the "unit" is the main unit. That makes a lot more sense now.

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
Here is what my GameMyMesh.pas looks like now:

Code: Pascal  [Select][+][-]
  1. {
  2.   Copyright 2023-2023 Michalis Kamburelis.
  3.  
  4.   This file is part of "Castle Game Engine".
  5.  
  6.   "Castle Game Engine" is free software; see the file COPYING.txt,
  7.   included in this distribution, for details about the copyright.
  8.  
  9.   "Castle Game Engine" is distributed in the hope that it will be useful,
  10.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12.  
  13.   ----------------------------------------------------------------------------
  14. }
  15.  
  16. { TCastleTransform descendant that renders unlit mesh using TCastleRenderUnlitMesh. }
  17. unit GameMyMesh;
  18.  
  19. interface
  20.  
  21. uses SysUtils,
  22.   CastleRenderPrimitives, CastleBoxes, CastleTransform;
  23.  
  24. type
  25.   { Mesh rendered using TCastleRenderUnlitMesh, not using TCastleScene.
  26.     This is not generally advised, TCastleScene has much more features
  27.     and is easier to use than TCastleRenderUnlitMesh.
  28.     We do this only to test TCastleRenderUnlitMesh with rcForceFixedFunction here. }
  29.   TMyMesh = class(TCastleTransform)
  30.   published
  31.     AvatarTransform: TCastleTransform;
  32.   strict private
  33.     Mesh: TCastleRenderUnlitMesh;
  34.   public
  35.     procedure LocalRender(const Params: TRenderParams); override;
  36.     procedure GLContextClose; override;
  37.     function LocalBoundingBox: TBox3D; override;
  38.   end;
  39.  
  40. implementation
  41.  
  42. uses CastleVectors, CastleRenderContext, CastleColors, CastleGLUtils, GameViewPlay;
  43.  
  44. { TMyMesh -------------------------------------------------------------------- }
  45.  
  46. function TMyMesh.LocalBoundingBox: TBox3D;
  47. begin
  48.   Result := inherited;
  49.   Result := Result + Box3D(
  50.     Vector3(-1, -1, -1),
  51.     Vector3( 1,  1,  1)
  52.   );
  53. end;
  54.  
  55. procedure TMyMesh.LocalRender(const Params: TRenderParams);
  56.  
  57.   procedure CreateMesh(const PlayerTransform: TCastleTransform);
  58.   begin
  59.     Mesh := TCastleRenderUnlitMesh.Create(true);
  60.     Mesh.SetVertexes([
  61.       Vector4(0.0, PlayerTransform.Translation.Y, 0.0, 1.0),
  62.       Vector4(0.0, (PlayerTransform.Translation.Y - PlayerTransform.Direction.Y), 0.0, 1.0)
  63.     ], false);
  64.     Mesh.SetIndexes([
  65.       // line loop on Z = -1
  66.       0, 1
  67.     ]);
  68.     Mesh.Color := Yellow;
  69.   end;
  70.  
  71. var
  72.   SavedDepthTest: Boolean;
  73.   SavedLineWidth: Single;
  74. begin
  75.   inherited;
  76.   SavedDepthTest := RenderContext.DepthTest;
  77.   SavedLineWidth := RenderContext.LineWidth;
  78.   RenderContext.DepthTest := true;
  79.   RenderContext.LineWidth := 5;
  80.  
  81.   if Mesh = nil then
  82.     CreateMesh(AvatarTransform);
  83.   Mesh.ModelViewProjection := RenderContext.ProjectionMatrix *
  84.     Params.RenderingCamera.CurrentMatrix * WorldTransform;
  85.   Mesh.Render(pmLines);
  86.  
  87.   RenderContext.DepthTest := SavedDepthTest;
  88.   RenderContext.LineWidth := SavedLineWidth;
  89. end;
  90.  
  91. procedure TMyMesh.GLContextClose;
  92. begin
  93.   FreeAndNil(Mesh);
  94.   inherited;
  95. end;
  96.  
  97. end.

Here is what my GameViewPlay.pas looks like as well:

Code: Pascal  [Select][+][-]
  1. {
  2.   Copyright 2020-2023 Michalis Kamburelis.
  3.  
  4.   This file is part of "Castle Game Engine".
  5.  
  6.   "Castle Game Engine" is free software; see the file COPYING.txt,
  7.   included in this distribution, for details about the copyright.
  8.  
  9.   "Castle Game Engine" is distributed in the hope that it will be useful,
  10.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12.  
  13.   ----------------------------------------------------------------------------
  14. }
  15.  
  16. { Main "playing game" view, where most of the game logic takes place. }
  17. unit GameViewPlay;
  18.  
  19. { Unit for GameMesh renderer features. }
  20.  
  21. {.$define CASTLE_UNFINISHED_CHANGE_TRANSFORMATION_BY_FORCE}
  22.  
  23. interface
  24.  
  25. uses Classes,
  26.   CastleComponentSerialize, CastleUIControls, CastleControls,
  27.   CastleKeysMouse, CastleViewport, CastleScene, CastleVectors, CastleCameras,
  28.   CastleTransform, CastleInputs, CastleThirdPersonNavigation, CastleDebugTransform,
  29.   CastleSceneCore, SysUtils, CastleRenderPrimitives, CastleBoxes,
  30.   GameEnemy;
  31.  
  32. type
  33.  
  34.   { Main "playing game" view, where most of the game logic takes place. }
  35.   TViewPlay = class(TCastleView)
  36.   published
  37.     { Components designed using CGE editor.
  38.       These fields will be automatically initialized at Start. }
  39.     LabelFps: TCastleLabel;
  40.     MainViewport: TCastleViewport;
  41.     AvatarTransform: TCastleTransform;
  42.     SandyLegs, SandyHead, SandyTorso, SceneLevel: TCastleScene;
  43.     AvatarRigidBody: TCastleRigidBody;
  44.     CheckboxCameraFollows: TCastleCheckbox;
  45.     CheckboxAimAvatar: TCastleCheckbox;
  46.     CheckboxDebugAvatarColliders: TCastleCheckbox;
  47.     CheckboxImmediatelyFixBlockedCamera: TCastleCheckbox;
  48.     SliderAirRotationControl: TCastleFloatSlider;
  49.     SliderAirMovementControl: TCastleFloatSlider;
  50.     ButtonChangeTransformationAuto,
  51.     ButtonChangeTransformationDirect,
  52.     ButtonChangeTransformationVelocity,
  53.     ButtonChangeTransformationForce: TCastleButton;
  54.   private
  55.     { Enemies behaviors }
  56.     Enemies: TEnemyList;
  57.  
  58.     DebugAvatar: TDebugTransform;
  59.     { Change things after ThirdPersonNavigation.ChangeTransformation changed. }
  60.     procedure UpdateAfterChangeTransformation;
  61.     procedure ChangeCheckboxCameraFollows(Sender: TObject);
  62.     procedure ChangeCheckboxAimAvatar(Sender: TObject);
  63.     procedure ChangeCheckboxDebugAvatarColliders(Sender: TObject);
  64.     procedure ChangeCheckboxImmediatelyFixBlockedCamera(Sender: TObject);
  65.     procedure ChangeAirRotationControl(Sender: TObject);
  66.     procedure ChangeAirMovementControl(Sender: TObject);
  67.     procedure ClickChangeTransformationAuto(Sender: TObject);
  68.     procedure ClickChangeTransformationDirect(Sender: TObject);
  69.     procedure ClickChangeTransformationVelocity(Sender: TObject);
  70.     procedure ClickChangeTransformationForce(Sender: TObject);
  71.   public
  72.     constructor Create(AOwner: TComponent); override;
  73.     procedure Start; override;
  74.     procedure Stop; override;
  75.     procedure Update(const SecondsPassed: Single; var HandleInput: Boolean); override;
  76.     function Press(const Event: TInputPressRelease): Boolean; override;
  77.     function Release(const Event: TInputPressRelease): Boolean; override;
  78.   end;
  79.  
  80.   TMyThirdPersonNavigation = class(TCastleThirdPersonNavigation)
  81.   protected
  82.     procedure SetAnimation(const AnimationNames: array of String); override;
  83.   end;
  84.  
  85. var
  86.   ViewPlay: TViewPlay;
  87.   MyThirdPersonNavigation: TMyThirdPersonNavigation;
  88.   GroundRayCast: TPhysicsRayCastResult;
  89.   StandOnGround: Boolean;
  90.   SandyInRunning: Boolean;
  91.   MaxDistance: Integer;
  92.  
  93. implementation
  94.  
  95. uses Math, StrUtils, CastleRenderContext, CastleColors,
  96.   CastleSoundEngine, CastleLog, CastleStringUtils, CastleFilesUtils,
  97.   GameViewMenu, GameMyMesh;
  98.  
  99. { TViewPlay ----------------------------------------------------------------- }
  100.  
  101. constructor TViewPlay.Create(AOwner: TComponent);
  102. begin
  103.   inherited;
  104.   DesignUrl := 'castle-data:/gameviewplay.castle-user-interface';
  105. end;
  106.  
  107. procedure TMyThirdPersonNavigation.SetAnimation(const AnimationNames: array of String);
  108. begin
  109.  
  110. end;
  111.  
  112. procedure TViewPlay.Start;
  113. var
  114.   SoldierScene: TCastleScene;
  115.   Enemy: TEnemy;
  116.   I: Integer;
  117.   MyMesh: TMyMesh;
  118. begin
  119.   inherited;
  120.  
  121.   MyMesh := TMyMesh.Create(FreeAtStop);
  122.   AvatarTransform.Add(MyMesh);
  123.  
  124.   MyThirdPersonNavigation := TMyThirdPersonNavigation.Create(FreeAtStop);
  125.   { Create TEnemy instances, add them to Enemies list }
  126.   Enemies := TEnemyList.Create(true);
  127.      for I := 1 to 4 do
  128.      begin
  129.         SoldierScene := DesignedComponent('SceneSoldier' + IntToStr(I)) as TCastleScene;
  130.         { Below using nil as Owner of TEnemy, as the Enemies list already "owns"
  131.         instances of this class, i.e. it will free them. }
  132.         Enemy := TEnemy.Create(nil);
  133.         SoldierScene.AddBehavior(Enemy);
  134.         Enemies.Add(Enemy);
  135.      end;
  136.  
  137.   { synchronize state -> UI }
  138.   SliderAirRotationControl.Value := MyThirdPersonNavigation.AirRotationControl;
  139.   SliderAirMovementControl.Value := MyThirdPersonNavigation.AirMovementControl;
  140.   UpdateAfterChangeTransformation;
  141.  
  142.   CheckboxCameraFollows.OnChange := {$ifdef FPC}@{$endif} ChangeCheckboxCameraFollows;
  143.   CheckboxAimAvatar.OnChange := {$ifdef FPC}@{$endif} ChangeCheckboxAimAvatar;
  144.   CheckboxDebugAvatarColliders.OnChange := {$ifdef FPC}@{$endif} ChangeCheckboxDebugAvatarColliders;
  145.   CheckboxImmediatelyFixBlockedCamera.OnChange := {$ifdef FPC}@{$endif} ChangeCheckboxImmediatelyFixBlockedCamera;
  146.   SliderAirRotationControl.OnChange := {$ifdef FPC}@{$endif} ChangeAirRotationControl;
  147.   SliderAirMovementControl.OnChange := {$ifdef FPC}@{$endif} ChangeAirMovementControl;
  148.   ButtonChangeTransformationAuto.OnClick := {$ifdef FPC}@{$endif} ClickChangeTransformationAuto;
  149.   ButtonChangeTransformationDirect.OnClick := {$ifdef FPC}@{$endif} ClickChangeTransformationDirect;
  150.   ButtonChangeTransformationVelocity.OnClick := {$ifdef FPC}@{$endif} ClickChangeTransformationVelocity;
  151.   ButtonChangeTransformationForce.OnClick := {$ifdef FPC}@{$endif} ClickChangeTransformationForce;
  152.  
  153.   {$ifndef CASTLE_UNFINISHED_CHANGE_TRANSFORMATION_BY_FORCE}
  154.   { Hide UI to test ChangeTransformation = ctForce, it is not finished now,
  155.     not really useful for normal usage. }
  156.   ButtonChangeTransformationForce.Exists := false;
  157.   {$endif}
  158.  
  159.   { This configures SceneAvatar.Middle point, used for shooting.
  160.     In case of old physics (ChangeTransformation = ctDirect) this is also the center
  161.     of SceneAvatar.CollisionSphereRadius. }
  162.   // SceneAvatar.MiddleHeight := 0.9;
  163.  
  164.   { Configure some parameters of old simple physics,
  165.     these only matter when SceneAvatar.Gravity = true.
  166.     Don't use these deprecated things if you don't plan to use ChangeTransformation = ctDirect! }
  167.   // SceneAvatar.GrowSpeed := 10.0;
  168.   // SceneAvatar.FallSpeed := 10.0;
  169.   { When avatar collides as sphere it can climb stairs,
  170.     because legs can temporarily collide with objects. }
  171.   // SceneAvatar.CollisionSphereRadius := 0.5;
  172.  
  173.   { Visualize SceneAvatar bounding box, sphere, middle point, direction etc. }
  174.   DebugAvatar := TDebugTransform.Create(FreeAtStop);
  175.   // DebugAvatar.Parent := SceneAvatar;
  176.  
  177.   { Configure MyThirdPersonNavigation keys (for now, we don't expose doing this in CGE editor). }
  178.   MyThirdPersonNavigation.Input_LeftStrafe.Assign(keyQ);
  179.   MyThirdPersonNavigation.Input_RightStrafe.Assign(keyE);
  180.   MyThirdPersonNavigation.MouseLook := true; // TODO: assigning it from editor doesn't make mouse hidden in mouse look
  181.   MyThirdPersonNavigation.Init;
  182.   MyThirdPersonNavigation.AvatarHierarchy := AvatarTransform;
  183.   SandyLegs.AutoAnimation := 'LEGS_IDLE';
  184.   SandyTorso.AutoAnimation := 'TORSO_IDLE';
  185. end;
  186.  
  187. procedure TViewPlay.Stop;
  188. begin
  189.   FreeAndNil(Enemies);
  190.   inherited;
  191. end;
  192.  
  193. procedure TViewPlay.Update(const SecondsPassed: Single; var HandleInput: Boolean);
  194.  
  195.   // Test: use this to make AimAvatar only when *holding* right mouse button.
  196.   (*
  197.   procedure UpdateAimAvatar;
  198.   begin
  199.     if buttonRight in Container.MousePressed then
  200.       ThirdPersonNavigation.AimAvatar := aaHorizontal
  201.     else
  202.       ThirdPersonNavigation.AimAvatar := aaNone;
  203.  
  204.     { In this case CheckboxAimAvatar only serves to visualize whether
  205.       the right mouse button is pressed now. }
  206.     CheckboxAimAvatar.Checked := ThirdPersonNavigation.AimAvatar <> aaNone;
  207.   end;
  208.   *)
  209.  
  210. var
  211.   SandyAnims: array of String;
  212.   RayCastResult: TPhysicsRayCastResult;
  213.   MoveAmount: TVector3;
  214.   RayCastDirection: TVector3;
  215.   MaxDistance: Single;
  216.   SandyAirborne: Integer;
  217.   SandyIdling: Integer;
  218. begin
  219.   inherited;
  220.   { This virtual method is executed every frame (many times per second). }
  221.   SandyIdling := 0;
  222.   SandyAirborne := 0;
  223.   MaxDistance := 0.3;
  224.   MoveAmount := Vector3(0, -5, 0);
  225.   RayCastDirection := Vector3(0, -1, 0);
  226.   RayCastResult := AvatarRigidBody.PhysicsRayCast(
  227.   (AvatarTransform.Translation),
  228.   RayCastDirection,
  229.   0.3
  230.   );
  231.   if RayCastResult.Hit then
  232.   begin
  233.        SandyAirborne := 0;
  234.        LabelFps.Caption := 'FPS: PLACEHOLDER';
  235.       if SandyIdling = 0 then
  236.       begin
  237.            SandyIdling := 1;
  238.            SandyLegs.PlayAnimation('LEGS_IDLE', true);
  239.            SandyTorso.PlayAnimation('TORSO_IDLE', true);
  240.       end;
  241.   end
  242.   else
  243.       SandyIdling := 0;
  244.       begin
  245.            if SandyAirborne = 0 then
  246.            begin
  247.                 SandyAirborne := 1;
  248.                 SandyTorso.PlayAnimation('TORSO_AIRBORNE', true);
  249.                 SandyLegs.PlayAnimation('LEGS_AIRBORNE', true);
  250.             end;
  251.        AvatarTransform.Move(MoveAmount, false, true);
  252.        LabelFps.Caption := 'FPS: ' + Container.Fps.ToString
  253.        end;
  254.   // UpdateAimAvatar;
  255.   end;
  256.  
  257. function TViewPlay.Press(const Event: TInputPressRelease): Boolean;
  258. var
  259.   HitByAvatar: TCastleTransform;
  260.   HitEnemy: TEnemy;
  261. begin
  262.   Result := inherited;
  263.   if Result then Exit; // allow the ancestor to handle keys
  264.  
  265.   { This virtual method is executed when user presses
  266.     a key, a mouse button, or touches a touch-screen.
  267.  
  268.     Note that each UI control has also events like OnPress and OnClick.
  269.     These events can be used to handle the "press", if it should do something
  270.     specific when used in that UI control.
  271.     The TViewPlay.Press method should be used to handle keys
  272.     not handled in children controls.
  273.   }
  274.  
  275.   if Event.IsMouseButton(buttonLeft) then
  276.   begin
  277.     SoundEngine.Play(SoundEngine.SoundFromName('shoot_sound'));
  278.   end;
  279.  
  280.   if Event.IsMouseButton(buttonRight) then
  281.   begin
  282.     MyThirdPersonNavigation.MouseLook := not MyThirdPersonNavigation.MouseLook;
  283.     Exit(true);
  284.   end;
  285.  
  286.   if Event.IsKey(keyF5) then
  287.   begin
  288.     Container.SaveScreenToDefaultFile;
  289.     Exit(true);
  290.   end;
  291.  
  292.   if Event.IsKey(keyEscape) then
  293.   begin
  294.     Container.View := ViewMenu;
  295.     Exit(true);
  296.   end;
  297.  
  298.   if (Event.IsKey(keyArrowUp) and SandyInRunning = false) then
  299.   begin
  300.     SandyInRunning := true;
  301.     SandyLegs.PlayAnimation('LEGS_RUN', true);
  302.     SandyTorso.PlayAnimation('TORSO_RUN', true);
  303.   end;
  304. end;
  305.  
  306. function TViewPlay.Release(const Event: TInputPressRelease): Boolean;
  307. begin
  308.   Result := inherited;
  309.   if Result then Exit; // allow the ancestor to handle keys
  310.  
  311.   { This virtual method is executed when user releases
  312.     a key, a mouse button, or touches a touch-screen.
  313.  
  314.     Note that each UI control has also events like OnPress and OnClick.
  315.     These events can be used to handle the "press", if it should do something
  316.     specific when used in that UI control.
  317.     The TViewPlay.Release method should be used to handle keys
  318.     not handled in children controls.
  319.   }
  320.  
  321.   if (Event.IsKey(keyArrowUp) and SandyInRunning = true) then
  322.   begin
  323.     SandyInRunning := false;
  324.     SandyLegs.PlayAnimation('BOTH_IDLE', true);
  325.     SandyTorso.PlayAnimation('BOTH_IDLE', true);
  326.   end;
  327. end;
  328.  
  329. procedure TViewPlay.ChangeCheckboxCameraFollows(Sender: TObject);
  330. begin
  331.   MyThirdPersonNavigation.CameraFollows := CheckboxCameraFollows.Checked;
  332. end;
  333.  
  334. procedure TViewPlay.ChangeCheckboxAimAvatar(Sender: TObject);
  335. begin
  336.   if CheckboxAimAvatar.Checked then
  337.     MyThirdPersonNavigation.AimAvatar := aaHorizontal
  338.   else
  339.     MyThirdPersonNavigation.AimAvatar := aaNone;
  340.  
  341.   { The 3rd option, aaFlying, doesn't make sense for this case,
  342.     when avatar walks on the ground and has Gravity = true. }
  343. end;
  344.  
  345. procedure TViewPlay.ChangeCheckboxDebugAvatarColliders(Sender: TObject);
  346. begin
  347.   DebugAvatar.Exists := CheckboxDebugAvatarColliders.Checked;
  348. end;
  349.  
  350. procedure TViewPlay.ChangeCheckboxImmediatelyFixBlockedCamera(Sender: TObject);
  351. begin
  352.   MyThirdPersonNavigation.ImmediatelyFixBlockedCamera := CheckboxImmediatelyFixBlockedCamera.Checked;
  353. end;
  354.  
  355. procedure TViewPlay.ChangeAirRotationControl(Sender: TObject);
  356. begin
  357.   MyThirdPersonNavigation.AirRotationControl := SliderAirRotationControl.Value;
  358. end;
  359.  
  360. procedure TViewPlay.ChangeAirMovementControl(Sender: TObject);
  361. begin
  362.   MyThirdPersonNavigation.AirMovementControl := SliderAirMovementControl.Value;
  363. end;
  364.  
  365. procedure TViewPlay.UpdateAfterChangeTransformation;
  366. begin
  367.   ButtonChangeTransformationAuto.Pressed := MyThirdPersonNavigation.ChangeTransformation = ctAuto;
  368.   ButtonChangeTransformationDirect.Pressed := MyThirdPersonNavigation.ChangeTransformation =  ctDirect;
  369.   ButtonChangeTransformationVelocity.Pressed := MyThirdPersonNavigation.ChangeTransformation =  ctVelocity;
  370.   {$ifdef CASTLE_UNFINISHED_CHANGE_TRANSFORMATION_BY_FORCE}
  371.   ButtonChangeTransformationForce.Pressed := ThirdPersonNavigation.ChangeTransformation = ctForce;
  372.   {$endif}
  373.  
  374.   { ctDirect requires to set up gravity without physics engine,
  375.     using deprecated TCastleTransform.Gravity.
  376.     See https://castle-engine.io/physics#_old_system_for_collisions_and_gravity }
  377.   AvatarRigidBody.Exists := MyThirdPersonNavigation.ChangeTransformation <> ctDirect;
  378.  
  379.   { Gravity means that object tries to maintain a constant height
  380.     (SceneAvatar.PreferredHeight) above the ground.
  381.     GrowSpeed means that object raises properly (makes walking up the stairs work).
  382.     FallSpeed means that object falls properly (makes walking down the stairs,
  383.     falling down pit etc. work). }
  384.   SandyTorso.Gravity := not AvatarRigidBody.Exists;
  385.   SandyLegs.Gravity := not AvatarRigidBody.Exists;
  386.   SandyHead.Gravity := not AvatarRigidBody.Exists;
  387. end;
  388.  
  389. procedure TViewPlay.ClickChangeTransformationAuto(Sender: TObject);
  390. begin
  391.   MyThirdPersonNavigation.ChangeTransformation := ctAuto;
  392.   UpdateAfterChangeTransformation;
  393. end;
  394.  
  395. procedure TViewPlay.ClickChangeTransformationDirect(Sender: TObject);
  396. begin
  397.   MyThirdPersonNavigation.ChangeTransformation := ctDirect;
  398.   UpdateAfterChangeTransformation;
  399. end;
  400.  
  401. procedure TViewPlay.ClickChangeTransformationVelocity(Sender: TObject);
  402. begin
  403.   MyThirdPersonNavigation.ChangeTransformation := ctVelocity;
  404.   UpdateAfterChangeTransformation;
  405. end;
  406.  
  407. procedure TViewPlay.ClickChangeTransformationForce(Sender: TObject);
  408. begin
  409.   {$ifdef CASTLE_UNFINISHED_CHANGE_TRANSFORMATION_BY_FORCE}
  410.   ThirdPersonNavigation.ChangeTransformation := ctForce;
  411.   {$endif}
  412.   UpdateAfterChangeTransformation;
  413. end;
  414.  
  415. end.

All I did was add one simple line to include the necessary extra units for reference, but now even though it compiles it immediately crashes with the attached error message, even though I followed all the directions of the original example to a T.

What else am I doing wrong? I don't get it, because all I did was copy examples that are known and trusted to work correctly the first time, and make slight modifications as necessary.

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
Do I perhaps need to include all the lines from the test_rendering_opengl_capabilties other files too, like GameViewMain.Pas, and GameInitialize.Pas, for the code to work correctly, given that I am using units that reference/depend on each other?

That's the only logical explanation I can think of - that I didn't include all the lines needed to draw the vector correctly, because I only used one file's code and not all of them.

michalis

  • Full Member
  • ***
  • Posts: 143
    • Castle Game Engine
As I wrote in an earlier post:

> You will also still have to set the AvatarTransform on TMyMesh. Without this, that code will fail, AvatarTransform will be nil.

You didn't do it.

Follow the error message you show on the screenshot. Find the line it talks about. Research what it means -- is the `PlayerTransform` correct at this point? What value does it have? Why?


cdbc

  • Hero Member
  • *****
  • Posts: 1868
    • http://www.cdbc.dk
Hi
Even I can see that "AvatarTransform" doesn't get created, from looking at the code, alas it eludes me where the creation should be, due to the 'AvatarTransform' being a published property...
I see 2 places and so does the compiler, shown in the errormessages line 61,82.
...and where does the AvatarTransform come from in these lines:
Code: Pascal  [Select][+][-]
  1. procedure TViewPlay.Start;
  2. var
  3.   SoldierScene: TCastleScene;
  4.   Enemy: TEnemy;
  5.   I: Integer;
  6.   MyMesh: TMyMesh;
  7. begin
  8.   inherited;
  9.  
  10.   MyMesh := TMyMesh.Create(FreeAtStop);
  11.   AvatarTransform.Add(MyMesh); // <- HERE?!?
  12.   //etc...
who creates it first(or is supposed to)?!?
Have a closer look at the code and follow Michalis' advice, because he knows his own baby best  ;)
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
If you read my latest version, that point objectively doesn't make sense - I created a reference to "AvatarTransform" the way I was supposed to do, in both GameViewPlay and GameMyMesh, and I am pretty sure in the original example it wasn't created in the code but was a reference to an existing object - by defining it in the "type" section at the top of the file like I am normally supposed to do.

The reason I didn't include the "AvatarTransform.Add(MyMesh)" in the GameMyMesh.pas, is because I thought it was only needed to be done one time total in the project, it wouldn't make sense to assign it in two different places if they're connected together, which they are here.

For proof of this, read the initial example and see how "UnLitMeshParent", the thing that I am replacing with AvatarTransform but is still just like it, a regular old Transform object, isn't assigned any value in the "var" section yet compiles fine, in the official example!:

Code: Pascal  [Select][+][-]
  1. {
  2.   Copyright 2023-2023 Michalis Kamburelis.
  3.  
  4.   This file is part of "Castle Game Engine".
  5.  
  6.   "Castle Game Engine" is free software; see the file COPYING.txt,
  7.   included in this distribution, for details about the copyright.
  8.  
  9.   "Castle Game Engine" is distributed in the hope that it will be useful,
  10.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12.  
  13.   ----------------------------------------------------------------------------
  14. }
  15.  
  16. { Main view, where most of the application logic takes place. }
  17. unit GameViewMain;
  18.  
  19. interface
  20.  
  21. uses Classes,
  22.   CastleVectors, CastleComponentSerialize, CastleScene, CastleCameras,
  23.   CastleUIControls, CastleControls, CastleKeysMouse, CastleGLImages, CastleViewport,
  24.   CastleTransform, CastleGLUtils;
  25.  
  26. type
  27.   { Main view, where most of the application logic takes place. }
  28.   TViewMain = class(TCastleView)
  29.   published
  30.     { Components designed using CGE editor.
  31.       These fields will be automatically initialized at Start. }
  32.     LabelFps, LabelGlInformation: TCastleLabel;
  33.     ScenePhong: TCastleScene;
  34.     MainViewport: TCastleViewport;
  35.     WalkNavigation: TCastleWalkNavigation;
  36.     UnlitMeshParent: TCastleTransform;
  37.   private
  38.     DrawableImage: TDrawableImage;
  39.   public
  40.     constructor Create(AOwner: TComponent); override;
  41.     procedure Start; override;
  42.     procedure Stop; override;
  43.     procedure Update(const SecondsPassed: Single; var HandleInput: Boolean); override;
  44.     procedure RenderOverChildren; override;
  45.   end;
  46.  
  47. var
  48.   ViewMain: TViewMain;
  49.  
  50. implementation
  51.  
  52. uses SysUtils,
  53.   CastleLoadGltf, CastleRectangles, CastleImages,
  54.   CastleBoxes, CastleColors, CastleRenderContext, CastleUtils, X3DLoad,
  55.   GameMyMesh;
  56.  
  57. { TViewMain ----------------------------------------------------------------- }
  58.  
  59. constructor TViewMain.Create(AOwner: TComponent);
  60. begin
  61.   inherited;
  62.   DesignUrl := 'castle-data:/gameviewmain.castle-user-interface';
  63. end;
  64.  
  65. procedure TViewMain.Start;
  66. var
  67.   MyMesh: TMyMesh;
  68. begin
  69.   inherited;
  70.  
  71.   LabelGlInformation.Caption :=
  72.     'OpenGL capabilities requested: ' + CapabilitiesStr[TGLFeatures.RequestCapabilities] + NL +
  73.     '(see log for the details about context)';
  74.  
  75.   { Load ScenePhong.Url with temporary GltfForcePhongMaterials set to true.
  76.     We want to test Phong shading works in ForceFixedFunction too. }
  77.   GltfForcePhongMaterials := true;
  78.   ScenePhong.Url := 'castle-data:/sample_3d.gltf';
  79.   GltfForcePhongMaterials := false;
  80.  
  81.   DrawableImage := TDrawableImage.Create('castle-data:/texture_alpha.png');
  82.  
  83.   MyMesh := TMyMesh.Create(FreeAtStop);
  84.   UnlitMeshParent.Add(MyMesh);
  85.  
  86.   MainViewport.AddScreenEffect(LoadNode('castle-data:/screen_effect_frame.x3dv'));
  87. end;
  88.  
  89. procedure TViewMain.Stop;
  90. begin
  91.   FreeAndNil(DrawableImage);
  92.   inherited;
  93. end;
  94.  
  95. procedure TViewMain.Update(const SecondsPassed: Single; var HandleInput: Boolean);
  96. begin
  97.   inherited;
  98.   { This virtual method is executed every frame (many times per second). }
  99.   Assert(LabelFps <> nil, 'If you remove LabelFps from the design, remember to remove also the assignment "LabelFps.Caption := ..." from code');
  100.   LabelFps.Caption := 'FPS: ' + Container.Fps.ToString;
  101.  
  102.   WalkNavigation.MouseLook := buttonRight in Container.MousePressed;
  103. end;
  104.  
  105. procedure TViewMain.RenderOverChildren;
  106. begin
  107.   inherited;
  108.   { Do some direct drawing, to test this API works with ForceFixedFunction too. }
  109.   DrawRectangle(FloatRectangle(10, 10, 50, 50), Green);
  110.   DrawableImage.Draw(100, 10);
  111.  
  112.   { Render DrawableImage again, forcing alpha testing }
  113.   DrawableImage.Alpha := acTest;
  114.   DrawableImage.Draw(400, 10);
  115.   DrawableImage.Alpha := acAuto;
  116.  
  117.   FallbackFont.Print(700, 10, Red, 'Another sample text');
  118. end;
  119.  
  120. end.

Maybe your guys' point is that I should, but again this is more proof that for a newcomer who is following exactly what the examples tell him and nothing more and nothing less, it just doesn't make any sense.

Again, I will add the AvatarTransform value in the vars field because I know other examples suggest it besides this one project, but for the specific purpose of what I am doing, creating a drawing from code using a well-trusted example, it isn't done for whatever reason.

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
And actually, I was right!

I get an error on line 118 about AvatarTransform being a duplicate identifier, most likely because there was no reason to do it given how the code worked in the official example I copied, like I brought up.

Code: Pascal  [Select][+][-]
  1. {
  2.   Copyright 2020-2023 Michalis Kamburelis.
  3.  
  4.   This file is part of "Castle Game Engine".
  5.  
  6.   "Castle Game Engine" is free software; see the file COPYING.txt,
  7.   included in this distribution, for details about the copyright.
  8.  
  9.   "Castle Game Engine" is distributed in the hope that it will be useful,
  10.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12.  
  13.   ----------------------------------------------------------------------------
  14. }
  15.  
  16. { Main "playing game" view, where most of the game logic takes place. }
  17. unit GameViewPlay;
  18.  
  19. { Unit for GameMesh renderer features. }
  20.  
  21. {.$define CASTLE_UNFINISHED_CHANGE_TRANSFORMATION_BY_FORCE}
  22.  
  23. interface
  24.  
  25. uses Classes,
  26.   CastleComponentSerialize, CastleUIControls, CastleControls,
  27.   CastleKeysMouse, CastleViewport, CastleScene, CastleVectors, CastleCameras,
  28.   CastleTransform, CastleInputs, CastleThirdPersonNavigation, CastleDebugTransform,
  29.   CastleSceneCore, SysUtils, CastleRenderPrimitives, CastleBoxes,
  30.   GameEnemy;
  31.  
  32. type
  33.  
  34.   { Main "playing game" view, where most of the game logic takes place. }
  35.   TViewPlay = class(TCastleView)
  36.   published
  37.     { Components designed using CGE editor.
  38.       These fields will be automatically initialized at Start. }
  39.     LabelFps: TCastleLabel;
  40.     MainViewport: TCastleViewport;
  41.     AvatarTransform: TCastleTransform;
  42.     SandyLegs, SandyHead, SandyTorso, SceneLevel: TCastleScene;
  43.     AvatarRigidBody: TCastleRigidBody;
  44.     CheckboxCameraFollows: TCastleCheckbox;
  45.     CheckboxAimAvatar: TCastleCheckbox;
  46.     CheckboxDebugAvatarColliders: TCastleCheckbox;
  47.     CheckboxImmediatelyFixBlockedCamera: TCastleCheckbox;
  48.     SliderAirRotationControl: TCastleFloatSlider;
  49.     SliderAirMovementControl: TCastleFloatSlider;
  50.     ButtonChangeTransformationAuto,
  51.     ButtonChangeTransformationDirect,
  52.     ButtonChangeTransformationVelocity,
  53.     ButtonChangeTransformationForce: TCastleButton;
  54.   private
  55.     { Enemies behaviors }
  56.     Enemies: TEnemyList;
  57.  
  58.     DebugAvatar: TDebugTransform;
  59.     { Change things after ThirdPersonNavigation.ChangeTransformation changed. }
  60.     procedure UpdateAfterChangeTransformation;
  61.     procedure ChangeCheckboxCameraFollows(Sender: TObject);
  62.     procedure ChangeCheckboxAimAvatar(Sender: TObject);
  63.     procedure ChangeCheckboxDebugAvatarColliders(Sender: TObject);
  64.     procedure ChangeCheckboxImmediatelyFixBlockedCamera(Sender: TObject);
  65.     procedure ChangeAirRotationControl(Sender: TObject);
  66.     procedure ChangeAirMovementControl(Sender: TObject);
  67.     procedure ClickChangeTransformationAuto(Sender: TObject);
  68.     procedure ClickChangeTransformationDirect(Sender: TObject);
  69.     procedure ClickChangeTransformationVelocity(Sender: TObject);
  70.     procedure ClickChangeTransformationForce(Sender: TObject);
  71.   public
  72.     constructor Create(AOwner: TComponent); override;
  73.     procedure Start; override;
  74.     procedure Stop; override;
  75.     procedure Update(const SecondsPassed: Single; var HandleInput: Boolean); override;
  76.     function Press(const Event: TInputPressRelease): Boolean; override;
  77.     function Release(const Event: TInputPressRelease): Boolean; override;
  78.   end;
  79.  
  80.   TMyThirdPersonNavigation = class(TCastleThirdPersonNavigation)
  81.   protected
  82.     procedure SetAnimation(const AnimationNames: array of String); override;
  83.   end;
  84.  
  85. var
  86.   ViewPlay: TViewPlay;
  87.   MyThirdPersonNavigation: TMyThirdPersonNavigation;
  88.   GroundRayCast: TPhysicsRayCastResult;
  89.   StandOnGround: Boolean;
  90.   SandyInRunning: Boolean;
  91.   MaxDistance: Integer;
  92.  
  93. implementation
  94.  
  95. uses Math, StrUtils, CastleRenderContext, CastleColors,
  96.   CastleSoundEngine, CastleLog, CastleStringUtils, CastleFilesUtils,
  97.   GameViewMenu, GameMyMesh;
  98.  
  99. { TViewPlay ----------------------------------------------------------------- }
  100.  
  101. constructor TViewPlay.Create(AOwner: TComponent);
  102. begin
  103.   inherited;
  104.   DesignUrl := 'castle-data:/gameviewplay.castle-user-interface';
  105. end;
  106.  
  107. procedure TMyThirdPersonNavigation.SetAnimation(const AnimationNames: array of String);
  108. begin
  109.  
  110. end;
  111.  
  112. procedure TViewPlay.Start;
  113. var
  114.   SoldierScene: TCastleScene;
  115.   Enemy: TEnemy;
  116.   I: Integer;
  117.   MyMesh: TMyMesh;
  118.   AvatarTransform: TCastleTransform;
  119. begin
  120.   inherited;
  121.  
  122.   MyMesh := TMyMesh.Create(FreeAtStop);
  123.   AvatarTransform.Add(MyMesh);
  124.  
  125.   MyThirdPersonNavigation := TMyThirdPersonNavigation.Create(FreeAtStop);
  126.   { Create TEnemy instances, add them to Enemies list }
  127.   Enemies := TEnemyList.Create(true);
  128.      for I := 1 to 4 do
  129.      begin
  130.         SoldierScene := DesignedComponent('SceneSoldier' + IntToStr(I)) as TCastleScene;
  131.         { Below using nil as Owner of TEnemy, as the Enemies list already "owns"
  132.         instances of this class, i.e. it will free them. }
  133.         Enemy := TEnemy.Create(nil);
  134.         SoldierScene.AddBehavior(Enemy);
  135.         Enemies.Add(Enemy);
  136.      end;
  137.  
  138.   { synchronize state -> UI }
  139.   SliderAirRotationControl.Value := MyThirdPersonNavigation.AirRotationControl;
  140.   SliderAirMovementControl.Value := MyThirdPersonNavigation.AirMovementControl;
  141.   UpdateAfterChangeTransformation;
  142.  
  143.   CheckboxCameraFollows.OnChange := {$ifdef FPC}@{$endif} ChangeCheckboxCameraFollows;
  144.   CheckboxAimAvatar.OnChange := {$ifdef FPC}@{$endif} ChangeCheckboxAimAvatar;
  145.   CheckboxDebugAvatarColliders.OnChange := {$ifdef FPC}@{$endif} ChangeCheckboxDebugAvatarColliders;
  146.   CheckboxImmediatelyFixBlockedCamera.OnChange := {$ifdef FPC}@{$endif} ChangeCheckboxImmediatelyFixBlockedCamera;
  147.   SliderAirRotationControl.OnChange := {$ifdef FPC}@{$endif} ChangeAirRotationControl;
  148.   SliderAirMovementControl.OnChange := {$ifdef FPC}@{$endif} ChangeAirMovementControl;
  149.   ButtonChangeTransformationAuto.OnClick := {$ifdef FPC}@{$endif} ClickChangeTransformationAuto;
  150.   ButtonChangeTransformationDirect.OnClick := {$ifdef FPC}@{$endif} ClickChangeTransformationDirect;
  151.   ButtonChangeTransformationVelocity.OnClick := {$ifdef FPC}@{$endif} ClickChangeTransformationVelocity;
  152.   ButtonChangeTransformationForce.OnClick := {$ifdef FPC}@{$endif} ClickChangeTransformationForce;
  153.  
  154.   {$ifndef CASTLE_UNFINISHED_CHANGE_TRANSFORMATION_BY_FORCE}
  155.   { Hide UI to test ChangeTransformation = ctForce, it is not finished now,
  156.     not really useful for normal usage. }
  157.   ButtonChangeTransformationForce.Exists := false;
  158.   {$endif}
  159.  
  160.   { This configures SceneAvatar.Middle point, used for shooting.
  161.     In case of old physics (ChangeTransformation = ctDirect) this is also the center
  162.     of SceneAvatar.CollisionSphereRadius. }
  163.   // SceneAvatar.MiddleHeight := 0.9;
  164.  
  165.   { Configure some parameters of old simple physics,
  166.     these only matter when SceneAvatar.Gravity = true.
  167.     Don't use these deprecated things if you don't plan to use ChangeTransformation = ctDirect! }
  168.   // SceneAvatar.GrowSpeed := 10.0;
  169.   // SceneAvatar.FallSpeed := 10.0;
  170.   { When avatar collides as sphere it can climb stairs,
  171.     because legs can temporarily collide with objects. }
  172.   // SceneAvatar.CollisionSphereRadius := 0.5;
  173.  
  174.   { Visualize SceneAvatar bounding box, sphere, middle point, direction etc. }
  175.   DebugAvatar := TDebugTransform.Create(FreeAtStop);
  176.   // DebugAvatar.Parent := SceneAvatar;
  177.  
  178.   { Configure MyThirdPersonNavigation keys (for now, we don't expose doing this in CGE editor). }
  179.   MyThirdPersonNavigation.Input_LeftStrafe.Assign(keyQ);
  180.   MyThirdPersonNavigation.Input_RightStrafe.Assign(keyE);
  181.   MyThirdPersonNavigation.MouseLook := true; // TODO: assigning it from editor doesn't make mouse hidden in mouse look
  182.   MyThirdPersonNavigation.Init;
  183.   MyThirdPersonNavigation.AvatarHierarchy := AvatarTransform;
  184.   SandyLegs.AutoAnimation := 'LEGS_IDLE';
  185.   SandyTorso.AutoAnimation := 'TORSO_IDLE';
  186. end;
  187.  
  188. procedure TViewPlay.Stop;
  189. begin
  190.   FreeAndNil(Enemies);
  191.   inherited;
  192. end;
  193.  
  194. procedure TViewPlay.Update(const SecondsPassed: Single; var HandleInput: Boolean);
  195.  
  196.   // Test: use this to make AimAvatar only when *holding* right mouse button.
  197.   (*
  198.   procedure UpdateAimAvatar;
  199.   begin
  200.     if buttonRight in Container.MousePressed then
  201.       ThirdPersonNavigation.AimAvatar := aaHorizontal
  202.     else
  203.       ThirdPersonNavigation.AimAvatar := aaNone;
  204.  
  205.     { In this case CheckboxAimAvatar only serves to visualize whether
  206.       the right mouse button is pressed now. }
  207.     CheckboxAimAvatar.Checked := ThirdPersonNavigation.AimAvatar <> aaNone;
  208.   end;
  209.   *)
  210.  
  211. var
  212.   SandyAnims: array of String;
  213.   RayCastResult: TPhysicsRayCastResult;
  214.   MoveAmount: TVector3;
  215.   RayCastDirection: TVector3;
  216.   MaxDistance: Single;
  217.   SandyAirborne: Integer;
  218.   SandyIdling: Integer;
  219. begin
  220.   inherited;
  221.   { This virtual method is executed every frame (many times per second). }
  222.   SandyIdling := 0;
  223.   SandyAirborne := 0;
  224.   MaxDistance := 0.3;
  225.   MoveAmount := Vector3(0, -5, 0);
  226.   RayCastDirection := Vector3(0, -1, 0);
  227.   RayCastResult := AvatarRigidBody.PhysicsRayCast(
  228.   (AvatarTransform.Translation),
  229.   RayCastDirection,
  230.   0.3
  231.   );
  232.   if RayCastResult.Hit then
  233.   begin
  234.        SandyAirborne := 0;
  235.        LabelFps.Caption := 'FPS: PLACEHOLDER';
  236.       if SandyIdling = 0 then
  237.       begin
  238.            SandyIdling := 1;
  239.            SandyLegs.PlayAnimation('LEGS_IDLE', true);
  240.            SandyTorso.PlayAnimation('TORSO_IDLE', true);
  241.       end;
  242.   end
  243.   else
  244.       SandyIdling := 0;
  245.       begin
  246.            if SandyAirborne = 0 then
  247.            begin
  248.                 SandyAirborne := 1;
  249.                 SandyTorso.PlayAnimation('TORSO_AIRBORNE', true);
  250.                 SandyLegs.PlayAnimation('LEGS_AIRBORNE', true);
  251.             end;
  252.        AvatarTransform.Move(MoveAmount, false, true);
  253.        LabelFps.Caption := 'FPS: ' + Container.Fps.ToString
  254.        end;
  255.   // UpdateAimAvatar;
  256.   end;
  257.  
  258. function TViewPlay.Press(const Event: TInputPressRelease): Boolean;
  259. var
  260.   HitByAvatar: TCastleTransform;
  261.   HitEnemy: TEnemy;
  262. begin
  263.   Result := inherited;
  264.   if Result then Exit; // allow the ancestor to handle keys
  265.  
  266.   { This virtual method is executed when user presses
  267.     a key, a mouse button, or touches a touch-screen.
  268.  
  269.     Note that each UI control has also events like OnPress and OnClick.
  270.     These events can be used to handle the "press", if it should do something
  271.     specific when used in that UI control.
  272.     The TViewPlay.Press method should be used to handle keys
  273.     not handled in children controls.
  274.   }
  275.  
  276.   if Event.IsMouseButton(buttonLeft) then
  277.   begin
  278.     SoundEngine.Play(SoundEngine.SoundFromName('shoot_sound'));
  279.   end;
  280.  
  281.   if Event.IsMouseButton(buttonRight) then
  282.   begin
  283.     MyThirdPersonNavigation.MouseLook := not MyThirdPersonNavigation.MouseLook;
  284.     Exit(true);
  285.   end;
  286.  
  287.   if Event.IsKey(keyF5) then
  288.   begin
  289.     Container.SaveScreenToDefaultFile;
  290.     Exit(true);
  291.   end;
  292.  
  293.   if Event.IsKey(keyEscape) then
  294.   begin
  295.     Container.View := ViewMenu;
  296.     Exit(true);
  297.   end;
  298.  
  299.   if (Event.IsKey(keyArrowUp) and SandyInRunning = false) then
  300.   begin
  301.     SandyInRunning := true;
  302.     SandyLegs.PlayAnimation('LEGS_RUN', true);
  303.     SandyTorso.PlayAnimation('TORSO_RUN', true);
  304.   end;
  305. end;
  306.  
  307. function TViewPlay.Release(const Event: TInputPressRelease): Boolean;
  308. begin
  309.   Result := inherited;
  310.   if Result then Exit; // allow the ancestor to handle keys
  311.  
  312.   { This virtual method is executed when user releases
  313.     a key, a mouse button, or touches a touch-screen.
  314.  
  315.     Note that each UI control has also events like OnPress and OnClick.
  316.     These events can be used to handle the "press", if it should do something
  317.     specific when used in that UI control.
  318.     The TViewPlay.Release method should be used to handle keys
  319.     not handled in children controls.
  320.   }
  321.  
  322.   if (Event.IsKey(keyArrowUp) and SandyInRunning = true) then
  323.   begin
  324.     SandyInRunning := false;
  325.     SandyLegs.PlayAnimation('BOTH_IDLE', true);
  326.     SandyTorso.PlayAnimation('BOTH_IDLE', true);
  327.   end;
  328. end;
  329.  
  330. procedure TViewPlay.ChangeCheckboxCameraFollows(Sender: TObject);
  331. begin
  332.   MyThirdPersonNavigation.CameraFollows := CheckboxCameraFollows.Checked;
  333. end;
  334.  
  335. procedure TViewPlay.ChangeCheckboxAimAvatar(Sender: TObject);
  336. begin
  337.   if CheckboxAimAvatar.Checked then
  338.     MyThirdPersonNavigation.AimAvatar := aaHorizontal
  339.   else
  340.     MyThirdPersonNavigation.AimAvatar := aaNone;
  341.  
  342.   { The 3rd option, aaFlying, doesn't make sense for this case,
  343.     when avatar walks on the ground and has Gravity = true. }
  344. end;
  345.  
  346. procedure TViewPlay.ChangeCheckboxDebugAvatarColliders(Sender: TObject);
  347. begin
  348.   DebugAvatar.Exists := CheckboxDebugAvatarColliders.Checked;
  349. end;
  350.  
  351. procedure TViewPlay.ChangeCheckboxImmediatelyFixBlockedCamera(Sender: TObject);
  352. begin
  353.   MyThirdPersonNavigation.ImmediatelyFixBlockedCamera := CheckboxImmediatelyFixBlockedCamera.Checked;
  354. end;
  355.  
  356. procedure TViewPlay.ChangeAirRotationControl(Sender: TObject);
  357. begin
  358.   MyThirdPersonNavigation.AirRotationControl := SliderAirRotationControl.Value;
  359. end;
  360.  
  361. procedure TViewPlay.ChangeAirMovementControl(Sender: TObject);
  362. begin
  363.   MyThirdPersonNavigation.AirMovementControl := SliderAirMovementControl.Value;
  364. end;
  365.  
  366. procedure TViewPlay.UpdateAfterChangeTransformation;
  367. begin
  368.   ButtonChangeTransformationAuto.Pressed := MyThirdPersonNavigation.ChangeTransformation = ctAuto;
  369.   ButtonChangeTransformationDirect.Pressed := MyThirdPersonNavigation.ChangeTransformation =  ctDirect;
  370.   ButtonChangeTransformationVelocity.Pressed := MyThirdPersonNavigation.ChangeTransformation =  ctVelocity;
  371.   {$ifdef CASTLE_UNFINISHED_CHANGE_TRANSFORMATION_BY_FORCE}
  372.   ButtonChangeTransformationForce.Pressed := ThirdPersonNavigation.ChangeTransformation = ctForce;
  373.   {$endif}
  374.  
  375.   { ctDirect requires to set up gravity without physics engine,
  376.     using deprecated TCastleTransform.Gravity.
  377.     See https://castle-engine.io/physics#_old_system_for_collisions_and_gravity }
  378.   AvatarRigidBody.Exists := MyThirdPersonNavigation.ChangeTransformation <> ctDirect;
  379.  
  380.   { Gravity means that object tries to maintain a constant height
  381.     (SceneAvatar.PreferredHeight) above the ground.
  382.     GrowSpeed means that object raises properly (makes walking up the stairs work).
  383.     FallSpeed means that object falls properly (makes walking down the stairs,
  384.     falling down pit etc. work). }
  385.   SandyTorso.Gravity := not AvatarRigidBody.Exists;
  386.   SandyLegs.Gravity := not AvatarRigidBody.Exists;
  387.   SandyHead.Gravity := not AvatarRigidBody.Exists;
  388. end;
  389.  
  390. procedure TViewPlay.ClickChangeTransformationAuto(Sender: TObject);
  391. begin
  392.   MyThirdPersonNavigation.ChangeTransformation := ctAuto;
  393.   UpdateAfterChangeTransformation;
  394. end;
  395.  
  396. procedure TViewPlay.ClickChangeTransformationDirect(Sender: TObject);
  397. begin
  398.   MyThirdPersonNavigation.ChangeTransformation := ctDirect;
  399.   UpdateAfterChangeTransformation;
  400. end;
  401.  
  402. procedure TViewPlay.ClickChangeTransformationVelocity(Sender: TObject);
  403. begin
  404.   MyThirdPersonNavigation.ChangeTransformation := ctVelocity;
  405.   UpdateAfterChangeTransformation;
  406. end;
  407.  
  408. procedure TViewPlay.ClickChangeTransformationForce(Sender: TObject);
  409. begin
  410.   {$ifdef CASTLE_UNFINISHED_CHANGE_TRANSFORMATION_BY_FORCE}
  411.   ThirdPersonNavigation.ChangeTransformation := ctForce;
  412.   {$endif}
  413.   UpdateAfterChangeTransformation;
  414. end;
  415.  
  416. end.

cdbc

  • Hero Member
  • *****
  • Posts: 1868
    • http://www.cdbc.dk
Hi
Quote
Again, I will add the AvatarTransform value in the vars field because I know other examples suggest it besides this one project
NO, why would you do that?!? AvatarTransform IS ALREADY a part of the object, see here:
Code: Pascal  [Select][+][-]
  1.   TViewPlay = class(TCastleView)
  2.   published
  3.     { Components designed using CGE editor.
  4.       These fields will be automatically initialized at Start. }
  5.     LabelFps: TCastleLabel;
  6.     MainViewport: TCastleViewport;
  7. ///////// HERE //////////
  8.     AvatarTransform: TCastleTransform;
  9. /////////HERE ///////////
  10.  
You just don't CREATE IT, Do that, before you use it the first time.
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

cdbc

  • Hero Member
  • *****
  • Posts: 1868
    • http://www.cdbc.dk
Hi
What happens if you create it here:
Code: Pascal  [Select][+][-]
  1. procedure TViewPlay.Start;
  2. var
  3.   SoldierScene: TCastleScene;
  4.   Enemy: TEnemy;
  5.   I: Integer;
  6.   MyMesh: TMyMesh;
  7. begin
  8.   inherited;
  9.   /////////// try here //////////
  10.   AvatarTransform:= TAvatarTransform.Create({someparams});
  11.   /////////// above /////////////
  12.   MyMesh := TMyMesh.Create(FreeAtStop);
  13.   AvatarTransform.Add(MyMesh);
  14.   // etc...
  15.  
Just curious  :D
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
*Facepalm* but why should I, if as I pointed out clearly the official example doesn't and still works 100% fine? This is the kind of stuff I am saying doesn't make any sense to people without insider knowledge.

Or if it's created, then maybe you mean that it's created in the scene itself, but again I already did that too - you will notice in my project I have AvatarTransform as a well-defined Transform object in particular, just like UnlitMeshParent in the official example, which again is known to work flawlessly the way it is?

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
I will follow your example suggestion, but again I still stand by if you read the official example carefully, that line never ever comes up.

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
Here it is with the new line added about creating the Transform:

Code: Pascal  [Select][+][-]
  1. {
  2.   Copyright 2020-2023 Michalis Kamburelis.
  3.  
  4.   This file is part of "Castle Game Engine".
  5.  
  6.   "Castle Game Engine" is free software; see the file COPYING.txt,
  7.   included in this distribution, for details about the copyright.
  8.  
  9.   "Castle Game Engine" is distributed in the hope that it will be useful,
  10.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12.  
  13.   ----------------------------------------------------------------------------
  14. }
  15.  
  16. { Main "playing game" view, where most of the game logic takes place. }
  17. unit GameViewPlay;
  18.  
  19. { Unit for GameMesh renderer features. }
  20.  
  21. {.$define CASTLE_UNFINISHED_CHANGE_TRANSFORMATION_BY_FORCE}
  22.  
  23. interface
  24.  
  25. uses Classes,
  26.   CastleComponentSerialize, CastleUIControls, CastleControls,
  27.   CastleKeysMouse, CastleViewport, CastleScene, CastleVectors, CastleCameras,
  28.   CastleTransform, CastleInputs, CastleThirdPersonNavigation, CastleDebugTransform,
  29.   CastleSceneCore, SysUtils, CastleRenderPrimitives, CastleBoxes,
  30.   GameEnemy;
  31.  
  32. type
  33.  
  34.   { Main "playing game" view, where most of the game logic takes place. }
  35.   TViewPlay = class(TCastleView)
  36.   published
  37.     { Components designed using CGE editor.
  38.       These fields will be automatically initialized at Start. }
  39.     LabelFps: TCastleLabel;
  40.     MainViewport: TCastleViewport;
  41.     AvatarTransform: TCastleTransform;
  42.     SandyLegs, SandyHead, SandyTorso, SceneLevel: TCastleScene;
  43.     AvatarRigidBody: TCastleRigidBody;
  44.     CheckboxCameraFollows: TCastleCheckbox;
  45.     CheckboxAimAvatar: TCastleCheckbox;
  46.     CheckboxDebugAvatarColliders: TCastleCheckbox;
  47.     CheckboxImmediatelyFixBlockedCamera: TCastleCheckbox;
  48.     SliderAirRotationControl: TCastleFloatSlider;
  49.     SliderAirMovementControl: TCastleFloatSlider;
  50.     ButtonChangeTransformationAuto,
  51.     ButtonChangeTransformationDirect,
  52.     ButtonChangeTransformationVelocity,
  53.     ButtonChangeTransformationForce: TCastleButton;
  54.   private
  55.     { Enemies behaviors }
  56.     Enemies: TEnemyList;
  57.  
  58.     DebugAvatar: TDebugTransform;
  59.     { Change things after ThirdPersonNavigation.ChangeTransformation changed. }
  60.     procedure UpdateAfterChangeTransformation;
  61.     procedure ChangeCheckboxCameraFollows(Sender: TObject);
  62.     procedure ChangeCheckboxAimAvatar(Sender: TObject);
  63.     procedure ChangeCheckboxDebugAvatarColliders(Sender: TObject);
  64.     procedure ChangeCheckboxImmediatelyFixBlockedCamera(Sender: TObject);
  65.     procedure ChangeAirRotationControl(Sender: TObject);
  66.     procedure ChangeAirMovementControl(Sender: TObject);
  67.     procedure ClickChangeTransformationAuto(Sender: TObject);
  68.     procedure ClickChangeTransformationDirect(Sender: TObject);
  69.     procedure ClickChangeTransformationVelocity(Sender: TObject);
  70.     procedure ClickChangeTransformationForce(Sender: TObject);
  71.   public
  72.     constructor Create(AOwner: TComponent); override;
  73.     procedure Start; override;
  74.     procedure Stop; override;
  75.     procedure Update(const SecondsPassed: Single; var HandleInput: Boolean); override;
  76.     function Press(const Event: TInputPressRelease): Boolean; override;
  77.     function Release(const Event: TInputPressRelease): Boolean; override;
  78.   end;
  79.  
  80.   TMyThirdPersonNavigation = class(TCastleThirdPersonNavigation)
  81.   protected
  82.     procedure SetAnimation(const AnimationNames: array of String); override;
  83.   end;
  84.  
  85. var
  86.   ViewPlay: TViewPlay;
  87.   MyThirdPersonNavigation: TMyThirdPersonNavigation;
  88.   GroundRayCast: TPhysicsRayCastResult;
  89.   StandOnGround: Boolean;
  90.   SandyInRunning: Boolean;
  91.   MaxDistance: Integer;
  92.  
  93. implementation
  94.  
  95. uses Math, StrUtils, CastleRenderContext, CastleColors,
  96.   CastleSoundEngine, CastleLog, CastleStringUtils, CastleFilesUtils,
  97.   GameViewMenu, GameMyMesh;
  98.  
  99. { TViewPlay ----------------------------------------------------------------- }
  100.  
  101. constructor TViewPlay.Create(AOwner: TComponent);
  102. begin
  103.   inherited;
  104.   DesignUrl := 'castle-data:/gameviewplay.castle-user-interface';
  105. end;
  106.  
  107. procedure TMyThirdPersonNavigation.SetAnimation(const AnimationNames: array of String);
  108. begin
  109.  
  110. end;
  111.  
  112. procedure TViewPlay.Start;
  113. var
  114.   SoldierScene: TCastleScene;
  115.   Enemy: TEnemy;
  116.   I: Integer;
  117.   MyMesh: TMyMesh;
  118. begin
  119.   inherited;
  120.  
  121.   AvatarTransform := TAvatarTransform.Create(FreeAtStop);
  122.  
  123.   MyMesh := TMyMesh.Create(FreeAtStop);
  124.   AvatarTransform.Add(MyMesh);
  125.  
  126.   MyThirdPersonNavigation := TMyThirdPersonNavigation.Create(FreeAtStop);
  127.   { Create TEnemy instances, add them to Enemies list }
  128.   Enemies := TEnemyList.Create(true);
  129.      for I := 1 to 4 do
  130.      begin
  131.         SoldierScene := DesignedComponent('SceneSoldier' + IntToStr(I)) as TCastleScene;
  132.         { Below using nil as Owner of TEnemy, as the Enemies list already "owns"
  133.         instances of this class, i.e. it will free them. }
  134.         Enemy := TEnemy.Create(nil);
  135.         SoldierScene.AddBehavior(Enemy);
  136.         Enemies.Add(Enemy);
  137.      end;
  138.  
  139.   { synchronize state -> UI }
  140.   SliderAirRotationControl.Value := MyThirdPersonNavigation.AirRotationControl;
  141.   SliderAirMovementControl.Value := MyThirdPersonNavigation.AirMovementControl;
  142.   UpdateAfterChangeTransformation;
  143.  
  144.   CheckboxCameraFollows.OnChange := {$ifdef FPC}@{$endif} ChangeCheckboxCameraFollows;
  145.   CheckboxAimAvatar.OnChange := {$ifdef FPC}@{$endif} ChangeCheckboxAimAvatar;
  146.   CheckboxDebugAvatarColliders.OnChange := {$ifdef FPC}@{$endif} ChangeCheckboxDebugAvatarColliders;
  147.   CheckboxImmediatelyFixBlockedCamera.OnChange := {$ifdef FPC}@{$endif} ChangeCheckboxImmediatelyFixBlockedCamera;
  148.   SliderAirRotationControl.OnChange := {$ifdef FPC}@{$endif} ChangeAirRotationControl;
  149.   SliderAirMovementControl.OnChange := {$ifdef FPC}@{$endif} ChangeAirMovementControl;
  150.   ButtonChangeTransformationAuto.OnClick := {$ifdef FPC}@{$endif} ClickChangeTransformationAuto;
  151.   ButtonChangeTransformationDirect.OnClick := {$ifdef FPC}@{$endif} ClickChangeTransformationDirect;
  152.   ButtonChangeTransformationVelocity.OnClick := {$ifdef FPC}@{$endif} ClickChangeTransformationVelocity;
  153.   ButtonChangeTransformationForce.OnClick := {$ifdef FPC}@{$endif} ClickChangeTransformationForce;
  154.  
  155.   {$ifndef CASTLE_UNFINISHED_CHANGE_TRANSFORMATION_BY_FORCE}
  156.   { Hide UI to test ChangeTransformation = ctForce, it is not finished now,
  157.     not really useful for normal usage. }
  158.   ButtonChangeTransformationForce.Exists := false;
  159.   {$endif}
  160.  
  161.   { This configures SceneAvatar.Middle point, used for shooting.
  162.     In case of old physics (ChangeTransformation = ctDirect) this is also the center
  163.     of SceneAvatar.CollisionSphereRadius. }
  164.   // SceneAvatar.MiddleHeight := 0.9;
  165.  
  166.   { Configure some parameters of old simple physics,
  167.     these only matter when SceneAvatar.Gravity = true.
  168.     Don't use these deprecated things if you don't plan to use ChangeTransformation = ctDirect! }
  169.   // SceneAvatar.GrowSpeed := 10.0;
  170.   // SceneAvatar.FallSpeed := 10.0;
  171.   { When avatar collides as sphere it can climb stairs,
  172.     because legs can temporarily collide with objects. }
  173.   // SceneAvatar.CollisionSphereRadius := 0.5;
  174.  
  175.   { Visualize SceneAvatar bounding box, sphere, middle point, direction etc. }
  176.   DebugAvatar := TDebugTransform.Create(FreeAtStop);
  177.   // DebugAvatar.Parent := SceneAvatar;
  178.  
  179.   { Configure MyThirdPersonNavigation keys (for now, we don't expose doing this in CGE editor). }
  180.   MyThirdPersonNavigation.Input_LeftStrafe.Assign(keyQ);
  181.   MyThirdPersonNavigation.Input_RightStrafe.Assign(keyE);
  182.   MyThirdPersonNavigation.MouseLook := true; // TODO: assigning it from editor doesn't make mouse hidden in mouse look
  183.   MyThirdPersonNavigation.Init;
  184.   MyThirdPersonNavigation.AvatarHierarchy := AvatarTransform;
  185.   SandyLegs.AutoAnimation := 'LEGS_IDLE';
  186.   SandyTorso.AutoAnimation := 'TORSO_IDLE';
  187. end;
  188.  
  189. procedure TViewPlay.Stop;
  190. begin
  191.   FreeAndNil(Enemies);
  192.   inherited;
  193. end;
  194.  
  195. procedure TViewPlay.Update(const SecondsPassed: Single; var HandleInput: Boolean);
  196.  
  197.   // Test: use this to make AimAvatar only when *holding* right mouse button.
  198.   (*
  199.   procedure UpdateAimAvatar;
  200.   begin
  201.     if buttonRight in Container.MousePressed then
  202.       ThirdPersonNavigation.AimAvatar := aaHorizontal
  203.     else
  204.       ThirdPersonNavigation.AimAvatar := aaNone;
  205.  
  206.     { In this case CheckboxAimAvatar only serves to visualize whether
  207.       the right mouse button is pressed now. }
  208.     CheckboxAimAvatar.Checked := ThirdPersonNavigation.AimAvatar <> aaNone;
  209.   end;
  210.   *)
  211.  
  212. var
  213.   SandyAnims: array of String;
  214.   RayCastResult: TPhysicsRayCastResult;
  215.   MoveAmount: TVector3;
  216.   RayCastDirection: TVector3;
  217.   MaxDistance: Single;
  218.   SandyAirborne: Integer;
  219.   SandyIdling: Integer;
  220. begin
  221.   inherited;
  222.   { This virtual method is executed every frame (many times per second). }
  223.   SandyIdling := 0;
  224.   SandyAirborne := 0;
  225.   MaxDistance := 0.3;
  226.   MoveAmount := Vector3(0, -5, 0);
  227.   RayCastDirection := Vector3(0, -1, 0);
  228.   RayCastResult := AvatarRigidBody.PhysicsRayCast(
  229.   (AvatarTransform.Translation),
  230.   RayCastDirection,
  231.   0.3
  232.   );
  233.   if RayCastResult.Hit then
  234.   begin
  235.        SandyAirborne := 0;
  236.        LabelFps.Caption := 'FPS: PLACEHOLDER';
  237.       if SandyIdling = 0 then
  238.       begin
  239.            SandyIdling := 1;
  240.            SandyLegs.PlayAnimation('LEGS_IDLE', true);
  241.            SandyTorso.PlayAnimation('TORSO_IDLE', true);
  242.       end;
  243.   end
  244.   else
  245.       SandyIdling := 0;
  246.       begin
  247.            if SandyAirborne = 0 then
  248.            begin
  249.                 SandyAirborne := 1;
  250.                 SandyTorso.PlayAnimation('TORSO_AIRBORNE', true);
  251.                 SandyLegs.PlayAnimation('LEGS_AIRBORNE', true);
  252.             end;
  253.        AvatarTransform.Move(MoveAmount, false, true);
  254.        LabelFps.Caption := 'FPS: ' + Container.Fps.ToString
  255.        end;
  256.   // UpdateAimAvatar;
  257.   end;
  258.  
  259. function TViewPlay.Press(const Event: TInputPressRelease): Boolean;
  260. var
  261.   HitByAvatar: TCastleTransform;
  262.   HitEnemy: TEnemy;
  263. begin
  264.   Result := inherited;
  265.   if Result then Exit; // allow the ancestor to handle keys
  266.  
  267.   { This virtual method is executed when user presses
  268.     a key, a mouse button, or touches a touch-screen.
  269.  
  270.     Note that each UI control has also events like OnPress and OnClick.
  271.     These events can be used to handle the "press", if it should do something
  272.     specific when used in that UI control.
  273.     The TViewPlay.Press method should be used to handle keys
  274.     not handled in children controls.
  275.   }
  276.  
  277.   if Event.IsMouseButton(buttonLeft) then
  278.   begin
  279.     SoundEngine.Play(SoundEngine.SoundFromName('shoot_sound'));
  280.   end;
  281.  
  282.   if Event.IsMouseButton(buttonRight) then
  283.   begin
  284.     MyThirdPersonNavigation.MouseLook := not MyThirdPersonNavigation.MouseLook;
  285.     Exit(true);
  286.   end;
  287.  
  288.   if Event.IsKey(keyF5) then
  289.   begin
  290.     Container.SaveScreenToDefaultFile;
  291.     Exit(true);
  292.   end;
  293.  
  294.   if Event.IsKey(keyEscape) then
  295.   begin
  296.     Container.View := ViewMenu;
  297.     Exit(true);
  298.   end;
  299.  
  300.   if (Event.IsKey(keyArrowUp) and SandyInRunning = false) then
  301.   begin
  302.     SandyInRunning := true;
  303.     SandyLegs.PlayAnimation('LEGS_RUN', true);
  304.     SandyTorso.PlayAnimation('TORSO_RUN', true);
  305.   end;
  306. end;
  307.  
  308. function TViewPlay.Release(const Event: TInputPressRelease): Boolean;
  309. begin
  310.   Result := inherited;
  311.   if Result then Exit; // allow the ancestor to handle keys
  312.  
  313.   { This virtual method is executed when user releases
  314.     a key, a mouse button, or touches a touch-screen.
  315.  
  316.     Note that each UI control has also events like OnPress and OnClick.
  317.     These events can be used to handle the "press", if it should do something
  318.     specific when used in that UI control.
  319.     The TViewPlay.Release method should be used to handle keys
  320.     not handled in children controls.
  321.   }
  322.  
  323.   if (Event.IsKey(keyArrowUp) and SandyInRunning = true) then
  324.   begin
  325.     SandyInRunning := false;
  326.     SandyLegs.PlayAnimation('BOTH_IDLE', true);
  327.     SandyTorso.PlayAnimation('BOTH_IDLE', true);
  328.   end;
  329. end;
  330.  
  331. procedure TViewPlay.ChangeCheckboxCameraFollows(Sender: TObject);
  332. begin
  333.   MyThirdPersonNavigation.CameraFollows := CheckboxCameraFollows.Checked;
  334. end;
  335.  
  336. procedure TViewPlay.ChangeCheckboxAimAvatar(Sender: TObject);
  337. begin
  338.   if CheckboxAimAvatar.Checked then
  339.     MyThirdPersonNavigation.AimAvatar := aaHorizontal
  340.   else
  341.     MyThirdPersonNavigation.AimAvatar := aaNone;
  342.  
  343.   { The 3rd option, aaFlying, doesn't make sense for this case,
  344.     when avatar walks on the ground and has Gravity = true. }
  345. end;
  346.  
  347. procedure TViewPlay.ChangeCheckboxDebugAvatarColliders(Sender: TObject);
  348. begin
  349.   DebugAvatar.Exists := CheckboxDebugAvatarColliders.Checked;
  350. end;
  351.  
  352. procedure TViewPlay.ChangeCheckboxImmediatelyFixBlockedCamera(Sender: TObject);
  353. begin
  354.   MyThirdPersonNavigation.ImmediatelyFixBlockedCamera := CheckboxImmediatelyFixBlockedCamera.Checked;
  355. end;
  356.  
  357. procedure TViewPlay.ChangeAirRotationControl(Sender: TObject);
  358. begin
  359.   MyThirdPersonNavigation.AirRotationControl := SliderAirRotationControl.Value;
  360. end;
  361.  
  362. procedure TViewPlay.ChangeAirMovementControl(Sender: TObject);
  363. begin
  364.   MyThirdPersonNavigation.AirMovementControl := SliderAirMovementControl.Value;
  365. end;
  366.  
  367. procedure TViewPlay.UpdateAfterChangeTransformation;
  368. begin
  369.   ButtonChangeTransformationAuto.Pressed := MyThirdPersonNavigation.ChangeTransformation = ctAuto;
  370.   ButtonChangeTransformationDirect.Pressed := MyThirdPersonNavigation.ChangeTransformation =  ctDirect;
  371.   ButtonChangeTransformationVelocity.Pressed := MyThirdPersonNavigation.ChangeTransformation =  ctVelocity;
  372.   {$ifdef CASTLE_UNFINISHED_CHANGE_TRANSFORMATION_BY_FORCE}
  373.   ButtonChangeTransformationForce.Pressed := ThirdPersonNavigation.ChangeTransformation = ctForce;
  374.   {$endif}
  375.  
  376.   { ctDirect requires to set up gravity without physics engine,
  377.     using deprecated TCastleTransform.Gravity.
  378.     See https://castle-engine.io/physics#_old_system_for_collisions_and_gravity }
  379.   AvatarRigidBody.Exists := MyThirdPersonNavigation.ChangeTransformation <> ctDirect;
  380.  
  381.   { Gravity means that object tries to maintain a constant height
  382.     (SceneAvatar.PreferredHeight) above the ground.
  383.     GrowSpeed means that object raises properly (makes walking up the stairs work).
  384.     FallSpeed means that object falls properly (makes walking down the stairs,
  385.     falling down pit etc. work). }
  386.   SandyTorso.Gravity := not AvatarRigidBody.Exists;
  387.   SandyLegs.Gravity := not AvatarRigidBody.Exists;
  388.   SandyHead.Gravity := not AvatarRigidBody.Exists;
  389. end;
  390.  
  391. procedure TViewPlay.ClickChangeTransformationAuto(Sender: TObject);
  392. begin
  393.   MyThirdPersonNavigation.ChangeTransformation := ctAuto;
  394.   UpdateAfterChangeTransformation;
  395. end;
  396.  
  397. procedure TViewPlay.ClickChangeTransformationDirect(Sender: TObject);
  398. begin
  399.   MyThirdPersonNavigation.ChangeTransformation := ctDirect;
  400.   UpdateAfterChangeTransformation;
  401. end;
  402.  
  403. procedure TViewPlay.ClickChangeTransformationVelocity(Sender: TObject);
  404. begin
  405.   MyThirdPersonNavigation.ChangeTransformation := ctVelocity;
  406.   UpdateAfterChangeTransformation;
  407. end;
  408.  
  409. procedure TViewPlay.ClickChangeTransformationForce(Sender: TObject);
  410. begin
  411.   {$ifdef CASTLE_UNFINISHED_CHANGE_TRANSFORMATION_BY_FORCE}
  412.   ThirdPersonNavigation.ChangeTransformation := ctForce;
  413.   {$endif}
  414.   UpdateAfterChangeTransformation;
  415. end;
  416.  
  417. end.

I get an error about AvatarTransform being an unidentified identifier on line 121 where I added the line about creating it, despite it being defined as a legitimate object with the reference in the list under "type", like you pointed out yourself.

These kinds of errors objectively don't make any sense to people who don't know some kind of insider trick.

michalis

  • Full Member
  • ***
  • Posts: 143
    • Castle Game Engine
You should not create "AvatarTransform" in "TViewPlay" in this case. It is a published field of the view, and it is automatically set when the view starts. See e.g. docs in https://castle-engine.io/view_events , section "5. Access designed components in the code".

( Compared to LCL, this is exactly like published fields of forms -- they are assigned automatically to deserialized components of a form you have visually designed. )

The analogy with "UnlitMeshParent" in https://github.com/castle-engine/castle-engine/blob/master/examples/research_special_rendering_methods/test_rendering_opengl_capabilities/code/gameviewmain.pas is correct in this case. In that example, there's a "UnlitMeshParent" in the corresponding design, matching variable name in code. In your case, you have "AvatarTransform" (in your code and design).

You still have error at runtime, as you didn't follow what I wrote in

Quote
> You will also still have to set the AvatarTransform on TMyMesh. Without this, that code will fail, AvatarTransform will be nil.

You didn't do it.

Follow the error message you show on the screenshot. Find the line it talks about. Research what it means -- is the `PlayerTransform` correct at this point? What value does it have? Why?

You have received an error message in one of the earlier posts. That error message points to a line in your source code. Look at that line. Hint: That line uses `PlayerTransform` variable. Test whether the value of that is correct.

And the solution is actually given above: you have to set the "AvatarTransform" field of the "TMyMesh" instance. If you are not sure what this means, consult the Pascal learning resources we pointed out.
« Last Edit: February 19, 2024, 06:54:05 pm by michalis »

 

TinyPortal © 2005-2018