本程序是结合自己对于面向对象的理解,线程和GUI做的小游戏
游戏运行如图:
首先我定义了两个类,一个用于存储蛇的信息,一个用于存储食物的信息
蛇的类
package SnakeGame;
public class Snake {
// 设置蛇的身体位置坐标,最大可达到34*24
public int[] snakex=new int[750];
public int[] snakey=new int[750];
// 蛇身体的长度
int len=0;
// 蛇的方向
String direction=null;
// 初始化
public Snake() {
setup();
}
// 初始化
public void setup() {
len=3;
direction="R";
snakex[0]=100; snakex[1]=75; snakex[2]=50;
snakey[0]=100; snakey[1]=100; snakey[2]=100;
}
}
食物的类
package SnakeGame;
import java.util.*;
public class food {
Random r=new Random();
// 定义食物的数量
public int len=4;
// 定义食物的位置
int[] footx=new int[len];
int[] footy=new int[len];
public food() {
for(int i=0;i<len;i++) {
footx[i]=r.nextInt(34)*25+25;
footy[i]=r.nextInt(24)*25+75;
}
}
// 用于初始化
public void setup() {
for(int i=0;i<len;i++) {
footx[i]=r.nextInt(34)*25+25;
footy[i]=r.nextInt(24)*25+75;
}
}
// 用于重新生成食物
public void produce(int i) {
footx[i]=r.nextInt(34)*25+25;
footy[i]=r.nextInt(24)*25+75;
}
}
*说明:如上图运行界面所示的,因为我黑色背景定义的宽高为850px650px,蛇的身体节点和食物的宽高都是25px,x轴空出的间距有25px,y轴空出75px,所以footx[i]=r.nextInt(34)*25+25;footy[i]=r.nextInt(24)*25+75;(其他情况以此类推)
创建窗口
package SnakeGame;
import javax.swing.*;
public class SnakeFrame {
public static void main(String[] args) {
JFrame frame=new JFrame();
SnakePanel sp=new SnakePanel();
frame.add(sp);
frame.setBounds(400,50,900,720);
frame.setIconImage(new ImageIcon("Images/logo.png").getImage());
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("贪吃蛇");
frame.setVisible(true);
}
}
在画板中画出
package SnakeGame;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.*;
@SuppressWarnings("serial")
public class SnakePanel extends JPanel implements ActionListener,KeyListener{
ImageIcon title=new ImageIcon("Images/title.jpg");
ImageIcon body=new ImageIcon("Images/body.png");
ImageIcon up=new ImageIcon("Images/up.png");
ImageIcon down=new ImageIcon("Images/down.png");
ImageIcon right=new ImageIcon("Images/right.png");
ImageIcon left=new ImageIcon("Images/left.png");
ImageIcon food=new ImageIcon("Images/food.png");
// 蛇
Snake s;
// 食物
food f;
// 是否开始
boolean isStarted=false;
// 是否结束
boolean isFailed=false;
// 计时器
Timer timer=new Timer(110, this);
public SnakePanel() {
// 获取焦点
this.setFocusable(true);
s=new Snake();
f=new food();
// 计时器运行
timer.start();
// 加入监听事件
this.addKeyListener(this);
}
@Override
public void paint(Graphics g) {
super.paintComponent(g);
title.paintIcon(this, g, 25, 11);
g.fillRect(25, 75, 850, 650);
// 判断蛇的方向,画蛇头
if (s.direction.equals("R"))
right.paintIcon(this, g, s.snakex[0], s.snakey[0]);
else if (s.direction.equals("L"))
left.paintIcon(this, g, s.snakex[0], s.snakey[0]);
else if (s.direction.equals("U"))
up.paintIcon(this, g, s.snakex[0], s.snakey[0]);
else if (s.direction.equals("D"))
down.paintIcon(this, g, s.snakex[0], s.snakey[0]);
// 画蛇的身体
for(int i=1;i<s.len;i++) {
body.paintIcon(this, g, s.snakex[i], s.snakey[i]);
}
// 画食物
for(int i=0;i<f.len;i++) {
food.paintIcon(this, g,f.footx[i], f.footy[i]);
}
// 判断游戏是否开始,没开始就显示
if(!isStarted) {
g.setColor(Color.WHITE);
g.setFont(new Font("arial",Font.BOLD,30));
g.drawString("Press Space to start/pause", 200, 200);
}
// 判断游戏是否结束,结束就显示
if(isFailed) {
g.setColor(Color.WHITE);
g.setFont(new Font("arial",Font.BOLD,30));
g.drawString("Game Over,Press Space to restart", 200, 200);
}
// 画分数和蛇的长度
g.setColor(Color.WHITE);
g.setFont(new Font("arial",Font.BOLD,15));
g.drawString("Length: "+(s.len), 650, 35);
g.drawString("Score : "+(s.len-3)*10, 650, 55);
}
@Override
public void actionPerformed(ActionEvent e) {
// timer.start();
// 如果开始并且未结束执行
if(isStarted&&!isFailed) {
// 存储的坐标会比蛇的长度多一,因为如果蛇吃到食物就能马上获取最后一个的坐标
// 如果没有多一,蛇的身体会画在(0,0)位置
// 从后往前,给最后一个赋值前一个的坐标
for(int i=s.len;i>0;i--) {
s.snakex[i]=s.snakex[i-1];
s.snakey[i]=s.snakey[i-1];
}
// 判断蛇头的方向,每次加减25px(图片大小25px)
if(s.direction.equals("R")) {
s.snakex[0]+=25;
if(s.snakex[0]>850) s.snakex[0]=25;
}else if(s.direction.equals("L")) {
s.snakex[0]-=25;
if(s.snakex[0]<25) s.snakex[0]=850;
}else if(s.direction.equals("U")) {
s.snakey[0]-=25;
if(s.snakey[0]<75) s.snakey[0]=650;
}else if(s.direction.equals("D")) {
s.snakey[0]+=25;
if(s.snakey[0]>650) s.snakey[0]=75;
}
// 判断是否吃到食物,吃到就调用food的produce重新生成食物位置,蛇长度+1
for(int i=0;i<f.len;i++) {
if(s.snakex[0]==f.footx[i]&&s.snakey[0]==f.footy[i]) {
s.len++;
f.produce(i);
}
}
// 判断是否撞到自己身体,撞到结束游戏
for(int i=1;i<s.len;i++) {
if(s.snakex[0]==s.snakex[i]&&s.snakey[0]==s.snakey[i]) {
isFailed=true;
}
}
}
// 重绘
repaint();
}
// 用于蛇,食物位置,判断条件初始化
public void setup() {
s.setup();
f.setup();
isStarted=false;
isFailed=false;
}
@Override
public void keyPressed(KeyEvent e) {
// 如果按键为空格执行
if(e.getKeyCode()==KeyEvent.VK_SPACE) {
// 判断是否结束,结束初始化
if(isFailed) {
setup();
}else {
// 没有结束就就为暂停/开始,当前状态取反
isStarted=!isStarted;
}
}else if(isStarted&&!isFailed) {//当游戏开始时才能按
if(e.getKeyCode()==KeyEvent.VK_UP&&s.direction!="D") {//按下向上,且当前蛇的方向不能是向下,防止往回跑
s.direction="U";
}else if(e.getKeyCode()==KeyEvent.VK_DOWN&&s.direction!="U") {//
s.direction="D";
}else if(e.getKeyCode()==KeyEvent.VK_RIGHT&&s.direction!="L") {//
s.direction="R";
}else if(e.getKeyCode()==KeyEvent.VK_LEFT&&s.direction!="R") {//
s.direction="L";
}
}
}
@Override
public void keyReleased(KeyEvent arg0) {
}
@Override
public void keyTyped(KeyEvent arg0) {
}
}