I'm currently making a platformer game where I want the player to not collide with a platform made from a tile in a tilemap when they hold the down arrow, but to still be able to collide with other tiles. I thought that I could make the platform tile its own physics layer, and to make the player turn its physics mask for that layer on and off, depending on the input. However, I could not find a way to do that. Some answers said to just increase the y-coordinate for the player when they press the button and are on the floor, but the player's y velocity keeps resetting every time they hit a platform. Could anybody please help?
Constitutional I thought that I could make the platform tile its own physics layer, and to make the player turn its physics mask for that layer on and off, depending on the input. However, I could not find a way to do that.
This way works! You just have to know how to use the bitmasks. See here for an explanation.
I wrote some simple modifications to the default CharacterBody2D script to show how it can be done:
extends CharacterBody2D
const SPEED = 300.0
const JUMP_VELOCITY = -800.0
#switch back to this when we aren't holding down
var collision_mask_default := collision_mask
#This is a small trick with bits. On the right side we have the binary representation of the bitmask for layer 3.
#This assumes that we are putting our one-way platforms in layer 3. See the explanation in the docs.
#The ~ flips all the bits so all the 0s become 1s and all the 1s become 0s,
#becoming basically "every layer except for 3"
#The & gives a result where each bit is a 1 if and only if both sides are 1, otherwise 0
#The result is, if collision_mask were 0b00000000_00000000_00000000_00001111,
#then collision_mask_fallthrough would be 0b00000000_00000000_00000000_00001011
var collision_mask_fallthrough = collision_mask & ~0b00000000_00000000_00000000_00000100
# Get the gravity from the project settings to be synced with RigidBody nodes.
var gravity: int = ProjectSettings.get_setting("physics/2d/default_gravity")
func _physics_process(delta: float) -> void:
if Input.is_action_pressed("ui_down"):
#if we're holding down, apply the collision mask to not collide with the one-way platforms
collision_mask = collision_mask_fallthrough
else:
#make sure we are colliding with them otherwise
collision_mask = collision_mask_default
# Add the gravity.
if not is_on_floor():
velocity.y += gravity * delta
# Handle jump.
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
# Get the input direction and handle the movement/deceleration.
# As good practice, you should replace UI actions with custom gameplay actions.
var direction := Input.get_axis("ui_left", "ui_right")
if direction:
velocity.x = direction * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
move_and_slide()
Btw, I prefer to add something like this to my project:
class_name Layers
enum {
PLAYER = 0b00000000_00000000_00000000_00000001,
STAGE = 0b00000000_00000000_00000000_00000010,
PLATFORM = 0b00000000_00000000_00000000_00000100,
ENEMY = 0b00000000_00000000_00000000_00001000,
}
That way,
var collision_mask_fallthrough = collision_mask & ~0b00000000_00000000_00000000_00000100
becomes
var collision_mask_fallthrough = collision_mask & ~Layers.PLATFORM
which is much easier to read.
Zarah Talking about readability, personally I would only write as many nibbles or bytes as needed.
enum {
PLAYER = 0b0001,
STAGE = 0b0010,
}
Or:
enum {
PLATFORM = 0b00000100,
ENEMY = 0b00001000,
}
Otherwise it looks like there might be bits set in the upper bytes. Just a minor nitpick though. 😉
Ruscher Fair criticism. I actually use 2n to write mine and didn't know you could just do nibbles, but I thought dragging powers of 2 into the explanation would make it seem more complicated. But now I know about the shorter representation, thanks!
Thanks for the reply! However, I already know how to set the bitmasks, I just don't know how to give individual tiles in a tileset their own collision layers. Is that even possible, or do I have to make the platforms their own nodes?
I have finally found my answer! It lies in the physics materials of the tilemap.
First, I went to the Physics Layers menu in the tilemap inspector, added a new element and gave it its own collision layer:
Then I went to the tileset tab at the bottom of the screen, clicked on paint, selected "Physics Layer 1". clicked on my platform tile, and enabled one-way collision:
And voila! With the player script toggling the second bitmask, I can drop through as many platforms as I want while still not falling through my red tiles.
Do I need to mark my question as solved?
© 2022 - 2024 — McMap. All rights reserved.