超级玛丽小游戏(Java)

源码素材包,需要提取码加VX:17347064818

百度网盘 请输入提取码

目录

第一关界面

第二关界面 

第三关界面

背景类

敌人类

马里奥类

音乐类

窗口类,游戏主界面实现 

障碍物类

常量类

主界面实现 


第一关界面

第二关界面 

第三关界面

背景类

import java.awt.*;
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 List<Obstacle>obstacleList = new ArrayList<>();

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

    public void setEnemyList(List<Enemy> enemyList) {
        this.enemyList = enemyList;
    }

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

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

    //判断玛丽奥是否到达旗杆位置
    private boolean isReach = false;

    //判断旗帜是否落地
    private boolean isBase = false;

    public BackGround(){

    }

    //构造类,构造各关卡
    public BackGround(int sort,boolean flag){
        this.sort = sort;
        this.flag = flag;
        if(flag){
            bgImage = StaticValue.bg2;
        }else{
            bgImage = StaticValue.bg;
        }

        //判断是否是第一关,有关坐标见PPT
        if(sort == 1){
            //绘制第一关的地面,上地面type=1,下地面type=2
            //通过for循环来绘制,窗口的横坐标为800,每个地面图片为30,所以循环27次
            for(int i = 0;i < 27; i++){
                obstacleList.add(new Obstacle(i * 30,420,1,this));
            }
            for(int j = 0;j <= 120;j += 30){
                for(int i = 0;i < 27;i ++){
                    obstacleList.add(new Obstacle(i * 30,570 - j,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));
                }
            }

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

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

        //判断是否是第二关
        if(sort == 2){
            //第二关的地面跟第一关的地面一样,直接复制过来
            //绘制第二关的地面,上地面type=1,下地面type=2
            //通过for循环来绘制,窗口的横坐标为800,每个地面图片为30,所以循环27次
            for(int i = 0;i < 27; i++){
                obstacleList.add(new Obstacle(i * 30,420,1,this));
            }
            for(int j = 0;j <= 120;j += 30){
                for(int i = 0;i < 27;i ++){
                    obstacleList.add(new Obstacle(i * 30,570 - j,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));
            }

            //绘制第二关的第一个食人花敌人
            enemyList.add(new Enemy(75,420,2,true,this,328,418));

            //绘制第二关的第二个食人花敌人
            enemyList.add(new Enemy(635,420,2,true,this,298,388));

            //绘制第二关的第一个蘑菇敌人
            enemyList.add(new Enemy(200,385,1,true,this));

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

        //判断是否是第三关
        if(sort == 3){
            //绘制地面,同上
            for(int i = 0;i < 27; i++){
                obstacleList.add(new Obstacle(i * 30,420,1,this));
            }
            for(int j = 0;j <= 120;j += 30){
                for(int i = 0;i < 27;i ++){
                    obstacleList.add(new Obstacle(i * 30,570 - j,2,this));
                }
            }

            //绘制第三个背景的A-O砖块
            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));

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

    public BufferedImage getBgImage() {
        return bgImage;
    }

    public int getSort() {
        return sort;
    }

    public boolean isFlag() {
        return flag;
    }

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

    public BufferedImage getGan() {
        return gan;
    }

    public BufferedImage getTower() {
        return tower;
    }

    public boolean isReach() {
        return isReach;
    }

    public void setReach(boolean reach) {
        isReach = reach;
    }

    public boolean isBase() {
        return isBase;
    }

    public void setBase(boolean base) {
        isBase = base;
    }

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

敌人类

import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;

//敌人类
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;

    //定义线程对象,实现食人花敌人和蘑菇敌人的运动
    Thread thread = new Thread(this);

    //定义当前图片的状态
    private int image_type = 0;

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

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

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

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public BufferedImage getShow() {
        return show;
    }

    public int getType() {
        return type;
    }

    @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 canLeft = 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)){
                    canLeft = false;
                }
            }

            //判断蘑菇敌人是否是向左走,并且碰到方向则改变方向
            if(face_to && !canLeft || 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);
            }
            //线程休眠50毫秒,意思就是让食人花敌人停止运动50毫秒后继续运动
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

马里奥类

import java.awt.image.BufferedImage;

//玛丽奥类
public class Mario implements Runnable{
    //用于表示横纵坐标
    private int x;
    private int y;

    //用于表示当前的状态
    private String status;

    //用于显示当前状态对应的图像
    private BufferedImage show = null;

    //定义一个Background对象,用来获取障碍物的信息
    private BackGround backGround = new BackGround();

    //用来实现玛丽奥的动作
    private Thread thread = null;

    //玛丽奥的移动速度
    private int xSpeed;

    //玛丽奥的跳跃速度
    private int ySpeed;

    //定义一个索引
    private int index;

    //表示玛丽奥跳跃上升的时间
    private int upTime = 0;

    //用于判断玛丽奥是否走到了城堡的位置
    private boolean isOk;

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

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

    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();
    }

    //创建玛丽奥死亡的方法
    public void death(){
        isDeath = true;
    }

    //玛丽奥向左移动
    public void leftMove(){
        //改变速度
        xSpeed = -5;

        //判断玛丽奥是否碰到了旗帜
        if(backGround.isReach()){
            xSpeed = 0;
        }

        //判断玛丽奥是否处于空中
        if(status.indexOf("jump") != -1){
            status = "jump--left";
        }else{
            status = "move--left";
        }
    }

    //玛丽奥向右移动
    public void rightMove(){
        //改变速度
        xSpeed = 5;

        //判断玛丽奥是否碰到了旗帜
        if(backGround.isReach()){
            xSpeed = 0;
        }

        //判断玛丽奥是否处于空中
        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";
        }
    }

    //玛丽奥跳跃
    public void jump(){
        //判断是否是跳跃状态
        if(status.indexOf("jump") == -1){
            //判断玛丽奥的方向是哪里
            if(status.indexOf("left") != -1){//向左跳跃
                status = "jump--left";
            }else{//向右跳跃
                status = "jump--right";
            }
            //改变垂直速度,下落时y轴减少
            ySpeed = -10;
            upTime = 7;
        }
        //判断玛丽奥是否碰到了旗帜
        if(backGround.isReach()){
            ySpeed = 0;
        }
    }
    //玛丽奥下落
    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;

            //判断是否可以往右走
            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);
                            //顶到砖块加1分
                            score += 1;
                        }
                        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;
                    }
                }

                //判断玛丽奥是否碰到敌人死亡或者踩死蘑菇敌人
                for(int i = 0;i < backGround.getEnemyList().size(); i++){
                    Enemy e = backGround.getEnemyList().get(i);

                    //判断玛丽奥此时是否踩在敌人头上
                    if(e.getY() == this.y + 20 && (e.getX() - 25 < this.x && e.getX() + 35 >= this.x)){
                        //判断是蘑菇敌人还是食人花敌人,只有蘑菇敌人才能被踩死
                        if(e.getType() == 1){
                            //调用蘑菇敌人的死亡方法实现踩死蘑菇敌人
                            e.death();

                            //踩死敌人加2分
                            score += 2;

                            //玛丽奥上升一小段
                            upTime = 3;
                            ySpeed = -10;
                        }else if(e.getType() == 2){//食人花敌人的情况
                            //玛丽奥死亡
                            death();
                        }
                    }

                    //判断玛丽奥是否碰到敌人,碰到敌人也会死亡
                    if((e.getX() + 35 > this.x && e.getX() - 25 < this.x) && (e.getY() + 35 > this.y && e.getY() - 20 < this.y)){
                        //玛丽奥死亡
                        death();
                    }
                }

                //进行玛丽奥跳跃的操作
                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 {//不等于0时处于最高点
                        fall();//下落
                    }
                    y += ySpeed;
                }
            }
            if((canLeft && xSpeed < 0) || (canRight && 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;
            }
            //判断是否向左跳跃
            if("jump--left".equals(status)){
                show = StaticValue.jump_L;
            }
            //判断是否向右跳跃
            if("jump--right".equals(status)){
                show = StaticValue.jump_R;
            }
            //让线程休眠50毫秒
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    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;
    }

    public void setBackGround(BackGround backGround) {
        this.backGround = backGround;
    }

    public boolean isOk() {
        return isOk;
    }

    public boolean isDeath() {
        return isDeath;
    }

    public int getScore() {
        return score;
    }
}

音乐类

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

import java.awt.image.BufferedImage;
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 name = new BufferedInputStream(new FileInputStream(str));
        player = new Player(name);
        player.play();
    }
}

窗口类,游戏主界面实现 

import javazoom.jl.decoder.JavaLayerException;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;

//创建窗口类,并且实现开始游戏
public class MyGame extends JFrame implements KeyListener,Runnable {
    /**
     * 实例化对象,运行玛丽奥游戏
     * 按”a“向左移动,按”d“向右移动,按”h“向上跳跃
     * 消除一个方块得1分,消灭一个敌人得2分,满分14分
     * @param args
     */
    public static void main(String[] args) {
        MyGame m = new MyGame();
    }
    //用于存储所有的背景
    private List<BackGround> allBg = new ArrayList<>();

    //用于存储当前的背景
    private BackGround nowBg = new BackGround();

    //用于双缓存
    private Image offScreenImage = null;

    //创建玛丽奥对象
    private Mario mario = new Mario();

    //定义一个线程对象,用于实现玛丽奥的移动
    private Thread thread = new Thread(this);

    //构造窗口属性
    public MyGame() {
        //设置窗口的大小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("欢迎进入超级玛丽小游戏");

        //初始化图片
        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);
        mario.setBackGround(nowBg);

        //绘制图像
        repaint();

        //启动线程
        thread.start();

        //播放音乐
        try {
            new Music();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (JavaLayerException e) {
            e.printStackTrace();
        }
    }

    @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);

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

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

        //绘制城堡
        graphics.drawImage(nowBg.getTower(),620,270,this);

        //绘制旗杆
        graphics.drawImage(nowBg.getGan(),500,220,this);

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

        //绘制分数
        Color c = graphics.getColor();
        //设置颜色为黑色
        graphics.setColor(Color.BLACK);
        //设置字体为黑体加粗,字体大小为25
        graphics.setFont(new Font("黑体", Font.BOLD,25));
        graphics.drawString("当前的分数为: "+mario.getScore(),300,100);
        graphics.setColor(c);

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

    @Override
    public void keyTyped(KeyEvent e) {

    }

    //当键盘按下键盘时调用
    @Override
    public void keyPressed(KeyEvent e) {
        //向右移动按“d”
        if(e.getKeyChar() == 100){
            mario.rightMove();
        }
        //向左移动按“a“
        if(e.getKeyChar() == 97){
            mario.leftMove();
        }
        //跳跃按”h“
        if(e.getKeyChar() == 104){
            mario.jump();
        }
    }

    @Override
    //当松开按键时触发该方法
    public void keyReleased(KeyEvent e) {
        //向左停止
        if(e.getKeyChar() == 97){
            mario.leftStop();
        }
        //向右停止
        if(e.getKeyChar() == 100){
            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);
                }

                //判断玛丽奥是否死亡
                if(mario.isDeath()){
                    JOptionPane.showMessageDialog(this,"玛丽奥死亡游戏结束!");
                    //停止JVM虚拟机运行
                    System.exit(0);
                }

                //判断游戏是否结束
                if(mario.isOk()){
                    JOptionPane.showMessageDialog(this,"恭喜你成功通关!");
                    //停止JVM虚拟机运行
                    System.exit(0);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

障碍物类

import java.awt.image.BufferedImage;

//障碍物类
public class Obstacle implements Runnable{
    //用于表示坐标
    private int x;
    private int y;

    //用于记录障碍物类型
    private int type;

    //用于显示图像
    private BufferedImage show = null;

    //定义当前的场景对象
    private BackGround bg = null;

    //定义一个线程对象,实现旗帜下落的过程
    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.obstcle.get(type);
        //如果是旗帜的话,启动线程
        if(type == 8){
            thread.start();
        }
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public int getType() {
        return type;
    }

    public BufferedImage getShow() {
        return show;
    }

    @Override
    public void run() {
        while(true){
            //为false则到达旗杆位置
            if(this.bg.isReach()){
                //判断旗杆是否到达地上
                if(this.y < 374){
                    this.y += 5;
                }else{//旗帜成功落地
                    this.bg.setBase(true);
                }
            }
            //线程休眠50毫秒
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

常量类

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

//常量类
public class StaticValue {
    //背景
    public static BufferedImage bg = 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> obstcle = 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 {
            //加载背景图片
            bg = ImageIO.read(new File(path + "bg.png"));
            bg2 = ImageIO.read(new File(path+"bg2.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"));
            //加载玛丽奥向左站立
            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"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        //玛丽奥向左跑
        for(int i = 1;i <= 2; i++){
            try {
                run_L.add(ImageIO.read(new File(path+"s_mario_run"+i+"_L.png")));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //玛丽奥向右跑
        for(int i = 1;i <= 2; i++){
            try {
                run_R.add(ImageIO.read(new File(path+"s_mario_run"+i+"_R.png")));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //加载障碍物
        try {
            obstcle.add(ImageIO.read(new File(path+"brick.png")));
            obstcle.add(ImageIO.read(new File(path+"soil_up.png")));
            obstcle.add(ImageIO.read(new File(path+"soil_base.png")));
        } catch (IOException e) {
            e.printStackTrace();
        }
        //加载水管
        for (int i = 1; i <= 4; i++) {
            try {
                obstcle.add(ImageIO.read(new File(path+"pipe"+i+".png")));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //加载不可破坏的砖块和旗子
        try {
            obstcle.add(ImageIO.read(new File(path+"brick2.png")));
            obstcle.add(ImageIO.read(new File(path+"flag.png")));
        } catch (IOException e) {
            e.printStackTrace();
        }
        //加载蘑菇敌人
        for(int i = 1;i <= 3; i++){
            try {
                mogu.add(ImageIO.read(new File(path+"fungus"+i+".png")));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //加载食人花敌人
        for(int i = 1;i <= 2; i++){
            try {
                flower.add(ImageIO.read(new File(path+"flower1."+i+".png")));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

主界面实现 

import javazoom.jl.decoder.JavaLayerException;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;

//创建窗口类,并且实现开始游戏
public class MyGame extends JFrame implements KeyListener,Runnable {
    /**
     * 实例化对象,运行玛丽奥游戏
     * 按”a“向左移动,按”d“向右移动,按”h“向上跳跃
     * 消除一个方块得1分,消灭一个敌人得2分,满分14分
     * @param args
     */
    public static void main(String[] args) {
        MyGame m = new MyGame();
    }
    //用于存储所有的背景
    private List<BackGround> allBg = new ArrayList<>();

    //用于存储当前的背景
    private BackGround nowBg = new BackGround();

    //用于双缓存
    private Image offScreenImage = null;

    //创建玛丽奥对象
    private Mario mario = new Mario();

    //定义一个线程对象,用于实现玛丽奥的移动
    private Thread thread = new Thread(this);

    //构造窗口属性
    public MyGame() {
        //设置窗口的大小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("欢迎进入超级玛丽小游戏");

        //初始化图片
        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);
        mario.setBackGround(nowBg);

        //绘制图像
        repaint();

        //启动线程
        thread.start();

        //播放音乐
        try {
            new Music();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (JavaLayerException e) {
            e.printStackTrace();
        }
    }

    @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);

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

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

        //绘制城堡
        graphics.drawImage(nowBg.getTower(),620,270,this);

        //绘制旗杆
        graphics.drawImage(nowBg.getGan(),500,220,this);

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

        //绘制分数
        Color c = graphics.getColor();
        //设置颜色为黑色
        graphics.setColor(Color.BLACK);
        //设置字体为黑体加粗,字体大小为25
        graphics.setFont(new Font("黑体", Font.BOLD,25));
        graphics.drawString("当前的分数为: "+mario.getScore(),300,100);
        graphics.setColor(c);

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

    @Override
    public void keyTyped(KeyEvent e) {

    }

    //当键盘按下键盘时调用
    @Override
    public void keyPressed(KeyEvent e) {
        //向右移动按“d”
        if(e.getKeyChar() == 100){
            mario.rightMove();
        }
        //向左移动按“a“
        if(e.getKeyChar() == 97){
            mario.leftMove();
        }
        //跳跃按”h“
        if(e.getKeyChar() == 104){
            mario.jump();
        }
    }

    @Override
    //当松开按键时触发该方法
    public void keyReleased(KeyEvent e) {
        //向左停止
        if(e.getKeyChar() == 97){
            mario.leftStop();
        }
        //向右停止
        if(e.getKeyChar() == 100){
            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);
                }

                //判断玛丽奥是否死亡
                if(mario.isDeath()){
                    JOptionPane.showMessageDialog(this,"玛丽奥死亡游戏结束!");
                    //停止JVM虚拟机运行
                    System.exit(0);
                }

                //判断游戏是否结束
                if(mario.isOk()){
                    JOptionPane.showMessageDialog(this,"恭喜你成功通关!");
                    //停止JVM虚拟机运行
                    System.exit(0);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_54702911/article/details/121454180