Log In  

Cart #shadow_178_chars-0 | 2022-02-03 | Code ▽ | Embed ▽ | Forks ▽ | License: CC4-BY-NC-SA
4

TO LOAD THIS PICO-8 CART in immediate mode, type: load #shadow_178_chars

Cart #shadow_178_chars_light-0 | 2022-02-03 | Code ▽ | Embed ▽ | Forks ▽ | License: CC4-BY-NC-SA
4

TO LOAD THIS PICO-8 CART in immediate mode, type: load #shadow_178_chars_light

Be aware the shadows and ships position can be anywhere. I just moved them in a loop in and out to demonstrate they are not at a fixed position according to their original sprite.

Hello !

As you can see from recent activity there has been some code written about shadows. Most of them make use of poke, poke4, transferring the screen to advanced memory starting at 0x8000 hex, making use of memcpy(), bit shifting numbers ... ugh !

So how did I do it old-school years ago ?

Well back on the Commodore Amiga 1000 computer I had a resolution of 320x256 pixels and a limit of 32-colors. I didn't have any fancy commands in Delphi Noetic to copy memory positions, to backup the entire screen to memory locations, or anything like that. And bit shifting numbers back then, especially a whole bunch of them, was really slow.

So what did I do ?

I sat down on paper to doodle stuff. Trying to think. I can easily darken the pixels beneath where my game sprites would be but how do I make sure I don't redarken it again later with an overlaying shadow ? So I thought I could create a table for it, and as strings were really fast in Delphi instead of numbered arrays, I used that instead.

So first I created a single string the screen size 320*256 and made it at 81920 characters containing only spaces.

scrn$=space$(81920)

Then anytime I plotted a pixel for the shadow I would change that single string character position to reflect a "."

mid$(scrn$,x+y*320+1,1)="."

This is essentially what I am doing here, changing from a NIL to a 1, and you can see even after all these years it works perfectly. And you are not limited to just shadows. You can do illumination too which is pretty cool considering how beautiful that looks in RPGs, especially torchlit rooms.

In any case for Pico-8 in only 178-characters you can definitely get both your shade and brightness on ! :)

And you can write your own color adjust table as well, 16 colors, you are not limited to mine.

Please examine the source-code as I have detailed how to use it.

Just keep in mind the following each cycle in _update() in this order:

  1. Clear the screen.
  2. Plot your map or tiles.
  3. Plot the shadows FIRST.
  4. Plot the sprites for those shadows NEXT.

And that's it ! Do this and you should have easy shadowing for any game you create.

HOPE THIS HELPS !

P#106244 2022-02-03 02:41 ( Edited 2022-02-03 17:52)

real "old school" games were wonders of memory manipulation, bit shifting and cycle optimization to draw anything on screen (up until first GPU appeared mid-90's).

your technique is fine for entry level experiments (and that's good) but eats a fair chunk of the cpu budget.

P#106278 2022-02-03 22:06
:: dw817

Hi @freds72, thanks !

Yet I couldn't do memory moves and swaps in DELPHI Basic. I was limited to what I had. And I guess as long as you don't see lag here then it runs fine for me.

Heck even runs fine at 60fps. Now if ZEP would pull out the limiter plug I suspect we could have THOUSANDS of sprites with shadows all moving just fine in this code. I know when I coded back in Turbo Pascal with a resolution of 320x200 and 256-colors, it was so frigging fast I could update every single pixel at 240fps and that was on a slow computer.

Cart #shadow_178_chars_60fps-0 | 2022-02-03 | Code ▽ | Embed ▽ | Forks ▽ | License: CC4-BY-NC-SA

I wanted it mostly for myself to draw "light" around objects like you might see in a RPG and even in RPG Maker I never saw more than 5 lights on the screen at a time, and they were stationary.

I can look at your code adjust again from @kevinthompson, but I don't understand it. You don't leave remarks for every line like I do sometimes. And I can take that one-line function Shadow of mine and break it out so it's perfectly understandable with remarks for every line. I was going for brevity tho.

-- my nifty shadow drawing
-- routine! 178-chars!
-- not really since i made it
-- bigger here.
-- x+y = pos to draw shadow
-- a+b = sprite top-left x+y
-- h+v = size of sprite x+y
-- uses _shadow{} for colors
function drawshadow(x,y,a,b,h,v)

-- needed so we don't repeat
-- calculations more than once.
-- good for tweets and small
-- code.
local c,d,e

-- loop entire size of sprite.
  for i=0,v-1 do 
    for j=0,h-1 do

-- set c to screen pos x+scan
-- and remove floating point.
      c=j+x\1

-- set d to screen pos y+scan
-- and remove floating point.
      d=i+y\1

-- calculate x*y on screen to
-- single # for marker array.
      e=c+d*128

-- if there's a pixel here in
-- the spritesheet =and= it
-- has not been flagged that
-- this pixel was draw on the
-- screen then do following>>
      if sget(a+j,b+i)>0 and _scrn[e]!=1 then

-- plot pixel on screen using
-- shadow{} as the color set.
        pset(c,d,_shadow[pget(c,d)])

-- mark this pixel location
-- has now been shaded - it
-- won't be shaded again until
-- we rerun _update().
        _scrn[e]=1

      end
    end
  end
end
-- done !

Freds if you can write your code out like this, where everything is explained, I might be able to understand it better - others might too.

P#106279 2022-02-03 22:40

[Please log in to post a comment]

Follow Lexaloffle:        
Generated 2022-09-26 00:10:09 | 0.026s | Q:21