Is there a way to use Vector2i positioning for Node2D?

Godot Version

4.4.1

Question

Currently, I am working on a pixel-perfect game. For the most part the floating point nature of the Node2D transformation system seems to translate just fine into a 320x180 window, but it seems to create an issue with my camera boundary system. I have a boundary system for the camera that involves 4 raycasts (N,E,S,W) coming from the player to the bounds of the screen. When they are touched on collision 4, it stops the camera from moving in that direction. However, as the player can move with decimals to position, this causes the camera to sometimes display one pixel fewer than it should when colliding with a boundary. If I use round() to round the positions of the boundary raycasts in physics_process it seems to resolve the issue. However, I feel like this is an unessesary step to have to run every physics frame in terms of preformance, and it also seems like it could cause a potential bug in the future since it could possiblly flash between rounded and non-rounded positions.

TL;DR: I need a good way to force either the whole game or just one Node2D to be able to position/transform with no decimals/Vector2i.

Does setting Snap 2D Transforms to Pixel in the project settings meet your needs?

Oh my gosh, this is an option I have been looking for ever since I started making my pixel game, I had no idea this existed! Thank you!

Oof, it seems as though that option only snaps the position graphically. I need something that can actually change the actual position of the Node2D to never have decimals or be an integer.

You can call floor() on the components…

Yes, but again that would require me calling global_position=floor(global_position) in process, which is pretty much the same as what I am doing right now with round().

Also, I created a new algorithm for my camera that does not involve raycasts and works fine, although I still think it would be preferable if it was possible to use integer positioning if possible.

I don’t think you can do exactly what you mention.
As an alternative, you can maybe create a variable that is just a getter that casts your Vector2 position into a Vector2i. This is still essentially just rounding down your position, but at least you’re not doing it every process frame unnecessarily, but only when needed.

var position_int: Vector2i:
    get: 
        return Vector2i(position)

Then you can call position_int instead of position in your code and it’ll get you a nice rounded int position.

PS: I’m on mobile, so can’t test the provided code myself, but should work nonetheless.

I am unaware of the “get” when defining the variable. Does “get” just essentially allow yow to run code with a return statement for setting a variable?

If this does what I think it does (literally creating a variable that is nothing but a Vector2i version of position) then I think that’s a good idea, but of little use for my purposes.

You see, I am looking more for performance and accuracy in pixel games, which can only be accomplished if the position is only ever processed in an integer.

That’s correct. You can find some more info about getters and setters here

Do you need to optimize the performance specifically here though? These operations are a breeze to calculate, even when done every frame. I doubt this will ever become your bottleneck.

Is this not accurate to what you’re looking for?

I more meant performance in the sense of “If you don’t need to calculate something, don’t”. And while it’s true that it’s a small difference, the decimals are just an unnecessary step in the case of a pixel game and therefore should not be calculated in the first place. Like, I want my game to be at least a locked 30 even on the most ancient of laptops, and have the best battery and power consumption as possible even on modern machines.

And I more meant accuracy as in collision, as without decimals players will 100% be certain that is an object narrowly missed them, they will be fine. However, with floating point values, even if the collisionbody is exactly matched up in pixels to a sprite there is a visibly 1 pixel margin in which an object can appear to miss another object yet still collide. However, with integer positions, the object will always be 100% synced with the sprite.

Anyway, it seems as though this is not a feature in Godot, so I opened up a feature request on github.

1 Like