I figure it’s just to do with me using the wrong syntax for this particular situation, even though you normally use the period for accessing a scene’s property, and I believe I should be perfect after this one is fixed, but you never know with code errors.
Hi, I got these errors instead now after fixing that one.
Does anyone know why AvatarHiearchy is not recognized in the current code?
I made sure to use the correct syntax for accessing a scene’s property initially, but had to change the period to a colon after I was given the compiler error in the post above (which again, makes zero sense because you are supposed to put the period to access a scene’s property).
unit GameViewMain;
interface
uses Classes,
CastleVectors, CastleComponentSerialize,
CastleUIControls, CastleControls, CastleKeysMouse,
CastleThirdPersonNavigation;
type
TMyThirdPersonNavigation = class(TCastleThirdPersonNavigation)
TMyThirdPersonNavigation:AvatarHierarchy := MyTransform;
protected
procedure SetAnimation(const AnimationNames: array of String); override;
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;
ExampleLegsScene, ExampleTorsoScene: TCastleScene;
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;
{ TMyThirdPersonNavigation ---------------------------------------------------- }
procedure TMyThirdPersonNavigation.SetAnimation(const AnimationNames: array of String);
begin
if AnimationNames[0] = 'idle' then
begin
ExampleLegsScene.PlayAnimation('idle', true);
ExampleTorsoScene.PlayAnimation('idle', true);
end else
if AnimationNames[0] = 'walk' then
begin
ExampleLegsScene.PlayAnimation('walk', true);
ExampleTorsoScene.PlayAnimation('walk', true);
end;
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);
// TODO: Remember to assign MyNavigation properties
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 statement does not seem correct. But allow me a note: this is not about the complexity of CGE but rather about the syntax of Pascal. I’m not a good programmer and therefore I don’t want to teach someone when I myself haven’t finished learning yet (and when does it ever end? ).
In your place I would take a couple of days to read michalis’ guide (I did, I’ve been using Pascal for a long time, but why not?).
Also I noticed that sometimes you repeat the same mistakes. For example your previous code class declarations after michalis had just explained to you that it was the wrong way to do it.
Again, it’s not a criticism, we all want to see the results of our work soon and we don’t take the time to get it right. Note this detail too:
one way to achieve it is to define and initialize additional fields in TMyThirdPersonNavigation , like `ExampleLegsScene, ExampleTorsoScene: TCastleScene
You put them in TViewMain, not TMyThirdPersonNavigation.
Another detail you should clarify:
MyNavigation.AvatarHierarchy := MyTransform; // MyTransform here is just an example
Thank you for that feedback. By no means am I offended; I know no one is a perfect programmer, especially if you are only a beginner without the advanced knowledge like me.
That clarification about me putting something in the wrong spot is very good feedback, cause that is definitely not something I noticed at first like you already figured out.
The MyTransform was just because I was copying the code verbatim, but maybe it’s meant to reference an actual transform like “HumanBase1?”
Unfortunately, I am getting the same exact error as the previous error report even with the fix, so we’re just going to have to sit back and wait for michaelis to clarify what else I am doing wrong.
unit GameViewMain;
interface
uses Classes,
CastleVectors, CastleComponentSerialize,
CastleUIControls, CastleControls, CastleKeysMouse,
CastleThirdPersonNavigation;
type
TMyThirdPersonNavigation = class(TCastleThirdPersonNavigation)
TMyThirdPersonNavigation:AvatarHierarchy := HumanBase1;
protected
procedure SetAnimation(const AnimationNames: array of String); override;
published
ExampleLegsScene, ExampleTorsoScene: TCastleScene;
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;
{ TMyThirdPersonNavigation ---------------------------------------------------- }
procedure TMyThirdPersonNavigation.SetAnimation(const AnimationNames: array of String);
begin
if AnimationNames[0] = 'idle' then
begin
ExampleLegsScene.PlayAnimation('idle', true);
ExampleTorsoScene.PlayAnimation('idle', true);
end else
if AnimationNames[0] = 'walk' then
begin
ExampleLegsScene.PlayAnimation('walk', true);
ExampleTorsoScene.PlayAnimation('walk', true);
end;
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);
// TODO: Remember to assign MyNavigation properties
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.
MyNavigation.AvatarHierarchy := MyTransform; // MyTransform here is just an example
Have you tried changing the code again?
Also, does your code know what HumanBase1 is? Otherwise there is no difference with MyTransform. I really believe you need to load the 3D model before you can use it, maybe in TViewMain.Create. I haven’t used CGE in a while, but you might want to take a look at the examples to see where and how your model needs to be initialized.
That is actually what I tried initially, but got an error with the period being in place of where a colon should be (again, makes no sense if you follow the rules of Pascal for accessing a scene’s properties!)
Maybe it was because, however, I used the wrong reference after the period, like it was when I copy pasted the old one before HumanBase1, and I can try the syntax again now?
Yes, in my opinion the error is raised by the compiler not because the dot needs to be replaced with a colon, but rather because it doesn’t recognize what follows (MyTransform or HumanBase1).
I’m pretty sure if you can initialize the model correctly, the error will go away
Okay, unfortunately I am getting more errors, in particular I get an error about IMPLEMENTATION being expected instead if I try initializing the HumanBase before accessing it in the code, and I get a whole slew of different errors worse than the current ones shown above, like about AvatarHiearchy not being defined, if I put the call to HumanBase1 in the protected section after the section where I declare all the TCastleScenes instead.
Finally, if I leave the order like it is but add the initiialization of HumanBase1 to the list with the Torso and Leg parts etc, I get the same exact errors as in the previous posts.
Does anyone know the proper solution to how to initalize it?
inside the class declaration. This doesn’t make sense for a few reasons
it’s an assignment (so it is something you are supposed to use inside a function/procedure/method body, not in class declaration).
you treat AvatarHierarchy as a class property, when it’s a property of an instance, as I said and shown.
HumanBase1 is not defined.
It seems you’re trying to write code by trail and error, but I’m afraid this will not work effectively (in Pascal or other languages). You are also in the middle of a bigger task (using navigation class and MD3) which is not a good way to learn.
They show how to declare classes, fields and how they work. I would advise to test these things on simple programs (not even related to CGE), e.g. create a class TApple with 2 fields like Weight and Radius, and play with them. Add sample fields, add sample virtual methods, see how it all “plays out” in a simple case, independently of existing CGE classes.
Once you have some simple test applications using (your own) basic classes, then get back to this subject. You need to know how to declare and use fields in a Pascal class to use CGE effectively
Okay, thank you for pointing me directly toward the resources that can answer my questions. I will try them and see how it goes, but I believe if I read it thoroughly I should have no issues.
Okay, I get these errors instead even though I make sure to follow all the examples to a T.
For example, I added the HumanBase1 in the same exact way as I was told to do earlier for the other things, and I saw in the reference examples that as long as you intialize the objects in the class declaration, you can use them wihout having to re-declare them in the procedure.
Am I missing something again?
unit GameViewMain;
interface
uses Classes,
CastleVectors, CastleComponentSerialize,
CastleUIControls, CastleControls, CastleKeysMouse,
CastleThirdPersonNavigation;
type
TMyThirdPersonNavigation = class(TCastleThirdPersonNavigation)
protected
procedure SetAnimation(const AnimationNames: array of String); override;
procedure AssignAvatar;
published
ExampleLegsScene, HumanBase1, ExampleTorsoScene: TCastleScene;
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;
{ TMyThirdPersonNavigation ---------------------------------------------------- }
procedure TMyThirdPersonNavigation.SetAnimation(const AnimationNames: array of String);
begin
if AnimationNames[0] = 'idle' then
begin
ExampleLegsScene.PlayAnimation('idle', true);
ExampleTorsoScene.PlayAnimation('idle', true);
end else
if AnimationNames[0] = 'walk' then
begin
ExampleLegsScene.PlayAnimation('walk', true);
ExampleTorsoScene.PlayAnimation('walk', true);
end;
end;
procedure TMyThirdPersonNavigation.AssignAvatar;
begin
TMyThirdPersonNavigation: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);
// TODO: Remember to assign MyNavigation properties
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.
That line is still not valid Pascal. You used :, you used class name TMyThirdPersonNavigation as if to assign a class property.
To solve the 1st error message also add CastleScene to the uses clause.
Please read the resources we pointed in this thread. And start from small examples. Don’t try to do this task (combining 3rd-person navigation with MD3 animations) by trial and error. To reiterate most important links:
Okay, thank you for the links! It is really weird/annoying that the colon assignment works in some spots and not others, but I guess that’s just programming life for you.
And actually, I was right about something not making sense even if you read the manual, namely that the error about TMyThirdPersonNavigation not accepting class properties doesn’t make any sense, because it is defined as a class explicitly/word for word in the manual, like in the scripting API like in the page I linked above.
Do you know if it’s supposed to be something else but says class in the manual?
I also know already about how the uses clause works, so for example I know that it lets you use the code that comes pre-packaged in the unit and without it the code is meaningless; I understand that already, it’s just tricky because the scripting API is really weird and doesn’t mention all of the uses for all the classes, especially the newer ones, which is what I was explaining earlier.
Yeah, and now it’s telling me what yo were telling me about TThirdPersonNavigation is not a class, and only class properties may be accessed in the syntax I used (which again is exactly what you said above).
This literally makes no sense, however, even after you read the manual, because it tells you TThirdPersonNavigation is defined as a class specifcally in the scripting API.
Okay, I re-read the page and it still stands that you explicitly define it with keywords like “type custom name = class(classdefined)”,
But it turns out that I mis-read it initially and you actually use TCastleMouseLookNavigation in the parenthesis part of the class definition and not TCastleThirdPersonNavigation.
However, now it’s telling me that TCastleMouseLookNavigation is an identifier not found, which I call absolute BS on, because as I just said it’s given to you word for word on the reference page.
Is it perhaps that I am missing another uses unit? Again, on the page it’s not given if that is the problem. Under Unit, it only says TCastleThirdPersonNavigation, and not anything else at all, period.
Other than that, I really recommend to follow the documentation (both CGE and Pascal) mentioned in my older post :
And start smaller. Start from simple FPC command-line programs to test various Pascal class features. Check out CGE examples (that are tested for compilation + run) link from above pages, do small modifications there once you understand them.
You are now in the middle of a complicated task (using 3rd-person navigation with MD3). Learning in the middle of this complicated task how to properly use assignment, what is a class property vs instance property etc. – this is not efficient.