Screen coordinates


How can I set coordinates so that x,y = 0,0 bottom left screen of the background image for this scene sprite?
0,0 is now centre of the viewport; that is not usable.
So I would like to align it to bottom left corner of the image.

Viewport.Camera.Orthographic.Width := 1920;
Viewport.Camera.Orthographic.Height := 1080;
Viewport.Camera.Orthographic.Origin := Vector2(0.5, 0.5);

PlayerScene.Translation := Vector3(0, 0, 1);

About the first question (coordinates): Just shifting the scene by (SceneWidth / 2, SceneHeight / 2) works without any issues:

I’ve tried to create something like a point-and-click example, see here : GitHub - eugeneloza/point-and-click: A small example of point-and-click movement

Many thanks for this.

I am trying to move a custom mouse (scene) to the same coordinates as the Windows mouse. When I move it to 0,0 (bottom left screen) they match but moving it up and right the distance between them becomes larger. I don’t know what I am doing wrong here.

Mouse.Translation := Vector3(Window.MousePosition.X - Background.BoundingBox.Size.X/2 , Window.MousePosition.Y - Background.BoundingBox.Size.Y/2, 1);

Note that TCastleWindowBase.MousePosition (or TCastleUserInterface.Container.MousePosition) are in “screen coordinates” - i.e. in real pixels of the Player’s monitor. And all UI and transforms are scaled in “effective coordinates” - i.e. original (unscaled) pixels before they are scaled to Player’s monitor. There are two values proportional to each other with TCastleUserInterface.UIScale (or TCastleWindowBase.Container.UiScale) coefficient. You can see this conversion done in the example I’ve posted above. For your specific case it will be:

Mouse.Translation := Vector3(Window.MousePosition.X / Window.Container.UiScale - Background.BoundingBox.Size.X/2 , Window.MousePosition.Y / Window.Container.UiScale - Background.BoundingBox.Size.Y/2, 1);

Thanks, but now I get a message that there is no UIScale member?

Ah indeed, it’s TWindowContainer, not TUiContainer. And TUiContainer in turn hides FCalculatedUIScale as a private field allowing TCastleUserInterface to access it through “almost-cheating” mechanism :slight_smile:

So, overall, that means you cannot get access to UiScale except from a TCastleUserInterface derivative. I see you have designed your game screen in Castle Editor - that means you should load it as a TUiState, right?

This way if you are updating the Mouse.Translation inside some of the TUiState events (e.g. Update) then you can simply:

Mouse.Translation := Vector3(Window.MousePosition.X / UiScale - Background.BoundingBox.Size.X/2 , Window.MousePosition.Y / UiScale - Background.BoundingBox.Size.Y/2, 1);

I am not using Castle Editor and TUistate (yet), the game screen was just for trying things out.
So how can I access UiScale within a TCastleUserInterface derivative?

Just like UiScale (as in `Self.UiScale).

Hm, I’m not using TUiState either, do I need to use that really?
My code is in topic “Collision Course”.

TUiState is a derivative of TCastleUserInterface. As far as I understand:

You are using a TCastleUserInterface, right - who updates it? I’ll check your code in that topic a later.

@Carring Indeed the UI scaling is making this non-trivial.

But we have a dedicated methods in CGE viewport to make it easy: TCastleViewport.PositionTo2DWorld documented on Castle Game Engine: CastleViewport: Class TCastleViewport . If you pass ScreenCoordinates = true parameter, then it will automatically work with mouse position, and handle some things:

  • that UI scaling may be used (mouse positions are provided unscaled)

  • that viewport may not fill the entire screen.

So you can use the resulting value as MyTransform.Translation. E.g. code like this will make sense:

MyTransform.Translation := MyViewport.PositionTo2DWorld(Event.MousePosition, true);

The ScreenCoordinates = false is also useful, it means that you provide values in viewport size (so e.g. X between 0 and MyViewport.EffectiveWidth). This allows to reliably ask “what is the position inside world at any corner of the TCastleViewport”, e.g. MyViewport.PositionTo2DWorld(Vector2(0, 0), false) (left-bottom corner), MyViewport.PositionTo2DWorld(Vector2(MyViewport.EffectiveWidth, MyViewport.EffectiveHeight), false) (right-top corner) etc.

See also some related utils like PositionToRay, PositionToCameraPlane, PositionToWorldPlane. They all define ScreenCoordinates parameter with the same meaning.

Now I stumble upon that Scene translation is Vector3 and PositionTo2DWorld “wants” Vector2.
I have this (which gives error):

procedure SetMouse;
Mouse := TCastleScene.Create(Application);
Mouse.Load(‘castle-data:/mouse-icons.starling-xml#fps:8, anim-naming:strict-underscore’);
Mouse.Translation := vector3(Window.MousePosition.X, Window.MousePosition.Y, 5);
Mouse.PlayAnimation(‘mouse-icons-2’, true);

procedure WindowUpdate(Container: TUIContainer);
Mouse.Translation := Viewport.PositionTo2DWorld(Window.MousePosition, true);


That’s because mouse position doesn’t have Z coordinate - it’s on the screen. But scenes indeed have Z coordinate - it goes from the Player (negative values) to depth (positive value). Here Z means Z-sorting, i.e. the scenes with higher Z are further away from the camera. So, if you want to have mouse cursor over all other scenes - be sure to give it the minimal Z coordinate value, e.g. like this:

Mouse.Translation := Vector3(Viewport.PositionTo2DWorld(Window.MousePosition, true), -1);

P.S. Note, that it’s much more readable if you enclose the code pieces in “`” symbols (the back-quote one, which is on the same key where “~” symbol is.

If you use a matching pair those in one line you get blocks like this.

Or you can put three back-quote symbols on a separate line - and another three in the end to have a big block of code inside

This way your code will be much more readable and won’t lose indentation. (Yes, I didn’t yet look at your code in that topic you’ve mentioned above just for this reason - I can’t such a big piece without any indentation and markup, and indenting it manually would take a lot of time.

For very large pieces of code you might also want to use or even a public git repository (at GitHub, GitLab or any other convenient git hosting with visual code viewer).

Thanks, finally got this working.

And I will experiment with your suggestion on the enclosure of the code.

About the Z coordinate: Is it not the other way around that the higher the Z coordinate is, the scene is more placed in the front? When I give Mouse Z - 1 it is not visible on the screen. I think it is placed behind the background scene as it has Z 0 and other scenes have Z 1 and 2. I have to give Mouse Z a higher Z value than the other scenes to place it in front of all the others. so I gave it number 9.

1 Like

Yes, the Z coordinate (in standard 2D projection in CGE) grows as you get closer to the viewer.

In standard 2D projection in CGE:

  • X grows to the right
  • Y grows up
  • Z grows toward the camera

It’s easy to visually using “right-hand rule”, as CGE has “right-handed coordinate system”, Right-Handed Coordinate System -- from Wolfram MathWorld , Right-hand rule - Wikipedia .

As for placing the mouse cursor in front: remember to also call Viewport.Items.SortBackToFront2D after adding new mouse scene to Viewport.Items, to make proper blending. See Blending · castle-engine/castle-engine Wiki · GitHub for gory details.