學Android--實現2048小遊戲
1、遊戲佈局(activity_main.xml)
首先在xml檔案中實現遊戲的整體佈局
(1)新增兩個TextView用來顯示分數
<LinearLayout
android:layout_width="match_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:id="@+id/tvScore"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
(2)2048遊戲介面的佈局,遊戲介面是通過程式碼來實現的,所以應該用包名加類名的方式來引用
<com .jxl.game2048.GameView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/gameView">
</com.jxl.game2048.GameView>
2、新建遊戲執行的主要類(GameView.java),該類繼承GridLayout
(1)在構造方法中,需要對遊戲進行初始化( 呼叫initGameView()方法 )
initGameView()主要用來初始化遊戲,該方法中需要實現OnTouchListener,通過座標值判斷使用者滑動的方式,響應不同的事件
在initGameView()指定列數,設定背景:
setColumnCount(4);
setBackgroundColor(0xffbbada0);
setOnTouchListener(new OnTouchListener() {
private float startX,startY,offsetX,offsetY;
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = event.getX();
startY = event.getY();
break;
case MotionEvent.ACTION_UP:
offsetX = event.getX()-startX;
offsetY = event.getY()-startY;
//在水平方向上移動
if(Math.abs(offsetX)>Math.abs(offsetY)){
//向左滑動
if(offsetX<-5){
swipeLeft();
//向右滑動
}else if(offsetX>5){
swipeRight();
}
}else{
//向上滑動
if(offsetY<-5){
swipeUp();
//向下滑動
}else if(offsetY>5){
swipeDown();
}
}
break;
default:
break;
}
return true;
}
});
3、將2048的介面看做由4*4的小方塊組成,將這些方塊抽象為Card類,該類繼承自FrameLayout
(1)遊戲進行時小方塊中的數字為2、4、8、16.……初始化所有小方塊,將數字設為0,即數字為0時表示這一格為空
setNum(0);
private int num = 0;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
(2)在構造方法中,需要對小方塊進行初始化,為小方塊新增TextView儲存數字,並設定字型大小,數字對應的顏色等
private TextView label;
public Card(Context context) {
super(context);
label = new TextView(getContext());
label.setTextSize(32);
label.setGravity(Gravity.CENTER);
setNum(0);
}
public void setBGColor(int num){
switch (num) {
case 2:
label.setBackgroundColor(0xffFFF68F);
break;
case 4:
label.setBackgroundColor(0xffFFEC8B);
break;
case 8:
label.setBackgroundColor(0xffFFD700);
break;
case 16:
label.setBackgroundColor(0xffFFC125);
break;
case 32:
label.setBackgroundColor(0xffFF890F);
break;
case 64:
label.setBackgroundColor(0xffFFA500);
break;
case 128:
label.setBackgroundColor(0xffFF8C00);
break;
case 256:
label.setBackgroundColor(0xffFF7F24);
break;
case 512:
label.setBackgroundColor(0xffFF4500);
break;
case 1024:
label.setBackgroundColor(0xffFF0000);
break;
case 2048:
label.setBackgroundColor(0xff7FF00);
break;
case 4096:
label.setBackgroundColor(0xff68228B);
break;
default:
label.setBackgroundColor(0x33ffffff);
break;
}
}
(3)新增一個佈局引數,寬高為-1,表示填充滿整個父類容器:
LayoutParams lp = new LayoutParams(-1,-1);
//設定小方塊之間的間距
lp.setMargins(10, 10, 0, 0);
//然後將label新增進佈局中:
addView(label, lp)
(4)在setNum()方法中,將數字轉換成字串並新增到對應的TextView中
public void setNum(int num) {
this.num = num;
if(num<=0){
label.setText("");
}else{
label.setText(num+"");
}
}
(5)新增equals()方法判斷兩個卡片上的數字是否相等:
public boolean equals(Card o) {
// TODO Auto-generated method stub
return getNum()==o.getNum();
}
4、將16個方塊抽象化為4*4的二維陣列,並將這些小方塊新增到佈局中
private Card[][] cardsMap = new Card[4][4];
private void addCards(int cardWidth,int cardHeight){
Card c;
for(int y=0;y<4;y++){
for(int x=0;x<4;x++){
c = new Card(getContext());
c.setNum(0);
c.setBGColor(c.getNum());
addView(c, cardWidth, cardHeight);
cardsMap[x][y] = c;
}
}
}
5、新建emptyPoint List來存放空的小方塊
private List<Point> emptyPoints = new ArrayList<Point>();
遊戲中新生成的數字在這些空的小方塊中隨機出現
private void addRandomNum(){
emptyPoints.clear();
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
if(cardsMap[x][y].getNum()<=0){
emptyPoints.add(new Point(x,y));
}
}
}
Point p = emptyPoints.remove((int)(Math.random()*emptyPoints.size()));
//隨機產生2或4,生成2的概率大於4
cardsMap[p.x][p.y].setNum(Math.random()>0.1?2:4);
cardsMap[p.x][p.y].setBGColor(cardsMap[p.x][p.y].getNum());
}
6、開始遊戲,實現startGame()方法
private void startGame(){
MainActivity.getMainActivity().clearScore();
for (int y = 0; y < 4; y++) {
for(int x = 0; x < 4; x++){
cardsMap[x][y].setNum(0);
}
}
//隨機生成兩個數字
addRandomNum();
addRandomNum();
}
7、實現遊戲中最重要的部分—使用者滑動後需要呼叫的方法,以向左滑動為例
private void swipeLeft(){
boolean merge = false;
//從上至下的第一行開始
for (int y = 0; y < 4; y++) {
//從左至右
for(int x = 0; x < 4; x++){
for(int x1 = x+1; x1 < 4; x1++){
//當前位置上的值不為0
if(cardsMap[x1][y].getNum()>0){
//當前方塊左邊的方塊為空,則將當前方塊的值傳到左邊,直到左邊是不為空的方塊為止
if(cardsMap[x][y].getNum()<=0){
cardsMap[x][y].setNum(cardsMap[x1][y].getNum());
cardsMap[x][y].setBGColor(cardsMap[x][y].getNum());
cardsMap[x1][y].setNum(0);
cardsMap[x1][y].setBGColor(cardsMap[x1][y].getNum());
x--;
merge = true;
//左邊卡片的值不為空且與當前值當等
}else if(cardsMap[x][y].equals(cardsMap[x1][y])){
cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2);
cardsMap[x][y].setBGColor(cardsMap[x][y].getNum());
cardsMap[x1][y].setNum(0);
cardsMap[x1][y].setBGColor(cardsMap[x1][y].getNum());
MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum());
merge = true;
}
break;
}
}
}
}
if(merge){
//完成後再新增一個隨機數字
addRandomNum();
//並判斷遊戲是否結束
checkComplete();
}
}
private void checkComplete(){
boolean complete = true;
ALL:
for (int y = 0; y < 4; y++) {
for(int x = 0; x < 4; x++){
if(cardsMap[x][y].getNum()==0||
(x>0&&cardsMap[x][y].equals(cardsMap[x-1][y]))||
(x<3&&cardsMap[x][y].equals(cardsMap[x+1][y]))||
(y>0&&cardsMap[x][y].equals(cardsMap[x][y-1]))||
(y<3&&cardsMap[x][y].equals(cardsMap[x][y+1]))){
complete = false;
break ALL;
}
}
}
if(complete){
new AlertDialog.Builder(getContext()).setTitle("2048").
setMessage("遊戲結束").setPositiveButton("重來", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
// TODO Auto-generated method stub
startGame();
}
}).show();
}
}
8、在GameView中重寫onSizeChanged()方法,動態地計算每個方塊的寬、高:
在AndroidManifest.xml中修改屏幕布局為垂直:
android:screenOrientation=”portrait”
@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();
}
9、在MainActivity中新增addScore()、showScore()、clearScore()方法,實現計分功能
public class MainActivity extends Activity {
private TextView tvScore;
private int score = 0;
public MainActivity(){
mainActivity = this;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvScore = (TextView) findViewById(R.id.tvScore);
}
public void clearScore(){
score = 0;
showScore();
}
public void showScore(){
tvScore.setText(score+"");
}
public void addScore(int s){
score+=s;
showScore();
}
private static MainActivity mainActivity = null;
public static MainActivity getMainActivity(){
return mainActivity;
}
}
注:該文章根據“極客學院”中2048遊戲視訊教程總結而來