安卓简单实现贪吃蛇

个人纯手写纯原生的安卓贪吃蛇,原理是recycview的局部刷新和通过变量判断移动方向,运用到了一些算法原理和技巧,感兴趣的可以查看源码

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.SimpleItemAnimator;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.Timer;

public class MainActivity extends AppCompatActivity {
    private RecyclerView recycler;
    private TextView score;
    private TextView duration;

    private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");

    private int forward;  // 下0、左1、上2、右3
    private int dx[] = {0, -1, 0, 1};
    private int dy[] = {1, 0, -1, 0};

    public static int width = 32;

    private List<Site> path = new ArrayList<>();
    private Site food;

    private GestureDetector.OnGestureListener gesture;
    private GestureDetector detector;

    private boolean gameOver = false;
    private Handler handler;
    Random random = new Random();
    private GameAdapter gameAdapter;

    int time = 0, fenshu = 0;
    private Handler timer;
    private Site changes[] = new Site[5];
    private int speed;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initGesture();
        initGame();
        initTime();
        startMove();  /*核心*/
    }

    private void initTime() {
        timer = new Handler(Looper.myLooper(), new Handler.Callback() {
            @Override
            public boolean handleMessage(@NonNull Message message) {
                if(!gameOver) {
                    addTime();
                    timer.sendEmptyMessageDelayed(1, 1000);
                }
                return false;
            }
        });
        timer.sendEmptyMessageDelayed(1, 1000);
    }

    private void startMove() {
        handler = new Handler(Looper.myLooper(), new Handler.Callback() {
            @Override
            public boolean handleMessage(@NonNull Message message) {
                if(!gameOver){
                    /*新走到的位置*/
                    Site end = path.get(path.size() - 1);
                    Site site = new Site(end.x + dx[forward], end.y + dy[forward]);
                    site = offset(site);

                    if(path.contains(site)){   // 是否咬到自己
                        path.add(site);
                        gameAdapter.notifyDataSetChanged();
                        stopGame();
                        return false;
                    }
                    changes[0] = site;
                    changes[1] = end;
                    changes[2] = path.get(0);
                    changes[3] = food;

                    path.add(site);  // 重载食物,去掉尾巴
                    if(!site.equals(food)){
                        path.remove(0);
                    }else {
                        fenshu ++;
                        score.setText("Score:"+fenshu);
                        while(path.contains(food)) food = new Site(random.nextInt(width * width));
                    }
                    for (int i = 0; i < 5; i++) {
                        gameAdapter.notifyItemChanged(changes[i].getPosition(), null);
                    }
//                    gameAdapter.notifyDataSetChanged();   //  只需要更新旧头,新头site、尾path[0]、旧的食物food(既新头)、新的食物while+food
                    handler.sendEmptyMessageDelayed(0, speed);
                }
                return false;
            }
        });
        gameAdapter = new GameAdapter();
        recycler.setAdapter(gameAdapter);
        handler.sendEmptyMessageDelayed(0, 1000);
    }

    private void addTime() {
        time ++;
        Date date = new Date();
        date.setTime(16*60*60*1000L + time * 1000);
        String format = sdf.format(date);
        duration.setText("Duration:"+format);
    }

    private void stopGame() {
        gameOver=true;
        saveScore();
        new AlertDialog.Builder(this).setTitle("Game Over").setMessage("请选择重新开始或返回首页")
                .setPositiveButton("Play again", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        startActivity(new Intent(MainActivity.this, MainActivity.class));
                        finish();
                    }
                }).setNegativeButton("Back to home", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        finish();
                    }
                }).setOnCancelListener(new DialogInterface.OnCancelListener() {
                    @Override
                    public void onCancel(DialogInterface dialogInterface) {
                        startActivity(new Intent(MainActivity.this, MainActivity.class));
                        finish();
                    }
                }).show();
    }

    private void saveScore() {
        SharedPreferences sp = getSharedPreferences("user", MODE_PRIVATE);
        try {
            JSONArray jsonArray = new JSONArray(sp.getString("data", ""));
            JSONObject obj = new JSONObject();
            obj.put("score", fenshu);
            obj.put("duration", time);
            jsonArray.put(obj);
            sp.edit().putString("data", jsonArray.toString()).apply();
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
    }

    private void initGame() {
        SharedPreferences sp = getSharedPreferences("user", MODE_PRIVATE);
        int wid = Integer.parseInt(sp.getString("width", "4"));
        path.add(new Site(random.nextInt(width * width)));
        forward = random.nextInt(4);
        for (int i = 0; i < wid; i++) {
            Site end = path.get(path.size() - 1);
            Site site = new Site(end.x + dx[forward], end.y + dy[forward]);
            site = offset(site);
            path.add(site);
        }
        food = new Site(random.nextInt(width * width));
        while(path.contains(food)) food = new Site(random.nextInt(width * width));
    }

    private Site offset(Site site) {
        site.x = site.x % width;
        site.y = site.y % width;
        if (site.x < 0) {
            site.x += width;
        }
        if (site.y < 0) {
            site.y += width;
        }
        return site;
    };

    private void initView() {
        recycler = findViewById(R.id.recyc);
        ((SimpleItemAnimator)recycler.getItemAnimator()).setSupportsChangeAnimations(false);  // 不显示itemChange的闪烁动画
        recycler.setLayoutManager(new GridLayoutManager(this, width){
            @Override
            public boolean canScrollVertically() {
                return false;
            }
        });
        score = findViewById(R.id.score);
        duration = findViewById(R.id.duration);

        SharedPreferences sp = getSharedPreferences("user", MODE_PRIVATE);
        speed = Integer.parseInt(sp.getString("speed", 600+""));
    }

    private void initGesture() {
        gesture = new GestureDetector.SimpleOnGestureListener(){
            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                float offset = getResources().getDisplayMetrics().density * 50;  // 50dp
//                float offset = 30;
                if(e1.getX() - e2.getX() > offset){   // 左滑
                    // "不能往反方向滑动",
                    if(forward != 3){ forward = 1; }
                }else if(e2.getX() - e1.getX() > offset){  // 右滑
                    if(forward != 1){ forward = 3; }
                }else if(e2.getY() - e1.getY() > offset){  // 下滑
                    if(forward != 2){ forward = 0; }
                }else if(e1.getY() - e2.getY() > offset){  // 上滑
                    if(forward != 0){ forward = 2; }
                }
                return super.onFling(e1, e2, velocityX, velocityY);
            }
        };
        detector = new GestureDetector(this, gesture);
        recycler.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                detector.onTouchEvent(motionEvent);
                return false;
            }
        });
    }

    public void back(View view) {
        finish();
    }

    public void move(View view) {
        switch (view.getId()){
            case R.id.up:
                if(forward != 0){ forward = 2; }
                break;
            case R.id.left:
                if(forward != 3){ forward = 1; }
                break;
            case R.id.right:
                if(forward != 1){ forward = 3; }
                break;
            case R.id.down:
                if(forward != 2){ forward = 0; }
                break;
        }
    }


    class GameAdapter extends RecyclerView.Adapter<GameAdapter.MyViewHolder>{
        private ColorDrawable colors[] = {
                new ColorDrawable(getResources().getColor(R.color.body)),
                new ColorDrawable(Color.TRANSPARENT)
        };
        @NonNull
        @Override
        public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            return new MyViewHolder(LayoutInflater.from(MainActivity.this).inflate(R.layout.item_game, parent, false));
        }

        @Override
        public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
            Site site = new Site(position);
            if(path.contains(site)){
                holder.itemView.setBackground(colors[0]);
                if(path.get(path.size()-1).equals(site)) holder.itemView.setBackground(getResources().getDrawable(R.drawable.baseline_face_24));
            }else if(food.equals(site)){
                holder.itemView.setBackground(getResources().getDrawable(R.drawable.baseline_fastfood_24));
            }else{
                holder.itemView.setBackground(colors[1]);
            }
        }
        @Override
        public int getItemCount() {
            return width * width;
        }
        class MyViewHolder extends RecyclerView.ViewHolder{
            public MyViewHolder(@NonNull View itemView) {
                super(itemView);
            }
        }
    }

}

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值