通过对JAVA中swing和awt运用的基础学习来初步实现贪吃蛇。
学习途径如下:
整体功能
贪吃蛇最终实现的功能:
1.空格——开始/暂停
2.上下左右——控制移动方向
3.每吃下一个食物长度加一
4.碰到身体或边界游戏结束
5.实时计算分数与长度
启动类RunGame
创建一个启动类来运行贪吃蛇:
package Snakegame;
import javax.swing.*;
public class RunGame {
public RunGame() {
JFrame frame = new JFrame("贪吃蛇冲冲冲!");
frame.setBounds(350, 40, 800, 600);//游戏窗口的位置及宽高
frame.setResizable(false);//设置游戏窗口不可拉伸
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);//关闭窗口
frame.add(new SnakePanel());//加载面板
frame.setVisible(true);//窗口可视化
}
public static void main (String[]args){
new RunGame();
}
}
游戏元素URL转换
然后我们需要创建一个类来对贪吃蛇中的元素进行URL转换:(其中的元素地址格式必须注意!)
package Snakegame;
import javax.swing.*;
import java.net.URL;
public class Data {
public static URL bodyURL = Data.class.getResource("/static/body.png");//将图片转换为URL
public static ImageIcon body = new ImageIcon(bodyURL);//再将URL转换为图像图标
public static URL foodURL = Data.class.getResource("/static/food.png");
public static ImageIcon food = new ImageIcon(foodURL);
public static URL leftURL = Data.class.getResource("/static/left.png");
public static ImageIcon left = new ImageIcon(leftURL);
public static URL rightURL = Data.class.getResource("/static/right.png");
public static ImageIcon right = new ImageIcon(rightURL);
public static URL upURL = Data.class.getResource("/static/up.png");
public static ImageIcon up = new ImageIcon(upURL);
public static URL downURL = Data.class.getResource("/static/down.png");
public static ImageIcon down = new ImageIcon(downURL);
}
基于画板、监听器整体实现
最后我们可以开始对蛇进行总的设计与实现:
package Snakegame;
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;
游戏各元素定义
public class SnakePanel extends JPanel implements KeyListener, ActionListener {
//定义蛇的数据结构
int length;//长度
int[] snakeX = new int[500];
int[] snakeY = new int[100];
String fx;
//食物坐标
int foodx;
int foody;
Random random=new Random();
//积分
int score;
boolean isStart = false; //设置游戏状态 默认为暂停
boolean isFail= false; //判断游戏失败
@Override
protected String paramString() {
return super.paramString();
}
游戏刷新及初始化
//定时器
Timer timer=new Timer(100,this);//100毫秒刷新一次
//构造器
public SnakePanel() {
init();
//获得焦点和键盘事件
this.setFocusable(true);//获得焦点
this.addKeyListener(this);//获得键盘
timer.start();//游戏开始,定时器启动
}
//初始化方法
public void init() {
length = 3;
snakeX[0] = 100;
snakeY[0] = 100;//头坐标
snakeX[1] = 75;
snakeY[1] = 100;//脖子坐标
snakeX[2] = 50;
snakeY[2] = 100;//身体坐标
fx = "R";
//食物随机生成
foodx= 25+25*random.nextInt(28);
foody=75+25*random.nextInt(16);
score=0;
}
将游戏元素画入画板区
//定义画笔
@Override
protected void paintComponent(Graphics g) {
super.paintComponents(g);//清屏
//绘制静态面板
this.setBackground(Color.BLACK);
g.fillRect(25, 28, 725, 500);//运动面板
//画上积分
g.setColor(Color.black);
g.setFont(new Font("微软雅黑",Font.BOLD,12));
g.drawString("长度 "+length,700,10);
g.drawString("分数 "+score,700,25);
//画食物
Data.food.paintIcon(this,g,foodx,foody);
//绘制小蛇
if (fx.equals("R")) {
Data.right.paintIcon(this, g, snakeX[0], snakeY[0]);
} else if (fx.equals("L")) {
Data.left.paintIcon(this, g, snakeX[0], snakeY[0]);
} else if (fx.equals("U")) {
Data.up.paintIcon(this, g, snakeX[0], snakeY[0]);
} else if (fx.equals("D")) {
Data.down.paintIcon(this, g, snakeX[0], snakeY[0]);
}
for (int i = 1; i < length; i++) {
Data.body.paintIcon(this, g, snakeX[i], snakeY[i]);
}
//游戏状态
if (isStart == false) {
g.setColor(Color.white);
g.setFont(new Font("微软雅黑", Font.BOLD, 30));
g.drawString("按空格/暂停开始游戏", 250, 250);
}
//失败判定
if(isFail){
g.setColor(Color.RED);
g.setFont(new Font("微软雅黑",Font.BOLD,28));
g.drawString("按下空格重新开始游戏",250,270);
}
}
游戏监听
键盘监听
//键盘监听事件
@Override
public void keyPressed(KeyEvent e) {
int keyCode =e.getKeyCode(); //获取按下的按键
if(keyCode==KeyEvent.VK_SPACE){ //按下空格键
if(isFail){
//重新开始
isFail=false;
init();
}else {
isStart = !isStart;//取反
}
repaint();
}
//小蛇移动判断
if(keyCode==KeyEvent.VK_UP){
fx="U";
}else if(keyCode==KeyEvent.VK_DOWN){
fx="D";
}else if(keyCode==KeyEvent.VK_LEFT){
fx="L";
}else if(keyCode==KeyEvent.VK_RIGHT){
fx="R";
}
}
事件监听及画面刷新
//事件监听
@Override
public void actionPerformed(ActionEvent e) {
if(isStart && isFail==false) {//开始游戏,没有失败则运行小蛇
//吃食物
if(snakeX[0]==foodx &&snakeY[0]==foody){
length++; //长度加一
score=score+10;//分数加10
//刷新食物
foodx= 25+25*random.nextInt(25);
foody=75+25*random.nextInt(15);
}
for (int i = length - 1; i > 0; i--) {//后一节向前一节移动
snakeX[i] = snakeX[i - 1];
snakeY[i] = snakeY[i - 1];
}
//走向
if (fx.equals("R")) {
snakeX[0] = snakeX[0] + 25;
if (snakeX[0] > 725) {
isFail=true;
}
} else if (fx.equals("L")) {
snakeX[0] = snakeX[0] - 25;
if (snakeX[0] < 25) {
isFail=true;
init();
}
} else if (fx.equals("U")) {
snakeY[0] = snakeY[0] - 25;
if (snakeY[0] < 25){
isFail=true;
}
}else if(fx.equals("D")){
snakeY[0]=snakeY[0]+25;
if (snakeY[0]>500){
isFail=true;
}
//碰撞自己则失败
for(int i=1;i<length;i++){
if(snakeX[0]==snakeX[i]&& snakeY[0]==snakeY[i]){
isFail=true;
}
}
}
repaint();//刷新画面
}
timer.start();//定时器开启
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void keyTyped(KeyEvent e) {
}
}
到这里基本实现了贪吃蛇的运行。(其他细节待完善)
最终实现界面如下: