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?

    RobotZap10000 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.

    • Toxe replied to this.

      award 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. 😉

        Toxe 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.

        5 months later