Java究竟怎么玩?

天地程序已定棋,人间大数待变局

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
效果图如下:


孔丘仲尼先生曾经曰过“斋必变食,居必迁坐。食不厌精,脍不厌细”,被捧上天的圣人尚且如此,游戏中的角色更不例外,在ACT游戏中举凡加分、恢复体力、发动必杀技种种,都离不开“食物”的伟大功绩。

我们大家都知道,在典型的平面2D ACT游戏中,是使用层级的概念来描绘整个画面的,最底层的背景一般不参与游戏进程,而由再上一级的前景来承载角色及限制角色活动区域。所有置于前景之上的本质上都是活动精灵,只是扮演的角色不同,才会发生不同的作用与效果。

比如,在本例中我将Sprite抽象出来,而由Role及Food分别继承,他们的命运就变成了吃与被吃的关系……

代码如下:

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

            }

        }

    }


}


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


}


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;

    
final static public int WIDTH = 40;

    
final static public int HEIGHT = 40;

    
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);
        _vx 
= 0;
        _vy 
= 0;
        isFlat 
= false;
        _dir 
= RIGHT;
    }


    
public void stop() {
        _vx 
= 0;
    }


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


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


    
public void jump() {
        
if (isFlat) {
            _vy 
= -JUMP_SPEED;
            isFlat 
= 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);
    }

}


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 = {
            
0000000000000000000000,
                
00000002 }
,
            
0000000000000000000000,
                    
00000001 }
,
            
2000000000000000000000,
                    
00000001 }
,
            
1000000000000000000000,
                    
00000001 }
,
            
1333000000000000000222,
                    
22222221 }
,
            
1222000000000000000100,
                    
00000001 }
,
            
1000000000000000000100,
                    
00000001 }
,
            
1000000000000000000100,
                    
00000001 }
,
            
1000000000000000000130,
                    
00000001 }
,
            
1000000000000000000120,
                    
00000001 }
,
            
1000002222222200000100,
                    
00000001 }
,
            
1000000000000000000100,
                    
00000001 }
,
            
1000000000000000000100,
                    
00000001 }
,
            
1333330000000033333122,
                    
00000031 }
,
            
1222220000000022222100,
                    
00000021 }
,
            
1000000000000000000100,
                    
00000001 }
,
            
1000000000000000000100,
                    
00000001 }
,
            
1000000000000000000000,
                    
00000001 }
,
            
1000000000000000000000,
                    
00000001 }
,
            
1222222222222222222222,
                    
22222221 }
 }
;
    

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

             }

         }

    }


    
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 player
     * 
@param newX
     * 
@param newY
     * 
@return
     
*/

    
public Point getTileHit(Role player, double newX, double newY) {

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

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

        
int fromTileX = pixelsToTiles(fromX);
        
int fromTileY = pixelsToTiles(fromY);
        
int toTileX = pixelsToTiles(toX + Role.WIDTH - 1);
        
int toTileY = pixelsToTiles(toY + Role.HEIGHT - 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"19040, _map);

        
// 监听窗体
        addKeyListener(this);

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


    
/**
     * 运行
     
*/

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

                }

            }


            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(
00, _WIDTH, _HEIGHT);
        _graphics.drawImage(back, 
00this);
        
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, 
00null);
    }


    
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来做马里奥(3)—食不厌精");
        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);
            }

        }
);
    }


}

posted on 2008-03-09 11:12  cping  阅读(160)  评论(0编辑  收藏  举报