Creating a strategic adventure step by step - part 3

About time for an update.
I wanted to add more stuff and there are some flaws that I am working at, but anyway, here is another demo.
I will try to put a better picture quality movie later than this one.

Most things that I worked on are in the code (so you won’t see them in the demo) but here are some visible:

  1. added some sounds
  2. expanded NPC scenes and properties
  3. NPC can now move and (be ordered to) follow player
  4. location scenery objects (palm trees, ocean), and props (speedboat, waves)
  5. first location

In the next update I will expand on this (more locations, scenery and props).
The arriving speedboat will be part of the game intro, game progression will be in chapters and events.

1 Like

Looks good, I’m happy you keep the progress on this!

P.S. If you haven’t yet tried TCastleImageTransform , I would encourage you to look at it: TCastleImageTransform – best way now to place image inside a TCastleViewport – Castle Game Engine . It addresses some uncomfortable image behavior that we have talked in the past, e.g. you can set Pivot to (0,0) to have image pivot be at a corner (not at center).

Thanks, I just tried it (replacing the static speedboat image TCastleScene with TCastleImageTransform) and it works fine.
Because the oceanwaves and speedboatwaves are animated scenes that used the same custom object I will have to create a different class for them now.
But I have a strange problem with displaying the transforms at certain negative coordinates that I also had using TCastleScene:


type TRescueObject = class
  private
    Image: TCastleImageTransform;
    Text: TCastleText;
    Name, Description: string;
    public
    Constructor Create;
end;    
              
  Location.Props[1]:= TRescueObject.Create;
    with Location.Props[1] do
    begin
      Image.URL := 'castle-data:/objects/speedboat_backlayer.png';
      Image.Pivot := Vector2(0,0);
      Image.Translation := Vector3(-1153, 200, -Image.Translation.Y/10);
      Image.Scale := Vector3(0.7, 0.7, 0.7);
      Viewport.Items.Add(Location.Props[1].Image);
    end;          

When I decrease the image translation.X beyond a certain value (here -1153, the image will not appear on screen; it has to be at least -1153.

The same goes with the head of the player characters:

 Location.Props[5]:= TRescueObject.Create;
    with Location.Props[5] do
    begin
      Image.URL := 'castle-data:/characters/john carring/casual/johninspeedboat.png';
      Image.Pivot := Vector2(0,0);
      Image.Translation := Vector3(-63, 373, -318/10);
      Image.Scale := Vector3(0.75, 0.75, 0.75);
      Viewport.Items.Add(Location.Props[5].Image);
    end;                      

Here -63 is the maximum negative X value. If I decrease it any further the image won’t appear on screen, even if I increase the value with an update routine (as you could see in the demo the boat and character head move to the right because with every call X := X + 2).
So I don’t understand this restriction. Any idea what could be the cause of this?

From your code, I do not see anything wrong. Of course negative X values should work OK, and the image should be visible (at least part of it that fits within current viewport, taking into account the camera).

If you gradually change the X value, the image should gradually “slide” into/out of the screen, not disappear suddenly.

(Note: We do have “culling” algorithms that actually avoid rendering things that should be completely outside of the view. But these algorithms should be “invisible” to you, i.e. they are just an optimization, and they should work regardless of the current scene/image translation.)

I’d have to see a testcase, project to reproduce the problem, to debug it more.

Rescue_Island 8-02-2022.zip (82.3 MB)

Hi Michalis, here is the stripped down testcase version.
When Translation.X of the speedboat is < - 576 it won’t show up anymore on screen.
The same goes for the other props (character heads) if they get a negative value beyond some point, they do not show up anymore.

You should not use

Location.Props[1].Image.Translation.X :=
  StatePlay.Location.Props[1].Image.Translation.X + 2;
  1. First of all, you should not modify record component X this way, see Coding Traps | Castle Game Engine . You would modify a temporary vector value, or bypass the property “setter”.

    The page Coding Traps | Castle Game Engine lists various solutions, like doing Image.Translation := Image.Translation + Vector3(xxx, 0, 0) or Image.TranslationPersistent.X := Image.TranslationPersistent.X + xxx.

    I was thinking today, as you’re not the first one to fall into this trap… and I figured out how to prevent it, on the CGE side. If you take the latest Castle Game Engine code, the line

    Location.Props[1].Image.Translation.X := StatePlay.Location.Props[1].Image.Translation.X + 2;

    will not even compile (and that’s good as it would not work reliably). So the compiler will prevent the error. I will make a news post about it tomorrow.

    This was the culprit of problems. I can now start speedboat from X = -576, I can start johninspeedboat from X = -100, and it all works. The rest of notes are unrelated to the problem you reported (disappearing speedboat).

  2. You should not just add a constant value 2 in UpdateObjects. The TStatePlay.Update, and thus TStatePlay.UpdateObjects, are executed with different frequency on various computers, so this animation may play with different speed for different people. Instead, always scale all your movement by SecondsPassed (you have this parameter given in TStatePlay.Update, you can pass it to UpdateObjects). See Designing user interface and handling events (press, update) within the state | Manual | Castle Game Engine .

  3. You also should not need to refer to your own singleton StatePlay above.

In the end, this is what you should do instead:

Location.Props[1].Image.Translation :=
  Location.Props[1].Image.Translation + Vector3(120 * SecondsPassed, 0, 0);

I changed the 2 into 120, as now it is a speed per 1 second. If you adjusted the speed 2 to typical 60 FPS, then new 120 = 2 * 60 should achieve the same speed (but now reliably, i.e. speed will be the same even if the game will not run at 60 FPS on some systems).

  1. Same comment as 1 applies to changing Z, using Location.Props[1].Image.Translation.Z.

    Also, beware: there are limits on Z, outside of these limits the objects become invisible. These limits are in Viewport.Camera.ProjectionNear / ProjectionNear in your gamestateplay.castle-user-interface, and are (-1000, 1000) by default. So they are quite large… but they still exist :slight_smile: If anything will have Z outside of (-1000, 1000) range, it will not be visible anymore.

    From what I tested, this was not a culprit of your problems though. Still, please be aware of these limits on Z.

  2. You should not free your own instance by FreeAndNil(StatePlay) in TStatePlay.Stop. This was causing a crash at exit, at TStatePlay.Stop, as it calls inherited but it has already freed itself.

    You just don’t need to free the StatePlay ever, in normal case. It is owned by the Application, let it exist.

I attach the gamestateplay.pas after applying my changes and experimenting with start positions.
gamestateplay.pas (8.4 KB)

Wow, many comments on a little piece of my code, I would be afraid to send you the complete code.
:wink:
Just kidding.
Thanks! This is very clear now. I played with the start positions and they are fine.
I must admit (and you would guess) I already had many of the movements of Player and NPC with the Image.Translation.X, Y and Z in my complete code. Up until now I had no problems with them but obviously it is becoming a problem.
So I will have to overhaul my code and replace the movements with the Vector3 and SecondsPassed.

I am happy that I can now make the speedboat slide in from completely outside the view, that was my goal.
Thanks again.

I just downloaded latest CGE but it still compiles the old Image.Translation.X.
?

Ah, that’s because I made a small mistake yesterday and automatic tests didn’t pass, so the latest binary download on https://castle-engine.io/ doesn’t yet contain the changes to vector API that prevent the incorrect code from compiling.

I fixed them already, in a few hours it should be OK – I mean the binary build will contain my changes. You can check it by looking at https://github.com/castle-engine/castle-engine/releases/tag/snapshot , right now it says “20 commits to master since this release” and if you click on them ( https://github.com/castle-engine/castle-engine/compare/snapshot...master ) you can see a commit “TVectorXxx.X/Y/Z/W are regular fields, to avoid trap of …”. So this commit is not yet in binary build. But it will be soon, Jenkins will do it automatically, if I didn’t make any other errors :slight_smile: