国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

cleverpig分享用MIDP實現(xiàn)貪吃蛇游戲的全過程

2019-11-18 16:19:25
字體:
供稿:網(wǎng)友

  本文由Matrix的j2me版版主cleverpig原創(chuàng).
clever是Matrix j2me版版主
cleverpig的blog: http://www.matrix.org.cn/blog/cleverpig
本文原址:http://matrix.org.cn/forum_view.asp?forum_id=4&view_id=17199

貪吃蛇是一款非常經(jīng)典的手機游戲,本文將使用MIDP實現(xiàn)這款著名的游戲。首先我將介紹下主要用到的七個類:

   WormMain:最主要的類,控制所有其它類的運行和銷毀。

   WormPit:處理鍵盤輸入事件并實例化Worm類和WormFood類的。

   Worm:抽象了貪吃蛇的屬性和動作

   WormFood:抽象了食物的屬性和動作

   WormScore:用來紀(jì)錄分?jǐn)?shù)的類

   WormLink:抽象了蛇身上的一段,保存了這段的坐標(biāo)、方向和所有狀態(tài)。

   WormException:處理異常類

基本概念介紹

   節(jié):一條蛇可以看成有許多正方形的“小格子”拼湊成,我把它稱作節(jié)。節(jié)是蛇身上最小的單位。

   段:當(dāng)許多節(jié)連成一條直線,我稱它為段。上圖的貪吃蛇只有一段,如果它拐彎就變成兩段。

   鏈表:用來保存每一段的狀態(tài),鏈表的元素單位是段。且鏈表的最后一個元素表示蛇的頭部段。

   坐標(biāo)系:MIDP中的坐標(biāo)以左上角那點為(0,0),向右則x遞增,向下則y遞增。

worm類

  一條完整的貪吃蛇是由一段一段組成的。鏈表中保存的第一個元素是蛇的尾巴段,最后一個元素是蛇的頭部段。當(dāng)蛇運動的時候,它頭部段增加一節(jié)而尾段減少一節(jié)。如果它吃到了食物,尾部段就不減少一節(jié)。也就是說,蛇是從頭部段開始長的。

  下面的代碼段顯示了Worm類保存的各種屬性:

/* 貪吃蛇可能移動的方向 */

public final static byte DOWN = 2;

public final static byte LEFT = 4;

public final static byte RIGHT = 6;

public final static byte UP = 8;

// 貪吃蛇的當(dāng)前方向

PRivate byte currentDirection;

// 保存貪吃蛇每一段的列表

private Vector worm = new Vector(5, 2);

// 是否需要更新狀態(tài)

private boolean needUpdate;

// 是否在運動中

private boolean moveOnNextUpdate;

// 是否吃到食物

private boolean hasEaten;

// 貪吃蛇的初始位置、長度和方向

private final static int INIT_X = 3;

private final static int INIT_Y = 8;

private final static int INIT_LEN = 8;

private final static byte INIT_DIR =RIGHT;


下面重點介紹下Worm類中的幾個方法:

public void setDirection(byte direction)

  這個方法用來改變貪吃蛇運動的方向,只能90度。看下面的實現(xiàn)代碼:

if ((direction != currentDirection) && !needUpdate) {

// 取出列表中的最后一個元素(蛇的頭部)

WormLink sl = (WormLink)worm.lastElement();

int x = sl.getEndX();

int y = sl.getEndY();

// 不同的運動方向坐標(biāo)的改變也不一樣

switch (direction) {

case UP: // 當(dāng)這段向上運動的時候

if (currentDirection != DOWN) {

y--; needUpdate = true; }

break;

case DOWN: // 當(dāng)這段向下運動的時候

if (currentDirection != UP) {

y++; needUpdate = true; }

break;

case LEFT: // 當(dāng)這段向左運動的時候

if (currentDirection != RIGHT) {

x--; needUpdate = true; }

break;

case RIGHT: // 當(dāng)這段向右運動的時候

if (currentDirection != LEFT) {

x++; needUpdate = true; }

break; }

// 當(dāng)更改方向后需要更新

if (needUpdate == true) {

worm.addElement(new WormLink(x, y, 0, direction));

currentDirection = direction; } }

  public void update(Graphics g)

  這個函數(shù)是更新貪吃蛇狀態(tài)。每次更新都把頭部增加一節(jié),尾部減少一節(jié)。如果它吃到食物尾部段就不減少一節(jié)。看起來就像整只蛇長了一節(jié)。

// 把貪吃蛇頭部增加一格

head = (WormLink)worm.lastElement();

head.increaseLength();

// 如果沒有吃到食物則尾部減少一格

if (!hasEaten) {

WormLink tail;

tail = (WormLink)worm.firstElement();

int tailX = tail.getX();

int tailY = tail.getY();

// 如果尾部塊長度為0就刪除

tail.decreaseLength();

if (tail.getLength() == 0) {

worm.removeElement(tail); }

// 尾部減少一格

g.setColor(WormPit.ERASE_COLOUR);

drawLink(g, tailX, tailY, tailX, tailY, 1);

} else {

// 如果吃到食物就不刪除尾部

hasEaten = false; }

needUpdate = false;

// 確認(rèn)是否在邊界中

if (!WormPit.isInBounds(head.getEndX(), head.getEndY())) {

// 如果不在,就死了

throw new WormException("over the edge"); }

headX = (byte)head.getEndX();

headY = (byte)head.getEndY();

//貪吃蛇的頭部增加一格

g.setColor(WormPit.DRAW_COLOUR);

drawLink(g, headX, headY, headX, headY, 1);

// 判斷是否吃到自己

for (int i = 0; i < worm.size()-1; i++) {

sl = (WormLink)worm.elementAt(i);

if (sl.contains(headX, headY)) {

throw new WormException("you ate yourself"); } }

  void drawLink(Graphics g, int x1, int y1, int x2, int y2, int len)

  這個函數(shù)用來畫蛇的一段,一只完整的蛇是一段一段組成的。

// 把長度轉(zhuǎn)換成像素長度

len *= WormPit.CELL_SIZE;

// (x1 == x2)說明這一段是垂直的

if (x1 == x2) {

// 把x1轉(zhuǎn)成像素長度

x1 *= WormPit.CELL_SIZE;

// (y2 < y1)說明是向上運動

if (y2 < y1) {

// 就把頭、尾左邊交換并轉(zhuǎn)成像素

y1 = y2 * WormPit.CELL_SIZE;

} else {

// 把y1轉(zhuǎn)成像素

y1 *= WormPit.CELL_SIZE; }

g.fillRect(x1, y1, WormPit.CELL_SIZE, len);

} else {

// 這是水平的一段

y1 *= WormPit.CELL_SIZE;

if (x2 < x1) {

// 就把頭、尾左邊交換并轉(zhuǎn)成像素

x1 = x2 * WormPit.CELL_SIZE;

} else {

x1 *= WormPit.CELL_SIZE; }

g.fillRect(x1, y1, len, WormPit.CELL_SIZE); }

  public void paint(Graphics g)

  畫出一只完整的貪吃蛇

WormLink sl;

int x1, x2, y1, y2;

int len;

for (int i = 0; i < worm.size(); i++) {

// 取出每一段,然后畫出這一段,連起來就是一只完整的蛇

sl = (WormLink)worm.elementAt(i);

x1 = sl.getX(); x2 = sl.getEndX();

y1 = sl.getY(); y2 = sl.getEndY();

len = sl.getLength();

drawLink(g, x1, y1, x2, y2, len); }


wormlink類

  貪吃蛇是由一節(jié)一節(jié)組成的。因為它經(jīng)常有一些節(jié)連成一條直線形成段,所以這是一種相對有效的方法來保存整個蛇。[X,Y]表示段頭部的坐標(biāo),然后段的頭部開始按照方向向后畫若干節(jié)。(段的頭尾和蛇的頭尾不是一個概念)

  下面代碼段是WormLink中的段得屬性:

// 段頭部坐標(biāo)

private int x, y;

// 段長度

private int len;

// 移動方向

private byte dir;

  下面重點介紹幾個重要函數(shù):

  public void decreaseLength()

  這是從段的頭部減少一格

// 首先段的總長度減少1

len--;

switch (dir) { // 不同的方向左邊的改變也不一樣

case Worm.LEFT:

x--; break;

case Worm.RIGHT:

x++; break;

case Worm.UP:

y--; break;

case Worm.DOWN:

y++; break; }

  public boolean contains(int x, int y)

  判斷所給的坐標(biāo)(x,y)是否包含在段中

switch (dir) { // 不同的方向判斷的方法也不一樣

case Worm.LEFT:

return ((y == this.y) && ((x <= this.x) && (x >= getEndX())));

case Worm.RIGHT:

return ((y == this.y) && ((x >= this.x) && (x <= getEndX())));

case Worm.UP:

return ((x == this.x) && ((y <= this.y) && (y >= getEndY())));

case Worm.DOWN:

return ((x == this.x) && ((y >= this.y) && (y <= getEndY())));

}

  public int getEndX()

  得到這一段的尾部x坐標(biāo)(段方向指向的最后一格的坐標(biāo)),當(dāng)這段是蛇的頭部段時,得到的是頭部最前面的坐標(biāo)。

// 不同的方向判斷方法不一樣

if (dir == Worm.LEFT)

return x-len;

if (dir == Worm.RIGHT)

return x+len;

return x;


wormpit類

  WormPit類中包括了Worm和WormFood。貪吃蛇將會在畫面中移動尋找食物。如果它吃到食物它將會長一格。如果它碰到邊界或者吃到自己將Game Over。

  下面介紹幾個重要的函數(shù):

  private void paintPitContents(Graphics g) 

  重繪屏幕上的所有元素

// 更新貪吃蛇的狀態(tài)

myWorm.update(g);

// 頭部的位置和食物的位置重合就吃到食物

if (myFood.isAt(myWorm.getX(), myWorm.getY())) {

myWorm.eat();

score += level;

foodEaten++;

if (foodEaten > (level << 1)) {

/* 增加游戲難度 */

forceRedraw = true;

foodEaten = 0;

level++;

if (tonePlayer != null) {

try {

tonePlayer.setMediaTime(0);

tonePlayer.start();

} catch (MediaException me) { } }

} else {

if (audioPlayer != null) {

try {

Manager.playTone(69, 50, 100); // Play audio

} catch (MediaException me) { } } }

g.setColor(WormPit.ERASE_COLOUR);

// 填充長方形(三個字的寬度)

g.fillRect((width - (SCORE_CHAR_WIDTH * 3))-START_POS,

height-START_POS,

(SCORE_CHAR_WIDTH * 3),

SCORE_CHAR_HEIGHT);

g.setColor(WormPit.DRAW_COLOUR);

// 顯示新的分?jǐn)?shù)

g.drawString("" + score,

width - (SCORE_CHAR_WIDTH * 3) - START_POS,

height - START_POS, Graphics.TOPGraphics.LEFT);

// 重新生成食物

myFood.regenerate();

int x = myFood.getX();

int y = myFood.getY();

while (myWorm.contains(x, y)) {

// 如果食物和貪吃蛇的身體重復(fù)就重新生成

myFood.regenerate();

x = myFood.getX(); y = myFood.getY(); } }

// 畫出食物

myFood.paint(g);

} catch (WormException se) { gameOver = true; }

  public void run()

  主循環(huán)體:

while (!gameDestroyed) { // 游戲不終止就一直循環(huán)執(zhí)行

try {

synchronized (myWorm) { // 多線程中要進行同步

// 如果游戲結(jié)束

if (gameOver) {

if (WormScore.getHighScore(level) < score) {

// 把最高分保存

WormScore.setHighScore(level, score, "me"); }

if ((audioPlayer != null) &&

(audioPlayer.getState() == Player.STARTED)) {

try {

audioPlayer.stop();

Manager.playTone(60, 400, 100);

} catch (Exception ex) { } }

// 重繪

repaint();

// 游戲結(jié)束時等待用戶重新開始

myWorm.wait();

} else if (gamePaused) {

//重繪

repaint();

// 游戲暫停時等待用戶重新開始

myWorm.wait();

} else {

// 游戲繼續(xù)

myWorm.moveOnUpdate();

repaint();

// 這里的等待時間決定了游戲難度!!!

myWorm.wait(DEFAULT_WAIT-(level*40));

}

}

} catch (java.lang.InterruptedException ie) {

}

}

  
wormmain類

  最主要的類,繼承自MIDlet父類并實現(xiàn)了CommandListener接口。

  protected void startApp()

  實現(xiàn)MIDlet父類的方法,當(dāng)開始程序時首先執(zhí)行這個函數(shù)

// 顯示畫板

Display.getDisplay(this).setCurrent(theGame);

try {

// 開始游戲線程

Thread myThread = new Thread(theGame);

myThread.start();

} catch (Error e) {

destroyApp(false);

notifyDestroyed(); }

public void commandAction(Command c, Displayable d)

  接受并處理用戶輸入事件

// 重新開始

if (c == restartCmd) {

theGame.restart();

};

// 改變難度等級

if (c == levelCmd) {

Item[] levelItem = {//請自己替換[]

new Gauge("Level", true, 9, theGame.getLevel())

};

Form f = new Form("Change Level", levelItem);

f.addCommand(OKCmd);

f.addCommand(cancelCmd);

f.setCommandListener(this);

Display.getDisplay(this).setCurrent(f);

};

// 離開游戲

if (c == exitCmd) {

 destroyApp(false);

 notifyDestroyed();

};

// 開始游戲

if (c == startCmd) {

theGame.removeCommand(startCmd);

theGame.addCommand(restartCmd);

theGame.restart();

};

// 確定

if (c == OKCmd) {

Form f = (Form)d;

Gauge g = (Gauge)f.get(0);

theGame.setLevel(g.getvalue());

Display.getDisplay(this).setCurrent(theGame);

};

// 取消

if (c == cancelCmd) {

Display.getDisplay(this).setCurrent(theGame);

};

// 打開音效

if (c == audioOnCmd) {

/* 打開音效 */

theGame.createAudioPlayer();

theGame.removeCommand(audioOnCmd);

theGame.addCommand(audioOffCmd);

};

// 關(guān)閉音效

if (c == audioOffCmd) {

/* 關(guān)閉音效 */

theGame.destroyAudioPlayer();

theGame.removeCommand(audioOffCmd);

theGame.addCommand(audioOnCmd);

}
進入討論組討論。

(出處:http://m.survivalescaperooms.com)



發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 伊吾县| 武强县| 大英县| 米易县| 德清县| 巧家县| 邹城市| 克东县| 沙洋县| 湄潭县| 喀喇| 新竹市| 大名县| 石景山区| 宁城县| 新营市| 罗平县| 西峡县| 磴口县| 商城县| 屏东县| 赣榆县| 玉门市| 常宁市| 行唐县| 嘉荫县| 江川县| 改则县| 万全县| 辽阳县| 舟山市| 保康县| 洪雅县| 万年县| 赣州市| 宁化县| 阿荣旗| 怀远县| 横山县| 常山县| 佳木斯市|