MD3 - improve animations support

Alpha versions are alphas for a reason (they’re not even “betta than nuffin”). They make quick changes, sometimes breaking ones (as in incompatible), sometimes breaking one (as in buggy).

Without being able to look at the development history and reasoning between specific changes - just grabbing some arbitrary snapshot and hoping it will go is one risky game. If getting into version-control is too much of effort, then i believe one should never start sailing. HAve the stable mostly immovable shore - as in last released stable - and homestead there, updating as rarely as possible.

If one choses to live on the edge, then, merely having a snapshot as a blackbox is not safe. Being able to read WHY this specific linewas changed and why (as in both commit message and other lines changed in the same day) can be a life saver. And “perverseness of the universe tends to a maximum”.

When i first wet my feet in CGE, git blame often helped me - to grasp the idea of some low level code line i had to match it with other lines changed in the same batch.

Now, surely, not everyone happen to have some old buggy video driver like i did - yet these or those troubles are always lurking in the shadows and one is always better safe than sorry.

We take both stability and backward compatibility heavily into consideration. I reiterate: the versions on Download | Castle Game Engine , even though marked as 7.0-alpha.snapshot, are what I recommend to use, also for production.

Of course if you use them for production – take a note about the date when you get them, and always when upgrading do the testing before you commit to new version. Watch our news ( Castle Game Engine – Open-Source 3D and 2D Game Engine ) for notes about important changes. (If anyone wants, of course also look at git log/blame… but this is unworkable for most people, in CGE or any other actively developed project.)

Current 7.0-alpha.snapshot is much better than last released 7.0-alpha.2 ( Release 7.0-alpha.2 release: a lot of new components (lights, primitives), new cameras, terrains, sprite sheet editor, Delphi · castle-engine/castle-engine · GitHub ). And really noone should even consider using older 6.4. The new things done are on New Features in Castle Game Engine 7.0 | Castle Game Engine .

In all of this, there’s of course an important TODO that I want to address ASAP: release “Castle Game Engine” as full, official, 7.0. Without any alpha or beta. But this takes time. Until that is available, I repeat: I heavily recommend using the default downloads from Download | Castle Game Engine , even though they are marked as 7.0-alpha.snapshot . They are simply the best we got.

Hi,

It appears that when I try to add a “ThirdPersonNavigation” Navigation object, it only lets you use nonsegmented/one piece models as avatars, and won’t let you use castle transforms that contain multiple parts, like the example uses.

Do you know of a good workaround, to make a third person camera that lets you use multi-part models as well as single part models for reference avatars that the camera should follow all the time?

Indeed TCastleThirdPersonNavigation expected to control animations using TCastleScene.AutoAnimation. So it assumed that the animation is played by TCastleScene.

I thought about possible answers, even pondering a recommendation to fork our CastleThirdPersonNavigation unit into your own.

… But then I realized I can easily make the TCastleThirdPersonNavigation class more flexible. I made the SetAnimation method virtual – see this GitHub commit which includes documentation how SetAnimation should behave: Make SetAnimation virtual, allow to override it in descendants · castle-engine/castle-engine@88dc2b9 · GitHub . As usual, I pushed the change to GitHub and it will take a while but eventually it will be available in the downloads on Download | Castle Game Engine . Watch this page: Comparing snapshot...master · castle-engine/castle-engine · GitHub , when it will no longer show the commit " Make SetAnimation virtual, allow to override it in descendants" → it means that this commit is now part of download on Download | Castle Game Engine .

The way to use it:

Define your own descendant of TCastleThirdPersonNavigation in your game that overrides SetAnimation. Like this:

type
  TMyThirdPersonNavigation = class(TCastleThirdPersonNavigation)
  protected
    procedure SetAnimation(const AnimationNames: array of String); override;
  end;

procedure TMyThirdPersonNavigation.SetAnimation(const AnimationNames: array of String);
begin
  // Apply desired animation in any way.
  // You are most interested in AnimationNames[0].
  // Over-simplifying, you can think that default implementation does "Avatar.AutoAnimation := AnimationNames[0]"
end;

Next use this class. You can add it to the viewport from code e.g. in view start:

procedure TMyView.Start;
var
  MyNavigation: TMyThirdPersonNavigation;
begin
  inherited;
  MyNavigation := TMyThirdPersonNavigation.Create(FreeAtStop);
  // adjust any parameters you need:MyNavigation.CameraSpeed := 9;
  MyViewport.InsertBack(MyNavigation);
end;

Make sure to remove the previous navigation, if you added any (by code or in editor).

Alternatively, you could register your custom navigation class following Custom Components | Manual | Castle Game Engine . This way TMyThirdPersonNavigation will be available at design-time, in the editor. Ignore this if this sounds too complicated :slight_smile:

Note: We are designing with Andrzej Kilijański a new approach to more modular “navigation classes”. They will be simpler, split into behaviors, and will make it easier to “roll your own navigation”. Initially a big simplification for 1st-person navigation, they will also come to offer simpler alternative to 3rd-person navigation. Watch CGE news in the upcoming weeks :slight_smile:

Thank you so much for the fix! I think from what I can tell, the latter half about custom components has the same instructions as the former one where you gave the instructions directly in the post, it just has more details on top of it.

I know because I want to do ThirdPersonNavigation only however, and not worry about other details, it would most likely be smarter to follow only the instructions in the post and ignore the link unless I need it for other classes.

I also highly anticipate and appreciate making the navigation classes more modular, instead of having only one very limited type of each.

Hi,

I downloaded the lateset version, making sure the set virtual thing you mentioned in the post is no longer on the page and therefore implemented,

but unfortunately I am running into syntax error weirdness with other parts of the code, even though I make sure to paste it word for word.

I used the code from the “md3 tags” demonstration that comes with the project per usual, but then just pasted the code provided above as an addition on top.

The exact error I am getting is “an = where a : should be” even though that is the syntax you used in the above post for the class defintion of TCastleThirdPersonNavigation.

Do you know why this is, is it perhaps put in the wrong spot?

{
  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;

type
  { Main view, where most of the application logic takes place. }
  TViewMain = class(TCastleView)
  TMyThirdPersonNavigation = class(TCastleThirdPersonNavigation)
  protected
  procedure SetAnimation(const AnimationNames: array of String); override;
  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;

  procedure TMyThirdPersonNavigation.SetAnimation(const AnimationNames: array of
  begin

  end;
  )

var
  ViewMain: TViewMain;

implementation

uses SysUtils;

{ 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);
  MyViewport.InsertBack(MyNavigation);
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.

Hi,

Does anyone have any replies on the issue in my previous post?

I made sure to be diligent about posting exactly the original code plus the additions given above where I thought it would fit best in the code (note in the original example that it was just standing alone and I had to guess where each line goes, which is probably part of the problem);

am I simply going about this the wrong way, like maybe there’s a different method altogether than using a third person camera explicitly to make a third person character with multiple, seperately, animated parts, or am I on the right track and need help with the code like I initially thought?

Sorry for a delay in answering. I had a busy July (started with IPC conference: International Pascal Congress – my presentation slides, various (positive) thoughts about Pascal (both FPC and Delphi) bright future, and why you should use Pascal – Castle Game Engine ), and I still didn’t recover to go through all my backlog and answer everything pending :slight_smile:

As for your question: The syntax you used to declare TMyThirdPersonNavigation inside TViewMain is incorrect.

1. You do

TViewMain = class(TCastleView)
TMyThirdPersonNavigation = class(TCastleThirdPersonNavigation)

which starts one class in another, but that’s not a way to declare a class within another (misses type keyword), also you never end the “inner” class.

See e.g. section " 9.2. More stuff inside classes and nested classes" in Modern Object Pascal Introduction for Programmers | Castle Game Engine about how to use nested classes. But, I would advise to actually not try to use this feature if you’re just starting, better follow my advise lower :slight_smile:

2. You also placed TMyThirdPersonNavigation.SetAnimation in the interface, while it’s an implementation should go into unit implementation section. You also added ) after it.

What you should do:

I know how the Pascal syntax in general works, so I don’t think reading up on how to program better would solve this particular issue; it’s just that I had problems understanding how your particular script was supposed to work, cause I was told to just copy paste it without understanding the implications of each line.

For example, declaring a class below another class should make it seperate intuitively/by common sense, and it’s really weird/unexpected that it would start a nested class.

Also, just based off the code provided there was no easy way to know ahead of time that the implementation of .SetAnimation should go in the implementation and not the interface section, but maybe I should have read about what classes go in interface and what go in implementation?

Either way, it would be easier for someone seeking support like me if you explained limitations like that ahead of time, instead of just assuming that I would look up that each piece of code belongs somewhere else specific from the other lines.

The help is always appreciated though!

Could you please help show me in full how the correct implementation looks using the third person camera example that comes with the game, what I was trying to do?

Okay, I copy pasted the code you attached as your example of the fixed version word for word, but now I am getting exactly these errors, I did the smart thing and sent a screenshot of what the errors say word for word so that way there is no misunderstanding like earlier.

Do you know why this is happening? I know that the classes should work correctly, so TCastleThirdPersonNavigation class should be in fact declared.

First of all, sorry – the code snippets I post here are often not tested for compilation, and they are often not the final solution ready to be pasted verbatim without any adjustments. I post code snippets to get you started :slight_smile: I hope to post enough to make it clear, but since I really don’t test for compilation all my snippets, some additional work is sometimes needed. If I’ll post something that I tested (for compilation / execution), I usually make it clear. If I instead mark the code snippet with a text like “use something like this” – the “like this” in general means that this is not final, and will not work if just pasted verbatim.

Up to your question from last post:

The error message means that you didn’t add to use uses clause in the interface section of your unit (GameViewMain) the unit that defines the TCastleThirdPersonNavigation class.

The missing unit is CastleThirdPersonNavigation in this case.

In general: You can always find the unit that contains some identifier by finding the given class in our API docs ( Castle Game Engine: API Reference ) and see at the “unit” containing it. In this case, these are docs for TCastleThirdPersonNavigation class: Castle Game Engine: CastleThirdPersonNavigation: Class TCastleThirdPersonNavigation . They specify it is in “Unit CastleThirdPersonNavigation”.

In Pascal, when you refer to something in the interface (in this case: TCastleThirdPersonNavigation class) then the respective unit (in this case: CastleThirdPersonNavigation) has to be in the uses clause in the interface section. And note that the unit in this case cannot be in the implementation section (you can only use unit once).

I would still very suggest to read our " Modern Object Pascal Introduction for Programmers" Modern Object Pascal Introduction for Programmers | Castle Game Engine . It has a section “Units” that explains these and other details about units :slight_smile: FPC has also docs e.g. about units: Free Pascal Reference guide .

I updated my sample on Fix syntax from https://forum.castle-engine.io/t/md3-improve-animations-support/775/73 · GitHub now. But this is still not something I tested for compilation! Go ahead and test it. If it fails, see if above resources allow to find the fix :slight_smile:

Okay, thank you for clarifying that misunderstanding that the code snippets are not actually the final versions but works in progress.

I will try to work with your suggestions in this post and see how it goes.

1 Like

Sadly, I am still getting the error about there being no method to override classes, even with your code; is there something in the documents I am missing?

Link to Image; darn upload feature isn’t working

Again, the issue isn’t that I am ignorant of Pascal language because I know that “uses” defines the code that lets you use the resources, or that I know that you have to type things in a particular order or else it won’t work,

the only problem is that I was trying to follow your directions literally/verbatim without understanding that there was actually more steps to it than just that, but you helped clarify that. I still strongly believe that showing all the steps to make something correct is the most helpful, however, rather than telling them to figure it out themselves after only a few steps.

For example, you should tell the person asking for help up front that they need to use the uses class for the ThirdPersonNavigation, rather than just having them shift through the documents and hope they figure it out themselves, as it is not obvious in the documents what classes require special “uses” declarations and which ones do not.

Do you understand that is my point now, like not everything is put neatly in the documents otherwise there probably wouldn’t be a need to ask for help?

Concrete example to demonstrate not every solution is neatly presented in the documents:

Third Person Navigation does not mention that it uses ThirdPersonNavigation under “uses”!

The API documentation for the ThirdPersonNavigation class you mentioned in your code above does not mention that it uses ThirdPersonNavigation as one of its Uses explicitily; you are left to essentially make an educated assumption and blindly hope it works.

Hm, I just tested Fix syntax from https://forum.castle-engine.io/t/md3-improve-animations-support/775/73 · GitHub and the only compilation error there is now about MyViewport missing – which makes sense, it is based on your code sample that didn’t contain MyViewport field. After commenting out the

MyViewport.InsertBack...

line it compiles OK. Of course in actual application you should have some MyViewport, and defined in your design, otherwise the navigation doesn’t make sense :slight_smile:

Anyhow, I don’t see the error message you show. It suggests you use outdated version of CGE, that actually doesn’t have my change to TCastleThirdPersonNavigation that exposed that virtual SetAnimation.

Can you please test whether you have the latest CGE? Get it from Download | Castle Game Engine .

You posted a link to the TChangeTransformation type in CastleThirdPersonNavigation unit. If you open that page and hit “home” key (or just scroll up to the very top) you will see it is part of “Unit CastleThirdPersonNavigation”.

Oops, I think that was a mistake cause I clicked on the first thing related to TCastleThirdPerson when I searched, but the point still stands that when you scroll to the top on my end, you don’t actually see “TCastleThirdPersonNavigation” listed explicitly under the “Uses” banner on the top, so again they would have to guess that part.

But I will delete the part about the MyViewport; again, this isn’t an issue about my lack of knowledge of Pascal, but something specific to the task at hand.

And yeah, probably cause it’s telling me that it doesn’t override when it should like you were telling me earlier, it’s probably just an old and outdated version of the Castle Game Engine, so I am going to re-download from the downloads page and see if it works afterward.

Okay, now I’m getting these errors having downloaded the latest version that does support the override I want using the same code.

Do you know why it expects a type identifier for the call to ThirdPersonNavigation, because I already specified a type identifier for the declaration of ThirdPersonNavigation earlier in the code exactly like you did?

I have the same confusion about the second part of the error message, because again I followed the syntax correctly the way it should work, it just doesn’t for whatever reason.

Like in your version, you had no right parenthesis, yet it wants it here for some unspecified reason, even though that is not, capital N-O-T, the way you did it.