源码素材包,需要提取码加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();
}
}
}
}