I’m very new to game dev, have almost no prior programming experience. I’ve been watching various tutorials, and I have been scrolling through various forums. Working on my first game and one of the core mechanics is having the players in game size (and hit box) change based on their current speed.
I don’t know if this is something that can be done but I’m hoping to make it so my character will shrink in size the faster they move. I know how to manually change size through the inspector, but don’t know how to transfer that into script and allow the script to change it as my player current speed changes.
My thought process was get character current speed
If speed is 0, then player and collision hit box is 3x3y. if speed is between 1 and 10 player size is 2x 2y. if speed is greater than 10 than their size would be 1x 1y
Eventually, I’d like to connect other player stats (like max hp, attack power, etc.) to whatever size the character is but that can be a puzzle for another day. The main goal is changing size and collision size, making it so you can only fit through tight spaces if you’re going fast enough or falling through cracks if you aren’t big enough to roll over them.
Welcome to game dev and good job putting in the work to learn everything.
You already figured out you need to programatically change the size of the player’s collision, so that’s a first step.
Go to your player script and:
extends CharacterBody2D
var speed = 100
func get_input():
var input_dir = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
velocity = input_dir * speed
func _physics_process(delta):
get_input()
var mycollisionshape2d: CollisionShape2d = $CollisionShape2D
# Assuming you're using RectangleShape2D
var myshape: RectangleShape2D = mycollisionshape2d.shape
if speed <= 100 and speed > 0:
myshape.size = Vector2(2,2)
elif speed < 1:
myshape.size = Vector2(3,3)
elif speed > 100:
myshape.size = Vector2(1,1)
move_and_collide(velocity * delta)
# call this to set the new speed
func update_speed(newspeed: int):
speed = newspeed
This will just update the collisionshape. You’ll need to adjust the numbers to fit your purpose and update the reference to $CollisionShape2D if you renamed your shape. If your player uses a sprite you can use the same logic to update that too.
I am wondering what happens when you player moves at speed 150 and has a size of (1,1), squeeses in a small space and then stops? The player would then expand in a small area and get stuck?
Thank you for responding! I’m playing around with it, but it’s not quite working right. I’m not getting any errors popping up but it’s probably an issue with my code elsewhere. I’ve been playing with the speed and acceleration. I’ll be able to troubleshoot that later. If I’m using CircleShape2d, would I still use Vector2(x,y)?
Currently I’ve got:
I had a bit of a whoops earlier when manually changing sizes. I set it to 10,10 and when I hit play my character freaked out and kept snapping back to their starting point. I’m guessing something similar is going to happen when the player changes size while in a tight spot. I’m scheming different ways to change that, either through friction, level design, or I might add a secret and keep it as a surprise or achievement.
I’m not receiving any error codes, but the collision shape is still staying the same size. Removed my attempt at mysprite2D just in case it I didn’t type it up correctly and potentially causing issues.
Also tried using $CollisionShape2D instead of myshape just to check. Tried myshape.size.set_radius, myshape.set_radius(), and set_radius = radius. When I set it to Print(speed) and it does look like acceleration is working. Player does change speeds.
Unfortunately, that did not work either. I went to test something. I added a rule that if speed is between certain points then JUMP_VELOCITY would change. example.
If speed > 1:
JUMP_VELOCITY = 0
Jump velocity didn’t change, I’m wondering if that means I’ve written something that’s overriding the speed check. I’m going to play around and look through my other code to see if I can spot my oops
It would help if you put your code in a codeblock when you post instead of a screenshot. I actually couldn’t read your second screenshot, but I went back and read your first one just now. Your update_speed() method isn’t doing anything. You’re immediately overwriting the argument you just passed. Try changing the first line to: speed = newspeed
According to this code, your player’s jump velocity is only increasing if your player is moving right.
You have implemented _physics_proccess() twice. Your compiler should be giving you an error about that.
You never appear to use mysprite2D, mycollisionshape2d, or myshape in your code.
All three of those variables should be declared at the top of your file as @onready variables for two reasons. One, they are currently being declared, assigned, and destroyed 60 times a second. That could become a performance issue. Two, _physics_process can run before your object is ready, causing some gnarly race conditions. Having variables that refer to other nodes as @onready variables prevents this from happening.
You are never calling your update_speed() method in this code. (I’d also call it update_size, as that is what the code is doing.)
Not a huge thing, but since you update JUMP_VELOCITY after you assign it, it doesn’t change until the frame after it is modified.
JUMP_VELOCITY is no longer a constant, and it will improve readability of your code if you change it to jump_velocity to be less confusing. (That’s just a coding standard thing.) I initially wondered why you were trying to assign values to a constant, as that would not work. (Likewise base_speed would be clearer as BASE_SPEED.)
I’ve got through as best I could and am happy to say it’s working!
I can hit play and the collision box is changing size, jumping seems to be working, acceleration and deceleration is also working. I tried a few ways to get Sprite2d but I’m unsure how I’d go about formatting it. Would it be Texture2D, sprite_2d, Sprite2D, or something else?
extends CharacterBody2D
var speed = 100
const BASE_SPEED = 100
var max_speed = 500
var jump_velocity = -100
var acc = 10
@onready var sprite_2d: Sprite2D = $Sprite2D
@onready var collision_shape_2d: CollisionShape2D = $CollisionShape2D
@onready var mycollisionshape2d: CollisionShape2D = $CollisionShape2D
@onready var myshape: CircleShape2D = mycollisionshape2d.shape
@onready var mysprite2d: Sprite2D = $Sprite2D
func _physics_process(delta: float) -> void:
update_size()
# Add the gravity.
if not is_on_floor():
velocity += get_gravity() * delta
# Handle jump.
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = jump_velocity
if speed < 1 and speed < -1:
velocity.y = jump_velocity
elif speed <= 100 and speed> 1:
jump_velocity = -200
elif speed <= 200 and speed > 100:
jump_velocity = -400
elif speed > 200 and speed <= 300:
jump_velocity = -600
elif velocity.x > 300 and speed <= 400:
jump_velocity = -800
elif speed > 400:
jump_velocity = -1000
# Get the input direction and handle the movement/deceleration.
var direction := Input.get_axis('left', 'right')
if direction:
velocity.x = direction * speed
if speed < max_speed:
if Input.is_action_pressed('left'):
speed = move_toward(-velocity.x, -max_speed, -acc)
if Input.is_action_pressed('right'):
speed = move_toward(velocity.x, max_speed, acc)
elif speed >= max_speed:
speed = max_speed
elif speed < BASE_SPEED:
speed = BASE_SPEED
else:
velocity.x = move_toward(velocity.x, 0, acc)
speed = 0
move_and_slide()
#Flippy bits. Move left look left, move right look right
if Input.is_action_pressed('left'):
#print( velocity.x, jump_velocity, -speed)
sprite_2d.flip_h = true
if Input.is_action_pressed('right'):
sprite_2d.flip_h = false
#print(velocity.x, jump_velocity, -speed)
#Changing Size- Reminder to Thank Sniper Cup and Dragonforge
func update_size():
if Input.is_action_pressed('left') or Input.is_action_pressed('right'):
#print(velocity.x, jump_velocity, -speed)
#print(mycollisionshape2d.shape.radius)
if velocity.x < 1 and velocity.x > -1:
mycollisionshape2d.shape.set_radius(30)
#mysprite2d.size = Vector2(6,6)-
elif speed <= 100 and speed > 1:
#mysprite2d.size = Vector2(5,5)
mycollisionshape2d.shape.set_radius(25)
elif speed <= 200 and speed > 100:
#mysprite2d.size = Vector2(4,4)
mycollisionshape2d.shape.set_radius(20)
elif speed > 200 and speed <= 300:
#mysprite2d.size = Vector2(3,3)
mycollisionshape2d.shape.set_radius(15)
elif speed > 300 and speed <= 400:
#mysprite2d.size = Vector2(2,2)
mycollisionshape2d.shape.set_radius(10)
elif speed > 400:
#mysprite2d.size = Vector2(1,1)
mycollisionshape2d.shape.set_radius(5)
else:
mycollisionshape2d.shape.set_radius(30)
node names are usually in PascalCase,
including the default node name based on the node type.
so to get the direct child node named Sprite2D, you can use get_node("Sprite2D") or shorthand $Sprite2D.
to get the child Sprite2D of the child Foobar, you can use get_node("Foobar/Sprite2D") or $"Foobar/Sprite2D"
Yes, I was unsure of what node name to use but didn’t know the term I was looking for was called a node name. It ended up just being being mysprite2d for the sprite and didn’t need a secondary node name similar to how collsionshape has a secondary part called circleshape