android 簡單的貪吃蛇小遊戲
貪吃蛇是一款經典的小遊戲,遊戲比較簡單,實現也比較簡單。
本篇部落格將詳細介紹我自己寫的貪吃蛇的思路以及實現方式。
首先我們需要在遊戲介面將遊戲區域劃分成無數個小方格,類似下圖
畫布(遊戲區域)的寬為 width 高為 height ,列數 sizex=width/pointSize ,行數 sizey=height/pointSize. 由於畫布的長寬不一定是pointSize的整數倍,所以為了所有的資料居中需要設定 x軸 y軸的偏移量(當前貌似偏移量可有可無,本人強迫症一定要加上),offsetX=(width - sizex*pointSize)/ 2,offsetY=(height - sizey*pointSize) / 2.
新建陣列 spoints=new int[ sizex ][ sizey ] 用於儲存方格矩陣 其中 spoints[x][y]==1說明該點屬於當前小蛇身體的一部分, spoints[x][y]==0則表示小蛇當前未運動到此點。
新建 ArrayList<Point> points=new ArrayList<Point>(); 用於儲存小蛇的身體的所有節點(points 中的 所有point的x,y對應的是 spoints陣列的所有值為1的點的下標),points.get(0) 為頭部座標點,最後一個為尾部座標點
上面兩幅圖片代表的意思相同,都表示小蛇的當前狀態(小蛇畫的比較醜,請見諒)
下面開始考慮的小蛇的移動,小蛇的移動可以看成是將小蛇的尾巴的移動到小蛇的頭部(根據方向判斷移動的上下左右位置),其他的節點保持不動,見圖示
得到下圖運動後的狀態
然後修改spoints陣列對應的座標的值,新增的頭部對應的值修改為 1,移除的尾部的值修改為 0. 並將對應的座標點加入points連結串列的對應位置,移除尾部的座標點
解決了小蛇的移動問題,再來解決小蛇吃食物點的問題。
當小蛇吃到食物的時候,相當於將食物的點當成新的頭部,而尾部不變,這樣就相當於吃了之後變長了
這樣就完成了小蛇的增長。
沒有程式碼那就是耍流氓!!下面開始貼程式碼
git程式碼下載:
csdn下載:https://download.csdn.net/download/weixin_41191134/10832869
再提供一個數獨小遊戲的下載:https://download.csdn.net/download/weixin_41191134/10832903
只貼了要的遊戲介面的程式碼
public class TcsView extends View {
private Paint paint;
//小蛇的組成點
private ArrayList<Point> points=new ArrayList<Point>();
private Point pointFood=new Point();//食物點
//遊戲介面的 方格劃分
private int[][] spoints;
//方格陣列的大小
private int sizex;
private int sizey;
//小蛇的頭部對應在陣列中的位置
private int headerX;
private int headerY;
//食物的座標點
private int foodX;
private int foodY;
//偏移量
private int offsetX=0;
private int offsetY=0;
//隨機數
private Random random=new Random();
private boolean isStart=true;
//螢幕寬高
private int width;
private int height;
//小蛇方塊的大小
private int pointSize=20;
//方向
private int direction=0;// 0 上 -1 下 1 左 2 右
//觸控點座標
private float tdx;
private float tdy;
private boolean isStop=false;
private TcsScoreListener tcsScoreListener;
private Handler handler=new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message message) {
switch (message.what){
case 1:
headerNext();
break;
}
return false;
}
});
private void headerNext(){
if(points.size()==0||isStop||foodX==-1) return;
//小蛇的移動控制,可以看成是小蛇的首尾發生了移動,
// 頭部根據下一次移動的方向移動到下一格,然後去掉結尾
switch (direction){
case 0:
headerY--;
break;
case -1:
headerY++;
break;
case 1:
headerX--;
break;
case 2:
headerX++;
break;
}
//判斷是否到達邊界
if(headerX<0||headerY<0){
isStop=true;
}else {
//判斷小蛇是否吃到自己
if(spoints[headerX][headerY]==1){
isStop=true;
}
points.add(0,new Point(headerX,headerY));
spoints[headerX][headerY]=1;
if(tcsScoreListener!=null){
tcsScoreListener.onTCSScore(points.size());
}
if(headerX==foodX && headerY==foodY){
foodX=-1;
foodY=-1;
initPointFood();
}else {
Point move=points.get(points.size()-1);
spoints[move.x][move.y]=0;
points.remove(points.size() - 1);
}
if (!isStop){
invalidate();
}
}
}
public TcsView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
paint=new Paint();
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(1);
paint.setAntiAlias(true);
//100為時間的發生間隔,即小蛇多久移動一次,此處修改可調節小蛇的速度
new Timer().schedule(new TimerTask() {
@Override
public void run() {
handler.sendEmptyMessage(1);
}
},0,100);
}
public void setTcsScoreListener(TcsScoreListener tcsScoreListener) {
this.tcsScoreListener = tcsScoreListener;
}
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
width=getWidth();
height=getHeight();
if(isStart){
//根據寬高以及 pointSize 將遊戲區域劃分成不同的矩形區塊,
sizex=width/pointSize;
sizey=height/pointSize;
spoints=new int[sizex][sizey];
//計算偏移量
offsetX=(width-(sizex*pointSize))/2;
offsetY=(height-(sizey*pointSize))/2;
//頭部起始座標預設在螢幕中央
headerX=sizex/2;
headerY=sizey/2;
spoints[headerX][headerY]=1;
points.add(0,new Point(headerX,headerY));
initPointFood();
isStart=false;
}
for(int i=0;i<points.size();i++){
Point point=points.get(i);
drawPoint(canvas,paint,point);
}
drawPoint(canvas,paint,pointFood);
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
if(!isStop) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
tdx = event.getX();
tdy = event.getY();
break;
case MotionEvent.ACTION_UP:
float dx = Math.abs(tdx - event.getX());
float dy = Math.abs(tdy - event.getY());
if (dx > 40 || dy > 40) {
//判斷為滑動,不是點選
Log.d("*****onTouchEvent****", "/**/*/*//*////*98*8/*9*/89*898565/*** ");
} else {
if (direction == 0 || direction == -1) {
if (tdx > points.get(0).x) {
direction = 2;
} else {
direction = 1;
}
} else if (direction == 1 || direction == 2) {
if (tdy > points.get(0).y) {
direction = -1;
} else {
direction = 0;
}
}
handler.sendEmptyMessage(1);
}
break;
}
}
return super.onTouchEvent(event);
}
//根據點的左邊畫出對應的點
private void drawPoint(Canvas canvas,Paint paint,Point point){
RectF rectF=new RectF(
offsetX+point.x*pointSize,
offsetY+point.y*pointSize,
offsetX+(point.x+1)*pointSize,
offsetY+(point.y+1)*pointSize);
canvas.drawRect(rectF,paint);
}
/**
* 確定食物點的位置
*/
private void initPointFood(){
foodX=random.nextInt(sizex);//獲取隨機的座標點
foodY=random.nextInt(sizey);
//判斷當前座標點是否在小蛇的軌跡上
if(spoints[foodX][foodY]==1){
initPointFood();
}else {
//標準化座標位置
pointFood.set(foodX,foodY);
}
}
/**
* 根據傳入的引數 修改小蛇的運動方向
* @param dire
*/
public void changeDirection(int dire) {
switch (dire){
case 0:// 小蛇上下運動時 可修改為左右運動
case -1:
if(direction==1||direction==2){
direction=dire;
}
break;
case 1://小蛇左右運動時 可修改方向為上下運動
case 2:
if(direction==0||direction==-1){
direction=dire;
}
break;
}
}
/**
* 設定重新開始
*/
public void restart(){
isStop=false;
isStart=true;
points.clear();
invalidate();
}
}