Log In  

Cart #39821 | 2017-04-22 | Code ▽ | Embed ▽ | No License

Hey all,

I was doing Ludum Dare 38 this weekend but I hated the theme and my mechanics weren't coming together so I decided to submit a mapscale function I figured out instead in case it was useful to someone.

It's basically identical to the map() function, except it takes a scale parameter also, similar to sspr (although it doesn't scale width separately from height, though you could add that with only a few quick adjustments if you wanted it). It uses sspr under the hood which is probably not super performant, but it seems to work well enough and I doubt there's a much faster way to scale a full screen worth of sprites anyways if that's what you need to do. It can be zoomed down past 1x or as high up as you want.

To try the demo just hit Z to zoom out. It does 4x,3x,2x,1x in order and then loops back to the beginning again twice as slow each loop so you can inspect how the pixels are getting smooshed if you like. It could probably be improved as when it's slow the scaling is a bit ugly, but it looks fine if you do it quickly.

Below is the code, I tried to add comments to make it a little clearer and I took as much code as I could out of the inner loop for performance. You might be able to optimize the code further, I didn't spend much time on optimization, but I think this is pretty reasonable as is. If you're scaling a full screen of sprites you probably aren't jonesing for performance anyways. I left a parameter for specifying layers but I didn't implement it, shouldn't be hard though it already pulls up the sprite id.

function ceil(num)
  return -flr(-num)

function map_scaled(cell_x,cell_y,sx,sy,cell_w,cell_h,layer,scale)
  local sprite_id
  local drawx,drawy,draww,drawh
  local spritex,spritey,spritew,spriteh
  local lcell,rcell,bcell,tcell,wcell,hcell
  local cell_x_current,cell_y_current
  for offsetx=0,flr(cell_w)+1 do
    cell_x_current = cell_x+offsetx --x pointing to current iterated cell

    -- these are the most i could move out of the y for loop
    -- makes it a bit confusing but otherwise lots of wasted calculations
    --these take into account a cell getting cut off
    lcell=max(cell_x,flr(cell_x_current)) --left bound of current cell
    rcell=min(flr(cell_x_current)+1,cell_x+cell_w) --right bound of current cell
    wcell=rcell-lcell --width of current cell
    spritew=wcell*8 --width of sprite, taking cutoff into account
    draww = wcell*scale*8 --width of rectangle to draw sprite in
    drawx=flr(sx+offsetx*8*scale)-(cell_x_current-lcell)*8*scale --x to draw rectangle at

    for offsety=0,flr(cell_h)+1 do
      cell_y_current = cell_y+offsety --y pointing to current iterated cell

      sprite_id = mget(cell_x_current,cell_y_current) --sprite id corresponding to current iterated cell

      spritex=(sprite_id%16)*8+(lcell%1)*8 --x of sprite (if the sprite gets cut off, it's the left bound of the cutoff)

      --these take into account a cell getting cut off
      bcell=max(cell_y,flr(cell_y_current)) --bottom of the cell is technically top of the screen. ie, lowest y
      tcell=min(flr(cell_y_current)+1,cell_y+cell_h) --top bound of current cell, highest y
      hcell=tcell-bcell --cell height

      spritey=flr(sprite_id/16)*8+(bcell%1)*8 --y of sprite (if it gets cut off, it's the lower y bound of the cutoff)

      spriteh=hcell*8 --height of sprite, taking cutoff into account
      drawh = hcell*scale*8 --height of rectangle to draw for current sprite
      drawy=flr(sy+offsety*8*scale)-(cell_y_current-bcell)*8*scale --y to draw rectangle at

      if draww > 0 and drawh > 0 then --skip if there's nothing to draw
        sspr(spritex,spritey,spritew,spriteh,drawx,drawy,ceil(draww),ceil(drawh)) --round width/height up so there are no gaps

Let me know if you have any questions, want me to add anything (like scaling x separately from y, implementing the layer checks, etc), or if you find it useful. Do feel free to reuse it without permission. Happy coding

P#39822 2017-04-22 13:06 ( Edited 2017-04-23 09:00)

Thank you for providing this @jcwilk

I was looking to implement something very similar myself for my current project, so this will save so much time! ;o)

PS. - Just looking at the code, are you aware of the BTNP() function? As this does the checking for pressed, and only fires on release of a button. Hope that helps & thanks again :o)

P#39838 2017-04-23 02:57 ( Edited 2017-04-23 06:57)

Oh thanks I didn't know about btnp, must have missed it in the documentation thanks!

Very glad someone found use from the function, it was a real doozey to figure out though not near as crazy as a lot of the other stuff people submit on here of course. The tricky part was making it suport non-integers when specifying the map coords so you can get partially cut off sprites. Let me know if any parts are unclear or buggy, thanks 😁

P#39845 2017-04-23 05:00 ( Edited 2017-04-23 09:00)

[Please log in to post a comment]