Attention | Topic was automatically imported from the old Question2Answer platform. | |
Asked By | MysticalKitsune |
I’m making a top-down action RPG that’s in 2d but tries to emulate 3d. I chose 2d because I wanted to have tilemaps, pixel-perfect rendering, and the kind of perspective that you’ll never achieve in 3d, not even with orthogonal camera. So saying “might be easier to just do it in 3d” is not an option.
So for my collision detection I used collision layers and masks, and the player’s layer is determined based on the position of the character and its base area. The character also has a layer_3d
var that helps manage overlapping collision.
Now since I’m planning on having quite a lot of platforming in my game, some part of me thinks having level collision take up almost half of all available layers is a terrible idea, but I just don’t know any other options, so if someone suggested one, it would be greatly appreciated.
The character scene has an area2d pointing in front of the character to detect whether it’s facing a platform. I didn’t use a raycast instead because as far as I’ve understood, raycasts don’t detect collision when inside the area if they aren’t long enough. And if a character falls from a higher area into a larger lower one, I believe this will be exactly the case.
That was enough text, here’s the code for the character:
extends KinematicBody2D
onready var ray = $Char/FakeRayCast
var accel = 850
var max_speed = 250
var friction = 800
var velocity = Vector2.ZERO
var input_vector = Vector2.ZERO
var jump_force = 250
var jump_vel = Vector2.ZERO
var gravity = 500
var pos_z = 0
var layer_3d = 0
func _physics_process(delta):
pos_z = int($Char.position.y)
move(delta)
if (ray.get_overlapping_areas()) and layer_3d == 1:
set_collision_mask_bit(0, false)
else:
set_collision_mask_bit(0, true)
# The layer_3d value should be that of the platform
# I just want to make sure everything works correctly with just 1 layer before stacking more
func move(delta):
input_vector.x = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
input_vector.y = Input.get_action_strength("ui_down") - Input.get_action_strength("ui_up")
input_vector = input_vector.normalized()
if input_vector != Vector2.ZERO:
velocity = velocity.move_toward(input_vector * max_speed, accel * delta)
# I don't know if you can turn a vector into a rotation degree
# This part would've been easier with a raycast
if input_vector == Vector2.UP:
ray.rotation = deg2rad(180)
if input_vector == Vector2.DOWN:
ray.rotation = deg2rad(0)
if input_vector == Vector2.LEFT:
ray.rotation = deg2rad(90)
if input_vector == Vector2.RIGHT:
ray.rotation = deg2rad(-90)
else:
velocity = velocity.move_toward(Vector2.ZERO, friction * delta)
velocity = move_and_slide(velocity)
jump_vel.y += gravity * delta
if Input.is_action_pressed("jump") and $Char.is_on_floor():
jump()
if Input.is_action_just_released("jump"):
fall()
jump_vel = $Char.move_and_slide(jump_vel, Vector2(0, -1))
func jump():
jump_vel.y -= jump_force
func fall():
if jump_vel.y < -150:
jump_vel.y = -150
func _on_LayerChangeArea_area_entered(area):
layer_3d = layer_3d + 1
func _on_LayerChangeArea_area_exited(area):
layer_3d = layer_3d - 1
# Starting from here, I don't quite understand what I'm trying to achieve
func _onCollTop_area_entered(area):
if layer_3d == 1:
position.y = position.y + 32 * layer_3d
$Char.position.y = $Char.position.y - 32 * layer_3d
# When above a higher layer, move the shadow up but don't move the char until it lands
# I probably have to modify this to account for platforms that are placed on higher layers
# And if layer_3d somehow turns out to be 0, that's no good
# So a better way to do this would also be appreciated
func _on_CollFull_area_entered(area):
if layer_3d > 0:
position.y = position.y - 32 * layer_3d
$Char.position.y = $Char.position.y + 32 * layer_3d
Also I can’t for the life of me figure out why the character’s y position relative to the parent node shifts slightly when the player is moving up and down, and it’s also not 0 at the start but rather -0.000549. Does it have to do with kinematic physics? The character is a kinematic body and so is its parent node, maybe that’s the problem. If I keep using layers for the z axis, I’m fine with the shifting as long as it doesn’t affect how the z axis works. However, if I choose a different approach based on your suggestions, it might become a problem.