《面向对象》课程设计--超级玛丽

1. 团队介绍

团队名称:会飞的代码

团队成员 任务分配
兰心怡(组长) 游戏框架搭建、游戏背景设置、静态常量初始化
王思嘉 马里奥的左右移动、跳跃等,判断马里奥是否与障碍物相撞,敌人的活动状态

2. 参考代码

https://blog.csdn.net/hj7jay/article/details/54310817
https://blog.csdn.net/weixin_42313980/article/details/114098276
https://blog.csdn.net/jiachunchun/article/details/89670721

3. 前期调查


4. 功能架构图

5. 面向对象设计包图、类图

  • images包存放游戏相关的所有图片
  • MyFrame--游戏框架的构建、游戏窗口的设置
  • BackGround--游戏背景的绘制
  • StaticValue--将静态常量初始化,并将图片加载至内存中
  • Mario--马里奥(游戏人物)的左右移动、跳跃等,并判断是否会与障碍物相撞
  • Enemy--敌人的移动、状态及死亡
  • Obstacle--障碍物初始化

6. 项目运行



7. 项目关键代码

马里奥类(游戏人物类):

 //马里奥的死亡方法
    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;
    }


    @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);
                            score = getScore() + 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 = getScore() + 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 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();
			}
    	}
    }

窗口设置:

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

背景绘制:

if(sort == 1) {
			//绘制第一关地面
			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, true, 1, this));
			//绘制第一关的食人花敌人
			enemyList.add(new Enemy(635, 420, true, 2, 328, 428, this));
			
		}

图片初始化:

public static void init() {
    	//加载背景图片
    	try {
    		bg = 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"));
    	}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 {
            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();
            }
        }

        //加载食人花敌人
        for (int i = 1;i <= 2;i++) {
            try {
                flower.add(ImageIO.read(new File(path + "flower1."+i+".png")));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

8.未来展望

此次课设还是有许多的不足之处,比如在游戏过程中游戏人物有时候会突然卡在一些奇奇怪怪的地方,或砖块,或水管,所以还是需要继续学习,可能找到一种更为合适更为简便的算法来修复这些小Bug,同时希望可以继续完善这个小游戏,例如增加更多的关卡、增加游戏人物的生命值、增加更多地图等。

posted @ 2022-01-12 21:05  七棋  阅读(395)  评论(0)    收藏  举报