Recent

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

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
Hi everyone,

I am new to these forums, but have experience in programming in many languages, like C++ or Python, using Windows computers.

I am using the Castle Game Engine to develop video games because it is 100% free and works on the very old and slow machines from the 90s, whereas most so-called professional game engines like Unity or Unreal 5 cost money or don't run on old machines you will find in most schools or homes.

The Castle Game Engine uses Pascal for its language and Lazarus for its compiler, and is cross platform, but because I am using it on a Windows computer I decided Windows forums would be most appropriate compared to "Miscallenous" which seems to be about non-home computer electronics specifically, and not cross-platform software.

I am having trouble with a project you can find on this link that you copy-paste into a new browser tab: https://drive.google.com/file/d/1HicqpXh9fk4jk6tWHzXEh4CB4zrhJnXS/view?usp=sharing, which I made free to download for everyone who has the Castle Game Engine downloaded on their computer - I made sure it actually opens on my copy correctly first obviously.

I posted the link this way as the direct link was removed for security purposes, which is fine and I understand why - it's for both the forum's and my own safety.

It is meant to be a third person game that is a platformer where you play as Sandy Cheeks from SpongeBob, like a kid friendly game.

I initially asked for help on this forum thread, again copy paste the link in a new tab cause direct links don't work for security reasons: https://forum.castle-engine.io/t/need-help-making-collision-with-ground-work-correctly/1025/62, but got called unhelpful responses like "being a hopeless idiot who doesn't pay attention" by the so-called helpers, even after I used examples to prove I was paying attention.

I understand that their point was that I would not include certain lines that made the code not work the way it does, like not including the correct amount of "begins" and "ends", but I pointed out how I understood conceptually how a begin and end block was supposed to work, like how it begins and ends a specific block of code, or that a procedure is defined in a certain way always, and that it carries out a particular task with or without a certain number of inputs, I only needed help with the details.

This code snippet is what I need help with, in the line about gamemymesh.pas:

Code: Pascal  [Select][+][-]
  1. procedure CreateMesh;
  2.   begin
  3.     Mesh := TCastleRenderUnlitMesh.Create(true);
  4.     Mesh.SetVertexes([
  5.       Vector4(-1, -1, -1, 1),
  6.       Vector4( 1, -1, -1, 1),
  7.       Vector4( 1,  1, -1, 1),
  8.       Vector4(-1,  1, -1, 1),
  9.  
  10.       Vector4(-1, -1,  1, 1),
  11.       Vector4( 1, -1,  1, 1),
  12.       Vector4( 1,  1,  1, 1),
  13.       Vector4(-1,  1,  1, 1)
  14.     ], false);
  15.     Mesh.SetIndexes([
  16.       // line loop on Z = -1
  17.       0, 1,
  18.       1, 2,
  19.       2, 3,
  20.       3, 0,
  21.  
  22.       // line loop on Z = 1
  23.       4, 5,
  24.       5, 6,
  25.       6, 7,
  26.       7, 4,
  27.  
  28.       // connect Z = -1 with Z = 1
  29.       0, 4,
  30.       1, 5,
  31.       2, 6,
  32.       3, 7
  33.     ]);
  34.  
  35.     // Later on in the code
  36.     CreateMesh;


This is the relevant code snippets from the example I was using.

I learned that SetVertices sets each point of the fesh, and SetIndices sets how the points are connected and in what order, like I initiailly guessed, when I asked.

However, when I asked for clarification on how to get custom inputs to "SetVertices", which I needed to do to get the player character's location precisely drawn down,

I wasn't given any response, so I assumed it was because they wanted me to figure things out for myself like they told me explicitly many times earlier, which is fine.

I did the resourceful thing and looked up if that particular procedure came pre-coded with a particular number of inputs/parameters in the manual's API, and fortunately it wasn't, so I made an educated guess that it was just a function customly made for that particular piece of code,

So I defined my own version of it with arguments for getting the player Transform object's properties, and made sure that each input of the Vector4's were all of the same type, so single precision singles, like the API says should happen right on the page for Vector4 itself:

Like so:

Code: Pascal  [Select][+][-]
  1.  
  2. procedure CreateMesh(const AvatarTransform: TCastleTransform);
  3.   begin
  4.     Mesh := TCastleRenderUnlitMesh.Create(true);
  5.     Mesh.SetVertexes([
  6.       Vector4(0.0, AvatarTransform.Translation.Y, 0.0, 1.0),
  7.       Vector4(0.0, (AvatarTransform.Translation.Y - AvatarTransform.Direction.Y), 0.0, 1.0)
  8.     ], false);
  9.     Mesh.SetIndexes([
  10.       // line loop on Z = -1
  11.       0, 1
  12.     ]);
  13.  
  14.  
  15.  // Line somewhere later down the code; I guessed the problem was
  16.  // not having the correct amount of inputs to match the procedure
  17.  // definition above, but it still doesn't draw anything afterward
  18.  
  19. CreateMesh(AvatarTransform);

However, as mentioned in the comments in the code, even after I correctly specify the correct number of inputs when I call the newly made function, nothing happens at all, not even drawing small dots.

Again, if you want to test this yourself, simply open the Castle Game Engine and the project, copy and paste the code from the second snippet where appropriate in the first snippet, and witness for yourself how it compiles fine but doesn't actually do anything, when I was given that the first example worked perfectly as it was.

Does anyone with any expertise in Pascal Game Engine's Lazarus compiler in particular, know why the above code in the second snippet doesn't work?
« Last Edit: February 18, 2024, 01:55:37 am by JPF12141999 »

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
I caught on that maybe changing the line about the direction to a "plus" the direction rather than "minus" the direction, might be part of the problem, but again at least something should have been drawn instead of nothing at all for the start point without the direction added, for example, and a line of some kind should still be there regardless of that detail.

I intentionally removed the "end" of the blocks because I wanted to focus on posting the minimal code necessary to reproduce the problem, trusting that the reader knows how to copy paste appropriate lines in the appropriate spots rather than just copy pasting the code exactly like that, and if you look at the full code in the project I attached, I have the end added correctly later on in the code.

michalis

  • Full Member
  • ***
  • Posts: 140
    • Castle Game Engine
To answer your main question:

You show how you setup the TCastleRenderUnlitMesh instance. But you don't show if (and where) do you call "Mesh.Render(pmLines)" which is necessary to actually render something. Possibly you just forgot it, which explains why you don't see anything.

If you are unsure how TCastleRenderUnlitMesh works, please:


Note: You didn't make https://drive.google.com/file/d/1b-aukNCEtTM09vVPh0rKv_9p5pFgwNOq/view?usp=sharing accessible to public. In GDrive, select something like "Anyone with link: Can View" in sharing permissions. So I cannot see your complete source code. I'm only basing my answer on the code snippet you pasted.

To addreess some additional things you mention in this thread, about Castle Game Engine forum (latest thread with you: https://forum.castle-engine.io/t/need-help-making-collision-with-ground-work-correctly/ ):


cdbc

  • Hero Member
  • *****
  • Posts: 1157
    • http://www.cdbc.dk
Hi
Had a 'looksee' at the last post and did some formatting and found your missing end, here it is:
Code: Pascal  [Select][+][-]
  1. begin
  2.   inherited;
  3.   { This virtual method is executed every frame (many times per second). }
  4.   SandyIdling := 0;
  5.   SandyAirborne := 0;
  6.   MaxDistance := 0.3;
  7.   MoveAmount := Vector3(0, -5, 0);
  8.   RayCastDirection := Vector3(0, -1, 0);
  9.   RayCastResult := AvatarRigidBody.PhysicsRayCast(
  10.     (AvatarTransform.Translation),
  11.     RayCastDirection,
  12.     0.3
  13.   );
  14.   if RayCastResult.Hit then
  15.   begin //1
  16.     SandyAirborne := 0;
  17.     LabelFps.Caption := 'FPS: PLACEHOLDER';
  18.     if SandyIdling = 0 then
  19.     begin //2
  20.       SandyIdling := 1;
  21.       SandyLegs.PlayAnimation('LEGS_IDLE', true);
  22.       SandyTorso.PlayAnimation('TORSO_IDLE', true);
  23.     end //2
  24.   end; //1 <<<<----- THIS ONE WAS MISSING!!!!
  25.   else
  26.   begin //3
  27.     SandyIdling := 0; { this I moved from the line above 'begin' 15.02.24 /bc }
  28.     if SandyAirborne = 0 then
  29.     begin //4
  30.       SandyAirborne := 1;
  31.       SandyTorso.PlayAnimation('TORSO_AIRBORNE', true);
  32.       SandyLegs.PlayAnimation('LEGS_AIRBORNE', true);
  33.     end; //4
  34.     AvatarTransform.Move(MoveAmount, false, true);
  35.     LabelFps.Caption := 'FPS: ' + Container.Fps.ToString
  36.   end; //3
  37.   // UpdateAimAvatar;
  38. end;
  39.  
I hope I'm not intruding...?
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
To michaelis: I did review the begins and ends, as pointed out in the thread, and although the word "idiot" wasn't used verbatim calling someone hopless when they are patiently pointing out the facts is saying exactly the same thing.

I understand he did it only once, but once is still too much/enough, especially because I was just using the facts.

I got a reply on another forum thread that I included the wrong amount of "ends", like you suggested, and that helped, but again when I checked in the compiler I got that every begin was highlighted with a red rectangle with another end that was also highlighted in the same way, like the compiler was showing me every "begin" had an "end" associated, so I didn't see what was wrong at first.

For the new problem, I am very sorry if I didn't make this 100% clear even though I tried to, but I only included the minimum amount of code relevant to the problem at hand and nothing more, and because "Mesh.Render(pmLines)" was exactly the same way in both lines, I used deductive reasoning/logic to guess that if a piece of code works correcly as it was, then it couldn't be part of the problem after changing other pieces of code; the problem had to be with the changed pieces.

Again, this kind of stuff is common sense and you understand, but the so-called "helper" calling me hopeless wouldn't listen when I pointed this out to him in many of the threads.

To cdbc:

Thank you so so much for your patient and thoughtful response! You're the best helper a newcomer to Pascal can help for :)

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
So to elaborate on my point to michaelis, you will see I actually did include it in my full code when you download the attached project, but I didn't post every last detail in my post because I only wanted to point out the problem lines in particular, and assumed the viewer would be able to download the full code and help explain the problem better once they have read every last line to the end.
« Last Edit: February 15, 2024, 10:33:07 pm by JPF12141999 »

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
Does anyone have any help, again making sure they actually download the project attached now that it's publicly viewable for everyone (I'm sorry I didn't at first - that was definitely my mistake), and read all the lines of the code and not just the problem snippet I posted?

I already fixed the repeating "end"'s that cdbc pointed out, and I already fixed the extra comma at the end of the list as pointed out earlier too; does anyone else have any other things they know are wrong with my code?

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
Okay, I was getting compile errors about semicolons and periods being in wrong places for the blocks, so here is what the fixed code looks like:

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;
  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. begin
  118.   inherited;
  119.   MyThirdPersonNavigation := TMyThirdPersonNavigation.Create(FreeAtStop);
  120.   { Create TEnemy instances, add them to Enemies list }
  121.   Enemies := TEnemyList.Create(true);
  122.      for I := 1 to 4 do
  123.      begin
  124.         SoldierScene := DesignedComponent('SceneSoldier' + IntToStr(I)) as TCastleScene;
  125.         { Below using nil as Owner of TEnemy, as the Enemies list already "owns"
  126.         instances of this class, i.e. it will free them. }
  127.         Enemy := TEnemy.Create(nil);
  128.         SoldierScene.AddBehavior(Enemy);
  129.         Enemies.Add(Enemy);
  130.      end;
  131.  
  132.   { synchronize state -> UI }
  133.   SliderAirRotationControl.Value := MyThirdPersonNavigation.AirRotationControl;
  134.   SliderAirMovementControl.Value := MyThirdPersonNavigation.AirMovementControl;
  135.   UpdateAfterChangeTransformation;
  136.  
  137.   CheckboxCameraFollows.OnChange := {$ifdef FPC}@{$endif} ChangeCheckboxCameraFollows;
  138.   CheckboxAimAvatar.OnChange := {$ifdef FPC}@{$endif} ChangeCheckboxAimAvatar;
  139.   CheckboxDebugAvatarColliders.OnChange := {$ifdef FPC}@{$endif} ChangeCheckboxDebugAvatarColliders;
  140.   CheckboxImmediatelyFixBlockedCamera.OnChange := {$ifdef FPC}@{$endif} ChangeCheckboxImmediatelyFixBlockedCamera;
  141.   SliderAirRotationControl.OnChange := {$ifdef FPC}@{$endif} ChangeAirRotationControl;
  142.   SliderAirMovementControl.OnChange := {$ifdef FPC}@{$endif} ChangeAirMovementControl;
  143.   ButtonChangeTransformationAuto.OnClick := {$ifdef FPC}@{$endif} ClickChangeTransformationAuto;
  144.   ButtonChangeTransformationDirect.OnClick := {$ifdef FPC}@{$endif} ClickChangeTransformationDirect;
  145.   ButtonChangeTransformationVelocity.OnClick := {$ifdef FPC}@{$endif} ClickChangeTransformationVelocity;
  146.   ButtonChangeTransformationForce.OnClick := {$ifdef FPC}@{$endif} ClickChangeTransformationForce;
  147.  
  148.   {$ifndef CASTLE_UNFINISHED_CHANGE_TRANSFORMATION_BY_FORCE}
  149.   { Hide UI to test ChangeTransformation = ctForce, it is not finished now,
  150.     not really useful for normal usage. }
  151.   ButtonChangeTransformationForce.Exists := false;
  152.   {$endif}
  153.  
  154.   { This configures SceneAvatar.Middle point, used for shooting.
  155.     In case of old physics (ChangeTransformation = ctDirect) this is also the center
  156.     of SceneAvatar.CollisionSphereRadius. }
  157.   // SceneAvatar.MiddleHeight := 0.9;
  158.  
  159.   { Configure some parameters of old simple physics,
  160.     these only matter when SceneAvatar.Gravity = true.
  161.     Don't use these deprecated things if you don't plan to use ChangeTransformation = ctDirect! }
  162.   // SceneAvatar.GrowSpeed := 10.0;
  163.   // SceneAvatar.FallSpeed := 10.0;
  164.   { When avatar collides as sphere it can climb stairs,
  165.     because legs can temporarily collide with objects. }
  166.   // SceneAvatar.CollisionSphereRadius := 0.5;
  167.  
  168.   { Visualize SceneAvatar bounding box, sphere, middle point, direction etc. }
  169.   DebugAvatar := TDebugTransform.Create(FreeAtStop);
  170.   // DebugAvatar.Parent := SceneAvatar;
  171.  
  172.   { Configure MyThirdPersonNavigation keys (for now, we don't expose doing this in CGE editor). }
  173.   MyThirdPersonNavigation.Input_LeftStrafe.Assign(keyQ);
  174.   MyThirdPersonNavigation.Input_RightStrafe.Assign(keyE);
  175.   MyThirdPersonNavigation.MouseLook := true; // TODO: assigning it from editor doesn't make mouse hidden in mouse look
  176.   MyThirdPersonNavigation.Init;
  177.   MyThirdPersonNavigation.AvatarHierarchy := AvatarTransform;
  178.   SandyLegs.AutoAnimation := 'LEGS_IDLE';
  179.   SandyTorso.AutoAnimation := 'TORSO_IDLE';
  180. end;
  181.  
  182. procedure TViewPlay.Stop;
  183. begin
  184.   FreeAndNil(Enemies);
  185.   inherited;
  186. end;
  187.  
  188. procedure TViewPlay.Update(const SecondsPassed: Single; var HandleInput: Boolean);
  189.  
  190.   // Test: use this to make AimAvatar only when *holding* right mouse button.
  191.   (*
  192.   procedure UpdateAimAvatar;
  193.   begin
  194.     if buttonRight in Container.MousePressed then
  195.       ThirdPersonNavigation.AimAvatar := aaHorizontal
  196.     else
  197.       ThirdPersonNavigation.AimAvatar := aaNone;
  198.  
  199.     { In this case CheckboxAimAvatar only serves to visualize whether
  200.       the right mouse button is pressed now. }
  201.     CheckboxAimAvatar.Checked := ThirdPersonNavigation.AimAvatar <> aaNone;
  202.   end;
  203.   *)
  204.  
  205. var
  206.   SandyAnims: array of String;
  207.   RayCastResult: TPhysicsRayCastResult;
  208.   MoveAmount: TVector3;
  209.   RayCastDirection: TVector3;
  210.   MaxDistance: Single;
  211.   SandyAirborne: Integer;
  212.   SandyIdling: Integer;
  213. begin
  214.   inherited;
  215.   { This virtual method is executed every frame (many times per second). }
  216.   SandyIdling := 0;
  217.   SandyAirborne := 0;
  218.   MaxDistance := 0.3;
  219.   MoveAmount := Vector3(0, -5, 0);
  220.   RayCastDirection := Vector3(0, -1, 0);
  221.   RayCastResult := AvatarRigidBody.PhysicsRayCast(
  222.   (AvatarTransform.Translation),
  223.   RayCastDirection,
  224.   0.3
  225.   );
  226.   if RayCastResult.Hit then
  227.   begin
  228.        SandyAirborne := 0;
  229.        LabelFps.Caption := 'FPS: PLACEHOLDER';
  230.       if SandyIdling = 0 then
  231.       begin
  232.            SandyIdling := 1;
  233.            SandyLegs.PlayAnimation('LEGS_IDLE', true);
  234.            SandyTorso.PlayAnimation('TORSO_IDLE', true);
  235.       end;
  236.   end
  237.   else
  238.       SandyIdling := 0;
  239.       begin
  240.            if SandyAirborne = 0 then
  241.            begin
  242.                 SandyAirborne := 1;
  243.                 SandyTorso.PlayAnimation('TORSO_AIRBORNE', true);
  244.                 SandyLegs.PlayAnimation('LEGS_AIRBORNE', true);
  245.             end;
  246.        AvatarTransform.Move(MoveAmount, false, true);
  247.        LabelFps.Caption := 'FPS: ' + Container.Fps.ToString
  248.        end;
  249.   // UpdateAimAvatar;
  250.   end;
  251.  
  252. end.
  253.  
  254. function TViewPlay.Press(const Event: TInputPressRelease): Boolean;
  255. var
  256.   HitByAvatar: TCastleTransform;
  257.   HitEnemy: TEnemy;
  258. begin
  259.   Result := inherited;
  260.   if Result then Exit; // allow the ancestor to handle keys
  261.  
  262.   { This virtual method is executed when user presses
  263.     a key, a mouse button, or touches a touch-screen.
  264.  
  265.     Note that each UI control has also events like OnPress and OnClick.
  266.     These events can be used to handle the "press", if it should do something
  267.     specific when used in that UI control.
  268.     The TViewPlay.Press method should be used to handle keys
  269.     not handled in children controls.
  270.   }
  271.  
  272.   if Event.IsMouseButton(buttonLeft) then
  273.   begin
  274.     SoundEngine.Play(SoundEngine.SoundFromName('shoot_sound'));
  275.   end;
  276.  
  277.   if Event.IsMouseButton(buttonRight) then
  278.   begin
  279.     MyThirdPersonNavigation.MouseLook := not MyThirdPersonNavigation.MouseLook;
  280.     Exit(true);
  281.   end;
  282.  
  283.   if Event.IsKey(keyF5) then
  284.   begin
  285.     Container.SaveScreenToDefaultFile;
  286.     Exit(true);
  287.   end;
  288.  
  289.   if Event.IsKey(keyEscape) then
  290.   begin
  291.     Container.View := ViewMenu;
  292.     Exit(true);
  293.   end;
  294.  
  295.   if (Event.IsKey(keyArrowUp) and SandyInRunning = false) then
  296.   begin
  297.     SandyInRunning := true;
  298.     SandyLegs.PlayAnimation('LEGS_RUN', true);
  299.     SandyTorso.PlayAnimation('TORSO_RUN', true);
  300.   end;
  301. end.
  302.  
  303. function TViewPlay.Release(const Event: TInputPressRelease): Boolean;
  304. begin
  305.   Result := inherited;
  306.   if Result then Exit; // allow the ancestor to handle keys
  307.  
  308.   { This virtual method is executed when user releases
  309.     a key, a mouse button, or touches a touch-screen.
  310.  
  311.     Note that each UI control has also events like OnPress and OnClick.
  312.     These events can be used to handle the "press", if it should do something
  313.     specific when used in that UI control.
  314.     The TViewPlay.Release method should be used to handle keys
  315.     not handled in children controls.
  316.   }
  317.  
  318.   if (Event.IsKey(keyArrowUp) and SandyInRunning = true) then
  319.   begin
  320.     SandyInRunning := false;
  321.     SandyLegs.PlayAnimation('BOTH_IDLE', true);
  322.     SandyTorso.PlayAnimation('BOTH_IDLE', true);
  323.   end;
  324. end.
  325.  
  326. procedure TViewPlay.ChangeCheckboxCameraFollows(Sender: TObject);
  327. begin
  328.   MyThirdPersonNavigation.CameraFollows := CheckboxCameraFollows.Checked;
  329. end;
  330.  
  331. procedure TViewPlay.ChangeCheckboxAimAvatar(Sender: TObject);
  332. begin
  333.   if CheckboxAimAvatar.Checked then
  334.     MyThirdPersonNavigation.AimAvatar := aaHorizontal
  335.   else
  336.     MyThirdPersonNavigation.AimAvatar := aaNone;
  337.  
  338.   { The 3rd option, aaFlying, doesn't make sense for this case,
  339.     when avatar walks on the ground and has Gravity = true. }
  340. end;
  341.  
  342. procedure TViewPlay.ChangeCheckboxDebugAvatarColliders(Sender: TObject);
  343. begin
  344.   DebugAvatar.Exists := CheckboxDebugAvatarColliders.Checked;
  345. end;
  346.  
  347. procedure TViewPlay.ChangeCheckboxImmediatelyFixBlockedCamera(Sender: TObject);
  348. begin
  349.   MyThirdPersonNavigation.ImmediatelyFixBlockedCamera := CheckboxImmediatelyFixBlockedCamera.Checked;
  350. end;
  351.  
  352. procedure TViewPlay.ChangeAirRotationControl(Sender: TObject);
  353. begin
  354.   MyThirdPersonNavigation.AirRotationControl := SliderAirRotationControl.Value;
  355. end;
  356.  
  357. procedure TViewPlay.ChangeAirMovementControl(Sender: TObject);
  358. begin
  359.   MyThirdPersonNavigation.AirMovementControl := SliderAirMovementControl.Value;
  360. end;
  361.  
  362. procedure TViewPlay.UpdateAfterChangeTransformation;
  363. begin
  364.   ButtonChangeTransformationAuto.Pressed := MyThirdPersonNavigation.ChangeTransformation = ctAuto;
  365.   ButtonChangeTransformationDirect.Pressed := MyThirdPersonNavigation.ChangeTransformation =  ctDirect;
  366.   ButtonChangeTransformationVelocity.Pressed := MyThirdPersonNavigation.ChangeTransformation =  ctVelocity;
  367.   {$ifdef CASTLE_UNFINISHED_CHANGE_TRANSFORMATION_BY_FORCE}
  368.   ButtonChangeTransformationForce.Pressed := ThirdPersonNavigation.ChangeTransformation = ctForce;
  369.   {$endif}
  370.  
  371.   { ctDirect requires to set up gravity without physics engine,
  372.     using deprecated TCastleTransform.Gravity.
  373.     See https://castle-engine.io/physics#_old_system_for_collisions_and_gravity }
  374.   AvatarRigidBody.Exists := MyThirdPersonNavigation.ChangeTransformation <> ctDirect;
  375.  
  376.   { Gravity means that object tries to maintain a constant height
  377.     (SceneAvatar.PreferredHeight) above the ground.
  378.     GrowSpeed means that object raises properly (makes walking up the stairs work).
  379.     FallSpeed means that object falls properly (makes walking down the stairs,
  380.     falling down pit etc. work). }
  381.   SandyTorso.Gravity := not AvatarRigidBody.Exists;
  382.   SandyLegs.Gravity := not AvatarRigidBody.Exists;
  383.   SandyHead.Gravity := not AvatarRigidBody.Exists;
  384. end;
  385.  
  386. procedure TViewPlay.ClickChangeTransformationAuto(Sender: TObject);
  387. begin
  388.   MyThirdPersonNavigation.ChangeTransformation := ctAuto;
  389.   UpdateAfterChangeTransformation;
  390. end;
  391.  
  392. procedure TViewPlay.ClickChangeTransformationDirect(Sender: TObject);
  393. begin
  394.   MyThirdPersonNavigation.ChangeTransformation := ctDirect;
  395.   UpdateAfterChangeTransformation;
  396. end;
  397.  
  398. procedure TViewPlay.ClickChangeTransformationVelocity(Sender: TObject);
  399. begin
  400.   MyThirdPersonNavigation.ChangeTransformation := ctVelocity;
  401.   UpdateAfterChangeTransformation;
  402. end;
  403.  
  404. procedure TViewPlay.ClickChangeTransformationForce(Sender: TObject);
  405. begin
  406.   {$ifdef CASTLE_UNFINISHED_CHANGE_TRANSFORMATION_BY_FORCE}
  407.   ThirdPersonNavigation.ChangeTransformation := ctForce;
  408.   {$endif}
  409.   UpdateAfterChangeTransformation;
  410. end;
  411.  
  412. end.

Unfortunately, now I am getting errors about all the functions being declared, starting on line 60, about being unsolved forward declarations, even though I remember the way the example initially was, and by following all the other examples, that this is the way you are supposed to define the procedures to use later on in the code.

Why is this telling me the forward declaration is unsolved on each and every single line in that particular section (lines 60 to 77, ignore everything before and after)?

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
By "the way the code initially was", I meant if you have a copy of Castle Game Engine on your computer, open the third person navigation example and see for yourself how the procedures are declared in exactly the same way, private keyword beforehand, semicolons after each procedure, and all; I never altered that particular area in any way which is why it's weird it's giving errors now.

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
I guessed it might have been because of adding the periods before each new function rather than semicolons, but you will see that the procedures are called/used before the first period of that kind ever comes up, in particular in lines 133 thru 151, so that doesn't explain it - besides the compiler wouldn't like it if I didn't include those particular periods, so I assumed it had to be right thing to do.

cdbc

  • Hero Member
  • *****
  • Posts: 1157
    • http://www.cdbc.dk
Hi
Something irritates my eyes in lines 236..239:
Code: Pascal  [Select][+][-]
  1.   end
  2.   else
  3.       SandyIdling := 0; // THIS
  4.       begin
Only "SandyIdling := 0;" belongs to the /else/ block! Thus rendering the following 'begin-end' pair superfluous; the code will be executed with both /if/ and /else/ regardless.... I don't understand that and it rubs me the wrong way!
Look at my first changes in this thread, there I  moved the "SandyIdling := 0;" below the following 'begin', because then the begin-end pair makes sense.
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
I made it that way on purpose, because I wanted to set "SandyIdling" to 0 if you aren't touching the ground, and I thought an if-else block was the correct way of doing it. If you read the rest of the code for context, I am pretty sure I made it clear that SandyIdling = 0 only if you aren't touching the ground, it shouldn't start if you are, so I am not sure where you are getting the idea the "else" is repetitive.

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
Also, the "begin" and "end" block after the else has the same deal - it will be executed only if you aren't touching the ground, and shouldn't execute always no matter what and make the "else" useless.

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
And on top of that, the nested "if" block has the same purpose as the block before the first big "else" directly before the block you think is repetitive - namely to check if it isn't true that you are airborne already, so that way the animation isn't playing over and over again and not actually playing properly, and also so that the game doesn't lag because of the sheer amount of times you are calling the script per frame.

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
As a reminder, my newest problem isn't that at all, although that is good to point out as well, but is instead the fact that the procedures I declared in the "type" section are said to be unsolved forward declarations, even though they are exactly the same as in the initial example before I changed the code, because I didn't change those particular details.

Again, for proof of that have your own copy of Castle Game Engine installed, and open the "Third Person Navigation" example and look at the file gameviewplay.pas in particular, as that is the file with the errors that I changed.

 

TinyPortal © 2005-2018