学习Java的时候,我用swing写了一个贪吃蛇。运行效果如图:
下面给出程序完整源代码,可以直接复制粘贴到你的机子上运行(注意文件名要改成Main.java)。
关于代码有任何问题可以留言我,我会尽力解答。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
public class Main extends JFrame{
private static GamePanel p1 = new GamePanel();//创建游戏面板
private static InformationPanel p2 = new InformationPanel();//创建信息面板
public Main(){//配置框架的布局
setLayout(new BorderLayout());
add(p1,BorderLayout.CENTER);
add(p2,BorderLayout.EAST);
}
public static void main(String[] args){
JFrame frame = new Main();//新建框架
//配置框架
frame.setTitle("贪吃蛇");
frame.setSize(1100, 800);
frame.setVisible(true);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
//新建线程
Thread thread1 = new Thread(p1);
thread1.start();
Thread thread2 = new Thread(p2);
thread2.start();
}
}
class GamePanel extends JPanel implements Runnable{
public static final int PER_UNIT_LENGTH = 20;//单位长度
public static final int MULTIPLE = 15;//倍数
public static final int HALF_SIDE = MULTIPLE * PER_UNIT_LENGTH;//游戏边框的一半长 = 倍数 * 单位长度
private boolean isFirstRun = true;//判断是否需要初始化
private boolean isStarted = false;//判断是否开始
private boolean isPaused = false;//判断是否暂停
private static int score = 0;//游戏分数
private static int information = 0;//传递游戏信息
private Snake snake = new Snake();//新建一条蛇
private Dot dessert = new Dot();//新建一个点心
protected void paintComponent(Graphics g){
super.paintComponent(g);
//获取中点座标
int xCentre = getWidth() / 2;
int yCentre = getHeight() / 2;
//获取一个随机点座标
int xRandom, yRandom;
if(isFirstRun){
isFirstRun = false;
//初始化游戏边框
g.drawRect(xCentre - HALF_SIDE, yCentre - HALF_SIDE, HALF_SIDE * 2, HALF_SIDE * 2);
//初始化蛇头
snake.getHead().setX(xCentre);
snake.getHead().setY(yCentre);
g.setColor(Color.ORANGE);
g.fillOval(snake.getHead().getX(), snake.getHead().getY(), PER_UNIT_LENGTH, PER_UNIT_LENGTH);
//初始化点心
do{
xRandom = xCentre - HALF_SIDE + ((int)(Math.random() * MULTIPLE * 2)) * PER_UNIT_LENGTH;
yRandom = yCentre - HALF_SIDE + ((int)(Math.random() * MULTIPLE * 2)) * PER_UNIT_LENGTH;
}while(xRandom == snake.getHead().getX() && yRandom == snake.getHead().getY());
dessert.setX(xRandom);
dessert.setY(yRandom);
g.setColor(Color.DARK_GRAY);
g.fillOval(dessert.getX(), dessert.getY(), PER_UNIT_LENGTH, PER_UNIT_LENGTH);
}
else{
//绘画游戏边框
g.drawRect(xCentre - HALF_SIDE, yCentre - HALF_SIDE, HALF_SIDE * 2, HALF_SIDE * 2);
//绘画蛇身
g.setColor(Color.MAGENTA);
for(int i = 0;i < snake.getBody().size();i++){
g.fillOval(snake.getBody().get(i).getX(), snake.getBody().get(i).getY(), PER_UNIT_LENGTH, PER_UNIT_LENGTH);
}
//绘画蛇头
g.setColor(Color.ORANGE);
g.fillOval(snake.getHead().getX(), snake.getHead().getY(), PER_UNIT_LENGTH, PER_UNIT_LENGTH);
//如果蛇吃到点心,则更新点心
if(isEncountered()){
do{
xRandom = xCentre - HALF_SIDE + ((int)(Math.random() * MULTIPLE * 2)) * PER_UNIT_LENGTH;
yRandom = yCentre - HALF_SIDE + ((int)(Math.random() * MULTIPLE * 2)) * PER_UNIT_LENGTH;
}while(xRandom == snake.getHead().getX() && yRandom == snake.getHead().getY());
dessert.setX(xRandom);
dessert.setY(yRandom);
}
g.setColor(Color.DARK_GRAY);
g.fillOval(dessert.getX(), dessert.getY(), PER_UNIT_LENGTH, PER_UNIT_LENGTH);
//如果游戏结束,则追加绘画GAME OVER
if(isCrushed()){
g.setColor(Color.BLACK);
FontMetrics fm = g.getFontMetrics();
int stringWidth = fm.stringWidth("GAME OVER");
int stringAscent = fm.getAscent();
int xCoordinate = xCentre - stringWidth / 2;
int yCoordinate = yCentre - stringAscent / 2;
g.drawString("GAME OVER", xCoordinate, yCoordinate);
}
}
}
public GamePanel(){
//配置面板属性
setFocusable(true);
setFont(new Font("Californian FB", Font.BOLD, 80));
//注册键盘监听器
addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e){
int direction = snake.getDirection();
switch(e.getKeyCode()){
case KeyEvent.VK_UP:
if(isStarted && !isPaused && !isCrushed()){
if(direction != Snake.DIRECTION_UP && direction != Snake.DIRECTION_DOWN){
snake.setDirection(Snake.DIRECTION_UP);
changeSnakeLocation();
}
}
break;
case KeyEvent.VK_DOWN:
if(isStarted && !isPaused && !isCrushed()){
if(direction != Snake.DIRECTION_UP && direction != Snake.DIRECTION_DOWN){
snake.setDirection(Snake.DIRECTION_DOWN);
changeSnakeLocation();
}
}
break;
case KeyEvent.VK_LEFT:
if(isStarted && !isPaused && !isCrushed()){
if(direction != Snake.DIRECTION_LEFT && direction != Snake.DIRECTION_RIGHT){
snake.setDirection(Snake.DIRECTION_LEFT);
changeSnakeLocation();
}
}
break;
case KeyEvent.VK_RIGHT:
if(isStarted && !isPaused && !isCrushed()){
if(direction != Snake.DIRECTION_LEFT && direction != Snake.DIRECTION_RIGHT){
snake.setDirection(Snake.DIRECTION_RIGHT);
changeSnakeLocation();
}
}
break;
case KeyEvent.VK_ENTER:
if(isCrushed()){//如果游戏结束,则重置数据重新开始游戏
snake.setDirection(Snake.DIRECTION_RIGHT);
snake.setSpeed(Snake.SPEED_3);
snake.setBody(new LinkedList<Dot>());
isFirstRun = true;
isStarted = false;
isPaused = false;
score = 0;
information = 0;
repaint();
}
else{
isStarted = true;
}
break;
case KeyEvent.VK_SPACE:
if(isStarted && !isCrushed())
isPaused = !isPaused;
break;
case KeyEvent.VK_F1:snake.setSpeed(Snake.SPEED_1);break;
case KeyEvent.VK_F2:snake.setSpeed(Snake.SPEED_2);break;
case KeyEvent.VK_F3:snake.setSpeed(Snake.SPEED_3);break;
case KeyEvent.VK_F4:snake.setSpeed(Snake.SPEED_4);break;
case KeyEvent.VK_F5:snake.setSpeed(Snake.SPEED_5);break;
default:
}
}
});
}
public void run(){//控制蛇自动前进
while(true){
if(isStarted && !isPaused && !isCrushed()){
changeSnakeLocation();
}
try{
Thread.sleep(snake.getSpeed());
}
catch(InterruptedException ex){
ex.printStackTrace();
}
}
}
public synchronized void changeSnakeLocation(){//改变蛇的位置信息并重画
//存储蛇头先前的信息,为蛇身的更新提供依据
int xPrevious = snake.getHead().getX();
int yPrevious = snake.getHead().getY();
//更新蛇头位置
switch(snake.getDirection()){
case Snake.DIRECTION_UP:snake.getHead().setY(yPrevious - PER_UNIT_LENGTH);break;
case Snake.DIRECTION_DOWN:snake.getHead().setY(yPrevious + PER_UNIT_LENGTH);break;
case Snake.DIRECTION_LEFT:snake.getHead().setX(xPrevious - PER_UNIT_LENGTH);break;
case Snake.DIRECTION_RIGHT:snake.getHead().setX(xPrevious + PER_UNIT_LENGTH);break;
default:
}
//根据蛇头信息和是否吃到点心更新蛇身位置
if(isEncountered()){
score++;
snake.getBody().addFirst(new Dot(xPrevious, yPrevious));
}
else{
snake.getBody().addFirst(new Dot(xPrevious, yPrevious));
snake.getBody().removeLast();
}
//重画并获取焦点
repaint();
requestFocus();
}
public boolean isEncountered(){//判断是否吃到点心
if(snake.getHead().getX() == dessert.getX()
&& snake.getHead().getY() == dessert.getY()){
return true;
}
else{
return false;
}
}
public boolean isCrushed(){//判断游戏是否结束
//先判断是否碰触边框
boolean isCrushedByBorder = snake.getHead().getX() >= getWidth() / 2 + HALF_SIDE
|| snake.getHead().getX() < getWidth() / 2 - HALF_SIDE
|| snake.getHead().getY() >= getHeight() / 2 + HALF_SIDE
|| snake.getHead().getY() < getHeight() / 2 - HALF_SIDE;
if(isCrushedByBorder){
information = 1;
return true;
}
//再判断是否碰触自身
boolean isCrushedByItself = false;
for(int i = 0;i < snake.getBody().size();i++){
if(snake.getHead().getX() == snake.getBody().get(i).getX()
&& snake.getHead().getY() == snake.getBody().get(i).getY() && !isCrushedByItself)
isCrushedByItself = true;
}
if(isCrushedByItself){
information = 2;
return true;
}
else{
return false;
}
}
public static int getScore(){
return score;
}
public static int getInformation(){
return information;
}
}
class InformationPanel extends JPanel implements Runnable{
private Box box = Box.createVerticalBox();//创建一个垂直盒子容器
private JLabel[] help = new JLabel[5];//显示帮助信息
private JLabel score = new JLabel("分数:");//显示分数
private JLabel show = new JLabel();//显示信息
public InformationPanel(){
//初始化数组
for(int i = 0;i < help.length;i++)
help[i] = new JLabel();
//配置字体
Font font1 = new Font("DialogInput", Font.BOLD, 20);
Font font2 = new Font("DialogInput", Font.BOLD + Font.ITALIC, 25);
for(int i = 0;i < help.length;i++)
help[i].setFont(font1);
score.setFont(font2);
score.setForeground(Color.GREEN);
show.setFont(font2);
show.setForeground(Color.RED);
//配置帮助信息
help[0].setText("回车键开始游戏");
help[1].setText("方向键移动蛇");
help[2].setText("空格键暂停游戏");
help[3].setText("按键F1-F5调节蛇速");
help[4].setText("按回车键可以重新开始游戏");
//配置信息面板
add(box);
box.add(Box.createVerticalStrut(150));
for(int i = 0;i < help.length;i++){
box.add(help[i]);
box.add(Box.createVerticalStrut(10));
}
box.add(Box.createVerticalStrut(90));
box.add(score);
box.add(Box.createVerticalStrut(150));
box.add(show);
}
public void run(){//更新游戏信息
while(true){
String string1 = "分数:" + Integer.toString(GamePanel.getScore());
score.setText(string1);
String string2 = null;
switch(GamePanel.getInformation()){
case 0:break;
case 1:string2 = "你撞穿墙壁了!";break;
case 2:string2 = "你吃到自己了!";break;
default:
}
show.setText(string2);
}
}
}
class Snake{//蛇类
public static final int DIRECTION_UP = 1;
public static final int DIRECTION_DOWN = 2;
public static final int DIRECTION_LEFT = 3;
public static final int DIRECTION_RIGHT = 4;
public static final int SPEED_1 = 300;
public static final int SPEED_2 = 200;
public static final int SPEED_3 = 150;
public static final int SPEED_4 = 100;
public static final int SPEED_5 = 30;
private int direction = DIRECTION_RIGHT;
private int speed = SPEED_3;
private Dot head = new Dot();
private LinkedList<Dot> body = new LinkedList<Dot>();
public Snake(){
}
public Dot getHead(){
return head;
}
public LinkedList<Dot> getBody(){
return body;
}
public int getDirection(){
return direction;
}
public int getSpeed(){
return speed;
}
public void setBody(LinkedList<Dot> body){
this.body = body;
}
public void setDirection(int direction){
this.direction = direction;
}
public void setSpeed(int speed){
this.speed = speed;
}
}
class Dot{//点类
private int x = 0;
private int y = 0;
public Dot(){
}
public Dot(int x, int y){
this.x = x;
this.y = y;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public void setX(int x){
this.x = x;
}
public void setY(int y){
this.y = y;
}
}
参考:Java语言程序设计(基础篇)