Jump to content

johncl

Members
  • Content Count

    23
  • Joined

  • Last visited

Posts posted by johncl


  1. It wasn't until way later with machines like the Amiga you could do colour cycling by swapping palette indexes around, and ofc later with PC 256 colour palette VGA graphics. I guess some sort of colour cycling is possible on a machine like the C64, but only 3 of the colours in a multicolour sprite/character set (you have to update the character colour by writing in colour memory in order to change that). The usual way to fix it is to use rasters and just update one of the colours (not the character one though) so in that sense its basically the way the Atari 2600 would do it too. Ofc with the Amiga you had dedicated hardware that read a raster configuration (called the copper list) making these things exceptionally simple - hence all the "raster bars" (or "copper bars" as they were called) in Amiga demos. :) - Its one of those little things that made coding games and all that so much simpler on the Amiga.


  2. You've got a valid point here. If blinky is say one or two pixels away from eating Pacman and gaining, especially in "Cruise Elroy" mode, and Pacman waits until he's at the gate to make the right angle, the bounding box for Pacman will stop it's forward momentum as he turns sideways, yet the ghost's bounding box will continue to move. This results in a collision between the corner of Pacman's bounding box and the ghosts bounding box, resulting in death every time. The arcade creators probably padded a few pixels of leeway so that Pacman warps forward just far enough when rounding a corner, to prevent such collision. I don't know what the exact arcade value is, but I think 4 pixels (half a tile in the arcade) would do it. Obviously less if it were implemented in VCS port because the pixels are chunkier and wide aspect ratio.

     

    Read the Pacman Dossier web page, it really details how the arcade was coded. There is no "bounding box", Pacman and the ghosts are in one tile at a time and they move at an offset from this tile. The "bounding box" is the tile and that is used for the collision test. Furthermore pacman can corner turns meaning he moves diagonally for either 3 or 4 pixels depending on which direction he corners from, hence the ability to reach a tile faster than if he had to move all the way into a full char position before turning. Cornering is essential for any seasoned pacman player to gain a distance from the ghosts and indeed to follow any of the known patterns for maximum score.

     

    The definitive proof of this tile positioning is that pacman can in fact move straight through a ghost as the collision test is done after both pacman and the ghosts have moved, and thus enables pacman and a ghosts tile position to just miss each other at the right spot. Check out some youtube videoes of this demonstrated - although its very vell detailed in the Pacman Dossier.

    • Like 1

  3. I remember reading an interview with Miamoto on developing Super Mario Brothers. When they were ironing out the physics during development of the game, the sprites hadn't even been created yet and they were basically working to create the game with moving rectangles around on a screen. Only after they got the engine perfected, they started to add spit and polish to the colorful characters and backgrounds that eventually became Super Mario Brothers. Shows you why the game was so successful. Most designers would start out with a main character, then try and decide what kind of world to create and how he/she was to interact with the environment.

     

    It's rather common within any games programming even today to use placeholder graphics, as you can almost complete most of the major game logic before thinking about graphics. Ofc the big game projects have already tons of resources allocated to graphics and a lot of it isnt ready before very late in the development cycle so programmers have do work with placeholders for a very long time, even simple 3d primitives in complex 3d games.


  4. I don't think it's a glitch nor programmed in purposely. I think it's just the way it WAS programmed. Kind of like Mario can jump backwards in DK. I think Mario jumps before he changes direction.

     

    Most games have inherit "features" based on the order of the logic. Pacman also has the well known "feature" where you can run straight through a ghost simply because collision detection is done tile based and both pacmans and the ghosts move logic is executed before the check for a collision between pacman and the ghosts.

     

    If you want to go realism I guess Pinky and Inky should both suffer from the up vector offset bug (2 up and 2 to the left and 4 up and 4 to the left), I am sure all seasoned pacman players know about that one and use it to their fullest. :)


  5. Very nice project. Having dabbled some with a pacman clone myself, the Pac-Man Dossier is a well studied page. :)

     

    Just wondering, have you coded the angular "cornering" logic for Pacman? I always found this piece of information pretty fantastic for a game developed so early. Like being able to affect where the barrels roll down in Donkey Kong, these tidbits of code makes these games stand out from the crowd. No doubt these were also features that likely all the clones missed.


  6. Starting with how it should look when its boxed sounds like "jumping the gun" a bit. I'd say you first need to figure out what kind of game you want to do or start experimenting with some challenge. 8bit systems have some very nice challenges due to the limitation of the hardware, which also means one might even get away with sub-par graphics skills too if the game is good. The more advanced the display hardware is, the harder it is to make it look decent. A system like the Atari 2600 is extremely challenging though compared to most other later 8 bit systems. Memory constraints add to this challenge, and there are systems in the middle like an 8kb Commodore PET or a 3.5 kb Vic20 that can be good platforms too.

     

    Personally I am a Commodore 64 guy and can relate to the post by Christopher above, its littered with unfinished projects. Most of them end when the coders challenge is met in e.g. some cool display technique. To finish a whole project takes perseverance and motivation of a different kind as there surely is no money to be made on this either. So far I have only completed one C64 project, a Jetpac clone called Rocket Smash where I did a 16kb cartridge version with Saul Cross (who did graphics and music) for the last RGCD cartridge compo (we got 5th place). A fuller 64kb version with a story and digitized samples is practically finished (just need to fix some text in it now) but it took ages for me to motivate myself to really finish this in spite of a deal with RGCD to publish this on cartridge too.

     

    I have another project with Saul Cross as well that is about half finished, but again its a lot of work now left and not many big challenges left so it takes some special motivation and indeed time to commit to the last half bit of hard work. Although I know the game will probably be well liked by the community when its eventually finished - I still have a few other secret pet projects that have potential but are also daunting amount of work to get to any finished state, haha.

     

    So do not think too hard on the finished project - but enjoy the way there. :)

    • Like 1

  7. Just wanted to congratulate on a fantastic job. I am not an Atari guy really, but somehow got fascinated by the programming of this console as its a fantastic challenge. Having played some with programming for the device its certainly amazing what you have managed to push through the Stella. But I understand you also rely on some external hardware? How does that work, will making cartridges with the game be very costly?


  8. Hi, I am a Commodore collector and creator/coder of the site http://retrocollector.org where we add scans and photos as well as preserving tapes.

     

    I am seeking to complete my tapes collection which no doubt will be a seriously long mission. :)

     

    But the main wishlist of tapes is growing shorter by the year and if you have any C64 tapes for sale/trade then please do check my wishlist here:

     

    http://retro.lonningdal.net/wish.html

     

    My main focus has been tapes, but I also collect disks and cartridges. I don't have many US tapes on my wishlist yet but I know I miss a lot of e.g. Victory Software titles.

     

    Here are some examples of titles I am seeking:

     

    6293.jpg 27621.jpg 488.jpg

     

    487.jpg 24905.jpg 20210.jpg

     

    24628.jpg 29369.jpg 19031.jpg


  9. Old thread, but I just wanted to point out that indeed the C64 has a multicolor character mode where each pixel is paired with the next one effectively making chars 4x8 resolution but at double width. Which is why you see those wide pixels on many C64 games. The same thing goes for sprites. And essentially its was not a bad thing on a bad PAL/NTSC composite signal where you wouldnt be able to see the pixels that well defined anyway in the horizontal resolution.

     

    Furthermore as people have pointed out the special sprite to background priority was one of the nice features of the C64 but it had a fun little "quirk" in that both bit pairs 00 (background) and 01 (multicolor 1) was considered background, so that the sprite would be in front of these in all cases even when you set the sprite to be behind "chars". While some would "palmface" at this design constraint, games like Fist II used this to its fullest enabling the sprite to move in a charset environment with a somewhat detailed 2-colour foreground and 2-colour background imagery.

     

    However a disadvantage was that multicolour char mode had a nasty limitation, you could only use the lower 0-7 colours as character color (bit pairs 11) as the colour set for that particular character defined whether the char was in multicolor mode or standard highres. So your normally 16 char colour option was reduced to the first 8 as the 4th bit in the char colour memory decides if its multicolor or not. Its a bit tricky to understand from writing, but essentially when you set the char colour to e.g. light blue, the actual char colour would be standard blue for the bit pairs 11 in the char data. For multicolor 1 and 2 as well as the background you could select any of the 16 colours.

     

    To make matters even worse, many of the good colours were in the upper indexes 8-15: brown, light red (pink/skin colour), dark brown, 3 greys, light blue and light green. That meant if you wanted to e.g. use all 3 greys in your multicolor charset you would have to set background to dark gray, mc1 to grey and mc2 to light grey. You were then limited to the lower 8 index bog standard colours for the char colour (black,white,red,cyan,purple,green,blue,yellow).

     

    Many like to bash the muted pallette of the C64, but in my opinion one of the strengths of the C64 pallette is the many greys and "earthly colours" which makes it ideal for many games featuring some kind of nature. The nice skin colours help a bit too naturally. Save the bright colours are for spectrums and Las Vegas. :)

     

    Anyway, you can imagine the interesting challenges a C64 graphics artist is often facing when selecting colours! Lets say your game needs some trees, ah wonderful, we have two browns and two greens. Splendid! Hey wait a minute, hmmm... both browns and light greens are in the upper indexes... Dang. Ok so we need to reserve both MC1 and MC2 as well as BG for these three colours and we can use the standard green as char colour. Voila a pretty tree! Hmm, but the whole background of the game is now either light green, brown or dark brown. Oh oh I want a green grassy floor with dirt underneath, no problemo, colours are all ready to be used. Oh and I want a blue sky using both blues!... Hmmm... one blue is char colour, but the light blue is upper index colour! And my green tree cant use green char colour on the chars that are also partly sky. Dang!

     

    This is where the artist and coder has to come up with trickery to enable more colours "in the mix", and it is possible to change both MC1, MC2 as well as BG for every scanline if you so wish with some raster code. In our example, we could use the light green on the edges of the foliage of the tree with holes in them to let the blue shine through (as we have changed our char colour for those tiles from green to blue). Additionally we could change the light green MC colour to a light blue when the trunk begins to use the light blue for a sky gradient at the horizon, and then swap it back to light green when the ground begins. Now if you want rolling hills in your background scenery you would have to use char colour green on those tiles and save the light green details for when the sky is finished. Many tricks are possible with some smart use of char colour and changing them on the fly during the drawing. For C64 enthusiasts, pause the games you play and try to figure out what colours are used where for BG, MC1 and MC2 as well as char colour. Sometimes you will be surprised at what they chose. Some games have a black background, and you might immediately think, they have set the background to black, but what they often do is use char colour black and the real background colour shines through the "holes" drawn in the chars whenever needed. In most cases this is because the game required the use of 3 upper index colours.

     

    In many cases you have to make sacrifices and e.g drop one colour so that you have more freedom with the char colour to add detail. In some cases you resort to sprites for some missing details although that will again limit your use of sprites on top of the scene since there are maximum 8 on any one horizontal scanline (you can multiplex and reuse sprites on different scanline locations with some limitations). Additionally, the sprites also has a nasty limit, their multicolour indexes are shared between all sprites (much like chars but the registers are different so you can have other colours for sprites multicolours). But you are at least free to use all 16 colors as the sprite colour. Again, you can change sprite colours at any raster to get more colours here as well if the sprites are spread vertically (for SMC1 and SMC2 colours at least). Atari 2600 programmers know all about changing colours for every raster so it shouldn't be a surprise this trick is often used on the C64 too.

     

    The multicolour char and sprite modes are important features of why the C64 became so popular as it enabled a rich visual style at a time where home computers often had single colour chars and a small pallette (the Atari 2600 being an exception on the palette selection naturally, although very limiting in every other aspect of graphics). But it comes with a price as you have seen, and for the C64 graphics coder it often becomes a challenge to find the best tricks to enable as much use of the 16 colour palette as possible, much like an Atari 2600 coders challenge to squeeze as much out of every rasterline the code sets up. Both equally fun for a seasoned programmer. :)

    • Like 2

  10. Just a quick question. I felt like reinventing the wheel and doing a 6 digit score. I assumed it was done by using the two sprites next to each other, set them to repeat 3 times and then change the GRP0 and GRP1 as it draws over the screen. And I guess the idea is to use the stack register as extra storage since that only uses 2 cycles to transfer the value which is just enough to sqeeze in that last sta GRP1 to set the 6th number. But is this safe?

     

    And it works fine for me now in Stella, can I assume its working on real hardware as well? Or are there things you can do in Stella that allows TIA trickery beyond what the real hardware can do?

     

    Also one last question. Is it possible to reuse the sprites on the same raster line in any way all? (Even if I cant move it but always relative to previous location?)


  11. Btw I tried out Stay Frosty, and its a brilliant platformer with some nice challenges as you get into the game. The only thing missing from it is a level number indicator and perhaps a bonus life there now and then (perhaps there is). I love the detail and expression you have gotten into that snowman, I guess you have used the missile and ball a lot on him.

     

    I was hoping to give my hero some eyes using the ball and perhaps some other tiny details. But I dont think I have enough cycles to do that. The screen I have now looks fairly nice but with a mirrored playfield. My next challenge is to update it during draw so its asymmetrical and I need to draw one sprite as well in the same scanline but I guess I will try to use some assumptions that the next data is available always so I just pad the end of the sprite with zeros to avoid any sort of checks.

     

    At least I have seen that I need to make my kernel quite a bit larger and split the drawing up into sections since there will be whole lines where there is no playfield (but only background color and the main player sprite). These are perfect places to multiplex the other sprite.

     

    I guess I should design the game for NTSC and 192 visible lines and just have more border on the PAL versions (or extra decorations).


  12. Thank you all for the replies. Will definitely look into other ways of placing sprite. I did try that skipdraw method and it uses 22 cycles at most which is the same that my method already uses. Rewriting my code to the skipdraw gives me:

     

    		inc SPRYCNT	; 5
    	lda SPRYCNT	; 3
    	sec			; 2 
    	sbc PlayerY	; 3
    	adc #SPR_HEIGHT+1 ; 2
    	bcc skipDrawSprite; 2-3
    	tay			; 2
    	jmp drawSprite	; 3   = 22 cycles (pass through bcc)
    skipDrawSprite		
    	ldy #0			; 2
    drawSprite
    	ldx $f900,y
    	lda (SPRPTRLO),y

     

    Putting the skipDraw outside the kernal and branching back doesnt give any benefits as that would just move the jmp outside and would use 23 cycles in whenever it is being skipped.

     

    Naturally the benefit with this method is that you need to have a scanline counter which is of great use to other kernel code. I didnt have that and sorely needed one so I will probably use the skipsprite method for now.

     

    About the tip of empty scanlines thats how I intend to reuse the other sprite several times down the screen. Just afraid my kernel will grow very big. :)

     

    Edit: I see now that the cycles savings for doing the skipDraw outside the kernel is that I dont need to read the color and indirect adressing of data. Thats naturally a big saving in that case! So it seems the skipdraw will max out at 19 cycles which 3 cycles lower than what I had. Good good. :)


  13. Thanks for the tips. That mask looks interesting but how many cycles keeping it up to date ($00 or $ff I assume) during the draw?

     

    This is my sprite draw routine now:

     

    		ldy SPRYCNT
    	beq nosprite; skip when sprite has ended
    	dec SPRYPOS
    	bne nosprite; until position is at sprite y pos
    	lda #1
    	sta SPRYPOS
    	dey
    	sty SPRYCNT
    
    nosprite
    	ldx $f900,y
    	lda (SPRPTRLO),y
    
    ; --- scanline 1 - Player Sprite draw (even line)
    	sta WSYNC	  
    	sta GRP0
    	stx COLUP0

     

    The color info is at $f900 and the sprite is at $f800 and I calculate the SPRPTRLO based on which sprite to show. The whole problem is figuring when the sprite is supposed to be drawn and figure a way to know when it is finished. In my case it just fetches a the first entry (zero value) in the sprite data over and over again when the sprite counter has ended. To make sure it iterates over all bytes I need to set a #1 in the counter again so it passes through every time (all which is naturally skipped when it has reached the end). Still a lot of cycles wasted for these checks and iterations.

     

    Edit: Reading your code snippets again I now understand that the mask is a table of preceding zeroes and $ff depending on the height of the sprite and then a lot of zeroes after. And your MASK pointer is then adjusted to when it should start drawing, and your sprite pointer is also offset by the same amount. A really smart trick there yes. I guess one could sacrifice some bytes in rom for this table.


  14. Just to ask others before I try it. Is it possible to do asymetrical mirrored playfield (as in they are updated during the drawing) using PF1, PF2 and at the same time draw one sprite, and cycle background, sprite and playfield colors? Seems pretty tight...

     

    And yes Eshu, I have limited myself to PF1, PF2 only. Should be enough with a 32 bits wide area for the platforms.


  15. I like that version, nice use of LAX, but you gotta be brave and not use the temp ;)

     

        LAX word
       INX
       AND #$F0
       STA word
       TXA
       AND #$0F
       ORA word
       STA word

     

    A late reply to the starting hack of this thread. If you got a free byte of memory space and you could initialise that before the loop this should be faster:

     

    At an init stage store the top 4 bits in a variable:

     

    lda word
    and #$f0
    sta hi

     

    And in your loop when you are iterating and need the wraparound increment on lower 4 bits:

     

    ldx word ; 3
    inx	  ; 2
    txa	  ; 2
    and #$0f ; 2
    ora hi; 3
    sta word ; 3

     

    Uses a total of 15 cycles, 4 less than the one quoted assuming word and hi are in zero page. :)

     

    Well, if you can assume that your "word" variable bit 4 is always zero (so counter starts from one of $00,$20,$40,$60,$80,$a0,$c0,$e0) you could do this also:

     

    ldx word; 3
    inx	 ; 2
    txa	 ; 2
    and #$ef; 2
    sta word; 2

     

    Which is only 11 cycles! :P


  16. Hmm, seems I have met a wall here. I just cant seem to find enough cycles to do it all with a full playfield that is updated during the scanline to get different data on both sides. The problem is naturally that since the PF0,PF1,PF2 needs to be updated during the scanline you have to update them twice on every scanline. This severely limits the amount of time for anything else, and I probably have to think differently about how I iterate over the sprite data (consuming too many cycles now).


  17. Yes I know about splitting up the kernel in several "passes" and thats what I do now. One pass to change background color, one to check if sprites should be drawn, one for setting playfield data and last one for drawing alternate line of sprite. I realised that you could simplify the algorithm a bit by adding some zeros to the top and bottom of the sprite so that you could "slide" its starting position with how it aligns with the rasters that way I can advance the sprite fetch index without checking stuff on all the other raster lines since the actual start/stop of drawing would be issued at every 4th raster.

     

    However, I see that multiplexing the second sprite several times down the screen in all of this will be tough. The sprite positioning I use now (found the HMP0, HMOVE routine here) uses two WSYNC's so that ruins the sprite draw routine. One the other hand it seems the only operation it does after the second WSYNC is a sta HMOVE (and then rts) so there should be enough time to store the next sprite data immediately in GRP0. The y register is not used in the sprite positioning subroutine also so I could prefetch that data as well. Except that I also need to get the color information... hmm its going to be challenging... just as my thread title says. :)

     

    Its fun to tweak the code and try to find the most optimal way of doing stuff. Sometimes I see that using tables and indirect indexed fetches just takes too much time compared to actually doing some arithmetic work in the code also (if its simple stuff). In other cases you can often shave one or two cycles by precalculating stuff. And like with the sprites you can do things that allow your draw routine to assume it can always fetch some new data although it is fetching zeroes until its ready, so that the actual logic is only done once in a while. Many cool algorithms to be found here.

     

    And Jay Miner sure didnt make it easy for us with the playfield thing. One thing is the repeated/mirrored playfield where you have to change the data at the correct spots to get new data on the right hand, another is the rather "backwards" drawing of PF1. Its really no problem if your want to add some graphics to the screen, but if you want a sprite to interact with it, its clear your best option is to have two "versions" of the playfield data, one where the bits are correct from left to right, and another that is used for drawing the screen. Naturally you could create the other on the fly and store that in memory (whats left of it). Simply because in order to figure out where in the playfield the player is you need to rotate a masking test bit based on the X position. Another nice challenge. Btw I am making a platformer and my initial idea was to have the screen scroll, but I have chosen not do that but rather let the player move left and right to reach other screens.


  18. Hi, I have a general interest in all retro computing, and although my main focus (and collection) is Commodore 64 I read about the Atari and considering that it was out as early as 1977 with full color graphics I found the whole machine intriguing. Especially the rather complex connection between the TIA and the 6507. I have followed the excellent tutorials in this forum and thought I'd try to code something. The first plan was just to create a nice raster sky/ground and then add a sprite. This is where things get really challenging, and I see that the amount of cycles you have to do stuff is severly limited.

     

    I found a pattern though and that was to compute the data needed for the next scanline during the scanline draw so that it was simply a fetch and save into the TIA registers when its retracing for the next scanline. However even this becomes challenging simply because I only got 3 registers (A,X,Y) and these has to be used at its most optimal way so you dont end up shuffling data in and out of memory variables, as there is really no time for this. I see the outlines of serious tweaks here and there just to make things flow nicely. :)

     

    Fortunately the X position of sprites could be done e.g. during the vertical blank so the real challenge is to put non-zero data into the sprite at the right place and zero it out at the end. I've never seen such complexity just to move a sprite around, its truly challenging. I cannot imagine how I could ever multiplex sprites in y direction in all of this! And this even before I have thought about playfield data. :)


  19. Hi. This is my first post here on this forum, and this thread was one that immediately caught my interest. I have general interest in games programming, but my main retro computer is the C64. However I have always been intrigued by the first games technology and reading a book about Atari caught my interest in their first video game machine for the home, the VCS or 2600 which it eventually was called. I have no relation to this console whatsoever until I read about it and being the tech geek I am I found it interesting to read about how the TIA worked and how the code had to go "hand in hand" with that video chip. Nifty raster work is of course essential for all cool games on these computers but on the Atari 2600 there is really no option to be "lazy". :)

     

    I then started thinking about developing for this machine, since i liked the challenge, and came across batari basic which would probably be the gentlest approach. So naturally this thread caught my interest since i see the quality game that is possible using this (although I wouldnt really call it basic, but a simplified assembler language actually). The Cave In game and Steves work here is really nice to read about, and its fun to see how the development has progressed, and the fact that at one point its all about what the gameplay is supposed to be. Its a fast paced game indeed, but I think parts of it took some strange directions. I have only been playing it using the latest release of the Stella emulator and not on real hardware though. Here is a short list of things I would comment:

     

    The way you find the keys is a bit odd. I'd rather see the key in a room somewhere so I know I have picked it up. The whole bumping into walls is a bit odd to me, and I frequently forgot about it only to see that there is a key there in my inventory. It would also be cool if the key was randomly placed within certain rooms so that the replay value went up. Also, I wish there was an indication on the door which key fits where.

     

    Another cool thing would be for at least the easier levels to not respawn a mob that you have killed when you enter the room again. This enables a player to know where he has been (of course drawing a map would do the trick as well). Also you could have tried to make randomized maps as well, like Diablo, that would also increase replay value. All of these things naturally requires some nifty bitwork to save space since the amount of ram is really limited. But you know with randomly generated things you actually only need an initial seed and a function to "find the random number" based on certain parameters... just a thought.

     

    When I play it in Stella, after a while there is something happening so that my char has a jerky/lag movement although mobs always move smoothly. This happens after some minutes of play. Might be an emulator issue though.

     

    Other than that, an excellent game and I really hope you will be able to publish this with the nice label/manual artwork! Nothing more gratifying than getting your work packed and shipped. :)

×
×
  • Create New...