Android打地鼠游戏的修改和优化

卞轶
2023-12-01

最近在研究android原生的游戏,主要是打地鼠这款经典小游戏的熟悉和修改,因为直接copy的是开源的代码,不过因为年代久远,再加上要修改的符合需求,所以做了一些调整,先看界面:


1.打地鼠的实现图

这个界面是用自定义View来实现的,所以可扩展性比较强,HP是血量,总共20ms,进行倒计时操作,Grade是分数,每打中一次地鼠,则增加100分,首先,我们先看看这两个是如何绘制的:


2.HP和Grade的绘制

也就五行代码,利用Paint画笔,设置字体颜色为红色,字体大小为30sp,利用Canva的drawText()方法进行字体文本的绘制,同时GameAgrs这个类是游戏属性的封装类,里面的HP_X和HP_Y,Grade_X和Grade_Y分别对应着各自的横坐标和纵坐标。

接下来,我们来仔细讲解一下这九个老鼠窝的绘制,因为老鼠窝有九个,但是其中的每个属性都是一样的,我们先来看看其中一个鼠窝究竟有哪些元素和属性构成的:



3.每个方块的属性页方法

因为是直接拿源码直接来改的,所以这里面的倒计时有一点问题,利用的是自减而非传统的CountDownTime等倒计时的方式,所以会倒计时会出现一点问题,这个未来会做相应的修改。

得到每个方块的属性和方法之后,我们虽然可以绘制鼠窝,但是为了给老鼠一个美丽的家,所以我们设置一下背景和老鼠弹出、撤退的图片。





4.鼠窝背景和老鼠的三个状态的设置

利用Map存储老鼠的三个状态,暴露出一个getBitmap的方法让外界进行调用,获取鼠窝的背景和老鼠的三个状态。

到目前为止,我们完成了单个鼠窝的属性,背景和老鼠的绘制,接下来我们需要对九个鼠窝进行绘制,由于代码太多,就不截图了,直接看代码

public classGameViewextendsView {

public static intspeed=100;//刷新速度

private static final intsHeight=298;

private booleanisCancel=false;

publicGameView(Context context) {

     super(context);

     initView(context);

     GameView.this.post(updatePaint);//刷新画面线程

      GameView.this.postDelayed(setMouse,1000);//增加地鼠的线程,1s后执行

}

publicGameView(Context context,@NullableAttributeSet attrs) {

     super(context,attrs);

     initView(context);

    GameView.this.post(updatePaint);//刷新画面线程

    GameView.this.postDelayed(setMouse,1000);//增加地鼠的线程,1s后执行

    Log.i("GameViewThread:",Thread.currentThread() +"");

}

publicGameView(Context context,@NullableAttributeSet attrs, intdefStyleAttr) {

     super(context,attrs,defStyleAttr);

    initView(context);

    GameView.this.post(updatePaint);//刷新画面线程

   GameView.this.postDelayed(setMouse,1000);//增加地鼠的线程,1s后执行

}

public static voidinitView(Context context){

     DisplayMetrics dMetrics =newDisplayMetrics();

     //获取屏幕分辨率

     dMetrics = context.getResources().getDisplayMetrics();

     GameAgrs.InitArgs(dMetrics);

    MainMapManager.Init(context);

    VolumsPlayer.init(context);

}

intstart_X= GameAgrs.start_X;//开始画方块的X坐标

intstart_Y= GameAgrs.start_Y;//开始画方块的Y坐标

privateRandomrandom=newRandom();//定义一个随机函数

//初始化每块方块的信息

privateListmainList=newArrayList(GameAgrs.Total_Count);

{

     for(inti =0;i < GameAgrs.Total_Count;i++) {

        mainList.add(newEpicture());

    }

}

RunnableupdatePaint=newRunnable() {

@Override

public voidrun() {

        GameView.this.invalidate();

       GameView.this.postDelayed(this,speed);//每100ms刷新一次

}

};

Runnable setMouse=new  Runnable() {

@Override

public void run() {

       LinkedList  tempList =new  LinkedList();

      for(inti =0;i

           Epicture epicture =mainList.get(i);

           if(epicture.getCurrenty() == GameAgrs.Hole_Empty) {

          tempList.add(epicture);

}

}

inttempSize = tempList.size();

if(tempSize ==1) {

tempList.poll().toShow();

}else if(tempSize >1) {

//随机出一个或者两个地鼠

for(inti =0;i

tempList.remove(random.nextInt(tempList.size())).toShow();

}

GameView.this.invalidate();

}

GameView.this.postDelayed(this,800- GameAgrs.Grade/20);

}

};

private void  drawMessage(Canvas canvas) {

Paint paint =new  Paint();

paint.setColor(Color.RED);

paint.setTextSize(GameAgrs.text_size);

canvas.drawText("HP:"+ GameAgrs.HP,GameAgrs.HP_X,GameAgrs.HP_Y,paint);

canvas.drawText("\nGrade:  "+ GameAgrs.Grade,GameAgrs.Grade_X,GameAgrs.Grade_Y,paint);

}

//游戏结束处理

private void   doGameOver() {

AlertDialog.Builder builder =new  AlertDialog.Builder(getContext());

if(GameAgrs.Grade<2500)

builder.setTitle("继续努力O(∩_∩)O");

else if(GameAgrs.Grade<3500)

builder.setTitle("那你很棒棒呦(。^▽^)");

else

builder.setTitle("哇!你坠棒(๑•̀ㅂ•́)و✧");

builder.setMessage("得分:"+ GameAgrs.Grade+",是否重新开始游戏?");

builder.setPositiveButton("确定", newDialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, intwhich) {

GameAgrs.Reset();//用户信息重置

isCancel=false;

initView(getContext());

GameView.this.post(updatePaint);//刷新画面线程

GameView.this.postDelayed(setMouse,1000);

}

});

builder.setNegativeButton("取消", newDialogInterface.OnClickListener() {

@Override

public voidonClick(DialogInterface dialog, intwhich) {

isCancel=true;

GameAgrs.Reset();//用户信息重置

initView(getContext());

GameView.this.invalidate();

}

});

builder.setCancelable(false);

AlertDialog dialog = builder.create();

dialog.show();

}

@Override

protected void  onMeasure(intwidthMeasureSpec, intheightMeasureSpec) {

super.onMeasure(widthMeasureSpec,heightMeasureSpec);

setMeasuredDimension(ViewGroup.LayoutParams.MATCH_PARENT,sHeight);

}

@Override

protected void  onDraw(Canvas canvas) {

super.onDraw(canvas);

if(GameAgrs.HP<=0) {

getHandler().removeCallbacks(updatePaint);

getHandler().removeCallbacks(setMouse);

doGameOver();

return;

}

canvas.drawColor(Color.WHITE);//将背景设置为白色

drawMessage(canvas);//显示用户信息

if(isCancel) {

for(inti =0;i

Epicture epicture =mainList.get(i);

intx = i % GameAgrs.Colums_Count;//获得所在列

inty = i / GameAgrs.Colums_Count;//获得所在行

canvas.drawBitmap(MainMapManager.getBitmap(epicture.getEmpty()),

start_X+ x * GameAgrs.EpicSize,start_Y+ y

* GameAgrs.EpicSize, null);

}

return;

}

for(inti =0;i

Epicture epicture =mainList.get(i);

intx = i % GameAgrs.Colums_Count;//获得所在列

inty = i / GameAgrs.Colums_Count;//获得所在行

canvas.drawBitmap(MainMapManager.getBitmap(epicture.getCurrenty()),

start_X+ x * GameAgrs.EpicSize,start_Y+ y

* GameAgrs.EpicSize, null);

epicture.toNext();//进入下一个状态

}

}

//触摸事件

@Override

public boolean  onTouchEvent(MotionEvent event) {

if(event.getAction() != MotionEvent.ACTION_DOWN) {

return true;

}

floatx = event.getX();

floaty = event.getY();

intX = (int) ((x -start_X) / GameAgrs.EpicSize);

intY = (int) ((y -start_Y) / GameAgrs.EpicSize);

if(X <0|| Y <0|| X >=3|| Y >=4) {//如果打击不在方块范围内则不响应

//点击外围的时候,则开始游戏

startGame();

return true;

}

intnum = Y * GameAgrs.Colums_Count+ X;

Log.i("game-----------",num +"");

if(num <9){//暂时先解决数组出界的问题

Epicture epicture =mainList.get(num);

epicture.beHited();

}

return true;

}

private void  startGame() {

GameAgrs.Reset();//用户信息重置

initView(getContext());

isCancel=false;

GameView.this.post(updatePaint);//刷新画面线程

GameView.this.postDelayed(setMouse,1000);

}

}

代码不长,但是有几个方法,首先定义了updatePaint和setMouse的两个runnable,分别用来更新UI界面和老鼠动作,onDraw()方法用来绘制九个鼠窝和背景和老鼠的动作状态,onTouchEvent主要用来处理点击事件,具体的可以看看代码,都有注释,并不难理解,doGameOver(),则定义了一个弹窗,点击确定则继续开始,点击取消,则重置页面初始状态。

以上就是打地鼠的代码了,虽然不全,但是精华已经全都交代出来了,另外这个还只是最初的修改版本,未来工作中还有更多的修改,包括页面的重绘,逻辑的修改等等。

 类似资料: