Android实战源码--围住神经猫
最终效果:

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.caobotao.crazycat" > <application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity android:name=".MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application> </manifest>
MainActivity.java
package com.example.caobotao.crazycat; import android.support.v7.app.AppCompatActivity;
import android.os.Bundle; public class MainActivity extends AppCompatActivity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new PlayGround(this));
}
}
Dot.java
package com.example.caobotao.crazycat; /**
* Created by caobotao on 15/11/9.
*/
public class Dot {
private int x;
private int y;
private int status;
static final int STATUS_ON = 1;//障碍的圆圈状态
static final int STATUS_OFF = 0;//可点击的圆圈状态
static final int STATUS_IN = 9;//猫所在的圆圈状态
public Dot(){}
//实例化时每个圆圈都是可点击的状态
public Dot(int x,int y){
this.x = x;
this.y = y;
status = STATUS_OFF;
} 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 getStatus() {
return status;
} public void setStatus(int status) {
this.status = status;
} public void setXY(int x,int y){
this.x = x;
this.y = y;
}
}
PlayGround.java
package com.example.caobotao.crazycat; import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.Toast; import java.util.HashMap;
import java.util.Vector; /**
* Created by caobotao on 15/11/9.
*/
public class PlayGround extends SurfaceView implements OnTouchListener{
private static int WIDTH = 45;//圆圈宽度
private static final int ROW = 10;//每行显示的圆圈数
private static final int COL = 10;//每列显示的圆圈数
private static final int Blocks = 13;//初始化障碍的个数
private Dot matrix[][];
private Dot cat;
public PlayGround(Context context) {
super(context);
getHolder().addCallback(callback);
//声明ROW x COL的圆圈矩阵并初始化
matrix = new Dot[ROW][COL];
for (int i = 0;i < ROW;i ++){
for (int j = 0;j < ROW;j ++){
matrix[i][j] = new Dot(j,i);
}
}
initGame();
setOnTouchListener(this);
}
private void redraw(){
//初始化画板
Canvas canvas = getHolder().lockCanvas();
// Log.i("info", "222222");
//设置画板背景色
canvas.drawColor(Color.LTGRAY);
Paint p = new Paint();
p.setFlags(Paint.ANTI_ALIAS_FLAG);
//设置不同状态的圆圈的颜色,并绘制
for (int i = 0;i < ROW;i ++){
int offset = 0;
//如果为偶数行,设置半个圆圈宽度的偏移量
if (i % 2 != 0){
offset = WIDTH / 2;
}
for (int j = 0;j < COL; j ++){
Dot one = getDot(j, i);
switch (one.getStatus()){
case Dot.STATUS_OFF:
p.setColor(0xFFEEEEEE);
break;
case Dot.STATUS_ON:
p.setColor(0xFFFFAA00);
break;
case Dot.STATUS_IN:
p.setColor(0xFFFF0000);
break;
}
RectF rectF = new RectF(one.getX() * WIDTH + offset, one.getY() * WIDTH,
(one.getX() + 1) * WIDTH + offset, (one.getY() + 1) * WIDTH);;
// if(i % 2 ==0) {
// rectF = new RectF((one.getX() + 1) * WIDTH, (one.getY() + 2) * WIDTH, (one.getX() + 2) * WIDTH, (one.getY() + 2) * WIDTH);
// }
canvas.drawOval(rectF,p);
}
}
getHolder().unlockCanvasAndPost(canvas);
}
private void initGame(){
//将每个圆圈初始化为可点击状态
for (int i = 0;i < ROW;i ++){
for (int j = 0;j < ROW;j ++){
matrix[i][j].setStatus(Dot.STATUS_OFF);
}
}
//将(4,5)设置初始化为猫所在的圆圈,并将状态设置为猫所在
cat = getDot(4,5);
cat.setStatus(Dot.STATUS_IN);
//随机设置Blocks个障碍
for (int i = 0 ;i < Blocks;){
int x = (int) ((Math.random() * 1000)%COL);
int y = (int) ((Math.random() * 1000)%ROW);
if(getDot(x,y).getStatus() == Dot.STATUS_OFF){
getDot(x,y).setStatus(Dot.STATUS_ON);
i ++;
}
} }
private boolean isAtEdge(Dot dot){
//判断某个圆圈是否在边缘
if(dot.getX() * dot.getY() == 0 || dot.getX()+1 == ROW || dot.getY() + 1 == COL){
return true;
}
return false;
}
//获取某个圆圈的左起1,2,3,4,5,6方向的相邻的圆圈
private Dot neighbour(Dot dot,int dir){
int x = -1;
int y = -1;
switch (dir){
case 1:
//return getDot(dot.getX()-1,dot.getY());
x = dot.getX()-1;
y = dot.getY();
break;
case 2:
if(dot.getY() % 2 == 0){
x = dot.getX() - 1;
y = dot.getY() - 1;
}
else {
x = dot.getX();
y = dot.getY() - 1;
}
break;
case 3:
if(dot.getY() % 2 == 0){
x = dot.getX() ;
y = dot.getY() - 1;
}
else {
x = dot.getX() + 1;
y = dot.getY() - 1;
}
break;
case 4:
x = dot.getX() + 1;
y = dot.getY();
break;
case 5:
if(dot.getY() % 2 == 0){
x = dot.getX() ;
y = dot.getY() + 1;
}
else {
x = dot.getX() + 1;
y = dot.getY() + 1;
}
break;
case 6:
if(dot.getY() % 2 == 0){
x = dot.getX() - 1;
y = dot.getY() + 1;
}
else {
x = dot.getX();
y = dot.getY() + 1;
}
break;
}
if (x != -1 || y != -1){
return getDot(x,y);
}
return null;
}
//获取某个圆圈在某个方向到矩阵边缘或到障碍的距离,如果是到边缘,返回正值,如果是到障碍,返回负值
private int getDistance(Dot dot,int dir){
int distance = 0;
if (isAtEdge(dot)){
return 1;
}
Dot ori = dot;
Dot next;
while (true){
next = neighbour(ori,dir);
if (next.getStatus() == Dot.STATUS_ON){
return distance * -1;
}
if (isAtEdge(next)){
distance ++;
return distance;
}
distance ++;
ori = next;
}
}
//将猫移动到某个圆圈
private void moveTo(Dot dot){
Dot temp = new Dot();
temp = dot;
dot = cat;
cat = temp;
cat.setStatus(Dot.STATUS_IN);
dot.setStatus(Dot.STATUS_OFF);
//如果移动后猫已在矩阵边缘,则游戏失败
if (isAtEdge(cat)){
lose();
}
// getDot(cat.getX(),cat.getY()).setStatus(Dot.STATUS_OFF);
// dot.setStatus(Dot.STATUS_IN);
// cat.setXY(dot.getX(), dot.getY());
}
private Dot getDot(int x,int y){
return matrix[y][x];
}
Callback callback = new Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
redraw();
} @Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
//根据屏幕自适应每个圆圈的宽度
WIDTH = width / (COL + 1);
redraw();
} @Override
public void surfaceDestroyed(SurfaceHolder holder) { }
}; @Override
public boolean onTouch(View v, MotionEvent event) {
// Log.i("info","33333"); if (event.getAction() == MotionEvent.ACTION_UP){
// Log.i("info", "44444");
// Toast.makeText(getContext(),event.getX() + ":" + event.getY(),Toast.LENGTH_SHORT).show();
int x,y;
//获取点击点所在的列数
y = (int) (event.getY() / WIDTH);
//获取点击点所在的行数
if (y % 2 == 0){
x = (int) (event.getX() / WIDTH);
}
else {
x = (int) ((event.getX() - WIDTH/2) / WIDTH);
}
//如果点击点不在矩阵范围内,重新初始化游戏
if (x + 1 > COL || y + 1 > ROW){
initGame();
}
//否则如果点击的圆圈的状态是可点击的,就将此圆圈的状态设置为障碍,并将猫进行移动
else if (getDot(x,y).getStatus() == Dot.STATUS_OFF){
getDot(x,y).setStatus(Dot.STATUS_ON);
move();
}
redraw();
//
}
return true;
} private void move() {
//如果猫已在矩阵边缘,则游戏失败
if (isAtEdge(cat)){
lose();
return;
}
//猫可以移动的圆圈
Vector<Dot> available = new Vector<Dot>();
//猫可以移动的到矩阵边缘没有障碍的圆圈
Vector<Dot> positive = new Vector<Dot>();
HashMap<Dot,Integer> al = new HashMap<Dot,Integer>();
for (int i =1;i<7;i++){
Dot n = neighbour(cat,i);
if(n.getStatus() == Dot.STATUS_OFF){
available.add(n);
al.put(n,i);
if (getDistance(n,i) > 0){
positive.add(n);
}
}
}
//如果猫没有可以移动的圆圈,则游戏成功
if (available.size() == 0){
win();
}
//如果猫只有一个可以移动的圆圈,则移动到此圆圈
else if (available.size() == 1){
moveTo(available.get(0));
}
//否则选最优的圆圈进行移动
else{
Dot best = null;
//如果存在可以直接到达屏幕边缘的走向
if (positive.size() != 0){
System.out.println("向前进");
int min = 999;
for (int i = 0;i < positive.size();i ++){
int a = getDistance(positive.get(i), al.get(positive.get(i)));
if (a < min){
min = a;
best = positive.get(i);
}
}
}
//所有路径均有路障
else{
System.out.println("躲路障");
int max = 0;
for (int i = 0; i < available.size();i ++){
int k = getDistance(available.get(i),al.get(available.get(i)));
if (k < max){
max = k;
best = available.get(i);
}
}
} if(best != null) {
moveTo(best);
}
else{
moveTo(available.get(0));
} // Dot d = available.get(0);
// for (int i = 1;i<available.size();i++){
// if ( Math.min(available.get(i).getX(), available.get(i).getY()) < Math.min(d.getX(),d.getY()) ){
// d = available.get(i);
// }
// }
// moveTo(d);
}
}
//赢得游戏
private void win() {
Toast.makeText(getContext(),"YOU HAVE WON THE GAME!",Toast.LENGTH_SHORT).show();
}
//游戏失败
private void lose() {
Toast.makeText(getContext(),"YOU HAVE LOST THE GAME!",Toast.LENGTH_SHORT).show();
}
} 注:由于本项目只是用于简单学习交流,代码中难免会有bug出现,请自行调试修改。
Android实战源码--围住神经猫的更多相关文章
- Android项目源码分享
http://blog.csdn.net/gao_chun/article/details/47263063 Android项目源码分享 给大家分享几个Android开发项目源码,大部分功能相信可以在 ...
- 45个android实例源码
分享45个android实例源码,很好很强大http://www.apkbus.com/android-20978-1-1.html andriod闹钟源代码http://www.apkbus.com ...
- 分享45个android实例源码,很好很强大
分享45个android实例源码,很好很强大 http://www.apkbus.com/android-20978-1-1.html 分享45个android实例源码,很好很强大http://www ...
- 将Android系统源码导入ecplise
Android系统源码中带有个IDE的配置文件,目录为:development/ide/ 如果要用eclipse导入查看系统源码,则将development/ide/eclipse/.classpat ...
- Android 如何在Eclipse中查看Android API源码 及 support包源码
当我们阅读android API开发文档时候,上面的每个类,以及类的各个方法都是已经写好的方法和控件,可是我们只是在搬来使用,不知道它的原理,它是如何被实现的.android系统是开源的,所以谷歌官方 ...
- Android之源码之模块编译和调试
Android之源码之模块编译调试 (一) 进行源码模块修改进行编译的调试 1.首先是从git或者svn上拉一套完整的工程下来,然后全编一下,一般这个时间比较长,大概会得2,3个小时左右, 2,编译成 ...
- 关于查看Android系统源码【Written By KillerLegend】
可能你会想下载Android系统源码,但是我不知道你会看多少系统的源码,如果你对源码只是偶尔看一次的话,推荐你在线看Android的系统源码,下面提供几种查看android系统源码的方法. 1:打开这 ...
- 【转】Android 如何在Eclipse中查看Android API源码 及 support包源码
原文网址:http://blog.csdn.net/vipzjyno1/article/details/22954775 当我们阅读android API开发文档时候,上面的每个类,以及类的各个方法都 ...
- 将android Settings 源码 导入到 eclipse工程
1. 新建 android 项目 拷贝源码/packages/apps/Settings到你的其它目录. 在eclipse中,新建项目,但是要从exitting source选择: 2. 导入相关的 ...
随机推荐
- mysqldb mysql_config
在安装mysqldb Python的时候会用到mysql_config,但是正常安装的MySQL环境下是没有这个文件的,这个文件在Linux下是可执行文件,所以需要到mysql官方网站上下载MySQL ...
- tomcat项目中配置数据库连接池
1. 在项目中新建context.xml文件,不要在tomcat服务器的目录中修改context.xml(会对整个服务器生效).. 在web项目的META-INF中存放context.xml 2. ...
- 2019.01.19 bzoj4592: [Shoi2015]脑洞治疗仪(ODT)
传送门 ODT水题. 支持区间01赋值,区间填补(把区间[l,r][l,r][l,r]从左往右数kkk个1都变成0),区间查询最长连续1个数. 思路: 区间填补操作感觉不是很好弄,写线段树的神仙可以套 ...
- 蓝绿部署、红黑部署、AB测试、灰度发布、金丝雀发布、滚动发布的概念与区别(转)
出处:https://www.baidu.com/link?url=QjboallwNm_jxcL3fHG57wEakiBfAs_3-TChTGu1eBXstlHEsGBc-NDA7AKTqsiroB ...
- oracle学习笔记一:用户管理(3)用户口令管理
当某个用户不断的尝试密码进行登录数据库是很危险的,因此对密码(口令)的管理十分重要.好在我们可以限制登录次数,超过某些次数的登录将会把用户锁住,隔一段时间才允许其登录,这和你的手机是不是有点一样,你的 ...
- 1.8.1suspend与resume方法使用
暂停线程意味着线程还能恢复运行 suspend()方法暂停线程.resume()恢复线程 测试如下 package com.cky.thread; /** * Created by edison on ...
- _编程语言_C++_setw()
C++ 中使用setw(int n) 来控制输出间隔. 例如: cout<<)<<'a'<<endl;//s与a之间有7个空格,setw()只对后面紧跟的输出产生作 ...
- noip第22课作业
1. 数字分解 [问题描述] 任何一个大于1的自然数n,总可以拆分成若干个小于n的自然数之和,当n等于5时有6种拆分方法: 5=1+1+1+1+1 5=1+1+1+2 5=1+1+3 5=1+2+ ...
- Android 模仿微信发送图片 钟罩效果
参考资料http://trylovecatch.iteye.com/blog/1189452 http://bbs.51cto.com/thread-1031415-1.html### 1.添加资源文 ...
- hdu 5089 使做对k-1题最大概率的选题方案
http://acm.hdu.edu.cn/showproblem.php?pid=5089 给出N道难度递增的题目,难度用可能做出的百分比表示,选出K道题目使得做出K-1道题目的概率最大. 选k题的 ...