Jump to content

My First Smartphone (& PDA) game.


Guest nIghtorius

Recommended Posts

Guest nIghtorius

Hi!

I have finished my first smartphone game.. (which also works on PDA's by resizing the 176x220 image to 320x240 or 640x480, depending on what PDA)

the controls of the game are selfexplainery. but still I'll explain them..

{enter} = select a item in the menu / pauses/unpauses the game.

{left} or {4} = move column to the left

{right} or {6} = move column to the right

{up} or {2} = move up in the menu / slides the available items in the column

{down} or {8} = move down in the menu / forces faster down movement of column

smartphone only {r-soft-button} = immediate shutdown of the game. (my panic button ;) )

some in-game screens:

full.pngfull.png

full.pngfull.png

download the .CAB version for smartphones.. (confirmed to be working on SP2003(SE)) and if the .CAB version refuses or you own a PDA/MDA use the .ZIP attached file.. just put the contents in a directory.

also.. I have a C500. so you don't have to worry about the "flickerbug".. It runs just fine.

I hope you enjoy this game. I think this is my first post.. even I have registered a while ago.

The graphics on this post aren't representative anymore..

go visit DaddyCool's post for a feel:

<{POST_SNAPBACK}>

download here:

columns_ce.zip

columns.CAB

Edited by nIghtorius
Link to comment
Share on other sites

Guest nIghtorius
;) isnt there alot of these games avaible already? thanx anyway

<{POST_SNAPBACK}>

Gimme some slack here.. this is my first SP game.. heck my first SP application whatsoever. It's all a learning process here..

Most of those games I downloaded suffered from the annoying flickerbug on my C500.. which is irritating like hell. So I thought why not do it myself? and learn some neat tricks along the way.

is also a good way to test my GAPI graphicslibrary which supports the following:

* Alpha rendering

* Sprites

* Stretching

* avoiding the flickerbug on the SPV C500 ;)

* screendisplaysize independecy.. (i.e.: 176x220 being fullscreen on 320x240 PDA devices, or a 320x240 image scaled down to fit in 176x220 without hassling the programmer)

* Heck it even supports a "working directory" (this is really a pain in the ass with the CE OS.. having to working directory)

* Font engine

* Loading of 24bpp bitmaps (8-bit bitmaps (RLE compressed) in the works)

* smooth-scrolling by using (scoll (SCROLL_UP):P

and this featurelist still grows.. depending what my next project needs.

Edited by nIghtorius
Link to comment
Share on other sites

Guest agent.m
Gimme some slack here.. this is my first SP game.. heck my first SP application whatsoever. It's all a learning process here..

Most of those games I downloaded suffered from the annoying flickerbug on my C500.. which is irritating like hell. So I thought why not do it myself? and learn some neat tricks along the way.

is also a good way to test my GAPI graphicslibrary which supports the following:

* Alpha rendering

* Sprites

* Stretching

* avoiding the flickerbug on the SPV C500 ;)

* screendisplaysize independecy.. (i.e.: 176x220 being fullscreen on 320x240 PDA devices, or a 320x240 image scaled down to fit in 176x220 without hassling the programmer)

* Heck it even supports a "working directory" (this is really a pain in the ass with the CE OS.. having to working directory)

* Font engine

* Loading of 24bpp bitmaps (8-bit bitmaps (RLE compressed) in the works)

* smooth-scrolling by using (scoll (SCROLL_UP);)

and this featurelist still grows.. depending what my next project needs.

<{POST_SNAPBACK}>

Hey homes chill! You dont have to justify yourself :P welcome to Modaco

Link to comment
Share on other sites

Guest mupwangle
Hey homes chill! You dont have to justify yourself  ;)  welcome to Modaco

<{POST_SNAPBACK}>

Aye. Some folks are never happy! :roll:

Is it meant to flash as the columns rotate? It sort of looks deliberate, but I thought it was a bit visually distracting.

The 3d text on the title screen makes my eyes go funny. Kinda magic eye effect. :shock:

Link to comment
Share on other sites

Guest nIghtorius
Aye.  Some folks are never happy! :roll:

Is it meant to flash as the columns rotate?  It sort of looks deliberate, but I thought it was a bit visually distracting.

The 3d text on the title screen makes my eyes go funny.  Kinda magic eye effect. :shock:

<{POST_SNAPBACK}>

Well.. I also think I should have used more animation frames for the columns rotation animations. But I do not have 1337 drawing/animation skillz.

I will someday rework the animation frames of the columns to be more "smooth" and less distracting.

You can replace the ?cube.bmp files with your own versions.. be sure it's 3 frames of 16x16 images (making a whole 48x16 bmp image)

just to get a message out here:

If you want to make a animation for the game which exceeds 3 frames.. just submit it here and I will take a look and modify the game code if needed. they really could need some better animation.. ;)

neat feat: (stretching code)

unsigned short * buffer = (unsigned short *) GXBeginDraw();

	if (buffer == NULL) return;


	int  dx = (Source.width << 16) / (gx_displayprop.cxWidth << 8);

	int  dy = (Source.height << 16) / (gx_displayprop.cyHeight << 8);

	int  rx = 0, ry = 0;


	for (unsigned int y = 0; y < gx_displayprop.cyHeight; y++) {

  for (unsigned int x = 0; x < gx_displayprop.cxWidth; x++) {

  	buffer [x] = Source.framebuffer [(rx >> 8) + ( (ry>>8) * Source.width)];

  	rx+=dx;

  }

  ry+=dy;

  rx = 0;

  buffer+=gx_displayprop.cbyPitch >> 1;

	}


	GXEndDraw();

note:

It would be nice if you report the functionality of the game and on what hardware and what installation you used (CAB/ZIP)

for example: I have used the .CAB version to test-install on my SPV C500 phone. I also tested on a T-Mobile MDA (416Mhz ARM proc)

and also tell if the game is too difficult/easy.. (or hopefully just right)

Edited by nIghtorius
Link to comment
Share on other sites

hiya

well done on making your first game ;)

I've not actually installed it yet (will do that later) but as a fellow coder there's a couple of technical points I'd suggest

- bmp's are HUGE compared to a compressed format like PNG

- look at the Hekkus sound library (http://www.shlzero.com/) instead of FMOD - smaller and cheaper should you go commercial with games in the future

- the loop above is begging for optimisation (if only to remove the multiplication you are doing every pixel)

all the best

muff

p.s. I pulled down the zip so I could look at the raw files quickly ;)

Link to comment
Share on other sites

Guest mupwangle

The flashing isn't between frames - it's more like the 3rd frame is a flashing one (if that makes sense). It's like 1,2,flash,1,2,flash. That's why I thought it was by design.

I installed the CAB on an app-unlocked (not sim-inlocked) c500 running le neuveau rom francais. Seems to work OK so far. Haven't had a chance to play with it much though.

Link to comment
Share on other sites

Guest nIghtorius
hiya

well done on making your first game ;)

I've not actually installed it yet (will do that later) but as a fellow coder there's a couple of technical points I'd suggest

- bmp's are HUGE compared to a compressed format like PNG

- look at the Hekkus sound library (http://www.shlzero.com/) instead of FMOD - smaller and cheaper should you go commercial with games in the future

- the loop above is begging for optimisation (if only to remove the multiplication you are doing every pixel)

all the best

muff

p.s. I pulled down the zip so I could look at the raw files quickly ;)

<{POST_SNAPBACK}>

That's what I mean. it's my first app.. So it's great food for optimalisations. Still. it runs quite fast.. read as: it ran smooth even on the slowest PDA i could find. (since this is the only thing what invokes this code (requires stretching on PDA's))

and due to the fact I can't emulate a PDA and not having availability of one nearby. I programmed as safe as I could. thus keeping readability a plus. highly optimised code is sensitive of little mishaps/mistakes.

Keep in mind that the code doesn't copy 1 on 1 but resizes the image in the process. (resizing a 176x220 image to 320x240 when putting on the screen)

I have refrained from the most performance killing technique. using floats/doubles for calculation.. those are sure make it really slow.

an obvious optimisation would be:

unsigned short * buffer = (unsigned short *) GXBeginDraw();

	if (buffer == NULL) return;


	int  dx = (Source.width << 16) / (gx_displayprop.cxWidth << 8);

	int  dy = (Source.height << 16) / (gx_displayprop.cyHeight << 8);

	int  rx = 0, ry = 0;

	int  yb;


	for (unsigned int y = 0; y < gx_displayprop.cyHeight; y++) {

  yb = (ry >> 8) * Source.width;

  for (unsigned int x = 0; x < gx_displayprop.cxWidth; x++) {

  	buffer [x] = Source.framebuffer [(rx >> 8) + yb];

  	rx+=dx;

  }

  ry+=dy;

  rx = 0;

  buffer+=gx_displayprop.cbyPitch >> 1;

	}


	GXEndDraw();
look @ the new var (yb) and how it's implemented. This optimisation did actually require not much thought and should have it right away. but my stretching code was a bit hush hush :oops: also a good optimisation would be this:
unsigned short * buffer = (unsigned short *) GXBeginDraw();

	unsigned short * scanline;


	if (buffer == NULL) return;


	int  dx = (Source.width << 16) / (gx_displayprop.cxWidth << 8);

	int  dy = (Source.height << 16) / (gx_displayprop.cyHeight << 8);

	int  rx = 0, ry = 0;


	for (unsigned int y = 0; y < gx_displayprop.cyHeight; y++) {

  scanline = (unsigned short *) Source.framebuffer [ (ry >> 8) * Source.width ];

  for (unsigned int x = 0; x < gx_displayprop.cxWidth; x++) {

  	buffer [x] = scanline [(rx >> 8)];

  	rx+=dx;

  }

  ry+=dy;

  rx = 0;

  buffer+=gx_displayprop.cbyPitch >> 1;

	}


	GXEndDraw();

I am going the "profile" those code snippets to figure out which one performs better.

about the flashing issue.. yes you're right.. it's the graphics what causes the problem.. just as I said before.. I should redo them (block graphics)

Edited by nIghtorius
Link to comment
Share on other sites

the first optimisation you did there was the obvious one I meant

only thing I'd then look at is reversing the x&y loops to do -- instead of ++ [ this means that the compiled code will be doing the equivalent of "branch if not zero" test, instead of actually doing a comparison ]

precalc the y line buffer bump as well? - instead of recalcing each time as well

oh, and on a device that has the original resolution, obviously dont do any scaling, have a tighter code specifically for that scenario - only add's an 'if' as overhead (actually on re-reading u might already have done this)

are you allowing for the different aspect ratio's at all?

there are loads more potential optimisations that are based on experience with the devices (like PPC's executing a blit loop like above slower than the Smartphones - so you end up writing specific blit's)

please dont take these as criticisms of your code though - think of it as enthusiatic fellow coder assistance ;)

it's good to see a new coder on the block ;)

muff

Edited by muff
Link to comment
Share on other sites

Guest nIghtorius
the first optimisation you did there was the obvious one I meant

only thing I'd then look at is reversing the x&y loops to do -- instead of ++ [ this means that the compiled code will be doing the equivalent of "branch if not zero" test, instead of actually doing a comparison ]

precalc the y line buffer bump as well? - instead of recalcing each time as well

oh, and on a device that has the original resolution, obviously dont do any scaling, have a tighter code specifically for that scenario - only add's an 'if' as overhead (actually on re-reading u might already have done this)

are you allowing for the different aspect ratio's at all?

there are loads more potential optimisations that are based on experience with the devices (like PPC's executing a blit loop like above slower than the Smartphones - so you end up writing specific blit's)

please dont take these as criticisms of your code though - think of it as enthusiatic fellow coder assistance ;)

it's good to see a new coder on the block :P

muff

<{POST_SNAPBACK}>

don't worry.. there is a if statement which checks if the resolution and output are equal and executes a much faster (just a bunch of memcpy's) method.. I haven't shown this piece of code as it is too obvious how to code such thing.

I am quite new to "C/C++" compilers.. But what you just said about "branch if not zero" sounds about right. at least I think it is.. since my "old" assembly days the "JNZ" instruction was far more efficient to use then "CMP AX, xxxx; JZ"

about the specific blits.. that alone defeats my purpose of having one piece of readable code for all PocketPC devices. I try to find the slowest piece of hardware I can find and if it still runs great then it is fine by me ;)

about the y line buffer bump precalculation.. did you mean like this:

scanline += ylbump;
I would love to do such optimization.. but my "ylbump" is irregular. It may bump or it may not bump.. But there is a way.. but then I am wondering if it actually goes faster.. this is the optimisation I mean
unsigned short * buffer = (unsigned short *) GXBeginDraw();	


	if (buffer == NULL) return;


	int  dx = (Source.width << 16) / (gx_displayprop.cxWidth << 8);

	int  dy = (Source.height << 16) / (gx_displayprop.cyHeight << 8);

	int  rx = 0, ry = 0, by = 0;


	unsigned short * scanline;

	scanline = Source.framebuffer;	


	for (unsigned int y = gx_displayprop.cyHeight; y > 0; y--) {

  if ( (by >> 8) != ry) {

  	ry = ( by >> 8 );

  	scanline += Source.width;

  }

  for (unsigned int x = gx_displayprop.cxWidth; x > 0; x--) {

  	buffer [x] = scanline [(rx >> 8)];

  	rx+=dx;

  }

  ry+=dy;

  rx = 0;

  buffer+=gx_displayprop.cbyPitch >> 1;

	}


	GXEndDraw();

ps) this is a nice discussion.. it forces me to perform better. 8)

btw) as a fellow coder.. What programming-tools are you using for your games? I am using eMbedded VC++ 4.0 for my programming needs :D

ps2) aren't you the one who made SPVMan? since there is also a "SPVMan by Muff" in there ;)

Edited by nIghtorius
Link to comment
Share on other sites

I actually meant the line

buffer+=gx_displayprop.cbyPitch >> 1;
and a slight change to the loops check (atm the compiler might still give you a CMP instead of the JNZ we are after) so you'd get something like this
unsigned short * buffer = (unsigned short *) GXBeginDraw(); 

if (buffer == NULL) return;

int  dx = (Source.width << 16) / (gx_displayprop.cxWidth << 8);
int  dy = (Source.height << 16) / (gx_displayprop.cyHeight << 8);
int  rx = 0, ry = 0, by = 0;
int ybump = gx_displayprop.cbyPitch >> 1;

unsigned short * scanline;
scanline = Source.framebuffer;

for (int y = gx_displayprop.cyHeight; y != 0; y--) {
scanline = (unsigned short *) Source.framebuffer [ (ry >> 8) * Source.width ];
for (int x = gx_displayprop.cxWidth; x != 0; x--) {
 buffer [x] = scanline [(rx >> 8)];
 rx+=dx;
}
ry+=dy;
rx = 0;
buffer += ybump;
}

GXEndDraw();[/code]

note ybump var and the changes to the for loop definitions to be != instead of >

also converted x+y to ordinary int's instead of unsigned ones - personally think that signed int's are easier on the CPU than signed ones

there is a slight overhead looking up the structure vars i.e. Source.width instead of looking this up from an ordinary var - but that's only slight

and of course your gfx blit routines can use the reverse loops if you're not already ;)

Edited by muff
Link to comment
Share on other sites

Guest nIghtorius
also converted x+y to ordinary int's instead of unsigned ones - personally think that signed int's are easier on the CPU than signed ones

That one point I beg to differ.. good example: as we take 8-bit signed/unsigned integers. (shortint if I am correct)

computation:

32+64 = 96 (unsigned)

0010 0000

0100 0000+

------------

0110 0000 = 96 (unsigned)

now 128 + 32 = 160 (unsigned)

1000 0000

0010 0000+

------------

1010 0000 = 160

what if -32 + 32 = 0 (signed)

1110 0000 (!!! -32 signed var)

0010 0000+

------------

0000 0000 = 0 8) (signed)

meaning.. signed or unsigned integers is treated the same by the CPU.. actually there is no difference in arithmetic.

another example: heftier one..

-44 + 80 = 36 (signed)

1101 0100

0101 0000+

------------

0010 0100 = 32 + 4 = 36 (signed)

and again.. the right answer popped up. never ever had to change the method of computation here. that is the beauty of 2-complement numbers ;)

Link to comment
Share on other sites

in this case with loops you're right, and it's probably a moot point, but certainly in the past when using unsigned int's instead of straight int's in something more complex then I found them to be slower

you're right that the CPU should treat them the same speedwise - it's probably just a personal preference I've got into over the years ;)

oh and 8 bit vars are CHAR ;)

Link to comment
Share on other sites

Guest argh
and shortints too ;)

@ http://www.fsref.com/Fatal/FE090500.SHTML

<{POST_SNAPBACK}>

Implementation defined. Only char, signed char and unsigned char are guaranteed to be 1 byte in C++ (in fact, I heard somewhere that only char/signed char were guaranteed to be 1 byte - I haven't paid for the latest C++ spec document so mine may be out of date on this issue).

Link to comment
Share on other sites

Guest nIghtorius
Made some replacement graphics for ya. There can be just copied over the orignal ones to work.

<{POST_SNAPBACK}>

OMG! put some better graphics in it.. OMG.. wow.. I am speechless.. (For now I really know my graphics sucks ass ;) )

As I really liked those new graphics by DaddyCool. I have upped the "optimised" version 0.25a. added some credits to DaddyCool in the gamecode.. (loadingscreen/mainscreen).. and when game over it shows your score and you have to press the action key to return to the main menu.

two attachments again: (with DaddyCool's GFX pack applied + some fixes) the ZIP and CAB.

Edited by nIghtorius
Link to comment
Share on other sites

Guest nIghtorius

I have optimized the binaries a bit.. faster blitting code.. more compatible code.. and I am even trying to get it working on WM2002.. replaced most WCE420 code with WCE300 compatible code.

Still I cannot verify this since I am not in posession of a WM2002 telephone.

you can fetch the optimized binaries here:

columns.CAB

columns_ce.zip

Edited by nIghtorius
Link to comment
Share on other sites

Guest nIghtorius

version 0.3a built.

* huge improvements in image quality on PDA's. it's toggleable since I do not know how much performance impact it may have on older PDA's.

* more optimisations in code to make it run faster ;)

image quality improvement.. how?

I have implemented a reasonably fast algorithm bi-linear stretched filter (for stretching up the 176x220 image to 240x320 or 480x640)

** edit: upped 0.31a..

contains huge "optimisation".. it uses a shadow buffer to figure out which parts of the image needs to be updated (and ofcourse bilinearly filtered).. this means around 50 upto 80% performance improvement ;).. yay

^^ this makes the game perfectly playable on the T-Mobile MDA instead having it crawling (running dogslow) on the 416Mhz Intel ARM processor with the HQ (High Quality) rendering.

This is how it looks:

before

post-119535-1115512911_thumb.jpg

after HQ mode (press -> in the mainmenu)

post-119535-1115512927_thumb.jpg

install the latest version of columns on your PDA/Smartphone and replace the columns.exe file with this version:

columns.exe

Edited by nIghtorius
Link to comment
Share on other sites

Guest nIghtorius

For ppl who want a insight of "integer"-based interpolation scaling algorithm. I have decided to give my "unoptimised" version of my bilinear filter..

void	bltgapi_stretchHQ (gxImage Source)

{

	// if source != displayadapter.. 

	if ( ( Source.width == (signed)gx_displayprop.cxWidth) && (Source.height == (signed)gx_displayprop.cyHeight) )

	{

  bltgapi (Source);

  return;

	}


	unsigned short * buffer = (unsigned short *) GXBeginDraw();

	if (buffer == NULL) return;	// do not draw frame


	int  dx = (Source.width << 16) / (gx_displayprop.cxWidth << 8);

	int  dy = (Source.height << 16) / (gx_displayprop.cyHeight<< 8);

	int  rx = 0, ry = 0;

	int  ybump = gx_displayprop.cbyPitch >> 1;

	int  ddx, ddy, xi;

	int  idx, idy;


	unsigned short * sc1;

	unsigned short * sc2;

	unsigned short pix;

	int  r, g, b, r2, g2, b2;


	for (unsigned int y = gx_displayprop.cyHeight - 1; y != 0; y--) {

  sc1 = &Source.framebuffer [ ( ry >> 8 ) * Source.width ];

  sc2 = &Source.framebuffer [ ( ( ry >> 8 ) + 1 ) * Source.width ];

  

  // interpolation won't come freely.. expect a huge performance hit.

  // but it looks so pretty ^_^'

  ddy = ry - ( ( ry >> 8) << 8 );

  idy = 256 - ddy;


  for (unsigned int x = 0; x < gx_displayprop.cxWidth; x++) {

 	 // buffer [x] = sc1 [(rx >> 8)]; ///// toooooo easyyyy .. :)

 	 xi = rx >> 8;

 	 ddx = rx - ( (rx >> 8) << 8 );

 	 idx = 256 - ddx;

 	 

 	 // every pixel is formatted rrrr rggg gggb bbbb

 	 

 	 pix = sc1 [xi];

 	 r = (( ((pix & 0xF800) >> 11) << 8 ) * idx ) >> 16;

 	 g = (( ((pix & 0x07E0) >> 5) << 8 ) * idx ) >> 16;

 	 b = (( ((pix & 0x001F)) << 8 ) * idx ) >> 16;

 	 pix = sc1 [xi + 1];

 	 r+= (( ((pix & 0xF800) >> 11) << 8 ) * ddx ) >> 16;

 	 g+= (( ((pix & 0x07E0) >> 5) << 8 ) * ddx ) >> 16;

 	 b+= (( ((pix & 0x001F)) << 8 ) * ddx ) >> 16;

 	 pix = sc2 [xi];

 	 r2 = (( ((pix & 0xF800) >> 11) << 8 ) * idx ) >> 16;

 	 g2 = (( ((pix & 0x07E0) >> 5) << 8 ) * idx ) >> 16;

 	 b2 = (( ((pix & 0x001F)) << 8 ) * idx ) >> 16;

 	 pix = sc2 [xi + 1];

 	 r2+= (( ((pix & 0xF800) >> 11) << 8 ) * ddx ) >> 16;

 	 g2+= (( ((pix & 0x07E0) >> 5) << 8 ) * ddx ) >> 16;

 	 b2+= (( ((pix & 0x001F)) << 8 ) * ddx ) >> 16;


 	 // hor-fusion.

 	 r = (((r << 8) * idy) >> 16) + (((r2 << 8) * ddy) >> 16);

 	 g = (((g << 8) * idy) >> 16) + (((g2 << 8) * ddy) >> 16);

 	 b = (((b << 8) * idy) >> 16) + (((b2 << 8) * ddy) >> 16);


 	 buffer [x] = (r << 11) + (g << 5) + b;

 	 

 	 rx+=dx;

  }

  ry+=dy;

  rx = 0;

  buffer += ybump;

	}


	GXEndDraw();

}

I think this is interesting material for future game-programmers.

Edited by nIghtorius
Link to comment
Share on other sites

  • 2 months later...
Guest nIghtorius

Long time..

I am posting the C550 compatible version now.. 99,9% change of it working fine. PDA users still can get the older versions.. this version is specially designed for C550 smartphones.. although it works fine on C500, MDA or any other 2003 smartphone.

columns.cab

Link to comment
Share on other sites

  • 1 year later...
Guest nIghtorius

I know you guys are think'n.. what the heck.. Why am I releasing an update on Januari 2007? because I have a C600 for 7 months right now and Wm2005 QVGA devices are getting quite common right now.

My game always ran in the 176x220 resolution. Although it could scale-up to 240x320 using a bilinear filtering technique.

But it will never look as good as a native 240x320 app. So I have decided to upgrade the graphics and port the game to QVGA (240x320).. Took me 4 hours to complete. Especially I am not such good graphics designer. and the graphics from DaddyCool were awesome.

but I have worked hard for native 240x320 graphics.. And I have to say.. They turned out pretty well. It gives a whole new experience @ native resolution. Game runs great on SPV C500/C550/C600/F600 (tested). Also on PDA's @ 240x320.

You are wondering? C500??? yeah the QVGA runs on the C500 too.. Although the image quality isn't as good on the 550+ models because it will scale down to 176x220 :)

If you liked this kind of game. You should try it.. It's really worth it.

Columns version 0.41qvga released on sun 28 jan 2007.

columns.CAB

columns_qvga_pda.zip

Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.