Я не могу понять ваш код, но, создав свой движок Mega Man, я узнал кое-что, чем могу поделиться. Мой метод обработки столкновений заключался в том, чтобы попытаться двигаться, а затем отступить на необходимую сумму. Вам также необходимо знать, в каком направлении вы подошли к блоку, что не является тривиальным.
1) попытаться переместить. player.position += player.velocity
2) проверка на наличие столкновений с помощью пересечения ограничительной рамки
2a) Найдите пересечение ограничивающих прямоугольников игрока и блока. Я не собираюсь приводить формулу для этого, это почти тривиально.
2b) Ключевой момент: вы ДОЛЖНЫ рассматривать пересечение 0 высоты или 0 ширины (но не обоих) как столкновение! В противном случае ваш игрок будет «вибрировать» против поверхности столкновения.
3) Используя прямоугольник пересечения, определите направление захода на посадку. Алгоритм для этого включает сравнение наклонов скорости захода на посадку и диагонали прямоугольника пересечения.
4) в зависимости от направления захода на посадку (горизонтального или вертикального) решить, следует ли отступить от компонента движения x или y. Используйте высоту или ширину пересечения в качестве суммы для возврата.
5) Сохраните факт, что ваш игрок теперь заблокирован в этом направлении. Обратите внимание, что вы теперь касаетесь блока, но не внедряетесь в него. Вот почему пересечение нулевого размера все еще является столкновением - если это не так, то в следующем кадре он подумает, что не сталкивается и снова падает, что приводит к "вибрирующему" эффекту.
Что касается "уже на полпути в клетке" - вы случайно сравниваете центральную точку игрока с краем плитки?