Factored out common collision logic (plenty more to go)