So I'm trying to make my object move a few pixels at a time through a loop. But all I can manage to get it to do is move full tiles, I've tried pretty much everything but I can't seem to get it to function.. Could anyone help me get through this?

if(helm.getspeed() <= 0)
src.transform = turn(matrix(), helm.heading)
step(src, NORTH, 2)

I've tried move, walk, step, in all sorts of combinations and setups, it just doesn't want to function for me.

(On a side-note, would the transform be enough to rotate the object to the heading I select? If not, I could use help on that too.)
That looks like SS13 programming, which uses tile movement. Thus, you cannot feasibly move in increments smaller than world.icon_size.

I'm not sure what you mean in your second question. At a glance it looks fine, but I don't know what helm.heading is and what result you expect.
the heading is an angle, but the object does not seem to follow the turn.

Either way, on the most simple level, how would I change the system to pixel-based rather than tile-based? I recall it being a few variables that would have to be changed to get it to work partially.
(Not mentioning the huge amount of work to make everything work well with it but still the basic switch)
In response to Laser50
atom.transform is purely visual; it has no effect on anything "physical" like movement and collisions.

In other words, step() uses global directions, so NORTH is north regardless of the mover's transform.

I have a library that provides procs to move a number of pixels. absolutepositions?tab=index

In your case, you could call Project(distance, angle):
if(helm.getspeed() <= 0)
src.transform = turn(matrix(), helm.heading)
Project(2, helm.heading)

Project() uses Translate(), which takes an (x, y) offset to move, so it would be more efficient to convert to rectangular once (every time the speed or direction changes), store those, and then call Translate() repeatedly.

A key point of this library is to preserve sub-pixel movements; which is necessary since BYOND rounds all positional values to whole integers. If you want to move 2 pixels at any angle, without sub-pixel movements, you'd end up only moving one of the 8 directions most of the time.

Also, the angle given to Project() is "degrees east of north"; i.e. clockwise degrees where 0 is north. It assumes your icon points north by default. To convert between this angle and a more mathematically standard "degrees north of east", it's simply 90 - angle:
Project(2, 90 - helm.heading) // if your icon points east by default

Of course, if you have a normalized vector pointing in the same direction as your icon, you can use Translate() and not worry about angles at all.
In response to Laser50
I recall it being a few variables that would have to be changed to get it to work partially.

When you set a movable atom's bound_x/bound_y/bound_width/bound_height/step_x/step_y to a non-multiple of world.icon_size, the world uses pixel movement.
I was aware that it was purely visual, that was the entire point, although my step function is set to north for testing purposes (I couldn't get my angletotext function to work yet), It really just was supposed to rotate the ship into the angle it is set to go.
In response to Laser50
So what results are you seeing? Have you done any debugging to figure out what angle you should be using relative to the movable atom's dir?
I've tried to work using the following code:
angle = round(angle, 45)
world << "Angle is now [angle]"
if(1 to 45)
if(56 to 90)
return EAST
if(91 to 135)
if(136 to 180)
return SOUTH
if(181 to 225)
if(226 to 270)
return WEST
if(271 to 315)
if(316 to 0)
return NORTH

to return the direction back in the right form since any type of movement only accepts actual directions and not a heading. At most I can see the object turn around, but it doesn't really turn anything other than that.

But it's probably the rounding I did that I shouldn't even be doing, or am I mistaken?
In response to Laser50
Did you read past the first sentence of my post? It's all about moving by angles instead of 8-dirs.
I actually did, but I'm not really looking to use an entire library for this one bit of code that I need to function, so I figured I'd try my best at converting the values into useable BYOND stuff but it doesn't seem keen on doing so at all.

the directions may be a bit primitive, but I suppose if it worked it didn't matter.
In response to Laser50
BYOND is one of the only engine you'll ever encounter that doesn't come with extremely simple ways to move something around by pixels instead of tiles. So, I wrote a library for it, because it's really not something that anyone should have to know how to write in order to make the simplest games.

Okay, well, the gist of moving by an (x, y) of whole integer pixels goes like this:
atom/movable/proc/WholePixelMove(x, y)
step_size = max(abs(x)), abs(y))
return Move(loc, dir, step_x + x, step_y + y)

Setting step_size ensures that a move is a slide (connected, collision detection from start to finish along the straight line as in a box-cast) instead of a jump (collision only at the end position).
The call to Move() is probably the simplest way to move by pixels.

The important part is to preserve sub-pixel movements, which is important for moving slow and precisely at any angle, not just one of the 8 dirs:
var sub_step_x = 0, sub_step_y = 0

proc/PixelMove(x, y)
var whole_x = 0, whole_y = 0
sub_step_x += x
sub_step_y += y
whole_x = round(sub_step_x, 1)
whole_y = round(sub_step_y, 1)
sub_step_x -= whole_x
sub_step_y -= whole_y
return WholePixelMove(whole_x, whole_y)

This "PixelMove" function is called "Translate" in the library. Another convenient function is"Project", which lets you move by a pixel distance and angle in degrees (clockwise):
atom/movable/proc/PixelProject(distance, angle)
return PixelMove(distance * sin(angle), distance * cos(angle))

The rest of the library is convenience functions to calculate world pixel coordinates of atoms, so that you can easily preform calculations on vectors between atoms and stuff like that. It also contains functions to set an atom's position according to would pixel coordinates. If you only use the snippets here, then that's all you're really missing out on.

I don't see why anyone wouldn't want to have these functions if they're working with pixel movement in DM. The built-in stuff is just lacking in a lot of places. You don't need to see the code like this just to be able to use a library that makes things work. You could make a game like in my "car" or "planes" demo in under an hour if you'd let yourself use what someone else wrote instead of forcing yourself to reinvent the spokes (because you didn't want the wheel just yet).