1.概述
首先要了解游戏的画面--一个画面为一帧,那怎么让画面动起来还是要靠定时器进行刷新。
这个小游戏主要需要掌握的技术要点:
首先:面板的绘制,必须是需要一个面板来展示游戏嘛;其次:键盘输入的控制(玩游戏肯定是在键盘上操作嘛),最后:定时器的操作(看多少秒刷新一帧,让游戏动起来的关键)
那下面的代码实现就主要围绕着三个方面来进行啦
2.代码实现
2.1 绘制面板及画面
Step1:先绘制静态窗口,再窗口上面绘制一个游戏面板,主要的操作就在游戏面板中进行,这个类就是游戏的启动类
public class StartGame {
public static void main(String[] args) {
//1.绘制一个静态窗口
Jframe frame=new Jframe("贪吃蛇游戏");
frame.setBounds(10,10,900,720);
frame.setResizable(false);
frame.setDefaultCloseOperation(Jframe.EXIT_ON_CLOSE);
//2.绘制一个面板 游戏面板
frame.add(new GamePanel());
frame.setVisible(true);
}
Step2:绘制游戏面板
我们先看一下效果图:可以看到将这个面板分成了三个区域,其中1就是一个图标,2部分记录了当前蛇的长度和分数,第三个部分就是主要玩游戏的地方(包括蛇的绘制、一个食物,一句话语(按下空格开始游戏))
需要明确的是:一个画面中的某一点其实可以抽象成一个坐标来表示,所以无论是食物还是蛇我们都可以通过坐标来进行表示
先定义一些变量:(这是所有的变量定义,有些变量后面才会用到,后面再进行解释)
int length; //蛇的长度
int[] snakeX=new int[500]; //蛇x坐标
int[] snakeY=new int[500]; //y坐标
String fx; //方向
boolean isStart=false; //游戏是否开始
//定时器
Timer timer;
int delay; //时间
//1.定义一个食物
int foodX;
int foodY;
Random random=new Random();
//死亡判断
boolean isFail=false;
//积分系统
int score;
再初始化:
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(34);
foodY=75+25*random.nextInt(24);
score=0;
再将物体画在面板上:主要是重写paintComponent()方法:
//画头部
Data.header.paintIcon(this,g,25,11);
g.fillRect(25,75,850,600);
//根据方向画头部的方向
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
这里蛇的头部和身体都是由一张图片组成,主要需要定义一个Data类记录这些图片:
public class Data {
//头部
public static URL headerURL = Data.class.getResource("/statics/header.png");
public static ImageIcon header = new ImageIcon(headerURL);
//贪吃蛇 头部上下左右
public static URL upURL = Data.class.getResource("/statics/up.png");
public static URL downURL = Data.class.getResource("/statics/down.png");
public static URL leftURL = Data.class.getResource("/statics/left.png");
public static URL rightURL = Data.class.getResource("/statics/right.png");
public static ImageIcon up = new ImageIcon(upURL);//上
public static ImageIcon down = new ImageIcon(downURL);//下
public static ImageIcon left = new ImageIcon(leftURL);//左
public static ImageIcon right = new ImageIcon(rightURL);//右
//身体
public static URL bodyURL = Data.class.getResource("/statics/body.png");
public static ImageIcon body = new ImageIcon(bodyURL);
//食物
public static URL foodURL = Data.class.getResource("/statics/food.png");
public static ImageIcon food = new ImageIcon(foodURL);
}
2.2 键盘点击事件
这里主要是需要继承KeyListener重写方法,在keyPressed()方法中进行操作。这里的输入主要是蛇的移动上下左右、还有空格。
空格键的处理:如果游戏失败,那就按空格键重新开始,如果游戏还未失败那就是按空格键暂停或者开始:
//键盘按下,未释放
//获取按下的键盘是哪个键
int keyCode = keyEvent.getKeyCode();
if(keyCode==KeyEvent.VK_SPACE){
//如果失败了就重新开始
if(isFail){
isFail=false;
//重新初始化
init();
}else{
//如果没有失败就是暂停或者开始
isStart=!isStart;
}
repaint();//刷新页面
}
蛇的移动:这里主要是根据键盘的输入来定义蛇的移动方向,并且不能转头
if(keyCode==KeyEvent.VK_RIGHT){
if(fx.equals("L")){
fx="L";
}else{
fx="R";
}
}else if(keyCode==KeyEvent.VK_LEFT){
if(fx.equals("R")){
fx="R";
}else{
fx="L";
}
}else if(keyCode==KeyEvent.VK_UP){
if(fx.equals("D")){
fx="D";
}else{
fx="U";
}
}else if(keyCode==KeyEvent.VK_DOWN){
if(fx.equals("U")){
fx="U";
}else{
fx="D";
}
}
2.3 定时器刷新
主要是需要继承ActionListener重写actionPerformed()方法
初始化定时器:这里指的是多少毫秒刷新一次,也可以根据这个时间调节快慢
delay=100;
timer=new Timer(100,this);
这里的逻辑主要是蛇的移动的坐标:
if(isStart && isFail==false) {
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]>850){
// snakeX[0]=25;
// }
}else if(fx.equals("L")){
snakeX[0] = snakeX[0] - 25;
//边界判断
// if(snakeX[0]<25){
// snakeX[0]=25;
// }
}else if(fx.equals("U")){
snakeY[0] = snakeY[0] - 25;
//边界判断
// if(snakeY[0]<75){
// snakeY[0]=650;
// }
}else if(fx.equals("D")){
snakeY[0] = snakeY[0] + 25;
//边界判断
// if(snakeY[0]>650){
// snakeY[0]=75;
// }
}
蛇吃食物:当蛇头的坐标与食物的坐标重合时就证明吃到了食物,分数+1,蛇的长度也进行相应的加1,并且重新生成食物就可以
if(snakeX[0]==foodX && snakeY[0]==foodY){
//长度+1,分数+1
length++;
score++;
//重新生成食物
foodX=25+25*random.nextInt(34);
foodY=75+25*random.nextInt(24);
}
在进行游戏结束的判断、刷新页面:
private void isFailMethod() {
for(int i=1;i850)||(snakeY[0]<75 || snakeY[0]>650 ) ){
isFail = true;
}
}
一定不要忘记最后让定时器启动!!!!
timer.start();
3.总结
Step1:先绘制静态窗口,再窗口上面绘制一个游戏面板,主要的操作就在游戏面板中进行,这个类就是游戏的启动类
public class StartGame { public static void main(String[] args) { //1.绘制一个静态窗口 Jframe frame=new Jframe("贪吃蛇游戏"); frame.setBounds(10,10,900,720); frame.setResizable(false); frame.setDefaultCloseOperation(Jframe.EXIT_ON_CLOSE); //2.绘制一个面板 游戏面板 frame.add(new GamePanel()); frame.setVisible(true); }Step2:绘制游戏面板
我们先看一下效果图:可以看到将这个面板分成了三个区域,其中1就是一个图标,2部分记录了当前蛇的长度和分数,第三个部分就是主要玩游戏的地方(包括蛇的绘制、一个食物,一句话语(按下空格开始游戏))
需要明确的是:一个画面中的某一点其实可以抽象成一个坐标来表示,所以无论是食物还是蛇我们都可以通过坐标来进行表示
先定义一些变量:(这是所有的变量定义,有些变量后面才会用到,后面再进行解释)
int length; //蛇的长度 int[] snakeX=new int[500]; //蛇x坐标 int[] snakeY=new int[500]; //y坐标 String fx; //方向 boolean isStart=false; //游戏是否开始 //定时器 Timer timer; int delay; //时间 //1.定义一个食物 int foodX; int foodY; Random random=new Random(); //死亡判断 boolean isFail=false; //积分系统 int score;再初始化:
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(34); foodY=75+25*random.nextInt(24); score=0;再将物体画在面板上:主要是重写paintComponent()方法:
//画头部 Data.header.paintIcon(this,g,25,11); g.fillRect(25,75,850,600); //根据方向画头部的方向 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这里蛇的头部和身体都是由一张图片组成,主要需要定义一个Data类记录这些图片:
public class Data { //头部 public static URL headerURL = Data.class.getResource("/statics/header.png"); public static ImageIcon header = new ImageIcon(headerURL); //贪吃蛇 头部上下左右 public static URL upURL = Data.class.getResource("/statics/up.png"); public static URL downURL = Data.class.getResource("/statics/down.png"); public static URL leftURL = Data.class.getResource("/statics/left.png"); public static URL rightURL = Data.class.getResource("/statics/right.png"); public static ImageIcon up = new ImageIcon(upURL);//上 public static ImageIcon down = new ImageIcon(downURL);//下 public static ImageIcon left = new ImageIcon(leftURL);//左 public static ImageIcon right = new ImageIcon(rightURL);//右 //身体 public static URL bodyURL = Data.class.getResource("/statics/body.png"); public static ImageIcon body = new ImageIcon(bodyURL); //食物 public static URL foodURL = Data.class.getResource("/statics/food.png"); public static ImageIcon food = new ImageIcon(foodURL); }
2.2 键盘点击事件
这里主要是需要继承KeyListener重写方法,在keyPressed()方法中进行操作。这里的输入主要是蛇的移动上下左右、还有空格。
空格键的处理:如果游戏失败,那就按空格键重新开始,如果游戏还未失败那就是按空格键暂停或者开始:
//键盘按下,未释放
//获取按下的键盘是哪个键
int keyCode = keyEvent.getKeyCode();
if(keyCode==KeyEvent.VK_SPACE){
//如果失败了就重新开始
if(isFail){
isFail=false;
//重新初始化
init();
}else{
//如果没有失败就是暂停或者开始
isStart=!isStart;
}
repaint();//刷新页面
}
蛇的移动:这里主要是根据键盘的输入来定义蛇的移动方向,并且不能转头
if(keyCode==KeyEvent.VK_RIGHT){
if(fx.equals("L")){
fx="L";
}else{
fx="R";
}
}else if(keyCode==KeyEvent.VK_LEFT){
if(fx.equals("R")){
fx="R";
}else{
fx="L";
}
}else if(keyCode==KeyEvent.VK_UP){
if(fx.equals("D")){
fx="D";
}else{
fx="U";
}
}else if(keyCode==KeyEvent.VK_DOWN){
if(fx.equals("U")){
fx="U";
}else{
fx="D";
}
}
2.3 定时器刷新
主要是需要继承ActionListener重写actionPerformed()方法
初始化定时器:这里指的是多少毫秒刷新一次,也可以根据这个时间调节快慢
delay=100;
timer=new Timer(100,this);
这里的逻辑主要是蛇的移动的坐标:
if(isStart && isFail==false) {
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]>850){
// snakeX[0]=25;
// }
}else if(fx.equals("L")){
snakeX[0] = snakeX[0] - 25;
//边界判断
// if(snakeX[0]<25){
// snakeX[0]=25;
// }
}else if(fx.equals("U")){
snakeY[0] = snakeY[0] - 25;
//边界判断
// if(snakeY[0]<75){
// snakeY[0]=650;
// }
}else if(fx.equals("D")){
snakeY[0] = snakeY[0] + 25;
//边界判断
// if(snakeY[0]>650){
// snakeY[0]=75;
// }
}
蛇吃食物:当蛇头的坐标与食物的坐标重合时就证明吃到了食物,分数+1,蛇的长度也进行相应的加1,并且重新生成食物就可以
if(snakeX[0]==foodX && snakeY[0]==foodY){
//长度+1,分数+1
length++;
score++;
//重新生成食物
foodX=25+25*random.nextInt(34);
foodY=75+25*random.nextInt(24);
}
在进行游戏结束的判断、刷新页面:
private void isFailMethod() {
for(int i=1;i850)||(snakeY[0]<75 || snakeY[0]>650 ) ){
isFail = true;
}
}
一定不要忘记最后让定时器启动!!!!
timer.start();
3.总结
这里主要是需要继承KeyListener重写方法,在keyPressed()方法中进行操作。这里的输入主要是蛇的移动上下左右、还有空格。
空格键的处理:如果游戏失败,那就按空格键重新开始,如果游戏还未失败那就是按空格键暂停或者开始:
//键盘按下,未释放
//获取按下的键盘是哪个键
int keyCode = keyEvent.getKeyCode();
if(keyCode==KeyEvent.VK_SPACE){
//如果失败了就重新开始
if(isFail){
isFail=false;
//重新初始化
init();
}else{
//如果没有失败就是暂停或者开始
isStart=!isStart;
}
repaint();//刷新页面
}
蛇的移动:这里主要是根据键盘的输入来定义蛇的移动方向,并且不能转头
if(keyCode==KeyEvent.VK_RIGHT){
if(fx.equals("L")){
fx="L";
}else{
fx="R";
}
}else if(keyCode==KeyEvent.VK_LEFT){
if(fx.equals("R")){
fx="R";
}else{
fx="L";
}
}else if(keyCode==KeyEvent.VK_UP){
if(fx.equals("D")){
fx="D";
}else{
fx="U";
}
}else if(keyCode==KeyEvent.VK_DOWN){
if(fx.equals("U")){
fx="U";
}else{
fx="D";
}
}
3.总结主要是需要继承ActionListener重写actionPerformed()方法
初始化定时器:这里指的是多少毫秒刷新一次,也可以根据这个时间调节快慢
delay=100; timer=new Timer(100,this);这里的逻辑主要是蛇的移动的坐标:
if(isStart && isFail==false) { 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]>850){ // snakeX[0]=25; // } }else if(fx.equals("L")){ snakeX[0] = snakeX[0] - 25; //边界判断 // if(snakeX[0]<25){ // snakeX[0]=25; // } }else if(fx.equals("U")){ snakeY[0] = snakeY[0] - 25; //边界判断 // if(snakeY[0]<75){ // snakeY[0]=650; // } }else if(fx.equals("D")){ snakeY[0] = snakeY[0] + 25; //边界判断 // if(snakeY[0]>650){ // snakeY[0]=75; // } }蛇吃食物:当蛇头的坐标与食物的坐标重合时就证明吃到了食物,分数+1,蛇的长度也进行相应的加1,并且重新生成食物就可以
if(snakeX[0]==foodX && snakeY[0]==foodY){ //长度+1,分数+1 length++; score++; //重新生成食物 foodX=25+25*random.nextInt(34); foodY=75+25*random.nextInt(24); }在进行游戏结束的判断、刷新页面:
private void isFailMethod() { for(int i=1;i850)||(snakeY[0]<75 || snakeY[0]>650 ) ){ isFail = true; } } 一定不要忘记最后让定时器启动!!!!
timer.start();
主要的代码逻辑这里就可以分别进行说明啦。整个运行的代码我上传在我的资源上啦



