El personaje podría ser no-sólido para que los enemigos puedan tocarlo, el empalme se evitaría con código. Tengo un sistema en el que el personaje y los enemigos tienen máscaras de colisión rectangulares, pero reaccionan a las colisiones como si fuesen circulares.

Es un script pequeño, pero necesitas conocer un poco de álgebra vectorial para entenderlo. Se coloca en un evento de colisión.
[gml]
///Colisión con un objeto movil
//Los objetos se desplazan de forma simetrica
d = point_distance( x,y, other.x,other.y ); //distancia
e = r + other.r - d; //empalme
if( e > 0 ) //si hay empalme
{
dx = (x-other.x)*e/d/2; //componentes del
dy = (y-other.y)*e/d/2; // desplazaminto
x += dx; //desplazar las dos
y += dy; // instancias en cantidas
other.x -= dx; // iguales, pero en
other.y -= dy; // direcciones opuestas
}
[/gml]
Es necesario que las dos instancias que colisionan tengan definida la variable r, que indica su radio.
Para realizar el knockback puedes usar las variables speed y friction, así el personaje se detiene automáticamente. Observa si eso no afecta el sistema de colisión que ya tienes establecido.

Es un script pequeño, pero necesitas conocer un poco de álgebra vectorial para entenderlo. Se coloca en un evento de colisión.
[gml]
///Colisión con un objeto movil
//Los objetos se desplazan de forma simetrica
d = point_distance( x,y, other.x,other.y ); //distancia
e = r + other.r - d; //empalme
if( e > 0 ) //si hay empalme
{
dx = (x-other.x)*e/d/2; //componentes del
dy = (y-other.y)*e/d/2; // desplazaminto
x += dx; //desplazar las dos
y += dy; // instancias en cantidas
other.x -= dx; // iguales, pero en
other.y -= dy; // direcciones opuestas
}
[/gml]
Es necesario que las dos instancias que colisionan tengan definida la variable r, que indica su radio.
Para realizar el knockback puedes usar las variables speed y friction, así el personaje se detiene automáticamente. Observa si eso no afecta el sistema de colisión que ya tienes establecido.