News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_ervin

My CPCRetroDev2015 entry - RUN"CPC"

Started by ervin, 13:08, 28 June 15

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

ervin

#75
Quote from: TFM on 20:33, 31 July 15
No offense but... in the games the player can go up & down a bit. That makes the nice feeling imho. But you don't have to repeat old stuff.  ;)

It's cool, no offense taken.
8) :)

You're absolutely right, so I've been working on tweaking the collision detection routines, so that they work no matter where the player sprite is on the screen.
Then I'll adjust the 3D calculations so that the obstacles still move around correctly, even though the player sprite can change position on-screen.

Once that is done, I'll post one more build to see what you think (despite saying that I wouldn't upload any more versions).
:)


TFM

Don't post too much. I'm really looking forward to see the final polished result! And it will be great!  :)
TFM of FutureSoft
Also visit the CPC and Plus users favorite OS: FutureOS - The Revolution on CPC6128 and 6128Plus

ervin

#77
Alrighty! I've now got the player sprite moving around the screen (within a limited area, in order to still relate correctly to the position of the obstacles).
I had to subtly change the 3D calculations in order to offset the obstacle positions correctly when the player sprite moves from the centre.
That part was easier than I thought it would be.

The collision detection however has been trickier than I expected.  :'(
I've *almost* got the adjustments working now; just a nasty glitch to fix.
Hopefully that'll be sorted out very soon.

[EDIT] YES!!! Sorted!
This change has resulted in a 2% drop in average frame-rate, but that's ok.
It's not noticeable during gameplay anyway, so I can live with it.
8)

So, even though it'll make a liar out of me, I've uploaded ONE. LAST. BUILD.
runcpc_9 contains the player sprite movement, and the adjusted collision detection routines.

I think it feels great, but I know it could be a bit better.
Luckily, it *will* get a bit better because my player sprite will have some animation frames to imply movement - though that won't be shown until the competition is over.
:P


TFM

9 is the perfect number, so upload #9 is just fine. Will play it immediately...
TFM of FutureSoft
Also visit the CPC and Plus users favorite OS: FutureOS - The Revolution on CPC6128 and 6128Plus

ervin

Wow, transparency within tiles is a pain in the butt when using double buffering!

Because of the dirty buffer system I've got running, I'd sometimes get leftovers from the previous frame (i.e. the last time the same screen buffer was displayed). So I was getting annoying flickering, particularly around the player sprite.
And if the player doesn't move for a moment, the dirty buffer thought that the cells where the player sprite is printed hadn't changed, and the see-through bits weren't being updated, because the cell wasn't being updated!  >:(

To solve this I have to print the player sprite every frame, whether it changes position or not.
This has caused a slight speed hit, but oh well. It's still very fast.

That little glitch took many frustrating hours to fix... I hope it's the last major difficulty I'm going to face.
"Not likely!", say the programmers reading this!
:P


alex76gr

Ervin, this is one of the most impressive things i have ever seen on CPC!!! :o
Great job.
I still believe that i got my myopia from the green GT-65 monitor, but i can't prove it! :)

ervin

Quote from: alex76gr on 07:43, 05 August 15
Ervin, this is one of the most impressive things i have ever seen on CPC!!! :o
Great job.

:)
Thanks man!
It's amazing to hear (or read!) someone say that about something I'm working on.
Makes all the hard work worthwhile.

ervin

#82
Alrighty, I've now got 25 different frames of animation for the player sprite, which display depending where the player sprite is on-screen.
This enhances the feeling of movement - it's like a tilting effect on the sprite as you move up/down, and a turning effect as you move left/right.

I've also managed to solve the drop in speed caused by forcing the player sprite to be printed each frame.
I incorporated the player sprite into the main tile printing routine more smoothly, and now things are flying along again!
I'm pretty happy about that.
;D

In other news, I've just discovered the joy of the cpctelera script cpct_bin2c.
This instantly converts a compiled binary into a C array of byte values, which is amazingly useful, because I'll need to stored sprite definitions as compressed data (via exomizer), in order to fit all my sprite defs in.
Sprite data will be uncompressed on the fly as required, when the game changes the "zone" that the player is flying through.

Each obstacle's uncompressed sprite definitions will take up 1,805 bytes, so RAM will run out very fast without this method.
The reason the sprite defs take up so much space is because I'm storing 21 sprite definitions for each obstacle, effectively pre-calculating the scaled versions of each obstacle.

I wrote a quick little program (in Blitz Basic) last night, that converts an image into a list of tile references.
At the moment it only handles tiles of one colour, but I'll have to extend it to cater for tiles that are more than a simple block of colour.
This little program will make it very easy to convert the tile graphics into something usable within SDCC.

I'm creating the sprites in PhotoFiltre, and then I'll chop them into tiles using the cpctelera script cpct_sp2tile.
Have I mentioned before how awesome cpctelera is?  :D

I only need to manually create one version of each obstacle (the "closest" sprite - i.e. the largest, unscaled version), and then I can use PhotoFiltre re-sizing tools to create the other 20 sprites.
Some tidy-up is required, but this method is still very quick. Good thing too, as time is moving very quickly, and I need to take as many shortcuts as I can!
Also, I'm not very good at pixel art, so having the graphics pre-scaled by PhotoFiltre will save me many, many hours of work.


ronaldo

I'm really happy to see that utilities we have created within CPCtelera are really useful for projects :). That also empowers our spirits to carry on :)

Have you tried the latest script included in 1.2, cpct_img2tileset? Reading your comments I imagine that it will be helpful for you :).

Keep up the good work! :D

ervin

#84
Thanks ronaldo.

cpct_img2tileset looks like it would be very useful as well!
I'm not sure which one will be best for my needs, but I'll give both cpct_img2tileset and cpct_sp2tile a try.

[EDIT] I just had an idea...

Let's say you have a main.c that simply contains a number of array declarations (all initialised with data), and an empty void main(){}

It would be great to do the following:

- compile that main.c file
   Does it have to be called "main.c"?
   Does it need void main(){}?

- compress the resulting .bin file with exomizer
   For example, exomizer raw "file.bin" -o "file.exo"

- use cpct_bin2c to create a C array of the compressed data
   For example, cpct_bin2c file.exo>file.txt

[EDIT 2] Ah, I just realised that this won't work, as exomizer is a windows program...
Never mind. It's easy to do these steps manually anyway.
:)

ronaldo

Well, cpct_img2tileset and cpct_sp2tiles have different uses. The second one works over a C array, splitting them in smaller arrays (tiles). The first one works directly over an image (PNG, TIFF, JPG). It treats the image as a set of tiles or sprites of the same size, and generates two files .c and .h with all the tiles/sprites converted to C-Arrays, and a tileset array pointing to all of them.

So, cpct_img2tileset is designed to work direcly on assets and transform them into code. cpct_sp2tiles works on code. Everything depends always on your needs :).

The maskSpritesAligned example has an assets folder with the tileset it uses in PNG format. Focusing on workflow, designers create tilesets like this one, and then they can be mapped with Tiled (.tmx and .csv files). Then a command like this one:

   cpct_img2tileset -pf { 0 18 5 6 9 11 12 } tiles.png

Is all you need to generate tiles.c and tiles.h files, with all tile definitions and the tileset array, ready to compile in your code :).

The final step will be performed on future versions, integrating this with the building procedure, so that nothing else than make is requiered. Then designers can focus on design, while coders focus on code :).

ervin

Thanks ronaldo - that's *very* useful information.
:)

ronaldo

@ervin: I've read your exomizer thoughts and do not understand what you are proposing. Are you talking about creating a compressed binary to load faster? Is it that you think of a way of compressing all data of a program transparently to the programmer?

ervin

Quote from: ronaldo on 08:36, 07 August 15
@ervin: I've read your exomizer thoughts and do not understand what you are proposing. Are you talking about creating a compressed binary to load faster? Is it that you think of a way of compressing all data of a program transparently to the programmer?

No, nothing that complex.
:)

What I need to do in my program is store my sprite definition tables in a compressed form.
Otherwise they simply won't fit, as I've got 21 sprites (some of which are VERY large) for each obstacle.

So I will be creating a small C program for each obstacle's sprite definitions.
If I end up having 10 obstacle types, I'll need to create 10 of these little programs.
Each of these small programs will consist of 21 initialised arrays, and an empty main() function.
(The main() function appears to be required in order for the C file to compile).

Now, the compiled file is a .bin consisting of 1,805 bytes, which is way too big.
So I will run them through exomizer to compress them.
The first one I tried came down to under 200 bytes, due to the high repetition of bytes in the compiled file.

So theoretically I will be able to fit several compressed files into a portion of memory reserved for this data.
Now, I want the program to be single-load, so I need the compressed files to be resident in memory.
When I need a new sprite to be available to the program, I will uncompress it using the z80 decompressor, to another area of memory where uncompressed sprite data will temporarily sit.
(Unfortunately the decompress routine needs modification, as it is not 100% compatible with the z80 format used by SDCC).

To get the compressed .EXO files into memory (i.e. to be included in the game binary file), I want to put the compressed data into my C program somewhere, most likely as a bunch of include files. cpct_bin2c makes this very easy.

That's about it. Quite messy, but it's the only way all my huge sprites will fit in 64K.
:)

Neil79

The latest in Indie & Retro News!!! IndieRetroNews - Indie Retro News on twitter

ervin

Quote from: Neil79 on 12:38, 07 August 15
Grand :D

I've been featured!
Thanks man!

The game has progressed quite a bit since the last version I uploaded, but I can't upload any more builds, as I don't want to break the competition rules regarding releasing the game independently of the competition.
I *could* release what I've got now and I think I'd be safe, but I'd rather not take any chances.
:P

Neil79

Quote from: ervin on 13:16, 07 August 15
I've been featured!
Thanks man!

The game has progressed quite a bit since the last version I uploaded, but I can't upload any more builds, as I don't want to break the competition rules regarding releasing the game independently of the competition.
I *could* release what I've got now and I think I'd be safe, but I'd rather not take any chances.
:P


Any time buddy, I did note that it was an early build, so it's all good  ;D
The latest in Indie & Retro News!!! IndieRetroNews - Indie Retro News on twitter

ronaldo

@ervin: I undetstand better now :). I've been thinking about similar problem for some time and I've got some designs in mind about data management tools (something more general that will cover your case). Unfortunately, my designs will have to wait some months until I finish another more urgent project I'm developing now (work always has greater priority, regrettably). However, I promise I will develop these ideas as soon as I'm able to return again to the scene :D.

ervin

#93
Quote from: ronaldo on 15:14, 07 August 15
@ervin: I undetstand better now :) . I've been thinking about similar problem for some time and I've got some designs in mind about data management tools (something more general that will cover your case). Unfortunately, my designs will have to wait some months until I finish another more urgent project I'm developing now (work always has greater priority, regrettably). However, I promise I will develop these ideas as soon as I'm able to return again to the scene :D .

No trouble at all.
It's easy to do this stuff manually.
:)

I've now got my program storing 2 sets of compressed data in RAM, and one of them is chosen at random whenever the player enters a new "zone".
The data is uncompressed in the "live" sprite data area, and the appropriate sprite set is used for obstacles!

This technique has made a HUGE difference to memory usage.
I now have lots of memory left - more than enough to finish the game, I think.
(I can afford to devote a little over 8K to compressed sprite data).

ervin

#94
With a little bit of research in cpctelera's docs, I've figured out how to write a PressAnyKey routine, as opposed to a routine that waits for a specific keypress (like Space, for example).
This means my front screen now says "PRESS ANY KEY" instead of "PRESS SPACE".
Much better.

Here is the code.
The first DO loop waits until there are no keys being held down.
The second DO loop can then check for a "clean" keypress.

void waitForKey(){
    u8 i;
    u8 keyPressed=0;

    do{
        keyPressed=0;
        cpct_scanKeyboard_f();

        for (i=0;i<10;i++){
            if (cpct_keyboardStatusBuffer[i]!=255){
                keyPressed=1;
            }
        }
    } while(keyPressed!=0);

    do{
        keyPressed=0;
        cpct_scanKeyboard_f();

        for (i=0;i<10;i++){
            if (cpct_keyboardStatusBuffer[i]!=255){
                keyPressed=1;
            }
        }
    } while(keyPressed==0);
}


Also, I've been able to make good use of cpctelera's cpct_drawStringM0 function to nicely centre text on a mode 0 screen.
This function (and I presume the mode 1 version as well) allows the x position of a string to be any byte position on a character row.
So whereas normal mode 0 printing in BASIC forces a string to be at byte positions 0, 4, 8, 12 and so on, cpct_drawStringM0 allows it to be at any byte position, thereby making centering much more accurate.
8)

In other news, I've got the gameplay flow nailed down now.
I run with a "level" for 10 "stages".
These are indicated by the colour of the ground stripes approaching the player - each colour represents a stage.

After 10 stages, there is an empty stage, where I decompress the next set of sprite data.
The new sprites then appear in the subsequent stage, and stay for 10 stages.
And so on...

The speed also increases every 10 stages (though the maximum speed will be capped).
:P

At first I didn't have the empty stage during the decompress phase, and I found that any sprites currently on screen would suddenly change to new sprites!
This happened because the same area of memory is being used from level to level to read the sprite data, and the program would continue reading that area and happily printing the newly decompressed sprites!
:laugh:

Having this empty stage also gives the player a brief respite from the onslaught of approaching obstacles!
In addition, it hides the slight pause during sprite decompression.

ronaldo

Nice work @ervin :) . Here I leave you some suggestions for improving performance on checking keyboard for any key. All functions return TRUE when there was at least 1 key pressed, and 0 otherwise:

//
// C Version 1: Compact and Balanced.
//
u8 isAnyKeyPressed_1() {
   u8 i=10, result, *keys = cpct_keyboardStatusBuffer;

   result = *keys;
   while(--i) {
      result &= *++keys;
   }

   return 1 + result;
}

//
// C Version 2: Expanded, but faster
//
u8 isAnyKeyPressed_2() {
   u8 *keys = cpct_keyboardStatusBuffer;

   return 1 + (*keys++ & *keys++ & *keys++ & *keys++ & *keys++ &
               *keys++ & *keys++ & *keys++ & *keys++ & *keys);
}

//
// ASM Version 1: Compact and Balanced (much better than C version 1)
//
u8 isAnyKeyPressed_3() {
   __asm
      ld   hl, #_cpct_keyboardStatusBuffer
      ld    b, #9
      ld    a, (hl)
$0001:
      inc  hl
      and (hl)
      djnz $0001
      inc   a
      ld    l, a
   __endasm;   
}

//
// ASM Version 2: Expanded and fast (faster of all 4, smaller than C version 2)
//
u8 isAnyKeyPressed_4() {
   __asm
      ld   hl, #_cpct_keyboardStatusBuffer
      ld    a, (hl)
      inc  hl
      and (hl)
      inc  hl
      and (hl)
      inc  hl
      and (hl)
      inc  hl
      and (hl)
      inc  hl
      and (hl)
      inc  hl
      and (hl)
      inc  hl
      and (hl)
      inc  hl
      and (hl)
      inc  hl
      and (hl)
      inc   a
      ld    l, a
   __endasm;   
}

Then, picking up any of these functions, you may rewrite your code like this:

void wait4Keypress() {
   // First, if there is any key pressed, we wait until no key is pressed
   do { cpct_scanKeyboard_f(); } while ( isAnyKeyPressed());

   // Then we wait until a Key is pressed
   do { cpct_scanKeyboard_f(); } while ( !isAnyKeyPressed());
}


Hope that helps :) . Keep up the good work! :D

Axelay

Quote from: ervin on 03:00, 12 August 15

Having this empty stage also gives the player a brief respite from the onslaught of approaching obstacles!
In addition, it hides the slight pause during sprite decompression.


You mentioned previously that you were using exomizer for that.  If that is still the case, have you tried bitbuster at all?  It's not quite as good at packing as exomizer but is a great deal faster at depacking.

ervin

Quote from: ronaldo on 10:01, 12 August 15
Nice work @ervin :) . Here I leave you some suggestions for improving performance on checking keyboard for any key. All functions return TRUE when there was at least 1 key pressed, and 0 otherwise:

//
// C Version 1: Compact and Balanced.
//
u8 isAnyKeyPressed_1() {
   u8 i=10, result, *keys = cpct_keyboardStatusBuffer;

   result = *keys;
   while(--i) {
      result &= *++keys;
   }

   return 1 + result;
}

//
// C Version 2: Expanded, but faster
//
u8 isAnyKeyPressed_2() {
   u8 *keys = cpct_keyboardStatusBuffer;

   return 1 + (*keys++ & *keys++ & *keys++ & *keys++ & *keys++ &
               *keys++ & *keys++ & *keys++ & *keys++ & *keys);
}

//
// ASM Version 1: Compact and Balanced (much better than C version 1)
//
u8 isAnyKeyPressed_3() {
   __asm
      ld   hl, #_cpct_keyboardStatusBuffer
      ld    b, #9
      ld    a, (hl)
$0001:
      inc  hl
      and (hl)
      djnz $0001
      inc   a
      ld    l, a
   __endasm;   
}

//
// ASM Version 2: Expanded and fast (faster of all 4, smaller than C version 2)
//
u8 isAnyKeyPressed_4() {
   __asm
      ld   hl, #_cpct_keyboardStatusBuffer
      ld    a, (hl)
      inc  hl
      and (hl)
      inc  hl
      and (hl)
      inc  hl
      and (hl)
      inc  hl
      and (hl)
      inc  hl
      and (hl)
      inc  hl
      and (hl)
      inc  hl
      and (hl)
      inc  hl
      and (hl)
      inc  hl
      and (hl)
      inc   a
      ld    l, a
   __endasm;   
}

Then, picking up any of these functions, you may rewrite your code like this:

void wait4Keypress() {
   // First, if there is any key pressed, we wait until no key is pressed
   do { cpct_scanKeyboard_f(); } while ( isAnyKeyPressed());

   // Then we wait until a Key is pressed
   do { cpct_scanKeyboard_f(); } while ( !isAnyKeyPressed());
}


Hope that helps :) . Keep up the good work! :D

Brilliant! Thanks ronaldo.

ervin

Quote from: Axelay on 10:11, 12 August 15
You mentioned previously that you were using exomizer for that.  If that is still the case, have you tried bitbuster at all?  It's not quite as good at packing as exomizer but is a great deal faster at depacking.

Thanks Axelay.
I haven't tried bitbuster before, but it might be worth a look...

Having said that, I'm only doing decompressing during the empty stage, which is the transition stage between sets of 10 stages.
The empty stage has no sprites on screen, so rendering is very fast - just sky and ground, and I only draw character cells which have changed since the last frame.
As a result, the decompressing phase is virtually invisible to the player.
I know it's happening, but I have to look very hard to notice it.
:)

TFM

The problem with Exomizer is, that depacking sometime crash the CPC. Reasons unknown.

TFM of FutureSoft
Also visit the CPC and Plus users favorite OS: FutureOS - The Revolution on CPC6128 and 6128Plus

Powered by SMFPacks Menu Editor Mod