java小游戏-超级玛丽

连接视频

1 创建窗口

创建MyFrame类

public class MyFrame extends JFrame implements KeyListener {

    public MyFrame(){
        //设置窗口大小 800*600
        this.setSize(800,600);
        //设置窗口居中显示
        this.setLocationRelativeTo(null);
        //设置窗口的可见性
        this.setVisible(true);
        //设置点击窗口上的关闭键,结束程序
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //设置窗口大小不可变
        this.setResizable(false);
        //向窗口对象添加键盘监听器
        this.addKeyListener(this);
        //设置窗口名称
        this.setTitle("超级玛丽");
    }

    public static void main(String[] args) {
        MyFrame myFrame = new MyFrame();
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {

    }

    @Override
    public void keyReleased(KeyEvent e) {

    }
}

2 创建并完成常量类

先导入相关图片在文件中

创建StaticValue类

public class StaticValue {
    //背景
    public static BufferedImage bg1 = null;
    public static BufferedImage bg2 = null;
    //马里奥向左跳跃
    public static BufferedImage jump_L = null;
    //马里奥向右跳跃
    public static BufferedImage jump_R = null;
    //马里奥向左站立
    public static BufferedImage stand_L = null;
    //马里奥向右站立
    public static BufferedImage stand_R = null;
    //城堡
    public static BufferedImage tower = null;
    //旗杆
    public static BufferedImage gan = null;

    //障碍物
    public static List<BufferedImage> obstacle = new ArrayList<>();
    //马里奥向左跑
    public static List<BufferedImage> run_L = new ArrayList<>();
    //马里奥向右跑
    public static List<BufferedImage> run_R = new ArrayList<>();
    //蘑菇敌人
    public static List<BufferedImage> mogu = new ArrayList<>();
    //食人花敌人
    public static List<BufferedImage> flower = new ArrayList<>();
    //路径的前缀,方便后续调用
    public static String path = System.getProperty("user.dir") + "/src/images/";

    //初始化方法
    public static void init() {

        try {
            //加载背景图片
            bg1 = ImageIO.read(new File(path + "bg.png"));
            bg2 = ImageIO.read(new File(path + "bg2.png"));
            //加载马里奥向左站立
            stand_L = ImageIO.read(new File(path + "s_mario_stand_L.png"));
            //加载马里奥向右站立
            stand_R = ImageIO.read(new File(path + "s_mario_stand_R.png"));
            //加载城堡
            tower = ImageIO.read(new File(path + "tower.png"));
            //加载旗杆
            gan = ImageIO.read(new File(path + "gan.png"));
            //加载马里奥向左跳跃
            jump_L = ImageIO.read(new File(path + "s_mario_jump1_L.png"));
            //加载马里奥向右跳跃
            jump_R = ImageIO.read(new File(path + "s_mario_jump1_R.png"));

            //加载马里奥向左跑
            for (int i = 1; i <= 2; i++) {
                run_L.add(ImageIO.read(new File(path + "s_mario_run" + i + "_L.png")));
            }

            //加载马里奥向右跑
            for (int i = 1; i <= 2; i++) {
                run_R.add(ImageIO.read(new File(path + "s_mario_run" + i + "_R.png")));
            }

            //加载障碍物
            obstacle.add(ImageIO.read(new File(path + "brick.png")));//普通砖块
            obstacle.add(ImageIO.read(new File(path + "soil_up.png")));//上地面
            obstacle.add(ImageIO.read(new File(path + "soil_base.png")));//下地面

            //加载水管
            for (int i = 1; i <= 4; i++) {
                obstacle.add(ImageIO.read(new File(path + "pipe" + i + ".png")));
            }

            //加载不可破坏的砖块和旗子
            obstacle.add(ImageIO.read(new File(path + "brick2.png")));//不可破坏的砖块
            obstacle.add(ImageIO.read(new File(path + "flag.png")));//旗子

            //加载蘑菇敌人
            for (int i = 1; i <= 3; i++) {
                mogu.add(ImageIO.read(new File(path + "fungus" + i + ".png")));
            }

            //加载食人花敌人
            for (int i = 1; i <= 2; i++) {
                flower.add(ImageIO.read(new File(path + "flower" + i + ".png")));
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在MyFrame类构造器中调用

public MyFrame(){
    ...
    this.setTitle("超级玛丽");

    //初始化图片
    StaticValue.init();
}

3 创建背景类

创建BackGround类

//背景类
public class BackGround {
    //当前场景需要显示的图像
    private BufferedImage bgImage = null;
    //记录当前是第几个场景
    private int sort;
    //判断是否是最后一个场景
    private boolean flag;

    public BackGround(){}

    public BackGround(int sort,boolean flag){
        this.sort = sort;
        this.flag = flag;

        if(flag){//最后一个场景
            bgImage = StaticValue.bg2;
        }else {
            bgImage = StaticValue.bg1;
        }
    }

    public BufferedImage getBgImage() { return bgImage; }
    public int getSort() { return sort; }
    public boolean isFlag() { return flag; }
}

4 绘制背景类

在MyFrame类添加背景类

//用于存储所有的背景
private List<BackGround> allBg = new ArrayList<>();
//用于存储当前的背景
private BackGround nowBg = new BackGround();
//用于双缓存
private Image offScreenImage = null;

public MyFrame(){
    ...

    //创建全部的场景
    for (int i = 1; i <= 3; i++) {
        allBg.add(new BackGround(i,i == 3 ? true : false));
    }
    //将第一个场景设置为当前场景
    nowBg = allBg.get(0);
    //绘制图像
    repaint();
}

@Override
public void paint(Graphics g) {
    if(offScreenImage == null){
        offScreenImage = createImage(800,600);
    }
    Graphics graphics = offScreenImage.getGraphics();
    graphics.fillRect(0,0,800,600);

    //绘制背景
    graphics.drawImage(nowBg.getBgImage(),0,0,this);

    //将图像绘制到窗口中
    g.drawImage(offScreenImage,0,0,this);
}

5 创建障碍物

创建Obstacle类

//障碍物类
public class Obstacle {
    //坐标
    private int x,y;
    //障碍物类型
    private int type;
    //显示图像
    private BufferedImage show = null;
    //定义当前的场景对象
    private BackGround bg = null;

    public Obstacle(int x, int y, int type, BackGround bg) {
        this.x = x;
        this.y = y;
        this.type = type;
        this.bg = bg;
        show = StaticValue.obstacle.get(type);
    }

    public int getX() { return x; }
    public int getY() { return y; }
    public int getType() { return type; }
    public BufferedImage getShow() { return show; }
}

在BackGround类中引用

//用于存放我们所有的障碍物
private List<Obstacle> obstacleList = new ArrayList<>();

6 第一关的设计

在BackGround类构造器中添加第一关判断

public BackGround(int sort,boolean flag){
    ...

    //判断是否是第一关
    if(sort == 1){
        //绘制第一关的地面,上地面是type=1,下地面type=2
        for (int i = 0; i < 27; i++) {
            obstacleList.add(new Obstacle(i*30,420,1,this));
        }

        for (int i = 0; i <= 120 ; i+=30) {
            for (int j = 0; j < 27 ; j++) {
                obstacleList.add(new Obstacle(j*30,570-i,2,this));
            }
        }

        //绘制砖块A
        for (int i = 120; i <= 150 ; i+=30) {
            obstacleList.add(new Obstacle(i,300,7,this));
        }

        //绘制砖块B-F
        for (int i = 300; i <= 570; i+=30) {
            if(i == 360 || i == 390 || i == 480 || i == 510 || i == 540){
                obstacleList.add(new Obstacle(i,300,7,this));
            }else {
                obstacleList.add(new Obstacle(i,300,0,this));
            }
        }

        //绘制砖块G
        for (int i = 420; i <= 450 ; i+=30) {
            obstacleList.add(new Obstacle(i,240,7,this));
        }

        //绘制水管
        for (int i = 360; i <= 600 ; i+=25) {
            if(i == 360){
                obstacleList.add(new Obstacle(620,i,3,this));
                obstacleList.add(new Obstacle(645,i,4,this));
            }else {
                obstacleList.add(new Obstacle(620,i,5,this));
                obstacleList.add(new Obstacle(645,i,6,this));
            }
        }
    }
}

public List<Obstacle> getObstacleList() { return obstacleList; }

在Obstacle类添加绘制

 @Override
public void paint(Graphics g) {
   ...

    //绘制障碍物
    for (Obstacle ob : nowBg.getObstacleList()){
        graphics.drawImage(ob.getShow(),ob.getX(),ob.getY(),this);
    }

    //将图像绘制到窗口中
    g.drawImage(offScreenImage,0,0,this);
}

7 第二关的设计

在BackGround类构造器中添加第二关判断

public BackGround(int sort,boolean flag){
   ...
    //判断是否第二关
    if(sort == 2){
        //绘制第二关的地面,上地面是type=1,下地面type=2
        for (int i = 0; i < 27; i++) {
            obstacleList.add(new Obstacle(i*30,420,1,this));
        }

        for (int i = 0; i <= 120 ; i+=30) {
            for (int j = 0; j < 27 ; j++) {
                obstacleList.add(new Obstacle(j*30,570-i,2,this));
            }
        }

        //绘制第一个水管
        for (int i = 360; i <= 600 ; i+=25) {
            if(i == 360){
                obstacleList.add(new Obstacle(60,i,3,this));
                obstacleList.add(new Obstacle(85,i,4,this));
            }else {
                obstacleList.add(new Obstacle(60,i,5,this));
                obstacleList.add(new Obstacle(85,i,6,this));
            }
        }

        //绘制第二个水管
        for (int i = 330; i <= 600 ; i+=25) {
            if(i == 330){
                obstacleList.add(new Obstacle(620,i,3,this));
                obstacleList.add(new Obstacle(645,i,4,this));
            }else {
                obstacleList.add(new Obstacle(620,i,5,this));
                obstacleList.add(new Obstacle(645,i,6,this));
            }
        }

        //绘制砖块C
        obstacleList.add(new Obstacle(300,330,0,this));

        //绘制砖块B/E/G
        for (int i = 270; i <= 330 ; i+=30) {
            if(i == 270 || i == 330){
                obstacleList.add(new Obstacle(i,360,0,this));
            }else {
                obstacleList.add(new Obstacle(i,360,7,this));
            }
        }

        //绘制砖块A/D/F/H/I
        for (int i = 240; i <= 360; i+=30) {
            if(i == 240 || i == 360){
                obstacleList.add(new Obstacle(i,390,0,this));
            }else {
                obstacleList.add(new Obstacle(i,390,7,this));
            }
        }

        //绘制妨碍1砖块
        obstacleList.add(new Obstacle(240,300,0,this));

        //绘制空1-4砖块
        for (int i = 360; i <= 540 ; i+=60) {
            obstacleList.add(new Obstacle(i,270,7,this));
        }
    }
}

8 第三关的设计

在BackGround类构造器中添加第三关判断

//用于显示旗杆
private BufferedImage gan = null;
//用于显示城堡
private BufferedImage tower = null;

public BackGround(int sort,boolean flag){
    ...
    //判断是否第三关
    if(sort == 3){
        //绘制第二关的地面,上地面是type=1,下地面type=2
        for (int i = 0; i < 27; i++) {
            obstacleList.add(new Obstacle(i*30,420,1,this));
        }

        for (int i = 0; i <= 120 ; i+=30) {
            for (int j = 0; j < 27 ; j++) {
                obstacleList.add(new Obstacle(j*30,570-i,2,this));
            }
        }

        //绘制第三个背景的A-0砖块
        int temp = 290;
        for (int i = 390; i >= 270 ; i-=30) {
            for (int j = temp; j <= 410 ; j+=30) {
                obstacleList.add(new Obstacle(j,i,7,this));
            }
            temp += 30;
        }

        //绘制第三个背景的P-R砖块
        temp = 60;
        for (int i = 390; i >= 360 ; i-=30) {
            for (int j = temp; j <= 90 ; j+=30) {
                obstacleList.add(new Obstacle(j,i,7,this));
            }
            temp += 30;
        }

        //绘制旗杆
        gan = StaticValue.gan;

        //绘制城堡
        tower = StaticValue.tower;

        //添加旗子到旗杆上
        obstacleList.add(new Obstacle(515,220,8,this));
    }
}

public BufferedImage getGan() { return gan; }
public BufferedImage getTower() { return tower; }

在Obstacle类添加绘制

@Override
    public void paint(Graphics g) {
        ...

        //绘制城堡
        graphics.drawImage(nowBg.getTower(),620,270,this);
        //绘制旗杆
        graphics.drawImage(nowBg.getGan(),500,220,this);

        //将图像绘制到窗口中
        g.drawImage(offScreenImage,0,0,this);
    }

9 创建马里奥类

创建Mario类

//马里奥类
public class Mario implements Runnable{
    //用于表示横纵坐标
    private int x,y;
    //用于表示当前的状态
    private String status;
    //用于显示当前状态对应的图像
    private BufferedImage show = null;
    //定义一个BackGround对象,用来获取障碍物的信息
    private BackGround backGround = new BackGround();
    //用来实现马里奥的动作
    private Thread thread = null;

    public Mario(){ }

    public Mario(int x,int y){
        this.x = x;
        this.y = y;
        show = StaticValue.stand_R;
        this.status = "stand_right";
        thread = new Thread(this);
        thread.start();
    }

    @Override
    public void run() {

    }

    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; }
    public BufferedImage getShow() { return show; }
    public void setShow(BufferedImage show) { this.show = show; }
}

在MyFrame类中绘制

//马里奥对象
private Mario mario = new Mario();

public MyFrame(){
    ...
    //初始化图片
    StaticValue.init();
    //初始化马里奥对象
    mario = new Mario(10,355);

    //创建全部的场景
    for (int i = 1; i <= 3; i++) {
        allBg.add(new BackGround(i,i == 3 ? true : false));
    }
    //将第一个场景设置为当前场景
    nowBg = allBg.get(0);
    //绘制图像
    repaint();
}

 @Override
public void paint(Graphics g) {
   ...
    //绘制旗杆
    graphics.drawImage(nowBg.getGan(),500,220,this);

    //绘制马里奥
    graphics.drawImage(mario.getShow(),mario.getX(),mario.getY(),this);

    //将图像绘制到窗口中
    g.drawImage(offScreenImage,0,0,this);
}

10 实现马里奥的移动

在Mario类添加移动参数

//马里奥的移动速度
private int xSpeed;
//马里奥的跳跃速度
private int ySpeed;
//定义一个索引
private int index;


//马里奥向左移动
public void leftMove(){
    //改变速度
    xSpeed = -5;
    //判断马里奥是否处于空中
    if(status.indexOf("jump") != -1){//处于空中
        status = "jump_left";
    }else{
        status = "move_left";
    }
}

//马里奥向右移动
public void rightMove(){
    //改变速度
    xSpeed = 5;
    //判断马里奥是否处于空中
    if(status.indexOf("jump") != -1){//处于空中
        status = "jump_right";
    }else{
        status = "move_right";
    }
}

//马里奥向左停止
public void leftStop(){
    //改变速度
    xSpeed = 0;
    //判断马里奥是否处于空中
    if(status.indexOf("jump") != -1){//处于空中
        status = "jump_left";
    }else{
        status = "stop_left";
    }
}

//马里奥向右停止
public void rightStop(){
    //改变速度
    xSpeed = 0;
    //判断马里奥是否处于空中
    if(status.indexOf("jump") != -1){//处于空中
        status = "jump_right";
    }else{
        status = "stop_right";
    }
}

@Override
public void run() {
    while (true){
        if(xSpeed < 0 || xSpeed > 0){
            x += xSpeed;
            //判断马里奥是否到了最左边
            if(x < 0){
                x = 0;
            }
        }
        //判断当前是否移动状态
        if(status.contains("move")){
            index = index == 0 ? 1 : 0;
        }
        //判断是否向左移动
        if("move_left".equals(status)){
            show = StaticValue.run_L.get(index);
        }
        //判断是否向右移动
        if("move_right".equals(status)){
            show = StaticValue.run_R.get(index);
        }
        //判断是否向左停止
        if("stop_left".equals(status)){
            show = StaticValue.stand_L;
        }
        //判断是否向右停止
        if("stop_right".equals(status)){
            show = StaticValue.stand_R;
        }

        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
    
public void setBackGround(BackGround backGround) { this.backGround = backGround; }

修改MyFrame类

public class MyFrame extends JFrame implements KeyListener,Runnable{

   ...
    //定义一个线程对象,用于实现马里奥的运动
    private Thread thread = new Thread(this);

    public MyFrame(){
      ...
        //将第一个场景设置为当前场景
        nowBg = allBg.get(0);
        mario.setBackGround(nowBg);
        //绘制图像
        repaint();
        thread.start();
    }

    ...

    //当键盘按下按键时调用
    @Override
    public void keyPressed(KeyEvent e) {
        //向右移动
        if(e.getKeyCode() == KeyEvent.VK_RIGHT){//→
            mario.rightMove();
        }
        //向左移动
        if(e.getKeyCode() == KeyEvent.VK_LEFT){//←
            mario.leftMove();
        }
    }

    //当键盘松开按键时调用
    @Override
    public void keyReleased(KeyEvent e) {
        //向左停止
        if(e.getKeyCode() == KeyEvent.VK_LEFT){//←
            mario.leftStop();
        }
        //向右停止
        if(e.getKeyCode() == KeyEvent.VK_RIGHT){//→
            mario.rightStop();
        }
    }

    @Override
    public void run() {
        while (true){
            //重新绘制图像
            repaint();
            try {
                Thread.sleep(50);
                if(mario.getX() >= 775){
                    nowBg = allBg.get(nowBg.getSort());
                    mario.setBackGround(nowBg);
                    mario.setX(10);
                    mario.setY(355);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}

11 实现马里奥的跳跃和下落

在Mario类添加跳跃和下落

//表示马里奥上升的时间
private int upTime = 0;

//马里奥跳跃
public void jump(){
    if(status.indexOf("jump") == -1){//不是调用状态
        if(status.indexOf("left") != -1){
            status = "jump_left";
        }else {
            status = "jump_right";
        }
        ySpeed = -10;
        upTime = 7;
    }
}

//马里奥下落
public void fall(){
    if(status.indexOf("left") != -1){
        status = "jump_left";
    }else {
        status = "jump_right";
    }
    ySpeed = 10;
}

@Override
public void run() {
    while (true){
    	//判断是否处于障碍物上
         boolean onObstacle = false;
         //遍历当前场景里所有障碍物
         for (int i = 0; i < backGround.getObstacleList().size(); i++) {
             Obstacle ob = backGround.getObstacleList().get(i);
             //判断马里奥是否位于障碍物上
             if(ob.getY() == this.y + 25 && (ob.getX() > this.x - 30 && ob.getX() < this.x + 25)){
                 onObstacle = true;
             }
         }

         //进行马里奥跳跃操作
         if(onObstacle && upTime == 0){
             if(status.indexOf("left") != -1){
                 if(xSpeed != 0){
                     status = "move_left";
                 }else {
                     status = "stop_left";
                 }
             }else {
                 if(xSpeed != 0){
                     status = "move_right";
                 }else {
                     status = "stop_right";
                 }
             }
         }else {
             //上升状态
             if(upTime != 0){
                 upTime--;
             }else {
                 fall();
             }
             y += ySpeed;
         }

         if(xSpeed < 0 || xSpeed > 0){
             x += xSpeed;
             //判断马里奥是否到了最左边
             if(x < 0){
                 x = 0;
             }
         }
        ...
        //判断是否向左跳跃
        if("jump_left".equals(status)){
            show = StaticValue.jump_L;
        }
        //判断是否向右跳跃
        if("jump_right".equals(status)){
            show = StaticValue.jump_R;
        }

        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在MyFrame类添加监听

//当键盘按下按键时调用
@Override
public void keyPressed(KeyEvent e) {
  ...
   //跳跃
   if(e.getKeyCode() == KeyEvent.VK_UP){//↑
       mario.jump();
   }
}

12 实现障碍物的阻挡

在Mario类run方法添加

@Override
public void run() {
   while (true){
       //判断是否处于障碍物上
       boolean onObstacle = false;
       //判断是否可以往右走
       boolean canRight = true;
       //判断是否可以往左走
       boolean canLeft = true;

       //遍历当前场景里所有障碍物
       for (int i = 0; i < backGround.getObstacleList().size(); i++) {
           Obstacle ob = backGround.getObstacleList().get(i);
           //判断马里奥是否位于障碍物上
           if(ob.getY() == this.y + 25 && (ob.getX() > this.x - 30 && ob.getX() < this.x + 25)){
               onObstacle = true;
           }

           //判断是否跳跃起来顶到砖块
           if((ob.getY() >= this.y - 30 && ob.getY() <= this.y -20)
               && (ob.getX() > this.x -30 && ob.getX() < this.x + 25)){
               if(ob.getType() == 0){
                   backGround.getObstacleList().remove(ob);
               }
               upTime = 0;
           }

           //判断是否可以往右走
           if(ob.getX() == this.x + 25 && (ob.getY() > this.y - 30 && ob.getY() < this.y + 25)){
               canRight = false;
           }
           //判断是否可以往左走
           if(ob.getX() == this.x - 30 && (ob.getY() > this.y - 30 && ob.getY() < this.y + 25)){
               canLeft = false;
           }
       }

      ...

       if((canLeft && xSpeed < 0) || (canRight && xSpeed > 0)){
           x += xSpeed;
           //判断马里奥是否到了最左边
           if(x < 0){
               x = 0;
           }
       }
   ...
   }
}

13 实现游戏结束

在Mario类修改run方法

//用于判断马里奥是否走到了城堡的门口
private boolean isOK;

//马里奥向左移动
public void leftMove(){
    //改变速度
    xSpeed = -5;
    //判断马里奥是否碰到了旗子
    if(backGround.isReach()){
        xSpeed = 0;
    }
    //判断马里奥是否处于空中
    if(status.indexOf("jump") != -1){//处于空中
        status = "jump_left";
    }else{
        status = "move_left";
    }
}

//马里奥跳跃
public void jump(){
    if(status.indexOf("jump") == -1){//不是调用状态
        if(status.indexOf("left") != -1){
            status = "jump_left";
        }else {
            status = "jump_right";
        }
        ySpeed = -10;
        upTime = 7;
    }
    //判断马里奥是否碰到了旗子
    if(backGround.isReach()){
        ySpeed = 0;
    }
}

//马里奥向左停止
public void leftStop(){
    //改变速度
    xSpeed = 0;
    //判断马里奥是否碰到了旗子
    if(backGround.isReach()){
        xSpeed = 0;
    }
    //判断马里奥是否处于空中
    if(status.indexOf("jump") != -1){//处于空中
        status = "jump_left";
    }else{
        status = "stop_left";
    }
}

@Override
public void run() {
    while (true){
        //判断是否处于障碍物上
        boolean onObstacle = false;
        //判断是否可以往右走
        boolean canRight = true;
        //判断是否可以往左走
        boolean canLeft = true;
        //判断马里奥是否到达旗杆位置
        if(backGround.isFlag() && this.x >= 500){
            this.backGround.setReach(true);
            //判断旗子是否下落完成
            if(this.backGround.isBase()){
                status = "move_right";
                if(x < 690){
                    x += 5;
                }else {
                    isOK = true;
                }
            }else {
                if(y < 395){
                    //在空中
                    xSpeed = 0;
                    this.y += 5;
                    status = "jump_right";
                }
                if (y > 395) {
                    this.y = 395;
                    status = "stop_right";
                }
            }
        }else {
            //遍历当前场景里所有障碍物
            for (int i = 0; i < backGround.getObstacleList().size(); i++) {
                Obstacle ob = backGround.getObstacleList().get(i);
                //判断马里奥是否位于障碍物上
                if(ob.getY() == this.y + 25 && (ob.getX() > this.x - 30 && ob.getX() < this.x + 25)){
                    onObstacle = true;
                }

                //判断是否跳跃起来顶到砖块
                if((ob.getY() >= this.y - 30 && ob.getY() <= this.y -20)
                        && (ob.getX() > this.x -30 && ob.getX() < this.x + 25)){
                    if(ob.getType() == 0){
                        backGround.getObstacleList().remove(ob);
                    }
                    upTime = 0;
                }

                //判断是否可以往右走
                if(ob.getX() == this.x + 25 && (ob.getY() > this.y - 30 && ob.getY() < this.y + 25)){
                    canRight = false;
                }
                //判断是否可以往左走
                if(ob.getX() == this.x - 30 && (ob.getY() > this.y - 30 && ob.getY() < this.y + 25)){
                    canLeft = false;
                }
            }

            //进行马里奥跳跃操作
            if(onObstacle && upTime == 0){
                if(status.indexOf("left") != -1){
                    if(xSpeed != 0){
                        status = "move_left";
                    }else {
                        status = "stop_left";
                    }
                }else {
                    if(xSpeed != 0){
                        status = "move_right";
                    }else {
                        status = "stop_right";
                    }
                }
            }else {
                //上升状态
                if(upTime != 0){
                    upTime--;
                }else {
                    fall();
                }
                y += ySpeed;
            }
        }

        if((canLeft && xSpeed < 0) || (canRight && xSpeed > 0)){
            x += xSpeed;
            //判断马里奥是否到了最左边
            if(x < 0){
                x = 0;
            }
        }
        ....
    }
}

public boolean isOK() { return isOK; }

在BackGround类添加参数

//判断马里奥是否到达旗杆位置
private boolean isReach = false;
//判断旗子是否落地
private boolean isBase = false;

public boolean isReach() { return isReach; }
public void setReach(boolean reach) { isReach = reach; }
public boolean isBase() { return isBase; }
public void setBase(boolean base) { isBase = base; }

在Obstacle类添加线程

public class Obstacle implements Runnable{
    ...
    //定义一个线程对象[旗子下落过程]
    private Thread thread = new Thread(this);

    public Obstacle(int x, int y, int type, BackGround bg) {
        this.x = x;
        this.y = y;
        this.type = type;
        this.bg = bg;
        show = StaticValue.obstacle.get(type);
        //如果是旗子的话,启动线程
        if(type == 8){
            thread.start();
        }
    }

 ..

    @Override
    public void run() {
        while (true){
            if(this.bg.isReach()){
                if (this.y < 374) {
                    this.y += 5;
                }else {
                    this.bg.setBase(true);
                }
            }

            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在MyFrame类添加通关提示

@Override
public void run() {
    while (true){
        //重新绘制图像
        repaint();
        try {
            Thread.sleep(50);
            if(mario.getX() >= 775){
                nowBg = allBg.get(nowBg.getSort());
                mario.setBackGround(nowBg);
                mario.setX(10);
                mario.setY(355);
            }
            //判断游戏是否结束
            if(mario.isOK()){
                //弹出提示
                JOptionPane.showMessageDialog(this,"恭喜你!成功通关了!");
                System.exit(0);
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

14 创建并完成敌人类

创建Enemy类

//敌人类
public class Enemy implements Runnable{
    //存储当前坐标
    private int x,y;
    //存储敌人类型
    private int type;
    //判断敌人运动方向
    private boolean face_to = true;
    //用于显示敌人的当前图像
    private BufferedImage show;
    //定义一个背景
    private BackGround bg;
    //食人花运动的极限范围
    private int max_up = 0;
    private int max_down = 0;
    //定义线程对象
    private Thread thread = new Thread(this);
    //定义当前的图片的状态
    private int image_type = 0;

    //蘑菇敌人的构造函数
    public Enemy(int x,int y,boolean face_to,int type,BackGround bg){
        this.x = x;
        this.y = y;
        this.face_to = face_to;
        this.type = type;
        this.bg = bg;
        show = StaticValue.mogu.get(0);
        thread.start();
    }

    //食人花敌人的构造函数
    public Enemy(int x,int y,boolean face_to,int type,int max_up,int max_down,BackGround bg){
        this.x = x;
        this.y = y;
        this.face_to = face_to;
        this.type = type;
        this.max_down = max_down;
        this.max_up = max_up;
        this.bg = bg;
        show = StaticValue.flower.get(0);
        thread.start();
    }

    //死亡方法
    public void death(){
        show = StaticValue.mogu.get(2);
        this.bg.getEnemyList().remove(this);
    }

    @Override
    public void run() {
        while (true){
            //判断是否是蘑菇敌人
            if(type == 1){
                if(face_to){
                    this.x -= 2;
                }else {
                    this.x += 2;
                }
                image_type = image_type == 1 ? 0 : 1;
                show = StaticValue.mogu.get(image_type);
            }

            //定义两个变量
            boolean calLeft = true;
            boolean canRight = true;

            for (int i = 0; i < bg.getObstacleList().size(); i++) {
                Obstacle ob1 = bg.getObstacleList().get(i);
                //判断是否可以向右走
                if(ob1.getX() == this.x + 36 && (ob1.getY() + 65 > this.y && ob1.getY() - 35 < this.y)){
                    canRight = false;
                }

                //判断是否可以向左走
                if(ob1.getX() == this.x - 36 && (ob1.getY() + 65 > this.y && ob1.getY() - 35 < this.y)){
                    calLeft = false;
                }
            }

            if(face_to && !calLeft || this.x == 0){
                face_to = false;
            }else if(!face_to && !canRight || this.x == 764){
                face_to = true;
            }

            //判断是否是食人花敌人
            if(type == 2){
                if(face_to){
                    this.y -= 2;
                }else {
                    this.y += 2;
                }
                image_type = image_type == 1 ? 0 : 1;
                //食人花是否到达极限位置
                if(face_to && (this.y == max_up)){//向上
                    face_to = false;
                }
                if(!face_to && (this.y == max_down)){//向下
                    face_to = true;
                }
                show = StaticValue.flower.get(image_type);
            }
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public int getX() { return x; }
public int getY() { return y; }
public BufferedImage getShow() { return show; }
public int getType() { return type; }

在BackGround类中引用

//用于存放我们所有的敌人
private List<Enemy> enemyList = new ArrayList<>();

public List<Enemy> getEnemyList() { return enemyList; }

15 向关卡中添加敌人

在BackGround类t添加敌人生成

public BackGround(int sort,boolean flag){
    ...

    //判断是否是第一关
    if(sort == 1){
       ...

        //绘制第一关的蘑菇敌人
        enemyList.add(new Enemy(580,385,true,1,this));
        //绘制第一关的食人花敌人
        enemyList.add(new Enemy(635,420,true,2,328,428,this));
    }

    //判断是否第二关
    if(sort == 2){
        ...

        //绘制第二关的第一个食人花敌人
        enemyList.add(new Enemy(75,420,true,2,328,418,this));
        //绘制第二关的第二个食人花敌人
        enemyList.add(new Enemy(635,420,true,2,298,388,this));
        //绘制第二关的第一个蘑菇敌人
        enemyList.add(new Enemy(200,385,true,1,this));
        //绘制第二关的第二个蘑菇敌人
        enemyList.add(new Enemy(500,385,true,1,this));

    }

    //判断是否第三关
    if(sort == 3){
        ...

        //添加旗子到旗杆上
        obstacleList.add(new Obstacle(515,220,8,this));

        //绘制第三关的第蘑菇敌人
        enemyList.add(new Enemy(150,385,true,1,this));
    }
}

在MyFramee类添加敌人绘制

@Override
public void paint(Graphics g) {
    ...

    //绘制背景
    graphics.drawImage(nowBg.getBgImage(),0,0,this);

    //绘制敌人
    for (Enemy e : nowBg.getEnemyList()) {
        graphics.drawImage(e.getShow(),e.getX(),e.getY(),this);
    }

    //绘制障碍物
    ...
}

16 完成马里奥杀死敌人和马里奥死亡

在Mario类添加判断

//用于判断马里奥是否死亡
private boolean isDeath = false;

//马里奥死亡方法
public void death(){
    isDeath = true;
}

@Override
public void run() {
    while (true){
        ...
        if(backGround.isFlag() && this.x >= 500){
           ...
        }else {
            //遍历当前场景里所有障碍物
            ...

            //判断马里奥是否碰到敌人死亡或者踩死蘑菇敌人
            for (Enemy enemy : backGround.getEnemyList()) {
                //判断马里奥是否位于敌人上方
                if(enemy.getY() == this.y + 20 && (enemy.getX() - 25 <= this.x && enemy.getX() + 35 >= this.x)){
                    if(enemy.getType() == 1){
                        enemy.death();
                        upTime = 3;
                        ySpeed = -10;
                    }else if(enemy.getType() == 2){
                        //马里奥死亡
                        death();
                    }
                }
                //碰到敌人
                if((enemy.getX() + 35 > this.x && enemy.getX() - 25 < this.x)
                    && (enemy.getY() + 35 > this.y && enemy.getY() - 20 < this.y)){
                    //马里奥死亡
                    death();
                }
            }

            //进行马里奥跳跃操作
           ...
    }
}

public boolean isDeath() { return isDeath; }

在MyFrame类添加马里奥死亡判断

@Override
public void run() {
    while (true){
        //重新绘制图像
        repaint();
        try {
            ...
            
            //判断马里奥是否死亡
            if(mario.isDeath()){
                JOptionPane.showMessageDialog(this,"马里奥死亡!!!");
                System.exit(0);
            }

           ....

    }
}

17 给游戏添加积分功能

在Mario类添加参数

//表示分数
private int score = 0;

@Override
public void run() {
    while (true){
        ...
        if(backGround.isFlag() && this.x >= 500){
            ...
        }else {
            //遍历当前场景里所有障碍物
            for (int i = 0; i < backGround.getObstacleList().size(); i++) {
                ...

                //判断是否跳跃起来顶到砖块
                if((ob.getY() >= this.y - 30 && ob.getY() <= this.y -20)
                        && (ob.getX() > this.x -30 && ob.getX() < this.x + 25)){
                    if(ob.getType() == 0){
                        backGround.getObstacleList().remove(ob);
                        score += 1;
                    }
                    upTime = 0;
                }

                ...
            }

            //判断马里奥是否碰到敌人死亡或者踩死蘑菇敌人
            for (Enemy enemy : backGround.getEnemyList()) {
                //判断马里奥是否位于敌人上方
                if(enemy.getY() == this.y + 20 && (enemy.getX() - 25 <= this.x && enemy.getX() + 35 >= this.x)){
                    if(enemy.getType() == 1){
                        enemy.death();
                        score += 2;
                        upTime = 3;
                        ySpeed = -10;
                    }else if(enemy.getType() == 2){
                        //马里奥死亡
                        death();
                    }
                }
                //碰到敌人
                if((enemy.getX() + 35 > this.x && enemy.getX() - 25 < this.x)
                    && (enemy.getY() + 35 > this.y && enemy.getY() - 20 < this.y)){
                    //马里奥死亡
                    death();
                }
            }

            ...
    }
}

public int getScore() { return score; }

在MyFrame类添加绘制分数

@Override
public void paint(Graphics g) {
    ...
    //绘制马里奥
    graphics.drawImage(mario.getShow(),mario.getX(),mario.getY(),this);

    //添加分数绘制
    Color c = graphics.getColor();
    graphics.setColor(Color.black);
    graphics.setFont(new Font("黑体",Font.BOLD,25));
    graphics.drawString("当前的分数为:" + mario.getScore(),300,100);

    graphics.setColor(c);

    //将图像绘制到窗口中
    g.drawImage(offScreenImage,0,0,this);
}

18 给游戏添加背景音乐

先导入jar 或者使用依赖

<dependency>
    <groupId>javazoom</groupId>
    <artifactId>jlayer</artifactId>
    <version>1.0.1</version>
</dependency>

创建Music类

import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.Player;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class Music {
    public Music() throws FileNotFoundException, JavaLayerException {
        Player player;
        String str = System.getProperty("user.dir") + "/src/music/music.wav";
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(str));
        player = new Player(bis);
        player.play();
    }
}

在MyFrame类添加

public MyFrame(){
   ...
    //绘制图像
    repaint();
    thread.start();

    try {
        new Music();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (JavaLayerException e) {
        e.printStackTrace();
    }
}
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值