根据我们之前的工作,StartObject已经被成功构建出来,那么,其余的GameObject只要照猫画虎,继承或重写几个方法,其他东西很快就能完成。
另外对于Player,我们采用解谜游戏比较经典的画法,让人物处于屏幕中心,让地图在屏幕上滚动,而人物只需要在原地做出走动的动画就好。
首先是加载界面LoadingObject。
package model.start;
import java.awt.Graphics;
import java.awt.Image;
import java.io.IOException;
import javax.imageio.ImageIO;
import model.GameObject;
import model.over.GameOverObject;
import model.rpg.RpgObject;
import model.rpg.SaveData;
import model.rpg.map.MapObjects.auto.Story2;
/**
* 缓冲功能,在加载RpgObject类之前使用此类,避免游戏看上去变卡的现象。
* */
public class LoadingObject extends GameObject {
private int wait = 0;
private static Image gameover;
private SaveData save;
static {
try {
gameover = ImageIO.read(GameOverObject.class.getClassLoader().getResourceAsStream("source/loading.png"));
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 构造方法。
* 当传入null时即认为是新的开始,没有存档
* */
public LoadingObject(SaveData save) {
this.save = save;
}
@Override
protected void keyResponse() {
}
/**
* 设置int变量,当变量达到条件时,
* 说明Load经过了足够时间,
* 将new出RpgObject
* */
@Override
public void draw(Graphics g) {
wait++;
if (wait == 20) {
die();
}
g.drawImage(gameover, 0, 0, null);
}
/**
* 判断目前是读档还是新的游戏,然后执行不同操作
* */
@Override
public void die() {
if(save == null)
new RpgObject();
else
new RpgObject(save);
}
}
其中,SaveData是一种存档的方式,读者暂时不用深究。当Loading传入了存档时,游戏即加载存档,开始RPG界面;否则开始新的游戏,从零开始启动RpgObject。
其次是RPG界面。我们知道,解谜游戏,或者说RPG游戏中很重要的两个部分:地图和人物。对于这两个玩意,我们可以类似GameObject的道理,不替换现有的GameObject,而是在GameObject中画图,即RpgObject的主要职能即执行地图和Player的paint方法。
由于地图是个复杂的东西,我们现在先只尝试构造Player类。
先放上目前的RpgObject,其中含有一个ImageSets类,这个类用于读取所有的图片文件,只需要传入一个数字,就可以根据数字返回一个图片对象。
package model.rpg;
import java.awt.Graphics;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import model.Game;
import model.GameObject;
import model.start.ItemObject;
import view.Control;
import view.ImageSets;
import view.Lib;
/**
* 游戏运行时主要重画此类即内部的地图和人物,
* 这个类中应存在一个saveData类,
* 里面设置ArrayList Map 、 Item 和currentMap,还应该存在一个ObjectWriter负责生成saveData的文件,即存档,
* 为此,此类应拥有一个带有saveData形参的构造方法,负责传入LoadObject传入的saveData
* */
public class RpgObject extends GameObject{
//记录目前状态
private boolean isRunning = false,isStanding = true;
protected Direction direction = Direction.R;
public RpgObject(){
super.musicStart("钟声.wav");
}
@Override
protected void keyResponse() {
//走、跑和静止操作,默认人物为走动
isStanding = false;
if(Control.UP){
direction = Direction.U;
}
else if(Control.DOWN){
direction = Direction.D;
}
else if(Control.LEFT){
direction = Direction.L;
}
else if(Control.RIGHT){
direction = Direction.R;
}
else {
isStanding = true;
}
if(Control.Z){
isRunning = true;
}
else{
isRunning = false;
}
}
/**
* 重画操作。
* 检查各种东西,包括:
* 镜子的反光,是否达成条件、调查物品、门的检查、Auto模块的检查。(之后会加上,现在还没有)
* */
public void paint(Graphics g){
//清屏操作
g.clearRect(0, 0, Lib.gameWIDTH, Lib.gameHEIGHT);
//站立不动时调用
if(isStanding){
Player.getInstance().draw(g,direction);
//最后加上阴影
g.drawImage(ImageSets.getImg(52), 0, 0, null);
}
//走动时调用
else{
Player.getInstance().draw(g,isRunning,direction);
g.drawImage(ImageSets.getImg(52), 0, 0, null);
}
}
@Override
public void draw(Graphics g) {
try{
isStanding = true;
paint(g);
}catch(Exception e){
e.getStackTrace();
}
}
@Override
public void die() {
super.musicStop();
}
}
这样一来,RpgObject对Player的调用基本完成,接下来需要构建Player。
仔细想想,Player也没什么很必要的属性,几个图片,一个物品栏,四个方向,还有走动状态就差不多了。对于方向,我们简单构建一个Direction的枚举。
package model.rpg;
/**
* 人物以及事件触发的方向
* */
public enum Direction {
U,D,L,R
}
然后开始编写Player。对于Player的物品栏目前暂且不提,首先读取Player需要的图片
两张图片,读取后使用BufferedImage的subImage方法可以获得整个图片的一部分,我们把它放进图片数组中。
//图片数组,读入两张图,分成32个小图
private BufferedImage walk,run;
private BufferedImage[] walku = new BufferedImage[4];
private BufferedImage[] walkd = new BufferedImage[4];
private BufferedImage[] walkl = new BufferedImage[4];
private BufferedImage[] walkr = new BufferedImage[4];
private BufferedImage[] runu = new BufferedImage[4];
private BufferedImage[] rund = new BufferedImage[4];
private BufferedImage[] runl = new BufferedImage[4];
private BufferedImage[] runr = new BufferedImage[4];
/**
* 构造方法,
* 读取图片,同时意味着这个对象不能被存档写入文件。(Image没有序列化,不能跟随写入文件)
* */
public Player(){
try {
walk = ImageIO.read(Player.class.getClassLoader().getResourceAsStream("source/rpg/player/walk.png"));
run = ImageIO.read(Player.class.getClassLoader().getResourceAsStream("source/rpg/player/run.png"));
} catch (IOException e) {
e.printStackTrace();
}
for(int i = 0;i<walku.length;i++){
walku[i] = walk.getSubimage(i*(walk.getWidth()/4), 3*(walk.getHeight()/4), walk.getWidth()/4, walk.getHeight()/4);
}
for(int i = 0;i<walkd.length;i++){
walkd[i] = walk.getSubimage(i*(walk.getWidth()/4), 0, walk.getWidth()/4, walk.getHeight()/4);
}
for(int i = 0;i<walkl.length;i++){
walkl[i] = walk.getSubimage(i*(walk.getWidth()/4), walk.getHeight()/4, walk.getWidth()/4, walk.getHeight()/4);
}
for(int i = 0;i<walkr.length;i++){
walkr[i] = walk.getSubimage(i*(walk.getWidth()/4), walk.getHeight()/2, walk.getWidth()/4, walk.getHeight()/4);
}
for(int i = 0;i<runu.length;i++){
runu[i] = run.getSubimage(i*(run.getWidth()/4), 3*(run.getHeight()/4), run.getWidth()/4, run.getHeight()/4);
}
for(int i = 0;i<rund.length;i++){
rund[i] = run.getSubimage(i*(run.getWidth()/4), 0, run.getWidth()/4, run.getHeight()/4);
}
for(int i = 0;i<runl.length;i++){
runl[i] = run.getSubimage(i*(run.getWidth()/4), run.getHeight()/4, run.getWidth()/4, run.getHeight()/4);
}
for(int i = 0;i<runr.length;i++){
runr[i] = run.getSubimage(i*(run.getWidth()/4), run.getHeight()/2, run.getWidth()/4, run.getHeight()/4);
}
x = Lib.gameWIDTH/2-walk.getWidth()/8;
y = Lib.gameHEIGHT/2-walk.getHeight()/8;
}
图片读取完成后,剩下的就是把他们画出来。我们需要几个参数:人物的方向,人物是走动、跑动还是静止。有了这些,我们可以把人物画出来。
/**人物移动时的绘制,包括是不是在奔跑*/
public void draw(Graphics g,boolean isRun,Direction playerDirection) {
direction = playerDirection;
if(!isRun){
if(direction==Direction.U)
g.drawImage(walku[imgChange], x, y, null);
if(direction==Direction.D)
g.drawImage(walkd[imgChange], x, y, null);
if(direction==Direction.L)
g.drawImage(walkl[imgChange], x, y, null);
if(direction==Direction.R)
g.drawImage(walkr[imgChange], x, y, null);
walkWait++;
if(walkWait==3){
walkWait = 0;
imgChange++;
}
}
else{
if(direction==Direction.U)
g.drawImage(runu[imgChange], x, y, null);
if(direction==Direction.D)
g.drawImage(rund[imgChange], x, y, null);
if(direction==Direction.L)
g.drawImage(runl[imgChange], x, y, null);
if(direction==Direction.R)
g.drawImage(runr[imgChange], x, y, null);
runWait++;
if(runWait==2){
runWait = 0;
imgChange++;
}
}
if(imgChange==4)
imgChange = 0;
}
/**人物静止不动时的绘制*/
public void draw(Graphics g, Direction direction) {
if(direction==Direction.U)
g.drawImage(walku[0], x, y, null);
if(direction==Direction.D)
g.drawImage(walkd[0], x, y, null);
if(direction==Direction.L)
g.drawImage(walkl[0], x, y, null);
if(direction==Direction.R)
g.drawImage(walkr[0], x, y, null);
}
public Direction getDirection(){
return direction;
}
public void clearDirection(){
direction = Direction.R;
}