B站教学视频:
01_超级玛丽_创建窗口_哔哩哔哩_bilibili
素材提取:
【超级会员V2】我通过百度网盘分享的文件:Java游戏项目…
链接:百度网盘 请输入提取码
提取码:k6j1
复制这段内容打开「百度网盘APP 即可获取」
百度网盘 请输入提取码
百度网盘为您提供文件的网络备份、同步和分享服务。空间大、速度快、安全稳固,支持教育网加速,支持手机端。注册使用百度网盘即可享受免费存储空间
百度网盘 请输入提取码
百度网盘为您提供文件的网络备份、同步和分享服务。空间大、速度快、安全稳固,支持教育网加速,支持手机端。注册使用百度网盘即可享受免费存储空间
游戏构造思路:
首先需要创建一个窗口,游戏需要在该窗口中运行,其次我们需要添加游戏中要用到的图片,将其添加到一个专属包中,并在类中实现。(有些物品一样或只用一次,如旗杆,城堡等,普通添加即可;有些如:玛丽,蘑菇敌人等,需要移动以及其他动作,故需要创建列表方便实现不同图片来回使用)。此外,我们还需要给游戏添加背景图,设定游戏的关卡数,以及不同关卡之间的切换。
在以上基础步骤之后,就需要在场景中添加游戏中最关键的两个角色:玛丽和敌人,这两个角色需要运动以及一系列其他操作,因此我们需要分两个类来写,并通过线程来调用。
以下代码中额外添加了一个休眠用来进行判定,在运行之后如果在较长时间(5秒左右)后按下空格键,则敌人类将不会再运动,同时,若在运行开始后,立即按下空格,敌人类会在经历一小段休眠后再进行运动(因为添加了休眠,故经过一小段休眠后才会进行判断)
以上休眠的添加是因为在添加暂停功能时本人无法实现暂停功能而写的一个妥协方案,欢迎各位大佬在评论区提出有关添加暂停功能的方法
代码实现:
MyFrame类:
package com.sxt;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;import static java.lang.Thread.sleep;//创建窗口需要继承JFrame类,
//添加键盘监听,需要该类实现KeyListener接口,并重写其中抽象方法
public class MyFrame extends JFrame implements KeyListener,Runnable {//用于储存所有的背景,定义一个列表用于存储背景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);static boolean isStart = false;//创建该类的空参构造public MyFrame() {//设置窗口大小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循环来创建for (int i = 1; i <= 3; i++) {//要传入两个参数:当前关卡数i和是否为最后一关的布尔变量//要用三目运算符进行判断,判断这时的i是否是第三关allBg.add(new BackGround(i, i == 3 ? true : false));}//将第一个背景设置为当前场景nowBg = allBg.get(0);mario.setBackGround(nowBg);//绘制图像repaint();//启动线程并调用start方法thread.start();//绘制图像开始时同步播放音乐try {new Music();} catch (FileNotFoundException e) {e.printStackTrace();} catch (JavaLayerException e) {e.printStackTrace();}}//重写一下paint方法@Overridepublic void paint(Graphics g) {//首先要判断,判断变量是否为nullif (offScreenImage == null) {offScreenImage = createImage(800, 600);}//定义Graphics(画笔)对象Graphics graphics = offScreenImage.getGraphics();//调用graphics的fillRect方法对我们的图像进行填充graphics.fillRect(0, 0, 800, 600);//绘制背景,调用graphics的drawImage方法,将当前背景图像进行绘画//此时是将图像绘制到了缓冲区上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);graphics.setFont(new Font("黑体", Font.BOLD, 25));graphics.drawString("当前分数为:" + mario.getScore(), 300, 100);if (isStart == false) {graphics.setFont(new Font("宋体", Font.BOLD, 25));graphics.drawString("按下空格开始游戏", 270, 160);}//还原画笔颜色graphics.setColor(c);//接下来将缓冲区的图片绘制到窗口中,调用g.drawImage方法g.drawImage(offScreenImage, 0, 0, this);}public static void main(String[] args) {MyFrame myFrame = new MyFrame();}@Overridepublic void keyTyped(KeyEvent e) {}//当键盘按下按键时调用@Overridepublic void keyPressed(KeyEvent e) {if (isStart == false) {if (e.getKeyCode() == 32) {isStart = true;}} else {//向右移动if (e.getKeyCode() == 39) {mario.rightMove();}//向左移动if (e.getKeyCode() == 37) {mario.leftMove();}//跳跃if (e.getKeyCode() == 38) {mario.jump();}}}//当键盘松开按键时调用@Overridepublic void keyReleased (KeyEvent e) {//向左停止if (isStart == true) {if (e.getKeyCode() == 37) {mario.leftStop();}//向右停止if (e.getKeyCode() == 39) {mario.rightStop();//接下来让MyFrame类来实现Runnable接口并且重写抽象方法}}}@Overridepublic void run () {//写一个死循环,在循环里调用repaint()方法,用于重新绘制我们的图像while (true) {repaint();//让线程休眠try {sleep(50);//判断此时马里奥是否移动到了最右端,是的话则要进行场景的切换//当前窗口大小为800,马里奥宽度为25if (mario.getX() >= 775) {//满足就要切换当前场景,在这里可以调用now的sort,他表示第几关,索引为1和2nowBg = allBg.get(nowBg.getSort());//将当前场景对象传递给马里奥类mario.setBackGround(nowBg);mario.setX(10);mario.setY(355);}//判断马里奥是否死亡if (mario.isDeath()) {JOptionPane.showMessageDialog(this, "马里奥死亡,游戏失败");System.exit(0);}//判断游戏是否结束,即判断mario的isOK是否为true,若true则游戏结束if (mario.isOK()) {JOptionPane.showMessageDialog(this, "恭喜你!通关了");System.exit(0);}} catch (InterruptedException e) {e.printStackTrace();}}}}
BackGround类:
package com.sxt;import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;public class BackGround {//当前场景要实现的图像,该对象用于显示当前场景的图片,赋初值为nullprivate BufferedImage bgImage=null; //在bgImage上设置getter方法//记录当前是第几个场景,储存当前是第几关private int sort;//判断是否是最后一个场景private boolean flag;//创建一个列表用于存放所有的障碍物private List<Obstacle>obstacleList=new ArrayList<>();//用于存放所有敌人private List<Enemy>enemyList=new ArrayList<>();//用于显示旗杆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; //第一关和第二关背景//下一步生成getter方法}//判断是否为第一关if (sort==1){//绘制第一关的地面,上地面type=1,下地面type=2,// 窗口横坐标为800,一个地面为30for (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));}}//绘制砖块Afor (int i=120;i<=150;i+=30){obstacleList.add(new Obstacle(i,300,7,this));//括号里是:横坐标,纵坐标,类型,this这个背景。}//绘制砖块B~~Ffor(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));}}//绘制砖块Gfor(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));//接下来实现Obstacle列表的getter方法}}//绘制第一关的蘑菇敌人enemyList.add(new Enemy(580,385,true,1,this));enemyList.add(new Enemy(300,385,true,1,this));enemyList.add(new Enemy(100,385,true,1,this));enemyList.add(new Enemy(400,385,true,1,this));enemyList.add(new Enemy(400,265,true,1,this));//绘制第一关的食人花敌人enemyList.add(new Enemy(635,420,true,2,328,428,this));}//判断是否为第二关if(sort==2){//直接复制第一关的,三关的地砖一样//绘制第二关的地面,上地面type=1,下地面type=2,// 窗口横坐标为800,一个地面为30for (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));}}//绘制砖块CobstacleList.add(new Obstacle(300,330,0,this));//绘制砖块B,E,Gfor (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,Ifor (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(200,385,true,1,this));//绘制第二个蘑菇敌人enemyList.add(new Enemy(500,385,true,1,this));//第三个enemyList.add(new Enemy(400,205,true,1,this));//绘制第二关第一个食人花敌人enemyList.add(new Enemy(75,420,true,2,328,418,this));//绘制第二个食人花敌人enemyList.add(new Enemy(635,420,true,2,298,388,this));}//判断是否为第三关if (sort==3) {//绘制地面//绘制第三关的地面,上地面type=1,下地面type=2,// 窗口横坐标为800,一个地面为30for (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));//接下来生成旗杆和城堡的getter方法//绘制第三关蘑菇敌人enemyList.add(new Enemy(150,385,true,1,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;}
}
加载图片的StaticValue类:
package com.sxt;import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.Buffer;
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> 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<>();//获取路径, 定义path变量,除了照片的名字以外前缀一直都一样,因此定义出来路径方便调用public static String path=System.getProperty("user.dir")+"/src/images/";//初始化方法public static void init(){//利用ImageIO流的read方法,注意在read处捕获异常all+entertry {//加载背景图片bg= ImageIO.read(new File(path+"bg.png"));bg2=ImageIO.read(new File(path+"bg2.png"));//加载玛丽向左站立stand_L=ImageIO.read(new File(path+"stand_L.png"));//加载玛丽向右站立stand_R=ImageIO.read(new File(path+"stand_R.png"));//加载马里奥向左跳跃jump_L=ImageIO.read(new File(path+"jump1_l.png"));//加载马里奥向右跳跃Jump_R=ImageIO.read(new File(path+"Jump1_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+"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+"run"+i+"_R.png")));} catch (IOException e) {e.printStackTrace();}}try {//加载障碍物,上下地面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")));} catch (IOException e) {e.printStackTrace();}//加载水管for (int i=1;i<=4;i++) {try {obstacle.add(ImageIO.read(new File(path+"pipe"+i+".png")));} catch (IOException e) {e.printStackTrace();}}//加载不可破坏的砖块和旗子try {obstacle.add(ImageIO.read(new File(path+"brick2.png")));obstacle.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();}}
Obstacle类:该类设置了到旗子处后的后续操作
package com.sxt;import java.awt.image.BufferedImage;public class Obstacle implements Runnable{ //让该类实现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.obstacle.get(type); //初始化show,得到该类型的障碍物图像//下一步,生成这四个变量的getter方法//如果是旗子的话,启动线程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;}@Overridepublic void run() {while(true){ //一个死循环//让线程休眠,休眠时间:50毫秒if (this.bg.isReach()) { //判断马里奥是否到达旗子位置if (this.y<374){ //判断此时旗子是否落到了地上this.y+=5; //若没有,则让旗子慢慢下降}else{this.bg.setBase(true);//将isBase设置为true,表示旗子已经成功落地}}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}}
}
Strong类:
package com.sxt;import java.awt.image.BufferedImage;public class Strong implements Runnable{//储存食物坐标private int x,y;//显示图像private BufferedImage show;//定义一个背景对象private BackGround bg;//实现线程对象private Thread thread=new Thread(this);public Strong(int x,int y,BackGround bg){this.x=x;this.y=y;this.bg=bg;}@Overridepublic void run() {}
}
Mario类:
package com.sxt;import jdk.nashorn.internal.ir.SplitReturn;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"; //下一步使马里奥类实现Runnable接口并重写其中的抽象方法//初始化线程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() {//判断是否是跳跃状态,判断status调用它的indexOF方法if (status.indexOf("jump")==-1) {//判断方向,不等于-1则方向向左if (status.indexOf("left")!=-1){status="jump--left";}else{status="jump--right";}//改变下降速度向上跳跃y值减少ySpeed=-10;//设置向上跳的高度upTime=7; //向上跳一下70}//判断马里奥是否碰到了旗子if (backGround.isReach()){ //若是,则马里奥不可再移动ySpeed=0;}}//马里奥下落public void fall(){//下落时可能是从障碍物上掉下也可能是跳起后落下if (status.indexOf("left")!=-1){status="jump--left";}else{status="jump--right";}//下落时速度应该是正的,因为y值要++ySpeed=10;}@Overridepublic void run() {while (true){//判断是否处于障碍物上boolean onObstacle=false;//判断是否可以向右走boolean canRight=true;//判断是否可以向左走boolean canLeft=true;//判断马里奥是否到达旗杆位置if (backGround.isFlag()&&this.x>=500){//setReach设置为true,表明此刻马里奥到达了旗杆的位置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)) {//判断此时顶到的砖块类型是否是普通砖块(0),若是则移除if (ob.getType() == 0) {//如果是则调用backGround.getObstacleList().remove()方法将ob移出去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置为falsecanRight = false;}//判断是否可以往左走if (ob.getX() == this.x - 30 && (ob.getY() > this.y - 30 && ob.getY() < this.y + 25)) {canLeft = false;}}//判断马里奥是否碰到敌人死亡或者踩死蘑菇敌人//通过for循环来遍历每一个敌人for (int i=0;i<backGround.getEnemyList().size();i++){Enemy e=backGround.getEnemyList().get(i); //用e来储存我们当前的敌人//判断马里奥是否位于敌人的头上if (e.getY()==this.y+20&&(e.getX()-25<=this.x&&e.getX()+35>=this.x)){//判断是蘑菇敌人还是食人花敌人if (e.getType()==1){e.death();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 {//不是,则说明到了最高点,该下落了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 int getY() {return y;}public BufferedImage getShow() {return show;}public void setShow(BufferedImage show){this.show=show;}public void setBackGround(BackGround backGround) {this.backGround = backGround;}public void setX(int x) {this.x = x;}public void setY(int y) {this.y = y;}public boolean isOK() {return isOK;}public boolean isDeath() {return isDeath;}public int getScore() {return score;}
}
Enemy(敌人类):
package com.sxt;import javax.xml.ws.BindingType;
import java.awt.image.BufferedImage;import static java.lang.Thread.sleep;public class Enemy implements Runnable{//储存当前坐标private int x,y;//储存敌人类型private final int type;//判断敌人的运动方向private boolean face_to=true;//用于显示敌人当前的图像private BufferedImage show;//定义一个背景对象private final BackGround bg;//食人花运动的极限范围private int max_up=0;private int max_down=0;//实现线程对象,用于实现食人花和蘑菇的运动private final Thread thread=new Thread(this);//定义当前图片的状态private int image_type=0;// 创建MyFrame对象
// MyFrame myFrame = new MyFrame();//蘑菇敌人的构造函数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(); //调用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_up=max_up;this.max_down=max_down;this.bg=bg;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;}@Overridepublic void run() {try {sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}if (MyFrame.isStart == true) {while (true) {//判断是否是蘑菇敌人,type是蘑菇敌人if (type == 1) {if (face_to) { //true是向左移动,false时向右移动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循环来遍历每一个障碍物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);}try {sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}} }}
Music类:
package com.sxt;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 name=new BufferedInputStream(new FileInputStream(str));//读取音乐player=new Player(name);//实例化对象。同上一步都需要抛出异常player.play();//调用方法播放音乐}
}