Need help understanding how to initalize a particular example

The constructor TMyThirdPersonNavigation.Create(AOwner: TComponent); should be followed by a block of code that defines what happens when you run the constructor. Merely adding this line doesn’t make sense, you only started the constructor. This is what Valtedb meant and it is one reason of compilation problems.

See any example that shows how to use constructor. There’s a lot of example code, in all tutorials and also CGE examples, showing it.

And as said above, make sure to post a complete source code, not just a line that you think is the culprit. You are assuming / speculating / guessing too much, and your assumptions about how things work (and what is BS) are often unfounded. Only when you show a complete code → then it is possible to tell why it fails.

I appreciate you do the reading and learning, but please spend more time reading and don’t write so many forum posts in a short time :slight_smile: Don’t treat this as a chat, this thread is quickly becoming hard to follow again, with 59 posts, last 12 generated in last 30 minutes if I count right. When you have something that doesn’t work, make sure you do some tests, compare with examples that work (from any tutorial / book), post only a complete source code with a clear question.

And do not assume too quickly how things work, I’m afraid these assumptions are often leading you astray.

Okay, that makes more sense why I should A: not post too much and B: give complete code snippets. Thank you for guiding me on that.

Okay, here is the code for reference 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)
  protected
  procedure AssignAvatar;
  published
    SceneHumanLegs1, SceneHumanBase: TCastleScene;
    HumanBase1: TCastleTransform;
  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: TCastleThirdPersonNavigation;

implementation

uses SysUtils;

constructor TMyThirdPersonNavigation.Create(AOwner: TComponent);
begin
  inherited;
  Avatar := 'HumanBase1';
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
  TMyThirdPersonNavigation.AssignAvatar;
  inherited;
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.

I am still getting the same exact crapola about method identifier expected, but look at! I follow the example of the constructor of TViewMain beneath it, which is known to work perfectly, and yet I am getting the same error on that one line even though the lines match in every single detail, down to the last drop.

If it was a problem with something else that might be different, but it’s telling me on that
one specific line that it doesn’t work even though I know for a fact that particular line
works flawlessly for another class.

Like for example, it doesn’t matter whether I omit the “beginning” and “ending” sections, the error only focuses on that one particular line, which was my point earlier but I guess I didn’t make that clear enough.

You again assume too much. Saying “the same crapola” doesn’t help :), that is: the compiler is really (almost) always correct. If compiler reports an error then you most likely really have invalid Pascal code. If the error seems surprising it most likely means you still don’t understand something.

It is not productive if you write a few posts showing how surprised you are by the error. Instead, do the investigation (on your own, as much as you can) what could be the reason.

The

Error: method identifier expected

error here is caused by the fact you didn’t declare the constructor in the class declaration. What does it mean to “declare”, what is class “declaration”? Again please go back to tutorials and books. Any example that shows a constructor (or really any other method) will show you how to do this properly. The TViewMain also does something you didn’t do in TMyThirdPersonNavigation.

Sorry for not giving you a straight answer, when the mistake is kind of obvious, but it really would not be beneficial in this case. You need to read and learn more. I’m happy you’re doing learning now, please do it some more :slight_smile: Whichever book or tutorial you are following right now, it will (or already did) definitely explain how to declare a method (and, in particular, a constructor) in a class. As usual, do not try to do this by “trial and error” and do not jump straight into your code of TMyThirdPersonNavigation (make simple test program from scratch instead to first test you know how to add a constructor to a class).

Okay, so I looked it up in the book further, like now I’m on the part on records and classes, and now I can understand on my own that I need to declare a constructor first in the “var” section of the record declaration, and then give the details of the implementation after, like the actual function body.

Is that correct?

You just need to look at how it is implemented in TViewMain = class(TCastleView) in the Public section :slightly_smiling_face:

Okay, so yeah, that was right.

Onto another issue now:

I followed the directions for assigning a local constructor of a copy of a class
when called inside a procedure of a different, unrelated class, like in this 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: TCastleThirdPersonNavigation;

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 MyThirdPersonNavigation: TMyThirdPersonNavigation;
begin
  MyThirdPersonNavigation := TMyThirdPersonNavigation.Create(ThirdPersonNavigation);
  MyThirdPersonNavigation.AssignAvatar;
  inherited;
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.

Where I want you to focus is under “TViewMain.Start” in particular.

Unfortunately, it initializes fine but it tells me “ThirdPersonNavigation” is an unknown
identifier, even though I can clearly see that ThirdPersonNavigation is a component
of the main viewport. What the heck is going on?

I don’t know what you’re trying to do, but you’re declaring twice MyThirdPersonNavigation:

var
ViewMain: TViewMain;
MyThirdPersonNavigation: TCastleThirdPersonNavigation;

procedure TViewMain.Start;
var MyThirdPersonNavigation: TMyThirdPersonNavigation;

If you declare it in the global var section, it is not needed in the TViewMain.Start.
Also, did you notice that the two statements are different?

I know in general you are not supposed to declare global variables as local because they already work globally for everything, but it didn’t work at first without the local declaration, but I think that was because I didn’t initalize it properly, like I didn’t do the constructor assignment in the procedure body.

Okay, after I omitted the local declaration it tells me identifier idents no member AssignAvatar, even though it is clearly defined in the public section of the class during the class definition, and I still get the same error about ThirdPersonNavigation is not defined even though again, it is in fact a real component of the viewport.

I have the impression that you don’t pay much attention to what is written.
One question: should MyThirdPersonNavigation be of type TCastleThirdPersonNavigation or TMyThirdPersonNavigation?

I re-read the code, and it says “class TMyThirdPersonNavigation” in the declaration of the class, and so I was intentional about that, and beneath that is a var that references TMyThirdPersonNavigation that omits the T intentionally because the book explains that’s the convention, as well as following the way it is done for TViewMain.

The book also explains you should reference the variables rather than the classes directly, so that was intentional as well. I have no clue what this is about not paying attention, because I made sure to be deliberate about following every convention to the T.

Oh, but now I see in the definition of the global variable there was yet another silly mistake, this time defining “TCastleThirdPersonNavigation” rather than “TMyThirdPersonNavigation”, which you alluded to.

I corrected that and will test it now.

Do you mean here?

var
  ViewMain: TViewMain;
  MyThirdPersonNavigation: TCastleThirdPersonNavigation;

Yes, to the latest post that came up while I was typing.

The error went away, but I still get the same error about ThirdPersonNavigation identifier not found in the function call however, even though again the parameter is of type TComponent, and MyThirdPersonNavigation is a valid component that I added to the main viewport manually.

Unfortunately, TViewMain is of no help here because there is no call to the constructor from another function, as there is no need to because it is the main function.

Cause I know for a fact that in the procedure and method (which is a special type of function/procedure) definitions, you type “template variable name: data type” like that word for word, because it explains all that in the book michaelis gave me.

Post the code you corrected again and indicate the line where it gives the error, so it will be easier for someone to help you.

{
  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
  MyThirdPersonNavigation := TMyThirdPersonNavigation.Create(ThirdPersonNavigation);
  MyThirdPersonNavigation.AssignAvatar;
  inherited;
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.

This is what the code looks like now, even though I made sure to be meticulous about making sure it is done according to the conventions the book lays out for me.

The error I am getting is in the TViewMain.Start script, where it tells me that
the call to ThirdPersonNavigation.AssignAvatar idents no member, even though
I created an instance of it above using the correct construction call; without it
I get a different error about ThirdPersonNavigation not being defined.

And cause I can tell that to call it local to a function body, you need to call a constuctor of/initalize the instance, if I am reading what the book tells me correctly.