目錄
0 簡介
1 什麼是2048
0 簡介
閑來無事,搞了個2048玩玩,源碼放到了github上了,先上連結 https://github.com/tzx666/Android2048
現在已經實作的功能有
經典模式
自定義模式
曆史檢視、遊玩、删除自己自定義的模式
還沒有實作的功能有
遊戲的動畫、聲音
背景功能、創意上傳、圖檔合并等
效果圖
1 什麼是2048
2048是一種遊戲,核心玩法是通過左滑右滑上滑下滑去合并相同的數字,如果到達了2048則判定為勝利,如果已經無法再滑動了則可以判斷失敗
那麼我們便可以構思出這個遊戲必然有以下功能
1 基礎背景,一個4*4的遊戲棋盤,這裡我們使用一維數組作為底層實作
2 滑動的合并與判斷
3 随機位置的生成
4 遊戲勝利和結束條件的判斷
5 引申而來的,我們同樣可以對遊戲使用mvc架構,即遊戲顯示什麼和實際邏輯是什麼并無關系,隻要定義符合合并機制,那麼無論顯示什麼都是合理的(霧)
2 抽象類的定義
根據上述的描述,我們不難定義出接口(其實應該用抽象類更合理的說)
interface Game2048 {
fun init(context:Context);
fun init(context:Context,size:Int);
fun start();
fun moveleft();
fun moveright();
fun moveup();
fun movedown();
fun addRanrom();
fun isEnd();
fun isFirstVisiable(position:Int):Boolean;
}
其中 init()負責初始化數組,isFirstVisiable()負責動畫出現的判斷,movexx函數負責遊戲過程中的合并
3 遊戲邏輯的實作
2048的遊戲邏輯比較簡單,參考代碼應該很好懂
/*
*@author tzx
*@descrption 2048的邏輯實作
*/
public class Game2048impl implements Game2048 {
private int score;
private int[] map;
private boolean[] isfirstAppear;
private int MAPSIZE;
private int GAME_OVER=101;
private int GAME_WIN=102;
private int GAME_CONTINUE=103;
private int state=GAME_CONTINUE;
private Context context;
@Override
public void init(Context context,int size) {
MAPSIZE=size;
this.context=context;
map=new int[MAPSIZE*MAPSIZE];
isfirstAppear=new boolean[MAPSIZE*MAPSIZE];
addRanrom();
addRanrom();
}
@Override
public boolean isFirstVisiable(int positon) {
return isfirstAppear[positon];
}
private enum state{
GAME_OVER,GAME_CONTINUE,GAME_WIN
};
@Override
public void init(Context context) {
this.context=context;
MAPSIZE=4;
map=new int[MAPSIZE*MAPSIZE];
isfirstAppear=new boolean[MAPSIZE*MAPSIZE];
addRanrom();
addRanrom();
}
@Override
public void start() {
}
public int[] getMap() {
return map;
}
@Override
public void moveleft() {
boolean merge=false;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
for(int z=j+1;z<4;z++){
if(map[i*MAPSIZE+z]>0){
if(map[i*MAPSIZE+j]==0){
map[i*MAPSIZE+j]=map[i*MAPSIZE+z];
map[i*MAPSIZE+z]=0;
j--;
merge=true;
}else if(map[i*MAPSIZE+j]==map[i*MAPSIZE+z]){
map[i*MAPSIZE+j]*=2;
score+=map[i*MAPSIZE+j];
map[i*MAPSIZE+z]=0;
merge=true;
}
break;
}
}
}
}
if(merge){
for(int i=0;i<isfirstAppear.length;i++)isfirstAppear[i]=false;
addRanrom();
isEnd();
}
}
@Override
public void moveright() {
boolean merge=false;
for(int i=0;i<4;i++){
for(int j=3;j>0;j--){
for(int z=j-1;z>=0;z--){
if(map[i*MAPSIZE+z]>0){
if(map[i*MAPSIZE+j]==0){
map[i*MAPSIZE+j]=map[i*MAPSIZE+z];
map[i*MAPSIZE+z]=0;
j++;
merge=true;
}else if(map[i*MAPSIZE+j]==map[i*MAPSIZE+z]){
map[i*MAPSIZE+j]*=2;
map[i*MAPSIZE+z]=0;
score+=map[i*MAPSIZE+j];
merge=true;
}
break;
}
}
}
}
if(merge){
for(int i=0;i<isfirstAppear.length;i++)isfirstAppear[i]=false;
addRanrom();
isEnd();
}
}
@Override
public void moveup() {
boolean merge=false;
for(int j=0;j<4;j++){
for(int i=0;i<4;i++){
for(int z=i+1;z<4;z++){
if(map[z*MAPSIZE+j]>0){
if(map[i*MAPSIZE+j]==0){
map[i*MAPSIZE+j]=map[z*MAPSIZE+j];
map[z*MAPSIZE+j]=0;
i--;
merge=true;
}else if(map[i*MAPSIZE+j]==map[z*MAPSIZE+j]){
map[i*MAPSIZE+j]*=2;
score+=map[i*MAPSIZE+j];
map[z*MAPSIZE+j]=0;
merge=true;
}
break;
}
}
}
}
if(merge){
for(int i=0;i<isfirstAppear.length;i++)isfirstAppear[i]=false;
addRanrom();
isEnd();
}
}
@Override
public void movedown() {
boolean merge=false;
for(int j=0;j<4;j++){
for(int i=3;i>0;i--){
for(int z=i-1;z>=0;z--){
if(map[z*MAPSIZE+j]>0){
if(map[i*MAPSIZE+j]==0){
map[i*MAPSIZE+j]=map[z*MAPSIZE+j];
map[z*MAPSIZE+j]=0;
i++;
merge=true;
}else if(map[i*MAPSIZE+j]==map[z*MAPSIZE+j]){
map[i*MAPSIZE+j]*=2;
score+=map[i*MAPSIZE+j];
map[z*MAPSIZE+j]=0;
merge=true;
}
break;
}
}
}
}
if(merge){
for(int i=0;i<isfirstAppear.length;i++)isfirstAppear[i]=false;
addRanrom();
isEnd();
}
}
@Override
public void addRanrom() {
Random rand=new Random();
int x=rand.nextInt(4);
int y=rand.nextInt(4);
do{
x=rand.nextInt(4);
y=rand.nextInt(4);
}while(map[x*MAPSIZE+y]!=0);
isfirstAppear[x*MAPSIZE+y]=true;
map[x*MAPSIZE+y]=Math.random()>0.1?2:4;
}
@Override
public void isEnd() {
int state=this.GAME_OVER;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if(map[i*MAPSIZE+j]==2048){
state=GAME_WIN;
return;
}else if(map[i*MAPSIZE+j]==0||(i>0&&map[i*MAPSIZE+j]==map[(i-1)*MAPSIZE+j])||(i<3&&map[i*MAPSIZE+j]==map[(i+1)*MAPSIZE+j])||(j>0&&map[i*MAPSIZE+j]==map[i*MAPSIZE+(j-1)])||(j<3&&map[i*MAPSIZE+j]==map[i*MAPSIZE+(j+1)])){
state=this.GAME_CONTINUE;
return;
}
}
}
if(state==GAME_OVER){
UtilsKt.showDialog(context, "遊戲結束", "", new Callback() {
@Override
public void onConfirm(@NotNull DialogInterface dialog) {
((Activity)context).finish();
}
@Override
public void onCancel(@NotNull DialogInterface dialog) {
}
});
}else if(state==GAME_WIN){
UtilsKt.showDialog(context, "遊戲勝利", "", new Callback() {
@Override
public void onConfirm(@NotNull DialogInterface dialog) {
((Activity)context).finish();
}
@Override
public void onCancel(@NotNull DialogInterface dialog) {
}
});
}
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
void Gesture(int c){
if(c==1) moveleft(); //getKeyCode()是表示按鍵按下的序号,KeyEvent.VK_UP表示up(下)鍵的序号
if(c==2) moveright();
if(c==3) moveup();
if(c==4) movedown();
}
}
事實上,上面的類完全可以通過scanner以控制台的形式跑起來
上篇總結
在本篇,我們主要關注遊戲的邏輯實作,但是麼有界面的遊戲一定是假遊戲,下一篇将結合用到的安卓開發知識介紹如何優雅的畫界面(霧)