ID:112941
 
Many might not realize just how easy it is to extend the sidescroller library. I had this problem when I started, too, so I would instead override things within the library, because I just couldn't get things to work otherwise. That's not necessary, I found out. Huzzah!

The easy extensibility allows any programmer to create things such as buttons, springs, pushable blocks, and much more. I'd like to take some time to demonstrate how easy it is to create those three things.

First and foremost, I defined a /mob/mechanism type to act as a parent to all such interactable objects. This means I have to do:
mob
can_bump(atom/a)
if(istype(a,/mob/mechanism))
return a.density
return ..()

And voila, I can bump into them!

Now, I also defined a /mob/player subtype, for the actual players. I wanted to make sure players could bump into boxes and make them move. The movement itself is not all that smooth, in my opinion, and that could be improved. However, the basic 'push and move' is not difficult either:
mob
player

bump(atom/a,d)
if(istype(a,/mob/mechanism/pushable))
var/mob/m = a
m.pixel_move(vel_x*2, 0)
..(a,d)

It's probably not that smooth because I'm forcing it to use pixel_move, instead of something else. I'm still re-learning how to use the library myself.
That's all that goes into pushing objects!

Springs themselves are a bit more interesting, because they have to operate in two parts (at least, the way I set them up, they do). The actual spring is a 32x32 block which is stepped on, and there's a non-dense block right above it which does the actual 'spring' animation. Here's a larger chunk of code for springs:
mob
mechanism
spring
//these can't be dense, otherwise the player will bump into them
//these need to have a pheight of at least 1, though.
spring_pretty
icon_state="spring"
pheight=1
density=0

pheight=32
pwidth=32
density=1
icon_state="wall"

//boost is just how much of a velocity boost you get by stepping on one
var/boost = 15

stepped_on(mob/m)

//if this return isn't here, you see the spring bouncing on itself, so to speak
if(istype(m,/mob/mechanism/spring)) return

//this handles making the top spring flick it's animation
spawn for(var/atom/o in top(5))
if(istype(o,/mob/mechanism/spring))
o.icon_state="spring_pressed"
spawn(2)
o.icon_state="spring"

//I initially wanted to make it reverse your vel_y, but I found that wasn't always a good solution
if(m.vel_y && m.vel_y < 0)
m.vel_y = -m.vel_y

//so it has a default value to change your vel_y to, too
else
m.vel_y = boost


I hope the comments help. I'm still working on the whole 'being descriptive' part.

The last thing I wanted to discuss was buttons. Firstly, I defined a separate type for this, linkable, along with a few useful members:
mob
mechanism
linkable
var/mob/mechanism/linkable/linked
proc
activate(mob/m)
deactivate(mob/m)

Next, I wanted to make sure I didn't have to do a lot of work to make two objects linkable. It means the map has to be played with a bit more, but that's alright with me. I simply overrode New():
            New()
..()
for(var/mob/mechanism/linkable/o in world)
if(o!=src && o.linked == linked)
o.linked = src
linked = o

Now, you'll notice it looks for two identical linked vars. This means they can be initially set to anything, and they will adjust themselves upon being created.

A recent change to the library was modifying how stepped_on works, and adding stepping and stepped_off. This helped my implementing of buttons by a lot, as you can see here:
mob
mechanism
linkable
button
stepped_on(mob/m)
pheight=1
icon_state="button_pressed"
if(linked)
linked.activate(m)
stepped_off(mob/m)
pheight=4
icon_state="button"
if(linked)
linked.deactivate(m)

It just activates and deactivates whatever it may be linked to at the time. Really, it's that easy. All you need to do is define another subtype of /mob/mechanism/linkable, set it's activate() and deactivate() procs, and all is well!

Hopefully this helps others see just how easy this library is to work with, and perhaps encourage some new developers to try it out!
Nice post!

I think a lot of people expect the library to do everything for them and having to learn new procs (can_bump, stepped_on, etc.) seems like a nuisance. I'm not sure what the stumbling point is for most people. I've been meaning to update the DM reference pages so that users can hit F1 to get help on library-defined vars/procs, but I'm not sure if people would use that.

There are also a lot of features you can create using DM's built-in procs. A Miner Adventure uses lots of tile-based stuff (cave-ins, interaction with NPCs/objects, water, etc.). The code to interact with an NPC is something like this:

for(var/mob/npc/n in view(1,src))
n.talk(src)


And it's similar for using switches. Having pixel movement doesn't have to complicate or change everything.

About pushing boxes, I'm not sure what the best way to handle it is. It's a common enough feature that I'd like to find a better way to handle it, I'm not sure if it'd require a change to the library or not. Maybe you could make them non-bumpable (but set scaffold = 1 for them so you can stand on top of them) and each time the player moves in such a way to overlap the box, the box gets pushed in whatever direction the player is facing. This way you could move the box by the amount that the player is overlapping.
I stumbled when trying to use the bump feature...
I think one of the best features to make for a side-scroller is a rope swing; And then the second best would be curved ramps(Sort of like for a skateboard). Then you could make a full loop with that like sonic and shoot out and swing ona rope! Hahah
The rope swing is a good idea and goes way back in platformer history. As to a curved ramp, basically that sounds like a variation on the spring. Kind of like a slope that also increases y velocity.

For the pushing objects, a simple way might be:
mob
// bumping a box causes it to move in the direction you bumped it
bump(mob/box/b, d)
if(istype(b))
b.move(d)
spawn(1) b.slow_down()
..()
In response to Jmurph (#4)
Jmurph wrote:
For the pushing objects, I check for overlap and then modify vel_x based on the pushers location relative to the object. "Heavy" objects get a small boost and slow down meaning you have to keep pushing and "light" ones go sliding away!

You could also set the object's move_speed and accel vars. A light object might get an accel of 1 and a heavy object has an accel of 0.5. You just need to call the move() proc for the object you're pushing and it'll accelerate in that direction based on its accel var.