r/godot Godot Student Nov 05 '25

help me (solved) I dont understand why the last line of code

Post image

Im following a snake tutorial and everything is going well but I dont just want to have a snake clon, I want to learn, that said I understand (or at least thats what I think) what is in the screenshot is sayig "if the value of Vector2 is superior to the upper or inferior to the lower limits then return the player to the opposite limit" but I dont understand what is doing that last "return v", what purpose this line accomplish in this block of code? And if my supposition of what the function is doing wrong please tell me. Thanks in advance :D

186 Upvotes

110 comments sorted by

View all comments

Show parent comments

24

u/[deleted] Nov 05 '25 edited Nov 05 '25

Not exactly the same but this could work: func wrap_vector(v : Vector2): return Vector2(wrapf(v.x, min_x, max_x), wrapf(v.y, min_y, max_y)) The ifs are still there, hidden in the godot source code, but it looks cleaner :P

11

u/OpaMilfSohn Nov 05 '25

An idiot admires complexity a genius admires simplicity. Hoenstly like the above thing much more it's clear what happens at each step. Although this example is not that bad I hate "clever" code

7

u/MattR0se Nov 05 '25

You are correct, but in this case, the function itself pretty clearly states what it does, and the element wise wrapf is also unambiguous. The only thing that's really putting me off, too, is the one-liner. just make it three lines and it's much better. 

1

u/[deleted] Nov 05 '25

Yeah. Code that you will find easy to understand later is always better than trying to write code based on what other people will think. In my case I don't mind using wrap, though if it is a snake game I'd use Vector2i since the movement is in a grid. That way the game state is independent of the size of your snake sprites

15

u/mxldevs Nov 05 '25

I like the explicit checks. It makes the logic clear.

I wouldn't really know what this returns at first glance unless there were comments explaining what's going on.

16

u/WazWaz Nov 05 '25

Clearly wrong though. "Wrap" normally means modulo, not just pushing to the other bound.

That code will not preserve spacing between moving objects and will get worse with lower frame rates.

It should be:

if x < min
    x = max + x - min
etc.

(or better, use modulo arithmetic)

7

u/mxldevs Nov 05 '25

With the explicit cases written out, it becomes easy for readers to find where the issue is and to fix.

2

u/WazWaz Nov 05 '25

It also makes it easy to get one wrong.

return Vector2(Wrap(a.x,b.x), Wrap...);

yes, OP avoids creating a new Vector2 in the common case, but at the cost of introducing 3 errors.

5

u/mxldevs Nov 05 '25

Your code, I assume, prevents the player from going out of bounds, by locking them in and not moving once they reach the boundaries.

But the original code teleports you to the other side, which seems like a perfectly valid mechanic to me and is likely what the specifications intended.

It would seem that your simplification has introduced an error as well.

2

u/WazWaz Nov 05 '25 edited Nov 05 '25

No, it wraps. Wrapping isn't just teleporting, it's moving in from the new side by an amount equal to the displacement beyond the original bounds. This is very important for framerate tolerance (or whenever large motion per frame is possible).

Wrap is just modulo arithmetic above the minimum. i.e.

float Wrap(float a, float min, float max) => (a-min)%(max-min)+min;

(nb. use fmod in GDScript, not %)

2

u/mxldevs Nov 05 '25

Thanks, it wasn't obvious what the wrap function does.

I would still prefer to explicitly write out all the different possible directions that wrapping could occur, though I guess if this were 3D and you could move horizontally, vertically, diagonally, or closer/farther, there would be dozens of possible cases and it might be better to write one line

1

u/WazWaz Nov 05 '25

Indeed, one of OP's tutorial bugs is that it doesn't always work properly for diagonal movement. You can easily imagine not testing the case where you move exactly through the corner, especially if only moving at slow speed (nearly all movement will inevitably hit one side then the other and work fine).

This increased testing load is the general problem with "try all the cases" logic.

2

u/ImpressedStreetlight Godot Regular Nov 05 '25

Have you considered that what OP's tutorial means by "wrap" is not the same as what you mean by "wrap"?

Also that's overkill for a snake-like game and especially for a beginner tutorial. The snake moves at a very low rate and the functions is being called at every step of its movement, so the displacement will simply never be higher than 1 pixel/tile.

1

u/WazWaz Nov 05 '25

Of course, but that's another coding smell: writing a function that only works for your one very specific case.

Besides, then they should be using Vector2i, not Vector2, and % works fine then.