通過(guò)一些學(xué)習(xí)小游戲的方式是對(duì)Java基礎(chǔ)的學(xué)習(xí)一個(gè)好的方法,同時(shí)也能給自己帶來(lái)一些樂(lè)趣。本篇文章將帶著各位小伙伴親手嘗試一下用Java寫(xiě)一個(gè)2048的小游戲。
實(shí)現(xiàn)文件
APP.java
import javax.swing.*;
public class APP {
public static void main(String[] args) {
new MyFrame();
}
}
類(lèi)文件
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;
//定義自己的類(lèi)(主類(lèi))去繼承JFrame類(lèi)并實(shí)現(xiàn)KeyListener接口和ActionListener接口
public class MyFrame extends JFrame implements KeyListener, ActionListener {
//用于存放游戲各位置上的數(shù)據(jù)
int[][] data = new int[4][4];
//用于判斷是否失敗
int loseFlag = 1;
//用于累計(jì)分?jǐn)?shù)
int score = 0;
//用于切換主題
String theme = "A";
//設(shè)置三個(gè)菜單項(xiàng)目
JMenuItem item1 = new JMenuItem("經(jīng)典");
JMenuItem item2 = new JMenuItem("霓虹");
JMenuItem item3 = new JMenuItem("糖果");
//核心方法
public MyFrame(){
//初始化窗口
initFrame();
//初始化菜單
initMenu();
//初始化數(shù)據(jù)
initData();
//繪制界面
paintView();
//為窗體提供鍵盤(pán)監(jiān)聽(tīng),該類(lèi)本身就是實(shí)現(xiàn)對(duì)象
this.addKeyListener(this);
//設(shè)置窗體可見(jiàn)
setVisible(true);
}
//窗體初始化
public void initFrame(){
//設(shè)置尺寸
setSize(514,538);
//設(shè)置居中
setLocationRelativeTo(null);
//設(shè)置總在最上面
setAlwaysOnTop(true);
//設(shè)置關(guān)閉方式
setDefaultCloseOperation(3);
//設(shè)置標(biāo)題
setTitle("2048小游戲");
//取消默認(rèn)布局
setLayout(null);
}
//初始化菜單
public void initMenu() {
//菜單欄目
JMenuBar menuBar = new JMenuBar();
JMenu menu1 = new JMenu("換膚");
JMenu menu2 = new JMenu("關(guān)于我們");
//添加上menuBar
menuBar.add(menu1);
menuBar.add(menu2);
//添加上menu
menu1.add(item1);
menu1.add(item2);
menu1.add(item3);
//注冊(cè)監(jiān)聽(tīng)
item1.addActionListener(this);
item2.addActionListener(this);
item3.addActionListener(this);
//添加進(jìn)窗體
super.setJMenuBar(menuBar);
}
//初始化數(shù)據(jù),在隨機(jī)位置生成兩個(gè)2
public void initData(){
generatorNum();
generatorNum();
}
//重新繪制界面的方法
public void paintView(){
//調(diào)用父類(lèi)中的方法清空界面
getContentPane().removeAll();
//判斷是否失敗
if(loseFlag==2){
//繪制失敗界面
JLabel loseLable = new JLabel(new ImageIcon("D:\Download\BaiDu\image\"+theme+"-lose.png"));
//設(shè)置位置和高寬
loseLable.setBounds(90,100,334,228);
//將該元素添加到窗體中
getContentPane().add(loseLable);
}
//根據(jù)現(xiàn)有數(shù)據(jù)繪制界面
for(int i=0;i<4;i++) {
//根據(jù)位置循環(huán)繪制
for (int j = 0; j < 4; j++) {
JLabel image = new JLabel(new ImageIcon("D:\Download\BaiDu\image\"+theme+"-"+data[i][j]+".png"));
//提前計(jì)算好位置
image.setBounds(50 + 100 * j, 50+100*i, 100, 100);
//將該元素添加進(jìn)窗體
getContentPane().add(image);
}
}
//繪制背景圖片
JLabel background = new JLabel(new ImageIcon("D:\Download\BaiDu\image\"+theme+"-Background.jpg"));
//設(shè)置位置和高寬
background.setBounds(40,40,420,420);
//將該元素添加進(jìn)窗體
getContentPane().add(background);
//得分模板設(shè)置
JLabel scoreLable = new JLabel("得分:"+score);
//設(shè)置位置和高寬
scoreLable.setBounds(50,20,100,20);
//將該元素添加進(jìn)窗體
getContentPane().add(scoreLable);
//重新繪制界面
getContentPane().repaint();
}
//用不到的但是必須重寫(xiě)的方法,無(wú)需關(guān)注
@Override
public void keyTyped(KeyEvent e) {}
//鍵盤(pán)被按下所觸發(fā)的方法,在此方法中加入?yún)^(qū)分上下左右的按鍵
@Override
public void keyPressed(KeyEvent e) {
//keyCode接收按鍵信息
int keyCode = e.getKeyCode();
//左移動(dòng)
if(keyCode == 37){
moveToLeft(1);
generatorNum();
}
//上移動(dòng)
else if(keyCode==38){
moveToTop(1);
generatorNum();
}
//右移動(dòng)
else if(keyCode==39){
moveToRight(1);
generatorNum();
}
//下移動(dòng)
else if(keyCode==40){
moveToBottom(1);
generatorNum();
}
//忽視其他按鍵
else {
return;
}
//檢查是否能夠繼續(xù)移動(dòng)
check();
//重新根據(jù)數(shù)據(jù)繪制界面
paintView();
}
//左移動(dòng)的方法,通過(guò)flag判斷,傳入1是正常移動(dòng),傳入2是測(cè)試移動(dòng)
public void moveToLeft(int flag) {
for(int i=0;i<data.length;i++){
//定義一維數(shù)組接收一行的數(shù)據(jù)
int[] newArr = new int[4];
//定義下標(biāo)方便操作
int index=0;
for(int x=0;x<data[i].length;x++){
//將有數(shù)據(jù)的位置前移
if(data[i][x]!=0){
newArr[index]=data[i][x];
index++;
}
}
//賦值到原數(shù)組
data[i]=newArr;
//判斷相鄰數(shù)據(jù)是否相鄰,相同則相加,不相同則略過(guò)
for(int x=0;x<3;x++){
if(data[i][x]==data[i][x+1]){
data[i][x]*=2;
//如果是正常移動(dòng)則加分
if(flag==1){
score+=data[i][x];
}
//將合并后的數(shù)據(jù)都前移,實(shí)現(xiàn)數(shù)據(jù)覆蓋
for(int j=x+1;j<3;j++){
data[i][j]=data[i][j+1];
}
//末尾補(bǔ)0
data[i][3]=0;
}
}
}
}
//右移動(dòng)的方法,通過(guò)flag判斷,傳入1是正常移動(dòng),傳入2是測(cè)試移動(dòng)
public void moveToRight(int flag) {
//翻轉(zhuǎn)二維數(shù)組
reverse2Array();
//對(duì)旋轉(zhuǎn)后的數(shù)據(jù)左移動(dòng)
moveToLeft(flag);
//再次翻轉(zhuǎn)
reverse2Array();
}
//上移動(dòng)的方法,通過(guò)flag判斷,傳入1是正常移動(dòng),傳入2是測(cè)試移動(dòng)
public void moveToTop(int flag) {
//逆時(shí)針旋轉(zhuǎn)數(shù)據(jù)
anticlockwise();
//對(duì)旋轉(zhuǎn)后的數(shù)據(jù)左移動(dòng)
moveToLeft(flag);
//順時(shí)針還原數(shù)據(jù)
clockwise();
}
//下移動(dòng)的方法,通過(guò)flag判斷,傳入1是正常移動(dòng),傳入2是測(cè)試移動(dòng)
public void moveToBottom(int flag) {
//順時(shí)針旋轉(zhuǎn)數(shù)據(jù)
clockwise();
//對(duì)旋轉(zhuǎn)后的數(shù)據(jù)左移動(dòng)
moveToLeft(flag);
//逆時(shí)針旋轉(zhuǎn)還原數(shù)據(jù)
anticlockwise();
}
//檢查能否左移動(dòng)
public boolean checkLeft(){
//開(kāi)辟新二維數(shù)組用于暫存數(shù)據(jù)和比較數(shù)據(jù)
int[][] newArr = new int[4][4];
//復(fù)制數(shù)組
copyArr(data,newArr);
//測(cè)試移動(dòng)
moveToLeft(2);
boolean flag = false;
//設(shè)置break跳出的for循環(huán)標(biāo)記
lo:
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
//如果有數(shù)據(jù)不相同,則證明能夠左移動(dòng),則返回true
if(data[i][j]!=newArr[i][j]){
flag=true;
break lo;
}
}
}
//將原本的數(shù)據(jù)還原
copyArr(newArr,data);
return flag;
}
//檢查能否右移動(dòng),與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;
}
//檢查能否上移動(dòng),與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;
}
//檢查能否下移動(dòng),與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(){
//上下左右均不能移動(dòng) ,則游戲失敗
if(checkLeft()==false&&checkRight()==false&&checkTop()==false&&checkBottom()==false){
loseFlag = 2;
}
}
//復(fù)制二維數(shù)組的方法,傳入原數(shù)組和新數(shù)組
public void copyArr(int[][] src,int[][] dest){
for (int i = 0; i < src.length; i++) {
for (int j = 0; j < src[i].length; j++) {
//遍歷復(fù)制
dest[i][j]=src[i][j];
}
}
}
//鍵盤(pán)被松開(kāi)
@Override
public void keyReleased(KeyEvent e) {}
//翻轉(zhuǎn)一維數(shù)組
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;
}
}
//翻轉(zhuǎn)二維數(shù)組
public void reverse2Array(){
for (int i = 0; i < data.length; i++) {
reverseArray(data[i]);
}
}
//順時(shí)針旋轉(zhuǎn)
public void clockwise(){
int[][] newArr = new int[4][4];
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
//找規(guī)律啦~
newArr[j][3-i] = data[i][j];
}
}
data = newArr;
}
//逆時(shí)針旋轉(zhuǎn)
public void anticlockwise(){
int[][] newArr = new int[4][4];
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
//規(guī)律
newArr[3-j][i] = data[i][j];
}
}
data = newArr;
}
//空位置隨機(jī)生成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){
//隨機(jī)數(shù)找到隨機(jī)位置
Random r= new Random();
int index = r.nextInt(w);
int x = arrarI[index];
int y = arrarJ[index];
//空位置隨機(jī)生成2
data[x][y]=2;
}
}
//換膚操作
@Override
public void actionPerformed(ActionEvent e) {
//接收動(dòng)作監(jiān)聽(tīng),
if(e.getSource()==item1){
theme = "A";
}else if(e.getSource()==item2){
theme = "B";
}else if(e.getSource()==item3){
theme = "C";
}
//換膚后重新繪制
paintView();
}
}
//測(cè)試失敗效果的數(shù)據(jù)
/*int[][] data = {
{2,4,8,4},
{16,32,64,8},
{128,2,256,2},
{512,8,1024,2048}
};*/
運(yùn)行效果
以上就是關(guān)于使用Java代碼來(lái)編寫(xiě)一個(gè)簡(jiǎn)單的2048小游戲的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持W3Cschool。