Need an answer for why my clamp isn't working

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By superkp

I’m new to Godot and I’m trying to follow the tutorial here: https://www.youtube.com/watch?v=FgtekgMca2E

This tutorial is obviously for version 2.0 and I’m coding in 3.1 - my below code is changed in a few ways to reflect that.

I’m running into a problem that I don’t understand as far as getting the code updated, and I’d like to understand what it is - I think that it’s a key to my own understanding of how 3.1 is doing a few things here.

Something is going wrong when I try to run it as-is. I get an error: "Invalid get index ‘width’ (on base: ‘Vector2’)

If I comment out the clamping lines at the end, it runs, but my player is obviously not clamped and can wander off the visible space of the game when run.

This could be the fact that (after checking the documentation for “get_viewport_rect”), “size” is just a vector, and not a rect2, which is what clamp would need if we are calling “screensize.width” there at the end.

OR, I’m not understanding something about how we call ‘get_view_rect().size’, and it’s returning something useful, but either clamp is working in a way that I don’t understand or the “.width” portion is working in a way I don’t understand. And I’d really like to understand this.

SO, this is the script on player.tscn, which also includes a sprite node and a collisionshape2d node. The entire script is below. I’m using “…” to indicate indents. Sorry for any issue with formatting, this is my first post here.

extends Area2D

export var speed = 400

var screensize
var extents
var vel = Vector2()

func _ready():
…set_physics_process(true)
…screensize = get_viewport_rect().size
…extents = get_node(“CollisionShape2D”).get_shape().get_extents()
…set_position(screensize / 2)

func _physics_process(delta):
…var input = Vector2(0, 0)
…input.x = int(Input.is_action_pressed(“ui_right”)) - int(Input.is_action_pressed(“ui_left”))
…input.y = int(Input.is_action_pressed(“ui_down”)) - int(Input.is_action_pressed(“ui_up”))
…vel = input.normalized() * speed
…var pos = get_position() + vel * delta
…position.x = clamp(position.x, 0, screensize.width)
…position.y = clamp(position.y, 0, screensize.height)
…set_position(pos)

:bust_in_silhouette: Reply From: Adam_S

Use screensize.x and screensize.y to get your width and height.
And I think you will have to set position before the clamp() function.

set_position(pos)
position.x = clamp(position.x, 0, screensize.x)
position.y = clamp(position.y, 0, screensize.y)

EDIT:

Of course you should use clamp() for the pos variable, and set the position after that.
So your last three lines should be:

pos.x = clamp(pos.x, 0, screensize.x)
pos.y = clamp(pos.y, 0, screensize.y)
set_position(pos)

That worked great. Thanks!

If you’ve got the time, do you know why it works that way?

like, what happened between version 2 and 3 that the order needs to be different?

superkp | 2019-09-15 13:55

In your code you use clamp() for the position property.
In the tutorial you linked clamp() is used for the pos variable.
That’s why the order has to be different.

Adam_S | 2019-09-15 14:24

pos was the variable name in Godot 2 (in the linked tutorial).
position is the name in Godot 3 (in the shared code).

jandrewlong | 2019-09-16 14:41

That mostly worked, but setting the clamp first still makes it not work.

Not sure why, but I’m moving on.

superkp | 2019-09-24 01:07