Respostas:
Isso ocorre porque, quando seu objeto entra na parede e você encontra a colisão, você está simplesmente parando o movimento do objeto, definindo sua velocidade como zero, mas o objeto ainda está dentro dessa parede.
Para corrigi-lo, você deve resolver a colisão movendo o objeto. Você tem duas opções aqui:
Implementação da segunda opção
Aqui, assumirei que a velocidade representa a direção em que o objeto está indo (basicamente, você não está alterando a velocidade entre a mudança de posição do objeto e a verificação de colisão). Também assumirei que sua origem está posicionada na parte superior esquerda da imagem (portanto, ao mover o objeto para resolver a colisão, posicionarei o canto superior esquerdo).
Aqui está como eu faria:
if (objRect.Intersects(wallRect)) // If there is a collision
{
Vector2 newPos = obj.Position;
if (obj.Velocity.X > 0) // object came from the left
newPos.X = wallRect.Left - objRect.Width;
else if (obj.Velocity.X < 0) // object came from the right
newPos.X = wallRect.Right;
if (obj.Velocity.Y > 0) // object came from the top
newPos.Y = wallRect.Top - objRect.Height;
else if (obj.Velocity.Y < 0) // object came from the bottom
newPos.Y = wallRect.Bottom;
obj.Position = newPos;
}
Você também pode usar a posição do objeto antigo para descobrir de onde ele é, mas usar a velocidade é mais simples nesse caso.
Você pode fazer isso de várias maneiras.
Um método é armazenar a posição anterior do retângulo em cada quadro. Portanto, quando seus retângulos se cruzarem, basta definir a posição do objeto para a anterior que não colidiu. Este método não é o melhor, porque se a velocidade do retângulo for alta, você poderá ver a reposição feita por código.
Outro método é testar a colisão com um Raycast, para que você possa visualizar uma colisão antes que ela aconteça.
Dê uma olhada no msdn para obter documentação sobre a colisão de Raycast e você poderá fazer isso.