Java实现超级玛丽,老程序员的国庆假期泡汤了!

Posted 编程界明世隐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java实现超级玛丽,老程序员的国庆假期泡汤了!相关的知识,希望对你有一定的参考价值。

作者简介

作者名:编程界明世隐
简介:CSDN博客专家,从事软件开发多年,精通Java、javascript,博主也是从零开始一步步把学习成长、深知学习和积累的重要性,喜欢跟广大ADC一起打野升级,欢迎您关注,期待与您一起学习、成长、起飞!

超级玛丽

系列目录

1. Java俄罗斯方块
2. Java五子棋小游戏
3. 老Java程序员花一天时间写了个飞机大战
4. Java植物大战僵尸
5. 老Java程序员花2天写了个连连看
6. Java消消乐(天天爱消除)
7. Java贪吃蛇小游戏
8. Java扫雷小游戏
9. Java坦克大战
10. Java迷宫小游戏

引言:

国庆前与群里的小伙伴们聊了一下,决定做一下超级玛丽这个游戏,毕竟以前也经常玩,网上找了一下资源,然后国庆就整起来了,果然程序员不配有假期,我的假期就这样泡汤了,超级玛丽你给我发工资。

实现思路

  1. 创建窗口。
  2. 创建加载所有图片的类。
  3. 创建场景,实例化场景。
  4. 创建障碍物,显示障碍物。
  5. 创建敌人,创建主线程,让敌人动起来。
  6. 创建马里奥,显示马里奥。
  7. 创建键盘事件。
  8. 马里奥的跳跃、左右移动、死亡等处理。
  9. 处理障碍物的消除,怪物的死亡等。
  10. 其他收尾处理(场景切换,背景音乐)。

代码实现

创建窗口

首先创建一个游戏窗体类GameFrame,继承至JFrame,用来显示在屏幕上(window的对象),每个游戏都有一个窗口,设置好窗口标题、尺寸、布局等就可以。

package main;

import javax.swing.JFrame;

/**
 *窗体类
 */
public class GameFrame extends JFrame {
	//构造方法
	public GameFrame(){
		setTitle("超级玛丽");//设置标题
		setSize(900, 600);//设置窗体大小
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭后进程退出
		setLocationRelativeTo(null);//居中
		setResizable(false);//不允许变大
	}
}

创建面板容器GamePanel继承至JPanel

package main;

import javax.swing.JPanel;

/**
 * 画布类
 */
public class GamePanel extends JPanel {
    private GameFrame mainFrame = null;
    private GamePanel panel = null;

  //构造里面初始化相关参数
  public GamePanel(GameFrame frame){
    this.setLayout(null);
    this.setOpaque(false);
    this.mainFrame=frame;
    this.panel =this;
  }
}

再创建一个Main类,来启动这个窗口,用来启动。

package main;

//Main类
public class Main {

	public static void main(String[] args) {
		GameFrame frame = new GameFrame();
		GamePanel panel = new GamePanel(frame);
		frame.add(panel);
		frame.setVisible(true);
	}
}

右键执行这个Main类,窗口建出来了

加载所有的图片

创建StaticValue类,用来加载图片,属性全部定义为static 类型,其中 init 方法,只需调用一次,然后加载好所有的图片,方便后面使用。

package main;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;

public class StaticValue {

  //存储马里奥的图片
  public static List<BufferedImage> allMarioImage = new ArrayList<BufferedImage>();
  //开始图片
  public static BufferedImage startImage = null;
  //结束图片
  public static BufferedImage endImage = null;
  //背景图片
  public static BufferedImage bgImage = null;
  //食人花图片
  public static List<BufferedImage> allFlowerImage = new ArrayList<BufferedImage>();
  //敌人图片
  public static List<BufferedImage> allTriangleImage = new ArrayList<BufferedImage>();
  //乌龟图片
  public static List<BufferedImage> allTurtleImage = new ArrayList<BufferedImage>();
  //障碍物图片
  public static List<BufferedImage> allObstructionImage = new ArrayList<BufferedImage>();
  //马里奥死亡图片
  public static BufferedImage mariDeadImage = null;
  //定义文件路径
  public static String ImagePath = "/image/";

  //将图片初始化
  public static void init() {

    String path = "";
    //玛丽奥图片初始化
    for (int i = 1; i <= 10; i++) {
      try {
        path = ImagePath + i + ".png";

        allMarioImage.add(ImageIO.read(StaticValue.class.getResource(path)));
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    //导入背景图片
    try {
      startImage = ImageIO.read(StaticValue.class.getResource(ImagePath + "start.jpg"));
      bgImage = ImageIO.read(StaticValue.class.getResource(ImagePath + "firststage.jpg"));
      endImage = ImageIO.read(StaticValue.class.getResource(ImagePath + "firststageend.jpg"));
    } catch (IOException e) {
      e.printStackTrace();
    }
    //导入敌人图片
    for (int i = 1; i <= 5; i++) {
      try {
        if (i <= 2) {
          allFlowerImage
              .add(ImageIO.read(StaticValue.class.getResource(ImagePath + "flower" + i + ".png")));
        }
        if (i <= 3) {
          allTriangleImage.add(
              ImageIO.read(StaticValue.class.getResource(ImagePath + "triangle" + i + ".png")));
        }
        allTurtleImage
            .add(ImageIO.read(StaticValue.class.getResource(ImagePath + "Turtle" + i + ".png")));
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
    //导入障碍物图片
    for (int i = 1; i <= 12; i++) {
      try {
        allObstructionImage
            .add(ImageIO.read(StaticValue.class.getResource(ImagePath + "ob" + i + ".png")));
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    //导入玛丽奥死亡图片
    try {
      mariDeadImage = ImageIO.read(StaticValue.class.getResource(ImagePath + "over.png"));
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

}

创建场景

创建场景的背景

有7个场景,前6个的背景图如下:

第7个背景图如下:

其实就是多了个旗杆和城堡,用来结束游戏的,这里在设置背景的时候有些区别,我们来定义BackGround类。

定义BackGround类

  1. sort代表场景的数字,比如第一个场景就是1。
  2. flag为true就是最后一个场景,所以最后一个场景的图片有点不一样。
package main;

import java.awt.image.BufferedImage;

public class BackGround {
  //当前场景图片
  private BufferedImage bgImage = null;
  //场景顺序
  private int sort;
  //是否为最后的场景
  private boolean flag;
  //游戏结束标记
  private boolean isOver = false;
  //定义降旗结束
  private boolean isDown = false;

  //构造方法
  public BackGround(int sort,boolean flag) {
    this.sort = sort;
    this.flag = flag;
    if (flag) {//最后一个场景
      bgImage = StaticValue.endImage;
    } else {//1-6场景
      bgImage = StaticValue.bgImage;
    }
  }
    //绘制
  public void draw(Graphics g) {
    g.drawImage(bgImage,0,0,null);
  }
}

实例化场景

  1. 在GamePanel类中加入相关成员
//存全部7个场景的集合
private List<BackGround> allBG = new ArrayList<BackGround>();
 //存当前场景
private BackGround nowBG = null;
  1. 在GamePanel类中加入init方法,此方法用来做游戏的全部初始化操作,比如 初始化图片、创建背景(包含障碍物、敌人等)、设置当前背景。
//初始化
private void init() {
  //图片初始化
  StaticValue.init();

  //创建全部场景
  for (int i = 1; i <= 7; i++) {
    //i==7?true:false  最后一个场景有点区别,有个结束的城堡
    this.allBG.add(new BackGround(i, i == 7 ? true : false));
  }
  //将第一个场景设置为当前场景
  this.nowBG = this.allBG.get(0);
}

在GamePanel中重写paint方法,并在此方法中绘制背景。

@Override
  public void paint(Graphics g) {
    super.paint(g);
    //绘制背景
    this.nowBG.draw(g);
  }

运行一下,背景被绘制到窗口上了。

创建障碍物类

package main;

import java.awt.Graphics;
import java.awt.image.BufferedImage;

public class Obstruction implements Runnable{
    //坐标
    private int x;
    private int y;

    //控制旗子
    private Thread t = new Thread(this);

    //类型
    private int type;
    //初始类型
    private int starttype;
    //显示图片
    private BufferedImage showImage = null;

    //取得场景
    private BackGround bg;

    //构造方法
    public Obstruction(int x,int y,int type,BackGround bg){
        this.x = x;
        this.y = y;
        this.type = type;
        this.starttype = type;
        this.bg = bg;
        setImage();
        if(this.type == 11){
            t.start();
        }
    }

    //绘制
    public void draw(Graphics g) {
        g.drawImage(showImage,x,y,null);
    }

    //重置方法
    public void reset(){
        this.type = starttype;
        this.setImage();
    }

    //根据状态改变显示图片
    public void setImage(){
        showImage = StaticValue.allObstructionImage.get(type);
    }

    public BufferedImage getShowImage() {
        return showImage;
    }
    public int getX() {
        return x;
    }
    public int getY() {
        return y;
    }
    public int getType() {
        return type;
    }
    public void setType(int type) {
        this.type = type;
    }

    public void run() {
        while(true){
            if(this.bg.isOver()){
                if(this.y < 420){
                    this.y += 5;
                }else{
                    this.bg.setDown(true);
                }
            }
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

障碍物介绍

总共有12种障碍物,图片如下:


修改BackGround类

加入绘制障碍物的方法,比如第一个场景的 buildBackGround1()

注意点:
比如:this.allObstruction.add(new Obstruction(i * 60, 540, 9, this));
这里传入的是9,但其实取得是第10个障碍物

因为我们在StaticValue存障碍物的集合allObstructionImage,集合是从0开始的,所以这里传入9等于取到的是第10个障碍物,其他的一样的意思。

package main;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;

public class BackGround {
  //当前场景图片
  private BufferedImage bgImage = null;
  //场景顺序
  private int sort;
  //是否为最后的场景
  private boolean flag;
  //游戏结束标记
  private boolean isOver = false;
  //定义降旗结束
  private boolean isDown = false;

  //用集合保存障碍物
  private List<Obstruction> allObstruction = new ArrayList<Obstruction>();
  //被消灭的障碍物
  private List<Obstruction> removeObstruction = new ArrayList<Obstruction>();

  //构造方法
  public BackGround(int sort,boolean flag) {
    this.sort = sort;
    this.flag = flag;
    if (flag) {//最后一个场景
      bgImage = StaticValue.endImage;
    } else {//1-6场景
      bgImage = StaticValue.bgImage;
    }

    //根据场景来配置对应的背景
    switch (sort){
      case 1:
        buildBackGround1();
        break;
      case 2:
        buildBackGround2();
        break;
      case 3:
        buildBackGround3();
        break;
      case 4:
        buildBackGround4();
        break;
      以上是关于Java实现超级玛丽,老程序员的国庆假期泡汤了!的主要内容,如果未能解决你的问题,请参考以下文章

程序员面试用Java写超级玛丽,直接上真本事面试官直接通过

ngMario —— 基于 AngularJS 实现的超级玛丽

超级玛丽游戏的开发过程

国庆假期,整整七天,我使用SpringBoot终于做出了即时通信!!!

国庆假期,整整七天,我使用SpringBoot终于做出了即时通信!!!

python实现超级玛丽小游戏(动图演示+源码分享)