android 2D游戏开发,引擎设计(三) 实验脚本编写与纸娃娃系统

2D纸娃娃

在以前没有采用纸娃娃系统的游戏中,游戏角色的所有外观都是游戏 美工预先制作好的,因此数量有限,且占用较多资源( 内存硬盘空间),比如为了实现同一角色拿着不同武器奔跑的图像,开发者不得不绘制两套奔跑图,分别加上不同的武器。而实际上,变化的只是武器,这样多的一组奔跑图像就是多余的。而纸娃娃系统就是针对此设计的。
在纸娃娃系统中,角色的每个动作,每套服装,武器,都只有一套,而且是独立的。引擎可以根据不同的需要,临时将几组图像拼装到一起,进而形成变化丰富的角色外观。例如同时角色奔跑,可以在手部绘制武器A,也可以绘制武器B。
为了丰富角色的动作,2D纸娃娃有时也将角色的头,身,手,脚等部位的动作都分开绘制,在2D图像基础上展示了更多变的角色动作。
2D纸娃娃系统比起普通游戏的最大优势就在于,数量相同的角色外观下,占用更少的资源,角色的外观变化即时展示。而这样的系统在 编程稍稍复杂。


纸娃娃系统并不复杂,它的难度如以下这个问题。

桌子上有一个碗,碗里面有个杯子,移动了一下桌子,问杯子的坐标?  (已知桌子的坐标,已知碗在桌子中的坐标)。

为了实现纸娃娃这种嵌套系统,我们需要引入相对坐标和绝对坐标的概念。


上回说的接口扮演者Act 和类演员Actor,我们添加新方法

        /**获得绝对坐标X*/
	public double getAbsoluteX();
	/**获得绝对坐标Y*/
	public double getAbsoluteY();
	/**获得相对于容器坐标X*/
	public double getX() ;
	/**设置相对于容器坐标X*/
	public void setX(double x);
	/**获得相对于容器坐标Y*/
	public double getY();
	/**设置相对于容器坐标Y*/
	public void setY(double y)

//获得绝对坐标方法

	public double getAbsoluteX() {
		//如果容器不为空,          绝对坐标X=容器的绝对坐标X加相对坐标X
		return getActParent()== null ? getX() : getActParent().getAbsoluteX() + getX();
	}

	public double getAbsoluteY() {
		//如果容器不为空,          绝对坐标Y=容器的绝对坐标Y加相对坐标Y
		return getActParent() == null ? getY() : getActParent().getAbsoluteY() + getY();
	}

绘制内部子扮演者方法

	/** 绘制当前 */
	public void draw(GameCanvas canvas, IAct thisAct) {
		if (getModel() != null)
			getModel().draw(canvas, thisAct);
		drawChild(canvas);
	};
	//绘制子扮演者
	public void drawChild(GameCanvas canvas) {
		if (childList != null) {
			Iterator<IAct> it = childList.iterator();
			while (it.hasNext()) {
				IAct act = it.next();
				act.draw(canvas, act);
				if (act.getScript() != null)
					act.getScript().timeScript(act.getGameStage(), canvas, act);
			}
		}
	}


package game.engines.inteface;

import java.util.HashMap;


import game.engines.Direction;
import game.engines.GameCanvas;
import game.engines.GameStage;
import game.engines.Model;
import game.engines.Script;

/**
 * 扮演者
 */
public interface IAct {
	/**将本身作为容器添加扮演者 被添加的扮演者绝对坐标将以容器相对坐标来计算*/
	public void addAct(IAct act);
	/**移除扮演者*/
	public void removeAct(IAct act);
	/**获得该扮演者上层容器*/
	public IAct getActParent();
	/**获得该扮演者上层容器*/
	public void setActParent(IAct act);
	/**绘制该版本扮演者
	 * 该方法同时
	 * @see drawChild
	 * */
	public void draw(GameCanvas canvas,IAct act);
	/**绘制扮演者容器中的子扮演者*/
	public void drawChild(GameCanvas canvas);
	/**设置扮演者脚本*/
	public void setScript(Script script);
	/**获得扮演者脚本*/
	public Script getScript();
	/**获得扮演者脚本*/
	public HashMap<String,Object> getAttributes();
	/**获得设置属性集*/
	public void setAttributes(HashMap<String, Object> attributes);
	/**获得设置属性*/
	public void setAttributes(String key,Object value);
	
	/**获得绝对坐标X*/
	public double getAbsoluteX();
	/**获得绝对坐标Y*/
	public double getAbsoluteY();
	/**获得相对于容器坐标X*/
	public double getX() ;
	/**设置相对于容器坐标X*/
	public void setX(double x);
	/**获得相对于容器坐标Y*/
	public double getY();
	/**设置相对于容器坐标Y*/
	public void setY(double y);
	
	/**获得宽度属性*/
	public int getWidth();
	/**设置宽度属性*/
	public void setWidth(int width) ;
	/**获得高度属性*/
	public int getHeight();
	/**设置高度属性*/
	public void setHeight(int height);
	/**获得移动速度*/
	public double getMove();
	/**设置移动速度*/
	public void setMove(double move);
	/**获得造型*/
	public Model getModel();
	/**设置造型*/
	public void setModel(Model model);
	
	/**设置方向*/
	public void setDirection(Direction direction);
	/**获得方向*/
	public Direction getDirection();
	/**获得所在舞台*/
	public GameStage getGameStage();
	/**设置所在舞台*/
	public void setGameStage(GameStage stage);
	
}



利用纸娃娃系统来编写的太阳系。如图 太阳(黄色) 地球(青色)  月球(蓝色) 卫星(灰色) 

如果将太阳系看作为一个整体你可以想象这用java需要多少行代码。

实际上只需要很少量的代码就足以完成它。


代码示例

package game.demo;

import android.graphics.Color;
import game.engines.Actor;
import game.engines.GameCanvas;
import game.engines.GameStage;
import game.engines.Model;
import game.engines.Script;
import game.engines.action.CircleMoveScript;

import game.engines.inteface.IAct;

/**
 * 游戏剧情脚本
 */
public class MyGameScript extends Script {
	/**
	 * 时间脚本
	 * */
	public void timeScript(GameStage stage, GameCanvas canvas, IAct act) {
        //新建一只精灵
		Actor sun= new Actor();
	  //新建一个造型.
		Model circle = new Model() {
			@Override
			public void draw(GameCanvas canvas, IAct thisAct) {
				try {
					//获得颜色属性
					int color = (Integer) thisAct.getAttributes().get("Color");
					canvas.getPaint().setColor(color);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				// paint.setStyle(Paint.Style.STROKE);
				//在绝对坐标上绘制一个圆
				canvas.drawCircle(thisAct.getAbsoluteX(),
						thisAct.getAbsoluteY(), thisAct.getHeight(),
						canvas.getPaint());

			}

		};
      //设置太阳的造型是圆
		sun.setModel(circle);
	  //设置太阳的属性 Color 黄色
		sun.setAttributes("Color", Color.YELLOW);
		sun.setX(250);
		sun.setY(150);
		sun.setWidth(25);
		sun.setHeight(25);
		//设置脚本为圆运动 半径25  角度从100开始 速率10毫秒内0.005转
		sun.setScript(new CircleMoveScript(25, 100, 0.005));
      //新建地球
		Actor earth = new Actor();
		earth.setAttributes("Color", Color.CYAN);
		earth.setModel(circle);
		earth.setWidth(15);
		earth.setHeight(15);
		earth.setScript(new CircleMoveScript(130, 0, 0.01));
		//
		Actor moon = new Actor();
		moon.setAttributes("Color", Color.BLUE);
		moon.setModel(circle);
		moon.setWidth(5);
		moon.setHeight(5);
		moon.setScript(new CircleMoveScript(35, 0, 0.04));

		Actor star = new Actor();
		star.setAttributes("Color", Color.GRAY);
		star.setModel(circle);
		star.setWidth(2);
		star.setHeight(2);
		star.setScript(new CircleMoveScript(10, 0, 0.1));
       //将月亮和卫星组合一个系统
		moon.addAct(star);
	   //将地球和月亮组合一个系统
		earth.addAct(moon);
		//将太阳和地球组合一个系统
		sun.addAct(earth);

		// 获得脚本的扮演者当前的舞台的场景 添加扮演者
		act.getGameStage().getScreen().addAct(sun);
		// 因为这个脚本只需要执行一次 所以执行完移除脚本
		act.getGameStage().setScript(null);
	}



package game.engines.action;
import game.engines.GameCanvas;
import game.engines.GameStage;
import game.engines.Script;
import game.engines.inteface.IAct;

/**
 * 圆周运动
 */
public class CircleMoveScript extends Script {

	double cx;
	double cy;
	double radius = 70;
	double speed;
	boolean init = false;

	double step = 0;
  
	public CircleMoveScript(double radius, double step,double speed) {
		super();
		this.radius = radius;
		this.step = step;
		this.speed=speed;
	}
    
	public void timeScript(GameStage stage,GameCanvas canvas,IAct a) {
		//初始化圆心
		if (!init) {
			cx = a.getX();
			cy = a.getY();
			init = true;
		}
        
		double x;
		double y;
		//每次角度+速率
		step += speed;
		//圆的参数方程
		x = cx + radius * Math.cos(step);
		y = cy + radius * Math.sin(step);
		a.setX(x);
		a.setY(y);
	}
}



*这时会发现Actor本身能代替Layer画布的功能,所以Layer可以删除今后由Actor任意实现多层嵌套纸娃娃系统的功能。

脚本引擎本身也是可以嵌套,重用性很强。我们的开发工作会越来越轻松。足够的灵活将带给我们所需要的强大的功能。


举个例子将来我们可以实现配置文件,

比如飞机坠落脚本,你能想象它的运动方式

飞机坠落.txt

[飞机]

x=0

y=0

width=100

height=100

script=圆周运动,向右运动,向下运动




  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值