java小游戏-java小游戏-超级玛丽
1 创建窗口
创建MyFrame类
public class MyFrame extends JFrame implements KeyListener {
public MyFrame(){
//设置窗口大小 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("超级玛丽");
}
public static void main(String[] args) {
MyFrame myFrame = new MyFrame();
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
}
2 创建并完成常量类
先导入相关图片在文件中
创建StaticValue类
public class StaticValue {
//背景
public static BufferedImage bg1 = 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<>();
//路径的前缀,方便后续调用
public static String path = System.getProperty("user.dir") + "/src/images/";
//初始化方法
public static void init() {
try {
//加载背景图片
bg1 = ImageIO.read(new File(path + "bg.png"));
bg2 = ImageIO.read(new File(path + "bg2.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"));
//加载马里奥向左跳跃
jump_L = ImageIO.read(new File(path + "s_mario_jump1_L.png"));
//加载马里奥向右跳跃
jump_R = ImageIO.read(new File(path + "s_mario_jump1_R.png"));
//加载马里奥向左跑
for (int i = 1; i <= 2; i++) {
run_L.add(ImageIO.read(new File(path + "s_mario_run" + i + "_L.png")));
}
//加载马里奥向右跑
for (int i = 1; i <= 2; i++) {
run_R.add(ImageIO.read(new File(path + "s_mario_run" + i + "_R.png")));
}
//加载障碍物
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")));//下地面
//加载水管
for (int i = 1; i <= 4; i++) {
obstacle.add(ImageIO.read(new File(path + "pipe" + i + ".png")));
}
//加载不可破坏的砖块和旗子
obstacle.add(ImageIO.read(new File(path + "brick2.png")));//不可破坏的砖块
obstacle.add(ImageIO.read(new File(path + "flag.png")));//旗子
//加载蘑菇敌人
for (int i = 1; i <= 3; i++) {
mogu.add(ImageIO.read(new File(path + "fungus" + i + ".png")));
}
//加载食人花敌人
for (int i = 1; i <= 2; i++) {
flower.add(ImageIO.read(new File(path + "flower" + i + ".png")));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
在MyFrame类构造器中调用
public MyFrame(){
...
this.setTitle("超级玛丽");
//初始化图片
StaticValue.init();
}
3 创建背景类
创建BackGround类
//背景类
public class BackGround {
//当前场景需要显示的图像
private BufferedImage bgImage = null;
//记录当前是第几个场景
private int sort;
//判断是否是最后一个场景
private boolean flag;
public BackGround(){}
public BackGround(int sort,boolean flag){
this.sort = sort;
this.flag = flag;
if(flag){//最后一个场景
bgImage = StaticValue.bg2;
}else {
bgImage = StaticValue.bg1;
}
}
public BufferedImage getBgImage() { return bgImage; }
public int getSort() { return sort; }
public boolean isFlag() { return flag; }
}
4 绘制背景类
在MyFrame类添加背景类
//用于存储所有的背景
private List<BackGround> allBg = new ArrayList<>();
//用于存储当前的背景
private BackGround nowBg = new BackGround();
//用于双缓存
private Image offScreenImage = null;
public MyFrame(){
...
//创建全部的场景
for (int i = 1; i <= 3; i++) {
allBg.add(new BackGround(i,i == 3 ? true : false));
}
//将第一个场景设置为当前场景
nowBg = allBg.get(0);
//绘制图像
repaint();
}
@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);
//将图像绘制到窗口中
g.drawImage(offScreenImage,0,0,this);
}
5 创建障碍物
创建Obstacle类
//障碍物类
public class Obstacle {
//坐标
private int x,y;
//障碍物类型
private int type;
//显示图像
private BufferedImage show = null;
//定义当前的场景对象
private BackGround bg = null;
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);
}
public int getX() { return x; }
public int getY() { return y; }
public int getType() { return type; }
public BufferedImage getShow() { return show; }
}
在BackGround类中引用
//用于存放我们所有的障碍物
private List<Obstacle> obstacleList = new ArrayList<>();
6 第一关的设计
在BackGround类构造器中添加第一关判断
public BackGround(int sort,boolean flag){
...
//判断是否是第一关
if(sort == 1){
//绘制第一关的地面,上地面是type=1,下地面type=2
for (int i = 0; i < 27; i++) {
obstacleList.add(new Obstacle(i*30,420,1,this));
}
for (int i = 0; i <= 120 ; i+=30) {
for (int j = 0; j < 27 ; j++) {
obstacleList.add(new Obstacle(j*30,570-i,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));
}
}
}
}
public List<Obstacle> getObstacleList() { return obstacleList; }
在Obstacle类添加绘制
@Override
public void paint(Graphics g) {
...
//绘制障碍物
for (Obstacle ob : nowBg.getObstacleList()){
graphics.drawImage(ob.getShow(),ob.getX(),ob.getY(),this);
}
//将图像绘制到窗口中
g.drawImage(offScreenImage,0,0,this);
}
7 第二关的设计
在BackGround类构造器中添加第二关判断
public BackGround(int sort,boolean flag){
...
//判断是否第二关
if(sort == 2){
//绘制第二关的地面,上地面是type=1,下地面type=2
for (int i = 0; i < 27; i++) {
obstacleList.add(new Obstacle(i*30,420,1,this));
}
for (int i = 0; i <= 120 ; i+=30) {
for (int j = 0; j < 27 ; j++) {
obstacleList.add(new Obstacle(j*30,570-i,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));
}
}
}
8 第三关的设计
在BackGround类构造器中添加第三关判断
//用于显示旗杆
private BufferedImage gan = null;
//用于显示城堡
private BufferedImage tower = null;
public BackGround(int sort,boolean flag){
...
//判断是否第三关
if(sort == 3){
//绘制第二关的地面,上地面是type=1,下地面type=2
for (int i = 0; i < 27; i++) {
obstacleList.add(new Obstacle(i*30,420,1,this));
}
for (int i = 0; i <= 120 ; i+=30) {
for (int j = 0; j < 27 ; j++) {
obstacleList.add(new Obstacle(j*30,570-i,2,this));
}
}
//绘制第三个背景的A-0砖块
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));
}
}
public BufferedImage getGan() { return gan; }
public BufferedImage getTower() { return tower; }
在Obstacle类添加绘制
@Override
public void paint(Graphics g) {
...
//绘制城堡
graphics.drawImage(nowBg.getTower(),620,270,this);
//绘制旗杆
graphics.drawImage(nowBg.getGan(),500,220,this);
//将图像绘制到窗口中
g.drawImage(offScreenImage,0,0,this);
}
9 创建马里奥类
创建Mario类
//马里奥类
public class Mario implements Runnable{
//用于表示横纵坐标
private int x,y;
//用于表示当前的状态
private String status;
//用于显示当前状态对应的图像
private BufferedImage show = null;
//定义一个BackGround对象,用来获取障碍物的信息
private BackGround backGround = new BackGround();
//用来实现马里奥的动作
private Thread thread = null;
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();
}
@Override
public void run() {
}
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; }
}
在MyFrame类中绘制
//马里奥对象
private Mario mario = new Mario();
public MyFrame(){
...
//初始化图片
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);
//绘制图像
repaint();
}
@Override
public void paint(Graphics g) {
...
//绘制旗杆
graphics.drawImage(nowBg.getGan(),500,220,this);
//绘制马里奥
graphics.drawImage(mario.getShow(),mario.getX(),mario.getY(),this);
//将图像绘制到窗口中
g.drawImage(offScreenImage,0,0,this);
}
10 实现马里奥的移动
在Mario类添加移动参数
//马里奥的移动速度
private int xSpeed;
//马里奥的跳跃速度
private int ySpeed;
//定义一个索引
private int index;
//马里奥向左移动
public void leftMove(){
//改变速度
xSpeed = -5;
//判断马里奥是否处于空中
if(status.indexOf("jump") != -1){//处于空中
status = "jump_left";
}else{
status = "move_left";
}
}
//马里奥向右移动
public void rightMove(){
//改变速度
xSpeed = 5;
//判断马里奥是否处于空中
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";
}
}
@Override
public void run() {
while (true){
if(xSpeed < 0 || 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;
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void setBackGround(BackGround backGround) { this.backGround = backGround; }
修改MyFrame类
public class MyFrame extends JFrame implements KeyListener,Runnable{
...
//定义一个线程对象,用于实现马里奥的运动
private Thread thread = new Thread(this);
public MyFrame(){
...
//将第一个场景设置为当前场景
nowBg = allBg.get(0);
mario.setBackGround(nowBg);
//绘制图像
repaint();
thread.start();
}
...
//当键盘按下按键时调用
@Override
public void keyPressed(KeyEvent e) {
//向右移动
if(e.getKeyCode() == KeyEvent.VK_RIGHT){//→
mario.rightMove();
}
//向左移动
if(e.getKeyCode() == KeyEvent.VK_LEFT){//←
mario.leftMove();
}
}
//当键盘松开按键时调用
@Override
public void keyReleased(KeyEvent e) {
//向左停止
if(e.getKeyCode() == KeyEvent.VK_LEFT){//←
mario.leftStop();
}
//向右停止
if(e.getKeyCode() == KeyEvent.VK_RIGHT){//→
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);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
11 实现马里奥的跳跃和下落
在Mario类添加跳跃和下落
//表示马里奥上升的时间
private int upTime = 0;
//马里奥跳跃
public void jump(){
if(status.indexOf("jump") == -1){//不是调用状态
if(status.indexOf("left") != -1){
status = "jump_left";
}else {
status = "jump_right";
}
ySpeed = -10;
upTime = 7;
}
}
//马里奥下落
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;
//遍历当前场景里所有障碍物
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(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(xSpeed < 0 || xSpeed > 0){
x += xSpeed;
//判断马里奥是否到了最左边
if(x < 0){
x = 0;
}
}
...
//判断是否向左跳跃
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();
}
}
}
在MyFrame类添加监听
//当键盘按下按键时调用
@Override
public void keyPressed(KeyEvent e) {
...
//跳跃
if(e.getKeyCode() == KeyEvent.VK_UP){//↑
mario.jump();
}
}
12 实现障碍物的阻挡
在Mario类run方法添加
@Override
public void run() {
while (true){
//判断是否处于障碍物上
boolean onObstacle = false;
//判断是否可以往右走
boolean canRight = true;
//判断是否可以往左走
boolean canLeft = true;
//遍历当前场景里所有障碍物
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);
}
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;
}
}
...
if((canLeft && xSpeed < 0) || (canRight && xSpeed > 0)){
x += xSpeed;
//判断马里奥是否到了最左边
if(x < 0){
x = 0;
}
}
...
}
}
13 实现游戏结束
在Mario类修改run方法
//用于判断马里奥是否走到了城堡的门口
private boolean isOK;
//马里奥向左移动
public void leftMove(){
//改变速度
xSpeed = -5;
//判断马里奥是否碰到了旗子
if(backGround.isReach()){
xSpeed = 0;
}
//判断马里奥是否处于空中
if(status.indexOf("jump") != -1){//处于空中
status = "jump_left";
}else{
status = "move_left";
}
}
//马里奥跳跃
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 leftStop(){
//改变速度
xSpeed = 0;
//判断马里奥是否碰到了旗子
if(backGround.isReach()){
xSpeed = 0;
}
//判断马里奥是否处于空中
if(status.indexOf("jump") != -1){//处于空中
status = "jump_left";
}else{
status = "stop_left";
}
}
@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);
}
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;
}
}
//进行马里奥跳跃操作
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;
}
}
....
}
}
public boolean isOK() { return isOK; }
在BackGround类添加参数
//判断马里奥是否到达旗杆位置
private boolean isReach = false;
//判断旗子是否落地
private boolean isBase = false;
public boolean isReach() { return isReach; }
public void setReach(boolean reach) { isReach = reach; }
public boolean isBase() { return isBase; }
public void setBase(boolean base) { isBase = base; }
在Obstacle类添加线程
public class Obstacle implements Runnable{
...
//定义一个线程对象[旗子下落过程]
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);
//如果是旗子的话,启动线程
if(type == 8){
thread.start();
}
}
..
@Override
public void run() {
while (true){
if(this.bg.isReach()){
if (this.y < 374) {
this.y += 5;
}else {
this.bg.setBase(true);
}
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
在MyFrame类添加通关提示
@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.isOK()){
//弹出提示
JOptionPane.showMessageDialog(this,"恭喜你!成功通关了!");
System.exit(0);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
14 创建并完成敌人类
创建Enemy类
//敌人类
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;
//定义线程对象
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_down = max_down;
this.max_up = max_up;
this.bg = bg;
show = StaticValue.flower.get(0);
thread.start();
}
//死亡方法
public void death(){
show = StaticValue.mogu.get(2);
this.bg.getEnemyList().remove(this);
}
@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 calLeft = 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)){
calLeft = false;
}
}
if(face_to && !calLeft || 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();
}
}
}
}
public int getX() { return x; }
public int getY() { return y; }
public BufferedImage getShow() { return show; }
public int getType() { return type; }
在BackGround类中引用
//用于存放我们所有的敌人
private List<Enemy> enemyList = new ArrayList<>();
public List<Enemy> getEnemyList() { return enemyList; }
15 向关卡中添加敌人
在BackGround类t添加敌人生成
public BackGround(int sort,boolean flag){
...
//判断是否是第一关
if(sort == 1){
...
//绘制第一关的蘑菇敌人
enemyList.add(new Enemy(580,385,true,1,this));
//绘制第一关的食人花敌人
enemyList.add(new Enemy(635,420,true,2,328,428,this));
}
//判断是否第二关
if(sort == 2){
...
//绘制第二关的第一个食人花敌人
enemyList.add(new Enemy(75,420,true,2,328,418,this));
//绘制第二关的第二个食人花敌人
enemyList.add(new Enemy(635,420,true,2,298,388,this));
//绘制第二关的第一个蘑菇敌人
enemyList.add(new Enemy(200,385,true,1,this));
//绘制第二关的第二个蘑菇敌人
enemyList.add(new Enemy(500,385,true,1,this));
}
//判断是否第三关
if(sort == 3){
...
//添加旗子到旗杆上
obstacleList.add(new Obstacle(515,220,8,this));
//绘制第三关的第蘑菇敌人
enemyList.add(new Enemy(150,385,true,1,this));
}
}
在MyFramee类添加敌人绘制
@Override
public void paint(Graphics g) {
...
//绘制背景
graphics.drawImage(nowBg.getBgImage(),0,0,this);
//绘制敌人
for (Enemy e : nowBg.getEnemyList()) {
graphics.drawImage(e.getShow(),e.getX(),e.getY(),this);
}
//绘制障碍物
...
}
16 完成马里奥杀死敌人和马里奥死亡
在Mario类添加判断
//用于判断马里奥是否死亡
private boolean isDeath = false;
//马里奥死亡方法
public void death(){
isDeath = true;
}
@Override
public void run() {
while (true){
...
if(backGround.isFlag() && this.x >= 500){
...
}else {
//遍历当前场景里所有障碍物
...
//判断马里奥是否碰到敌人死亡或者踩死蘑菇敌人
for (Enemy enemy : backGround.getEnemyList()) {
//判断马里奥是否位于敌人上方
if(enemy.getY() == this.y + 20 && (enemy.getX() - 25 <= this.x && enemy.getX() + 35 >= this.x)){
if(enemy.getType() == 1){
enemy.death();
upTime = 3;
ySpeed = -10;
}else if(enemy.getType() == 2){
//马里奥死亡
death();
}
}
//碰到敌人
if((enemy.getX() + 35 > this.x && enemy.getX() - 25 < this.x)
&& (enemy.getY() + 35 > this.y && enemy.getY() - 20 < this.y)){
//马里奥死亡
death();
}
}
//进行马里奥跳跃操作
...
}
}
public boolean isDeath() { return isDeath; }
在MyFrame类添加马里奥死亡判断
@Override
public void run() {
while (true){
//重新绘制图像
repaint();
try {
...
//判断马里奥是否死亡
if(mario.isDeath()){
JOptionPane.showMessageDialog(this,"马里奥死亡!!!");
System.exit(0);
}
....
}
}
17 给游戏添加积分功能
在Mario类添加参数
//表示分数
private int score = 0;
@Override
public void run() {
while (true){
...
if(backGround.isFlag() && this.x >= 500){
...
}else {
//遍历当前场景里所有障碍物
for (int i = 0; i < backGround.getObstacleList().size(); i++) {
...
//判断是否跳跃起来顶到砖块
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;
}
...
}
//判断马里奥是否碰到敌人死亡或者踩死蘑菇敌人
for (Enemy enemy : backGround.getEnemyList()) {
//判断马里奥是否位于敌人上方
if(enemy.getY() == this.y + 20 && (enemy.getX() - 25 <= this.x && enemy.getX() + 35 >= this.x)){
if(enemy.getType() == 1){
enemy.death();
score += 2;
upTime = 3;
ySpeed = -10;
}else if(enemy.getType() == 2){
//马里奥死亡
death();
}
}
//碰到敌人
if((enemy.getX() + 35 > this.x && enemy.getX() - 25 < this.x)
&& (enemy.getY() + 35 > this.y && enemy.getY() - 20 < this.y)){
//马里奥死亡
death();
}
}
...
}
}
public int getScore() { return score; }
在MyFrame类添加绘制分数
@Override
public void paint(Graphics g) {
...
//绘制马里奥
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);
}
18 给游戏添加背景音乐
先导入jar 或者使用依赖
<dependency>
<groupId>javazoom</groupId>
<artifactId>jlayer</artifactId>
<version>1.0.1</version>
</dependency>
创建Music类
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 bis = new BufferedInputStream(new FileInputStream(str));
player = new Player(bis);
player.play();
}
}
在MyFrame类添加
public MyFrame(){
...
//绘制图像
repaint();
thread.start();
try {
new Music();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (JavaLayerException e) {
e.printStackTrace();
}
}