杂兵马里奥 (转载自cping1982)(地址:http://blog.youkuaiyun.com/cping1982/category/455610.aspx)

Java来做马里奥[3]—杂兵登场 收藏

效果图如下:
 

在ACT类游戏中,你所扮演的角色时常会与各种杂兵发生这样或者那样的冲突,以此来增强游戏性。本回将例举一种Java游戏的杂兵制造方式。

在此例中将原来的 getTileHit改为注入Sprite,以此统一处理角色及杂兵的碰撞。

public  Point getTileHit(Sprite sprite,  double  newX,  double  newY)

Food.java(扮演食物的角色)
package  org.test.mario;

/**
 * <p>
 * Title: LoonFramework
 * </p>
 * <p>
 * Description:食物用类
 * </p>
 * <p>
 * Copyright: Copyright (c) 2008
 * </p>
 * <p>
 * Company: LoonFramework
 * </p>
 * <p>
 * License: http://www.apache.org/licenses/LICENSE-2.0
 * </p>
 * 
 * @author chenpeng
 * @email:ceponline@yahoo.com.cn
 * @version 0.1
 */

public   class  Food  extends  Sprite  {

    public Food(String fileName, double x, double y, Map map) {
        super(fileName, x, y, map);
    }


    public void update() {
        
    }


}


Sandaime.java(扮演杂兵的角色)
package  org.test.mario;

import  java.awt.Point;

/**
 * <p>
 * Title: LoonFramework
 * </p>
 * <p>
 * Description:
 * </p>
 * <p>
 * Copyright: Copyright (c) 2008
 * </p>
 * <p>
 * Company: LoonFramework
 * </p>
 * <p>
 * License: http://www.apache.org/licenses/LICENSE-2.0
 * </p>
 * 
 * @author chenpeng
 * @email:ceponline@yahoo.com.cn
 * @version 0.1
 */

public   class  Sandaime  extends  Sprite  {

    private static final double SPEED = 1;

    private double _vx;

    private double _vy;

    public Sandaime(String filename, double x, double y, Map map) {

        super(filename, x, y, map);
        width = 80;
        height = 75;
        _vx = -SPEED;
        _vy = 0;
    }


    public void update() {
        _vy += 0.1;

        double newX = _x + _vx;

        Point tile = _map.getTileHit(this, newX, _y);
        if (tile == null) {
            _x = newX;
        }
 else {
            if (_vx > 0) {
                _x = Map.tilesToPixels(tile.x) - width;
            }
 else if (_vx < 0) {
                _x = Map.tilesToPixels(tile.x + 1);
            }

            _vx = -_vx;
        }


        double newY = _y + _vy;
        tile = _map.getTileHit(this, _x, newY);
        if (tile == null) {
            _y = newY;
        }
 else {
            if (_vy > 0) {
                _y = Map.tilesToPixels(tile.y) - height;
                _vy = 0;
            }
 else if (_vy < 0) {
                _y = Map.tilesToPixels(tile.y + 1);
                _vy = 0;
            }

        }

    }


}


Role.java(扮演主角)
package  org.test.mario;

import  java.awt.Graphics;
import  java.awt.Point;

/**
 * <p>
 * Title: LoonFramework
 * </p>
 * <p>
 * Description:角色描述及绘制用类
 * </p>
 * <p>
 * Copyright: Copyright (c) 2008
 * </p>
 * <p>
 * Company: LoonFramework
 * </p>
 * 
 * @author chenpeng
 * @email:ceponline@yahoo.com.cn
 * @version 0.1
 */

public   class  Role  extends  Sprite  {

    private double _vx;

    private double _vy;

    private boolean _isFlat;

    private int _dir;

    // 强制跳跃
    private boolean _forceJump;

    final static private int SPEED = 6;

    final static private int JUMP_SPEED = 16;

    final static private int RIGHT = 0;

    final static private int LEFT = 1;

    /**
     * 构造函数,以角色图位置,初始的x、y坐标,地图四项参数创建一个可用的角色
     * 
     * @param filename
     * @param x
     * @param y
     * @param map
     */

    public Role(String filename, double x, double y, Map map) {
        super(filename, x, y, map);
        width=40;
        height=40;
        _vx = 0;
        _vy = 0;
        _isFlat = false;
        _forceJump = false;
        _dir = RIGHT;
    }


    public void setJump(boolean forceJump) {
        _forceJump = forceJump;
    }


    public void stop() {
        _vx = 0;
    }


    public void left() {
        _vx = -SPEED;
        _dir = LEFT;
    }


    public void right() {
        _vx = SPEED;
        _dir = RIGHT;
    }


    public void jump() {
        if (_isFlat || _forceJump) {
            _vy = -JUMP_SPEED;
            _isFlat = false;
            _forceJump = false;
        }

    }


    public void update() {
        // 0.6为允许跳跃的高度限制,反值效果
        _vy += 0.6;

        double newX = _x + _vx;

        Point tile = _map.getTileHit(this, newX, _y);
        if (tile == null) {
            _x = newX;
        }
 else {
            if (_vx > 0) {
                _x = Map.tilesToPixels(tile.x) - width;
            }
 else if (_vx < 0) {
                _x = Map.tilesToPixels(tile.x + 1);
            }

            _vx = 0;
        }


        double newY = _y + _vy;
        tile = _map.getTileHit(this, _x, newY);
        if (tile == null) {
            _y = newY;
            _isFlat = false;
        }
 else {
            if (_vy > 0) {
                _y = Map.tilesToPixels(tile.y) - height;
                _vy = 0;
                _isFlat = true;
            }
 else if (_vy < 0) {
                _y = Map.tilesToPixels(tile.y + 1);
                _vy = 0;
            }

        }

    }


    public void draw(Graphics g, int offsetX, int offsetY) {
        g.drawImage(_image, (int) _x + offsetX, (int) _y + offsetY, (int) _x
                + offsetX + width, (int) _y + offsetY + height, _count * width,
                _dir * height, _count * width + width, _dir * height + height,
                null);
    }

}


Sprite.java(抽象的精灵类)
package  org.test.mario;

import  java.awt.Graphics;
import  java.awt.Image;
import  java.awt.Rectangle;

import  org.loon.framework.game.image.Bitmap;

/**
 * <p>
 * Title: LoonFramework
 * </p>
 * <p>
 * Description:精灵类(为了批量制造角色,将Role中通用设定抽象成此类)
 * </p>
 * <p>
 * Copyright: Copyright (c) 2008
 * </p>
 * <p>
 * Company: LoonFramework
 * </p>
 * <p>
 * License: http://www.apache.org/licenses/LICENSE-2.0
 * </p>
 * 
 * @author chenpeng
 * @email:ceponline@yahoo.com.cn
 * @version 0.1
 */

public   abstract   class  Sprite  {
    // 坐标
    protected double _x;

    protected double _y;

    // 宽
    protected int width;

    // 高
    protected int height;

    // 图像
    protected Image _image;

    // 步数
    protected int _count;

    // 地图
    protected Map _map;

    /**
     * 构造函数,以角色图位置,初始的x、y坐标,地图四项参数创建一个可用的角色
     *  
     * @param fileName
     * @param _x
     * @param _y
     * @param map
     */

    public Sprite(String fileName,double _x, double _y, Map map) {
        this._x = _x;
        this._y = _y;
        this._map = map;

        width = 32;
        height = 32;

        loadImage(fileName);

        _count = 0;

        AnimationThread thread = new AnimationThread();
        thread.start();
    }


    public abstract void update();

    public void draw(Graphics g, int offsetX, int offsetY) {
        g.drawImage(_image, (int) _x + offsetX, (int) _y + offsetY, (int) _x
                + offsetX + width, (int) _y + offsetY + height, _count * width,
                0, _count * width + width, height, null);
    }


    public boolean isHit(Sprite sprite) {
        Rectangle playerRect = new Rectangle((int) _x, (int) _y, width, height);
        Rectangle spriteRect = new Rectangle((int) sprite.getX(), (int) sprite
                .getY(), sprite.getWidth(), sprite.getHeight());
        // 判定两者边框是否相交
        if (playerRect.intersects(spriteRect)) {
            return true;
        }


        return false;
    }


    public double getX() {
        return _x;
    }


    public double getY() {
        return _y;
    }


    public int getWidth() {
        return width;
    }


    public int getHeight() {
        return height;
    }


    private void loadImage(String filename) {
        _image = new Bitmap(filename).getImage();
    }


    private class AnimationThread extends Thread {
        public void run() {
            while (true) {
                // 换算步数
                if (_count == 0) {
                    _count = 1;
                }
 else if (_count == 1) {
                    _count = 0;
                }

                // 动作更替延迟
                try {
                    Thread.sleep(300);
                }
 catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }

        }

    }


    public void setHeight(int height) {
        this.height = height;
    }


    public void setWidth(int width) {
        this.width = width;
    }


}


Map.java(地图描述)
package  org.test.mario;

import  java.awt.Graphics;
import  java.awt.Image;
import  java.awt.Point;
import  java.util.LinkedList;

import  org.loon.framework.game.image.Bitmap;

/**
 * <p>
 * Title: LoonFramework
 * </p>
 * <p>
 * Description:地图绘制及描述用类
 * </p>
 * <p>
 * Copyright: Copyright (c) 2008
 * </p>
 * <p>
 * Company: LoonFramework
 * </p>
 * 
 * @author chenpeng
 * @email:ceponline@yahoo.com.cn
 * @version 0.1
 */

public   class  Map  {

    // 在以前的blog文章中我介绍过,游戏开发中通常以数组描述地图
    // 此处1描绘为一个障碍物,0描绘为一个可通行空间
    final static public int TILE_SIZE = 32;

    final static public int ROW = 20;

    final static public int COL = 30;

    final static public int WIDTH = TILE_SIZE * COL;

    final static public int HEIGHT = TILE_SIZE * ROW;

    final static public double GRAVITY = 0.6;
    
    //缓存精灵的list
    private LinkedList sprites;

    // 地图描述
    final static private int[][] map = {
            { 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, 2 }
,
            { 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 }
,
            { 2, 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 }
,
            { 1, 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 }
,
            { 1, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2,
                    2, 2, 2, 2, 2, 2, 2, 1 }
,
            { 1, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 1 }
,
            { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 1 }
,
            { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 1 }
,
            { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0,
                    0, 0, 0, 0, 0, 0, 0, 1 }
,
            { 1, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 1, 2, 0,
                    0, 0, 0, 0, 0, 0, 0, 1 }
,
            { 1, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 1, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 1 }
,
            { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 1 }
,
            { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 1 }
,
            { 1, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 4, 3, 3, 1, 2, 2,
                    0, 0, 0, 0, 0, 0, 3, 1 }
,
            { 1, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 1, 0, 0,
                    0, 0, 0, 0, 0, 0, 2, 1 }
,
            { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 1 }
,
            { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 1 }
,
            { 1, 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 }
,
            { 1, 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 }
,
            { 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
                    2, 2, 2, 2, 2, 2, 2, 1 }
 }
;
    

    final static private Image tile = new Bitmap("./tile_0.gif").getImage();

    final static private Image tile2 = new Bitmap("./tile_1.gif").getImage();

    /**
     * 构造函数
     * 
     */

    public Map() {
        //精灵list
        sprites=new LinkedList();
        //注入兵粮丸
         for (int i = 0; i < ROW; i++) {
             for (int j = 0; j < COL; j++) {
                 switch (map[i][j]) {
                     case 3:
                           sprites.add(new Food("./food.gif",tilesToPixels(j), tilesToPixels(i),this));
                         break;
                     case 4:
                         sprites.add(new Sandaime("./sdm.gif",tilesToPixels(j), tilesToPixels(i),this));
                       break;
                 }

             }

         }

    }


    public void draw(Graphics g, int offsetX, int offsetY) {
        int firstTileX = pixelsToTiles(-offsetX);
        int lastTileX = firstTileX + pixelsToTiles(Main._WIDTH) + 1;
        lastTileX = Math.min(lastTileX, COL);
        int firstTileY = pixelsToTiles(-offsetY);
        int lastTileY = firstTileY + pixelsToTiles(Main._HEIGHT) + 1;
        lastTileY = Math.min(lastTileY, ROW);

        for (int i = firstTileY; i < lastTileY; i++) {
            for (int j = firstTileX; j < lastTileX; j++) {
                // 转换map标识
                switch (map[i][j]) {
                
                case 1: // 绘制砖地

                    g.drawImage(tile, tilesToPixels(j) + offsetX,
                            tilesToPixels(i) + offsetY, null);
                    break;
                case 2: //绘制草地
                    g.drawImage(tile2, tilesToPixels(j) + offsetX,
                            tilesToPixels(i) + offsetY, null);
                    break;

                }

            }

        }

    }


    /**
     * 换算角色与地板的撞击,并返回Point用以描述新的x,y
     * 
     * @param sprite
     * @param newX
     * @param newY
     * @return
     */

    public Point getTileHit(Sprite sprite, double newX, double newY) {

        newX = Math.ceil(newX);
        newY = Math.ceil(newY);

        double fromX = Math.min(sprite.getX(), newX);
        double fromY = Math.min(sprite.getY(), newY);
        double toX = Math.max(sprite.getX(), newX);
        double toY = Math.max(sprite.getY(), newY);

        int fromTileX = pixelsToTiles(fromX);
        int fromTileY = pixelsToTiles(fromY);
        int toTileX = pixelsToTiles(toX + sprite.getWidth() - 1);
        int toTileY = pixelsToTiles(toY + sprite.getHeight() - 1);

        for (int x = fromTileX; x <= toTileX; x++) {
            for (int y = fromTileY; y <= toTileY; y++) {

                if (x < 0 || x >= COL) {
                    return new Point(x, y);
                }

                if (y < 0 || y >= ROW) {
                    return new Point(x, y);
                }

                if (map[y][x] == 1 || map[y][x] == 2) {
                    return new Point(x, y);
                }

            }

        }


        return null;
    }


    /**
     * 将Tiles转为Pixels
     * 
     * @param pixels
     * @return
     */

    public static int pixelsToTiles(double pixels) {
        return (int) Math.floor(pixels / TILE_SIZE);
    }


    /**
     * 将Pixels转为Tiles
     * 
     * @param pixels
     * @return
     */

    public static int tilesToPixels(int tiles) {
        return tiles * TILE_SIZE;
    }


    /**
     * 返回Sprite list
     * @return
     */

    public LinkedList getSprites() {
        return sprites;
    }


    public void setSprites(LinkedList sprites) {
        this.sprites = sprites;
    }

}


Main.java(部署及运行)
package  org.test.mario;

import  java.awt.Color;
import  java.awt.Frame;
import  java.awt.Graphics;
import  java.awt.Image;
import  java.awt.Panel;
import  java.awt.event.KeyEvent;
import  java.awt.event.KeyListener;
import  java.awt.event.WindowAdapter;
import  java.awt.event.WindowEvent;
import  java.util.Iterator;
import  java.util.LinkedList;

import  org.loon.framework.game.image.Bitmap;

/**
 * <p>
 * Title: LoonFramework
 * </p>
 * <p>
 * Description:
 * </p>
 * <p>
 * Copyright: Copyright (c) 2008
 * </p>
 * <p>
 * Company: LoonFramework
 * </p>
 * 
 * @author chenpeng
 * @email:ceponline@yahoo.com.cn
 * @version 0.1
 */

public   class  Main  extends  Panel  implements  Runnable, KeyListener  {

    /**
     * 
     */

    private static final long serialVersionUID = 1L;

    public static final int _WIDTH = 640;

    public static final int _HEIGHT = 480;

    private Map _map;

    private Role _role;

    private Thread _sleep;

    private Image _screen = null;

    private Graphics _graphics = null;

    // 方向控制,由于是自然落体所以没有down
    private boolean LEFT;

    private boolean RIGHT;

    private boolean UP;

    // 底层背景
    final static private Image back = new Bitmap("./雕像.png").getImage();

    public Main() {
        setSize(_WIDTH, _HEIGHT);
        setFocusable(true);
        _screen = new Bitmap(_WIDTH, _HEIGHT).getImage();
        _graphics = _screen.getGraphics();
        _map = new Map();
        // 设置扮演的角色
        _role = new Role("role.gif", 190, 40, _map);

        // 监听窗体
        addKeyListener(this);

        // 启动线程
        _sleep = new Thread(this);
        _sleep.start();
    }


    public void gameOver() {

        _map = new Map();

        _role = new Role("role.gif", 190, 40, _map);
    }


    /**
     * 运行
     */

    public void run() {
        while (true) {
            // 改变方向
            if (LEFT) {
                _role.left();
            }
 else if (RIGHT) {
                _role.right();
            }
 else {
                _role.stop();
            }

            if (UP) {
                _role.jump();
            }

            _role.update();

            LinkedList sprites = _map.getSprites();

            for (Iterator it = sprites.iterator(); it.hasNext();) {
                // 还原为sprite
                Sprite sprite = (Sprite) it.next();
                // 变更精灵状态
                sprite.update();

                // 碰撞检测
                if (_role.isHit(sprite)) {
                    // 对象检测,为兵粮丸时
                    if (sprite instanceof Food) {
                        Food coin = (Food) sprite;
                        // 删除对象
                        // it.remove();
                        sprites.remove(coin);
                        break;
               //为三代目时
                    }
else if (sprite instanceof Sandaime) {  
                        Sandaime sdm = (Sandaime)sprite;
                        if ((int)_role.getY() < (int)sdm.getY()) {
                            sprites.remove(sdm);
                            _role.setJump(true);
                            _role.jump();
                            break;
                        }
 else {
                            gameOver();
                        }

                }

            }

            }

            repaint();
            try {
                Thread.sleep(20);
            }
 catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

    }


    public void update(Graphics g) {
        paint(g);
    }


    public void paint(Graphics g) {

        _graphics.setColor(Color.BLACK);
        _graphics.fillRect(0, 0, _WIDTH, _HEIGHT);
        _graphics.drawImage(back, 0, 0, this);
        int offsetX = _WIDTH / 2 - (int) _role.getX();

        offsetX = Math.min(offsetX, 0);
        offsetX = Math.max(offsetX, _WIDTH - Map.WIDTH);

        int offsetY = _HEIGHT / 2 - (int) _role.getY();

        offsetY = Math.min(offsetY, 0);
        offsetY = Math.max(offsetY, _HEIGHT - Map.HEIGHT);

        _map.draw(_graphics, offsetX, offsetY);

        _role.draw(_graphics, offsetX, offsetY);
        // 遍历精灵对象并绘制
        LinkedList sprites = _map.getSprites();

        for (Iterator it = sprites.iterator(); it.hasNext();) {
            Sprite sprite = (Sprite) it.next();
            sprite.draw(_graphics, offsetX, offsetY);
        }

        g.drawImage(_screen, 0, 0, null);
    }


    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
        if (key == KeyEvent.VK_LEFT) {
            LEFT = true;
        }

        if (key == KeyEvent.VK_RIGHT) {
            RIGHT = true;
        }

        if (key == KeyEvent.VK_UP) {
            UP = true;
        }

    }


    public void keyReleased(KeyEvent e) {
        int key = e.getKeyCode();
        if (key == KeyEvent.VK_LEFT) {
            LEFT = false;
        }

        if (key == KeyEvent.VK_RIGHT) {
            RIGHT = false;
        }

        if (key == KeyEvent.VK_UP) {
            UP = false;
        }

    }


    public void keyTyped(KeyEvent e) {
    }


    public static void main(String[] args) {
        Frame frame = new Frame();
        frame.setTitle("Java来做马里奥(4)—杂兵登场");
        frame.setSize(_WIDTH, _HEIGHT + 20);
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.add(new Main());
        frame.setVisible(true);
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }

        }
);
    }


}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值