Tečaj
izdelave iger za mobilne telefone

:: Predavatelj: Žiga Hajduković. e-mail. .
:: Organizator: Dane Šoba. e-mail. Študentska organizacija FRI (ŠOFRI).

:: Domača stran tečaja: www.tetris1d.org/game/dev/tecaj/.
:: game/dev.si forum: www.tetris1d.org/game/dev/forum_si/.

:: Študentski info sistem FRI: http://www.student-info.net/fri/.

Novice

Čestitam vsem sodelujočim v velikem nagradnem tekmovanju za najboljšo mobilno igro, ki jo je sponzoriralo priznano podjetje Cocoasoft!
V zelo kratkem času vam je uspelo prekositi same sebe in ustvariti igre, ki so presegle vsa pričakovanja!
Objavili smo galerijo vseh sodelujočih iger, kjer si lahko ogledate posnetke akcije iz samih iger, pa tudi fotografije iz podelitve bogatih nagrad!
Ne pozabite na gd.si forum, kjer si bomo še naprej izmenjevali mnenja in pomagali drug drugemu na poti k izdelovanju najboljših mobilnih iger!

Lekcija 03

lekcija 02 :: domov :: lekcija 04

Epsilon 02

Epsilon 02 eclipse workspace project (sfx)

Epsilon 02 wap download

Odpri povezavo:

	http://www.tetris1d.org/gdwap/	
na svojem mobilnem telefonu in si naloži Epsilon_02.

Izvorna koda

Game.java (izvorna datoteka)

GameCanvas.java (izvorna datoteka)

GameSprite.java (izvorna datoteka)

Level.java (izvorna datoteka)

Grafika

Slika 1. Intro image

Slika 2. Background

Slika 3. Player

Slika 4. Izstrelki

Slika 5. Enemy sprite 1

Slika 6. Enemy sprite 2

Slika 7. Enemy sprite 3

Slika 8. Eksplozija

Slika 9. Tileset
Stage 1

Datoteka stage1.txt:


	Tileset:


  		 


		 J   L   ^   <   >

		 \   /   v   O   G
	

OOOOOOOOOOOOOOOO;                ;
OOvvvvvvvvvvvvOO;                ;
O/            \O;                ;
>              <;       B        ;
>              <;                ;
>              <;                ;
>              <;                ;
>              <;                ;
OL            JO;       VV       ;
OGL          JGO;    AA    AA    ;
OOGL        JGOO;       VV       ;
\OOGL      JGOO/;                ;
 \OG/      \GO/ ;                ;
  \/        \/  ;                ;
                ;    O O O O O   ;
       JL       ;                ;
      JOOL      ;                ;
L     <OOG      ;   O O O O O    ;
>     <GG>     J;                ;
/     <OO>     <;                ;
      GOO>     \;                ;
      \GG/      ;   V        V   ;
       \/       ;    V      V    ;
               J;     V    V     ;
    J^^L      JO;                ;
   JOvvOL     \O;                ;
  JG/  O>      \;   AA           ;
  <>  J>/      J;  A  A          ;
  J/  <G      JO;                ;
 J>  JO/     JOG;          AA    ;
J/  JO/     JOGO;         A  A   ;
GO^^^/      OOOG;                ;
GOGG/       OOGO;  O             ;
OGOO        OGOO;          O     ;
vvvv        Ovvv;                ;
                ;                ;
  JL        JL  ;                ;
 JOOL      JOOL ;     O   O      ;
JOOGO      OGOOL;       O        ;
OOGO>      <OGOO; O        O     ;
\GOGO      OGOG/;     O        O ;
 OOO>      <OOO ;   O   O   O    ;
 vvvv      vvvv ;                ;
 OOOO      OOOO ;     O  O   O   ;
 \vv/      \vv/ ; O              ;
                ;      O     O   ;
L              J;   O     O      ;
>             <O;                ;
/              \;                ;
                ;    O O O O O   ;
       JL       ;                ;
      JOOL      ;                ;
L     <OOG      ;   O O O O O    ;
>     <GG>     J;                ;
/     <OO>     <;                ;
      GOO>     \;                ;
      \GG/      ;   V        V   ;
       \/       ;    V      V    ;
               J;     V    V     ;
    J^^L      JO;                ;
   JOOOOL     \O;                ;
  JOOGOO>      \;                ;
  <OOOGO/      J;                ;
  JOOOOG      JO;       P        ;

Kako do dobre grafike za mobilne telefone

Uporaben program za te namene je Paint Shop Pro. Na hitro si bomo pogledali, katere njegove funkcije pridejo prav pri izdelavi grafike za mobilne telefone.

Paziti je potrebno predvsem na:

Manjše novosti

Sprite-i in njihovi frame-i

Novosti v GameSprite.java:

paintSprite()


	public static void paintSprite(Graphics g, GameSprite spr)
	{
		// set the clip window

		int cx = spr.x;
		int cy = spr.y;
		int cw = GameSprite.spriteImageFrameWidths[spr.imageId];
		int ch = spr.h;

		g.setClip(cx, cy, cw, ch);
		
		// calculate the x coordinate of where to start the image paint,
		// so our frame will be seen through the clip window

		int dx = spr.x - spr.frameId * GameSprite.spriteImageFrameWidths[spr.imageId];
		
		// paint the sprites image at the calculated coordinates

		g.drawImage(spriteImages[spr.imageId], dx, spr.y, Graphics.TOP | Graphics.LEFT);

		// restore the clip window

		g.setClip(0, 0, canvasWidth, canvasHeight);
	}


	

Primeri:


		// move enemy sprites
		for (int i=0; i < enemySprites.size(); i++)
		{
			GameSprite enemy = (GameSprite) enemySprites.elementAt(i);

			// animate sprite to next sprite frame every 3 frames
			if (global_frame_counter % 3 == 0)
				enemy.frameId = (byte) ( (enemy.frameId + 1) % (enemy.frameIdMax+1));

Player game over explosion FX

	public static int player_gameover_explosion_counter;
	public static int PLAYER_GAMEOVER_EXPLOSION_COUNTER = 40;

	// check for game end
	if (menu_command_2 || 
			( (player.energy <= 0) &&
					(player_gameover_explosion_counter == 0))
			)
	{
		...

...
	// player loses energy
	player.energy -= player.energyMax/4;
	if (player.energy <= 0 && player_gameover_explosion_counter < 0)
	{
		player_gameover_explosion_counter = PLAYER_GAMEOVER_EXPLOSION_COUNTER;
	}

...

public void updateExplosionSprites()
{
	...

	// create a big bada boom player gameover explosion
	//  7 - max explosion frames
	//  2 - add an explosion every 2nd frame
	if (player_gameover_explosion_counter > 7 &&
			player_gameover_explosion_counter % 2 == 0
			)
	{
		GameSprite new_exp = addExplosion(player);
		new_exp.x += random.nextInt() % player.w;
		new_exp.y += random.nextInt() % player.h;
	}
}
	

Level

Tileset

Slika 14. Tileset

The 2 Stage layers: space background, tiled background

paintLevel, loadLevel

tileMap (in spriteMap)

Slika 15. Level load / paint (clip window)

Slika 16. Level paint, clip window


class Level
{
	public static final byte LEVEL_WIDTH = 16;
	public static final byte LEVEL_HEIGHT = 64;
	
	public static final byte TILE_SIZE = 16;
	public static final byte TILES_PER_IMAGE_LINE = 5;

	// space background position and scroll speed
	public static int space_scroll_y;
	public static int space_scroll_vy = -1;

	// tiled background position and scroll speed
	public static int tiles_scroll_y;
	public static int tiles_scroll_vy = -2;
	public static int tiles_scroll_x;

	public static byte[] tileMap;

	//  a translation table for level tile text representation
	//  to tile index in the tile image 
	public static char[] tileTextToImageIndex = 
	{
		'J', 'L','^','<','>',
		'\\','/','v','O','G',
	};
	
	public static byte getTileIndex(char t)
	{
		byte idx = 0;
		// find tile index
		while ( idx < tileTextToImageIndex.length && tileTextToImageIndex[idx] != t )
			idx++;
		
		// handle unexisting or empty tiles
		if (idx > tileTextToImageIndex.length)
			idx = -1;
		
		return idx;
	}

	public static void loadLevel(byte level_no)
	{
		levelno = level_no;

		// intialize the scrolling background
		space_scroll_y = 0;
		space_scroll_vy = 1;

		InputStream inputstream = null;
		DataInputStream datainputstream = null;
	
		tileMap = new byte[LEVEL_HEIGHT * LEVEL_WIDTH];
		int map_row = 0;
		int tile_map_col = 0;
		int sprite_map_col = 0;
		try
		{
			inputstream = new Object().getClass().getResourceAsStream( "/stage"+ level_no +".txt" );
			datainputstream = new DataInputStream(inputstream);
	
			char ch;


            boolean eof = false;
            while(!eof)
            {
            	// read level text file lines
            	try
            	{
        			// load a row of tiles
            		tile_map_col = 0;
            		ch = ' ';
            		while (ch != ';')
            		{
            			ch = (char) datainputstream.readByte();
            			System.out.print(ch);
            			
            			if (ch != ';')
            			{
                			tileMap[ map_row * LEVEL_WIDTH + tile_map_col ] = getTileIndex(ch);

                			tile_map_col++;
            			}
            			else
            			{
            				break;
            			}
            		}
            		// load a row of sprites
            		sprite_map_col = 0;
            		ch = ' ';
            		while (ch != ';')
            		{

			...
			...
			...

            		}

            		// go to next line of text
            		map_row++;
            	}
            	catch (EOFException eofex)
            	{
            		eof = true;
            	}
            }


			inputstream.close();
			inputstream = null;
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
	}

	public static void paintTiles(Graphics g)
	{
		// clip window coordinates
		int cx, cy, cw, ch;
		// image draw coordinates
		int dx, dy;
		
		int x;
		int y = 0;

		while (y <= GameCanvas.canvasHeight)
		{
			x = 0;
			while (x <= GameCanvas.canvasWidth)
			{


	// get the tileMap index of the tile, located at tx, ty
	int tx = tiles_scroll_x + x;
	int ty = tiles_scroll_y + y;
	int tile_idx = ty / TILE_SIZE * LEVEL_WIDTH + tx / TILE_SIZE;

	// get tile index in image from tileMap
	byte tile_image_idx = tileMap[tile_idx];
				
	if ( tile_image_idx >= 0)
	{
		// get tile level coordinates from tile index
		int tile_idx_x = (tile_idx % LEVEL_WIDTH) * TILE_SIZE;
		int tile_idx_y = (tile_idx / LEVEL_WIDTH) * TILE_SIZE;

		// translate to screen coordinates
		tile_idx_x -= tiles_scroll_x;
		tile_idx_y -= tiles_scroll_y;
					
		int tile_col = tile_image_idx % TILES_PER_IMAGE_LINE;
		int tile_row = tile_image_idx / TILES_PER_IMAGE_LINE;
					
		cx = tile_idx_x;
		cy = tile_idx_y;
		cw = TILE_SIZE;
		ch = TILE_SIZE;

		//  check clip window coordinates, if out of screen
		if (cx < 0)
		{
			cw += cx;
			cx = 0;
		}
		if (cy < 0)
		{
			ch += cy;
			cy = 0;
		}

		//  check clip window size, if out of screen
		if (cx + cw > GameCanvas.canvasWidth)
			cw -= (cx + cw) - GameCanvas.canvasWidth; 
		if (cy + ch > GameCanvas.canvasHeight)
			ch -= (cy + ch) - GameCanvas.canvasHeight; 
					
		dx = tile_idx_x - tile_col * TILE_SIZE;
		dy = tile_idx_y - tile_row * TILE_SIZE;
					
		g.setClip(cx, cy, cw, ch);
		g.drawImage(GameCanvas.tileImage, dx, dy, Graphics.TOP | Graphics.LEFT);
	}

				x += TILE_SIZE;
			}
		
			y += TILE_SIZE;
		}
		g.setClip(0, 0, GameCanvas.canvasWidth, GameCanvas.canvasHeight);
	}

	public static void paintSpaceBackground(Graphics g)
	{
		// fill the vast space
		g.setColor(0x000000);
		g.fillRect(0, 0, GameCanvas.canvasWidth, GameCanvas.canvasHeight);
		
		// init scrolling background image tiling
		int x = 0;
		int y = space_scroll_y % GameCanvas.imgBackground.getHeight() - GameCanvas.imgBackground.getHeight();

		// image is wide enough, so we only need to tile it in the vertical (y) direction
		while (y < GameCanvas.canvasHeight)
		{
			g.drawImage(GameCanvas.imgBackground, x, y, Graphics.TOP | Graphics.LEFT);
		
			y += GameCanvas.imgBackground.getHeight();
		}
	}

}

	

Space-shooter-vertical-scroller material

Epsilon, dodatna grafika (by geci)

Grafika za igro Axion Space, Cocoasoft

Naloge

  1. Vzemi dateteko stage1.txt in vanjo vriši novo stopnjo in jo usposobi v igri.
    (Pazi predvsem na spremenljivki LEVEL_WIDTH in LEVEL_HEIGHT.)
  2. Dodaj stage2.txt in implementiraj prehod na novo stopnjo, ko player doseže vrh 1. stopnje.
  3. Za vsak tip nasprotnika naj bo možno dobiti različno število točk.
  4. Afterburner na player sprite-u.
    Namig: lahko uporabiš sliko eksplozije, ki jo rišeš pod player sprite in animirate.
  5. Vesolje v ozadju je dokaj enolično.
    Dodaj še planet in nebule (slike boš našel v epsilon paketu grafike) v ozadje, ki se bodo naključno pripeljali in skrolali s hitrostjo vesolja.
    Dodaj nov "layer", ki se bo pomikala s svojo hitrostjo, ali pa celo vsak planet / nebula s svojo.


game/dev.si :: predlogi ? pišite: Žiga Hajduković