Use one object type with a animation frame for each car.
The drag and drop is perfect for this and you can customize it with it's conditions.
If you save the position of the piece you're dragging to some variables at "on drag start" you can keep motion in one direction. For example for horizontal only motion make an event like this:
is dragging
or
on drop
---set y to start_y
When you drop the piece is when you want it to snap to the grid. It greatly simplifies things if the sprite's origin is to the top left since the cars are different sizes. Here is the formula for snapping to a grid: round(self.x/gridsize)*gridsize.
For collisions you could find the low and high limits of the motion so you could do the positioning like this:
is dragging
or
on drop
---set x to clamp(self.x, low, high)
---set y to start_y
A way to find the low and high would be to do a looping event under "on drag start" to first move the car left by grid steps until there is a wall to it's left. Save that as the low_x and then do a loop to do the same but moving right to find high_x.
ex.
on drag start:
--- repeat 10 times:
------[inverted] car overlaps wall at offset -gridsize
------ ++ car: set x to self.x-gridsize
------ ++ set low_x to car.x
--- repeat 10 times:
------[inverted] car overlaps wall at offset +gridsize
------ ++ car: set x to self.x+gridsize
------ ++ set high_x to car.x