My Player is a simple KinematicBody2D with a CollisionShape2D with a rectangle shape. Below is the code for my Player. For every frame it will print out "not on floor" or "IS on floor" depending on whether or not isonfloor() is true or false.
var vel: = Vector2.ZERO
var gravity: = 500
var FLOOR_NORMAL: = Vector2.UP
func _physics_process(delta: float) -> void:
if not is_on_floor():
print("not on floor")
print("IS on floor")
var x_input = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
vel.x += x_input * 4600 * delta - 0.25 * vel.x
vel.y += gravity * delta
vel = move_and_slide(vel, FLOOR_NORMAL)
This works fine when the object the Player stands on is a StaticBody2D with a CollisionShape2D child. When the Player is standing on the StaticBody2D it will print out "IS on floor" the whole time.
This also works well when I make a TileMap and use single tiles with Collision Mode of size 64x64 or larger. The Player can stand anywhere on the tiles and isonfloor() will always return true.
However, if the size of the tiles are 32x32, 16x16 or 8x8, when the player stands on them the isonfloor() function will return true and false consecutively on each frame. If you move about you can find some areas where isonfloor() works correctly, but most places the Player stands it will not work properly.
For added clarity, the TileMaps cell size is always set to the size of the single tiles (the Step size in the Snap Options) of the TileSet Editor. Also I have matched Layers and Masks between the Player and the TileMap.
It wouldn't be too difficult to quickly set up this scenario in a new project to test this out yourself.
Please help, thanks!