温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何运用surfaceviewAndroid进行2d游戏贪吃蛇的开发

发布时间:2021-09-10 16:19:12 来源:亿速云 阅读:199 作者:柒染 栏目:开发技术

如何运用surfaceviewAndroid进行2d游戏贪吃蛇的开发,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

我们先看一下这个同步框架,看看骚年你能不能自己领悟。

GameView.java(继承自SurfaceView)

package com.next.eatsnake; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.View.OnTouchListener; import java.util.Random; /**  * Created by Next on 2016/3/24 0024.  */ public class GameView extends SurfaceView implements SurfaceHolder.Callback,OnTouchListener,Runnable {     enum GameState{         Menu,         Playing,         Over;     }     GameState gameState;//游戏状态     Thread thread;//游戏线程     Boolean flag;//游戏循环控制标志     Canvas canvas;//画布     Paint paint;//画笔     SurfaceHolder holder;//SurfaceView控制句柄     Random random;//随机数     NextEvent nextEvent;//游戏输入事件     int scrW,scrH;//屏幕的宽和高     public GameView(Context context) {         super(context);         gameState = GameState.Menu;         flag = true;         paint = new Paint();         paint.setAntiAlias(true);//笔迹平滑         thread = new Thread(this);         random = new Random();         nextEvent = new NextEvent();         holder = this.getHolder();         holder.addCallback(this);         this.setOnTouchListener(this);         setKeepScreenOn(true);         scrW = ((MainActivity)context).getWindowManager().getDefaultDisplay().getWidth();         scrH = ((MainActivity)context).getWindowManager().getDefaultDisplay().getHeight();     }     @Override     public boolean onTouch(View v, MotionEvent event) {         if (event.getAction() == MotionEvent.ACTION_DOWN) {             nextEvent.setDownX((int) event.getX());             nextEvent.setDownY((int) event.getY());         }else if (event.getAction() == MotionEvent.ACTION_UP) {             nextEvent.setUpX((int) event.getX());             nextEvent.setUpY((int) event.getY());         }         return true;     }     private void mLogic(){         switch (gameState){             case Menu:                 menuLogic();                 break;             case Playing:                 playingLogic();                 break;             case Over:                 overLogic();                 break;         }         nextEvent.init();//每次逻辑循环后,清空事件     }     private void menuLogic(){         if(nextEvent.getUpX() > 0){             gameState = GameState.Playing;         }     }     private void playingLogic(){         if(nextEvent.getDir() == NextEvent.DOWN){             gameState = GameState.Over;         }     }     private void overLogic(){         if(nextEvent.getDir() == NextEvent.RIGHT){             gameState = GameState.Menu;         }     }     private void mDraw(){         try {             canvas = holder.lockCanvas();             canvas.drawColor(Color.WHITE);             switch (gameState){                 case Menu:                     menuDraw(canvas);                     break;                 case Playing:                     playingDraw(canvas);                     break;                 case Over:                     overDraw(canvas);                     break;             }         }catch (Exception e){             e.printStackTrace();         }finally {             holder.unlockCanvasAndPost(canvas);         }     }     private void menuDraw(Canvas canvas){         paint.setColor(Color.RED);         paint.setTextSize(50);         canvas.drawText("I am in menu.Touch me to next scence",100,100,paint);     }     private void playingDraw(Canvas canvas){         paint.setColor(Color.RED);         paint.setTextSize(50);         canvas.drawText("I am in playing,Slide down to next scence ",100,100,paint);     }     private void overDraw(Canvas canvas){         paint.setColor(Color.RED);         paint.setTextSize(50);         canvas.drawText("I am in over,Slide right to next scence",100,100,paint);     }     //这里就是同步触发机制了     //每一个时钟周期,执行一次逻辑方法和绘图方法     @Override     public void run() {         while(flag){             mLogic();             mDraw();             try {                 Thread.sleep(500);             }catch (Exception e){                 e.printStackTrace();             }         }     }     //SurfaceView创建时调用     @Override     public void surfaceCreated(SurfaceHolder holder) {         thread.start();     }     //SurfaceView发生改变时调用     @Override     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {     }     //SurfaceView销毁时调用     @Override     public void surfaceDestroyed(SurfaceHolder holder) {         flag = false;     } }

这只是一个游戏框架,还没有往里写任何内容,但根据我的经验(虽然我也没有很多经验),这里已经包括了所有游戏(这里特指小游戏-_-)的主体框架代码,有了这个框架,我们就只需要写游戏的逻辑和绘图方法了,不用纠结怎么搭建游戏框架了。
这里我还加了一个NextEvent的方法,在里面我封装了上个游戏用到的滑动手势,在这个挨踢圈里,人们最常说的一句话就是:不要重复造轮子。当我们看到写了很多重复代码时,就是我们需要精简的时候了。
上代码:

NextEvent.java

package com.next.eatsnake; /**  * Created by Next on 2016/3/24 0024.  */ public class NextEvent {     public static final int LEFT = 1;     public static final int RIGHT = 2;     public static final int UP = 3;     public static final int DOWN = 4;     public static final int QUIET = -1;//没有滑动     private int dir;     private int downX,downY,upX,upY;     public NextEvent()     {         init();     }     public void init(){         this.dir = QUIET;         this.downX = -1;         this.downY = -1;         this.upX = -1;         this.upY = -1;     }     public int getDir(){         float offsetX,offsetY;         offsetX = upX - downX;         offsetY = upY - downY;         if (Math.abs(offsetX) > Math.abs(offsetY)) {             if (offsetX > 5 ) {                 dir = RIGHT;             }else if (offsetX < -5) {                 dir = LEFT;             }         }else {             if (offsetY > 5) {                 dir = DOWN;             }else if (offsetY < -5) {                 dir = UP;             }         }         return dir;     }     public int getDownX() {         return downX;     }     public void setDownX(int downX) {         this.downX = downX;     }     public int getDownY() {         return downY;     }     public void setDownY(int downY) {         this.downY = downY;     }     public int getUpX() {         return upX;     }     public void setUpX(int upX) {         this.upX = upX;     }     public int getUpY() {         return upY;     }     public void setUpY(int upY) {         this.upY = upY;     } }

这个NextEvent是用来存储用户输入事件的,我们只是存储,而没有直接触发游戏逻辑。那么什么时候用到读取这个NextEvent呢?如果你仔细看了第一段代码,应该已经知道了——在每一个时钟周期的逻辑方法里判断NextEvent,并由此改变游戏逻辑。这种就是同步机制,而用户输入事件游戏逻辑就随之改变的就是异步机制。

下面我们用这个框架做一个贪吃蛇游戏,效果图如下:

如何运用surfaceviewAndroid进行2d游戏贪吃蛇的开发

如何运用surfaceviewAndroid进行2d游戏贪吃蛇的开发

如何运用surfaceviewAndroid进行2d游戏贪吃蛇的开发

MainActivity.java

package com.next.eatsnake; import android.app.Activity; import android.os.Bundle; import android.view.Window; import android.view.WindowManager; public class MainActivity extends Activity {     @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         requestWindowFeature(Window.FEATURE_NO_TITLE);         getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);         setContentView(new GameView(this));     } }

GameView.java

package com.next.eatsnake; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.View.OnTouchListener; import java.util.ArrayList; import java.util.Random; /**  * Created by Administrator on 2016/3/24 0024.  */ public class GameView extends SurfaceView implements SurfaceHolder.Callback,OnTouchListener,Runnable {     enum GameState{         Menu,         Playing,         Over;     }     GameState gameState;//游戏状态     Thread thread;//游戏线程     Boolean flag;//游戏循环控制标志     Canvas canvas;//画布     Paint paint;//画笔     SurfaceHolder holder;//SurfaceView控制句柄     public static Random random;//随机数     NextEvent nextEvent;//游戏输入事件     int scrW,scrH;//屏幕的宽和高     final int MAX_X = 15;     int MAX_Y;//竖向tile数量根据MAX_X动态计算,保证tile是正方形     public static Tile[][] tiles;     Snake snake;     public static boolean isEatFood;     public GameView(Context context) {         super(context);         gameState = GameState.Menu;         flag = true;         paint = new Paint();         paint.setAntiAlias(true);//笔迹平滑         paint.setTextAlign(Paint.Align.CENTER);//文字中间对齐         thread = new Thread(this);         random = new Random();         nextEvent = new NextEvent();         holder = this.getHolder();         holder.addCallback(this);         this.setOnTouchListener(this);         setKeepScreenOn(true);         scrW = ((MainActivity)context).getWindowManager().getDefaultDisplay().getWidth();         scrH = ((MainActivity)context).getWindowManager().getDefaultDisplay().getHeight();         Tile.width = scrW/MAX_X;         MAX_Y = scrH/Tile.width;         tiles = new Tile[MAX_X][MAX_Y];         isEatFood = false;     }     private void newGame(){         for (int x = 0;x < MAX_X;x++){             for (int y = 0;y < MAX_Y;y++){                 if (x == 0||y == 0||x == MAX_X-1||y == MAX_Y-1){                     tiles[x][y] = new Tile(x,y,Tile.TYPE_WALL);                 }else {                     tiles[x][y] = new Tile(x,y,Tile.TYPE_NULL);                 }             }         }         snake = new Snake(tiles[4][4],tiles[5][4],tiles[6][4], NextEvent.DOWN);         addFood();         addFood();         addFood();     }     public void addFood(){         ArrayList<Tile> nullList = new ArrayList<Tile>();         for (int x = 0;x < MAX_X;x++){             for (int y = 0;y < MAX_Y;y++){                 if (tiles[x][y].getType() == Tile.TYPE_NULL){                     nullList.add(tiles[x][y]);                 }             }         }         if (nullList.size()!=0){             nullList.get(random.nextInt(nullList.size())).setType(Tile.TYPE_FOOD);         }     }     @Override     public boolean onTouch(View v, MotionEvent event) {         if (event.getAction() == MotionEvent.ACTION_DOWN) {             nextEvent.setDownX((int) event.getX());             nextEvent.setDownY((int) event.getY());         }else if (event.getAction() == MotionEvent.ACTION_UP) {             nextEvent.setUpX((int) event.getX());             nextEvent.setUpY((int) event.getY());         }         return true;     }     private void mLogic(){         switch (gameState){             case Menu:                 menuLogic();                 break;             case Playing:                 playingLogic();                 break;             case Over:                 overLogic();                 break;         }         nextEvent.init();//每次逻辑循环后,清空事件     }     private void menuLogic(){         if(nextEvent.getUpX() > 0){             gameState = GameState.Playing;             newGame();         }     }     private void playingLogic(){         if (nextEvent.getDir()!=NextEvent.QUIET){             snake.setDir(nextEvent.getDir());         }         snake.move();         if (isEatFood){             addFood();             isEatFood = false;         }         if(!snake.isAlive()){             gameState = GameState.Over;         }     }     private void overLogic(){         if(nextEvent.getUpX() > 0){             gameState = GameState.Playing;             newGame();         }     }     private void mDraw(){         try {             canvas = holder.lockCanvas();             canvas.drawColor(Color.WHITE);             switch (gameState){                 case Menu:                     menuDraw(canvas);                     break;                 case Playing:                     playingDraw(canvas);                     break;                 case Over:                     overDraw(canvas);                     break;             }         }catch (Exception e){             e.printStackTrace();         }finally {             holder.unlockCanvasAndPost(canvas);         }     }     private void menuDraw(Canvas canvas){         paint.setColor(Color.BLACK);         paint.setTextSize(50);         canvas.drawText("Eat Snake,Touch me and start",scrW/2,scrH/2,paint);     }     private void playingDraw(Canvas canvas){         for (int x = 0;x < MAX_X;x++){             for (int y = 0;y < MAX_Y;y++){                 tiles[x][y].draw(canvas,paint);             }         }     }     private void overDraw(Canvas canvas){         paint.setColor(Color.BLACK);         paint.setTextSize(50);         canvas.drawText("Your score is:"+snake.getLength(),scrW/2,scrH/4,paint);         canvas.drawText("Touch me and try again",scrW/2,scrH/2,paint);     }     @Override     public void run() {         while(flag){             mLogic();             mDraw();             try {                 Thread.sleep(500);             }catch (Exception e){                 e.printStackTrace();             }         }     }     @Override     public void surfaceCreated(SurfaceHolder holder) {         thread.start();     }     @Override     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {     }     @Override     public void surfaceDestroyed(SurfaceHolder holder) {         flag = false;     } }

Tile.java

package com.next.eatsnake; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; /**  * Created by Next on 2016/3/26 0026.  */ public class Tile {     public static final int TYPE_NULL = 0;//空     public static final int TYPE_WALL = 1;//墙     public static final int TYPE_HEAD = 2;//蛇头     public static final int TYPE_BODY = 3;//蛇身     public static final int TYPE_TAIL = 4;//蛇尾     public static final int TYPE_FOOD = 5;//食物     private int x,y;     private int type;     public static int width;     public Tile(int x, int y, int type) {         this.x = x;         this.y = y;         this.type = type;     }     public void draw(Canvas canvas,Paint paint){         switch (type){             case TYPE_NULL:                 break;             case TYPE_WALL:                 paint.setColor(Color.BLACK);                 canvas.drawCircle(x*width+width/2,y*width+width/2,width/2,paint);                 break;             case TYPE_HEAD:                 paint.setColor(Color.MAGENTA);                 canvas.drawCircle(x*width+width/2,y*width+width/2,width/2,paint);                 paint.setColor(Color.WHITE);                 canvas.drawCircle(x*width+width/2,y*width+width/2,width/8,paint);                 break;             case TYPE_BODY:                 paint.setColor(Color.MAGENTA);                 canvas.drawCircle(x*width+width/2,y*width+width/2,width/2,paint);                 break;             case TYPE_TAIL:                 paint.setColor(Color.MAGENTA);                 paint.setStrokeWidth(10);                 canvas.drawLine(x * width, y * width + width / 2, x * width + width / 2, y * width, paint);                 canvas.drawLine(x*width+ width / 2,y*width,x*width+width,y*width+width/2,paint);                 canvas.drawLine(x*width+width,y*width+width/2,x*width+width/2,y*width+width,paint);                 canvas.drawLine(x*width+width/2,y*width+width,x*width,y*width+ width / 2,paint);                 break;             case TYPE_FOOD:                 switch (GameView.random.nextInt(3)){                     case 0:                         paint.setColor(Color.YELLOW);                         break;                     case 1:                         paint.setColor(Color.GREEN);                         break;                     case 2:                         paint.setColor(Color.CYAN);                         break;                 }                 canvas.drawCircle(x*width+width/2,y*width+width/2,width/2,paint);                 break;         }     }     public int getX() {         return x;     }     public void setX(int x) {         this.x = x;     }     public int getY() {         return y;     }     public void setY(int y) {         this.y = y;     }     public int getType() {         return type;     }     public void setType(int type) {         this.type = type;     } }

Snake.java

package com.next.eatsnake; import java.util.ArrayList; /**  * Created by Administrator on 2016/3/26 0026.  */ public class Snake {     private ArrayList<Tile> snake;     private int dir;     private boolean isAlive;     public Snake(Tile head,Tile body,Tile tail,int dir){         snake = new ArrayList<Tile>();         head.setType(Tile.TYPE_HEAD);         body.setType(Tile.TYPE_BODY);         tail.setType(Tile.TYPE_TAIL);         snake.add(head);         snake.add(body);         snake.add(tail);         isAlive = true;         this.dir = dir;     }     public void move(){         if (!isAlive)             return;         switch (dir){             case NextEvent.LEFT:                 switch (GameView.tiles[snake.get(0).getX()-1][snake.get(0).getY()].getType()){                     case Tile.TYPE_WALL:                     case Tile.TYPE_BODY:                     case Tile.TYPE_TAIL:                         isAlive = false;                         break;                     case Tile.TYPE_FOOD:                         GameView.tiles[snake.get(0).getX()-1][snake.get(0).getY()].setType(Tile.TYPE_HEAD);                         GameView.tiles[snake.get(0).getX()][snake.get(0).getY()].setType(Tile.TYPE_BODY);                         snake.add(0, GameView.tiles[snake.get(0).getX() - 1][snake.get(0).getY()]);                         GameView.isEatFood = true;                         break;                     case Tile.TYPE_NULL:                         GameView.tiles[snake.get(0).getX()-1][snake.get(0).getY()].setType(Tile.TYPE_HEAD);                         GameView.tiles[snake.get(0).getX()][snake.get(0).getY()].setType(Tile.TYPE_BODY);                         snake.add(0, GameView.tiles[snake.get(0).getX() - 1][snake.get(0).getY()]);                         snake.get(snake.size()-1).setType(Tile.TYPE_NULL);                         snake.remove(snake.size()-1);                         snake.get(snake.size()-1).setType(Tile.TYPE_TAIL);                         break;                 }                 break;             case NextEvent.RIGHT:                 switch (GameView.tiles[snake.get(0).getX()+1][snake.get(0).getY()].getType()){                     case Tile.TYPE_WALL:                     case Tile.TYPE_BODY:                     case Tile.TYPE_TAIL:                         isAlive = false;                         break;                     case Tile.TYPE_FOOD:                         GameView.tiles[snake.get(0).getX()+1][snake.get(0).getY()].setType(Tile.TYPE_HEAD);                         GameView.tiles[snake.get(0).getX()][snake.get(0).getY()].setType(Tile.TYPE_BODY);                         snake.add(0, GameView.tiles[snake.get(0).getX() + 1][snake.get(0).getY()]);                         GameView.isEatFood = true;                         break;                     case Tile.TYPE_NULL:                         GameView.tiles[snake.get(0).getX()+1][snake.get(0).getY()].setType(Tile.TYPE_HEAD);                         GameView.tiles[snake.get(0).getX()][snake.get(0).getY()].setType(Tile.TYPE_BODY);                         snake.add(0, GameView.tiles[snake.get(0).getX() + 1][snake.get(0).getY()]);                         snake.get(snake.size()-1).setType(Tile.TYPE_NULL);                         snake.remove(snake.size() - 1);                         snake.get(snake.size()-1).setType(Tile.TYPE_TAIL);                         break;                 }                 break;             case NextEvent.UP:                 switch (GameView.tiles[snake.get(0).getX()][snake.get(0).getY()-1].getType()){                     case Tile.TYPE_WALL:                     case Tile.TYPE_BODY:                     case Tile.TYPE_TAIL:                         isAlive = false;                         break;                     case Tile.TYPE_FOOD:                         GameView.tiles[snake.get(0).getX()][snake.get(0).getY()-1].setType(Tile.TYPE_HEAD);                         GameView.tiles[snake.get(0).getX()][snake.get(0).getY()].setType(Tile.TYPE_BODY);                         snake.add(0, GameView.tiles[snake.get(0).getX()][snake.get(0).getY()-1]);                         GameView.isEatFood = true;                         break;                     case Tile.TYPE_NULL:                         GameView.tiles[snake.get(0).getX()][snake.get(0).getY()-1].setType(Tile.TYPE_HEAD);                         GameView.tiles[snake.get(0).getX()][snake.get(0).getY()].setType(Tile.TYPE_BODY);                         snake.add(0, GameView.tiles[snake.get(0).getX()][snake.get(0).getY()-1]);                         snake.get(snake.size()-1).setType(Tile.TYPE_NULL);                         snake.remove(snake.size()-1);                         snake.get(snake.size()-1).setType(Tile.TYPE_TAIL);                         break;                 }                 break;             case NextEvent.DOWN:                 switch (GameView.tiles[snake.get(0).getX()][snake.get(0).getY()+1].getType()){                     case Tile.TYPE_WALL:                     case Tile.TYPE_BODY:                     case Tile.TYPE_TAIL:                         isAlive = false;                         break;                     case Tile.TYPE_FOOD:                         GameView.tiles[snake.get(0).getX()][snake.get(0).getY()+1].setType(Tile.TYPE_HEAD);                         GameView.tiles[snake.get(0).getX()][snake.get(0).getY()].setType(Tile.TYPE_BODY);                         snake.add(0, GameView.tiles[snake.get(0).getX()][snake.get(0).getY() + 1]);                         GameView.isEatFood = true;                         break;                     case Tile.TYPE_NULL:                         GameView.tiles[snake.get(0).getX()][snake.get(0).getY()+1].setType(Tile.TYPE_HEAD);                         GameView.tiles[snake.get(0).getX()][snake.get(0).getY()].setType(Tile.TYPE_BODY);                         snake.add(0, GameView.tiles[snake.get(0).getX()][snake.get(0).getY()+1]);                         snake.get(snake.size()-1).setType(Tile.TYPE_NULL);                         snake.remove(snake.size()-1);                         snake.get(snake.size()-1).setType(Tile.TYPE_TAIL);                         break;                 }                 break;         }     }     public void setDir(int dir){         if (this.dir == dir||this.dir == -dir||dir == NextEvent.QUIET)             return;         else             this.dir = dir;     }     public boolean isAlive(){         return isAlive;     }     public int getLength(){         return snake.size();     } }

NextEvent.java

就是刚开始介绍的那个类,这里就不重复贴出了

关于如何运用surfaceviewAndroid进行2d游戏贪吃蛇的开发问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注亿速云行业资讯频道了解更多相关知识。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI