android 2048游戏实现
android 的2048小游戏完整实现:GridLayout布局(android 4.0及以上)。
曾经做过一个2048的算法题,学了几天android,认为能够实现个安卓版的。也就动手写了个。
包括的东西:
GridLayout布局
在activity中动态加入view组件
推断用户在屏幕滑动的的方向
2048算法(參考之前用C++写的,写的还算通俗易懂吧,http://blog.csdn.net/liang5630/article/details/39895087)。
不多说,先上图:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGlhbmc1NjMw/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
package com.example.y2048; import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.GridLayout;
import android.widget.TextView;
import android.widget.Toast; import com.example.y2048.map.Direction;
import com.example.y2048.map.Maps; public class MainActivity extends Activity {
private String tag = "GridLayoutActivity";
GridLayout gridLayout;
float startX = 0, startY = 0, endX, endY;
Maps maps = new Maps();
private TextView score;
private TextView best; @SuppressLint("NewApi")
void init() {
// 获取View对象
gridLayout = (GridLayout) findViewById(R.id.root); for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
Button bn = new Button(this);
bn.setClickable(false);
bn.setText("");
// 设置该button的字号大小
bn.setTextSize(30);
bn.setWidth(120);
bn.setHeight(120);
// 指定该组件所在的行
GridLayout.Spec rowSpec = GridLayout.spec(i + 2);
// 指定该组件所在的列
GridLayout.Spec columnSpec = GridLayout.spec(j);
String msg = "rowSpec:" + (i + 2) + " - columnSpec:" + (j);
Log.d(tag, msg);
GridLayout.LayoutParams params = new GridLayout.LayoutParams(
rowSpec, columnSpec);
// 指定该组件占满容器
// params.setGravity(Gravity.FILL);
gridLayout.addView(bn, params);
maps.addButton(i, j, bn);
}
}
score = (TextView) findViewById(R.id.score);
score.setText("0");
best = (TextView) findViewById(R.id.best);
maps.setScore(score);
maps.setBest(best);
maps.init();
} @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
} @Override
public boolean dispatchTouchEvent(MotionEvent event) { // System.out.println("触摸");
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {
startX = event.getX();
startY = event.getY();
} else if (action == MotionEvent.ACTION_UP) {
endX = event.getX();
endY = event.getY();
int direction = GetSlideDirection(startX, startY, endX, endY);
// System.out.println(startX+","+startY+"|"+endX+","+endY+" "+direction);
// Toast.makeText(this, direction+"", Toast.LENGTH_LONG).show();
boolean gameOver = maps.Slide(direction);
if (gameOver) {
if(maps.getScore()>maps.getBestScore()){
Toast.makeText(this, "恭喜超过最佳记录!。!", Toast.LENGTH_SHORT).show();
maps.setBestScore(maps.getScore());
best.setText(maps.getScore()+"");
}else{
Toast.makeText(this, "GameOver", Toast.LENGTH_SHORT).show();
} }
}
return super.dispatchTouchEvent(event);
} // 返回角度
private double GetSlideAngle(float dx, float dy) {
return Math.atan2(dy, dx) * 180 / Math.PI;
} // 依据起点和终点返回方向 1:向上。2:向下,3:向左,4:向右,0:未滑动
private int GetSlideDirection(float startX, float startY, float endX,
float endY) {
float dy = startY - endY;
float dx = endX - startX;
int result = Direction.NONE;
// 假设滑动距离太短
if (Math.abs(dx) < 2 && Math.abs(dy) < 2) {
return result;
}
double angle = GetSlideAngle(dx, dy);
if (angle >= -45 && angle < 45) {
return Direction.RIGHT;
} else if (angle >= 45 && angle < 135) {
return Direction.UP;
} else if (angle >= -135 && angle < -45) {
return Direction.DOWN;
} else if ((angle >= 135 && angle <= 180)
|| (angle >= -180 && angle < -135)) {
return Direction.LEFT;
}
return result;
} public void reset(View view) {
maps.init();
} }
package com.example.y2048.map;
public interface Direction {
//1:向上,2:向下,3:向左,4:向右,0:未滑动
static final int LEFT=3;
static final int RIGHT=4;
static final int UP=1;
static final int DOWN=2;
static final int NONE=0;
}
package com.example.y2048.map; import java.util.Random; import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.view.View;
import android.widget.Button;
import android.widget.TextView; public class Maps {
private TextView score;
private TextView best;
private Button[][] maps = new Button[4][4]; public void addButton(int i, int j, Button btn) {
maps[i][j] = btn;
} private void swapText(Button btn1, Button btn2) {
CharSequence text = btn1.getText();
btn1.setText(btn2.getText());
btn2.setText(text);
} void up_remove_blank() {
int i, j, k;
for (j = 0; j < 4; j++) {
for (i = 1; i < 4; i++) {
k = i;
while (k - 1 >= 0
&& maps[k - 1][j].getText().toString().length() == 0) {// 上面的那个为空
swapText(maps[k][j], maps[k - 1][j]);
k--; }
}
}
} void down_remove_blank() {
int i, j, k;
for (j = 0; j < 4; j++) {
for (i = 2; i >= 0; i--) {
k = i;
while (k + 1 <= 3
&& maps[k + 1][j].getText().toString().length() == 0) {// 上面的那个为空
swapText(maps[k][j], maps[k + 1][j]);
k++;
}
}
}
} void left_remove_blank() {
int i, j, k;
for (i = 0; i < 4; i++) {
for (j = 1; j < 4; j++) {
k = j;
while (k - 1 >= 0
&& maps[i][k - 1].getText().toString().length() == 0) {// 上面的那个为空
swapText(maps[i][k], maps[i][k - 1]);
k--;
}
}
}
} void right_remove_blank() {
int i, j, k;
for (i = 0; i < 4; i++) {
for (j = 2; j >= 0; j--) {
k = j;
while (k + 1 <= 3
&& maps[i][k + 1].getText().toString().length() == 0) {// 上面的那个为空
swapText(maps[i][k], maps[i][k + 1]);
k++;
}
}
}
} void left() {
int i, j;
for (i = 0; i < 4; i++) {
for (j = 0; j < 3; j++) {
String s1 = maps[i][j].getText().toString();
String s2 = maps[i][j + 1].getText().toString(); if (s1.equals(s2) && !s1.equals("")) {
// maps[i][j]+=maps[i][j+1];
Integer sum = Integer.valueOf(maps[i][j].getText()
.toString());
sum += Integer.valueOf(maps[i][j + 1].getText().toString()); int total = Integer.valueOf(score.getText().toString());
score.setText(String.valueOf(sum + total));
maps[i][j].setText(sum.toString());
maps[i][j + 1].setText("");
left_remove_blank();
}
}
}
} void right() {
int i, j;
for (i = 0; i < 4; i++) {
for (j = 3; j >= 1; j--) {
String s1 = maps[i][j].getText().toString();
String s2 = maps[i][j - 1].getText().toString();
if (s1.equals(s2) && !s1.equals("")) {
// maps[i][j]+=maps[i][j-1];
// maps[i][j-1]=0;
Integer sum = Integer.valueOf(maps[i][j].getText()
.toString());
sum += Integer.valueOf(maps[i][j - 1].getText().toString());
int total = Integer.valueOf(score.getText().toString());
score.setText(String.valueOf(sum + total));
maps[i][j].setText(sum.toString());
maps[i][j - 1].setText("");
right_remove_blank();
}
}
}
} void up() {
int i, j;
for (j = 0; j < 4; j++) {// 每一列
for (i = 0; i < 3; i++) {
String s1 = maps[i][j].getText().toString();
String s2 = maps[i + 1][j].getText().toString();
if (s1.equals(s2) && !s1.equals("")) {
// maps[i][j]=maps[i][j]+maps[i+1][j];
// maps[i+1][j]=0;
Integer sum = Integer.valueOf(maps[i][j].getText()
.toString());
sum += Integer.valueOf(maps[i + 1][j].getText().toString());
int total = Integer.valueOf(score.getText().toString());
score.setText(String.valueOf(sum + total));
maps[i][j].setText(sum.toString());
maps[i + 1][j].setText("");
// 移除空格
up_remove_blank();
}
}
}
} void down() {
int i, j;
for (j = 0; j < 4; j++) {// 每一列
for (i = 3; i >= 1; i--) {
String s1 = maps[i][j].getText().toString();
String s2 = maps[i - 1][j].getText().toString();
if (s1.equals(s2) && !s1.equals("")) {
// maps[i][j]=maps[i][j]+maps[i-1][j];
// maps[i-1][j]=0;
Integer sum = Integer.valueOf(maps[i][j].getText()
.toString());
sum += Integer.valueOf(maps[i - 1][j].getText().toString());
int total = Integer.valueOf(score.getText().toString());
score.setText(String.valueOf(sum + total));
maps[i][j].setText(sum.toString());
maps[i - 1][j].setText("");
// 移除空格
down_remove_blank();
}
}
}
} private void addNumber() {
Random random = new Random();
int x = random.nextInt(4);
int y = random.nextInt(4);
int number = random.nextInt(20);//出现2的概率为95% 4的概率5%
if(number==0) number=4;
else number=2;
while (maps[x][y].getText().toString().length() != 0) {
x = random.nextInt(4);
y = random.nextInt(4);
}
maps[x][y].setText(number + "");
} public void init() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
maps[i][j].setText("");
}
}
score.setText("0");
addNumber();
addNumber();
} private boolean isFull() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (maps[i][j].getText().toString().length() == 0) {
return false;
}
}
}
return true;
} public boolean Slide(int direction) {
if (direction == Direction.LEFT) {
left_remove_blank();
left();
if (isFull())
return true;
else {
addNumber();
}
} else if (direction == Direction.RIGHT) {
right_remove_blank();
right();
if (isFull())
return true;
else {
addNumber();
}
} else if (direction == Direction.UP) {
up_remove_blank();
up();
if (isFull())
return true;
else {
addNumber();
}
} else if (direction == Direction.DOWN) {
down_remove_blank();
down();
if (isFull())
return true;
else {
addNumber();
}
}
return false;
} public void setScore(TextView score) {
this.score = score;
} public void setBest(TextView best) {
this.best = best;
best.setText(getBestScore()+"");
}
public int getScore(){
return Integer.valueOf(score.getText().toString());
}
public int getBestScore(){
SharedPreferences sp = best.getContext().getSharedPreferences("bestScore.txt", Context.MODE_PRIVATE);
int bestScore=sp.getInt("bestScore", 0);
return bestScore;
}
public void setBestScore(int score){
SharedPreferences sp = best.getContext().getSharedPreferences("bestScore.txt", Context.MODE_PRIVATE);
Editor edit = sp.edit();
edit.putInt("bestScore", score);
edit.commit();
} }
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnCount="4"
android:rowCount="6"
tools:ignore="NewApi" > <TextView
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:gravity="center"
android:text="Score:" /> <TextView
android:id="@+id/score"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:gravity="center"
android:text="Score:" /> <TextView
android:layout_width="wrap_content"
android:layout_height="50dp"
android:gravity="center"
android:text="Best:" /> <TextView
android:id="@+id/best"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:gravity="center" /> <Button
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_columnSpan="4"
android:onClick="reset"
android:text="reset" /> </GridLayout>
转载请注明出处:http://blog.csdn.net/liang5630/article/details/41251549
源代码及apk下载:
android 2048游戏实现的更多相关文章
- android 2048游戏、kotlin应用、跑马灯、动画源码
Android精选源码 2048游戏源码 android实现获取号码归属地和其他信息诈骗.骚扰 android kotlin仿开眼app源码 android多种reveal动画效果 android K ...
- Android项目开发实战-2048游戏
<2048>是一款比较流行的数字游戏,最早于2014年3月20日发行.原版2048首先在GitHub上发布,原作者是Gabriele Cirulli,后被移植到各个平台.这款游戏是基于&l ...
- Cocos2d-html5入门之2048游戏
一.介绍 Cocos2d-JS是Cocos2d-x的Javascript版本,它的前身是Cocos2d-html5.在3.0版本以前叫做Cocos2d-html5,从3.0版本开始叫做Cocos2d- ...
- 2048游戏分析、讨论与扩展 - Part I - 游戏分析与讨论
2048这个游戏从刚出開始就风靡整个世界. 本技术博客的目的是想对2048涉及到相关的全部问题进行仔细的分析与讨论,得到一些大家能够接受而且理解的结果. 在这基础上,扩展2048的游戏性,使其变得更好 ...
- 用javascript实现一个2048游戏
早就想自己写一个2048游戏了,昨晚闲着没事,终于写了一个 如下图,按方向键开始玩吧. 如果觉得操作不方便,请直接打开链接玩吧: http://gujianbo.1kapp.com/2048/2048 ...
- Android原生游戏开发:使用JustWeEngine开发微信打飞机
使用JustWeEngine开发微信打飞机: 作者博客: 博客园 引擎地址:JustWeEngine 示例代码:EngineDemo JustWeEngine? JustWeEngine是托管在Git ...
- powershell字符界面的,powershell加WPF界面的,2048游戏
------[序言]------ 1 2048游戏,有段时间很火,我在地铁上看有人玩过.没错,坐地铁很无聊,人家玩我就一直盯着看. 2 我在电脑上找了一个,试玩了以下,没几次格子就满了.我就气呼呼的放 ...
- [python] python实现2048游戏,及代码解析。
我初学python,有不对之处望大家指教.转载请征得同意. 我在网络上也找了一些2048游戏代码的讲解,但都不是特别详细.所以我希望能够尽量详细的讲解.同时,有的地方我也不懂,希望大家能帮助补充.我会 ...
- 对弈类游戏的人工智能(5)--2048游戏AI的解读
前言: 闲得没事, 网上搜"游戏AI", 看到一篇<<2048游戏的最佳算法是?来看看AI版作者的回答>>的文章. 而这篇文章刚好和之前讲的对弈类游戏AI对 ...
随机推荐
- [CQOI2015]任务查询系统 主席树_差分
Code: #include<vector> #include<cstdio> #include<algorithm> #include<string> ...
- linux上使用chrome自动化测试(无界面)
selenium自动化测试主要是用于有图形界面的系统上,对于无图形界面的情况可以通过以下方法来实现 服务器信息 [root@spider01 ~]# hostnamectl Static hostna ...
- 虚拟机virtualbox,直接复制本机虚拟硬盘vdi使用, 会提示错误的解决方法
提示语句为: 打开硬盘文件D:\Virtualbox\debian9 - 副本.vdi 失败. 明细(D) Cannot register the hard disk ‘D:\Virtualbox\d ...
- 题解 洛谷 P3381 【【模板】最小费用最大流】
发了网络流,再来一发费用流 能做费用流的,网络流自然做得来,但在这还是不要脸的安利一下自己的博客(里面也有网络流的题解): 点我 扯远了... 费用流,就是在不炸水管的情况下求源点到汇点的最小费用. ...
- Linux内存管理与C存储空间
ELF文件 在学习之前我们先看看ELF文件. ELF分为三种类型:.o 可重定位文件(relocalble file),可执行文件以及共享库(shared library),三种格式基本上从结构上是一 ...
- 2019年北航OO第三单元(JML规格任务)总结
一.JML简介 1.1 JML与契约式设计 说起JML,就不得不提到契约式设计(Design by Contract).这种设计模式的始祖是1986年的Eiffel语言.它是一种限定了软件中每个元素所 ...
- 洛谷——P3370 【模板】字符串哈希
题目描述 如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字.大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串. 友情提醒:如果真的想好好练习哈希的话,请自觉,否则请右转 ...
- Qt之pro配置多个子工程/子模块
简述 进行Qt项目开发的时候,尤其是大型项目,经常涉及多工程/多模块问题,其主要思想还是模块化,目的是为了降低程序复杂度,使程序设计.调试和维护等操作简单化. 简述 配置 效果 多工程 多模块 更多参 ...
- mac和iphone处理视频
今天在微信上面发现有视频打不开,也无法下载到相册 而到电脑上可以打开 搜了一下,发现格式不对,mp4有很多格式,有的是苹果支持不了的. 要下载一个转换器,我下载了“超级转霸”,然后把视频转成了ipho ...
- 6、python中的字符串
最早的编码为ascii码,共256个符号.UTF-8是国际通用编码,全面支持中文,以一个字节表示英文,以三个字节表示一个中文以及其他语言:GB2312是我国自己定制的中文编码标准,使用1个字节表示英文 ...