Need help understanding how to initalize a particular example

{
  Copyright 2023-2023 Michalis Kamburelis.

  This file is part of "Castle Game Engine".

  "Castle Game Engine" is free software; see the file COPYING.txt,
  included in this distribution, for details about the copyright.

  "Castle Game Engine" is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

  ----------------------------------------------------------------------------
}

{ Main view, where most of the application logic takes place. }
unit GameViewMain;

interface

uses Classes,
  CastleVectors, CastleComponentSerialize,
  CastleUIControls, CastleControls, CastleKeysMouse,
  CastleThirdPersonNavigation, CastleViewport, CastleScene,
  CastleCameras, CastleTransform, CastleInputs,
  CastleSceneCore, CastleDebugTransform;

type
  TMyThirdPersonNavigation = class(TCastleThirdPersonNavigation)
  published
    SceneHumanLegs1, SceneHumanBase: TCastleScene;
    HumanBase1: TCastleTransform;
  public
  constructor Create(AOwner: TComponent); override;
  procedure AssignAvatar;
  end;

  { Main view, where most of the application logic takes place. }
  TViewMain = class(TCastleView)
  published
    { Components designed using CGE editor.
      These fields will be automatically initialized at Start. }
    LabelFps: TCastleLabel;
  public
    constructor Create(AOwner: TComponent); override;
    procedure Start; override;
    procedure Update(const SecondsPassed: Single; var HandleInput: Boolean); override;
    function Press(const Event: TInputPressRelease): Boolean; override;
  end;

var
  ViewMain: TViewMain;
  MyThirdPersonNavigation: TMyThirdPersonNavigation;

implementation

uses SysUtils;

constructor TMyThirdPersonNavigation.Create(AOwner: TComponent);
begin
  Avatar := nil;
end;

procedure TMyThirdPersonNavigation.AssignAvatar;
begin
  MyThirdPersonNavigation.AvatarHierarchy := HumanBase1;
end;

{ TViewMain ----------------------------------------------------------------- }

constructor TViewMain.Create(AOwner: TComponent);
begin
  inherited;
  DesignUrl := 'castle-data:/gameviewmain.castle-user-interface';
end;

procedure TViewMain.Start;
var
  MyNavigation: TMyThirdPersonNavigation;
begin
  inherited;
  MyNavigation := TMyThirdPersonNavigation.Create(FreeAtStop);
  MyNavigation.AssignAvatar;
end;

procedure TViewMain.Update(const SecondsPassed: Single; var HandleInput: Boolean);
begin
  inherited;
  { This virtual method is executed every frame (many times per second). }
  Assert(LabelFps <> nil, 'If you remove LabelFps from the design, remember to remove also the assignment "LabelFps.Caption := ..." from code');
  LabelFps.Caption := 'FPS: ' + Container.Fps.ToString;
end;

function TViewMain.Press(const Event: TInputPressRelease): Boolean;
begin
  Result := inherited;
  if Result then Exit; // allow the ancestor to handle keys

  { This virtual method is executed when user presses
    a key, a mouse button, or touches a touch-screen.

    Note that each UI control has also events like OnPress and OnClick.
    These events can be used to handle the "press", if it should do something
    specific when used in that UI control.
    The TViewMain.Press method should be used to handle keys
    not handled in children controls.
  }

  // Use this to handle keys:
  {
  if Event.IsKey(keyXxx) then
  begin
    // DoSomething;
    Exit(true); // key was handled
  end;
  }
end;

end.

Unfortunately, I get these errors, even though I made sure to define and initalize
the correct local instance of the class, as well as use the correct syntax for accessing
the procedure of the local class, judging by the examples I see.

I don’t understand why at all.

I’m sorry for being frank, but you’re making an incomprehensible confusion.
It seems like you don’t think at all about what you write (and read).
What does MyNavigation have to do with it?
It was just an example from Michalis, your variable is MyThirdPersonNavigation. Furthermore, it is already declared.
Again, this example was just to point out the use of FreeAtStop, you don’t have to use it in your code. Restore your previous code.
I really don’t know how to help you unless you start doing the things that are suggested.
Have you or have you not gone back to read the entire previous thread? :question:
If you don’t start to understand what you’re doing and you paste meaningless pieces of code you’ll keep getting error after error.

Actually, I did try just doing “MyThirdPersonNavigation.AssignAvatar” directly, without needing vars or anything like that, because again I know from the book and michaelis’ post that global variables and classes have global scope,

so they should work within function bodies as well, but it was getting weird, and rejecting
it at first. I think it was cause I didn’t initailize it and also had “inherited” in the wrong order, like it should come first always because it won’t know to inherit from the parent
class otherwise.

Here is the code now:

{
  Copyright 2023-2023 Michalis Kamburelis.

  This file is part of "Castle Game Engine".

  "Castle Game Engine" is free software; see the file COPYING.txt,
  included in this distribution, for details about the copyright.

  "Castle Game Engine" is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

  ----------------------------------------------------------------------------
}

{ Main view, where most of the application logic takes place. }
unit GameViewMain;

interface

uses Classes,
  CastleVectors, CastleComponentSerialize,
  CastleUIControls, CastleControls, CastleKeysMouse,
  CastleThirdPersonNavigation, CastleViewport, CastleScene,
  CastleCameras, CastleTransform, CastleInputs,
  CastleSceneCore, CastleDebugTransform;

type
  TMyThirdPersonNavigation = class(TCastleThirdPersonNavigation)
  published
    SceneHumanLegs1, SceneHumanBase: TCastleScene;
    HumanBase1: TCastleTransform;
  public
  constructor Create(AOwner: TComponent); override;
  procedure AssignAvatar;
  end;

  { Main view, where most of the application logic takes place. }
  TViewMain = class(TCastleView)
  published
    { Components designed using CGE editor.
      These fields will be automatically initialized at Start. }
    LabelFps: TCastleLabel;
  public
    constructor Create(AOwner: TComponent); override;
    procedure Start; override;
    procedure Update(const SecondsPassed: Single; var HandleInput: Boolean); override;
    function Press(const Event: TInputPressRelease): Boolean; override;
  end;

var
  ViewMain: TViewMain;
  MyThirdPersonNavigation: TMyThirdPersonNavigation;

implementation

uses SysUtils;

constructor TMyThirdPersonNavigation.Create(AOwner: TComponent);
begin
  Avatar := nil;
end;

procedure TMyThirdPersonNavigation.AssignAvatar;
begin
  MyThirdPersonNavigation.AvatarHierarchy := HumanBase1;
end;

{ TViewMain ----------------------------------------------------------------- }

constructor TViewMain.Create(AOwner: TComponent);
begin
  inherited;
  DesignUrl := 'castle-data:/gameviewmain.castle-user-interface';
end;

procedure TViewMain.Start;
begin
  inherited;
  MyThirdPersonNavigation.AssignAvatar;
end;

procedure TViewMain.Update(const SecondsPassed: Single; var HandleInput: Boolean);
begin
  inherited;
  { This virtual method is executed every frame (many times per second). }
  Assert(LabelFps <> nil, 'If you remove LabelFps from the design, remember to remove also the assignment "LabelFps.Caption := ..." from code');
  LabelFps.Caption := 'FPS: ' + Container.Fps.ToString;
end;

function TViewMain.Press(const Event: TInputPressRelease): Boolean;
begin
  Result := inherited;
  if Result then Exit; // allow the ancestor to handle keys

  { This virtual method is executed when user presses
    a key, a mouse button, or touches a touch-screen.

    Note that each UI control has also events like OnPress and OnClick.
    These events can be used to handle the "press", if it should do something
    specific when used in that UI control.
    The TViewMain.Press method should be used to handle keys
    not handled in children controls.
  }

  // Use this to handle keys:
  {
  if Event.IsKey(keyXxx) then
  begin
    // DoSomething;
    Exit(true); // key was handled
  end;
  }
end;

end.

Unfortunately, it crashes with an exception error at line 66, even though I know for a fact that AvatarHiearchy is a valid property of CastleThirdPersonNavigation, and
the data type is 100% TCastleTransform, cause it says so on the API page for the class.

I also know for a fact that when you use a “uses” Unit, you also allow the usage
of all its procedures, variables etc cause it says so in the book michaelis gave me.

It doesn’t specify on the API page sadly if it’s public or private or some other setting
like protected, but I would suppose it’s public; I just don’t have any evidence.

Again, line 66 is where the focus is now, and the stuff below that is not part of
the problem as far as I understand.

Oh, but learning from the other examples I think I should omit the “class.” before declaring the variable, because that’s implied, especially if I use the inherited keyword like in this case?

EDIT AFTER TRYING: I was wrong, it gave the same error as well, which again is weird because I know I did the correct syntax besides that small detail, and I know for a fact the properties are valid and that I declared and initialized the class properly.

Okay, so I followed this structure from tutorialspoint.org for how to use a class inside another class, paying special attention to where I call the constructor (because I figured that was the problem here - I didn’t use the constructor but just declared it),

program classExample;

{$MODE OBJFPC} //directive to be used for creating classes
{$M+} //directive that allows class constructors and destructors
type
   Books = Class 
   private 
      title : String; 
      price: real;
   
   public
      constructor Create(t : String; p: real); //default constructor
      
      procedure setTitle(t : String); //sets title for a book
      function getTitle() : String; //retrieves title
      
      procedure setPrice(p : real); //sets price for a book
      function getPrice() : real; //retrieves price
      
      procedure Display(); // display details of a book
end;
var
   physics, chemistry, maths: Books;

//default constructor 
constructor Books.Create(t : String; p: real);
begin
   title := t;
   price := p;
end;

procedure Books.setTitle(t : String); //sets title for a book
begin
   title := t;
end;

function Books.getTitle() : String; //retrieves title
begin
   getTitle := title;
end;

procedure Books.setPrice(p : real); //sets price for a book
begin
   price := p;
end;

function Books.getPrice() : real; //retrieves price
begin
   getPrice:= price;
end;

procedure Books.Display();
begin
   writeln('Title: ', title);
   writeln('Price: ', price:5:2);
end;

begin 
   physics := Books.Create('Physics for High School', 10);
   chemistry := Books.Create('Advanced Chemistry', 15);
   maths := Books.Create('Algebra', 7);
   
   physics.Display;
   chemistry.Display;
   maths.Display;
end.

But unfortunately I get the same exact error; following the structure to the best of my ability, noticing how in this specific case there is no “begin” and “end” for the whole program because Castle Game Engine Pascal is slightly different from normal Pascal in the overall program structure, which again the book does tell me explicitly so there’s no surprise there,

my code now looks like this:

{
  Copyright 2023-2023 Michalis Kamburelis.

  This file is part of "Castle Game Engine".

  "Castle Game Engine" is free software; see the file COPYING.txt,
  included in this distribution, for details about the copyright.

  "Castle Game Engine" is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

  ----------------------------------------------------------------------------
}

{ Main view, where most of the application logic takes place. }
unit GameViewMain;

interface

uses Classes,
  CastleVectors, CastleComponentSerialize,
  CastleUIControls, CastleControls, CastleKeysMouse,
  CastleThirdPersonNavigation, CastleViewport, CastleScene,
  CastleCameras, CastleTransform, CastleInputs,
  CastleSceneCore, CastleDebugTransform;

type
  TMyThirdPersonNavigation = class(TCastleThirdPersonNavigation)
  published
    SceneHumanLegs1, SceneHumanBase: TCastleScene;
    HumanBase1: TCastleTransform;
  public
  constructor Create(AOwner: TComponent); override;
  procedure AssignAvatar;
  end;

  { Main view, where most of the application logic takes place. }
  TViewMain = class(TCastleView)
  published
    { Components designed using CGE editor.
      These fields will be automatically initialized at Start. }
    LabelFps: TCastleLabel;
  public
    constructor Create(AOwner: TComponent); override;
    procedure Start; override;
    procedure Update(const SecondsPassed: Single; var HandleInput: Boolean); override;
    function Press(const Event: TInputPressRelease): Boolean; override;
  end;

var
  ViewMain: TViewMain;
  MyThirdPersonNavigation: TMyThirdPersonNavigation;

implementation

uses SysUtils;

constructor TMyThirdPersonNavigation.Create(AOwner: TComponent);
begin
  Avatar := nil;
end;

procedure TMyThirdPersonNavigation.AssignAvatar;
begin
  AvatarHierarchy := HumanBase1;
end;

{ TViewMain ----------------------------------------------------------------- }

constructor TViewMain.Create(AOwner: TComponent);
begin
  inherited;
  DesignUrl := 'castle-data:/gameviewmain.castle-user-interface';
end;

procedure TViewMain.Start;
begin
  inherited;
  MyThirdPersonNavigation := TMyThirdPersonNavigation.Create(FreeAtStop);
  MyThirdPersonNavigation.AssignAvatar;
end;

procedure TViewMain.Update(const SecondsPassed: Single; var HandleInput: Boolean);
begin
  inherited;
  { This virtual method is executed every frame (many times per second). }
  Assert(LabelFps <> nil, 'If you remove LabelFps from the design, remember to remove also the assignment "LabelFps.Caption := ..." from code');
  LabelFps.Caption := 'FPS: ' + Container.Fps.ToString;
end;

function TViewMain.Press(const Event: TInputPressRelease): Boolean;
begin
  Result := inherited;
  if Result then Exit; // allow the ancestor to handle keys

  { This virtual method is executed when user presses
    a key, a mouse button, or touches a touch-screen.

    Note that each UI control has also events like OnPress and OnClick.
    These events can be used to handle the "press", if it should do something
    specific when used in that UI control.
    The TViewMain.Press method should be used to handle keys
    not handled in children controls.
  }

  // Use this to handle keys:
  {
  if Event.IsKey(keyXxx) then
  begin
    // DoSomething;
    Exit(true); // key was handled
  end;
  }
end;

end.

Does anyone have any idea what else could be wrong? Again, I can’t follow the example code exactly because the overall program structure is different, with “implementation” and “interface” sections to accomodate the Castle Game Engine structure, and doesn’t let you simply have a “begin” and “end” for the overall program flow.

However, I do know that you can create a local initalization inline to a function body if you want to use it for that function duration only, and that FreeAtStop will clear out the initalization as soon as it is no longer being used, so I have no clue what I am doing wrong following what I know the book michaelis told me is correct.

I thought you had SceneHumanLegs1 and SceneHumanBase created in CGE editor design. Then you should put them under TViewMain published section to be recognised or else you have to create them in code somewhere in the implementation section.

var
ViewMain: TViewMain;
MyThirdPersonNavigation: TMyThirdPersonNavigation

You have to put var MyThirdPersonNavigation in a TViewMain procedure or it won’t be recognised either.

To point 1) I didn’t create them just yet, so I commented out that line instead.

To point 2) I think that’s weird because I know for a fact I learned global variables can be accessed anywhere in the program by definition so I shouldn’t have to re-declare them, but I just added a copy of the vars under the “implementation” section rather than “interface” section.

`{
  Copyright 2023-2023 Michalis Kamburelis.

  This file is part of "Castle Game Engine".

  "Castle Game Engine" is free software; see the file COPYING.txt,
  included in this distribution, for details about the copyright.

  "Castle Game Engine" is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

  ----------------------------------------------------------------------------
}

{ Main view, where most of the application logic takes place. }
unit GameViewMain;

interface

uses Classes,
  CastleVectors, CastleComponentSerialize,
  CastleUIControls, CastleControls, CastleKeysMouse,
  CastleThirdPersonNavigation, CastleViewport, CastleScene,
  CastleCameras, CastleTransform, CastleInputs,
  CastleSceneCore, CastleDebugTransform;

type
  TMyThirdPersonNavigation = class(TCastleThirdPersonNavigation)
  published
    //SceneHumanLegs1, SceneHumanBase: TCastleScene;
    HumanBase1: TCastleTransform;
  public
  constructor Create(AOwner: TComponent); override;
  procedure AssignAvatar;
  end;

  { Main view, where most of the application logic takes place. }
  TViewMain = class(TCastleView)
  published
    { Components designed using CGE editor.
      These fields will be automatically initialized at Start. }
    LabelFps: TCastleLabel;
  public
    constructor Create(AOwner: TComponent); override;
    procedure Start; override;
    procedure Update(const SecondsPassed: Single; var HandleInput: Boolean); override;
    function Press(const Event: TInputPressRelease): Boolean; override;
  end;

var
  ViewMain: TViewMain;
  MyThirdPersonNavigation: TMyThirdPersonNavigation;

implementation

uses SysUtils;

var
  ViewMain: TViewMain;
  MyThirdPersonNavigation: TMyThirdPersonNavigation;

constructor TMyThirdPersonNavigation.Create(AOwner: TComponent);
begin
  Avatar := nil;
end;

procedure TMyThirdPersonNavigation.AssignAvatar;
begin
  AvatarHierarchy := HumanBase1;
end;

{ TViewMain ----------------------------------------------------------------- }

constructor TViewMain.Create(AOwner: TComponent);
begin
  inherited;
  DesignUrl := 'castle-data:/gameviewmain.castle-user-interface';
end;

procedure TViewMain.Start;
begin
  inherited;
  MyThirdPersonNavigation := TMyThirdPersonNavigation.Create(FreeAtStop);
  MyThirdPersonNavigation.AssignAvatar;
end;

procedure TViewMain.Update(const SecondsPassed: Single; var HandleInput: Boolean);
begin
  inherited;
  { This virtual method is executed every frame (many times per second). }
  Assert(LabelFps <> nil, 'If you remove LabelFps from the design, remember to remove also the assignment "LabelFps.Caption := ..." from code');
  LabelFps.Caption := 'FPS: ' + Container.Fps.ToString;
end;

function TViewMain.Press(const Event: TInputPressRelease): Boolean;
begin
  Result := inherited;
  if Result then Exit; // allow the ancestor to handle keys

  { This virtual method is executed when user presses
    a key, a mouse button, or touches a touch-screen.

    Note that each UI control has also events like OnPress and OnClick.
    These events can be used to handle the "press", if it should do something
    specific when used in that UI control.
    The TViewMain.Press method should be used to handle keys
    not handled in children controls.
  }

  // Use this to handle keys:
  {
  if Event.IsKey(keyXxx) then
  begin
    // DoSomething;
    Exit(true); // key was handled
  end;
  }
end;

end.`

Here is the code edited after your comments.

And I was right! I get an error about duplicate identifiers when I try your suggestion on the second issue, so I will just edit out the copy under implementation.

EDIT AFTER EDITING OUT DUPLICATE IDENTIFIERS:

Now I get this error instead, which doesn’t seem to be related to the above error, or anything at all for that matter in the code. However, I figure it’s best to show what the error says verbatim in case I am missing out on something.

You haven"t read very well what I wrote as the code is still not what I suggested. And this is the case with every reply you get from the helping people here, so I give up.

I was deliberate/did it on purpose about making the code not follow your suggestion word for word, because I was proving a point that it would most likely think it was a duplicate identifier and reject it, but your point is if I follow your directions word for word it shouldn’t, even though it does for declaring it in the implementation body?

Again, this is something I think is weird and doesn’t make any logical sense if it’s true, but I am good at memorizing patterns and therefore will just learn from experience that that is the pattern here.

{
  Copyright 2023-2023 Michalis Kamburelis.

  This file is part of "Castle Game Engine".

  "Castle Game Engine" is free software; see the file COPYING.txt,
  included in this distribution, for details about the copyright.

  "Castle Game Engine" is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

  ----------------------------------------------------------------------------
}

{ Main view, where most of the application logic takes place. }
unit GameViewMain;

interface

uses Classes,
  CastleVectors, CastleComponentSerialize,
  CastleUIControls, CastleControls, CastleKeysMouse,
  CastleThirdPersonNavigation, CastleViewport, CastleScene,
  CastleCameras, CastleTransform, CastleInputs,
  CastleSceneCore, CastleDebugTransform;

type
  TMyThirdPersonNavigation = class(TCastleThirdPersonNavigation)
  published
    //SceneHumanLegs1, SceneHumanBase: TCastleScene;
    HumanBase1: TCastleTransform;
  public
  constructor Create(AOwner: TComponent); override;
  procedure AssignAvatar;
  end;

  { Main view, where most of the application logic takes place. }
  TViewMain = class(TCastleView)
  published
    { Components designed using CGE editor.
      These fields will be automatically initialized at Start. }
    LabelFps: TCastleLabel;
  public
    constructor Create(AOwner: TComponent); override;
    procedure Start; override;
    procedure Update(const SecondsPassed: Single; var HandleInput: Boolean); override;
    function Press(const Event: TInputPressRelease): Boolean; override;
  end;

var
  ViewMain: TViewMain;
  MyThirdPersonNavigation: TMyThirdPersonNavigation;

implementation

uses SysUtils;

constructor TMyThirdPersonNavigation.Create(AOwner: TComponent);
begin
  Avatar := nil;
end;

procedure TMyThirdPersonNavigation.AssignAvatar;
begin
  AvatarHierarchy := HumanBase1;
end;

{ TViewMain ----------------------------------------------------------------- }

constructor TViewMain.Create(AOwner: TComponent);
begin
  inherited;
  DesignUrl := 'castle-data:/gameviewmain.castle-user-interface';
end;

procedure TViewMain.Start;
var MyThirdPersonNavigation: TMyThirdPersonNavigation;
begin
  inherited;
  MyThirdPersonNavigation := TMyThirdPersonNavigation.Create(FreeAtStop);
  MyThirdPersonNavigation.AssignAvatar;
end;

procedure TViewMain.Update(const SecondsPassed: Single; var HandleInput: Boolean);
begin
  inherited;
  { This virtual method is executed every frame (many times per second). }
  Assert(LabelFps <> nil, 'If you remove LabelFps from the design, remember to remove also the assignment "LabelFps.Caption := ..." from code');
  LabelFps.Caption := 'FPS: ' + Container.Fps.ToString;
end;

function TViewMain.Press(const Event: TInputPressRelease): Boolean;
begin
  Result := inherited;
  if Result then Exit; // allow the ancestor to handle keys

  { This virtual method is executed when user presses
    a key, a mouse button, or touches a touch-screen.

    Note that each UI control has also events like OnPress and OnClick.
    These events can be used to handle the "press", if it should do something
    specific when used in that UI control.
    The TViewMain.Press method should be used to handle keys
    not handled in children controls.
  }

  // Use this to handle keys:
  {
  if Event.IsKey(keyXxx) then
  begin
    // DoSomething;
    Exit(true); // key was handled
  end;
  }
end;

end.

Here is what it looks more like now, following your suggestion more strictly/directly, but again I get the same error.

I am using the honor system and assuming you didn’t know it wouldn’t work like this ahead of time, and it’s probably yet another thing that is wrong not related to your suggestion.

You declare MyThirdPersonNavigation: TMyThirdPersonNavigation; twice.
Global outside of TView and local in TViewMain. Start. That is wrong.

The main loop of the program is in TView so put it in type TView so it will be recognised.
Also you have not outcommented the Transform, only the first line.

You must learn to look for the reasons for errors.
First of all you have MyThirdPersonNavigation declared twice and if you are a programmer you should know that it doesn’t make sense.
Secondly you get an error about MyThirdPersonNavigation.AssignAvatar if I understand correctly.
You should ask yourself: is it the procedure call that generates the error or the procedure itself?
How to understand it?
Simple, change the content of the procedure to something you know won’t cause errors.
I added the CastleUtils unit, in your code I commented MyThirdPersonNavigation.AvatarHierarchy := HumanBase1 and I wrote something trivial like WarningWrite('pppppppppprggrewgergregerhge');
And you know what? The code compiles and the application starts, displaying the message window because you call MyThirdPersonNavigation.AssignAvatar into TViewMain.Start procedure.
What could this mean???