Android開發簡單的2048遊戲
作為一名android渣渣第一次用android寫了個簡單的小遊戲還是模仿網上的視訊寫的,,哎,,
寫在前面:這裡我用的IDE是eclipse,所以對與 Android studio 的來說可能會有點那個,,,
但是主要的程式碼應該沒問題的哈,,
介面和實現的邏輯:
1,activity_main.xml
這是遊戲的主介面(layout),遊戲介面 整體採用線性佈局,然後巢狀一個計分器面板也是線性佈局,
中間用了兩個textView一個顯示Score字型一個顯示分數然後下面的遊戲介面用個類繫結,類繼承
格子布局,然後遊戲的主要佈局就在那個類中實現
2,card.java 類
這是2048遊戲中的抽象出來的卡片,這裡我們來定義一些卡片的性質和一些介面供我們只用,我們用
個lable元件來表示卡片,大小為32*32顯示的數字為num,如果是0就是空 ,顏色會根據數字的不同而
不同,佈局用layoutparms 來控制,邊距為10,即格子與格子之間的距離為10
3,GameView.java 類
這裡是遊戲介面的佈局和遊戲邏輯的控制,首先通過建構函式來初始化遊戲initGameView()這裡面設定
介面佈局的列為4列,背景顏色為0xffbbada0然後 寫個監聽事件,監聽觸控事件,setOnTouchListener,
首先這裡我們定義startX,startY,offsetX,offsetY,當觸控時startX = even.getX(),startY = even.getY()當觸
摸結束時,offsetX = even.getX ()- startX offsetY = even.getY ()- startY 有了這些變數我們就可以判斷
手指滑動的方向了,如果如果abs(offsetX)>abs(offsetY)則滑動的方向定義為水平移動,然後我們定義
如果offset X<-5則為向左,這裡取了個相對值,其他的同理可得,然後我們過載 onSizeChanged方法,
即,如果視窗大改變是就執行這個方法,一開始開啟時視窗大小方式改變,這裡要在配置檔案裡配置
螢幕為豎屏,然後就執行這個方法,所以我們可以在這裡記錄卡片的長寬 = (min(w,h) -10)/4,然後
addCard(); startGame();在addCard中我們首先定義了個card的二維陣列來儲存介面上的4*4的卡片,
然後初始值為0,這裡就初始了介面的4*4的卡片,然後就是隨機新增兩個卡片這裡寫個隨機生成卡片
的方法,首先我們用個集合把所有空的卡片的點存進去,然後從中隨機生成個,然後在隨機生成個
數,這裡2:4 = 9:1 ,所以我們就可以判斷生成0-1的數與0.1比較,然後就實現了這個1:9,接下來就
是移動的操作,我們分別寫四個方法實現上下左右的操作,對於一種操作我們用三層迴圈去遍歷,
這裡我們假設向右,我們外層迴圈遍歷x,y從1-4,然後記憶體迴圈遍歷4到y+1,即每一行向右移動,
我們先從最右邊找,看它的左邊是否有卡片,然後還要判斷是否相同,相同就把數字相加存在最右
邊這個卡片,不相同就把卡片移動到它的左邊,然後向左移動一格(如果當前有)如果出現過有效
的移動就要在隨機一個卡片,最後判斷結束就是沒有空的卡片並且沒有相鄰且數字相同的卡片
上面就是我簡單的介紹我的程式碼的三個主要的程式碼類,其中有些模糊希望理解,表達不是很清晰,主要還是看程式碼吧!
MainActivity.java
package com.example.game2048;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;
public class MainActivity extends Activity {
public MainActivity() {
// TODO Auto-generated constructor stub
setMainActivity(this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvScore = (TextView) findViewById(R.id.tvScore);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void clearScore(){
score = 0;
showScore();
}
public void showScore(){
tvScore.setText(score+"");
}
public void addScore(int s){
score+=s;
showScore();
}
public static MainActivity getMainActivity() {
return mainActivity;
}
public static void setMainActivity(MainActivity mainActivity) {
MainActivity.mainActivity = mainActivity;
}
private int score = 0;
private TextView tvScore;
private static MainActivity mainActivity = null;
}
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/score"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tvScore"/>
</LinearLayout>
<com.example.game2048.GameView
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/gameView">
</com.example.game2048.GameView>
</LinearLayout>
card.java
package com.example.game2048;
import android.R.color;
import android.content.Context;
import android.content.pm.LabeledIntent;
import android.graphics.Color;
import android.view.Gravity;
import android.widget.FrameLayout;
import android.widget.TextView;
public class Card extends FrameLayout {
// 記錄卡片的顏色
private int [] cardColor = new int[30];
//初始化卡片的顏色
public void setColor(){
cardColor[0] =Color.BLUE;
cardColor[1] = Color.CYAN;
cardColor[8] = Color.DKGRAY;
cardColor[5] = Color.GRAY;
cardColor[4] = Color.GREEN;
cardColor[3] = Color.RED;
cardColor[6] = Color.LTGRAY;
cardColor[7] = Color.MAGENTA;
cardColor[2]= Color.YELLOW;
cardColor[9] = Color.WHITE;
cardColor[10] = Color.TRANSPARENT;
}
//構造方法
public Card(Context context) {
super(context);
setColor();
lable = new TextView(getContext());
lable.setTextSize(32); //設定大小
lable.setBackgroundColor(0x33ffffff); //背景顏色
lable.setGravity(Gravity.CENTER); //佈局為居中
LayoutParams lp = new LayoutParams(-1,-1);
lp.setMargins(10, 10, 0, 0); //邊距為10
addView(lable, lp);
setNum(0);
}
private int num = 0;
//獲取數字
public int getNum() {
return num;
}
//設定數字
public void setNum(int num) {
this.num = num;
if(num<=0){
lable.setBackgroundColor(0x33ffffff);
lable.setText("");
}else {
//取log得到x設定顏色
int x =(int) (Math.log((double)num));
x%=11;
lable.setBackgroundColor(cardColor[x]);
lable.setText(num+"");
}
}
//卡片的lable元件
private TextView lable;
//判斷是否相等
public boolean equals(Card o) {
// TODO Auto-generated method stub
return num==o.getNum();
}
}
GameView.java
package com.example.game2048;
import java.util.ArrayList;
import java.util.List;
import android.R.bool;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Point;
import android.provider.ContactsContract.CommonDataKinds.Event;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.GridLayout;
public class GameView extends GridLayout {
//構造方法
public GameView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
initGameView();
}
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
initGameView();
}
public GameView(Context context) {
super(context);
// TODO Auto-generated constructor stub
initGameView();
}
//初始化遊戲
private void initGameView(){
setColumnCount(4); //設定列為4
setBackgroundColor(0xffbbada0); //設定背景色
//監聽觸控事件
setOnTouchListener(new OnTouchListener() {
private float startX,startY,offsetX,offsetY; //四個變數記錄初始位置和偏移量
@Override
public boolean onTouch(View arg0, MotionEvent even) {
// TODO Auto-generated method stub
switch(even.getAction()){
case MotionEvent.ACTION_DOWN: //記錄初始位置
startX = even.getX();
startY = even.getY();
break;
case MotionEvent.ACTION_UP: //記錄偏移量
offsetX = even.getX()-startX;
offsetY = even.getY() -startY;
if(Math.abs(offsetX)>Math.abs(offsetY)){ //X的偏移量大於Y的偏移量
if(offsetX<-5){
swipeLeft(); //向左的操作
}else {
swipeRight(); //向右的操作
}
}else {
if(offsetY<-5){
swipeUp(); //向上的操作
}else{
swipeDown(); //向下的操作
}
}
break;
}
return true;
}
});
}
//過載方法,視窗大小改變使執行
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
// TODO Auto-generated method stub
super.onSizeChanged(w, h, oldw, oldh);
//記錄卡片的大小
int cardWidth = (Math.min(w, h)-10)/4;
//新增卡片
addCards(cardWidth, cardWidth);
//開始遊戲
startGame();
}
//新增卡片
private void addCards(int cardWidth,int cardHeight){
Card card;
//4*4
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
card = new Card(getContext()); //初始化卡片物件
card.setNum(0); //初始值為0
addView(card,cardWidth,cardHeight);//新增
cardsMap[i][j] = card; //將卡片與cardMap繫結
}
}
}
//新增隨機卡片
private void addRandomNum(){
//記錄空卡片的點的集合
emptyPoints.clear();
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if(cardsMap[j][i].getNum()<=0){
emptyPoints.add(new Point(j,i)); //新增所有空卡片
}
}
}
Point point = emptyPoints.remove((int)(Math.random()*emptyPoints.size())); //從空卡片中隨機一個卡片
cardsMap[point.x][point.y].setNum(Math.random()>0.1?2:4); //隨機生成一個數 2:4 = 1:9
}
//開始遊戲方法
private void startGame(){
//分數清零
MainActivity.getMainActivity().clearScore();
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
cardsMap[j][i].setNum(0); //初始化為0
}
}
//隨機生成兩個卡片
addRandomNum();
addRandomNum();
}
//向左移動的方法
private void swipeLeft(){
boolean flag = false;
for(int x = 0;x<4;x++){
for(int y = 0;y<4;y++){
for(int y1 = y+1;y1<4;y1++){
if(cardsMap[x][y1].getNum()>0){ //如果列舉位置有卡片
if(cardsMap[x][y].getNum()<=0){ //如果當前位置沒有卡片
cardsMap[x][y].setNum(cardsMap[x][y1].getNum()); //直接移動到當前位置
cardsMap[x][y1].setNum(0);
y--; //向前移動
flag = true;
}else if(cardsMap[x][y].equals(cardsMap[x][y1])){ //如果當前位置有卡片且相等
cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2); //覆蓋當前卡片並且陣列相加
cardsMap[x][y1].setNum(0);
MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum()); //分數增加
flag = true;
}
break;
}
}
}
}
if(flag){
//如果有有效移動則隨機一張卡片並且判斷是否結束
addRandomNum();
checkComplete();
}
}
//同上 向右移動的操作
private void swipeRight(){
boolean flag = false;
for(int x = 0;x<4;x++){
for(int y = 3;y>=0;y--){
for(int y1 = y-1;y1>=0;y1--){
if(cardsMap[x][y1].getNum()>0){
if(cardsMap[x][y].getNum()<=0){
cardsMap[x][y].setNum(cardsMap[x][y1].getNum());
cardsMap[x][y1].setNum(0);
y++;
flag = true;
}else if(cardsMap[x][y].equals(cardsMap[x][y1])){
cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2);
cardsMap[x][y1].setNum(0);
MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum());
flag = true;
}
break;
}
}
}
}
if(flag){
addRandomNum();
checkComplete();
}
}
//同上,向上移動的操作
private void swipeUp(){
boolean flag = false;
for(int y = 0;y<4;y++){
for(int x = 0;x<4;x++){
for(int x1 = x+1;x1<4;x1++){
if(cardsMap[x1][y].getNum()>0){
if(cardsMap[x][y].getNum()<=0){
cardsMap[x][y].setNum(cardsMap[x1][y].getNum());
cardsMap[x1][y].setNum(0);
x--;
flag = true;
}else if(cardsMap[x][y].equals(cardsMap[x1][y])){
cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2);
cardsMap[x1][y].setNum(0);
MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum());
flag = true;
}
break;
}
}
}
}
if(flag){
addRandomNum();
checkComplete();
}
}
//同上,向下移動的操作
private void swipeDown(){
boolean flag = false;
for(int y = 0;y<4;y++){
for(int x = 3;x>=0;x--){
for(int x1 = x-1;x1>=0;x1--){
if(cardsMap[x1][y].getNum()>0){
if(cardsMap[x][y].getNum()<=0){
cardsMap[x][y].setNum(cardsMap[x1][y].getNum());
cardsMap[x1][y].setNum(0);
x++;
flag = true;
}else if(cardsMap[x][y].equals(cardsMap[x1][y])){
cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2);
cardsMap[x1][y].setNum(0);
MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum());
flag = true;
}
break;
}
}
}
}
if(flag){
addRandomNum();
checkComplete();
}
}
//判斷是否結束遊戲
private void checkComplete(){
boolean complete = true;
All:
for(int x = 0;x<4;x++){
for(int y=0;y<4;y++){
//判斷有空或上下左右有相同的卡片則沒結束
if(cardsMap[x][y].getNum()==0||
(x-1>=0&&cardsMap[x][y].equals(cardsMap[x-1][y]))||
(x+1<4&&cardsMap[x][y].equals(cardsMap[x+1][y]))||
(y-1>=0&&cardsMap[x][y].equals(cardsMap[x][y-1]))||
(y+1<4&&cardsMap[x][y].equals(cardsMap[x][y+1]))){
complete = false;
break All;
}
}
}
//遊戲結束
if(complete){
new AlertDialog.Builder(getContext()).setTitle("你好").setMessage("遊戲結束!").setPositiveButton("重來", new DialogInterface.OnClickListener() {
//重新開始遊戲
@Override
public void onClick(DialogInterface arg0, int arg1) {
// TODO Auto-generated method stub
startGame();
}
}).show();
}
}
//記錄4*4卡片的陣列
private Card [][] cardsMap = new Card[4][4];
//記錄空卡片的集合
private List<Point> emptyPoints = new ArrayList<Point>();
}