* 1:设计游戏图纸
* 2:设计游戏窗体
* 3:在窗体上添加面板
* 4:在面板上添加画笔方法(paintComponent方法)
*5 用super调用父类的paintComponent (来每一次刷新界面)
* 6:在面板上添加标题:用ImageIcon导入图片类来导入图片,然后调用有关方法
* 7:在面板上添加黑色游戏区框(添加黑色方框)-----在画新成分的paintComponent方 法中 直接用画笔的天面方框的g.fillRect()来填满方框(已达到添加黑色方框的)
* 8:放静态的蛇(包括身体和头):—与在画板上添加标题是差不多的。都是放入图片,与其格式类似
* 9:定义蛇的数据结构 ----记录蛇的长度并把蛇能达到的x y 坐标记录在数组中。数据结 构:意思是将蛇的部位的x y坐标放入到数组中(存放在数组中,以方便调用,此即为蛇 的数据结构)
* 10:控制蛇头的方向----通过设置变量 +if else语句来控制蛇头的方向变化。
* 11:放上开始字符提示----用画笔的g.drawString方法在面板直接有字符串出现 (要先改变画 笔的颜色,用setColor()方法来改变画笔的颜色 +设计字体的有关内容,如字体类型、大 小、是否粗体等的setFont方法)
* 12 :设置boolean变量来显示是否是开始状态,且结合此状态来判断开始字符提示是否应 该没有(不打印了)----只有状态是false才输出开始提示
* 13:设置获取键盘事件-----设置获取焦点的setFocusable()方法,这样就可获取键盘事件
* 14:设置键盘监听器 ----通过addKeyListener()方法来设置键盘监听器,(自己监听自己 是键盘事件,那就要实现KeyListener的接口)
* 15:重写实现KeyListener接口的方法
* 16:通过设置变量 + getKeyCode()方法 来获取到键盘敲了哪个数字 (因为每一个按键都 对应一个数字,getKeyCode()方法能获取到键盘敲了哪个数字)
* 17:判断键盘是否敲了空格键,如果敲了就改变isstarted的状态 (KeyEvent.VK_SPACA : 表示空格键)
* 18:按空格键开始游戏
* 19:设置时钟—让程序到成运行结束和 运行结束后找数: 一般游戏是找回自身的即找 回this。 (要实现ActionListener接口才能设置时钟)(时间到了就会调用重写的 ActionListener的方法)
* 20 :实现ActionListener接口—让时钟能够设置
* 21 :重写接口方法
* 22:在重写的方法中,重写paintComponent方法(即repaint) +通过Timer.start() 让时钟再次开始
* 23:在构造方法中让时钟启动起来。
* 24 :让身体移动起来
* 25 :让头发生移动 ----通过snakex[0] =snakex[0] + 25;让蛇一直向右移动
* 26 :给头的移动范围增加边界----用if语句 +如果snakex[0] =850,就有snakex[0] =25, 通过此让其回到反方向的边界处。(到了边界就从反方向边界出现)
* 27:实现暂停 ----按空格就可有蛇不再跑 —(反正括号里是true则输出其语句,如果 是false则不输出)
* 28:根据键盘事件改编direction的值
* 29 :根据direction的值的变化来改变头的移动方向—actionPerformed(ActionEvent) 方法处写代码。因为这是这是与移动有关的内容
*30:添加食物—打印食物的图片 + 随机生成食物的坐标
* 31:吃掉食物
* 32 :判断蛇是否失败 ----设置变量isFiled =false; --当没死的时候才会移动
—用for语句判断如果蛇头的坐标与食物的坐标重合的时候,把 isFiled =true(这样会让蛇没法移动了)
* 33:游戏结束提示----当isFiled = true的时候就用drawString输出一个结束字符串提 示游戏结束 (和打印开始提示很类似)
* 34:当游戏结束后,有红色提示出现后,再按空格时不想要白色的开始提示---- 在监听空格键那里把开始提示的变量改为相反的值即可(即把)-
* 34:游戏结束提示 和 实现重新开始功能
* 35:添加分数和长度
……….
( 接下来的步骤可自己结合代码深入理解 )
package moonsnake;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;
/**
*
*创建游戏面板格式:(讲解:可new对象 或者直接继承JPnanel,让其为父类,获得其属性和方法)
*关键字为:JPanel
*/
/**
* 要在面板中画东西,如设置颜色等,前面都要有这两行内容
* public void paintComponent(Graphics g) {
* super.paintComponent(g);
*
*/
public class MPanel extends JPanel implements KeyListener, ActionListener { //实现接口,让该面板能监听
//创建图像类,传入图片到面板中。
ImageIcon title = new ImageIcon("src/title.jpg"); //用ImageIcon有关的知识点来引入图片
ImageIcon body= new ImageIcon("src/body.png");
ImageIcon up= new ImageIcon("src/up.png");
ImageIcon down= new ImageIcon("src/down.png");
ImageIcon left= new ImageIcon("src/left.png");
ImageIcon right= new ImageIcon("src/right.png");
ImageIcon food= new ImageIcon("src/food.png"); //然后用画笔画出来
/**
* 蛇的数据结构,即是有记忆的长度、宽度等是有记录的,长度是会增加的
*/
//设置长度
int len = 3; //蛇的身体长度默认是3
//设置分数
int score = 0;
//定义数组来存放蛇的x坐标和y坐标: 即蛇能在框移动的位置范围为750x750
int [] snakex = new int[750]; //蛇移动的位置:蛇移动产生的x、y坐标
int [] snakey = new int[750];
/**
* 定义变量来确定蛇的方向,而不是只打印一个方向
*
* 通过R,L,U,D 来分别代表四个方向
* 先赋一个值,后面根据实际情况而改变
*/
String direction = "R"; //先赋一个值,后面会根据实际情况而改变
//设置用于键盘监听器的变量
//设置判断是否为开始状态 默认是false
boolean isStarted = false;
//设置判断头是否是与身体重叠,重叠就让蛇 out掉
boolean isFailed = false;
//设置时钟,来让蛇体不断进行移动。 new 时钟(Timer)对象
Timer timer = new Timer(150,this); //参数为(规定的时间,到点了找谁) ---就可到点了再找回了this,然后不断重复以实现不断的
//(时钟设置好了,要在构造方法中进行开始)
//设置食物
/**
* 随机生成食物--引入随机函数 Random
*/
int foodx; //此变量在画的时候被用
int foody;
//引入随机函数
/**
* 生成随机数的格式是:调用生成随机数的nextInt()方法
* 如:random.nextInt(34) //从0到33中随机选一个数
*/
Random random = new Random();
//构造方法 (必须要有空的构造方法)
public MPanel() {
//调用刷新图片的initSnake()方法
initSnake(); //直接输入方法名
//调用设置获取焦点的方法 即为setFocusable()方法
//调用设置获取焦点
this.setFocusable(true); //获取焦点 即可获取键盘事件
//设置键盘监听器(参数中填this,即监听此面板的内容) :调用键盘监听器方法,然后监听自身
this.addKeyListener(this); //此处要实现KeyListener的接口
//开始已设置好的时钟
timer.start();
/**
* 时钟开始后,在actionPerformed(执行的操作中)进行蛇的移动的操作
*/
}
//画游戏中的成分/组成部分的方法
/**
* 其中有Graphics画笔内容
*/
public void paintComponent(Graphics g) {
//在这里面画东西
super.paintComponent(g); //调用父类面板方法然后把this.paintComponent中的g传入到调用的方法中
//设置面板颜色
/**
* 游戏窗体一般是不能设置颜色的,但游戏面板可以设置颜色
*
* 用this关键字调用方法则不用new对象的对象的引用来调用方法
*/
this.setBackground(Color.WHITE);
//把引入的图片画出来
title.paintIcon(this, g, 25, 11);
//第一把为画在哪里(this表示画在此面板上。) g表示传进来的画笔 后两个表示距离窗体的距离
//在游戏面板中画出黑色的框
/**
* 直接用画笔把想要的方框填成黑色
* 即用fill.Rect()方法来在指定位置来填成黑色
* (距离位置,距离位置,宽,高)
* g即为画笔的引用
*/
//画出黑色方框
g.fillRect(25, 75, 850, 600);
//先把画笔颜色设置为其他颜色,为打印长度和分数做准备
g.setColor(Color.WHITE);
//打印长度和分数(用drawString方法打印出字符串、字符)
g.drawString("len:" +len,750 , 35);
g.drawString("score:" +score,750 , 50);
//画出身体、上下左右
// right.paintIcon(this, g, 100, 100);
// body.paintIcon(this, g, 75, 100);
// body.paintIcon(this, g, 50, 100); //这里就不能这样画出蛇的内容,数量多就不行,要用for循环。
//打印头
if (direction == "R") {
right.paintIcon(this, g, snakex[0],snakey[0]); //如果是R,则打印向右的头图片
}else if (direction == "L") {
left.paintIcon(this, g, snakex[0],snakey[0]); //如果是L,则打印向左的头图片
}else if (direction == "U") {
up.paintIcon(this, g, snakex[0],snakey[0]); //如果是U,则打印向上的头图片
}else if (direction == "D") {
down.paintIcon(this, g, snakex[0],snakey[0]); //如果是D,则打印向下的头图片
}
//打印身体
for(int i =1 ;i<len;i++) {
//通过数组下标的增加来在for循环中,打印出蛇的身体 :其坐标为snakex[i],即可根据下标的改变而改变
body.paintIcon(this, g, snakex[i] ,snakey[i]);
}
//打印食物
food.paintIcon(this, g, foodx, foody);
//把画笔变成其他颜色
g.setColor(Color.WHITE);
//改变字体大小 :导入font包,然后设置好参数(字体类型,字符是粗体/斜体,字体大小)
g.setFont(new Font ("arial",Font.BOLD,40));
/**
*在面板中打印开始语 :实际上是用画笔画出字符串
*/
//画出开始语
//当游戏开始时取消画笔画出来的字,isStarted为false时才打印
if (isStarted ==false ) {
g.drawString("Press Space to start", 300, 300);
}
g.setColor(Color.RED);
g.setFont(new Font ("arial",Font.BOLD,40));
//输出重新开始语 ---然后要重新开始就要在响应键盘事件:在响应键盘哪里天健if语句使isFailed变成flase
if (isFailed ==true) { //如果isFailed = true则输出重新开始语
g.drawString("Failed:Press Space to start", 200, 300);
}
/**
* 要让这个面板真正的有颜色和其中的方法有效果,就要在窗体中用add方法把面板加入到窗体中。
*/
}
/**
* 图片的x y坐标放入到数组中,然后要输入x y坐标时调用对应下标的数值即有,+配合for循环语句来打印图片,此过程即为蛇的数据结构
*/
//建立初始化snake的方法 (刷新蛇的图片,让其产生移动的效果)
public void initSnake() { //init :初始化
len =3; //蛇开始长度是3
/**
* 蛇头的坐标是100x100,把存在数组的下标为0(x/y数组的下标都为0)
*/
snakex[0]=100;
snakey[0]=100; //把蛇头的位置坐标存到数组中,且下标为0
snakex[1]=75;
snakey[1]=100;
snakex[2]=50;
snakey[2]=100;
//设置食物的x y坐标位置
/**
* 用nextInt()生成随机数,然后给food坐标用上。 范围是25*(0-33)
*/
foodx = 25 +25*random.nextInt(34); //25 +... 的意思是 食物出现当后面的数是0时,就出现在第一个格子
foody = 75 +25*random.nextInt(24); //然后画出来 在paintComponent方法中画出来
//设置分数
score = 0; //让重新开始时,分数不会再继续。
}
@Override
public void keyTyped(KeyEvent e) { //当键敲了
}
@Override //响应键盘事件
public void keyPressed(KeyEvent e) { //当键敲到底了
//KeyEvent :指的是敲了哪个键,设置int类型的变量进行接受
/**
* 使用getKeyCode()方法来获取到敲击了哪个按键 (每一个按键都对应一个数字)
*/
int keycode = e.getKeyCode(); //能够知道敲击了哪个键盘
if ( keycode == KeyEvent.VK_SPACE ){ //keycode等于空格键就是isStarted的值改变为true
//重新开始(响应键盘事件)
if(isFailed) {
isFailed = false;
//格式化内容:即调用最开始的方法, 让蛇在一开始的地方重新开始
initSnake();
}
isStarted = !isStarted; //!isStarted是取反的意思 ,整体的意思就是值取反。
//再次画图片 :重画图片:repaint();
repaint(); //此即会重新调用方法
}else if (keycode == KeyEvent.VK_RIGHT) { //如果键盘按了向右的键盘
direction = "R";
}else if (keycode == KeyEvent.VK_LEFT) { //如果键盘按了向右的键盘
direction = "L";
}else if (keycode == KeyEvent.VK_UP) { //如果键盘按了向右的键盘
direction = "U";
}else if (keycode == KeyEvent.VK_DOWN) { //如果键盘按了向右的键盘
direction = "D"; //然后在actionPerformed中配合钟表来刷数据
}
}
@Override
public void keyReleased(KeyEvent e) { //当键敲完然后抬起来了
}
@Override
public void actionPerformed(ActionEvent e) { //时间到了就会调用这个方法
/**
* 时间到了就会调用此方法,然后在此内容结尾再次开启时钟,已达到不断循环的效果
*/
//到点了就重写
repaint();
//将图移动和空格键的内容连接起来
if (isStarted && !isFailed ) { //如果isStarted是true 且 !isFailed(且不是失败的)
/**
* 让蛇动起来 :先是头动,即让头的图像x,y发生移动。
*/
for (int i = len-1; i>0;i--) {
snakex[i] = snakex[i-1]; //蛇身体的x坐标移动
snakey[i] = snakey[i-1]; //蛇身体的y坐标移动
}
if (direction == "R") {
//direction = "R" 时执行的代码
snakex[0] =snakex[0]+25;
if (snakex[0] >850) snakex[0] = 25; //判断语句的简写形式
}else if (direction =="L") {
snakex[0] =snakex[0]-25;
if (snakex[0] <25) snakex[0] = 850; //判断语句的简写形式
}else if (direction =="U") {
snakey[0] =snakey[0]-25;
if (snakey[0] <75) snakey[0] = 650; //判断语句的简写形式
}else if (direction =="D") {
snakey[0] =snakey[0]+25;
if (snakex[0] >650) snakex[0] = 75; //判断语句的简写形式
}
//吃掉食物
/**
* 判断食物的x、y坐标是否为头的x、y坐标是否重合
*/
if (snakex[0] == foodx && snakey[0]==foody) {
len++; //头的图片和食物图片重合就长度+1 ---这样长度+1,身体就会变成。
//长度增加后,分数也会增加 (然后把分数显示出来,把它画出来:实质是打印字符一样打印出来即可)
score = score +10;
//然后重新刷新图片
foodx = 25 +25*random.nextInt(34); //25 +... 的意思是 食物出现当后面的数是0时,就出现在第一个格子
foody = 75 +25*random.nextInt(24); //然后画出来 在paintComponent方法中画出来
}
//判断头是否和身体重合,如果是则 (用for语句来循环输出len的值/数组的值,然后判断是否有重合现象)
for (int i = 1;i<len ;i++) {
if (snakex[i]==snakex[0] && snakey[i]==snakey[0]) {
//如果是重合的,那就有isFailed 变为true,让移动程序不再运行
isFailed = true;
}
}
}
//重写
repaint();
//然后还有让时钟再次开始
timer.start();
}
}
package moonsnake;
import java.awt.Color;
import javax.swing.JFrame;
/**
*
*
*画出窗体 :900x720
*
*/
/**
* 看着有颜色,实质上是面板中的颜色,而是窗体中的颜色。
*
*/
public class Msnake {
public static void main(String[] args) {
/**
* 窗体类关键字为:JFrame
* 作用就是会有一个游戏面板一样的东西会出现在屏幕上,只要这个窗体是有颜色的话。
*/
//画出窗体类
JFrame frame = new JFrame(); //new一个窗体类对象
//调用jframe的Bounds方法来设置窗体的大小和距离和距离屏幕的位置
frame.setBounds(10,10,900,700);
//用Resizable方法来设置面板不可拖动
frame.setResizable(false);
//用setDeafaultCloseOperation方法来关闭游戏界面
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
/**
* 用add方法把面板类加入到窗体中
*/
frame.add(new MPanel());
//用Visible方法来使窗体展现出来
frame.setVisible(true);
/**
* 做完这些的结果就是有一个900x720的白色的距离左上屏幕10,10距离的窗体。
*/
}
}
链接:百度网盘获得“代码”和“游戏图片”