java版超级玛丽游戏

技术选型

平台:Windows开发工具:Intelij IDEA

JDK环境:Java 8

UI界面:基于Swing的桌面编程技术。

绘图技术:Graphics

集合框架

IO流

多线程等

地图配置

地图map.txt文件

0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,1,0,0,0,1,1,1,1,0,0,2,2,0,0,0,0,0,0,3
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

读取地图

定义角色

超级玛丽中的角色包括了,水管,怪物,砖头等。并显示到主界面。

障碍物抽象父类Enemy

水管类

砖头类

金币类

子弹类

马里奥类

窗体

package cn.tx.ui;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JFrame;

import cn.tx.mario.Mario;
import cn.tx.role.*;
import cn.tx.util.GameMap;
import cn.tx.util.MusicUtil;
/**
   主体窗口界面:展示角色。
 */
public class GameFrame extends JFrame{
	// 超级玛丽:界面需要一个超级玛丽的。
	public Mario mario;
	// 分别定义:水管,金币和砖块
	public Enemy pipe ,coin , brick;
	//背景图片
	public BackgroundImage bg ;
	//定义一个集合容器装敌人对象
	public ArrayList<Enemy> eneryList = new ArrayList<Enemy>();
	//定义一个集合容器装子弹
	public ArrayList<Boom> boomList = new ArrayList<Boom>();
	//子弹的速度
	public int bspeed=0;

	//地图数据,制定规则,是1画砖头,是2画金币,是3画水管
	public int[][] map = null;
	//对象代码块: 当前类的创建的时候执行
	{
		// 实例代码块中初始化地图资源的数据
		GameMap mp = new GameMap();
		map = mp.readMap();
	}

	//构造函数里面初始化背景图片和马里奥对象
	public GameFrame() throws Exception {
		// 创建背景图片
		bg = new BackgroundImage();
		//初始化窗体相关属性信息数据
		// this代表了当前主界面对象。
		this.setSize(800,450);
		this.setTitle("超级玛丽");
		this.setResizable(true);
		// 居中展示窗口
		this.setLocationRelativeTo(null);
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		this.setVisible(true);

		// 创建玛丽对象
		mario = new Mario(this);



		// 读取地图,并配置地图
		for (int i = 0; i < map.length; i++) {
			for (int j = 0; j < map[0].length; j++) {
				//读取到的是1,画砖头
				if(map[i][j]==1){
					// x
					brick = new Brick(j*30,i*30,30,30,new ImageIcon("image/brick.png").getImage());
					eneryList.add(brick);
				}
				//读到2画金币
				if(map[i][j]==2){
					coin = new Coin(j*30,i*30,30,30,new ImageIcon("image/coin_brick.png").getImage());
					eneryList.add(coin);
				}
				//读到3画水管
				if(map[i][j]==3){
					pipe = new Pipe(j*30,i*30,60,120,new ImageIcon("image/pipe.png").getImage());
					eneryList.add(pipe);
				}
			}
		}

		mario.start();

		//开启一个线程负责界面的窗体重绘线程
		new Thread(){
			public void run(){
				while(true){
					//重绘窗体
					repaint(); // 自动触发当前窗口中的paint方法
					//检查子弹是否出界
					//checkBoom();
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}.start();


		//设置背景音乐
		new Thread(new Runnable() {
			@Override
			public void run() {
				MusicUtil.playBackground();
			}
		}).start();
	}

	/**
	 * 画窗体
	 * @param g
	 */
	@Override
	public void paint(Graphics g) {
		//利用双缓冲画背景图片和马里奥
		BufferedImage bi =(BufferedImage)this.createImage(this.getSize().width,this.getSize().height);
		//创建画图对象
		Graphics big = bi.getGraphics();
		//画背景
		big.drawImage(bg.img, bg.x, bg.y, null);

		// 开始绘制界面上的敌人。
		for (int i = 0; i < eneryList.size(); i++) {
			Enemy e = eneryList.get(i);
			//绘制敌人
			big.drawImage(e.img, e.x, e.y, e.width, e.height,null);
		}

		//画子弹
		for (int i = 0; i < boomList.size(); i++) {
			Boom b =boomList.get(i);
			Color c =big.getColor();
			big.setColor(Color.red);
			big.fillOval(b.x+=b.speed, b.y, b.width, b.width);
			big.setColor(c);
		}

		//画人物 玛丽自己
		big.drawImage(mario.img, mario.x, mario.y, mario.width, mario.height,null);
		g.drawImage(bi,0,0,null);

	}

	//检查子弹是否出界,出界则从容器中移除,不移除的话,内存会泄漏
	public void checkBoom(){
		for (int i = 0; i < boomList.size(); i++) {
			Boom b = boomList.get(i);
			if(b.x<0 || b.x>800){
				boomList.remove(i);
			}
		}
	}
}

键盘事件监听

package cn.tx.util;

import cn.tx.role.Boom;
import cn.tx.ui.GameFrame;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.ImageIcon;


//键盘按下监听类
public class KeyListener extends KeyAdapter {

    // 接收到了当前主界面:游戏界面
    public GameFrame gf;

    public KeyListener(GameFrame gf) {
        this.gf = gf;
    }

    //键盘监听
    @Override
    public void keyPressed(KeyEvent e) {
        //code是按下键盘的键对应的值
        int code = e.getKeyCode();
        switch (code) {
            //向右走
            case 39:
                gf.mario.right = true; // 信号位
                break;
            //向左走
            case 37:
                gf.mario.left = true;
                break;
            case 66:
                addBoom();
                break;
            //向上跳
            case 38:
                gf.mario.up = true;
                break;
        }
    }

    //添加子弹
    public void addBoom() {
        Boom b = new Boom(gf.mario.x, gf.mario.y + 5, 10);
        if (gf.mario.left) b.speed = -2;
        if (gf.mario.right) b.speed = 2;
        gf.boomList.add(b);
    }

    //键盘释放监听
    @Override
    public void keyReleased(KeyEvent e) {
        int code = e.getKeyCode();
        //释放右键
        if (code == 39) {
            gf.mario.right = false;
            gf.mario.img = new ImageIcon("image/mari1.png").getImage();
        }
        //释放左键
        if (code == 37) {
            gf.mario.left = false;
            gf.mario.img = new ImageIcon("image/mari_left1.png").getImage();
        }
        //释放上键
        if (code == 38) {
            gf.mario.up = false;
        }
    }
}

主方法和事件绑定

import cn.tx.ui.GameFrame;
import cn.tx.util.KeyListener;
/**
  超级玛丽启动类。
 */
public class Run {
	//主函数,程序入口
	public static void main(String[] args) throws Exception {
		GameFrame gf = new GameFrame();
		// 创建监听器对象
		KeyListener kl = new KeyListener(gf);
		// 给窗体添加键盘监听器
		gf.addKeyListener(kl);
	}
}
经验分享 程序员 微信小程序 职场和发展