Old projects and ugly XP icons

Tuesday, 13th September 2005

This is going to be a very boring update, I'm afraid. I wasn't feeling too good so haven't got much done. sad.gif

First of all, Latenite updates. With the project thingummy, I thought it would be nicest if it displayed the proper Windows icons for file types rather than the ones I had hardcoded in. Here is a function I wrote to take a filename and return an icon (in the form of a .NET Bitmap) based on it and whether you requested a large or small icon.
It works by going into the registry and looking up the ".ext" key. Some keys like that contain a DefaultIcon property and a filename/index number of the icon to use, some just point at another subkey with that DefaultIcon property.
After I found that, I use the rather nasty ExtractIconEx to retrieve icon pointers from the DLL/ICO/EXE, select the one I want, copy that to an Icon (and then to a Bitmap) then clean up.
Here's a screenshot of it in action:

latenite_icons.gif

You'll notice the crud around the final icon. It seems that any XP-style icons with an alpha channel get mucked up by the ExtractIconEx ripping out the icon's data. If possible, I would force it to retrieve the 256 colour version (at 16x16, that's still a colour for every pixel!) but don't possess enough Win32 wizardry to achieve this. If anyone could help me, I'd really appreciate this.

Here is the module, in case someone finds it useful. Sorry if it appears a bit hacky, but it seems to work fine for me.

Module mdlIcons

    Private Declare Function ExtractIconEx Lib "shell32.dll" Alias "ExtractIconExA" (ByVal lpszFile As String, ByVal nIconIndex As Int32, ByRef phiconLarge As Int32, ByRef phiconSmall As Int32, ByVal nIcons As Int32) As Int32
    Private Declare Function DestroyIcon Lib "user32.dll" (ByVal hIcon As Int32) As Int32

    Function getIconFromFilename(ByVal filename As String, ByVal largeIcon As Boolean) As Bitmap

        ' Grab the extension:
        Dim getExtension() As String = filename.Split(".")

        ' Look up the file type:
        Dim searchKey As Microsoft.Win32.RegistryKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey("." & getExtension(UBound(getExtension)), False)

        ' Was anything found?
        If searchKey Is Nothing Then Return Nothing

        ' Go through until you hit the end:
        Dim getDefaultIcon As Microsoft.Win32.RegistryKey
        Do
            getDefaultIcon = searchKey.OpenSubKey("DefaultIcon", False)
            If Not (getDefaultIcon Is Nothing) Then Exit Do
            searchKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(searchKey.GetValue(""))
            If searchKey Is Nothing Then Return Nothing
        Loop

        ' Get the details:

        Dim fileDescription As String = searchKey.GetValue("")
        Dim iconPath As String = getDefaultIcon.GetValue("")

        ' Close the registry keys:

        getDefaultIcon.Close()
        searchKey.Close()

        ' Now we have that data, we need to convert a "xxxx,0" path into a "xxxx" and a "0"

        Dim getPlainIconDetails() As String = iconPath.Replace("""", "").Split(",")
        Dim iconIndex As Integer = 0
        Dim plainIconName As String = getPlainIconDetails(0)

        For i As Integer = 1 To UBound(getPlainIconDetails) - 1
            plainIconName &= "," & getPlainIconDetails(i)
        Next

        If iconPath.Replace("""", "").ToUpper.EndsWith(".ICO") Then
            If UBound(getPlainIconDetails) <> 0 Then plainIconName &= getPlainIconDetails(UBound(getPlainIconDetails))
        Else
            iconIndex = Val(getPlainIconDetails(UBound(getPlainIconDetails)))
        End If

        ' Now we have all that info, let's grab the icon:

        Dim iconLarge As Int32
        Dim iconSmall As Int32
        If (ExtractIconEx(plainIconName, iconIndex, iconLarge, iconSmall, 1) > 0) Then
            Dim iconPtr As IntPtr

            If largeIcon = True Then
                iconPtr = New IntPtr(iconLarge)
            Else
                iconPtr = New IntPtr(iconSmall)
            End If

            Dim iconRes As Icon = Icon.FromHandle(iconPtr)

            Dim returnBitmap As Bitmap = iconRes.ToBitmap
            iconRes.Dispose()
            If iconLarge <> 0 Then DestroyIcon(iconLarge)
            If iconSmall <> 0 Then DestroyIcon(iconSmall)
            Return returnBitmap
        Else
            Return Nothing
        End If

    End Function

End Module

The C# source code I saw that used the ExtractIconEx call used ExtractIconExA instead of ExtractIconEx. I thought that this meant that A = alpha, so hopefully swapped the A in but VB.NET complained with a squiggly blue line. If only Win32 was as easy as that.

As far as Fire Track itself goes, there's nothing to really show for it - if you die, the game continues for a short way (with you invisible and uncontrollable) before decrementing your lives by one and sticking you back at the zone info screen. When you press START you get stuck back in the game at your old position in the level and you start again.
As dull as that sounds, there is a lot of work going on to achieve that - namely swapping palettes and tilesets to RAM and ROM and back again as required.

big_1.png big_2.png

Here's a silly pair of screenshots. I played around with some of the more interesting VDP mode bits last night, and this is the "sprite zoom" one. By changing a couple of lines of the sprite routines with .ifdef blocks I can now set a switch in my config.inc file before compiling and all sprites are double size. Not sure why one would want to do that, but it's nice to know that the option is there.

Finally, here are some old shots I could have shown in here a while back - I thought I'd teach myself some OpenGL, what with SDL just sitting around doing nothing much for me.

landscape_01_thumb.jpg
landscape_02_thumb.jpg
landscape_03_thumb.jpg

As ever, click for bigger. Yep, it's the generic starter app of a terrain engine. (The Perlin noise for heights was new to me, I'd only used a precalculated one from Photoshop before). I couldn't quite work out how to do ambient lighting, hence the black sides to the hills. Not to mention that the tiling of the ground texture is blatently visible. The water moves up and down slowly to "wave", and the entire water texture scrolls past slowly.
I wish those shots were "real" - in face, there are two major flaws in my engine. First up is the very poor culling for terrain chunks outside the view - it's purely 2D, so looking down at the ground looks like this:

landscape_04_thumb.jpg

...which isn't quite right. I also had to tweak the LOD calculation for the above shots - here it is with the LOD tuned the other way;

landscape_05_thumb.jpg

Lots of nasty holes. I couldn't quite work out the skirting myself, so consigned the project to the bins once again (as I do with about 49 out of 50 projects). It runs at ~150FPS in debug mode, which is something to be pleased with I suppose.

I will release Fire Track, though. I hope. If someone could help with the music.

Lost projects... now there's an idea for a Lounge thread. I think I'll spare that by posting a few in my journal instead. Some of these started out as Really Good Ideas at 3AM when I couldn't sleep, but never seemed to get anywhere:

album_art.png
Album Art Viewer - for those covers that Windows Media Player displays, which Windows Explorer hides.

wad_reader_thumb.png
WAD Reader - DOOM WADfile reader/viewer. Has support for all graphics ("pictures" and raw flats), DOS end screens, PC speaker sound effects. Can view pictures in special viewer where you can rotate the sprites or watch their animations (it has to guess a lot, so that's not perfect). Can export all lumps as raw data or convert to PNG (graphics) or RTF (DOS end screens). Can also play the PC speaker (not wave) sound effects if your PC has a PC speaker on the motherboard. VB.NET, but quite fast. Full screen pictures take about 2 seconds to render as properly, though. However, once rendered all are cached internally for instant retrieval.

lemming_syndrome.jpg
Lemming Syndrome
- (click to download 194KB file, requires .NET runtimes) - wow! I forgot about this one. It was meant to be for the 1W1B contest - a challenge to work on a game for one week, with the requirement that you only used one button to control it. So, er, try and bounce me over the river in your lifeboat. There is no "game", as such, (unfinished), so it'll go on for ever.

mysql_manager_thumb.png
MySQL Manager - I was feeling cheap and my trial to MySQL-Front was about to expire, so I started work on a MySQL clienty thing. It's massively faster at downloading/displaying data, but that's about all it actually does after I decided it was too much hassle to try and recreate a full tool, so I forked out for a license of MySQL-Front instead. rolleyes.gif

Anyway, this is scaring me, I just found a garishly coloured TETRIS.EXE that I swear I never wrote, but the code style is mine and it has my name on it, so I guess I actually did... I have been feeling a bit ropey for the last year-and-a-bit, so I guess it slipped my radar. Or I wrote it in my sleep. Or something. Just be glad I don't have an internet connection myself and have to rely on one at work, so you're safe from me posting in my sleep! grin.gif

On the merits of Excel and running out of space

Monday, 12th September 2005

video.jpg
Latest video. [2.29MB AVI]

You chaps probably don't know what a major headache it is trying to get clear, non-wobbly video... rolleyes.gif

taking_video.jpg

I gave up in the end and went for the "propped-up against a wall with camera on stack of books" approach. The reason I cannot, therefore, appear to play the game very well is because I cannot see the screen. All I can see is a faint, inverted glow and have to guess where I am. Not fun.

Here are the major updates since last time:

  • Removed Blackadder theme rolleyes.gif
  • Altered colour contrast on title screen, added wipe to clear it in imitation of original, restructured code for better fades, changed timing, added sound. Title screen is now complete.
  • Rewrote entire code for checking bullet collisions with buildings on the ground from scratch. It now works perfectly.
  • Levels now "start" correctly, so the ship moves in from the bottom, the start platform moves towards you very fast until they are in the correct positions, at which point gameplay commences (much smoother than just dumping you at the start position with a full level already there).
  • All levels now mapped correctly, in order, with correct palettes for backgrounds AND sprites. Levels that end a zone with a platform rather than with the face are flagged as such and the correct end is substituted in now.
  • Each level can be pointed at a 'replacements' table, which lists "replace tile X with tile Y". Tiles are swapped around properly so that levels appear more varied.
  • Explosions are now fully implemented (2 kinds, background and foreground - with very slightly different animations) and working.
  • Path-based enemy attacks are now in full working order, using paths generated with a combination of my graphical calculator and Excel.
  • A couple of other new enemy attacks have been added.
  • The game now sports a BBC Micro font which can be used for proper text display.
  • The "epilogue" to the game is fully coded (type-writer effect for final message copied from original game, including sound effects and fades).
  • Each level now begins with a summary screen (sprite limits meant that displaying all your lives at the start of the level was impossible, so is now done on an interval screen). The screen displays the zone name and a number of lives, the number of lives being surrounded by orbiting space-ships (the number of those being the number of lives left).
  • The game now fully works on hardware (should now work on old hardware - not checked, as I do not have an old BIOS-less Game Gear) and in all emulators (I was not initialising the display correctly).
  • Destroyed terrain tiles are not updated live to the name table in the fairly intesive loop - they are saved to a list of destroyed tiles, which are then read off directly and updated when needed in the intensive graphics bit.

I've probably forgotten a lot of stuff. Bear with me.

There have been a number of "WTF" moments reading back some of the source. Take, for example, this gem:
wtf.gif
Some explanation is needed here - this is from the code that handles the special case when you have shot a 2x2 square building and it lies out of bounds of the name table. The name table is my grid (32x28) of tiles indices that each point to an 8x8 tile in the VRAM. As the view point moves up this map, new tiles indices are written to it, or old ones are adjusted when something is blown up. The worst case scenario here is if the 2x2 tile lies just above the top of the name table - which is what the above code has to fudge. Look at this:

tilemap.gif
(I love debugging emulators!)
This shows all of my 32x28 tilemap. That funny white rectange is my view rectangle (it's currently half-off the display, and it loops around). If you look at the top and bottom edges of the tilemap, you'll see a ring has been shot out. Naturally, the bottom will have been hit first. What happens in this case is the address of the tiles that have been erased is decremented by a whole row of map points (there are 2 bytes to a spot on the name table, so I go backwards by 64). In this case, I find that the address is above the start of the tilemap so I add on 64*28 (which is the entire size of the table) and add it back to get back into the bounds of the table itself. As you can see, it was a successful operation in this case, but only because I was writing back HL this time and NOT the accumulator! No wonder my sprites were becoming destroyed as I was writing in completely the wrong part of the VRAM...

blown_up.gif
This is the screenshot from the emulator of the screen display for the above tilemap (the sprite layer is not displayed in the tilemap, for obvious reasons).

I'm still not getting very far with my quest for music. sad.gif
The only bit of the game that has music is the title screen, and that's not so much music as a weird noise (here is an MP3 of my Game Gear's rendition, this is the original from the BBC Micro). Even though I have specified that the noise channel (the one that produces the high beeping noises) to use the highest frequency, it's still lower than the Beeb. All the other notes are correct, though.

Latenite has got yet another update - project support. (It looks more and more like VS.NET every day!) Rather than create messy proejct files and stuff which makes distrubution tougher, I thought I'd go the easier route of just allowing people to stick directives in the file with the ;#latenite:main directive. You can now ;#latenite:name="name_of_project" and ;#latenite:project="file_name"[,"project_folder"].

latenite_small.jpg
Click for larger image

Skybound Visualstyles (which I'm using to fix the weird .NET XP interface bugs) looks lovely but hugely slows down the app - only really noticeable with so many hundreds of nested controls like me and when moving large windows on top of it forcing repaints, so now the XP styling option is saved away (so you can revert to boring standard grey if you like). Latenite now saves window/splitter positions when you close - a first for an app by me! grin.gif
In fact, Latenite is also my first app that needs a splash screen, it takes so long to get going... sad.gif It's only about 2 seconds, though, for it to track down all the tools, load all the documentation, add all the compiler scripts and present itself, so it's not too bad.

One overlooked piece of software is Microsoft Excel. People seem to develop a hatred of it, especially in people who end up trying to use it as a database application (it appears that this is what 9 out of 10 smallish (and some not so small!) companies do).
I have been using Excel to create those smooth curving paths for some of the enemies to follow. First, I prototype them on my graphical calculator (lots of trial and error involved!):

calc_1.jpg
calc_2.jpg

..before transferring into an Excel spreadsheet.

excel_small.jpg
Click for legible!

The Excel spreadsheet is set up so that column A is the steps (usually 0 to 256) in ascending order. Column B is the X coordinate, column C is the Y coordinate.
Columns E and F serve a special purpose - they contain the differences between each element in columns B and C (so E3=B3-B2, E4=B4-B2 and so on). Columns G and H "fix" the values - if it's negative, make it positive and set the fourth bit (just add 8). This is for the internal representation of the paths. Column I contains the data I can just copy and paste into the source files - it starts with the initial (x,y) coordinate, and then has a list of bytes. Each byte signifies a change in (x) and change in (y), with the lower four bits for (x) and the upper four bits for (y).If the nibble is moving the object left or up (rather than right or down), then the most significant bit of that nibble is set. For example:

%0001 - move right/down 1 pixel
%0011 - move right/down 3 pixels
%1001 - move left/up 1 pixel
%1100 - move left/up 4 pixels

...and therefore...

%11000001 = move right one, up four.

Poor Excel has suffered a little bit of neglect from me - I used to use it to generate my trig tables. WLA-DX, the assembler I learn to love more and more every day, supports creation of a number of different tables - including trig tables - with a single directive. Just specify .dbsin (or .dbcos) followed by the start angle, how many bytes of trig table you want, the step between each angle, the magnitude of the sine wave and the DC offset and away it goes.
People still using TASM, STOP! Use WLA-DX. It's ace (and free, not shareware!).

You can never have enough pictures in a journal (hey, you should see this page load on our 700 bits/sec phone line at home!)
Here's the full list of sprites:

sprites.gif

The last ship being after the explosions is a mistake, but it's too much hassle to change. I'm really pleased the way they've come out - I'm no pixel artist. smile.gif

I'll finish off with a few assorted screenies.

misc_01.pngmisc_02.png
misc_03.pngmisc_04.png

...I would have done. I should have done. However, when taking those screenshots I saw a glitch in the graphics. As an exercise for the reader, can YOU spot where the bug is?

bug.gif
(and it's not in one of those external functions I wrote - this is why copy-paste coding is bad, 'kay?)

Oh, (possibly?) final last thought popping into my head: one thing I really miss from the BBC Micro era is the comfortable keyboard layout. I mean, look at this small photo of a Master 128 keyboard:
master_128.jpg
Click for bigger

You might think that that blocky monstrosity would knacker your fingers, but that's not the reason. It's the fact that rather than squash one hand's fingers onto a small cursor pad (or the even sillier WASD), you balance movement between your two hands - Z and X for left and right, : and / for up and down. (On a modern UK layout, that'd be ZX and '/). The space bar is now conveniently accessible by both thumbs, and you can reach around most of the rest of the keyboard with your other fingers.
The Game Gear is an ergonomic handheld (unlike the uncomfortable Game Boy), so I'm reckoning that I can balance the controls between hands - ← and → on the d-pad can control left and right, and the 1 and 2 buttons can control up and down. I will offer multiple layouts, though, as otherwise that might confuse some people. wink.gif

Anyway, I hope you find this journal interesting. It seems a bit all over the place - video, pictures, rambling, odd bugs, nostalgia... The only thing that's an issue is my rapidly shrinking GDNet+ account web space!

Fire Track

Friday, 9th September 2005

When people ask, in the future, what the greatest feature of Fire Track is, they will not say the graphics. Nor the gameplay. In fact, they will... well, see for yourself. (Sorry, it's a bit quiet). smile.gif
There is one more attack pattern. I have redesigned the attack system so that the enemies do NOT have their clocks auto-incremented (though they can call a function in their update code to do so if they really need it). This is so I can use the clock to store states instead. The new attackers slide in from the top-right, move down until they are level with the player then slide right again.
One peculiarity of gameplay in Fire Track is that you are permanently firing. You can never let go of the fire button. Also, the enemy ships do not fire at you - they just try to crash in to you.
I ran out of room. The game refused to compile. So, with a bit of tweaking in the map editor and a rewritten scrolling routine, I have doubled the amount of free space (without the music, about 10000 bytes are free). I'm using RLE compression on each 20 bytes of the level. If I get even tighter for space, I could probably pack the 8 bit level bytes into 6 bits.

Here's an awful sprite of an explosion. It looks really ropey, but it's as close as I can get to the authentic Fire Track (ship) explosions. I don't know how good it'll look in action!

explosion.gif

Enemies!

Thursday, 8th September 2005

They claim a picture says a thousand words.
In this case, with these two pictures and one video [549 frames] I estimate that I have saved myself from having to write over half a million words in this journal entry.
enemies_1.gif enemies_2.gif
There is, of course, the usual shonkily shot video footage to watch: 416KB AVI.
The collision rectangles need a little bit of fine-tuning and something better than just vanishing sprites needs to be implemented, but the modular and simple system is there.
Each level contains a pointer to an "attacks" table.
Each "attacks" table entry contains a $FF terminated list of attack patterns, in order.
Each attack pattern specifies -

  • Which sprite number to use.
  • A pointer to the routine to call to initialise the enemy sprite locations.
  • A pointer to the routine to call to move each enemy sprite each frame.
  • An attack time.

Each enemy is held in a table containing an X,Y coordinate and a "ticks" counter that is incremented each frame automatically.
The "attack time" timer is primed and decremented each frame, and once it hits zero the system moves to the next attack pattern from the level's list.
This means that I can have a number of different patterns. So far, I've implemented a simple sine-wave attack and an even simpler random-positions-and-drift-past attack (both from the original game), but some attacks are more complex, relating to paths or drifting towards the player. This system I have in place should make having a wide variety of different types of attack simple.
I got so far, compiled, ran on my Game Gear and - oh dear. Lots of nasty name table corruption. To save space, I had decided to check the bullets against the enemy ships inside the sprite-writing routine, which was obviously too slow (much popping, pushing and use of the index registers) and as such the sprites were being written after the screen had started to be displayed. I have moved the code outside the loop and restructured parts of the code, but I hope that I have enough time/space to implement other things properly, without being restricted too badly by the low CPU speed.

I'm not getting far with this elsewhere, so I'll ask here - anybody here with BBC Micro skills?
I really need help with the music side of things - not so much writing a sound/music engine for the game, but more the actual "porting". The BBC Micro has the EXACT SAME PSG in it, so I could probably write a modification for a BBC emulator (BeebEm, for example, comes with source) which logged writes to the PSG hardware port (and time-since-start-of-program), but I'd still have the piou-piou-piou-skrrch sound effects over the top. Does anyone have a BBC Micro disk with a copy of the Fire Track music on it? I remember seeing/using music collection disks which featured game music on them a decade ago, and SOMEONE must have a "raw" copy of the Fire Track music (how else is there a recording in the STH archives?) but nobody on the STH fora seem to be able to or want to help.

Finished the levels! Wahey!

Wednesday, 7th September 2005

...and here is level 6. This, however, worries me:

egads.gif

Hopefully I can cram in all the rest of the code, tables, graphics and music into 5K. Failing that, I might have to start compressing my levels...

I don't believe I've introduced you to my enemies yet? Here's the complete sprite table - don't worry, the letters P, A, U, S, E and D do not feature as enemy craft!

sprites.gif

I spent some time adding a new command systen to QuadPlayer, so you can now set a song to loop back X times (or infinitely) to a particular spot. It'll only loop from the end, sadly. Nested repeats will be too evil to try and implement. I'd like to experiment more with white noise - maybe a command to set up certain channels as being white noise rather than tones? Not sure how I'd generate the white noise, as the register R (which is the source of my random number generators) isn't going to be very random if accessed in a short loop!

Sample song, from a Kirby game (I added the fade at the end manually, that's not produced by the calculator!) Not bad, seeing as it has been generated by a calculator with no proper sound hardware. smile.gif

Page 47 of 48 143 44 45 46 47 48

Older postsNewer postsLatest posts RSSSearchBrowse by dateIndexTags