Java究竟怎么玩?

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

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
记得在红白机(FC)年代,还刚刚上小学的我对马里奥、冒险岛、洛克人、魂斗罗等游戏几乎可说是痴迷,每天放学回家就是想去游戏,就是要通关,就是想和关底论个胜负高低。

许多年过去了,沧海桑田,FC曾经的荣耀早已不再,只留下我们对曾经少年时的点点记忆。即使当时在FC上看上去多么复杂,多么高不可攀的游戏,在当今,即使最普通的程序员都可以轻易实现。

本着向经典学习、向经典致敬的心情,我也准备用Java在PC机再现当年马里奥的风采。

下面我在代码中所演示的,是一个简单的ACT游戏动作及地图构成原型。

Map.java
package org.test.mario;

import java.awt.Color;
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 Map {

    
// 在以前的blog文章中我介绍过,游戏开发中通常以数组描述地图
    
// 此处1描绘为一个障碍物,0描绘为一个可通行空间
    final static private int[][] map = {
            
11111111111111111111 },
            
10000000000000000001 },
            
10000000000000000001 },
            
10000000000000000001 },
            
10000000000000001111 },
            
10000011111111000001 },
            
10000000000000000001 },
            
10000000000000000001 },
            
10000000000000000001 },
            
11111111100000111111 },
            
10000000000000000001 },
            
10000000000000000001 },
            
10000000000000000001 },
            
10000000000000000001 },
            
11111111111111111111 } }
;

    
// 地面瓦片的宽度
    final static private int TILE_SIZE = 32;

    
// 行
    final static private int ROW = 15;

    
// 列
    final static private int COL = 20;

    
/**
     * 构造函数
     * 
     
*/

    
public Map() {
    }


    
public void draw(Graphics g) {
         g.setColor(Color.ORANGE);
        
for (int i = 0; i < ROW; i++{
            
for (int j = 0; j < COL; j++{
                
switch (map[i][j]) {
                
case 1:
                    g.fillRect(tilesToPixels(j), tilesToPixels(i), TILE_SIZE,
                            TILE_SIZE);
                    
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);

        
// 返回Point,用以描述x,y坐标点
        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{
                    
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;
    }

}


Role.java

package org.test.mario;

import java.awt.Color;
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 {

    
// 坐标的x,y
    private double _x;

    
private double _y;

    
// 显示的x,_y
    private double _vx;

    
private double _vy;

    
// 是否在平地
    private boolean isFlat;

    
// 自定义的地图描述类
    private Map _map;

    
// 角色宽
    final static public int WIDTH = 32;

    
// 角色高
    final static public int HEIGHT = 32;

    
// 移动速度
    final static public int SPEED = 6;

    
// 跳越速度
    final static public int JUMP_SPEED = 25;

    
/**
     * 构造函数,注入初始的角色x,y及map
     * 
     * 
@param _x
     * 
@param _y
     * 
@param _map
     
*/

    
public Role(double x, double _y, Map _map) {
        
this._x = x;
        
this._y = _y;
        
this._map = _map;
        _vx 
= 0;
        _vy 
= 0;
        isFlat 
= false;
    }


    
/**
     * 停止动作
     * 
     
*/

    
public void stop() {
        _vx 
= 0;
    }


    
/**
     * 向左
     * 
     
*/

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


    
/**
     * 向右
     * 
     
*/

    
public void right() {
        _vx 
= SPEED;
    }


    
/**
     * 跳越动作
     * 
     
*/

    
public void jump() {
        
// 当角色立于平地时
        if (isFlat) {
            _vy 
= -JUMP_SPEED;
            isFlat 
= false;
        }

    }


    
/**
     * 变更位置
     * 
     
*/

    
public void update() {
        
// 加入偏差值
        _vy += 1.0;

        
// 获得新的newX
        double newX = _x + _vx;

        
// 获得地板x,_y
        Point tile = _map.getTileHit(this, newX, _y);
        
// 不存在时则默认为newX
        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;
            }

        }

    }


    
/**
     * 将角色绘制于指定Graphics上
     * 
     * 
@param g
     
*/

    
public void draw(Graphics g) {
        
// 目前以一个红色方块代替
        g.setColor(Color.RED);
        g.fillRect((
int) _x, (int) _y, WIDTH, HEIGHT);
    }


    
public double getX() {
        
return _x;
    }


    
public double getY() {
        
return _y;
    }


}


启动类: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 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;

    
public Main() {
        setSize(_WIDTH, _HEIGHT);
        setFocusable(
true);
        _screen 
= new Bitmap(_WIDTH, _HEIGHT).getImage();
        _graphics 
= _screen.getGraphics();
        _map 
= new Map();
        
        _role 
= new Role(10032, _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();
            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);
        _map.draw(_graphics);
        _role.draw(_graphics);
        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来做马里奥(1)—让精灵舞动");
        frame.setSize(_WIDTH, _HEIGHT);
        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);
            }

        }
);
    }


}


运行效果如下图:


现在开始,我会在blog中逐步构建马里奥中的一关,有关心java pc游戏开发者敬请留意。
posted on 2008-02-26 10:47  cping  阅读(341)  评论(1编辑  收藏  举报