目錄
6、在res裏創建drawable目錄,在裏面創建按鈕背景選擇器
7、在app子包裏創建應用程序常量接口AppConstants
8、在app子包裏創建貪喫蛇應用程序類SnakeApplicaiton
12、在ui子包裏創建貪喫蛇界面類SnakeActivity
(1)貪喫蛇界面佈局文件activity_snake.xml
13、在ui子包裏創建選擇地圖界面類SelectMapActivity
(1)在values裏的styles.xml裏增加單選按鈕和按鈕的樣式定義
(2)選擇地圖界面佈局文件activity_select_map.xml
14、在ui子包裏創建設置速度界面類SetSpeedActivity
(1)設置速度界面佈局文件activity_set_speed.xml
15、在ui子包裏創建選擇背景音樂界面類SelectMusicActivity
(1)選擇背景音樂界面佈局文件activity_select_music.xml
(3)選擇背景音樂界面類SelectMusicActivity
16、在ui子包裏創建排行榜界面類TopListActivity
(1)排行榜界面佈局文件activity_top_list.xml
(1)啓動界面佈局文件activity_splash_screen.xml
項目圖片素材【百度網盤下載網址 密碼:gcpt】
一、功能要求
1、遊戲規則
玩家使用方向鍵或手勢滑動操控一條長長的蛇不斷吞蘋果,同時蛇身隨着吞下的蘋果不斷長,當蛇頭撞到蛇身或障壁時遊戲結束。
2、遊戲設置
玩家可選擇地圖、設置背景音樂、選擇蛇移動速度。
3、遊戲排行榜
提供玩家排行榜,顯示前三名分數(貪喫蛇喫掉蘋果的數量)
二、運行效果
1、啓動界面
2、遊戲主控界面
3、選擇地圖
4、設置速度
5、選擇背景音樂
6、開始遊戲
7、遊戲結束
8、查看排行榜
9、查看幫助信息
10、關於作者
三、涉及知識點
1、佈局
2、常用控件
3、線程
4、消息處理器
5、自定義視圖
6、圖形圖像繪製
7、媒體播放器
8、集合類
四、項目結構圖
五、項目實現
1、創建安卓項目:貪喫蛇V1.0
2、修改包名
說明:net.hw.snake爲根包,ui子包用於存放界面類。
3、創建子包entity、app與view
4、準備圖片素材,拷貝到drawable-mdpi目錄裏
5、在res裏創建raw文件夾,拷貝幾首mp3音樂
6、在res裏創建drawable目錄,在裏面創建按鈕背景選擇器
(1)開始遊戲按鈕背景選擇器
(2)選擇地圖按鈕背景選擇器
(3)選擇背景音樂按鈕背景選擇器
(4)設置速度按鈕背景選擇器
(5)排行榜按鈕背景選擇器
(6)關於作者按鈕背景選擇器
(7)幫助信息按鈕背景選擇器
(8)退出遊戲按鈕背景選擇器
7、在app子包裏創建應用程序常量接口AppConstants
/**
* 功能:應用程序常量接口
* 作者:華衛
* 日期:2017年1月1日
*/
package net.hw.snake.app;
import android.app.Activity;
public interface AppConstants {
/**
* 應用程序標記
*/
String TAG = "net.hw.snake";
/**
* 地圖常量
*/
int O_SHAPE_MAP = 0;
int I_SHAPE_MAP = 1;
int X_SHAPE_MAP = 2;
int Z_SHAPE_MAP = 3;
int U_SHAPE_MAP = 4;
/**
* 速度常量
*/
int LOW_SPEED = 0;
int MEDIUM_SPEED = 1;
int HIGH_SPEED = 2;
/**
* 排行榜配置文件名
*/
String TOP_LIST_FILE_NAME = "toplist";
/**
* 文件訪問模式
*/
int ACCESS_MODE = Activity.MODE_PRIVATE;
/**
* 遊戲狀態常量
*/
int PAUSE = 0;
int READY = 1;
int RUNNING = 2;
int LOSE = 3;
/**
* 移動方向常量
*/
int NORTH = 1;
int SOUTH = 2;
int EAST = 3;
int WEST = 4;
/**
* 圖片常量
*/
int RED_STAR = 1;
int YELLOW_STAR = 2;
int GREEN_STAR = 3;
/**
* 蛇兩次移動之間的間隔
*/
int SHORT_INTERVAL = 100;
int MEDIUM_INTERVAL = 350;
int LONG_INTERVAL = 600;
/**
* 前三名分數
*/
String SCORE_OF_FIRST = "score_of_first";
String SCORE_OF_SECOND = "score_of_second";
String SCORE_OF_THIRD = "score_of_third";
}
8、在app子包裏創建貪喫蛇應用程序類SnakeApplicaiton
/**
* 功能:貪喫蛇應用程序類
* 作者:華衛
* 日期:2017年1月1日
*/
package net.hw.snake.app;
import android.app.Application;
import android.media.MediaPlayer;
public class SnakeApplication extends Application {
/**
* 地圖索引
*/
private int mapIndex;
/**
* 背景音樂索引
*/
private int musicIndex;
/**
* 速度索引
*/
private int speedIndex;
/**
* 媒體播放器
*/
private MediaPlayer mediaPlayer;
@Override
public void onCreate() {
super.onCreate();
}
public int getMapIndex() {
return mapIndex;
}
public void setMapIndex(int mapIndex) {
this.mapIndex = mapIndex;
}
public int getMusicIndex() {
return musicIndex;
}
public void setMusicIndex(int musicIndex) {
this.musicIndex = musicIndex;
}
public int getSpeedIndex() {
return speedIndex;
}
public void setSpeedIndex(int speedIndex) {
this.speedIndex = speedIndex;
}
public MediaPlayer getMediaPlayer() {
return mediaPlayer;
}
public void setMediaPlayer(MediaPlayer mediaPlayer) {
this.mediaPlayer = mediaPlayer;
}
}
9、在entity子包裏創建座標實體類Coordinate
/**
* 功能:座標實體
* 作者:華衛
* 日期:2017年1月1日
*/
package net.hw.snake.entity;
public class Coordinate {
/**
* 橫座標
*/
public int x;
/**
* 縱座標
*/
public int y;
/**
* 構造方法
*
* @param x
* @param y
*/
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
/**
* 相等方法(判斷兩點是否重合)
*/
public boolean equals(Object obj) {
if (obj instanceof Coordinate) {
Coordinate other = (Coordinate) obj;
if (x == other.x && y == other.y) {
return true;
}
}
return false;
}
@Override
public String toString() {
return "Coordinate: [" + x + "," + y + "]";
}
}
10、在view子包裏創建方磚視圖TileView
(1)在values目錄創建屬性文件attrs.xml
(2)方磚視圖類TileView
/**
* 功能:方磚視圖
* 作者:華衛
* 日期:2017年1月1日
*/
/**
* 控制方磚尺寸及其在視圖裏顯示範圍的參數,寬度與高度的單位是像素。
* 可繪製對象可以縮放來適合方磚尺寸,然後計算出橫向與縱向的方磚數。
*/
package net.hw.snake.view;
import net.hw.snake.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
public class TileView extends View {
/**
* 方磚尺寸
*/
protected static int mTileSize;
/**
* 橫向方磚數量
*/
protected static int mXTileCount;
/**
* 縱向方磚數量
*/
protected static int mYTileCount;
/**
* 橫向偏移量
*/
private static int mXOffset;
/**
* 縱向偏移量
*/
private static int mYOffset;
/**
* 方磚數組
*/
private Bitmap[] mTileArray;
/**
* 方磚網格
*/
private int[][] mTileGrid;
/**
* 畫筆
*/
private final Paint mPaint = new Paint();
/**
* 構造方法
*
* @param context
* @param attrs
* @param defStyle
*/
public TileView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TileView);
mTileSize = a.getInt(R.styleable.TileView_tileSize, 12);
a.recycle();
}
/**
* 構造方法
*
* @param context
* @param attrs
*/
public TileView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TileView);
mTileSize = a.getInt(R.styleable.TileView_tileSize, 12);
a.recycle();
}
/**
* 重置方磚
*
* @param tilecount
*/
public void resetTiles(int tileCount) {
mTileArray = new Bitmap[tileCount];
}
/**
* 屏幕尺寸發生變化時觸發,重新計算橫向與縱向方磚數以及橫向與縱向的偏移量,設置方磚網格
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
// 橫向方磚數
mXTileCount = (int) Math.floor(w / mTileSize);
// 縱向方磚數
mYTileCount = (int) Math.floor(h / mTileSize);
// 橫向偏移量
mXOffset = ((w - (mTileSize * mXTileCount)) / 2);
// 縱向偏移量
mYOffset = ((h - (mTileSize * mYTileCount)) / 2);
// 方磚網格
mTileGrid = new int[mXTileCount][mYTileCount];
// 清除方磚
clearTiles();
}
/**
* 加載方磚
*
* @param key
* @param tile
*/
public void loadTile(int key, Drawable tile) {
Bitmap bitmap = Bitmap.createBitmap(mTileSize, mTileSize, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
tile.setBounds(0, 0, mTileSize, mTileSize);
tile.draw(canvas);
mTileArray[key] = bitmap;
}
/**
* 清空方磚
*/
public void clearTiles() {
for (int x = 0; x < mXTileCount; x++) {
for (int y = 0; y < mYTileCount; y++) {
// 第一個參數爲0,表明不畫方磚
setTile(0, x, y);
}
}
}
/**
* 設置方磚
*
* @param tileIndex
* @param x
* @param y
*/
public void setTile(int tileIndex, int x, int y) {
// 在x行y列畫指定的方磚
mTileGrid[x][y] = tileIndex;
}
/**
* 繪製方法
*/
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int x = 0; x < mXTileCount; x += 1) {
for (int y = 0; y < mYTileCount; y += 1) {
if (mTileGrid[x][y] > 0) {
canvas.drawBitmap(mTileArray[mTileGrid[x][y]],
mXOffset + x * mTileSize, mYOffset + y * mTileSize, mPaint);
}
}
}
}
}
11、在view子包裏創建貪喫蛇視圖SnakeView
/**
* 功能:貪喫蛇視圖
* 作者:華衛
* 日期:2017年1月1日
*/
package net.hw.snake.view;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.TextView;
import net.hw.snake.R;
import net.hw.snake.app.AppConstants;
import net.hw.snake.app.SnakeApplication;
import net.hw.snake.entity.Coordinate;
public class SnakeView extends TileView implements AppConstants {
/**
* 共享參數
*/
private SharedPreferences sp;
/**
* 編輯器
*/
private Editor editor;
/**
* 名次信息
*/
private String rankMsg;
/**
* 遊戲狀態變量
*/
public int mMode = READY;
/**
* 蛇當前移動方向
*/
public int mDirection = EAST;
/**
* 蛇下一個移動方向
*/
public int mNextDirection = EAST;
/**
* 分數:蛇喫掉的蘋果數量
*/
private int mScore = 0;
/**
* 蛇移動的時間間隔
*/
private int mMoveDelay = 600;
/**
* 蛇上次移動的時間
*/
private long mLastMove;
/**
* 蛇身數組列表
*/
private ArrayList<Coordinate> mSnakeTrail = new ArrayList<Coordinate>();
/**
* 蘋果數組列表
*/
private ArrayList<Coordinate> mAppleList = new ArrayList<Coordinate>();
/**
* 牆壁數組列表
*/
private ArrayList<Coordinate> mWallList = new ArrayList<Coordinate>();
/**
* 隨機對象
*/
private static final Random RNG = new Random();
/**
* 貪喫蛇應用程序
*/
private SnakeApplication app;
/**
* 負責重繪的消息處理器
*/
private class RefreshHandler extends Handler {
@Override
public void handleMessage(Message msg) {
// 更新貪喫蛇視圖
SnakeView.this.update();
// 重繪貪喫蛇視圖
SnakeView.this.invalidate();
}
public void sleep(long delayMillis) {
// 清空消息隊列
this.removeMessages(0);
// 延遲發送消息
sendMessageDelayed(obtainMessage(0), delayMillis);
}
}
/**
* 聲明負責重繪的消息處理器
*/
private RefreshHandler mRedrawHandler = new RefreshHandler();
/**
* 貪喫蛇視圖構造方法
*
* @param context
* @param attrs
*/
public SnakeView(Context context, AttributeSet attrs) {
super(context, attrs);
// 獲取貪喫蛇應用程序對象
app = (SnakeApplication) ((Activity) context).getApplication();
// 初始化貪喫蛇視圖
initSnakeView();
}
/**
* 構造貪喫蛇視圖
*
* @param context
* @param attrs
* @param defStyle
*/
public SnakeView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// 獲取貪喫蛇應用程序對象
app = (SnakeApplication) ((Activity) context).getApplication();
// 初始化貪喫蛇視圖
initSnakeView();
}
/**
* 初始化貪喫蛇視圖
*/
private void initSnakeView() {
// 設置爲可獲得焦點
setFocusable(true);
// 重置方磚(四種方磚)
resetTiles(4);
// 加載紅星方磚
loadTile(RED_STAR, getContext().getResources().getDrawable(R.drawable.redstar));
// 加載黃星方磚
loadTile(YELLOW_STAR, getContext().getResources().getDrawable(R.drawable.yellowstar));
// 加載綠星方磚
loadTile(GREEN_STAR, getContext().getResources().getDrawable(R.drawable.greenstar));
// 加載音樂
switch (app.getMusicIndex()) {
case 0:
// 音樂:夢中的婚禮
app.setMediaPlayer(MediaPlayer.create(getContext(), R.raw.dream));
break;
case 1:
// 音樂:秋日私語
app.setMediaPlayer(MediaPlayer.create(getContext(), R.raw.autumn));
break;
case 2:
// 音樂:天空之城
app.setMediaPlayer(MediaPlayer.create(getContext(), R.raw.sky));
break;
case 3:
// 音樂:致愛麗絲
app.setMediaPlayer(MediaPlayer.create(getContext(), R.raw.alice));
break;
case 4:
// 歌曲:貝爾加湖畔
app.setMediaPlayer(MediaPlayer.create(getContext(), R.raw.lake));
case 5:
// 歌曲:暗香
app.setMediaPlayer(MediaPlayer.create(getContext(), R.raw.fragrance));
}
// 設置爲循環播放
app.getMediaPlayer().setLooping(true);
// 創建共享參數對象
sp = getContext().getSharedPreferences(TOP_LIST_FILE_NAME, ACCESS_MODE);
// 獲得編輯器
editor = sp.edit();
}
/**
* 初始化新遊戲
*/
public void initNewGame() {
// 清除蛇
mSnakeTrail.clear();
// 清除所有蘋果
mAppleList.clear();
// 初始蛇,三節,朝東移動
mSnakeTrail.add(new Coordinate(7, 7));
mSnakeTrail.add(new Coordinate(6, 7));
mSnakeTrail.add(new Coordinate(5, 7));
mNextDirection = EAST;
// 更新牆壁
updateWalls();
// 隨機添加兩個蘋果
addRandomApple();
addRandomApple();
// 根據用戶設置速度修改初始的蛇兩次移動時間間隔初始值
switch (app.getSpeedIndex()) {
case LOW_SPEED:
mMoveDelay = LONG_INTERVAL;
break;
case MEDIUM_SPEED:
mMoveDelay = MEDIUM_INTERVAL;
break;
case HIGH_SPEED:
mMoveDelay = SHORT_INTERVAL;
break;
}
// 初始化遊戲得分
mScore = 0;
}
/**
* 將數組列表轉換成數組
*
* @param cvec
* 座標對象的數組列表
* @return 包含座標值的簡單數組,如 [x1,y1,x2,y2,x3,y3...]
*/
private int[] coordArrayListToArray(ArrayList<Coordinate> cvec) {
int count = cvec.size();
int[] rawArray = new int[count * 2];
for (int index = 0; index < count; index++) {
Coordinate c = cvec.get(index);
rawArray[2 * index] = c.x;
rawArray[2 * index + 1] = c.y;
}
return rawArray;
}
/**
* 保存遊戲狀態,那麼在後臺遊戲進程被殺掉也不會丟失任何數據
*
* @return 保存視圖狀態的數據包
*/
public Bundle saveState() {
Bundle map = new Bundle();
map.putIntArray("mAppleList", coordArrayListToArray(mAppleList));
map.putInt("mDirection", Integer.valueOf(mDirection));
map.putInt("mNextDirection", Integer.valueOf(mNextDirection));
map.putLong("mMoveDelay", Integer.valueOf(mMoveDelay));
map.putLong("mScore", Integer.valueOf(mScore));
map.putIntArray("mSnakeTrail", coordArrayListToArray(mSnakeTrail));
return map;
}
/**
* 恢復遊戲狀態
*
* @param data
* 包含遊戲狀態的數據包
*/
public void restoreState(Bundle data) {
// 設置遊戲模式爲暫停
setMode(PAUSE);
mAppleList = coordArrayToArrayList(data.getIntArray("mAppleList"));
mDirection = data.getInt("mDirection");
mNextDirection = data.getInt("mNextDirection");
mMoveDelay = data.getInt("mMoveDelay");
mScore = data.getInt("mScore");
mSnakeTrail = coordArrayToArrayList(data.getIntArray("mSnakeTrail"));
}
/**
* 將座標對構成的數組轉換成座標對象的數組列表
*
* @param rawArray
* : [x1,y1,x2,y2,...]
* @return 座標對象的數組列表
*/
private ArrayList<Coordinate> coordArrayToArrayList(int[] rawArray) {
ArrayList<Coordinate> coordArrayList = new ArrayList<Coordinate>();
int coordCount = rawArray.length;
for (int index = 0; index < coordCount; index += 2) {
Coordinate c = new Coordinate(rawArray[index], rawArray[index + 1]);
coordArrayList.add(c);
}
return coordArrayList;
}
/*
* 按鍵事件處理
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent msg) {
// 按上方向鍵
if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
if (mMode == READY | mMode == LOSE) {
// 開始新遊戲
initNewGame();
// 設置爲運行模式
setMode(RUNNING);
// 播放音樂
app.getMediaPlayer().start();
// 更新遊戲界面
update();
return (true);
}
if (mMode == PAUSE) {
setMode(RUNNING);
update();
return (true);
}
if (mDirection != SOUTH) {
mNextDirection = NORTH;
}
return (true);
}
// 按下方向鍵
if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
if (mDirection != NORTH) {
mNextDirection = SOUTH;
}
return (true);
}
// 按左方向鍵
if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
if (mDirection != EAST) {
mNextDirection = WEST;
}
return (true);
}
// 按右方向鍵
if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
if (mDirection != WEST) {
mNextDirection = EAST;
}
return (true);
}
return super.onKeyDown(keyCode, msg);
}
/**
* 設置遊戲模式
*
* @param newMode
*/
public void setMode(int newMode) {
int oldMode = mMode;
mMode = newMode;
if (newMode == RUNNING & oldMode != RUNNING) {
update();
app.getMediaPlayer().start();
return;
}
if (newMode == LOSE) {
app.getMediaPlayer().stop();
try {
app.getMediaPlayer().prepare();
app.getMediaPlayer().seekTo(0);
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 隨機添加蘋果
*/
private void addRandomApple() {
Coordinate newCoord = null;
boolean found = false;
while (!found) {
// 爲蘋果選擇新位置
int newX = 1 + RNG.nextInt(mXTileCount - 2);
int newY = 1 + RNG.nextInt(mYTileCount - 2);
newCoord = new Coordinate(newX, newY);
boolean collision = false;
// 判斷新產生的蘋果有沒有與蛇或者牆碰撞
if (mSnakeTrail.contains(newCoord) || mWallList.contains(newCoord)) {
collision = true;
}
// 如果碰撞了,就表明沒找到合適位置,還要繼續找
found = !collision;
}
if (newCoord == null) {
Log.e(TAG, "新座標爲空!");
}
mAppleList.add(newCoord);
}
/**
* 更新方法:檢查是否處於運行狀態,決定是否該移動,更新蛇的位置
*/
public void update() {
if (mMode == RUNNING) {
long now = System.currentTimeMillis();
if (now - mLastMove > mMoveDelay) {
clearTiles();
updateWalls();
updateSnake();
updateApples();
mLastMove = now;
}
mRedrawHandler.sleep(mMoveDelay);
}
}
/**
* 更新牆壁
*
*/
private void updateWalls() {
for (int x = 0; x < mXTileCount; x++) {
setTile(GREEN_STAR, x, 0);
setTile(GREEN_STAR, x, mYTileCount - 1);
mWallList.add(new Coordinate(x, 0));
mWallList.add(new Coordinate(x, mYTileCount - 1));
}
for (int y = 1; y < mYTileCount - 1; y++) {
setTile(GREEN_STAR, 0, y);
setTile(GREEN_STAR, mXTileCount - 1, y);
mWallList.add(new Coordinate(0, y));
mWallList.add(new Coordinate(mXTileCount - 1, y));
}
switch (app.getMapIndex()) {
case I_SHAPE_MAP: // 工字型地圖
for (int x = 6; x < mXTileCount - 6; x++) {
setTile(GREEN_STAR, x, 20);
mWallList.add(new Coordinate(x, 20));
}
for (int y = 20; y <= mYTileCount - 20; y++) {
setTile(GREEN_STAR, mXTileCount / 2, y);
mWallList.add(new Coordinate(mXTileCount / 2, y));
}
for (int x = 6; x < mXTileCount - 6; x++) {
setTile(GREEN_STAR, x, mYTileCount - 20);
mWallList.add(new Coordinate(x, mYTileCount - 20));
}
break;
case X_SHAPE_MAP: // X字型地圖
for (int x = 10, y = 20; x < mXTileCount - 10 && y < mYTileCount - 20; x++, y++) {
setTile(GREEN_STAR, x, y);
mWallList.add(new Coordinate(x, y));
}
for (int x = mXTileCount - 10, y = 20; x >= 10 && y < mYTileCount - 20; x--, y++) {
setTile(GREEN_STAR, x, y);
mWallList.add(new Coordinate(x, y));
}
break;
case Z_SHAPE_MAP: // Z字型地圖
for (int x = 6; x < mXTileCount - 6; x++) {
setTile(GREEN_STAR, x, 20);
mWallList.add(new Coordinate(x, 20));
}
for (int x = mXTileCount - 6, y = 20; y <= 35; y++) {
setTile(GREEN_STAR, x, y);
mWallList.add(new Coordinate(x, y));
}
for (int x = 6; x < mXTileCount - 6; x++) {
setTile(GREEN_STAR, x, 35);
mWallList.add(new Coordinate(x, 35));
}
for (int x = 6, y = 35; y <= mYTileCount - 20; y++) {
setTile(GREEN_STAR, x, y);
mWallList.add(new Coordinate(x, y));
}
for (int x = 6; x < mXTileCount - 6; x++) {
setTile(GREEN_STAR, x, mYTileCount - 20);
mWallList.add(new Coordinate(x, mYTileCount - 20));
}
break;
case U_SHAPE_MAP: // U字型地圖
for (int x = 6, y = 20; y < mYTileCount - 20; y++) {
setTile(GREEN_STAR, x, y);
mWallList.add(new Coordinate(x, y));
}
for (int x = mXTileCount - 7, y = 20; y < mYTileCount - 20; y++) {
setTile(GREEN_STAR, x, y);
mWallList.add(new Coordinate(x, y));
}
for (int x = 6; x < mXTileCount - 6; x++) {
setTile(GREEN_STAR, x, mYTileCount - 20);
mWallList.add(new Coordinate(x, mYTileCount - 20));
}
break;
}
}
/**
* 更新蘋果
*/
private void updateApples() {
for (Coordinate c : mAppleList) {
setTile(YELLOW_STAR, c.x, c.y);
}
}
/**
* 更新蛇
*/
private void updateSnake() {
// 設置蛇生長狀態
boolean growSnake = false;
// 通過蛇頭來抓住蛇
Coordinate head = mSnakeTrail.get(0);
Coordinate newHead = new Coordinate(1, 1);
mDirection = mNextDirection;
// 根據蛇移動方向決定蛇頭座標
switch (mDirection) {
case EAST:
newHead = new Coordinate(head.x + 1, head.y);
break;
case WEST:
newHead = new Coordinate(head.x - 1, head.y);
break;
case NORTH:
newHead = new Coordinate(head.x, head.y - 1);
break;
case SOUTH:
newHead = new Coordinate(head.x, head.y + 1);
break;
}
// 判斷是否撞牆
if (mWallList.contains(newHead)) {
// 遊戲失敗
setMode(LOSE);
// 更新排行榜
updateTopList();
// 停止音樂播放
app.getMediaPlayer().stop();
try {
app.getMediaPlayer().prepare();
app.getMediaPlayer().seekTo(0);
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setIcon(R.drawable.ic_launcher);
builder.setTitle("遊戲結束");
if (mScore > 0) {
builder.setMessage("呵呵,你喫掉了" + mScore + "個蘋果!" + rankMsg);
} else {
builder.setMessage("遺憾,你一個蘋果也沒有喫掉!");
}
builder.setPositiveButton("返回主界面", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// 設置遊戲模式爲準備就緒
setMode(READY);
// 關閉當前界面
((Activity) getContext()).finish();
}
});
builder.setNegativeButton("再來玩一次", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// 初始化新遊戲
initNewGame();
// 設置遊戲模式爲運行
setMode(RUNNING);
// 播放音樂
app.getMediaPlayer().start();
// 更新遊戲
update();
}
});
builder.show();
}
// 判斷是否撞到自己
if (mSnakeTrail.contains(newHead)) {
// 遊戲失敗
setMode(LOSE);
// 更新排行榜
updateTopList();
// 停止音樂播放
app.getMediaPlayer().stop();
try {
app.getMediaPlayer().prepare();
app.getMediaPlayer().seekTo(0);
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setIcon(R.drawable.ic_launcher);
builder.setTitle("遊戲結束");
if (mScore > 0) {
builder.setMessage("呵呵,你喫掉了" + mScore + "個蘋果!" + rankMsg);
} else {
builder.setMessage("遺憾,你一個蘋果也沒有喫掉!");
}
builder.setPositiveButton("返回主界面", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
setMode(READY);
((Activity) getContext()).finish();
}
});
builder.setNegativeButton("再來玩一次", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// 初始化新遊戲
initNewGame();
// 設置遊戲模式爲運行
setMode(RUNNING);
// 播放音樂
app.getMediaPlayer().start();
// 更新遊戲
update();
}
});
builder.show();
}
// 檢測是否碰撞了蘋果
int applecount = mAppleList.size();
for (int appleindex = 0; appleindex < applecount; appleindex++) {
Coordinate c = mAppleList.get(appleindex);
if (c.equals(newHead)) {
mAppleList.remove(c);
addRandomApple();
// 得一分
mScore++;
switch (app.getSpeedIndex()) {
case LOW_SPEED:
mMoveDelay *= 0.9;
break;
case MEDIUM_SPEED:
mMoveDelay *= 0.8;
break;
case HIGH_SPEED:
mMoveDelay *= 0.7;
}
// 蛇生長狀態設置爲真
growSnake = true;
}
}
// 在蛇頭添加新元素
mSnakeTrail.add(0, newHead);
// 如果蛇不生長,那麼去掉蛇尾一個元素
if (!growSnake) {
mSnakeTrail.remove(mSnakeTrail.size() - 1);
}
// 重新繪製蛇(蛇頭設置爲黃磚,蛇身設置爲紅磚)
int index = 0;
for (Coordinate c : mSnakeTrail) {
if (index == 0) {
setTile(YELLOW_STAR, c.x, c.y);
} else {
setTile(RED_STAR, c.x, c.y);
}
index++;
}
}
/**
* 更新排行榜
*/
private void updateTopList() {
// 獲取前三名分數
int scoreOfFirst = sp.getInt(SCORE_OF_FIRST, 0);
int scoreOfSecond = sp.getInt(SCORE_OF_SECOND, 0);
int scoreOfThird = sp.getInt(SCORE_OF_THIRD, 0);
if (mScore > scoreOfFirst) {
rankMsg = "恭喜你獲得第一名!";
editor.putInt(SCORE_OF_FIRST, (int) mScore);
editor.putInt(SCORE_OF_SECOND, scoreOfSecond);
editor.putInt(SCORE_OF_THIRD, scoreOfThird);
} else if (mScore > scoreOfSecond) {
rankMsg = "恭喜你獲得第二名!";
editor.putInt(SCORE_OF_SECOND, (int) mScore);
editor.putInt(SCORE_OF_THIRD, scoreOfSecond);
} else if (mScore > scoreOfThird) {
rankMsg = "恭喜你獲得第三名!";
editor.putInt(SCORE_OF_THIRD, (int) mScore);
} else {
rankMsg = "加油啊,爭取進入排行榜!";
}
// 提交數據
editor.commit();
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mMode == READY) {
initNewGame();
setMode(RUNNING);
app.getMediaPlayer().start();
}
if (mMode == LOSE) {
// 繪製背景圖像
Paint paint = new Paint();
Bitmap background = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.lose);
canvas.drawBitmap(background, 0, 0, paint);
}
}
}
12、在ui子包裏創建貪喫蛇界面類SnakeActivity
(1)貪喫蛇界面佈局文件activity_snake.xml
(2)貪喫蛇界面類SnakeActivity
/**
* 功能:貪喫蛇界面
* 作者:華衛
* 日期:2017年1月1日
*/
/**
* 貪喫蛇: 人人都可以享受的簡單遊戲。
* 這是經典遊戲“貪喫蛇”的一個實現。你控制一條在花園裏遊動着尋找蘋果的蛇。
* 當心,蛇吃了蘋果,不僅要變長,而且移動速度會更快,只要蛇撞牆就結束遊戲。
*/
package net.hw.snake.ui;
import android.app.Activity;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.widget.TextView;
import net.hw.snake.R;
import net.hw.snake.app.AppConstants;
import net.hw.snake.app.SnakeApplication;
import net.hw.snake.view.SnakeView;
public class SnakeActivity extends Activity implements OnGestureListener, AppConstants {
/**
* 貪喫蛇視圖
*/
private SnakeView mSnakeView;
/**
* 手勢偵測器
*/
private GestureDetector detector;
/**
* 貪喫蛇應用程序
*/
private SnakeApplication app;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 利用佈局資源文件設置用戶界面
setContentView(R.layout.activity_snake);
// 通過資源標識獲得控件實例
mSnakeView = (SnakeView) findViewById(R.id.snake);
// 獲取貪喫蛇應用程序對象
app = (SnakeApplication) getApplication();
// 初始化手勢偵測器
detector = new GestureDetector(this, this);
// 貪喫蛇視圖獲得焦點
mSnakeView.requestFocus();
// 判斷是否保存過遊戲示例狀態數據
if (savedInstanceState == null) {
// 剛剛啓動———開啓一次新遊戲
mSnakeView.setMode(READY);
} else {
// 恢復貪喫蛇遊戲狀態數據
Bundle map = savedInstanceState.getBundle(TAG);
if (map != null) {
mSnakeView.restoreState(map);
} else {
// 設置貪喫蛇視圖爲暫停模式
mSnakeView.setMode(PAUSE);
}
}
}
/**
* 暫停回調方法
*/
@Override
protected void onPause() {
super.onPause();
// 隨窗口暫停而將貪喫蛇遊戲視圖設置爲暫停模式
mSnakeView.setMode(PAUSE);
// 暫停背景音樂
app.getMediaPlayer().pause();
}
@Override
public void onSaveInstanceState(Bundle outState) {
// 存儲遊戲狀態數據
outState.putBundle(TAG, mSnakeView.saveState());
}
/**
* 銷燬回調方法
*/
@Override
protected void onDestroy() {
super.onDestroy();
// 停止背景音樂
app.getMediaPlayer().stop();
// 釋放媒體播放器資源
app.setMediaPlayer(null);
}
// 將窗口的觸碰事件交給手勢偵測器來處理
@Override
public boolean onTouchEvent(MotionEvent event) {
return detector.onTouchEvent(event);
}
@Override
public boolean onDown(MotionEvent e) {
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// 手勢向上滑動
if (e2.getY() < e1.getY() - 20) {
if (mSnakeView.mMode == READY | mSnakeView.mMode == LOSE) {
// 開始新遊戲
mSnakeView.initNewGame();
// 設置爲運行模式
mSnakeView.setMode(RUNNING);
// 播放音樂
app.getMediaPlayer().start();
// 更新遊戲界面
mSnakeView.update();
}
if (mSnakeView.mMode == PAUSE) {
mSnakeView.setMode(RUNNING);
mSnakeView.update();
}
if (mSnakeView.mDirection != SOUTH) {
mSnakeView.mNextDirection = NORTH;
}
}
// 手勢向下滑動
if (e2.getY() > e1.getY() + 20) {
if (mSnakeView.mDirection != NORTH) {
mSnakeView.mNextDirection = SOUTH;
}
}
// 手勢向左滑動
if (e2.getX() < e1.getX() - 20) {
if (mSnakeView.mDirection != EAST) {
mSnakeView.mNextDirection = WEST;
}
}
// 手勢向右滑動
if (e2.getX() > e1.getX() + 20) {
if (mSnakeView.mDirection != WEST) {
mSnakeView.mNextDirection = EAST;
}
}
return true;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
}
13、在ui子包裏創建選擇地圖界面類SelectMapActivity
(1)在values裏的styles.xml裏增加單選按鈕和按鈕的樣式定義
(2)選擇地圖界面佈局文件activity_select_map.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/mapback"
android:gravity="center"
android:orientation="vertical" >
<RadioGroup
android:id="@+id/rg_map"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="80dp" >
<RadioButton
android:id="@+id/rb_o_map"
style="@style/rb_style"
android:checked="true"
android:text="@string/o_map" />
<RadioButton
android:id="@+id/rb_i_map"
style="@style/rb_style"
android:text="@string/i_map" />
<RadioButton
android:id="@+id/rb_x_map"
style="@style/rb_style"
android:text="@string/x_map" />
<RadioButton
android:id="@+id/rb_z_map"
style="@style/rb_style"
android:text="@string/z_map" />
<RadioButton
android:id="@+id/rb_u_map"
style="@style/rb_style"
android:text="@string/u_map" />
</RadioGroup>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:gravity="center_horizontal" >
<Button
android:id="@+id/btn_ok"
style="@style/btn_style"
android:onClick="doOK"
android:text="@string/ok" />
<Button
android:id="@+id/btn_cancel"
style="@style/btn_style"
android:onClick="doCancel"
android:text="@string/cancel" />
</LinearLayout>
</LinearLayout>
(3)選擇地圖界面類SelectMapActivity
/**
* 功能:選擇地圖
* 作者:華衛
* 日期:2017年1月1日
*/
package net.hw.snake.ui;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.RadioButton;
import net.hw.snake.R;
import net.hw.snake.app.AppConstants;
import net.hw.snake.app.SnakeApplication;
public class SelectMapActivity extends Activity implements AppConstants {
/**
* 口字型地圖的單選按鈕
*/
private RadioButton rbOMap;
/**
* 工字型地圖的單選按鈕
*/
private RadioButton rbIMap;
/**
* X型地圖的單選按鈕
*/
private RadioButton rbXMap;
/**
* Z型地圖的單選按鈕
*/
private RadioButton rbZMap;
/**
* U型地圖的單選按鈕
*/
private RadioButton rbUMap;
/**
* 貪喫蛇應用程序
*/
private SnakeApplication app;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 利用佈局資源文件設置用戶界面
setContentView(R.layout.activity_select_map);
// 通過資源標識獲得界面控件實例
rbOMap = (RadioButton) findViewById(R.id.rb_o_map);
rbIMap = (RadioButton) findViewById(R.id.rb_i_map);
rbXMap = (RadioButton) findViewById(R.id.rb_x_map);
rbZMap = (RadioButton) findViewById(R.id.rb_z_map);
rbUMap = (RadioButton) findViewById(R.id.rb_u_map);
// 獲取貪喫蛇應用程序對象
app = (SnakeApplication) getApplication();
// 設置地圖單選按鈕初始狀態
switch (app.getMapIndex()) {
case O_SHAPE_MAP: // 口字型地圖
rbOMap.setChecked(true);
break;
case I_SHAPE_MAP: // I字型地圖
rbIMap.setChecked(true);
break;
case X_SHAPE_MAP: // X字型地圖
rbXMap.setChecked(true);
break;
case Z_SHAPE_MAP: // Z字型地圖
rbZMap.setChecked(true);
break;
case U_SHAPE_MAP: // U字型地圖
rbUMap.setChecked(true);
break;
}
}
/**
* 確定按鈕單擊事件處理方法
*
* @param view
*/
public void doOK(View view) {
// 根據單選按鈕選中狀態設置地圖索引
if (rbOMap.isChecked()) {
// 設置口字型地圖
app.setMapIndex(O_SHAPE_MAP);
} else if (rbIMap.isChecked()) {
// 設置工字型地圖
app.setMapIndex(I_SHAPE_MAP);
} else if (rbXMap.isChecked()) {
// 設置X字型地圖
app.setMapIndex(X_SHAPE_MAP);
} else if (rbZMap.isChecked()) {
// 設置Z字型地圖
app.setMapIndex(Z_SHAPE_MAP);
} else if (rbUMap.isChecked()) {
// 設置U字型地圖
app.setMapIndex(U_SHAPE_MAP);
}
// 關閉當前界面
finish();
}
/**
* 取消按鈕單擊事件處理方法
*
* @param view
*/
public void doCancel(View view) {
// 關閉當前界面
finish();
}
}
14、在ui子包裏創建設置速度界面類SetSpeedActivity
(1)設置速度界面佈局文件activity_set_speed.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/speedback"
android:gravity="center"
android:orientation="vertical" >
<RadioGroup
android:id="@+id/rg_speed"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<RadioButton
android:id="@+id/rb_low_speed"
style="@style/rb_style"
android:checked="true"
android:text="@string/low_speed" />
<RadioButton
android:id="@+id/rb_medium_speed"
style="@style/rb_style"
android:text="@string/medium_speed" />
<RadioButton
android:id="@+id/rb_high_speed"
style="@style/rb_style"
android:text="@string/high_speed" />
</RadioGroup>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:gravity="center_horizontal" >
<Button
android:id="@+id/btn_ok"
style="@style/btn_style"
android:text="@string/ok"
android:onClick="doOK" />
<Button
android:id="@+id/btn_cancel"
style="@style/btn_style"
android:text="@string/cancel"
android:onClick="doCancel"/>
</LinearLayout>
</LinearLayout>
(2)設置速度界面類SetSpeedActivity
/**
* 功能:設置速度
* 作者:華衛
* 日期:2017年1月1日
*/
package net.hw.snake.ui;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.RadioButton;
import net.hw.snake.R;
import net.hw.snake.app.AppConstants;
import net.hw.snake.app.SnakeApplication;
public class SetSpeedActivity extends Activity implements AppConstants{
/**
* 低速單選按鈕
*/
private RadioButton rbLowSpeed;
/**
* 中速單選按鈕
*/
private RadioButton rbMediumSpeed;
/**
* 高速單選按鈕
*/
private RadioButton rbHighSpeed;
/**
* 貪喫蛇應用程序
*/
private SnakeApplication app;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 利用佈局資源文件設置用戶界面
setContentView(R.layout.activity_set_speed);
// 通過資源索引獲得界面控件實例
rbLowSpeed = (RadioButton) findViewById(R.id.rb_low_speed);
rbMediumSpeed = (RadioButton) findViewById(R.id.rb_medium_speed);
rbHighSpeed = (RadioButton) findViewById(R.id.rb_high_speed);
// 獲取貪喫蛇應用程序對象
app = (SnakeApplication) getApplication();
// 設置速度單選按鈕的初始狀態
switch (app.getSpeedIndex()) {
case LOW_SPEED: // 低速
rbLowSpeed.setChecked(true);
break;
case MEDIUM_SPEED: // 中速
rbMediumSpeed.setChecked(true);
break;
case HIGH_SPEED: // 高速
rbHighSpeed.setChecked(true);
break;
}
}
/**
* 確定按鈕單擊事件處理方法
*
* @param view
*/
public void doOK(View view) {
// 設置速度索引
if (rbLowSpeed.isChecked()) {
// 設置低速
app.setSpeedIndex(LOW_SPEED);
} else if (rbMediumSpeed.isChecked()) {
// 設置中速
app.setSpeedIndex(MEDIUM_SPEED);
} else if (rbHighSpeed.isChecked()) {
// 設置高速
app.setSpeedIndex(HIGH_SPEED);
}
// 關閉當前界面
finish();
}
/**
* 取消按鈕單擊事件處理方法
*
* @param view
*/
public void doCancel(View view) {
// 關閉當前界面
finish();
}
}
15、在ui子包裏創建選擇背景音樂界面類SelectMusicActivity
(1)選擇背景音樂界面佈局文件activity_select_music.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/musicback"
android:gravity="center"
android:orientation="vertical"
android:padding="20dp" >
<ListView
android:id="@+id/lv_music"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp" >
</ListView>
</LinearLayout>
(2)音樂列表項模板music_list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:gravity="center"
android:textColor="#000000"
android:textSize="20sp" />
(3)選擇背景音樂界面類SelectMusicActivity
/**
* 功能:選擇背景音樂
* 作者:華衛
* 日期:2017年1月1日
*/
package net.hw.snake.ui;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import net.hw.snake.R;
import net.hw.snake.app.SnakeApplication;
public class SelectMusicActivity extends Activity {
/**
* 音樂數組
*/
private String[] musics;
/**
* 數組適配器
*/
private ArrayAdapter<String> adapter;
/**
* 音樂列表控件
*/
private ListView lvMusic;
/**
* 貪喫蛇應用程序
*/
private SnakeApplication app;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 利用佈局資源文件設置用戶界面
setContentView(R.layout.activity_select_music);
// 通過資源索引獲得界面控件實例
lvMusic = (ListView) findViewById(R.id.lv_music);
// 獲取貪喫蛇應用程序對象
app = (SnakeApplication) getApplication();
// 初始化音樂數組
musics = new String[] { "夢中的婚禮", "秋日的私語", "天空之城", "致愛麗絲", "貝爾加湖畔", "暗香" };
// 創建數組適配器
adapter = new ArrayAdapter<String>(this, R.layout.music_list_item, musics);
// 給列表視圖對象設置適配器
lvMusic.setAdapter(adapter);
// 給音樂列表控件註冊監聽器
lvMusic.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
// 設置背景音樂索引
app.setMusicIndex(position);
// 彈出吐司提示用戶
Toast.makeText(SelectMusicActivity.this, "您選擇了【" + musics[position] + "】作爲背景音樂!", Toast.LENGTH_LONG)
.show();
// 關閉當前界面
finish();
}
});
}
}
16、在ui子包裏創建排行榜界面類TopListActivity
(1)排行榜界面佈局文件activity_top_list.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/toplistback"
android:gravity="center"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_first"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="80dp"
android:text="@string/first"
android:textColor="#0000ff"
android:textSize="20sp" />
<TextView
android:id="@+id/tv_second"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="@string/second"
android:textColor="#0000ff"
android:textSize="20sp" />
<TextView
android:id="@+id/tv_third"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="@string/third"
android:textColor="#0000ff"
android:textSize="20sp" />
<Button
android:id="@+id/btn_back"
style="@style/btn_style"
android:layout_marginTop="50dp"
android:text="@string/back"
android:onClick="doBack" />
</LinearLayout>
(2)在字符串資源文件strings.xml裏定義變量
(3)排行榜界面類TopListActivity
/**
* 功能:排行榜
* 作者:華衛
* 日期:2017年1月1日
*/
package net.hw.snake.ui;
import net.hw.snake.R;
import net.hw.snake.app.AppConstants;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class TopListActivity extends Activity implements AppConstants {
/**
* 第一名標籤
*/
private TextView tvFirst;
/**
* 第二名標籤
*/
private TextView tvSecond;
/**
* 第三名標籤
*/
private TextView tvThird;
/**
* 共享參數對象
*/
private SharedPreferences sp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 利用佈局資源文件設置用戶界面
setContentView(R.layout.activity_top_list);
// 通過資源索引獲得界面控件實例
tvFirst = (TextView) findViewById(R.id.tv_first);
tvSecond = (TextView) findViewById(R.id.tv_second);
tvThird = (TextView) findViewById(R.id.tv_third);
// 獲取共享參數對象
sp = getSharedPreferences(TOP_LIST_FILE_NAME, ACCESS_MODE);
// 在標籤上顯示前三名分數
tvFirst.setText("第一名:" + sp.getInt(SCORE_OF_FIRST, 0));
tvSecond.setText("第二名:" + sp.getInt(SCORE_OF_SECOND, 0));
tvThird.setText("第三名:" + sp.getInt(SCORE_OF_THIRD, 0));
}
/**
* 返回按鈕單擊事件處理方法
*
* @param view
*/
public void doBack(View view) {
// 關閉當前界面
finish();
}
}
17、在ui子包裏創建主界面類MainActivity
(1)主界面佈局文件activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/mainback"
android:gravity="center"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginTop="100dp"
android:text="@string/version"
android:textColor="#ff0000"
android:textSize="30sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:gravity="center"
android:orientation="horizontal" >
<Button
android:id="@+id/btn_start_game"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/start_game_button_selector"
android:onClick="doStartGame" />
<Button
android:id="@+id/btn_select_map"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/select_map_button_selector"
android:onClick="doSelectMap" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal" >
<Button
android:id="@+id/btn_set_speed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/set_speed_button_selector"
android:onClick="doSetSpeed" />
<Button
android:id="@+id/btn_select_music"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/select_music_button_selector"
android:onClick="doSelectMusic" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal" >
<Button
android:id="@+id/btn_top_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/top_list_button_selector"
android:onClick="doTopList" />
<Button
android:id="@+id/btn_help"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/help_button_selector"
android:onClick="doHelp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal" >
<Button
android:id="@+id/btn_about_author"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/about_author_button_selector"
android:onClick="doAboutAuthor" />
<Button
android:id="@+id/btn_exit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/exit_game_button_selector"
android:onClick="doExit" />
</LinearLayout>
</LinearLayout>
(2)字符串資源文件strings.xml裏定義變量
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">貪喫蛇V1.0</string>
<string name="version">Version1.0</string>
<string name="o_map">口字型地圖</string>
<string name="i_map">工字型地圖</string>
<string name="x_map">X字型地圖</string>
<string name="u_map">U字型地圖</string>
<string name="z_map">Z字型地圖</string>
<string name="low_speed">蛇移動速度:低速</string>
<string name="medium_speed">蛇移動速度:中速</string>
<string name="high_speed">蛇移動速度:高速</string>
<string name="ok">確定</string>
<string name="cancel">取消</string>
<string name="first">第一名:</string>
<string name="second">第二名:</string>
<string name="third">第三名:</string>
<string name="back">返回</string>
<string name="author_info">單位:瀘職院信息工程系\n作者:華衛\n電話:15892921170\n郵箱:[email protected]</string>
<string name="game_help">貪喫蛇又名貪食蛇,是一款經典的小遊戲。玩家使用方向鍵操控一條長長的蛇不斷吞蘋果,同時蛇身隨着吞下的蘋果不斷長,當蛇頭撞到蛇身或障壁時遊戲結束。</string>
<string name="action_settings">設置</string>
</resources>
(4)主界面類MainActivity
/**
* 功能:貪喫蛇主控界面
* 作者:華衛
* 日期:2017年1月1日
*/
package net.hw.snake.ui;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import net.hw.snake.R;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 利用佈局資源文件設置用戶界面
setContentView(R.layout.activity_main);
}
/**
* 啓動遊戲
*
* @param view
*/
public void doStartGame(View view) {
startActivity(new Intent(MainActivity.this, SnakeActivity.class));
}
/**
* 選擇地圖
*
* @param view
*/
public void doSelectMap(View view) {
startActivity(new Intent(MainActivity.this, SelectMapActivity.class));
}
/**
* 設置速度
*
* @param view
*/
public void doSetSpeed(View view) {
startActivity(new Intent(MainActivity.this, SetSpeedActivity.class));
}
/**
* 選擇背景音樂
*
* @param view
*/
public void doSelectMusic(View view) {
startActivity(new Intent(MainActivity.this, SelectMusicActivity.class));
}
/**
* 排行榜
*
* @param view
*/
public void doTopList(View view) {
startActivity(new Intent(MainActivity.this, TopListActivity.class));
}
/**
* 幫助信息
*
* @param view
*/
public void doHelp(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setIcon(R.drawable.ic_launcher);
builder.setTitle("幫助信息");
builder.setMessage(getResources().getString(R.string.game_help));
builder.setPositiveButton("確定", null);
builder.show();
}
/**
* 關於作者
*
* @param view
*/
public void doAboutAuthor(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setIcon(R.drawable.ic_launcher);
builder.setTitle("關於作者");
builder.setMessage(getResources().getString(R.string.author_info));
builder.setPositiveButton("確定", null);
builder.show();
}
/**
* 退出程序
*
* @param view
*/
public void doExit(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setIcon(R.drawable.snake);
builder.setTitle("溫馨提示");
builder.setMessage("您是否要退出【貪喫蛇】遊戲?");
builder.setPositiveButton("是", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
System.exit(0);
}
});
builder.setNegativeButton("否", null);
builder.show();
}
}
18、在ui子包裏修改啓動界面類SplashScreen
(1)啓動界面佈局文件activity_splash_screen.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/splashlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/splashback"
android:gravity="center_vertical"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginTop="170dp"
android:text="@string/version"
android:textColor="#ff00ff"
android:textSize="50sp" />
<TextView
android:id="@+id/tv_author"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginTop="100dp"
android:text="@string/author"
android:textColor="#0000ff"
android:textSize="16sp" />
</LinearLayout>
(2)字符串資源文件strings.xml裏定義變量
(3)啓動界面類SplashScreenActivity
/**
* 功能:啓動界面
* 作者:華衛
* 日期:2017年1月1日
*/
package net.hw.snake.ui;
import net.hw.snake.R;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;
public class SplashScreenActivity extends Activity {
/**
* 啓動畫面延遲時間
*/
private final int DELAY_TIME = 3000;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 利用佈局資源文件設置用戶界面
setContentView(R.layout.activity_splash_screen);
// 利用消息處理器延遲處理
new Handler().postDelayed(new Runnable() {
public void run() {
// 跳轉到主控界面
startActivity(new Intent(SplashScreenActivity.this,
MainActivity.class));
// 關閉啓動界面
finish();
}
}, DELAY_TIME);
}
}
19、項目清單文件設置全部界面都是全屏顯示
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.hw.snake"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="15" />
<application
android:name="net.hw.snake.app.SnakeApplication"
android:icon="@drawable/snake"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
<activity android:name="net.hw.snake.ui.SplashScreenActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="net.hw.snake.ui.MainActivity" />
<activity android:name="net.hw.snake.ui.SnakeActivity" />
<activity android:name="net.hw.snake.ui.SelectMapActivity" />
<activity android:name="net.hw.snake.ui.SelectMusicActivity" />
<activity android:name="net.hw.snake.ui.SelectSpeedActivity" />
<activity android:name="net.hw.snake.ui.TopListActivity" >
</activity>
</application>
</manifest>