MD3 - improve animations support

Did you mean this?

“Since it is published check if the name is exactly the same in the editor design. I remember this error when I changed names in the design and did not save the design first before recompiling the code.”

I did that, and as you can tell in the code the word “TMyThirdPersonNavigation” has the same exact syntax and spelling as when it was first defined earlier on the particular line it dislikes (line 60), so I don’t know what other errors I am making.

And even when I rename it to match the ThirdPersonNavigation name in the Viewport in all instances in the code, it gives me the same exact error. facepalm

Okay, actually I was wrong, it was about needing to use the variable name and not the class name, which again I stand by is nonsensical/weird, as almost always the syntax is “class.property” to access a property of a class and it doesn’t make sense to suddenly make random exceptions.

Now I am getting the crashing error I showed you guys earlier, even though I did everything right to the best of my ability. Am I missing something unspecified, because I did the same code as last time I did it and it was fine then?

For reference, 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)
  protected
  procedure AssignAvatar;
  published
    SceneHumanLegs1, SceneHumanBase: TCastleScene;
    HumanBase1: TCastleTransform;
    ThirdPersonNavigation: TCastleThirdPersonNavigation;
  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;

implementation

uses SysUtils;

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

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

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

procedure TViewMain.Start;
begin
  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.

And when I look up the Third Person Navigation in the API, there isn’t anything listed about “implementation” under the Unit/uses section, only the general unit. Does anyone know how I should figure out what to add under the “implementation” clause if that is what I am missing?

I tried Googling “Castle Game Engine implementation” but only got results about the general implementation of the engine as a whole, and not anything specific about the implementation section and what uses go under it vs the topmost “Uses” section.

This is wrong for a few reasons.

  • (Edit: Removed, this was a mistake on my side, there is such property of course. I was thinking of AutoAnimation.) There’s no property AvatarHierarchy in TCastleThirdPersonNavigation (which is the type of ThirdPersonNavigation field).
  • You didn’t initialize the field ThirdPersonNavigation. It would crash.
  • And it doesn’t make sense to have field ThirdPersonNavigation inside class TMyThirdPersonNavigation, when the TMyThirdPersonNavigation has already the features you want (as it descends from TCastleThirdPersonNavigation).
  • You also nowhere initialize any instance of TMyThirdPersonNavigation, nor do you use AssignAvatar.

I will repeat what I said in this thread a few times:

Please do not try to solve this task by writing code by “trial and error” (without understanding).

And this is what you effectively try to do, looking at 240 posts in this thread as of now. You make very basic mistakes, and you cannot solve the simplest compilation error. You have a number of misconceptions how the Pascal works. That’s all OK, we all learn, so…

Please take a step back. Learn Pascal, follow the resources we have pointed out, from More Resources to Learn Pascal | Castle Game Engine . Write a few simple applications, create your own simple classes, use them. Then come back to this problem.

What the actual heck do you mean I didn’t initalize TMyThirdPersonNavigation or
the field/variable ThirdPersonNavigation? I have it declared word for word at the top of the code, using the same exact syntax as declaring any other class and field within a class.

It’s this kind of stuff - stuff that’s inconsistent with what I do find in the tutorials - that I keep pointing out.

I guess you have a point that AvatarHiearchy is not a property of TCastleThirdPersonNavigation, so I can look in the API and try to figure out which one it is a property of. If that is the case though, why the actual heck even show me that you declared AvatarHiearchy as a property of TCastleThirdPersonNavigation using the syntax you specified I should use, when you know it doesn’t even work?!

It’s one thing to tell someone to fill in the details themselves for obvious stuff and learn for themselves, I’ll give you credit there, but to intentionally give people the wrong code is a whole nother story!

Also the idea I didn’t use AssignAvatar is nonsense; these lines in question use it word for word.

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

Also, I looked in the API for the TCastleThirdPersonNavigation, and guess what I found?!

AvatarHiearchy! For your reading pleasure:

Proof that AvatarHiearchy is explicitly defined as a property of TCastleThirdPersonNavigation!

Unless it’s done indirectly, like you can’t reference it explicitly, unlike how you can other properties, but again that is A: weird and incosistent with what a learner would generally expect, and B: I don’t think it’s documented well anywhere.

As for AvatarHierarchy: Sorry for confusing, indeed that was my mistake. Of course there is such property in TCastleThirdPersonNavigation, we have been talking about it a few posts above.

The rest of what I wrote (in post MD3 - improve animations support - #241 by michalis ) however still stands.

  • You didn’t initialize ThirdPersonNavigation. It’s not the same as declaring the field. Initializing means that you assing some value to the field, in this case: you need to assign some instance to ThirdPersonNavigation. Right now it is nil in your code and setting any property on it will crash.

  • You didn’t use the AssignAvatar which means you didn’t call this method anywhere. It’s not the same as defininig the method which you did.

  • The rest of problems I mentioned on MD3 - improve animations support - #241 by michalis also still stand. The code doesn’t make sense. Having a field ThirdPersonNavigation: TCastleThirdPersonNavigation inside TMyThirdPersonNavigation , which is TCastleThirdPersonNavigation descendant, doesn’t make sense for what you’re trying to do.

Please, again, step back. Write simple Pascal programs, declare some simple classes, use them. There’s lots of resources on More Resources to Learn Pascal | Castle Game Engine . Please follow them. Do not try to solve this problem by trial and error.

Thank you for clarifying the other things like what initalize vs declare mean, but the thing about having ThirdPersonNavigation inside TCastleThirdPersonNavigation is that I know it seems silly, but I had to do it or otherwise it wouldn’t accept me assigning the avatar hiearchy on the line I did it on, as I mentioned earlier, because it’s picky about using variables and not entire classes for whatever reason.

So I can figure out the code to initalize the variable by researching Pascal tutorials, like the specific syntax,

as well as seeing how you declare the variables in the official tutorials in the Manual specifically inside the body of the procedures you use them in, because it wouldn’t make sense to initalize the variable outside a procedure, function or similar cause it would cause confusion between multiple functions with the same variable name inside,

but I need help for this particular variable, knowing what value I should give it. Do I do it like “name of third person navigation object in the viewport”, making sure to use quotes to make it obvious I am passing a string, or do I do it without the quotes?

I also don’t understand why the procedure I was told to use for assigning the avatar doesn’t seem to have any inputs, unlike most procedures I have seen in the tutorials and examples.

I am not sure what do you mean by “picky about using variables”. But the construction you showed earlier really doesn’t make sense. You are already in TMyThirdPersonNavigation, a class descending from TCastleThirdPersonNavigation . You don’t need to declare a field ThirdPersonNavigation inside. You can just do AvatarHierarchy := .... (no need to prefix it with any instance) when you are implementing a method in class descending from TCastleThirdPersonNavigation.

It is hard to repeat, but really again: You lack basic knowledge how to use Pascal, or at least how to use classes in Pascal. Read resources linked from More Resources to Learn Pascal | Castle Game Engine . Stop trying to solve this particular task by “trial and error”. Read about how to use classes, create simple applications, declare some simple example classes that use
each other.

I mean, as I showed very clearly in one of my above posts, that if I passed “TCastleThirdPersonNavigation.AvatarHiearchy :=” as I know you should do for referencing a class property (and again I pointed out in the manual it says it is a class property), I would get errors about it not being accepted as a legitimate class reference, which is absolute crap, cause you and I both know that TCastleThirdPersonNavigation is a class by definition.

So I know it wasn’t you who pointed it out to me, but a user named Carring instead, but this is what he told me about it:

Hi.
I have seen this error many times when I call a class directly from within a procedure. :-)`
I think it is in:

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

You assigned a variable:

TViewPlay = class(TCastleView)
  published
    ThirdPersonNavigation: TCastleThirdPersonNavigation;

So in your procedure TMyThirdPersonNavigation.AvatarHierarchy := HumanBase1;
should be:
ThirdPersonNavigation.AvatarHierarchy := HumanBase1;

So why the heck is it that I don’t use TMyThirdPersonNavigation.AvatarHiearchy but instead use one of its variables, if I am supposed to be able to access and assign class properties directly? I think he pointed out I did it in a procedure, but again that doesn’t make any sense at all, I should be able to access the class reference with ease, and just cause I did it in a procedure it shouldn’t magically mean I have to use a different syntax all of a sudden.

But yes, I will get rid of the TCastleThirdPreson field and just try to pass the TCastleThirdPersonNavigation directly instead, and see if it works or not.

Again there is no logical reason why it shouldn’t, because I know the tutorials tell me that I can use class.property to access and assign class properties with ease.

The compiler is right, naturally. TCastleThirdPersonNavigation.AvatarHiearchy should not compile. AvatarHiearchy is a property of a class, and you need a class instance to use it. Solving it by adding a field ThirdPersonNavigation is exactly what I mean by “you will not solve it by trial and error” – it’s a nonsense solution because you don’t understand what is the problem.

Caring gave you a general solution “looks like you try to use a property on a class, but it requires an instance”. Yes, it will compile but is not applicable to this particular case. There are multiple other solutions.

We rely on you having programming knowledge to solve these things on your own.

We will really not get anywhere if you lack basic Pascal knowledge. You will misunderstand all the answers and recommendations we give you. This has happened now multiple times in this thread. All the compiler errors you get are absolutely logical, you just need to learn Pascal better to understand what’s going on.

It is hard to repeat, but really again: You lack basic knowledge how to use Pascal, or at least how to use classes in Pascal. Read resources linked from More Resources to Learn Pascal | Castle Game Engine . Stop trying to solve this particular task by “trial and error”. Read about how to use classes, create simple applications, declare some simple example classes that use each other.

Please follow my advise.

At this point, this thread has reached 250 posts. And I see no sign that you actually follow our advises and “take a step back and learn”. It is really not possible (for you, or others for you) to solve this by “trial and error”.

I ask you one more time: learn Pascal. Follow that resources. Write some simple applications. Do not try to solve this task by trial and error.

We will be happy to help, but we do not have capacity to teach you Pascal from scratch. That is why we refer you to resources above.

Please, go back to learning, and let’s stop this thread.

Now it makes sense that I am not following particular rules/exceptions, but again it all strikes me as weird and unintuitive that I have to memorize a bunch of exceptions instead of just doing things normally the way I would do them in most other languages, like usually “class.property :=” compiles fine in most other languages without needing instances etc, but I suppose I will just have to look more thoroughly.

It seems like what I pointed out to you several posts ago:

There doesn’t seem to be any variable that it references TMyThirdPersonNavigation.

Notice what the original code does:

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;

implementation
[…]

Now, from what I see and understand, I would try to add:

var
ViewMain: TViewMain;
ThirdPersonNavigation: TMyThirdPersonNavigation;

removing

ThirdPersonNavigation: TCastleThirdPersonNavigation;

from the class.

Also, I noticed this too but thought you removed it from the code to make it shorter, where do you call the AssignAvatar procedure?

I didn’t call it yet, but I will definitely transfer the vars over.

I know michalis’ heart is in the right place and he’s too busy to walk me through every step in painstaking detail, but many of the things I keep running into are stuff that would strike any sane person as unintuitive/illogical unless they know the ins and outs of Pascal programming already. For an analogy, it would be like expecting me to have a Ph.D in food chemistry when all I wanted to do was make myself a breakfast from an easy to use cookbook.

on top of this, the tutorials he gave me don’t actually show me for example, that I would use an instance for a class in a procedure and not the actual class reference itself, and that’s been my point the entire time - his resources don’t help you with every problem you encounter, which I will repeat as many times as he repeats the idea that I am getting problems because I didn’t read the directions thoroughly - sometimes there are no directions for the problems I get.