剛開始學JAVA GUI,就練手寫了一個小時候經常在諾基亞上玩的一個小游戲__貪吃蛇.
做的比較簡單,但還是可以玩的.
根據狂神的視頻做的,然后自己優化了一些bug,比如新生成食物的時候不會生成在蛇的身體上,再新增長身體的時候不會在左上角出現一個綠色的方塊以及增加了難度控制功能,以及可以使用WASD進行控制,而不僅僅限于上下左右方向鍵
最后的游戲界面是這樣的:

可以在上方的選單欄里選擇不同的難度進行游戲.難度對應的是不同的蛇移動的速度,點擊退出游戲和點擊右上角的X是一樣的功能,都是退出游戲.然后點擊重新開始就會回到最初的時候重新開始游戲.
按下空格開始游戲,隨時可以再次按下空格進行暫停游戲.同時每吃到一個食物就會在右上角加10分.

游戲代碼一共分成了三個類
一個是GameStart類,用來創建JFrame繪制游戲主體.
一個是GamePanel類,用來添加在JFrame中,里面加入了選單欄以及一些鍵盤監聽器,用來根據讀入的資訊操縱蛇移動.
另一個是Data類,用來讀取statics檔案夾中的圖片素材,代碼更簡潔.

GameStart類代碼如下:(具體代碼后面都有注釋)
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* @author Laurie
*/
public class GameStart {
public static void main(String[] args) {
JFrame jframe = new JFrame("貪吃蛇");
jframe.setBounds(10, 10, 900, 720);//繪制游戲主界面的范圍
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setResizable(false);//不可擴大縮小視窗
GamePanel gamePanel = new GamePanel();
jframe.add(gamePanel);
jframe.setVisible(true);//顯形
gamePanel.setLayout(new BorderLayout());
}
}
GamePanel類代碼是:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
/**
* @author Laurie
*/
public class GamePanel extends JPanel implements ActionListener, KeyListener {
int length;//蛇的長度
int[] snakeX = new int[500];//隨便定義長度,反之不出意外是不會超過的
int[] snakeY = new int[500];
String direction;//蛇的方向,來根據這個改變蛇頭的圖片
Timer timer = new Timer(60, this);//計時器,來觸發蛇移動的事件
int score;//分數
Boolean isFail = false;//是否失敗判斷
Boolean isStart = false;//是否啟動判斷
int foodX;//食物坐標
int foodY;
Random random = new Random();//用來產生亂數的Random類的實體化
public void init(){
length = 3;//一開始蛇的三節
snakeX[0] = 100;//蛇頭為下標0
snakeY[0] = 100;
snakeX[1] = 75;
snakeY[1] = 100;
snakeX[2] = 50;
snakeY[2] = 100;
direction = "R";//初始化方向朝右邊
score = 0;
foodX = getFoodX();//通過方法獲取食物的坐標
foodY = getFoodY();
}
public GamePanel(){
//建構式
init();//進行初始化
this.setFocusable(true);//設定可以被賦予焦點
this.setForeground(Color.pink);//設定為粉色
this.addKeyListener(this);//添加鍵盤的監聽
timer.start();//開始計時器
JMenuBar menuBar = new JMenuBar();//選項欄
JButton jb1 = new JButton("退出游戲");
JButton jb3 = new JButton("新手難度");
JButton jb4 = new JButton("高手難度");
JButton jb5 = new JButton("地獄難度");
menuBar.add(jb1);
menuBar.add(jb3);
menuBar.add(jb4);
menuBar.add(jb5);
jb1.addActionListener(e -> {//添加jb1的監聽
System.exit(0);//退出
});
jb3.addActionListener(e -> {
this.requestFocus();//不獲取焦點后面操作鍵盤都會在選單欄里,就無法操作蛇了
timer.stop();//把原來的timer停止
timer = new Timer(80, this);//使蛇的速度變慢
timer.start();//重新開始timer
});
jb4.addActionListener(e -> {
this.requestFocus();
timer.stop();
timer = new Timer(40, this);
timer.start();
});
jb5.addActionListener(e -> {
this.requestFocus();
timer.stop();
timer = new Timer(20, this);
timer.start();
});
this.add(menuBar);
JButton jb2 = new JButton("重新開始");
jb2.addActionListener(e -> {
init();//重新開始所以重新初始化一下
repaint();//重畫
this.requestFocus();
});
this.add(jb2);
}
public int getFoodX(){
//如果沒有判斷的話會出現bug,也就是食物可能出現在蛇的身體里,所以要進行判斷優化
boolean flag = true;
int x = 25 + 25 * random.nextInt(34);//因為一格為25,所以要乘一個25
while(flag){
for(int i = 0; i < length; i++){
if(snakeX[i] == x) {
x = 25 + 25 * random.nextInt(34);//如果和身體重合就重新隨機一個數
}else{
flag = false;
}
}
}
return x;
}
public int getFoodY(){
boolean flag = true;
int y = 75 + 25 * random.nextInt(24);//24是計算出來的,總panel的大小除以25
while(flag){
for(int i = 0; i < length; i++){
if(snakeY[i] == y) {
y = 75 + 25 * random.nextInt(34);
}else{
flag = false;
}
}
}
return y;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponents(g);//這個不加可能會出問題
this.setBackground(Color.white);
g.fillRect(0,0,90,30);
g.setColor(Color.black);
g.drawString("貪吃蛇大挑戰",10,20);
g.setColor(Color.LIGHT_GRAY);//分數提示框
g.fillRect( 25, 36, 850, 40);
g.setColor(Color.pink);//游戲主界面
g.fillRect(25,75, 850, 600);
if ("R".equals(direction)) {//判斷是什么蛇頭朝向,選擇不同的蛇頭圖片
Data.right.paintIcon(this, g, snakeX[0], snakeY[0]);
} else if ("L".equals(direction)) {
Data.left.paintIcon(this, g, snakeX[0], snakeY[0]);
} else if ("U".equals(direction)) {
Data.up.paintIcon(this, g, snakeX[0], snakeY[0]);
} else if ("D".equals(direction)) {
Data.down.paintIcon(this, g, snakeX[0], snakeY[0]);
}
for (int i = 1; i < length; i++) {//通過for回圈繪制蛇的身體
Data.body.paintIcon(this, g, snakeX[i], snakeY[i]);
}
g.setColor(Color.WHITE);
g.setFont(new Font("微軟雅黑", Font.BOLD, 18));
g.drawString("長度:"+length,650,54);
g.drawString("分數:"+score,750,54);//分數長度等的繪制
Data.food.paintIcon(this, g, foodX, foodY);//繪制食物
if (!isStart) {//如果還沒開始就提示按下空格開始
g.setColor(Color.WHITE);
g.setFont(new Font("微軟雅黑", Font.BOLD, 40));
g.drawString("按下空格來開始游戲", 300, 300);
}
if (isFail) {//如果失敗了就提示按下空格重新開始
g.setColor(Color.red);
g.setFont(new Font("微軟雅黑", Font.BOLD, 40));
g.drawString("蛇死了哦,按下空格重新開始吧", 200, 300);
}
}
@Override
public void actionPerformed(ActionEvent e) {
if (isStart && !isFail) {//如果已經開始并且沒有失敗
for (int i = length - 1; i > 0; i--) {
snakeX[i] = snakeX[i - 1];
//就把每節身體的位置都變成上一個身體的位置來模擬移動
snakeY[i] = snakeY[i - 1];
}
if ("R".equals(direction)) {
//動完了身體,這里動蛇頭,根據不同的方向來動到位置
snakeX[0] = snakeX[0] + 25;
if (snakeX[0] > 850) {
snakeX[0] = 25;
}
} else if ("L".equals(direction)) {
snakeX[0] = snakeX[0] - 25;
if (snakeX[0] < 25) {
snakeX[0] = 850;
}
} else if ("U".equals(direction)) {
snakeY[0] = snakeY[0] - 25;
if (snakeY[0] < 75) {
snakeY[0] = 650;
}
} else if ("D".equals(direction)) {
snakeY[0] = snakeY[0] + 25;
if (snakeY[0] > 650) {
snakeY[0] = 75;
}
}
if (snakeX[0] == foodX && snakeY[0] == foodY) {//判斷是否吃到食物
//如果兩者的xy坐標重合了就說明吃到了
length++;//吃到了長度加一
snakeX[length - 1] = foodX - 1;//這里是避免出現一個bug,沒有這兩行就會在吃吃到以后左上角出現一個綠方塊
//這是因為新增加的身體沒有賦值坐標,所以就默認在00的位置
snakeY[length - 1] = foodY - 1;
score = score + 10;
foodX = getFoodX();//重新生成新的食物
foodY = getFoodY();
}
for(int i = 1; i < length; i++){//進行判斷是否死亡,當蛇頭和身體重合就是死亡
if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) {
isFail = true;
break;
}
}
repaint();//蛇移動了所以需要重新畫一遍
}
timer.start();//計時器重新開始,蛇再進行下一步移動
}
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();//這個為接受的鍵盤的按鍵對應的代碼
if(keyCode == KeyEvent.VK_SPACE){//如果是空格的話激素hi進行判斷
if(!isFail){//如果沒有失敗就進行暫停與重新游戲的功能實作
isStart = !isStart;
}else{//如果已經死了就重新開始
isFail = false;
init();
}
repaint();//重新繪制
}
if (keyCode == KeyEvent.VK_LEFT && !"R".equals(direction)) {//檢查獲取的是上下左右的哪個進行蛇頭轉向
direction = "L";
} else if (keyCode == KeyEvent.VK_RIGHT && !"L".equals(direction)) {
direction = "R";
} else if (keyCode == KeyEvent.VK_UP && !"D".equals(direction)) {
direction = "U";
} else if (keyCode == KeyEvent.VK_DOWN && !"U".equals(direction)) {
direction = "D";
}
if (keyCode == KeyEvent.VK_A && !"R".equals(direction)) {//檢查獲取的是wasd的哪個進行蛇頭轉向
//注意當是與蛇頭反方向的不可以進行轉動,畢竟也不能180度轉脖子把
direction = "L";
} else if (keyCode == KeyEvent.VK_D && !"L".equals(direction)) {
direction = "R";
} else if (keyCode == KeyEvent.VK_W && !"D".equals(direction)) {
direction = "U";
} else if (keyCode == KeyEvent.VK_S && !"U".equals(direction)) {
direction = "D";
}
}
//這兩個沒有用,所以不用寫了
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
}
Data類代碼是:
import javax.swing.*;
import java.awt.*;
import java.net.URL;
/**
* @author Laurie
*/
public class Data {
//讀取statics檔案夾里的圖片,加載成圖片
public static URL bodyURL = Data.class.getResource("/statics/body.png");
public static URL foodURL = Data.class.getResource("/statics/food.png");
public static URL downURL = Data.class.getResource("/statics/down.png");
public static URL upURL = Data.class.getResource("/statics/up.png");
public static URL rightURL = Data.class.getResource("/statics/right.png");
public static URL leftURL = Data.class.getResource("/statics/left.png");
public static ImageIcon body = new ImageIcon(bodyURL);
public static ImageIcon food = new ImageIcon(foodURL);
public static ImageIcon down = new ImageIcon(downURL);
public static ImageIcon up = new ImageIcon(upURL);
public static ImageIcon right = new ImageIcon(rightURL);
public static ImageIcon left = new ImageIcon(leftURL);
}
整個專案檔案可以在github上自取,點擊藍字
github
上不去的也可以在gitee上自取,點擊藍字
gitee
💕
真的不下一個自己玩一玩嗎[手動滑稽]
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/347222.html
標籤:其他
上一篇:第2章 python程式實體決議
下一篇:ML-Agents命令及配置大全
