Pokitto is on the way, what games should I make?

giphy

4 Likes

why?
i thought you where doing something like this using the 16bit sprites and drawing them with index to the 256 buffer having like a 16 palet of 16 colors (could fit in 1 aditional pallet cuz black isnt changing color)
palletselect
rough mockup of what that could look like

Yeah, that would work – I didn’t want to bother with palettes I guess. My sprites and textures take twice as much space now, but it’s not an issue for me. If anyone wants to make a game out of the demo, it shouldn’t be that hard to switch to palettes – just change a few things in the drawing code.

Now I am basically conveniently working with normal RGB model everywhere, except it gets rounded to one of the 256 colors.

oh wow your converting rgb every pixel?
seriusly would recomend using something i showed as it gives you 16 levels of depth i guess

if your internaly using rgb you could just remove the buffer and just go for a 565 (16bit) array as a scanline and draw more directly to the screen since the back and forth is your bottleneck then im asuming

Well I’ve been careful not to create bottlenecks there. I’m doing it like this:

  • I have a general 256 color palette loaded.
  • I have a hopefully fast function rgbToIndex to which you hand R (3 bit), G (3 bit) and B (2 bit) and that gives you back the index of the palette color. The 8bit index corresponds to RGB like this: RRRGGGBB. So you can get RGB from the index and vice versa.
  • I call that function as sparsely as possible. Anytime I can precompute the color index I do. But sometimes I have to call that conversion function, e.g. if I want to darken a pixel due to fog etc.
  • My sprites and textures are stored in this format – i.e. 1 byte per pixel. I wrote a python script to convert png to this – it simply quantizes each of the RGB component to 3/3/2 bits, so it gives the closest color from the palette.

Okay, isn’t it?

1 Like

i see, its an interesting solution but i find it be better if you persui this to use 16bit color over the 8bit as there would be no lose or “color crunching” since in the end your converting 332 to 565

if you want more speed, going with the 16 color sprites as most games are using and setting up the precalculated depth color its just a bitchift and a multiply to to copy it on the buffer (if flash memory isnt a concern you could use 1byte per sprite but still limit the colors to 16 or 32 to have ether a depth of 16 or 8 respectivly)

(sorry if i dont make sence here but i do think these are sound solutions)
what is the depth level right now?

1 Like

I’ve kind of finished the third demo, so tomorrow I’ll look at optimizations :slight_smile:

out12

Sorry, I don’t get this – you mean 1 byte per pixel, right? What do you mean by depth then?

3 Likes

That looks amazing and fun haha I’m picturing world building on such a small device

(By the way, Minecraft added “recently” a feature that auto jump in front of a block that can be jumped onto, in order to ease moving around, especially for the Pocket Edition.)

2 Likes

you can use a 256 sprite but only use the first 16 or 3 number , its a bit of a wais on memory but makes an easyer copy since the color depth (discance from camera) is then just a multiple of 16 these are pre set color pallet with darke and darker version of that color. so theres no rgb converting at all

on the minecraft/block game i see it cant realy be voxels due so its more of a blocky hightmap, think a sort of maze builder/ fps dungeon builder seems like something cool this could turn into or just a on device level editor :stuck_out_tongue:

Are you thinking of generating terrain on the fly or once at startup?

I was going to suggest the diamond-square algorithm but I see @jonne beat me to it :P

Using brads for angles and using fixed points…

Neat game. It’s given me a few other ideas.

I always have more ideas than I do time to implement the ideas.
If they ever invent a cloning machine I’m first on the list,
I could do with at least three or five of me.

They use Lua. I like Lua.
It was through the Computercraft mod for Minecraft that I originally learnt Lua.

Commentary on their source code

The source code is surprisingly good.

Good points:

  • Uses references
  • Uses C++11 features
    • default
    • : x(x), y(y) style constructors (I forget the name for that)
  • const correct

Bad points:

  • Still uses raw pointers instead of smart pointers
  • Using pointers for out params instead of references
  • Not checking for nullptr when using out params
  • They swallow exceptions in places
  • Allocating objects on the heap and then returning the pointers to those heap objects
  • Use of the m_ convention
  • Brace style :P

I actually prefer the creative aspect of Minecraft to the survival aspect.
Some survival games I like, but I’ve always found the survival aspect of Minecraft to be less appealing (perhaps partly because I often play alone rather than in a group).

Once upon a time I was planning to use adventure mode combined with command blocks and the new functions feature to create a kind of adventure story, but I never got round to it because of the amount of work involved.

2 Likes

Today I’ve got two fun updates:

  • I experienced an accidental feature when trying to create a flyby camera intro screen for the Minecraft. The camera in the menu is really a player because in my simple world they are the same thing, and since I forgot to reinit the position of the player/camera after the start is pressed, the player is spawned right where the camera is flying at the moment, which ended up being an awesome way to start the game – looks cool and you can choose different spots to start at :smiley:
    1
  • Since I want my library to be generally usable on different platforms, I tried porting it to SDL. It was surprisingly easy, here is what it looks like (just quickly bundled together, haven’t done any PC specific tuning except for increasing view distance and resolution):
    https://peertube.mastodon.host/videos/watch/ab581288-8a35-41df-97b0-44e9cb1bcb1b

Other than that the demos and the library are workable – I could release them. On the other hand I know about a few bugs still, so let’s see, there’s no hurry I guess.

6 Likes

Ok you definitely must do something with this. Not just demos. And the the speed you are doing all that I can’t imagine what you could do focusing on just 1 thing. ( Even though if you are a little like me, I tend to starts a lot of things and take too much time to actually finish… At least when it comes to code)

I sometimes get these manic phases when I can be super productive but I tend to burn out and not finish stuff, just as you say :slight_smile: So I have to separate my projects into smaller parts. But I’d definitely like to make a complete game as a continuation of this.

3 Likes

Any idea what licence to intend to release this under?
I’m assuming CC0?

1 Like

This whole thread is just :heart_eyes:

Amazing work :+1:

2 Likes

Yep, it’s already CC0 :slight_smile:

However while fixing some of the remaining bugs I figured I’ll have to completely rewrite the rendering function. I’ve made it a horrible mess to the point I don’t even know how it works now :open_mouth: It renders some pixels more or less than once, which is bad. I spent whole yesterday trying to fix it, but I’ll have to scratch it. Never write poor code kids :frowning: Thankfully I have it ported to SDL now which makes it much easier to debug.

2 Likes

This is precisely why I pay so much attention to formatting and naming and try not to rush development.

It’s better to take your time to write clean code than to rush to get results.

A saying I’ve become quite fond of recently is “measure twice, cut once”.

2 Likes

The main mistake I did is that I was lazy to throw away the code when I should have. Instead I started fixing special cases – I thought there would be only a few of them, which turned out to be false, but even so I should have rewritten the code better at the beginning.

Another factor is that I originally held assumptions that would later break because I started generalizing the engine. E.g. one assumption was that the horizon would always be withing the screen coordinates, which with shearing I added later may not be true. So I had to fix this with a special case… etc.

This laziness will now cost me more effort.

EDIT:

Alright, working on it right now! Man that function gonna be so nice, you’ve never seen such nicely commented function :smiley: Really, I’m very happy about it.

EDIT2:

Phew, it’s done :slight_smile:

Summary
void _columnFunction(HitResult *hits, uint16_t hitCount, uint16_t x, Ray ray)
{
  // last written Y position, can never go backwards
  int_maybe32_t fPosY = _camera.resolution.y;
  int_maybe32_t cPosY = -1;

  // world coordinates
  Unit fZ1World = _startFloorHeight;
  Unit cZ1World = _startCeilHeight;

  PixelInfo p;
  p.position.x = x;

  int_maybe32_t i;

  // we'll be simulatenously drawing the floor and the ceiling now  
  for (uint_maybe32_t j = 0; j <= hitCount; ++j)
  {                          // ^ = add extra iteration for horizon plane
    int8_t drawingHorizon = j == hitCount;

    HitResult hit;
    Unit distance;

    Unit fWallHeight, cWallHeight;
    Unit fZ2World,    cZ2World;
    Unit fZ1Screen,   cZ1Screen;
    Unit fZ2Screen,   cZ2Screen;

    if (!drawingHorizon)
    {
      hit = hits[j];
      distance = adjustDistance(hit.distance,&_camera,&ray);

      fWallHeight = _floorFunction(hit.square.x,hit.square.y);
      fZ2World = fWallHeight - _camera.height;
      fZ1Screen = _middleRow - perspectiveScale(
        (fZ1World * _camera.resolution.y) / UNITS_PER_SQUARE,distance);
      fZ2Screen = _middleRow - perspectiveScale(
        (fZ2World * _camera.resolution.y) / UNITS_PER_SQUARE,distance);

      if (_ceilFunction != 0)
      {
        cWallHeight = _ceilFunction(hit.square.x,hit.square.y);
        cZ2World = cWallHeight - _camera.height;
        cZ1Screen = _middleRow - perspectiveScale(
          (cZ1World * _camera.resolution.y) / UNITS_PER_SQUARE,distance);
        cZ2Screen = _middleRow - perspectiveScale(
          (cZ2World * _camera.resolution.y) / UNITS_PER_SQUARE,distance);
      }
    }
    else
    {
      fZ1Screen = _middleRow;
      cZ1Screen = _middleRow + 1;
    }

    Unit limit;
    Unit verticalDistance;

    #define VERTICAL_DEPTH_MULTIPLY 2

    #define drawHorizontal(pref,l1,l2,comp,inc)\
      p.depth += absVal(pref##Z1World) * VERTICAL_DEPTH_MULTIPLY;\
      limit = clamp(pref##Z1Screen,l1,l2);\
      for (i = pref##PosY inc 1; i comp##= limit; inc##inc i)\
      {\
        p.position.y = i;\
        p.depth += _horizontalDepthStep;\
        _pixelFunction(&p);\
      }\
      if (pref##PosY comp limit)\
        pref##PosY = limit;

    p.isWall = 0;
    p.isHorizon = drawingHorizon;

    // draw floor until wall
    p.isFloor = 1;
    p.depth = (_fHorizontalDepthStart - fPosY) * _horizontalDepthStep;
    drawHorizontal(f,cPosY + 1,_camera.resolution.y,>,-)
                    // ^ purposfully allow outside screen bounds here

    if (_ceilFunction != 0 || drawingHorizon)
    {
      // draw ceiling until wall
      p.isFloor = 0;
      p.depth = (cPosY - _cHorizontalDepthStart) * _horizontalDepthStep;
      drawHorizontal(c,-1,fPosY - 1,<,+)
                    // ^ purposfully allow outside screen bounds here
    }

    #undef drawHorizontal
    #undef VERTICAL_DEPTH_MULTIPLY

    if (!drawingHorizon) // don't draw walls for horizon plane
    {
      #define drawVertical(pref,l1,l2,comp,inc)\
        {\
          limit = clamp(pref##Z2Screen,l1,l2);\
          Unit wallLength = pref##Z2Screen - pref##Z1Screen - 1;\
          wallLength = wallLength != 0 ? wallLength : 1;\
          Unit wallPosition = absVal(pref##Z1Screen - pref##PosY) + 1;\
          for (i = pref##PosY inc 1; i comp##= limit; inc##inc i)\
          {\
            p.position.y = i;\
            p.hit = hit;\
            p.textureCoordY = (wallPosition * UNITS_PER_SQUARE) / wallLength; \
            wallPosition++;\
            _pixelFunction(&p);\
          }\
          if (pref##PosY comp limit)\
            pref##PosY = limit;\
          pref##Z1World = pref##Z2World; /* for the next iteration */\
        }

      p.isWall = 1;
      p.depth = distance;
      p.isFloor = 1;

      // draw floor wall

      if (fPosY > 0) // still pixels left?
      {
        p.isFloor = 1;
        drawVertical(f,cPosY + 1,_camera.resolution.y,>,-)
      }               // ^ purposfully allow outside screen bounds here

      // draw ceiling wall

      if (_ceilFunction != 0 && cPosY < _camResYLimit) // still pixels left?
      {
        p.isFloor = 0;
        drawVertical(c,-1,fPosY - 1,<,+)
      }             // ^ puposfully allow outside screen bounds here 

      #undef drawVertical
    }
  }
}
1 Like

Trying to make the library usable on 8-bit MCUs: For this I switched to smaller data types, but I got into rendering problems which I traced down to the function that computes distance – for Euclidean distance you need to square distances, but since I use small data types, these squares overflow once the distance is bigger than very small. So I started looking for approximations, and here are the results of my experiments with different metrics (PC rendered):

dist2

Think I’ll go with octagonal.

EDIT:

Actually I could generalize the formula for octagonal distance and use a more sided polygon that approximates circle instead of Euclidean distance altogether, which may be a lot faster. Since I compute distance very often, this could bump the FPS.

6 Likes

I also need to calc the distance now that i have billboard objects in 3d world. I have to sort them by distance for having the correct drawing order. Calculating x * x + y * y should be enough to get them sorted.

2 Likes