Java小游戏练习---超级玛丽代码实现

article/2025/10/12 16:58:17

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();//调用方法播放音乐}
}


http://chatgpt.dhexx.cn/article/NwOZFp5w.shtml

相关文章

java 300行代码 冒险闯关小游戏(代码+讲解)

作为一个男孩子&#xff0c;从小就喜欢晚一些游戏。今天就用java写一个类似马里奥的冒险闯关小游戏&#xff0c;但这也不是一两天能完成的事情&#xff0c;我将会持续更新这个游戏&#xff08;有什么好的介意也非常欢迎大家提出来&#xff0c;也能在我的基础上自己接着写&#…

宝塔php防盗链,[宝塔面板]如何开启防盗链?

为了节省建站成本&#xff0c;大多数站长都会选择一些小服务器&#xff0c;在另加CDN、云存储之类的来减轻服务器的压力&#xff0c;但是这类功能大多收费。 如果自己网站的图片都让别人复制图片链接地址&#xff0c;那么自己CDN流量就跑得贼快&#xff0c;花了钱得不到好处。 …

HTTP防盗链(Referer)

HTTP请求防盗链&#xff1a;只允许某些域名请求来源才可以访问。比如A网站有一张图片或音频等资源被B网站直接通过img等标签属性引入使用&#xff0c;这样就是B网站盗用了A网站的资源。那么对于A网站来说&#xff0c;流量怎么被消耗的都不知道。 解决思路&#xff1a; 判断http…

Nginx防盗链的配置

Nginx防盗链的配置 通常站点&#xff0c;都会想让自己网站的视频和图片&#xff0c;免被盗用&#xff0c;毕竟视频流量&#xff0c;花的都是白花花银子   首先我们没有配置防盗链的情况下&#xff0c;放开静态资源你的访问。我们来看看效果 location ~* .*\.(gif|jpg|ico|pn…

python爬虫的防盗链

文章目录 前言一、防盗链是什么&#xff1f;二、 防盗链如何实现三、分析四、 对有防盗链的网站进行爬取对有视频连接的网站发出请求并且获取源码信息提取出我们的视频网站对我们提取的网址进行修改&#xff0c;和拼凑下载视频结束爬取 完整代码 前言 随着python的发展网页的反…

Nginx静态资源防盗链

1.什么是资源盗链 简单地说&#xff0c;就是将别人的资源用到自己的页面展示给用户。 2.效果演示 1&#xff09;准备图片 这两张图片直接在浏览器中访问都是可以打开的。 github图片地址&#xff1a;https://github.githubassets.com/images/modules/site/home-campaign/her…

取消文件服务器防盗链,如何取消防盗链保护

http标准协议中有专门的字段记录referer 一来可以追溯上一个入站地址是什么 二来对于资源文件&#xff0c;可以跟踪到包含显示他的网页地址是什么。 因此所有防盗链方法都是基于这个Referer字段 网上比较多的2种 一种是使用apache文件FileMatch限制&#xff0c;在httpd.conf中增…

视频防盗链

解析器链接&#xff1a; https://www.administratorw.com/index/qqvod.php?url 清晰度高url后面支持mp4、m3u8地址 https://z1.m1907.cn?jx 清晰度底&#xff0c;链接后面只支持电影名 此接口解析出来的m3u8地址为&#xff1a;&#xff08;雄狮少年&#xff09; https…

html 图片防盗链,【反防盗链】介绍一个对付图片防盗链的方法

悲催的声明: 由于腾讯也采用了防盗链技术,本文方法已经失效了! 当我们想在文章里引用某张图片时,如果对方设置了防盗链,我们看到的将是404或forbidden或其他图片,而不是想要的那张图片,为此,我们有无方法进行“反防盗链”呢?答案是有的,本文将介绍一个对付图片防盗链…

简单的视频防盗链

1.使用hls.js播放视频&#xff0c;页面中无法获得视频的src hls.js是视频播放的工具文件&#xff0c;在官网上有播放方式&#xff0c;可以产生如上图所示的效果&#xff0c;没有source标签&#xff0c;也就是说&#xff0c;在页面上隐藏掉了视频的url hls.js文件地址&#xff…

html设置referer防盗链,referer与防盗链

referer是什么 referer 中文意思是:参照页面,引用页。 下图直观感受,(づ ̄ 3 ̄)づ image 直接在浏览器中输入url地址来直接访问图片/js/css等资源时是没有referer的, 如果有referer说明是引用过来的,要么是从HTML页面,要么是通过css @import,再或则通过background(url)引用…

防盗链使用

现在很多网站启用了防盗链反爬&#xff0c;防止服务器上的资源被人恶意盗取。什么是防盗链呢&#xff1f; 以图片为例&#xff0c;访问图片要从他的网站访问才可以&#xff0c;否则直接访问图片地址得不到图片 练习&#xff1a;抓取微博图片&#xff1a;http://blog.sina.com…

nginx配置防盗链

现在流行前后端分离开发的情况下&#xff0c;一般我们都会将静态资源放在nginx的html目录下。这种情况下&#xff0c;我们就无法通过Java代码写拦截器来防盗链了。所以这里我们来说明一下如何使用nginx来配置防盗链。 1.我们先修改本地hosts文件&#xff0c;将 www.czx.com 映…

java防盗链_javaWeb防止恶意登陆或防盗链的使用

使用场景:明明引用了一个正确的图片地址,但显示出来的却是一个红叉或写有“此图片仅限于***网站用户交流沟通使用”之类的“假图片”。用嗅探软件找到了多媒体资源的真实地址用下载软件仍然不能下载。下载一些资源时总是出错,如果确认地址没错的话,大多数情况都是遇上防盗链…

防盗链机制

防盗链机制的几种实现 通常防盗链是为了防止图片&#xff0c;视频被盗用。下面简单介绍几种防盗链的机制&#xff1a; 1. 利用HTTP Referer字段 HTTP请求中会包含来自哪个url的点击来源&#xff0c;通过这个referer字段可以检测是否别的网站发送的请求。 2.利用登录验证信息 有…

网络中的防盗链是指什么?

什么是盗链&#xff1f; 比如,别人上传的东西,你直接拿了LINK去,贴到别的论坛或者网站,宣称"有好东西,快来下载",又或者告诉你的朋友"你要这个文件?俺有连接,快下",然后在那里接受别人的滔滔不绝的景仰之情。 “盗链” 的定义是&#xff1a; 此内容不在…

Nginx防盗链

Nginx防盗链的实现原理&#xff1a; 了解防盗链的原理之前&#xff0c;我们得先学习一个HTTP的头信息Referer,当浏览器向web服务器发送请求的时候&#xff0c;一般都会带上Referer,来告诉浏览器该网页是从哪个页面链接过来的。 后台服务器可以根据获取到的这个Referer信息来判…

Nginx-防盗链

目录 一、什么是盗链 如何区分哪些是不正常的用户&#xff1f; Referer理解 二、Nginx配置防盗链 三、使用 curl 测试防盗链 四、企业实战 1.设置返回错误页面 2.整合 rewrite 返回报错图片 一、什么是盗链 在实际生产过程中&#xff0c;我们线上的图片等静态资源&#…

Nginx:防盗链原理和配置

目录 一、防盗链概念 二、Nginx防盗链的具体实现 配置&#xff1a; 三、验证和验证时的问题 真正的验证&#xff1a; 没有none的验证 加上none参数的验证 让报错返回的是一张图片 注意事项&#xff1a; 一、防盗链概念 防盗链简单来说就是存在我们服务中的一些资源&#xff…

Java:eclipse下开发webservice教程

1 环境准备 下载wtp-all-in-one-sdk-R-1.5.4-win32&#xff0c;这个是eclipse的web开发插件 下载jakarta-tomcat-5.0.30 下载axis-src-1_4.zip 2 环境配置 配置tomcat关联到你的eclipse中 将axis-1_4\webapps\axis\WEB-INF\lib中的文件复制到$TOMCATHOME$\…