I looked at your code. Things unrelated to the issue at hand (shaky feet):
You leak memory.
Remember that you have to free the objects you create. There are various ways to do this – you can free explicity by
FreeAndNil(xxx), you can make objects descend from
TComponent and create with an “owner”. But you have to do something, otherwise the game at the end will leak memory. And it’s better to fix it, otherwise in more complicated scenarios the game will also leak memory during longer execution, eventually exhausting the available RAM.
See our Pascal introduction on Modern Object Pascal Introduction for Programmers about “Freeing classes”.
See our docs on how to be notified about these memory leaks: Detecting Memory Leaks Using HeapTrc · castle-engine/castle-engine Wiki · GitHub . I use HeapTrc by default, so I noticed these leaks.
For starters, I added
Stop method to the state and freed there some things you allocate in
// declare inside TStatePlay like this
procedure Stop; override;
// implement like this
You also need
TAvatar destructor, to free what you allocated in
// declare like this in TAvatar
destructor Destroy; override;
// implement like this
StandIdleScene := TCastleScene.Create(Application);
WalkLeftScene := TCastleScene.Create(Application);
WalkRightScene := TCastleScene.Create(Application);
TAvatar.Create is not useful – later you override the
StandIdleScene etc. values by
Player.StandIdleScene := DesignedComponent ('StandIdleScene') as TCastleScene;.
PlayerMouse := TGamemouse.Create(PlayerMouse); works, but is confusing. It is actually equivalent in this case to
PlayerMouse := TGamemouse.Create(nil); since
PlayerMouse is not yet initialized before it is created. Change it to just
PlayerMouse := TGamemouse.Create(nil); to be less confusing.
You have somewhat random indentation,
TAvatar and all it’s fields are indented by 3 spaces. It is more standard to have
TAvatar indented by 2 spaces, and the inside (like fields) by 4. In general any indentation is OK, but use it consistently, your
TStatePlay use a different indentation.
Your code and data is not prepared for the case-sensitive system, like on Unix. I mentioned this before, and eventually I just did now a mechanism in CGE to accept such names: use unit
CastleURIUtils and set
CastleDataIgnoreCase := true; early (may be in
About shaky feet:
- This has nothing to do with using
PositionTo2DWorld, in my tests. In occurs both with an without. You just accidentally positioned the player at a different place on the screen, on a different background, with
PositionTo2DWorld case (line 303). So it just happened to be more noticeable in case of
PositionTo2DWorld, because it was on different background then. Change the lines 302-303 inside
TStatePlay.Update to test it like this:
if Container.Pressed[KeyS] then
PlayerTransform.Translation := Vector3(Player.X - 400, Player.Y - 600, Player.S) // smooth movement
PlayerTransform.Translation := Vector3(MainViewport.PositionTo2DWorld(Vector2(Player.X, Player.Y), false), 10); // tremor feet movement
The hardcoded shifts
- 600 above are just a quick hack to make the test fair, i.e. move the character to a similar place of the background.
Press key “s” for one version, release “s” for another version. You will see that “shaky feet” occur in both versions. Indeed they are more visible when window is larger.
The reasons are the same as in that old thread from 2018, Castle Game Engine / Old Forum / General Discussion: Shaky Sprite move . Your sprite sheet has high number of frames, but not high enough, and “time aliasing” is visible when you render 44 FPS animation on a screen that renders 60 FPS. Some frames just stay on screen longer than others.
And you have 44 FPS – as there are 8 frames per second by default when reading from Starling sprite sheet ( Sprite sheets · castle-engine/castle-engine Wiki · GitHub ) and you set
TimePlayingSpeed = 5.5 on
Quoting my answer from 2018:
Your sprite sheet has 24 frames per second, and it’s high enough that our eye “thinks it should be smooth animation”, but then it’s not smooth enough.
Now you have 44, but it seems it’s still not high enough.
Solutions from that thread still stand.
- Move the character slower (or faster) to break the aliasing.
- Experiment with different TimePlayingSpeed to have more FPS on animation.
- Or prepare a sprite animation with more FramesPerSecond, e.g. 60.
- Last, probably something you don’t want as it is a big change: Prepare this animation as a smooth animation (Spine, Blender), not sprite sheets. Sprite sheets are great for retro games with low frames per second and small images, when the animation is obviously not smooth to our eye. Here you created an animaton with high FPS, enough high resolution, so our eye things “this should be smooth” and reacts badly when the illusion fails, because 44 FPS doesn’t match 60 FPS.