java實現2048小遊戲(含註釋)

本文實例為大傢分享瞭java實現2048小遊戲的具體代碼,供大傢參考,具體內容如下

實現文件

APP.java

import javax.swing.*;

public class APP {
 public static void main(String[] args) {
 new MyFrame();
 }
}

類文件

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;

//定義自己的類(主類)去繼承JFrame類並實現KeyListener接口和ActionListener接口
public class MyFrame extends JFrame implements KeyListener, ActionListener {

 //用於存放遊戲各位置上的數據
 int[][] data = new int[4][4];

 //用於判斷是否失敗
 int loseFlag = 1;

 //用於累計分數
 int score = 0;

 //用於切換主題
 String theme = "A";

 //設置三個菜單項目
 JMenuItem item1 = new JMenuItem("經典");
 JMenuItem item2 = new JMenuItem("霓虹");
 JMenuItem item3 = new JMenuItem("糖果");

 //核心方法
 public MyFrame(){
 //初始化窗口
 initFrame();
 //初始化菜單
 initMenu();
 //初始化數據
 initData();
 //繪制界面
 paintView();
 //為窗體提供鍵盤監聽,該類本身就是實現對象
 this.addKeyListener(this);
 //設置窗體可見
 setVisible(true);
 }

 //窗體初始化
 public void initFrame(){
 //設置尺寸
 setSize(514,538);
 //設置居中
 setLocationRelativeTo(null);
 //設置總在最上面
 setAlwaysOnTop(true);
 //設置關閉方式
 setDefaultCloseOperation(3);
 //設置標題
 setTitle("2048小遊戲");
 //取消默認佈局
 setLayout(null);
 }

 //初始化菜單
 public void initMenu() {
 //菜單欄目
 JMenuBar menuBar = new JMenuBar();
 JMenu menu1 = new JMenu("換膚");
 JMenu menu2 = new JMenu("關於我們");

 //添加上menuBar
 menuBar.add(menu1);
 menuBar.add(menu2);

 //添加上menu
 menu1.add(item1);
 menu1.add(item2);
 menu1.add(item3);

 //註冊監聽
 item1.addActionListener(this);
 item2.addActionListener(this);
 item3.addActionListener(this);

 //添加進窗體
 super.setJMenuBar(menuBar);
 }

 //初始化數據,在隨機位置生成兩個2
 public void initData(){
 generatorNum();
 generatorNum();
 }

 //重新繪制界面的方法
 public void paintView(){
 //調用父類中的方法清空界面
 getContentPane().removeAll();

 //判斷是否失敗
 if(loseFlag==2){
  //繪制失敗界面
  JLabel loseLable = new JLabel(new ImageIcon("D:\\Download\\BaiDu\\image\\"+theme+"-lose.png"));
  //設置位置和高寬
  loseLable.setBounds(90,100,334,228);
  //將該元素添加到窗體中
  getContentPane().add(loseLable);
 }

 //根據現有數據繪制界面
 for(int i=0;i<4;i++) {
  //根據位置循環繪制
  for (int j = 0; j < 4; j++) {
  JLabel image = new JLabel(new ImageIcon("D:\\Download\\BaiDu\\image\\"+theme+"-"+data[i][j]+".png"));
  //提前計算好位置
  image.setBounds(50 + 100 * j, 50+100*i, 100, 100);
  //將該元素添加進窗體
  getContentPane().add(image);
  }
 }

 //繪制背景圖片
 JLabel background = new JLabel(new ImageIcon("D:\\Download\\BaiDu\\image\\"+theme+"-Background.jpg"));
 //設置位置和高寬
 background.setBounds(40,40,420,420);
 //將該元素添加進窗體
 getContentPane().add(background);

 //得分模板設置
 JLabel scoreLable = new JLabel("得分:"+score);
 //設置位置和高寬
 scoreLable.setBounds(50,20,100,20);
 //將該元素添加進窗體
 getContentPane().add(scoreLable);

 //重新繪制界面
 getContentPane().repaint();
 }

 //用不到的但是必須重寫的方法,無需關註
 @Override
 public void keyTyped(KeyEvent e) {}

 //鍵盤被按下所觸發的方法,在此方法中加入區分上下左右的按鍵
 @Override
 public void keyPressed(KeyEvent e) {
 //keyCode接收按鍵信息
 int keyCode = e.getKeyCode();
 //左移動
 if(keyCode == 37){
  moveToLeft(1);
  generatorNum();
 }
 //上移動
 else if(keyCode==38){
  moveToTop(1);
  generatorNum();
 }
 //右移動
 else if(keyCode==39){
  moveToRight(1);
  generatorNum();
 }
 //下移動
 else if(keyCode==40){
  moveToBottom(1);
  generatorNum();
 }
 //忽視其他按鍵
 else {
  return;
 }
 //檢查是否能夠繼續移動
 check();
 //重新根據數據繪制界面
 paintView();
 }

 //左移動的方法,通過flag判斷,傳入1是正常移動,傳入2是測試移動
 public void moveToLeft(int flag) {
 for(int i=0;i<data.length;i++){
  //定義一維數組接收一行的數據
  int[] newArr = new int[4];
  //定義下標方便操作
  int index=0;
  for(int x=0;x<data[i].length;x++){
  //將有數據的位置前移
  if(data[i][x]!=0){
   newArr[index]=data[i][x];
   index++;
  }
  }
  //賦值到原數組
  data[i]=newArr;
  //判斷相鄰數據是否相鄰,相同則相加,不相同則略過
  for(int x=0;x<3;x++){
  if(data[i][x]==data[i][x+1]){
   data[i][x]*=2;
   //如果是正常移動則加分
   if(flag==1){
   score+=data[i][x];
   }
   //將合並後的數據都前移,實現數據覆蓋
   for(int j=x+1;j<3;j++){
   data[i][j]=data[i][j+1];
   }
   //末尾補0
   data[i][3]=0;
  }
  }
 }
 }

 //右移動的方法,通過flag判斷,傳入1是正常移動,傳入2是測試移動
 public void moveToRight(int flag) {
 //翻轉二維數組
 reverse2Array();
 //對旋轉後的數據左移動
 moveToLeft(flag);
 //再次翻轉
 reverse2Array();
 }

 //上移動的方法,通過flag判斷,傳入1是正常移動,傳入2是測試移動
 public void moveToTop(int flag) {
 //逆時針旋轉數據
 anticlockwise();
 //對旋轉後的數據左移動
 moveToLeft(flag);
 //順時針還原數據
 clockwise();
 }

 //下移動的方法,通過flag判斷,傳入1是正常移動,傳入2是測試移動
 public void moveToBottom(int flag) {
 //順時針旋轉數據
 clockwise();
 //對旋轉後的數據左移動
 moveToLeft(flag);
 //逆時針旋轉還原數據
 anticlockwise();
 }

 //檢查能否左移動
 public boolean checkLeft(){
 //開辟新二維數組用於暫存數據和比較數據
 int[][] newArr = new int[4][4];
 //復制數組
 copyArr(data,newArr);
 //測試移動
 moveToLeft(2);
 boolean flag = false;
 //設置break跳出的for循環標記
 lo:
 for (int i = 0; i < data.length; i++) {
  for (int j = 0; j < data[i].length; j++) {
  //如果有數據不相同,則證明能夠左移動,則返回true
  if(data[i][j]!=newArr[i][j]){
   flag=true;
   break lo;
  }
  }
 }
 //將原本的數據還原
 copyArr(newArr,data);
 return flag;
 }

 //檢查能否右移動,與checkLeft()方法原理相似
 public boolean checkRight(){
 int[][] newArr = new int[4][4];
 copyArr(data,newArr);
 moveToRight(2);
 boolean flag = false;
 lo:
 for (int i = 0; i < data.length; i++) {
  for (int j = 0; j < data[i].length; j++) {
  if(data[i][j]!=newArr[i][j]){
   flag=true;
   break lo;
  }
  }
 }
 copyArr(newArr,data);
 return flag;
 }

 //檢查能否上移動,與checkLeft()方法原理相似
 public boolean checkTop(){
 int[][] newArr = new int[4][4];
 copyArr(data,newArr);
 moveToTop(2);
 boolean flag = false;
 lo:
 for (int i = 0; i < data.length; i++) {
  for (int j = 0; j < data[i].length; j++) {
  if(data[i][j]!=newArr[i][j]){
   flag=true;
   break lo;
  }
  }
 }
 copyArr(newArr,data);
 return flag;
 }

 //檢查能否下移動,與checkLeft()方法原理相似
 public boolean checkBottom(){
 int[][] newArr = new int[4][4];
 copyArr(data,newArr);
 moveToBottom(2);
 boolean flag = false;
 lo:
 for (int i = 0; i < data.length; i++) {
  for (int j = 0; j < data[i].length; j++) {
  if(data[i][j]!=newArr[i][j]){
   flag=true;
   break lo;
  }
  }
 }
 copyArr(newArr,data);
 return flag;
 }

 //檢查是否失敗
 public void check(){
 //上下左右均不能移動 ,則遊戲失敗
 if(checkLeft()==false&&checkRight()==false&&checkTop()==false&&checkBottom()==false){
  loseFlag = 2;
 }
 }

 //復制二維數組的方法,傳入原數組和新數組
 public void copyArr(int[][] src,int[][] dest){
 for (int i = 0; i < src.length; i++) {
  for (int j = 0; j < src[i].length; j++) {
  //遍歷復制
  dest[i][j]=src[i][j];
  }
 }
 }

 //鍵盤被松開
 @Override
 public void keyReleased(KeyEvent e) {}

 //翻轉一維數組
 public void reverseArray(int[] arr){
 for(int start=0,end=arr.length-1;start<end;start++,end--){
  int temp = arr[start];
  arr[start] = arr[end];
  arr[end] = temp;
 }
 }

 //翻轉二維數組
 public void reverse2Array(){
 for (int i = 0; i < data.length; i++) {
  reverseArray(data[i]);
 }
 }

 //順時針旋轉
 public void clockwise(){
 int[][] newArr = new int[4][4];
 for(int i=0;i<4;i++){
  for(int j=0;j<4;j++){
  //找規律啦~
  newArr[j][3-i] = data[i][j];
  }
 }
 data = newArr;
 }

 //逆時針旋轉
 public void anticlockwise(){
 int[][] newArr = new int[4][4];
 for(int i=0;i<4;i++){
  for(int j=0;j<4;j++){
  //規律
  newArr[3-j][i] = data[i][j];
  }
 }
 data = newArr;
 }

 //空位置隨機生成2
 public void generatorNum(){
 int[] arrarI = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
 int[] arrarJ = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
 int w=0;
 for (int i = 0; i < data.length; i++) {
  for (int j = 0; j < data[i].length; j++) {
  if(data[i][j]==0){
   //找到並存放空位置
   arrarI[w]=i;
   arrarJ[w]=j;
   w++;
  }
  }
 }
 if(w!=0){
  //隨機數找到隨機位置
  Random r= new Random();
  int index = r.nextInt(w);
  int x = arrarI[index];
  int y = arrarJ[index];
  //空位置隨機生成2
  data[x][y]=2;
 }
 }

 //換膚操作
 @Override
 public void actionPerformed(ActionEvent e) {
 //接收動作監聽,
 if(e.getSource()==item1){
  theme = "A";
 }else if(e.getSource()==item2){
  theme = "B";
 }else if(e.getSource()==item3){
  theme = "C";
 }
 //換膚後重新繪制
 paintView();
 }
}


 //測試失敗效果的數據
 /*int[][] data = {
  {2,4,8,4},
  {16,32,64,8},
  {128,2,256,2},
  {512,8,1024,2048}
 };*/

運行效果

以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。