Android ImageView 纯视图贪吃蛇的实现方式

Android ImageView 纯视图贪吃蛇的实现方式,第1张

Android ImageView 纯视图贪吃蛇的实现方式
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ArrayAdapter;
import android.widget.ImageView;

import com.chengqi.drysister.R;
import android.os.Handler;
import android.widget.TextView;

import androidx.annotation.NonNull;

import org.w3c.dom.Text;

import java.lang.ref.PhantomReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.linkedList;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.jar.Attributes;

public class MyImageView extends androidx.appcompat.widget.AppCompatImageView {
    private final Bitmap snake;
    private final Bitmap food;
    //适配后的bitmap对象
    //每一个单位长度的蛇身体
    private  Bitmap mSnakeBitmap;
    private  Bitmap mFoodBitmap;
    private int screenWidth;
    private int screenHeight;
    private static int speed = 4;
    private static int length = 0;

    private static int mController = 0;
    int[] foodPoint = new int[2];

    private boolean initFlag = false;
    private final Context mContext;
    //在蛇尾部增加长度,使用arraylist
    private ArrayList snakeBody = new ArrayList<>();
    private static MoveHandler moveHandler ;

    private static final class MoveHandler extends Handler{
        WeakReference myImageViewWeakReference;
        Timer timer = new Timer();
        int R;
        public MoveHandler(MyImageView myImageView){
            myImageViewWeakReference = new WeakReference<>(myImageView);
        }
        @Override
        public void handleMessage(@NonNull Message msg) {
            MyImageView myImageView = myImageViewWeakReference.get();
            //物体有效面积半径
            R = myImageView.screenWidth/100;
            double lastX,lastY,thisX,thisY;
            lastX=myImageView.snakeBody.get(0).snakeBodyX;
            lastY=myImageView.snakeBody.get(0).snakeBodyY;
            //手机最左上角是坐标原点,因此x轴向右是正,y轴向下为正
            switch (msg.what){
                case 1 :
                    //如果到头了,将y坐标直接设置为最大值,从下边界出来(无边界模式)
                    if (myImageView.snakeBody.get(0).snakeBodyY<0) {
                        myImageView.snakeBody.get(0).snakeBodyY = myImageView.screenHeight;
                    } else {
                        //如果没到头,就向上增加speed个坐标
                        myImageView.snakeBody.get(0).snakeBodyY -= speed;
                    }
                    break;
                case 2 :
                    //如果到底了,将y坐标设置为0,从上边界出来
                    if (myImageView.snakeBody.get(0).snakeBodyY>myImageView.screenHeight) {
                        myImageView.snakeBody.get(0).snakeBodyY = 0;
                    } else {
                        //如果没到底,就减少speed个坐标
                        myImageView.snakeBody.get(0).snakeBodyY += speed;
                    }
                    break;
                case 3 :
                    //如果到最左边了,将x坐标设置为最大值,从右边界出来
                    if (myImageView.snakeBody.get(0).snakeBodyX<0) {
                        myImageView.snakeBody.get(0).snakeBodyX = myImageView.screenWidth;
                    } else {
                        //如果没到底,就减少speed个坐标
                        myImageView.snakeBody.get(0).snakeBodyX -= speed;
                    }
                    break;
                case 4 :
                    //如果到最右边了,将x坐标设置为0,从左边界出来
                    if (myImageView.snakeBody.get(0).snakeBodyX>myImageView.screenWidth) {
                        myImageView.snakeBody.get(0).snakeBodyX = 0;
                    } else {
                        //如果没到底,就增加speed个坐标
                        myImageView.snakeBody.get(0).snakeBodyX += speed;
                    }
                    break;
            }
            //如果foodPoint没有初始化完成,蛇头没有碰到豆子,则不会创建新的豆子
            if (myImageView.initFlag){
                //在某一瞬间,豆子和蛇头产生交集时,刷新豆子
                //以蛇头为中心点,蛇头宽为半径,豆子为中心点,豆子宽为半径,作为两个物体的有效面积
                //当蛇头和豆子中心点的距离小于两者半径之和时,代表两者有交集
                //两者中心点的距离可用勾股定理计算
                double distance = Math.sqrt(Math.pow((myImageView.foodPoint[0]-myImageView.snakeBody.get(0).snakeBodyX),2)+
                        Math.pow((myImageView.foodPoint[1]-myImageView.snakeBody.get(0).snakeBodyY),2));
                if (distance<(double) myImageView.screenWidth/100+(double) myImageView.screenWidth/100){
                    //吃掉豆子后,创建新的豆子
                    myImageView.foodPoint = myImageView.createFood();
                    //一个豆子十分,发送广播,长度加一
                    length++;
                    myImageView.mContext.sendBroadcast(new Intent("GET_SCORE"));
                    //每个单位长度都要遵循前一个单位行动的轨迹,每次吃到一个豆子,增加一个单位长度
                    //增加在蛇的末端
                    myImageView.snakeBody.add(new SnakeBodyObject(myImageView.snakeBody.get(myImageView.snakeBody.size()-1).snakeBodyX,
                            myImageView.snakeBody.get(myImageView.snakeBody.size()-1).snakeBodyY,myImageView.mSnakeBitmap));
                }
            }
            //将除头结点以外的结点依次覆盖下一个结点的位置
            for (int i = 1; i < myImageView.snakeBody.size(); i++) {
                thisX =myImageView.snakeBody.get(i).snakeBodyX;
                thisY =myImageView.snakeBody.get(i).snakeBodyY;
                myImageView.snakeBody.get(i).snakeBodyX=lastX;
                myImageView.snakeBody.get(i).snakeBodyY=lastY;
                lastX = thisX;
                lastY = thisY;
            }
            if (isDead()){
                stopTimer();
                //弹出消息,游戏结束
            }
            myImageView.invalidate();//将坐标更新后,重绘。会调用onDraw()方法
        }
        //每次吃一个豆子,蛇长增加speed个单位,由于蛇身体有效面积半径单位长度是screenWidth/100
        //因此,再第screenWidth/100*speed个豆子后,对蛇咬自己进行判断
        //和蛇咬豆子一个机制,只要对所有单位的身体中心点进行距离判断,如果小于两者半径之和则视为蛇咬了自己
        public boolean isDead(){
            if (length>R/speed){
                //等有时间再做,暂时搁置
                return true;
            }else {
                return false;
            }
        }
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                if (mController!=0)
                    sendEmptyMessage(mController);
            }
        };
        public void startMove(){
            timer.schedule(timerTask,0 , 10);
        }
        public void stopTimer(){
            timerTask.cancel();
            timer.cancel();
        }
    }

    public MyImageView(Context context, AttributeSet attributeSet){
        super(context,attributeSet);
        //获取贪吃蛇图片实例,从项目资源文件中加载一个Bitmap对象
        snake = BitmapFactory.decodeResource(context.getResources(), R.drawable.black);
        //获取豆子图片实例
        food = BitmapFactory.decodeResource(context.getResources(),R.drawable.red);
        //先开启线程,监听mController是否改变
        moveHandler = new MoveHandler(this);
        moveHandler.startMove();
        mContext = context;
    }
    //初始蛇的位置放在中心点
    public void initPoint(){
        //初始化豆子
        foodPoint[0] = new Random().nextInt(screenWidth);
        foodPoint[1] = new Random().nextInt(screenHeight);
        //初始化贪吃蛇,放置在中间位置
        snakeBody.add(new SnakeBodyObject(screenWidth/2.0,screenHeight/2.0,mSnakeBitmap));
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
//        canvas.drawBitmap(mSnakeBitmap,(float)startX,(float)startY,null);
        for (int i = 0; i < snakeBody.size(); i++) {
            canvas.drawBitmap(snakeBody.get(i).snakeBody,(float)snakeBody.get(i).snakeBodyX,
                    (float)snakeBody.get(i).snakeBodyY,null);
        }
        //如果没有开始控制,不显示豆子
        if (mController!=0) {
            canvas.drawBitmap(mFoodBitmap,(float)foodPoint[0],(float)foodPoint[1],null);
        }
    }

    public static void changeState(int state){
        //不能180度转向,不能0度转向
        if (state != mController){
            if (mController==0){
                mController = state;
            }else if (mController+state!=3 && mController+state!= 7){
                mController = state;
            }
        }
    }
    //在xml渲染完成后调用这个方法
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        this.getViewTreeObserver().addonGlobalLayoutListener(new ViewTreeObserver.onGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                MyImageView.this.getViewTreeObserver().removeonGlobalLayoutListener(this);
                //获取渲染完成后imageView的宽高值
                screenWidth = MyImageView.this.getMeasuredWidth();
                screenHeight = MyImageView.this.getMeasuredHeight();
                //图片按控件比例缩小
                mSnakeBitmap = Bitmap.createScaledBitmap(snake,screenWidth/50,screenHeight/50,true);
                mFoodBitmap = Bitmap.createScaledBitmap(food,screenWidth/50,screenHeight/50,true);
                //初始化蛇,豆子的位置
                initPoint();
                initFlag = true;
            }
        });
    }
    public int[] createFood(){
        return new int[]{new Random().nextInt(screenWidth),new Random().nextInt(screenHeight)};
    }
    public static void stop(){
        moveHandler.stopTimer();
        mController = 0;
    }
}

android 菜鸟 ,新手上路~ = w =

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5684955.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存