前段时间用Android编写了一个贪吃蛇的小游戏,感觉还不错,就想着能不能用java编写有个贪吃蛇的游戏,在电脑上面运行。于是就开始动手写了。
编写贪吃蛇游戏的博客或文档特别多,有些写的挺好的,都是一个共同的思想。都是通过没吃到食物时,头加尾减。吃到食物时头加尾不减。
我们看看通过java写这个游戏,要使用到哪些知识点,有可能写的不全面或不是最好的方法,希望在下面留言,指正下。
1:java里面关于swing的知识需要了解。图形化界面编程会用到里面的一些控件,例如 JFram,JPanel,JButton,JSpinner等。所以想学的同学,余姚了解swing。
2:java里面画布的知识了解下,类似于Canvas的。在java里面是通过Graphics 进行绘图的,以为我们需要将蛇体的当前状态和食物的当前位置绘制在面板上面。
3:了解下java里面关于键盘事件的监听,以为我们是通过键盘操作游戏的。
好了基本需要的知识就这些,剩下的就需要自己去实现逻辑代码,把整个游戏完成。来看看怎么写。
我在定义了三个类,主类 MyClass ,JFramDemo,Snake。
主类就不讲,java代码是从主类里面的main方法开始运行的。在这我把主要代码放在JFramDemo与Snake里面。主类比较少,知识让整个代码运行起来的。
public class MyClass {
public static void main(String[] strings) {
JFarmDemo mJFarmDemo = new JFarmDemo();
}
}
这上面就是我的主类,是不是比较少。所以重点在JFarmDemo 类里面。
JFarmDemo 类:
package com.example.lib.java;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.FlowLayout;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTabbedPane;
import javax.swing.SpinnerListModel;
import javax.swing.SpinnerModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class JFarmDemo {
/**
* mJFrame第一次显示的窗体,游戏开始前选择游戏难度的窗体
* jFrame 点击开始按钮后显示的窗体,游戏正在运行的窗体
*
*/
private static JFrame mJFrame, jFrame;
private static JLabel mJLabel, mJLabel1;
private static JPanel mJPanel, mJPanel2;
private static JButton mJButton, mJButton2;
private static JSpinner mJSpinner;
private static String[] strings;
private static int number = 20;
public JFarmDemo() {
init_J();
mJFrame.setBounds(500, 200, 300, 450);
mJFrame.setBackground(Color.BLUE);
mJFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mJFrame.setLayout(new BorderLayout(10, 10));
mJPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 10));
mJPanel.add(mJButton);
mJPanel.add(mJLabel1);
SpinnerModel model = new SpinnerListModel(strings);
mJSpinner = new JSpinner(model);
mJSpinner.setSize(50, 50);
mJPanel.add(mJSpinner);
mJPanel.add(mJButton2);
ImageIcon mIcon = new ImageIcon("image/snakeback.png");
mJLabel = new JLabel(mIcon);
mJPanel2.add(mJLabel);
mJFrame.add(mJPanel, BorderLayout.SOUTH);
mJFrame.add(mJPanel2, BorderLayout.CENTER);
mJFrame.setResizable(false);
mJFrame.setVisible(true);
Listen();
}
private void init_J() {
mJFrame = new JFrame("贪吃蛇");
jFrame = new JFrame("游戏界面");
mJPanel = new JPanel();
mJPanel2 = new JPanel();
mJButton = new JButton("开始");
mJLabel1 = new JLabel("选择难度");
mJButton2 = new JButton("退出");
strings = new String[]{"简单", "一般", "困难"};
}
private void Listen() {
mJButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
mJFrame.setVisible(false);
jFrame.getContentPane().setBackground(Color.CYAN);
Snake snake = new Snake(number, 300, 440);
snake.setBackground(Color.BLUE);
jFrame.add(snake);
jFrame.setBounds(500, 200, 320, 480);
jFrame.setResizable(false);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setVisible(true);
}
});
mJSpinner.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent changeEvent) {
switch (mJSpinner.getValue().toString()) {
case "简单":
number = 20;
break;
case "一般":
number = 15;
break;
case "困难":
number = 10;
break;
default:
break;
}
}
});
mJButton2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
mJFrame.dispose();
}
});
}
}
Snake类:
package com.example.lib.java;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JComponent;
public class Snake extends JComponent implements KeyListener {
private static List<Head> headList = new ArrayList<>();
private static int mSecretion;
private static boolean isRuning = true;
private static boolean iseating = true;
private static boolean isChange = false;
private static int a, b, space ;
private static int weight, high;
public Snake(final int number, int weight, int high) {
Snake.weight = weight;
Snake.high = high;
space = number;
this.setFocusable(true); // 获取焦点
this.addKeyListener(this); // 监听键盘事件
headList.add(new Head());
a = 4;
b = 5;
new Thread(new Runnable() {
@Override
public void run() {
while (isRuning) {
try {
Thread.sleep(100);
repaint();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
@Override
protected void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
for (int i = 1; i <= weight / space; i++) {
graphics.drawLine(i * space, 0, i * space, high);
}
for (int i = 1; i <= high / space; i++) {
graphics.drawLine(0, i * space, weight, i * space);
}
graphics.setColor(Color.BLUE);
if (isChange) {
isChange = false;
a = new Random().nextInt(14) + 1;
b = new Random().nextInt(21) + 1;
}
graphics.fillRect(a * space, b * space, space, space);
graphics.setColor(Color.BLACK);
for (int i = 0; i < headList.size(); i++) {
if (i==0){
graphics.setColor(Color.RED);
}else {
graphics.setColor(Color.BLACK);
}
graphics.fillRect(headList.get(i).x, headList.get(i).y, space, space);
}
snakeMove(headList, mSecretion);
if (iseating) {
headList.remove(headList.size() - 1);
}
iseating = true;
}
public void snakeMove(List<Head> heads, int mSnakedirection) {
Head mOldHead = heads.get(0);
Head mNewheads = new Head();
switch (mSnakedirection) {
//上
case 1:
mNewheads.x = mOldHead.x;
mNewheads.y = mOldHead.y - space;
break;
//下
case 2:
mNewheads.x = mOldHead.x;
mNewheads.y = mOldHead.y + space;
break;
//左
case 3:
mNewheads.x = mOldHead.x + space;
mNewheads.y = mOldHead.y;
break;
//右
case 4:
mNewheads.x = mOldHead.x - space;
mNewheads.y = mOldHead.y;
break;
}
Crossing(mNewheads.x, mNewheads.y);
EatMyself(heads);
EatFood(mNewheads.x, mNewheads.y);
Sanme(heads);
heads.add(0, mNewheads);
}
/**
* 越界
*
* @param x
* @param y
*/
private void Crossing(int x, int y) {
if ((x < 0 || x > 280) || (y < 0 || y > 420)) {
isRuning = false;
}
}
/**
* 碰到自己
*/
private void EatMyself(List<Head> heads) {
for (int i = 1; i < heads.size(); i++) {
if (heads.get(0).x == heads.get(i).x && heads.get(0).y == heads.get(i).y) {
isRuning = false;
}
}
}
/**
* 吃到食物
*/
private void EatFood(int x, int y) {
if (x == a * space && y == b * space) {
iseating = false;
isChange = true;
}
}
/**
* 避免食物与蛇体重合
*/
private void Sanme(List<Head> heads) {
for (int i = 0; i < heads.size(); i++) {
if (a == heads.get(i).x && b == heads.get(i).y) {
a = new Random().nextInt(14) + 1;
b = new Random().nextInt(21) + 1;
}
}
}
@Override
public void keyTyped(KeyEvent keyEvent) {
}
@Override
public void keyPressed(KeyEvent keyEvent) {
int keyCode = keyEvent.getKeyCode();
// System.out.print("键盘值:" + keyCode + "\n");
//上
if ((keyCode == 87 || keyCode == 38) && mSecretion != 2) {
mSecretion = 1;
}
//下
else if ((keyCode == 83 || keyCode == 40) && mSecretion != 1) {
mSecretion = 2;
}//左
else if ((keyCode == 68 || keyCode == 39 )&& mSecretion != 4) {
mSecretion = 3;
}//右
else if ((keyCode == 65 || keyCode == 37 )&& mSecretion != 3) {
mSecretion = 4;
}
}
@Override
public void keyReleased(KeyEvent keyEvent) {
}
}
运行效果:
游戏开始界面:
游戏运行界面:
有问题欢迎在下方留言,相互讨论一下。