J2ME Game Concept

1,916 views

Published on

การออกแบบการเล่นของเกมส์ให้ง่ายต่อความเข้าใจ
ขนาดของรูปภาพที่แสดงผลบนหน้าจอ
ขนาดของ files เสียง หรือ รูปภาพต่างๆที่นำมาใช้
ต้องไม่มีขนาดใหญ่จนเกินไป
จัดลำดับของ game loop ให้มีรูปแบบ
การเขียน Thread และใช้ runnable ให้คำนึงถึง
Memory และ condition ของเกมส์

1 Comment
1 Like
Statistics
Notes
No Downloads
Views
Total views
1,916
On SlideShare
0
From Embeds
0
Number of Embeds
7
Actions
Shares
0
Downloads
1
Comments
1
Likes
1
Embeds 0
No embeds

No notes for slide

J2ME Game Concept

  1. 1. Mobile Game and Application with J2ME อ.เจนโชค เตชะโกเมนท์ (เจ) jenchoke@hotmail.com สาขาวิชาสื่อนฤมิต คณะวิทยาการสารสนเทศ มหาวิทยาลัยมหาสารคาม http://www.it.msu.ac.th/nmd
  2. 2. การทำางานของ TimerTask ข้อดีของการใช้ TimerTask คือใช้งานง่ายเพราะมีเมธอด ให้ใช้งาน เพียงสังให้เริมต้นทำางานด้วยเมธอด run() และหยุด ่ ่ การทำางานด้วยเมธอด cancel() การทำางานของ TimerTask ต้องอาศัยการควบคุมผ่าน เมธอด schedule() ของ class Timer อีกทีหนึ่ง timer = new Timer(); // กำาหนด Instance ของ Timer TimerTask task = new TimerTask(Value); // สร้าง class ในส่วนการทำางานในรูปแบบของของ // TimerTask timer. Schedule(task,0,500); // timer จะควบคุมการทำางานของ TimerTask ทำางานทุกๆ 0.5 วินาที
  3. 3. การทำางานของ TimerTask Main Time Task Display ควบคุม TimerTask.run ทำาหน้าที่ Paint Time.schedule() (display) ตามคำาสั่ง random line มีวิธีการเขียน code j2me แบบง่ายดังนี้ ครับ โดยเริ่มเขียนจาก Java Class Java Class J2ME Midlet extends Canvas extends TimerTask Class
  4. 4. sk
  5. 5. TimerTask import javax.microedition.midlet.*; import javax.microedition.lcdui.*; import java.util.*; Class FieldMover Class TimerDemo extends TimerTask extends MIDlet Class StarField extends Canvas TimerDemo.java
  6. 6. import javax.microedition.midlet.*; TimerDemo.java import javax.microedition.lcdui.*; import java.util.*; public class TimerDemo extends MIDlet { Display display; StarField field = new StarField(); FieldMover mover = new FieldMover(); Timer timer = new Timer(); public TimerDemo() { display = Display.getDisplay( this ); } protected void destroyApp( boolean unconditional ) { } protected void startApp() { display.setCurrent( field ); timer.schedule( mover, 0, 50 ); } protected void pauseApp() { } public void exit(){ timer.cancel(); // stop scrolling destroyApp( true ); notifyDestroyed(); }
  7. 7. class FieldMover extends TimerTask { TimerDemo.java public void run() { field.scroll(); } } class StarField extends Canvas { int height; int width; int[] stars; Random generator = new Random(); boolean painting = false; private Random genColor = new Random(); public StarField(){ height = getHeight(); width = getWidth(); stars = new int[ height ]; for( int i = 0; i < height; ++i ){ stars[i] = -1; } }
  8. 8. public void scroll() { if( painting ) return; TimerDemo.java for( int i = height-1; i > 0; --i ){ stars[i] = stars[i-1]; } stars[0] = ( generator.nextInt() % ( 3 * width ) ) / 2; if( stars[0] >= width ){ stars[0] = -1; } repaint(); } protected void paint( Graphics g ){ painting = true; g.setColor( 0, 0, 0 ); g.fillRect( 0, 0, width, height ); for( int y = 0; y < height; ++y ){ int r_color = genColor.nextInt(255); int g_color = genColor.nextInt(255); int b_color = genColor.nextInt(255); g.setColor( r_color, g_color, b_color ); int x = stars[y]; if( x == -1 ) continue; g.drawLine( x, y, x, y + 1); } painting = false; }
  9. 9. TimerDemo.java protected void keyPressed( int keyCode ){ exit(); } } }
  10. 10. Sprite สไปรต์  Sprite  Sprite Frames  Frame sequence  Sprite transforms  Sprite drawing  Sprite collision sprite [N] ; เทพยดา Syn. elf; fairy Related. เทวดา, เทพธิดา, ภูต, นา
  11. 11. หลักการสร้างภาพเคลือนไหว ่ บนมือถือ (Animation) การสร้างภาพต่าง ๆ ที่เคลื่อนทีบนโทรศัพท์จะต้อง ่ แสดงภาพต่าง ๆ ด้วย ความเร็วอย่างน้อย 12 เฟรม (frame) ต่อวินาที แต่ ถ้าแต่ละภาพเคลื่อนที่ด้วย ความเร็ว 25 fps (frames per second) ภาพจะ เคลื่อนที่ด้วยความนุ่มนวลมาก ในการพัฒนา MIDlet ต่าง ๆ ของภาพเคลือนไหว จะ ่ ต้องคำานึงถึงความเร็วใน การแสดงเฟรมของภาพบนโทรศัพท์มือถือ เนื่องจาก โทรศัพท์มือถือ
  12. 12. ประเภทของภาพเคลื่อนไหว ( Type of Animation) แบ่งออกเป็น 2 ประเภท คือ • ภาพเคลื่อนไหวขึ้นอยู่กับเฟรม (frame-based Animation) • ภาพเคลื่อนไหวขึ้นอยู่กับการเคลื่อนที่ สิ่งต่าง ๆ ภายในเฟรม (Cast-based Animation)
  13. 13. Sprite สไปรต์ (Sprite) เป็นออปเจ็กต์ทาง กราฟฟิกที่สามารถ เคลื่อนที่อย่างอิสระบนพื้นหลัง (Background) หรือออปเจ็กต์อื่น
  14. 14. การสร้างภาพเคลือนไหวของส ่ ไปรต์ (Creating Sprite Animation) คลาส Sprite จะให้การสนับสนุนภาพ เคลื่อนไหวของเฟรม (frame) ในลักษณะอะเรย์ (Array) ของภาพต่าง ๆ ของ เฟรมและช่วยจำาแนกประเภทภาพเคลือนไหว ่ เมธอด (method) ต่าง ๆ ของคลาส Sprite  สร้างสไปรต์  การเคลื่อนที่ของสไปรต์  ตรวจสอบการชนกันของสไปรต์
  15. 15. คุณลักษณะต่าง ๆ ของสไปรต์ (Sprite Properties) • ตำาแหน่ง x: ใช้แทนพิกด (coordinate) ของสไปรต์ในแนว ั ระดับ ที่คอลัมน์ซายสุดของจอภาพ ้ ตำาแหน่ง x เป็น 0 คอลัมน์ขวาสุดของจอภาพกว้าง 100 จุด (pixel) เป็น 99 • ตำาแหน่ง y: ใช้แทนพิกัดของสไปรต์ในแนวดิ่ง แถวบนสุด ของจอภาพ ตำาแหน่ง y เป็น 0 แถวล่างสุดของจอภาพยาว 100 จุด (pixel) ตำาแหน่ง y จะเป็น 99 • ความเร็ว Vx: ใช้แทนความเร็วของสไปรต์ (ระยะที่สไปรต์ เคลื่อนที่ในแต่ละครั้ง) ในแนวระดับ นั่นคือ ทุก ๆ เฟรม (frame) สไปรต์จะเคลื่อนที่ Vx จุด (pixel) ถ้า Vx ค่าเป็นลบสไปรต์ จะเคลื่อนที่ไปทางซ้ายมือ นอกนั้นมันจะเคลื่อนทีไปทาง ่ ขวามือ
  16. 16. Sprite Properties • width: ใช้แทนความกว้างของภาพกราฟฟิก ของสไปรต์ เมื่อใช้ร่วมงานกับตำาแหน่ง x มัน จะกำาหนดขอบขวามือของสไปรต์บนพิกัด x • height: ใช้แทนความสูงของภาพกราฟฟิก ของสไปรต์ เมื่อใช้ร่วมงานกับตำาแหน่ง y มัน จะกำาหนดขอบล่างสุดของสไปรต์บนพิกัด y
  17. 17. Sprite : Constructor Sprite (Image image) สร้าง single frame sprite, non-animated Sprite (Sprite sprite) สร้าง sprite จาก sprite ตัวอื่น Sprite (Image image, int frameWidth, int frameHeight) สร้าง animated-sprite จาก Image โดยสร้างเป็น frame จาก image
  18. 18. frameWidth frameHeight frame index 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
  19. 19. NOTE !!  Really be careful !!!!  ตอนที่เราสร้าง Sprite จาก constructor Sprite (Image image, int frameWidth, int frameHeight)  ถ้า frameWidth, frameHeight ไม่ลงตัวกับ Image ที่สร้าง Sprite จะเกิด IllegalArgumentException  เช่นถ้า Image มีขนาด 40*80 แต่เราสร้าง Sprite s = new Sprite(im,24,7) แบบนี้ ไม่
  20. 20. Sprite: method boolean collidesWith(Sprite s, boolean pixelLevel) boolean collidesWIth(TiledLayer t, boolean pixelLevel) void defineCollisionRectangle(int x, int y, int w, int h) void defineReferencePixel(int x, int y) int getFrame() int getFrameSequenceLength() void nextFrame() void paint(Graphics g) void prevFrame() void setFrame(int sequenceIndex) void setFrameSequence(int[] sequence) void setTransform(int transform)
  21. 21. SpriteDemoMIDlet.java  สร้าง GameCanvas ให้แสดง Sprite สองจุด โดย ใช้ method nextFrame() และ prevFrame() ใน การแสดงผล 128 pixels 192 pixels
  22. 22. SpriteDemoMIDlet.java import java.io.IOException; import javax.microedition.lcdui.*; import javax.microedition.lcdui.game.*; import javax.microedition.midlet.MIDlet; import javax.microedition.midlet.MIDletStateChangeException; public class SpriteDemoMIDlet extends MIDlet { GameCanvasSprite1 canvas = new GameCanvasSprite1(); public SpriteDemoMIDlet() {} protected void destroyApp(boolean arg0) throws MIDletStateChangeException {} protected void pauseApp() {} protected void startApp() throws MIDletStateChangeException { Display display = Display.getDisplay(this); canvas.start(); display.setCurrent(canvas); } }
  23. 23. class GameCanvasSprite1 extends GameCanvas implements Runnable { Sprite hero, hero2; boolean running; protected GameCanvasSprite1() { super(true); Image im = null,im2 =null; try { im = Image.createImage("/sprites/c1.png"); im2 = Image.createImage("/sprites/c2.png"); } catch (IOException e) { } hero = new Sprite(im,32,48); // (128 / 4) = 32 hero2 = new Sprite(im2,32,48); // (192 / 4) = 48 } public void start(){ running = true; Thread t = new Thread(this); t.start(); }
  24. 24. public void run() { Graphics g = getGraphics(); int delay = 100; while(running){ drawScreen(g); hero.nextFrame(); hero2.prevFrame(); try {Thread.sleep(delay);} catch (InterruptedException e) { } } } void drawScreen(Graphics g){ int w = getWidth(); int h = getHeight(); g.setColor(237,143,237); g.fillRect(0, 0, w, h); g.setColor(0); g.drawString("Sprite Demo", 0, getHeight()- 20, g.TOP | g.LEFT); hero.setPosition(w/2-50, h/2); hero.paint(g); hero2.setPosition(w/2+50, h/2); hero2.paint(g); flushGraphics(); } }
  25. 25. สร้าง Direction  สร้าง int[] ของ direction แต่ละตัว เช่น  int[] frontDirection = {0,1,2,3};  int[] leftDirection = {4,5,6,7}; ** ขึ้นอยู่กับรูป sprite ของเราว่าหันไปทิศทางใดก่อน**  สร้าง thread ให้รบค่า input และ drawScreen ั โดยหากมีการกด key ให้เช็คว่า keyใดถูกกด เปลี่ยน direction ไปในทิศทางนัน และใช้ ้ method sprite.setFrameSequence(int[]) เพื่อ เปลี่ยน frame index ของ sprite ในการแสดงผล  **ในตัวอย่างเราสร้างเป็น int[][] เพื่อเก็บ sequence เพื่อให้เขียน code ง่ายขึ้น **
  26. 26. class GameCanvasSprite2 extends GameCanvas implements Runnable{ static int FRONT_DIRECTION = 0; //สร้าง static int เพื่อใหง่ายในการเขียน code static int LEFT_DIRECTION = 1; static int RIGHT_DIRECTION = 2; static int BACK_DIRECTION = 3; ง Sprite hero; boolean running; ่า int[][] sequence = { {0,1,2,3}, //front {4,5,6,7}, //left ย {8,9,10,11}, //right {12,13,14,15}}; //back อ int w, h; int cx,cy; ัว int currentDirection = FRONT_DIRECTION; ต protected GameCanvasSprite2() { super(true); Image im = null; try {im = Image.createImage("/sprites/c1.png");} catch (IOException e) { } hero = new Sprite(im,32,48); w = getWidth(); h = getHeight(); cx = w/2; cy = h/2; hero.setFrameSequence(sequence[0]); }
  27. 27. ง public void start(){ ่า running = true; Thread t = new Thread(this); ย t.start(); } อ public void run() { ัว Graphics g = getGraphics(); int delay = 40; ต while(running){ getInput(); drawScreen(g); hero.nextFrame(); try {Thread.sleep(delay);} catch (InterruptedException e) { } } } void drawScreen(Graphics g){ int w = getWidth(); int h = getHeight(); g.setColor(0); g.fillRect(0, 0, w, h); hero.setPosition(cx, cy); hero.paint(g); flushGraphics(); }
  28. 28. void getInput(){ int keyState = getKeyStates(); // เก็บทิศทางปั จจุบนไว้ เพ่ ือเช็คว่ามีการเปล่ียนทิศทางหรือไม่ ั int cDirection = currentDirection; if(keyState== LEFT_PRESSED){ cx--; cx = Math.max(0, cx); currentDirection= LEFT_DIRECTION; ง } ่า else if(keyState== RIGHT_PRESSED){ cx++; cx = Math.min(cx, w); ย currentDirection= RIGHT_DIRECTION; } อ else if(keyState== UP_PRESSED){ cy--; cy = Math.max(0, cy); ัว currentDirection= BACK_DIRECTION; } ต else if(keyState== DOWN_PRESSED){ cy++; cy = Math.min(cy, h); currentDirection= FRONT_DIRECTION; } if(cDirection != currentDirection){ //เช็คว่ามีการเปลี่ยน direction หรือเปล่า หากเปลี่ยนให้ setFrameSequence // ใหม่เพื่อให้ได้ frame sequence ที่ตรงกับทิศทางเดิม hero.setFrameSequence(sequence[currentDirection]); } } }
  29. 29. SpriteDemoMIDlet2.java  สร้าง GameCanvas ให้แสดง Sprite โดยแสดง ตำาแหน่ งและทิศทาง ตาม key ท่กดคือ ี  left  right  up  down
  30. 30. SpriteDemoMIDlet2.java import java.io.IOException; import javax.microedition.lcdui.*; import javax.microedition.lcdui.game.*; import javax.microedition.midlet.MIDlet; import javax.microedition.midlet.MIDletStateChangeException; public class SpriteDemoMIDlet2 extends MIDlet { GameCanvasSprite2 canvas = new GameCanvasSprite2(); public SpriteDemoMIDlet2() {} protected void destroyApp(boolean arg0) throws MIDletStateChangeException {} protected void pauseApp() {} protected void startApp() throws MIDletStateChangeException { Display display = Display.getDisplay(this); canvas.start(); display.setCurrent(canvas); } }
  31. 31. class GameCanvasSprite2 extends GameCanvas implements Runnable{ static int FRONT_DIRECTION = 0; static int LEFT_DIRECTION = 1; static int RIGHT_DIRECTION = 2; static int BACK_DIRECTION = 3; Sprite hero; boolean running; /* int[] frontSequence ={0,1,2,3}; int[] leftSequence ={4,5,6,7}; int[] rightSequence ={8,9,10,11}; int[] backSequence ={12,13,14,15}; */ int[][] sequence = {{0,1,2,3}, //front {4,5,6,7}, //left {8,9,10,11}, //right {12,13,14,15}}; //back int w, h; int cx,cy; int currentDirection = FRONT_DIRECTION;
  32. 32. protected GameCanvasSprite2() { super(true); Image im = null; try { im = Image.createImage("/sprites/c1.png"); } catch (IOException e) {} hero = new Sprite(im,32,48); w = getWidth(); h = getHeight(); cx = w/2; cy = h/2; hero.setFrameSequence(sequence[0]); } public void start(){ running = true; Thread t = new Thread(this); t.start(); }
  33. 33. public void run() { Graphics g = getGraphics(); int delay = 100; while(running){ getInput(); drawScreen(g); try {Thread.sleep(delay);} catch (InterruptedException e) { } } }
  34. 34. void getInput(){ int keyState = getKeyStates(); int cDirection = currentDirection; // then we know current direction if(keyState== LEFT_PRESSED) { cx = cx - 5; cx = Math.max(0, cx); currentDirection= LEFT_DIRECTION; hero.nextFrame(); } else if(keyState== RIGHT_PRESSED){ cx = cx + 5; cx = Math.min(cx, w-32); currentDirection= RIGHT_DIRECTION; hero.nextFrame(); } else if(keyState== UP_PRESSED){ cy = cy - 5; cy = Math.max(0, cy); currentDirection= BACK_DIRECTION; hero.nextFrame(); } else if(keyState== DOWN_PRESSED) { cy = cy + 5; cy = Math.min(cy, h - 48); currentDirection= FRONT_DIRECTION; hero.nextFrame(); } if(cDirection != currentDirection) { hero.setFrameSequence(sequence[currentDirection]); } }
  35. 35. void drawScreen(Graphics g){ int w = getWidth(); int h = getHeight(); g.setColor(213,234,149); g.fillRect(0, 0, w, h); hero.setPosition(cx, cy); hero.paint(g); g.setColor(0,0,255); g.drawString("Sprite Demo ["+cx+","+cy+"]", 0, getHeight() - 20, g.TOP | g.LEFT); flushGraphics(); } }
  36. 36. --- END ---

×