Jump to content
IGNORED

Wen hop? The Search for Planet X


Andrew Davie

Recommended Posts

Here's a new binary (Stella only, for now) with zooming/scanline, and a bunch of planets.

Use hold-SELECT to switch to next planet.  LEFT/RIGHT to change rotation speed.  UP/DOWN to zoom in and out.

 

 

So, how is it done?

 

Well firstly, it uses the engine that I'd previously shown - that one for drawing the Wen Hop game screen with all the flashy character animations and scrolling. It's exactly the same to start with - a "level" is unpacked to a screen buffer which is just a bunch of character #s used to define that screen. Whereas the wenhop playfield was 40 x 24 characters, with a scrolling 10 x 8 (ish) window viewport onto that, for the planets we have a 40 x 12 character area with a scrolling 10 x 12 (invisible) window onto that.  I copy the leftmost 10 character columns to column 30 onwards, so I get a "wrap-around" in terms of when I'm scrolling into that 40 x 12 area.

 

So now I have the planet texture unpacked into that 40x12 area ("the board") it behaves exactly as for WenHop itself.  That is, all the objects on the board animate and are processed, participate in collisions etc.  This is why you see dogecoin on some of the planets as they rotate, and the dogecoin are animating. It's just the original system in action.

 

So the "texture" is the same as the original WenHop screen that you play on, in technical terms. But in this case, it's hidden and just used as source data. So, based on the X scroll, I first "draw" the texture as a 10x12 window into that 40x12 "board" representing the planet surface. It's a rectangular, flat, scrolling window.

 

The next part is wrapping that texture onto the surface of a sphere. So, for this I wrote a small python utiltiy to generate some mathematically correct data.  All it is really doing is rendering a selected subsection of the rectangular texture map and showing it on the screen. That sounds difficult, but the technique is quite straightforward.

 

Let's cover verticals, first.  If you think about a sphere, and as you step down each scanline in a sphere, then the textured surface wraps around - of course. But the mapping of the scanline position to the texture pixel is actually quite straightforward. On a line-by-line basis, we know that ALL pixels on the line come from the same horizontal line in the texture map. So the real task here is just to find which horizontal line of the texture we're looking at, for each scanline. It comes down to some simple trigonometry; based on the curve of a sphere we can use pythagoras and trig to figure out the distance down from the top of the texture. That's done for each scanline, and so we effectively now ONLY display those texture lines which each scanline points to. And with that, we how have a horizontal cylinder onscreen.

 

Now it gets tricky. But not too much more so. The screen is drawn in two halves (left/right).  Each half is effectively a mirror in terms of the calculations, but with just a different texture offset (mirrored). So we'll look at only the right-side.  Now the earlier scrolling code took the rendered window-into-the-board to create the correct PF0 PF1 PF2 bytes.  In the planet code this is done slightly differently.  Rather than unpacking the potential 6 characters (catering for scroll) that we might see in this half, and copying 20 of those 24 pixels (with scroll 0..3 dropping off some) directly to the PF bytes (taking account of the weird PF format)... instead we only copy SOME of those 20 pixels. Consider the texture itself being a whole screen wide (i.e., 40 pixels for the sphere). We want to wrap this rendered 40 pixels onto the sphere itself, which varies in width from maybe 0 up to 30 or so pixels.  In other words, SOME of those pixels need to be used, and some discarded.

 

So, for each scanline I first calculate the width (in screen pixels) of that half of the scanline from the center. I know that I need to map those 20 pixels of the texture into that many pixels in the final screen display, and I'll have wrapped the texture around the sphere - for that line.  Trigonometry comes to the rescue again, and if you consider a single scanline half, but instead of looking head-on, we look top-down at it. We see half a hemisphere, i.e., a 90 degree sweep across the sphere. And we know that the 20 pixels of the texture map evenly onto the curved outer edge of that half-hemisphere.  So if for each pixel onscreen we know where it intersects that curved outer edge, we get a distance (horizontally) into the texture/surface map. We already know the line, from the vertical calcs, so now we are just getting the correct pixel in that line.

 

So, the python program aforementioned also creates a table for each scanline which is effectively a mask. It starts from the center, and specifies on/off for 20 bits horizontally. If a bit is ON, then we add a pixel from the texture. If OFF, then we skip that pixel.  And so, we get an effective gradated selection of pixels being dense towards center-screen, and sparser as it gets to the edge.

 

Put these two together - first the wrapping to a horizontal cylinder as described, and then on each line of that cylinder wrapping around a vertical cylinder (effectively) we get the combined effect of the both of them together forming a sphere. So, horizontal cylinder x vertical cylinder = sphere, I guess :). Anyway, that's how I did it. The actual calculations on the ARM are simple enough that i can scroll/animate/render the entire planet every single frame.

 

The rotation is achieved simply by scrolling over the original board, and letting the draw system draw from a window into the (wrapped) board as described earlier. When the scroll position becomes < 0 then I just flip it to the right edge (30). When it goes past the right edge, I flip it to the left edge (0).  It's seamless because earlier I'd copied the left 10 character columns to the right side.

 

To add to the explanation above, the scaling is achieved by first doing all of the above, but then after we've wrapped the texture onto each scanline half we post-process those 20 pixels with a simple linear scale.  Step through the pixels not one-by one, but by a scale factor and generate a new 20 pixels to use instead.  Similarly for the scanline->texture masking. So the joystick now controls a simple scale/multiplier and thus you get your zooming.

 

The principle here, in the whole engine basically, is to build layer upon layer of capability and use those to abstract away the hardware and difficult things by writing engines/systems, and then work at a higher level which is simpler and more capable.

 

 

WENHOP20210811b.bin

  • Like 10
Link to comment
Share on other sites

On 8/5/2021 at 5:56 PM, Andrew Davie said:

It uses the CDFJ bankswitch scheme that is supported already by emulators such as Stella and Gopher2600.  Gopher2600 is the more accurate in terms of timing, and perhaps in terms of hardware emulation too.  But they are both excellent and suitable for playing/testing CDFJ games. 

As a third choice, 6502.ts works fine, too (it does not emulate ARM cycles, though)

Link to comment
Share on other sites

I've made a start at tying the player sprite to the background. This is rudimentary stuff right now - in fact all it's doing is checking the character the player is over, and then 1) moving down if it's blank, otherwise moving up.  That's it. In the video all I am doing is moving left or right, and we see very rudimentary falling, and positioning upwards when "in something".  It's doing OK for such a simple start. The scroll is locking nicely to the player position, too. Bonus crash at the end!

 

 

  • Like 4
Link to comment
Share on other sites

4 hours ago, Bomberman94 said:

Any plans for a demo for „the real machine“ - maybe a PAL60 version, too? ?

Yes, sometime soon. The planet spinner works on the real thing now. I want to get some gameplay going before releasing a demo for that. But it's really close and although it might jump occasionally because the timing isn't as refined as it needs to be, the fundamentals are working fine on hardware now. I have long-term plans for PAL, but that will be late in the piece.

  • Like 2
Link to comment
Share on other sites

Hi Andrew,

 

Your planet-spin demo had me thinking:

  • is it possible to have a planet scroll up/down besides left/right?
  • does the background have to be black, or could it be another solid color, or even a textured background?

The reason I ask-- there may be some simple mechanics here that could make for an interesting "roll the ball" kind of game.  Since Playfield is a bit tedious to scroll sideways, I was thinking it might be interesting to try a simple vertical scroller, where the ball "rolls".  It rolls over certain power-ups, it gets bigger or smaller.  The ball could get smaller to fall into holes/tubes and pop out the other side, and get bigger to "climb over" walls.  Before thinking about it too hard though, I thought I'd see if any of the above is possible with the current engine idea.

 

Great demos so far, btw!

 

 

  • Like 1
Link to comment
Share on other sites

9 hours ago, Propane13 said:

is it possible to have a planet scroll up/down besides left/right?

More difficult because of the axis of spin. It's possible, but not with my current code.  The math is slightly different. Remember I'm just effectively "drawing" into a bitmap, so just about anything is possible if you can figure out the math and make it fast enough.

 

9 hours ago, Propane13 said:
  • does the background have to be black, or could it be another solid color, or even a textured background?

The background can be textured, with some minor modifications to the existing code

 

9 hours ago, Propane13 said:

The reason I ask-- there may be some simple mechanics here that could make for an interesting "roll the ball" kind of game.  Since Playfield is a bit tedious to scroll sideways, I was thinking it might be interesting to try a simple vertical scroller, where the ball "rolls".  It rolls over certain power-ups, it gets bigger or smaller.  The ball could get smaller to fall into holes/tubes and pop out the other side, and get bigger to "climb over" walls.  Before thinking about it too hard though, I thought I'd see if any of the above is possible with the current engine idea.

Well, sideways scrolling isn't tedious anymore with CDFJ.  It's pretty straightforward, actually.  I'd encourage you to pick up @SpiceWare's demo code and go from there.  Takes a little while to wrap your head around it, but worth the effort. I think my coding-head is wired differently because both that code, and some of the other code I've worked with recently (e.g., PlusCart) are just different to how I do stuff. Not wrong, just very different architecturally.

 

9 hours ago, Propane13 said:

Great demos so far, btw!

TY, it's been fun.

 

 

 

  • Like 1
Link to comment
Share on other sites

  • 1 month later...
3 hours ago, Bomberman94 said:

any news about your fantastic tech demos - maybe a bin file for the „real thing“ and (let me dream) a PAL60 version? ?

I will come back to this sometime; I think it has a lot of potential and was fun.

But for the short/medium term I will probably not be working on it; I have studies which should be taking up my time for the foreseeable future.

 

  • Like 1
Link to comment
Share on other sites

  • 1 month later...

I've had a bit of a play with this as I'm between other things that were taking my time.

 

Here I'm playing with rock/boulder mechanics. In the earlier iterations, the board was scanned top-to-bottom. That meant that if a rock decided it was going to fall, then it could move straight away, but the rock above it (if any) would not start falling until the next frame, and the rock above that would not fall until the frame after that. So the rocks got rather separated. I'm working towards allowing whole columns of rock to fall as a unit. Actually I want this so that I can have solid objects of arbitrary size that behave as "units" and will all fall as one "thing" without me having to do any work at all to make that happen.

 

So, to get that to happen, I changed the board scan to work bottom-to-top.  Now, when a rock sees it can fall, it moves down, and leaves a gap. The rock above it will, when its row is processed, see the gap, and also move down. So All movement in any column should happen at the same time. This video shows it partially working. Definitely areas where it's definitely working, but also areas I'm not-so-sure about. It's hard to see for sure.

 

As the rocks fall and land next to other rocks, they "merge" to form a solid rock mass.  I'm still deciding on exactly how the mechanics work for that, as I want passageways defined by rocks, through which you move. But I also want large sections of overhangs to be able to break off and fall by themselves. So, that's to come.

 

For now, though, I'm just re-familiarising myself with the code and learning how it all works.

 

 

  • Like 1
Link to comment
Share on other sites

One of the things that's happening there is that when rocks fall, they don't have the "cohesion"/joins with adjacent rocks, so they appear separate. This may be a gotcha peculiar to rocks. Other things falling will not separate like that because they don't dynamically "join" to other things. I may have to rethink all this; perhaps this is as good as it gets.

 

Link to comment
Share on other sites

I have worked out a way to get the rock conglomeration happening "instantly" instead of next-frame, and so blocks of objects (in any column) now look as one larger rock. Also, individual rock behaviour is still working properly, so I'm now happy enough with the basics here (visually). Not sure if/how I'll use it in the game; perhaps when time expires everything just falls in a heap. Dunno.  Anyhow, here's the improved visuals...

 

 

  • Like 5
Link to comment
Share on other sites

  • 2 weeks later...

Had a little play with some of the code today and cleaned up a few things.

I am working on the "eggs" which are no longer eggs, because they looked more like little worms/bugs.

So, in this video if you look at the wormy-things (wiggling white dots) - they now "eat" dirt. They also multiply. So, there's a balance between them growing/expanding into dirt areas, and them dying, and turning to dust. I see these as a potential tool/obstacle to assist with opening up areas of dirt for Mellon to move into. It seems to work OK, so I'll put this into the toolkit for gameplay use later on. Still very up in the air about all of this... rather disillusioned with everything Atari at the moment.

 

 

WENHOP20211121.bin

 

Hold F1 or F2 (reset/select) for screen restart.

Brief tap of SPACE (fire) toggles to overview screen and back

 

Edited by Andrew Davie
  • Like 6
Link to comment
Share on other sites

Sometimes I forget some of the cool things. Look at that awesome smooth horizontal scroll, colour playfield, animations.... never would have thought it possible, even with hardware assist. And so much going on.  Let's not forget the rotating texture-mapped planets. The circular wipe/fade.... Hope one day I can turn it into a game.

  • Like 8
Link to comment
Share on other sites

3 hours ago, Andrew Davie said:

Still very up in the air about all of this... rather disillusioned with everything Atari at the moment.

 

For what it's worth, I really like enjoy following this thread and its updates when they occur.  If the disillusionment is about the recent news where Atari is releasing "3 classics from 1983" and doing kind of a terrible job of it-- well, that isn't really Atari anymore from my perspective.  They're long gone, but I consider this community to be the real heart of Atari.  It's here where people are pushing hardware, communicating, teaching, and overall just keeping the spirit of things alive.  I hope you keep on going; this is always fun to check in on whenever news occurs.  And, I hope there's some new ship animations in the future-- those look FANTASTIC.

  • Like 1
Link to comment
Share on other sites

  • 2 months later...

With the amazing new code profiling available in @JetSetIlly's awesome Gopher emulator, I revisited the spinning planet code. Previously this was just too computationally intensive to run on real hardware - and relied on emulators giving the ARM a bit more leeway than it really had.  However, with the profiler (which basically tells you what proportion of time is spent in each part of your code), I was able to identify those areas needing optimisation.  Not only does Gopher do this for you as your program is running, it provides a list of profiled lines of code which link you directly back to the C source-code so you can see exactly where the time is going. Anyway, I profiled the spinning planets, made some changes, and now it runs on hardware!  The video shows a quick edit/build/run/profile/edit/build/run cycle, followed by footage on actual hardware as proof. 
Amazing, the quality of the tools we have these days...
 

 

  • Like 8
Link to comment
Share on other sites

This "spinning globe" demo uses some pretty tight code to enable it to run on a '2600 machine using CDFJ bankswitching. Previous versions had a bit of an odd transition along the vertical center-line. Textures seemed to "grab" and swipe past that center in a way that was not "convincing". Well, I figured the issue - as the screen is drawn in two halves, each half starting at the center and going to the edge... I started each at the same pixel. Technically this is correct for the exact center - but I realised that each playfield pixel is centered 0.5 pixels from that center, not at the left/right edge of the pixel. So, a bit of half-pixel shifting in my mathematics and voila! What you're looking at - it's subtle - is when things rotate past that vertical centerline of the screen... is the texture "locked" convincingly to the sphere.
 

 

 


Another interesting thing to look for in these demos - any individual frame looks pretty crappy... but as soon as the rotation hits a certain threshold, the eye sees the object with much more clarity. An example - as the earth spins, those "grid" longitude lines are actually flickering (badly) on/off. But at a certain speed they start to look like always-on, much thinner lines. It works.
 

  • Like 10
  • Thanks 1
Link to comment
Share on other sites

I have the spinning planet demo stable enough, I hope, to release a binary for NTSC users.

Many thanks and kudos to @JetSetIlly for assistance in profiling, optimising, bug finding, and particularly for the amazing Gopher2600 emulator!
RESET takes it back to the start planet

SELECT switches to next planet

If you just leave it onscreen, it will cycle through the planets slowly.

UP/DOWN will move the planet closer or further away

LEFT/RIGHT changes the spin speed

 

Edit: forgot to mention - this should run OK on hardware

 

 

spinningGlobes20220209.bin

Edited by Andrew Davie
  • Like 5
Link to comment
Share on other sites

The textured surface of each planet is made up of a bitmap which is unpacked from a character map.  That is, the texture is defined as an array of characters, and there is a separate character set. Each character in that set is 4 pixels across by 8 (ChronoColour) pixels deep.  This is a relatively fast to draw/unpack, and a somewhat efficient way to reduce ROM requirements.  The textures so far have been built "manually" by just using a generic character set (solid 4x24 blocks, or blocks with very minor patterning) and a character map with very basic things drawn using those generic characters.  For example, a block of random stuff, a "crater", horizontal, diagonal, and vertical lines.  These are sufficient to get the current planet set done.

But it does give a false-impression of the capabilities and resolution of the graphics. Because the current planets use generic "building blocks", that is the perceived resolution of the surfaces of the planets as they spin.  That is we see the resolution at the level of those blocks.  Groups of 4 pixels (nearly) always the same colour (horizontally) and 8 (vertically) then these are mapped onto the screen pixels.  But actually, with a decent conversion tool, we can have a custom character set which more closely reflects the source texture graphics.  That is, rather than using generic "blocks", we can have characters in the charset that specifically represent the area(s) where they are used.  In other words, the resolution achievable is 4 x 8 (=32) times greater than seen here. In reality, because of the curvature, it won't be that much.  But it will possibly be at least 10x higher in terms of resolution.  I think the thing to watch will be the Earth map, which is recognisable but "chunky" at the moment.  I'll use that as a yardstick for measuring improvements.

 

91115746_ScreenShot2022-02-11at1_12_17am.thumb.png.17f3cf141415312e131ae9364ecdd2d2.png

 

 

  • Like 5
Link to comment
Share on other sites

Looks fantastic!  Really neat that it works on real hardware.

 

Is there any leeway / time to be able to draw a player graphic and also potentially a missile graphic?  If so, I could envision taking what you've done and making a really simple breakout-like game where you can move rotationally around the spinning planet and destroy chunks of it with a ball.  Back in the day, a homebrewer was working on a game of circular breakout called "The Core" (https://web.archive.org/web/20000709161608/http://www.plethora.net/~paulo/thecore.html), and your demo reminded me of that.

 

I assume the definition / rendering for the globes have to be done in advance, or does it happen on-the-fly?  i.e. could you put a hole in a globe during gameplay and have it render the change?

 

Just thinking about possibilities...

Link to comment
Share on other sites

19 hours ago, Propane13 said:

Is there any leeway / time to be able to draw a player graphic and also potentially a missile graphic?

Yes,  both players are already being drawn - just blank. There are 10 cycles left in the kernel to implement other things.

 

Quote

I remember the Core well :)

Somewhere buried on my old hard drives I will have a screenshot of it. Can still see it in my mind.

 

Quote

I assume the definition / rendering for the globes have to be done in advance, or does it happen on-the-fly?  i.e. could you put a hole in a globe during gameplay and have it render the change?

Rendering is done on-the-fly. Sort of.  You have a bitmap of the texture.  The whole texture is unpacked to RAM before the globe spinning code.  It's a one-off, in other words. Once you are spinning the globe, the code reads the correct pixels to draw from the texture bitmap. On-the-fly.  So if you want to also make on-the-fly adjustments to the texture - yes, no problems, you can put a hole in the globe during gameplay.  Very easy. There aren't a lot of cycles to play with to do that, but sufficient, I think, to do real-time damage/modifications on the spinning globe.

 

 

 

 

 

Edited by Andrew Davie
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...