Might need help with code for my Sonic Engine

I’m not rly too experienced with Godot that much, but I can try to remake Sonic physics, if I even have the time. can ya help me turn sum of this base code into something that resembles Sonic physics?

extends CharacterBody2D

@export var speed = 1200
@export var jump_speed = -1800
@export var gravity = 4000
@export_range(0.0, 1.0) var friction = 0.1
@export_range(0.0 , 1.0) var acceleration = 0.25


func _physics_process(delta):
    velocity.y += gravity * delta
    var dir = Input.get_axis("walk_left", "walk_right")
    if dir != 0:
        velocity.x = lerp(velocity.x, dir * speed, acceleration)
    else:
        velocity.x = lerp(velocity.x, 0.0, friction)

    move_and_slide()
    if Input.is_action_just_pressed("jump") and is_on_floor():
        velocity.y = jump_speed

if you can, plzz let me know, thx

It would be better to use move_toward (with a much higher acceleration) instead of lerp, but other than that recommendation I’m not sure you’ve explain what makes something resemble sonic physics. Is there anything you are particularly dissatisfied with? What happens in game and what do you expect to happen? How do those two questions line up?

Alright i’ll get on that right away, but mainly I was asking how I can add Sonic styled terrain collision, air speed, loop-de-loops, rolling homing attack, and spindash

Okay, here’s the new code:

extends CharacterBody2D

@export var speed = 360
@export var jump_speed = -420
@export var gravity = 960
@export var friction = 2.68
@export var acceleration = 1.68


func _physics_process(delta):
    velocity.y += gravity * delta
    var dir = Input.get_axis("ui_left", "ui_right")
    if dir != 0:
        velocity.x = move_toward(velocity.x, dir * speed, acceleration)
    else:
        velocity.x = move_toward(velocity.x, 0.0, friction)

    move_and_slide()
    if Input.is_action_just_pressed("ui_accept") and is_on_floor():
        velocity.y = jump_speed

What about Sonic’s slope detection? What methods do you recommend?

I believe CharacterBody2D has a way to change gravity direction using a 2D vector representing up.

It definitely also has a maximum angle you can set which your game character considers a floor.

Maybe experimenting with those might help.

Tried that, and also tampered with my code:

extends CharacterBody2D

@export var speed = 360
@export var jump_speed = -420
@export var gravity = 960
@export var friction = 2.68
@export var acceleration = 1.68
@export var skid= 6.68
@export var acceleration_value=1.68
@export var is_skidding=false

func _physics_process(delta):
	velocity.y += gravity * delta
	var dir = Input.get_axis("ui_left", "ui_right")
	if dir != 0:
		velocity.x = move_toward(velocity.x, dir * speed, acceleration_value)
		if (dir==1 and velocity.x < 0) or (dir==-1 and velocity.x > 0):
			is_skidding=true
		else:
			is_skidding=false

		if is_skidding:
			acceleration_value = skid
		else:
			acceleration_value = acceleration
	else:
		velocity.x = move_toward(velocity.x, 0.0, friction)
	move_and_slide()
	if Input.is_action_just_pressed("ui_accept") and is_on_floor():
		velocity.y = jump_speed

Max angle is 180, snap length is 16 pixels. What I’m trying to ask is, how can I get Sonic to rotate with the slope, both the collision and the sprite?

Maybe swap out the CharacterBody2D entirely for a perfect circle rigidbody2d for the duration of the looping, using detection areas to trigger the swap?

You need to know the impulse to give to the rigidbody2d then, I have no clue how to compute that.

Honestly… IDRK if I even wanna do that… btw my collision shape is a rectangle, and plus, the rigid body 2d isn’t really that good for making platformers, and I want to keep using the character body, even thru the loops… maybe I could do that when sonic’s rolling…

Well, I’m sure my advice here won’t be the best, but sometimes a little out of the box extreme measure thinking will sharpen your sight on a viable possibility.

Another thing I sometimes hack is just not invoke move_and_slide at all during a certain state and simply make my character follow a fixed Path2D.. like rails

I decided to use a convex shape for my character body, and make sure it had the best of both worlds; no random rotation jitters on the floor, or in-between slope angles. It actually works REALLY good. Thank you for helping me think outside the box here, it really helped.

:heart_on_fire:thanks!

good to know it worked.
And here’s a hint for some of the trickier terrain collision: just force it on-rails. Most of the 3D games lock the character into the trajectory of a spline. Whenever you think sonic’s running direction detached from where you told him, that’s the stage turning into a train until the gravity-defying bit (loop-de-loop, upside down, twist-and-turn, wall-run) is over.

i’ll try that dw

I actually might need some help coding the gravity-defying part, because I got a test circle in my level that could be part of the defying gravity part… would you recommend I use a raycast to detect the angle of the ground?

Wouldn’t an Area2D to indicate the loop start+end be simpler? (last one I’m doing :wink:)

Okay, I’ll get on that.

As long as we’re just sparring. I do not pretend to know any better, just out of the boxing.

i was thinking the same.

    1. Area2D signals the player entered the loop, the stage disables character physics and lerps character position to the start of a curve2D node.
    1. character in “scripted traversal” mode runs along the trajectory of the curve2D node. The curve is manually crafted or generated so that it goes along the loop.
    1. another Area2D at the end of the curve signals the stage to put character back in physics mode and return control to the player.

Had to COMPLETELY rewrite the code… was doing it with Gemini (hope y’all can forgive me) and it tilted sideways and plummeted south pretty quick.

Here’s the new code:

extends CharacterBody2D

var speed = 360.0
var jump_speed = -420.0
var accel=170
var decel=270
var fastd=470

# Get the gravity from the project settings so you can sync with rigid body nodes.
var gravity = 960
var skidbool=false

func _physics_process(delta):
	# Add the gravity.
	velocity.y += gravity * delta

	# Handle Jump.
	if Input.is_action_just_pressed("jump") and is_on_floor():
		velocity.y = jump_speed

	# Get the input direction.
	var direction = Input.get_axis("ui_left", "ui_right")
	if direction !=0:
		velocity.x = move_toward(velocity.x,speed*direction,accel*delta)
	else:
		velocity.x = move_toward(velocity.x,0,decel*delta)

	move_and_slide()



	if (direction<0 and velocity.x>0) or (direction>0 and velocity.x<0):
		skidbool=true
	else:
		skidbool=false
	if skidbool:
		velocity.x=move_toward(velocity.x,0,fastd*delta)

What do you recommend so that the player’s collision AND sprite rotate along the ground normal?

Just let me know gng

I recommend starting with something simpler than Sonic.