Jump to content

Andrew Davie

+AtariAge Subscriber
  • Posts

    5,982
  • Joined

  • Last visited

  • Days Won

    8

Posts posted by Andrew Davie

  1. I had a flash of inspiration and figured out a way to really smooth out the falling objects. Despite being in the fairly "clunky" grid, the falling things now look MUCH smoother and effectively hide the rather grid-like nature of the board. Compare falling objects (rocks, geodoges, doge) in this video against any previous videos.  Still a bit of work to do to make it perfect, but IMHO it gives a whole new look/feel to the falling actions.  Feels very smooth and much more "trackable" rather than things instantly "clunking" into position...

     

     

    • Like 6
  2. "Ah, my fellow sailors of the digital abyss, let this thread be a testament to the unwavering power of obsession and the depths to which it can drive mankind. Behold! The tale of a game that never found its shore, a phantom project birthed by the dreams of a naive soul, entangled in a web of mockery for two decades hence.

    As I sail these treacherous waters, I cannot help but marvel at the tempestuous nature of human folly. To witness the ebb and flow of ridicule, a perpetual dance upon the grave of a long-lost endeavor, one can almost taste the bitter irony of it all. The audacity to declare 'hard work' and 'Knight Rider' in the same breath, and yet, the audacity of others to mercilessly jest, to wield their wit like harpoons, striking at the very heart of one man's aspirations.

    In this grand spectacle, we find both tragedy and triumph entwined. The original author, forever immortalized in their earnest yet misguided pursuit, serves as a cautionary tale for those who dare to set sail on uncharted seas. And yet, in the merciless jests and unyielding mockery, we discover the resilience of the human spirit, for even in failure's wake, humor and camaraderie prevail.

    Let this thread be a reminder, my comrades, that life's tapestry is woven not only with the grand victories and heroic conquests but also with the tangled threads of our follies. From the depths of this infamous tale, we learn that laughter, even at the expense of another's dreams, can bind us together in a shared understanding of the fickle nature of ambition.

    So, let us not judge too harshly the wayward captain who set sail with dreams of Knight Rider. Instead, let us raise our tankards high, brimming with mirth and camaraderie, celebrating the endurance of this thread and the enduring spirit of humanity to laugh in the face of our own vanities. For in the vast expanse of the digital sea, amidst the relentless waves of jest and jape, we find solace, unity, and the timeless allure of a story that has become legend."
    - Capt. Ahab

     

    • Like 4
    • Haha 1
  3. If you look at the "Avg" column in this screen grab, you see performance statistics for the various functions (rows) as the game proper runs.  It's a handy tool for optimising code. In this case I can see that the basic loop which iterates over the board looking for things to do/process (e.g., rocks, geodoges, etc.) is taking about 36% of processing time. That's the bare loop - does not include actually processing those objects. So that's a fair whack right there, and where I focussed my optimisations.

     

    276031274_Screenshot2023-06-17at12_57_18pm.thumb.png.ab0a121192766deee6101417c3bef66d.png

     

    If we go back to March, it looked like this...

     

    603846545_Screenshot2023-06-17at1_03_03pm.thumb.png.0ef7db55cbfcce41a66d21bf2436a2d7.png

     

    So, I've reduced drawScreen from 48% to 36%, processBoardSquares from 28% to 25%, and grab (=grabCharacters) has increased a tiny bit. The big difference in that routine, though, is that the first figure includes the automatic "rounded corner dirt" addition, so it's doing a *whole* lot more stuff than the latter one.  

     

    If I look inside the 'grabCharacters' function I see this...

     

    1653679409_Screenshot2023-06-17at1_10_14pm.thumb.png.eddf25cfd0b855509e36c858256a64d6.png

     

    Looking at the "Avg" column we see that there are no large values there -- in other words, there's not a lot of room for optimisation. I see the source lines as well, so I see that 'if (Animate[type])' is using 1.21% of total processing time. That's a LOT for a single tiny line of code, but there it is.  What can I do to improve the speed of that code. Well, pretty much nothing I think. And this is where i have to start looking at things a different way. Rather than thinking "how can I make this code more efficient?" I start thinking "why is this code even running in the first place?".  Of course what I'm showing here is post-optimisation so I've been down that path. There's nothing I can see here which is shouting out to me "optimise me!".  Just a lot of very similar-cost lines running a LOT of times per frame.  For reference, the grabCharacters is done inside the screen draw, and it retrieves the character shapes to draw from the board (for half of one character row), builds up "corner" masks by looking at the attributes of the 4 (up/down/left/right) surrounding characters, and returns all that info in arrays for the actual screen draw to use.  Here's the function...

     

    void grabCharacters() {
    
        unsigned char p2;
        unsigned char type;
        unsigned char udlr;
    
        for (int col = 0; col < 5; col++) {
    
            p2 = GET(p[col]);
            type = CharToType[p2];
    
            if (Animate[type])
                img[col] = charSet[revectorChar[*Animate[type]]];
            else
                img[col] = charSet[revectorChar[p2]];
    
            if (Attribute[type] & ATT_PAD) {
    
                udlr = ((Attribute[CharToType[GET(p[col - _1ROW])]] & ATT_CORNER) >> 31) |
                       ((Attribute[CharToType[GET(p[col + 1])]] & ATT_CORNER) >> 30) |
                       ((Attribute[CharToType[GET(p[col + _1ROW])]] & ATT_CORNER) >> 29) |
                       ((Attribute[CharToType[GET(p[col - 1])]] & ATT_CORNER) >> 28);
    
                corner[col] = roundedCorner[udlr];
            }
    
            else
                corner[col] = _CHAR_BLANK;
        }
    
        p += 4;
    }

     

     

    That 'revectorChar' was the very-recent addition which allows me to have a dynamic character set and bypass the original 128 character limit. revectorChar is an array that maps from absolute character number (0...n) into a current-character-set character number (0-127).  As you may see, it involves just one lookup per character on the screen and thus turned out to be extremely inexpensive to do.

     

    So, all of this is thanks to the amazing profiler in the Gopher emulator from @JetSetIlly -- just the best tool ever, and it makes my programming/optimisation much fun. Without it I don't think much of the stuff you see in WenHop would have been possible.

     

    Just as a parting observation, the complete screen draw (which handles the horitontal/vertical scroll offsets and draws all the animating stuff and the interleaved chronocolour too... is the code below. Amazingly concise.

     

    void drawScreen() { // --> cycles 62870 (@20230616)
    
        extern int shakeX, shakeY;
        int lcount = -((scrollY + shakeY) >> 16) * 3;
    
        int subBlockPixel = (((scrollX + shakeX) & 0xFFFF) * 5) >> 16;
        int shift = 5 - subBlockPixel;
    
        int startRow = (-lcount * (0x10000 / PIECE_DEPTH)) >> 16;
        lcount += startRow * PIECE_DEPTH;
    
        int characterX = (scrollX + shakeX) >> 16;
    
        int scanline = 0;
        for (int row = startRow; scanline < SCANLINES; row++) {
    
            const int height = SCANLINES - scanline < PIECE_DEPTH ? SCANLINES - scanline : PIECE_DEPTH;
    
            p = RAM + _BOARD + row * _1ROW + characterX;
    
            for (int half = 0; half < 2; half++) {
    
                grabCharacters();
    
                unsigned char *pf0 = arenas[half] + scanline;
    
                for (int y = -lcount; y < height; y++) {
    
                    int lineColour = rollDirect[roller][y];
    
                    int px = ((unsigned int)(img[0][lineColour] | corner[0][lineColour]) << 27 >> 7) |
                             ((unsigned int)(img[1][lineColour] | corner[1][lineColour]) << 27 >> 12) |
                             ((unsigned int)(img[2][lineColour] | corner[2][lineColour]) << 27 >> 17) |
                             ((unsigned int)(img[3][lineColour] | corner[3][lineColour]) << 27 >> 22) |
                             ((unsigned int)(img[4][lineColour] | corner[4][lineColour]) << 27 >> 27);
    
                    px >>= shift;
    
                    *(pf0 + (_ARENA_SCANLINES << 1)) = reverseBits[(unsigned char)px];
                    *(pf0 + _ARENA_SCANLINES) = px >> 8;
                    *pf0++ = reverseBits[px >> 16];
                }
            }
    
            scanline += height + lcount;
            lcount = 0;
        }
    }

     

    • Thanks 2
  4. Explaining the above gave me an idea, and at the cost of a few lines of code, I've changed the character system so that I can now have 128 characters *for any planet*, but there is no longer a limit on the total number of characters.  Another way of putting that; the wyrms may not exist on "planet A" so they are simply not included in the planet A character set.  It's not quite that each planet has its own character set, but instead that there's a global (huge) pool of character shapes, and each planet may choose 128 of those to use.  So if a planet does not have crushers, then those characters used for crushers do not count towards the 128 char limit for that characterset.  It's a simple change, and appears to work -- at the cost of making the screen draw just a tad slower. Just a bit. I think it's coping OK.

    • Like 2
  5. Update on CDFJ+ conversion.  Well, I've been through multiple passes looking at the code compared to a functional CDFJ+ "minimum viable product" (which runs). But WenHop doesn't run. But, but but... fortunately the Gopher emulator (@JetSetIlly) does show in the performance tab a list of C-functions called. So I can see it actually gets to the C-code and does sensible-looking stuff. And then halts. So it's almost certainly somewhere in the return back to the 6502 code.  So I've pared it down to a minimum set of stuff that still doesn't work. That means I'm getting close, because there's not much left that can actually be going wrong still. Thank goodness for that function track provided by the profiler - without it I'd be totally clueless as to what was happening.  I'll have this sorted in a week or so, I think.

     

    • Like 1
  6. Just now, TIX said:

    I don't pretend I understand any of these funky limitations..

    I just draw pixels for fun !

     

    ... and you're good at it. To detail it a bit more clearly...  the WenHop display is formed from what is called a "character set".  This is a set of shapes of a certain size (in this case, 5 pixels across, 30 deep).  The screen is "defined" by a grid of these characters (which in this case is 40 across x 22 deep).  The actual visible part onscreen is a window onto that large 40x22 area. The screen shows 8x7 (give or take) characters.  So that large grid is simply a matrix saying which character to draw at that position in the grid. Because RAM is at a premium, I use exactly one byte per character in that matrix, to say what character should be drawn there. It's a unique ID. One byte gives us 256 different characters we can refer to.  That's 8-bits per byte, and 2^8 = 256.  Because of how the draw system works, I need to know if a character in that big grid has been processed this frame or not -- and to do that I have a single bit saying yes/no.  That bit reduces the number of bits available to say what character to draw from 8 bits... to 7 bits.  And with 7 bits we can display 2^7 = 128 different characters. So that's our limit, with this system. And I'm already using 122 of the available 128.

    Hope this is clearer. Artists need to know these things, too :)


     

    • Like 1
  7. 17 hours ago, TIX said:

     

    check the new wyrms below, they are now animated and can slither freely next to each other !

     

    new-wyrm.gif.6f26ead317beede52c4abcdde89c4fb5.gif

    ..and since you are moving to a roomier environment, they are now using 28 characters  (if I count them correctly)

    • 4 heads pieces
    • 8 tails pieces
    • 8 body pieces
    • 8 corner pieces

     

     

    TY for the graphics. I'll have a look-see when I get a chance.

    BUT, there's a bit of a misunderstanding here - just because I have more ROM space doesn't mean I can easily add more characters to the character set. Characters in the character set are defined by a 7-bit character number.  One bit is used to flag if a character has been processed or not.  So, 7 bits to give character number means I have 128 different characters total. Full stop.  Right now I'm using 122 of them.  So, at most, currently 6 free.  You've added...28... not going to happen :). Not without a significant rewrite of systems, anyway. 

     

     

     

  8. Just now, Albert said:

    I removed the bad video links, the the editor is sometimes a bit stubborn.  Usually I place the cursor after the video and then hit backspace once or twice, or try to select before and after the video, then hit backspace.

     

     ..Al

     

    TY. None of those worked. Not even marking the whole lot and delete worked. They did not want to go.

  9. This may be the last CDFJ version.  I gotta stop rearranging the deckchairs, and bite the bullet and get the CDFJ+ conversion completed.  It's almost there... I think. I've done a lot of the stuff required, but it just crashes outright.  So.  But now I've run out of space, this has become my top priority.  So I thought I'd do a bit of a longplay recording, release a final CDFJ binary, and hunker down.  Having said that, knowing me I'll put it off and keep playing with this version. But hopefully not.
     

     

    WenHop_20230612@02_03_46.bin

     

     

    • Like 3
  10. A lot of bug fixing and optimisation here. Particularly optimisation. Things are under load when there's a screenful of lava, as the lava is implemented as one of the board characters with "logic". That means that every single lava character has to be "processed", taking up precious processing time. 880 characters of time, potentially - and the game slows down. Or, it did. Now the new approach I take is to do a quick 'is it visible' test.  If we can't see a lava character, then there's not much point animating it - and thus limiting the maximum number processed per frame to 8x7 = 56 (instead of the 880 potential).  So yes, that bit of code is around 10x faster.  Given that it took around 10% of total processing time, this is effectively (give or take) a 10% speedup. That, alone.  I've done similar things elsewhere in the code.

    While I was working on the lava rejig, I also reworked the graphics.  As I program stuff, I often have other things break. Probably a sign of poor programming - but these systems are very very complex now and sometimes unexpected chains of events happen and things break. Well, the lava was broken (it should bubble in the background).  So as noted, there's a new bubble effect as shown in the video.


    I also reworked the wyrm code.  There were instances where the wyrm could get trapped and it had two tails instead of a head and a tail. Now fixed.

     

     

     

    WenHop_20230611@00_25_13.bin

    • Like 2
  11. 22 minutes ago, TIX said:

    I probably misunderstood, but why do you alter the body width ?

    I went ahead and drew a wyrm that is symmetrical vertically and horizontally,

    this wyrm uses the same number of (5x10) characters as yours, but I added 4 extra corner body pieces to ease the transition:

     

    4 head pieces

    2 body pieces

    4 corner pieces

    4 tail pieces

     

    wyrm.gif.dc9bfcaa802647cf9191d32e62a52c93.gif

     

     

     

    Thank you for working on this.  Unfortuntely it's not to spec and can't be used at this stage.  The issues;

     

    1) You have used width 5.  Yes, the *character* the wyrm is drawn with is 5x 10.  But the specifications say that the wyrm is 4 wide, and there is a blank pixel. This is because when the wyrm gets big and wraps the body around so that successive rows (or columns) have bits of the same worm (i.e., it's really long), you need to be able to have separation between those body parts.  So you can't use ALL of the character's width or height. There MUST be a space pixel.

     

    In this sample, I have taken a vertical wyrm from your animation and placed it side by side, so 4 wyrms or parts thereof, shifted up/down and it shows the problem with no blank pixel/separation - it's just a mass that has no form....

    wyrmx.jpg.20fc25fb9475ba5d5ccab0d237737695.jpg

     

    The same will apply for horizontal.  Bottom line -- you need to design the body so that there is separation. That was the reason for the blanks, as explained, and not using the full 5-pixel width.  Or if you do use 5-pixels it must be asymmetric such that characters placed side by side do not have the above issue.

     

     

     

     

     

     

     

  12. 16 minutes ago, TIX said:

    I probably misunderstood, but why do you alter the body width ?

     

    Because when the wyrm gets long and is moving horizontally we have a wide "string" of the same body character. I'm not varying the *width* but varying the *offset* of  the left edge compared to the right edge (of the horizontal body character).  So it looks like the body is undulating.  Because the tail needs to connect to this horizontal body character (with undulations, or different left/right edges if you wish), then that is important difference between a left-facing tail and a right-facing one.

    I have tried to explain this in the image.  The greenish lines show the undulation, and the vertical below that show the character boundary. So, there are three of the horizontal body chars side by side, and the body is not flat-straight -- it has those wobbles. So the left/right edge of the horizontal body is not at the same position.  That was what I was talking about in the previous post.

     

    wyrm..thumb.jpg.ffcd615f7f1c775d1e7c464841badf97.jpg

     

  13. 27 minutes ago, TIX said:

    Yay tails !!

    If you give me the "specs" of the wyrm, I'd like to give it a shot..

     

    Great, TY.

    You have 5 pixels across and 10 pixels vertically, into which to fit a tail.  Keep to only a few colours max.  Wyrm body has ...
    1) the main body colour

    2) the eye colour

    3) The highlight/"Spot" colour

    I can go beyond these but I don't get to CHOOSE the colour, as those colours come from the same colours used in the rest of the game. So if you play it, and you see a wyrm, then you get to choose from all the other colours you see on the screen for the tail - but that will change as the palette changes everytime you play.  For example, the wyrm body is the same colour as the shadow on the right side of the rock.  The eye is same colour as the pipe white.  The spot colour is the same as the geodoge middle bit.  You could use those same three, or you could use any of the others (e.g., the dirt colour, or the colour of the dots on the hub below the tap when on). or the colour of the outside shell of the geodoge.

     

    There are 4 cases = 4 characters to draw.

     

    1) body is to the left, tail extends to the right.

    2) body is to the right, tail extends to the left

    3) body is above, tail extends downwards

    4) body is below, tail extends upwards.

     

    Because the wyrm body only uses 4 pixels horizontally you must attach tail with that maximum width (this is the case #3, #4)

    The wyrm body also only uses 8 of the 10 pixels in cases #1, #2,... but a bit more complex.  If the body is to the right, tail extending left, then the wyrm body  has a blank pixel top, and another bottom.  The 8 pixels are centered in the 10-pixel vertical range.  If the body is to the left, and tail extends right, then there are 0 pixels at top blank, and two pixels at bottom blank. In other words, a 1-pixel shift upwards for body to the right of the tail. 

     

    The colours - use what colours you want, and I will shift them to their correct ones.

     

    If this isn't clear, please ask.

     

     

    • Like 1
  14. 14 hours ago, Propane13 said:

    While it's still early in the pipe-making / deleting stage of things, have you thought about limiting the amount of pipe that's available in some levels (and maybe having it quietly make a buzzing noise or something if you have used too much)?  I could see an interesting puzzle where there are multiple taps available but only a limited amount of pipe in order to solve a level, so you have to carefully decide on placements.

     

    Yes, I'll be working on the pipes sometime soon. I don't like sound as a sole indicator of things mostly because I don't really like audio cues, so there's that.  But yes, some sort of limit might be good. I have a few ideas for pipe-functions;

    1) trapping objects such as the wyrms
    2) fully-connecting areas and have them internally fill with something... for some reason.... to do something
    3) allowing you to traverse the pipes. Go in one end, come out the other.
    4) blocking other objects (such as Tanya did to stop the crushers)

    5) acting as conduits to drain water, or carry water from one area to another. Kinda problematic as water is BG so we can't really have water in multiple places. But we might have some other kind of "stuff" that is carried from A to B by pipes

    6) acting as a network with switches - you need to turn on/off the appropriate switch network to get the correct A-B connection

     

    • Like 1
  15. 9 hours ago, Yurkie said:

    This would be a good question for @Andrew Davie

     

    I guessing he could draw the screen like Wen Hop and make a very decent looking version of the game.

     

    I've had a look at a YouTube video of the arcade version.  The Wen-Hop type system could display the backgrounds reasonably, I think, but only 1/4 of the visible screen.  Each of my "characters" is 5 pixels wide x 30 scanlines deep, and visible on the screen is thus 8 wide x about 7 deep.  The arcade appears to have about 16 x 14.  So, pretty much 1/4 exactly. This means you see less of the playing area.  The major issue though is that I do not have a multi-sprite system, catering for only the one player. It would be possible to do this, but with the typical '2600 sprite limitations so there would be flicker and lack of colours.  There are only 7 colours + black available in each character, too, so getting good looking screens using my system is a black art.  I'd say it might be do-able but difficult. I'm not sure this would be the right way to go for this game.
     

    • Thanks 1
  16. 17 hours ago, TIX said:

     

    • sometimes the cogs of the grinder are in "sync" (I don't know how to better put it),

     

    Yep, I have to alternate the frames A/B/A/B when putting them next to each other. Same vertically too. Otherwise the cogs don't mesh properly. Easy problem to fix; remember all of this at the moment is just technology development, not actual screens.

     

    17 hours ago, TIX said:
    • there is no "turning the faucet on/off" animation anymore ? hit it with the pick axe was pretty cool !

     

    Agreed. Will fix.

     

     

    17 hours ago, TIX said:
    • sometimes you are using the "impatient-taping-his foot down" image.png.c3e0ac67ba281ff2e66ebb5a4a7a452f.pngframe as an in between, in my opinion it doesn't look very good, you can use the appropriate frame from the full rotate animation I have prepared.

     

    I'll look into this.

     

     

     

    17 hours ago, TIX said:
    • why the worm doesn't have a tail ? 🙃

     

     

    Because space.  But since I'm moving to a larger ROM size (CDFJ) we can fix up that and all the player animations too, maybe :P

     

    Thanks for the report.

     

     

     

    • Like 1
  17. OK, here's the new dogecoin logic.  I think it works.  Essentially you collect coin that falls on you, rather than dying.  You can still stand under a coin - it will not immediately fall into you. To get a chain of coin to start falling -- move up then down again, and all the coin above will tumble down onto you.  If you happen to trigger a falling of dogecoin, and there happens to be a rock somewhere directly above -- well you better be aware and dodge it.

     

     

     

    WenHop_20230604@16_31_37.bin

    • Like 4
  18. My build process auto-names each binary and plonks a copy in a ROMs folder.  For WenHop, the current # of binaries in that folder has just hit 7,000.

    So technically there are 7K different versions of WenHop in existence, as of writing.

  19. 7 hours ago, TIX said:

     

    or it can still fall on you but now you just collect it,

    it would be really cool to just go under a huge column of geos start a chain reaction and eat the whole bunch !

     

    The first suggestion works, and I will keep that.

    The second does not work - the reason being a chain of doge often has a rock on top.  The mechanic then is you move along left/right minding your own business and suddenly you're dead because the doge column "collapses" as each doge gets collected by falling on you, and then the rock kills you before you even know what's happening.  So I'm not doing that one!

     

     

  20. Have been thinking about the scoring for mining conglomerates.  There is actually a score multiplier there already, but it's not entirely clear when it's in operation. What I think I'll do is use something like the Fibonacci numbers to act as a score multiplier for how many dogecoins were generated in a chain reaction (1,1,2,3,5...) and display that number on the screen (e.g., 13x), perhaps under the score itself.  That will fairly rapidly count down, and it indicates the multiplier you get when you collect dogecoin.  

×
×
  • Create New...