JAVA 实现《超级玛丽》游戏

前言

在你的童年记忆里,是否有一个蹦跳、顶蘑菇的小人?

如果你回忆起了它,你定然会觉得现在它幼稚、无聊,画面不漂亮,游戏不精彩……但请你记住:这才是真正的游戏,它给了你无限的欢乐!

马里奥是靠吃蘑菇成长,闻名世界的超级巨星。特征是大鼻子、头戴帽子、身穿背带工作服、还留着胡子。

如此经典的游戏,你怎么能错过,快来玩玩吧。

《超级玛丽》游戏是用java语言实现,采用了swing技术进行了界面化处理,设计思路用了面向对象思想。

主要需求

游戏剧情模拟超级玛丽,用swing来做界面化处理,学会利用面向对象的思想实现这个游戏

主要设计

1、游戏背景的设计

2、地图的显示

3、台阶的显示

4、游戏物品的显示

5、超级玛丽的设计,左右移动能力、跳动能力

6、小怪的设计,包含出现的地点、杀伤功能、跳动能力

7、游戏的分数系统设计

8、地图变动功能

9、射击功能

10、游戏采用多线程技术

11、背景音乐设计

功能截图

游戏开始:

image-202202179844383

超级玛丽跳动

image-202202189131472

换地图

image-202202189245930

过了这一关

image-20220218000326835

代码实现

游戏主界面


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);public MyFrame() {//设置窗口的大小为800 * 600this.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 (Exception e) {}}@Overridepublic 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);graphics.setFont(new Font("黑体",Font.BOLD,25));graphics.drawString("当前的分数为: " + mario.getScore(),300,100);graphics.setColor(c);//将图像绘制到窗口中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 (e.getKeyCode() == 39) {mario.rightMove();}//向左移动if (e.getKeyCode() == 37) {mario.leftMove();}//跳跃if (e.getKeyCode() == 38) {mario.jump();}}//当键盘松开按键时调用@Overridepublic void keyReleased(KeyEvent e) {//想左停止if (e.getKeyCode() == 37) {mario.leftStop();}//向右停止if (e.getKeyCode() == 39) {mario.rightStop();}}@Overridepublic 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,"马里奥死亡!!!");System.exit(0);}//判断游戏是否结束if (mario.isOK()) {JOptionPane.showMessageDialog(this,"恭喜你!成功通关了");System.exit(0);}} catch (InterruptedException e) {e.printStackTrace();}}}}

马里奥

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

小怪


public class Enemy implements Runnable{//存储当前坐标private int x;private int y;//存储敌人类型private int type;//判断敌人运动的方向private boolean face_to = true;//用于显示敌人的当前图像private BufferedImage show;//定义一个背景对象private BackGround bg;//食人花运动的极限范围private int max_up = 0;private int max_down = 0;//定义线程对象private Thread thread = new Thread(this);//定义当前的图片的状态private int image_type = 0;//蘑菇敌人的构造函数public Enemy(int x,int y,boolean face_to,int type,BackGround bg) {this.x = x;this.y = y;this.face_to = face_to;this.type = type;this.bg = bg;show = StaticValue.mogu.get(0);thread.start();}//食人花敌人的构造函数public Enemy(int x,int y,boolean face_to,int type,int max_up,int max_down,BackGround bg) {this.x = x;this.y = y;this.face_to = face_to;this.type = type;this.max_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() {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);}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}}
}

总结

通过此次的《超级玛丽》游戏实现,让我对JAVA的相关知识有了进一步的了解,对java这门语言也有了比以前更深刻的认识。

java的一些基本语法,比如数据类型、运算符、程序流程控制和数组等,理解更加透彻。java最核心的核心就是面向对象思想,对于这一个概念,终于悟到了一些。

源码获取

源码下载地址:传送门------->

点赞,关注博主后,私聊博主免费获取
需要技术指导,写项目程序,等更多服务请联系博主

今天是持续写作的第 18 / 100 天。
可以关注我,点赞我、评论我、收藏我啦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/353098.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Java游戏开发——连连看

游戏介绍&#xff1a; “连连看”是一款来源于我国台湾的桌面小游戏&#xff0c;主要考验的是玩家们的眼力&#xff0c;在有限的时间内&#xff0c;只要能把所有能连接的相同图案&#xff0c;两个两个的找出来&#xff0c;每找到一对&#xff0c;它们就会自动消失&#xff0c;只…

java小游戏超级玛丽:05.第一关的设计

第一关效果图&#xff1a; 目录 判断是否为第一关 绘制第一关的场景 绘制地面&#xff08;for循环&#xff09; 绘制砖块 绘制水管 生成Obstatic列表的getter方法 绘制障碍物 判断是否为第一关 if(sort 1){ } 在上面有定义变量sort 绘制第一关的场景 绘制地面&…

程序员从0到收获心仪offer,我靠训练营实现了180度逆袭!

我相信&#xff0c;在未来的职场中&#xff0c;我也能通过这段时间养成的学习习惯和生活习惯让自己一步步成为更好的自己&#xff0c;以自己为荣 我在大学里主修计算机科学与技术&#xff0c;一个普通的院校&#xff0c;一个算是常见的专业&#xff0c;我知道我的学历和一些其他…

10 【组件编码流程 组件自定义事件 全局事件总线】

1.组件编码流程 组件化编码流程&#xff1a; ​ (1).拆分静态组件&#xff1a;组件要按照功能点拆分&#xff0c;命名不要与html元素冲突。 ​ (2).实现动态组件&#xff1a;考虑好数据的存放位置&#xff0c;数据是一个组件在用&#xff0c;还是一些组件在用&#xff1a; ​ 1…

QQ互联地址 中注册的QQ开发者 在哪里提交审核?

QQ互联地址&#xff1a;https://connect.qq.com 废话不说&#xff0c;直接上图&#xff1a; 有时点击后没反应&#xff0c;耐心 多试几次&#xff01; 然后 就会看到 提交审核的表单了&#xff0c; 有没发现 这个提交审核的 链接藏的有点深&#xff01;&#xff01; 哈哈哈&am…

QQ小程序打开指定QQ群

官方提供了接口&#xff1a; <view class"footer"><button open-type "openGroupProfile" class"footer-tips" group-id"620033746">v1.0 by&#xff1a;IWH <text>加群玩&#xff01;</text></button&g…

打开图片链接直接打开QQ对话框

<a href"tencent://message/?uin7530****&SiteQQ交谈&Menuyes" target"blank"> <img border"0" src"http://wpa.qq.com/pa?p1:7530*****:7" alt"有事Q我吧" width"71" height"2…

QQ的分享

使用的sdk版本&#xff1a; V2.2.2&#xff08;发布日期&#xff1a;2014.3.17&#xff09; 弱弱的提醒下&#xff1a; 1.配置清单等环境搭建&#xff0c;这里就不多说了&#xff0c;可以去看看我的另外一篇博客&#xff0c;QQ的第三方登录&#xff0c;那里有介绍。 2.这里集…

QQ圈子:从哪里来,到哪里去

2019独角兽企业重金招聘Python工程师标准>>> 摆脱顿巴数的魔咒 社 交是人类的一个最基本的需求。但是&#xff0c;自然给我们人类的大脑&#xff0c;只能让我们维系150-200个左右的好友。超出这个范围&#xff0c;就会有好友慢慢地被淡忘。很多社会 群体的平均大小是…

html 打开腾讯qq,qq软件管理器 QQ应用管理器里面的腾讯软件打不开

手机QQ中的消息管理器在哪里 打开的qq软件主界面&#xff0c;点击左下角的“主菜单”按钮。 在打开的qq主菜单中&#xff0c;点击“设置”菜单项。 手机版qq怎么进消息管理器QQ右下角...有一个查找。 查找的左边,有一个小喇叭. 那个就是信息管理器。 腾讯qq上的应用管理器在哪 …

打开qq聊天界面的url

2019独角兽企业重金招聘Python工程师标准>>> 打开qq聊天界面的url 北极熊爱企鹅 10:43:39 NSString *open_URL "mqq://im/chat?chat_typewpa&uin501863587&version1&src_typeweb"; 转载于:https://my.oschina.net/LiuChongYang/blog/51829…

如何创建圈子

首先您需要登录您在CSDN Blog的个人管理后台,点击“圈子”.如图所示: 点击"创建一个新的圈子" 输入名称和标题&#xff08;名称将是URL的一部分&#xff0c;例如experts就是 http://blog.csdn.net/group/experts/的名称&#xff1b;而“CSDN专家群”则是标题&#x…

Numpy---创建多维数组、创建正态分布、创建均匀分布

1. 创建一个随机整数的多维数组 np.random.randint(low, highNone, sizeNone, dtypel) 参数说明: low : 最小值 highNone: 最大值 highNone时&#xff0c;生成的数值在【0, low&#xff09;区间内 如果使用high这个值&#xff0c;则生成的数值在【low, high&#xff09;区…

扩容系统盘【centos-root】

问题描述&#xff1a; 磁盘空间有42G&#xff0c;但是系统盘只有6G。 问题抛出&#xff1a;&#xff08;P2原本只有7G&#xff0c;其中有30G错误分配到nvmeOn1p2了&#xff09;p2的30G空间怎么合理分配给系统盘? &#xff08;执行&#xff1a; sudo growpart /dev/nvme0n1 …

华为od机试题目回顾

今天去做了华为机试&#xff0c;两道一星题&#xff0c;一道二星题。 一星题 1&#xff1a; 题目主要大意&#xff1a; 输入一串字符串&#xff0c;里面可能包含有(x,y)的坐标。 0<x<1000&#xff0c;0<y<1000&#xff0c;类似(01,1)、(1,01)、(0,100)的都是非法坐…

小米耳机怎么连接手机(实用方法)

今天来教教大家一个手机实用小技巧。就是手机怎么与小米蓝牙耳机配对连接。大家可以了解一下。 首先打开手机。进入设置。点击蓝牙进入。打开蓝牙开关。拿出蓝牙耳机。在蓝牙耳机的开关键上长按10秒左右。让耳机处于配对状态。点击进行小米蓝牙耳机连接。允许蓝牙耳机访问通讯…

【HTML-5】小米耳机产品模块

1. 以下为效果图 2.以下为源代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"…

入手评测 小米降噪耳机 Pro怎么样

小米智能生活 官微宣布&#xff0c;年度旗舰小米降噪耳机 Pro 将于 5 月 13 日发布。小米降噪耳机 Pro怎么样这些点很重要看过你就懂了http://www.adiannao.cn/1 官方称&#xff0c;小米降噪耳机 Pro 采用了蕴涵“生命感”的弧线设计&#xff0c;每个角度都打磨得恰到好处&…

什么牌子的耳机好?国产TWS耳机推荐

随着越来越多的手机取消3.8mm耳机接口&#xff0c;TWS耳机便成为了更多用户的选择。现如今&#xff0c;随处可见的都是TWS耳机&#xff0c;在这多样化的蓝牙耳机市场&#xff0c;选择更多、更困难。下面&#xff0c;我来推荐几款好用的国产TWS耳机&#xff0c;一起来看看吧。 …