目录
创建一个MainFrame类继承JFrame,表示主窗体。
- public class MainFrame extends JFrame {
- //创建窗体对象时,初始化船体参数
- public MainFrame(){
- initFrame();
- }
- }
MainFrame类中写一个initFrame方法,初始化窗体参数
- //1.初始化窗体参数
- private void initFrame() {
- //设置窗体标题
- setTitle("黑马贪吃蛇");
- //设置窗体大小
- setSize(610, 640);
- //设置窗体位置
- setLocation(400, 400);
- //设置窗体大小不能改变
- setResizable(false);
- //设置窗体关闭按钮的作用,是正常退出
- setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- }
在MainFrame中添加一个main方法,创建窗体并运行,就可以看到窗体了
- //主方法
- public static void main(String[] args) {
- //创建窗体,并显示在屏幕上
- new MainFrame().setVisible(true);
- }
在JFrame类中写一个initGamePanel方法,初始化游戏棋盘
- //初始化游戏面板
- private void initGamePanel() {
- JPanel jPanel = new JPanel() {
- //paint是用来绘制面板中的内容
- @Override
- public void paint(Graphics g) {
- //设置画笔颜色
- g.setColor(Color.black); //设置画笔颜色是黑色
- //绘制40条横线(起点横坐标,起点纵坐标,终点横坐标,终点纵坐标)
- for(int i=1;i<=40;i++){
- g.drawLine(0,15*i,600,15*i);
- }
-
- //绘制40条竖线
- for (int i=1;i<=40;i++){
- g.drawLine(15*i,0,15*i,600);
- }
- }
- };
- add(jPanel);
- }
创建一个Node类表示节点,一条蛇有若干个节点组成,每一个节点其实就是一个小方格,我们用行和列来定义节点在棋盘中的位置。
- public class Node {
- private int x; //横坐标
- private int y; //纵坐标
-
- public int getX() {
- return x;
- }
-
- public void setX(int x) {
- this.x = x;
- }
-
- public int getY() {
- return y;
- }
-
- public void setY(int y) {
- this.y = y;
- }
- }
创建Snake类表示蛇,一条蛇有多个节点使用LinkedList集合存储Node节点,蛇出生的时候 有3个节点。
- public class Snake {
- //body
- private LinkedList<Node> body;
-
- //创建蛇对象时,初始化蛇身
- public Snake() {
- initSnake();
- }
-
- //初始化蛇身 3个节点
- public void initSnake(){
- //创建蛇的躯体
- body=new LinkedList<>();
- //给蛇添加3个节点,在棋盘的中心位置横向排列
- body.add(new Node(20,20));
- body.add(new Node(21,20));
- body.add(new Node(22,20));
- }
-
- //获取蛇蛇身
- public LinkedList<Node> getBody(){
- return body;
- }
- }
把蛇绘制到棋盘上
在MainFrame中添加一个创建Snake的成员变量,表示窗体中有一条蛇
- public class MainFrame extends JFrame {
- //定义成员变量
- private Snake snake=new Snake();
- ....
- }
在绘制棋盘的paint方法中,添加下面的代码绘制把蛇绘制到棋盘上
- //绘制横线
- ...
- //绘制竖线
- ...
-
- //绘制蛇,根据每一个节点的坐标在棋盘上绘制矩形
- for (Node node : snake.getBody()) {
- //每一个节点的宽度和高度是15
- g.fillRect(node.getX()*15,node.getY()*15,15,15);
- }
再次运行,就可以看到有一条蛇静静的躺在棋盘中间了
定义一个枚举类型,表示运动的4个方向
- public enum Direction {
- UP,DOWN,LEFT,RIGHT
- }
在Snake类中定义一个移动方向的变量成员变量,和move方法。
- public class Snake{
- //蛇头运动的方向
- private Direction direction;
-
- //移动的方法: 每次移动在蛇头运动方向添加一个节点,再删除最后一个节点
- public void move(){
- //获取蛇头的节点
- Node head = body.getFirst();
- //新的蛇头节点
- Node newHead=null;
- //检查移动的方向
- switch (direction){
- //如果向左移动
- case LEFT:
- //创建一个新的蛇头节点
- newHead=new Node(head.getX()-1,head.getY());
- //把心得蛇头节点添加到body的第一个元素
- body.addFirst(newHead);
- //删除蛇尾
- body.removeLast();
- break;
- case RIGHT:
- //创建一个新的蛇头节点
- newHead=new Node(head.getX()-1,head.getY());
- //把心得蛇头节点添加到body的第一个元素
- body.addFirst(newHead);
- //删除蛇尾
- body.removeLast();
- break;
- case UP:
- //创建一个新的蛇头节点
- newHead=new Node(head.getX(),head.getY()-1);
- //把心得蛇头节点添加到body的第一个元素
- body.addFirst(newHead);
- //删除蛇尾
- body.removeLast();
- break;
- case DOWN:
- //创建一个新的蛇头节点
- newHead=new Node(head.getX(),head.getY()+1);
- //把心得蛇头节点添加到body的第一个元素
- body.addFirst(newHead);
- //删除蛇尾
- body.removeLast();
- break;
- }
- }
- }
在MainFrame类中,创建一个定时器每100毫秒,重绘游戏棋盘
- public class MainFrame extends JFrame {
- ...
- //游戏棋盘面板
- JPanel jPanel=null;
- //定义定时器
- private Timer timer;
-
- public MainFrame() throws HeadlessException {
- //初始化窗体参数
- initFrame();
- //初始化窗体中的游戏面板
- initGamePanel();
- //初始化定时器
- initTimer();
- }
-
- //2.初始化游戏棋盘
- private void initGamePanel() {
- jPanel = new JPanel() {
- //paint是用来绘制面板中的内容
- @Override
- public void paint(Graphics g) {
- //每次重绘时清空面板中的内容
- g.clearRect(0,0,getWidth(),getHeight());
- ....
- }
- };
- add(jPanel);
- }
-
- //3.初始化定时器
- private void initTimer() {
- TimerTask task=new TimerTask() {
- @Override
- public void run() {
- //调用蛇移动的方法
- snake.move();
- //每次移动重绘游戏棋盘,会自动调用jPanel的paint方法
- jPanel.repaint();
- }
- };
- timer=new Timer();
- timer.scheduleAtFixedRate(task,0,100);
- }
- }
在MainFrame类中,添加一个setKeyListener的方法,监听上下左右四个键
- public class MainFrame extends JFrame {
- ...
- public MainFrame() throws HeadlessException {
- ...
- //添加键盘监听
- setkeyListener();
- }
-
- //添加键盘监听
- private void setkeyListener() {
- //对上下左右键进行监听
- addKeyListener(new KeyAdapter() {
- @Override
- public void keyPressed(KeyEvent e) {
- switch (e.getKeyCode()){
- //按下上键
- case KeyEvent.VK_UP:
- //蛇头方向改为上
- snake.setDirection(Direction.UP);
- break;
- //按下下键
- case KeyEvent.VK_DOWN:
- //蛇头方向改为下
- snake.setDirection(Direction.DOWN);
- break;
- //按下左键
- case KeyEvent.VK_LEFT:
- //蛇头方向改为左
- snake.setDirection(Direction.LEFT);
- break;
- //按下右键
- case KeyEvent.VK_RIGHT:
- //蛇头方向改为右
- snake.setDirection(Direction.RIGHT);
- break;
- }
- }
- });
- }
- }
到此蛇就可以跟随键盘移动了
当蛇移动到边界处就游戏结束,把标记改为false
- public class Snake{
- ...
- //定义一个标记true表示蛇是活的,可以运动
- private boolean isLive=true;
-
- //检查蛇是否碰壁
- private void checkOver() {
- //获取蛇头
- Node head = body.getFirst();
- int x=head.getX();
- int y=head.getY();
- if(x<0||y<0||x>=40||y>=40){
- isLive=false;
- }
- }
- }
在定时器中调用checkOver()方法
- //3.初始化定时器
- private void initTimer() {
- TimerTask task=new TimerTask() {
- @Override
- public void run() {
- //移动
- snake.move();
- //检查是否碰壁
- snake.checkOver();
- }
- };
- timer=new Timer();
- timer.scheduleAtFixedRate(task,0,100);
- }
创建一个Food类表示食物,其实食物也是一个节点,所以让Food继承Node
- public class Food extends Node {
- //创建食物的时候,随机产生一个位置
- public Food() {
- reset();
- }
- //随产生位置
- public void reset(){
- //随机生成食物的坐标
- Random r=new Random();
- setX(r.nextInt(40));
- setY(r.nextInt(40));
- }
- }
在MainFrame中定义一个成员Food表示食物,并把食物绘制到棋盘上
- public class MainFrame extends JFrame {
- //定义食物
- private Node food=new Node();
-
- public MainFrame() throws HeadlessException {
- //初始化窗体参数
- initFrame();
- //初始化窗体中的游戏面板
- initGamePanel();
- //初始化定时器
- initTimer();
- //添加键盘监听
- setkeyListener();
- }
-
- //2.初始化游戏棋盘
- private void initGamePanel() {
- jPanel = new JPanel() {
- //paint是用来绘制面板中的内容
- @Override
- public void paint(Graphics g) {
- //清空棋盘
- g.clearRect(0,0,600,600);
-
- //绘制横线、绘制竖线、绘制蛇
-
- //绘制食物
- g.fillRect(food.getX()*15,food.getY()*15,15,15);
- }
- };
- add(jPanel);
- }
- }
在Snake类中添加一个eatFood方法
- //吃食物
- public void eatFood() {
- //获取蛇头
- Node head = body.getFirst();
- //如果蛇头和食物的位置重合,就在蛇头添加一个元素
- if(head.getX()==MainFrame.food.getX()
- &&head.getY()==MainFrame.food.getY()){
- //沿着蛇头运动方向创建一个节点
- //新的蛇头节点
- Node newHead=null;
- //检查移动的方向
- switch (direction){
- //如果向左移动
- case LEFT:
- //创建一个新的蛇头节点
- newHead=new Node(head.getX()-1,head.getY());
- //把心得蛇头节点添加到body的第一个元素
- body.addFirst(newHead);
- break;
- case RIGHT:
- //创建一个新的蛇头节点
- newHead=new Node(head.getX()+1,head.getY());
- //把心得蛇头节点添加到body的第一个元素
- body.addFirst(newHead);
- break;
- case UP:
- //创建一个新的蛇头节点
- newHead=new Node(head.getX(),head.getY()-1);
- //把心得蛇头节点添加到body的第一个元素
- body.addFirst(newHead);
- break;
- case DOWN:
- //创建一个新的蛇头节点
- newHead=new Node(head.getX(),head.getY()+1);
- //把心得蛇头节点添加到body的第一个元素
- body.addFirst(newHead);
- break;
- }
- //每次吃完食物,让食物重置
- MainFrame.food.reset();
- }
- }
在定时器中调用吃食物的方法
- //2.初始化游戏棋盘
- private void initGamePanel() {
- jPanel = new JPanel() {
- //paint是用来绘制面板中的内容
- @Override
- public void paint(Graphics g) {
- //清空棋盘
- g.clearRect(0,0,600,600);
-
- //绘制横线、绘制竖线、绘制蛇
-
- //绘制食物
- g.fillRect(food.getX()*15,food.getY()*15,15,15);
- }
- };
- add(jPanel);
- }