您的位置:首页 > 其它

LGame-0.2.9版二次修正(LGame-0.2.95,新增塔防示例,已提供下载)

2011-01-25 22:07 281 查看
2011-02-01

http://loon-simple.googlecode.com/files/LGame-0.2.95%28Graphics%20Optimization%29.7z

农历新年前做一个额外更新,此文件中附带了目前最新的LGame打包jar及源码(累计不足15行代码的小修正),主要修正了一个对于Android环境来说不合理的图像刷新方法(JavaSE版无此问题),此修正能让标准Screen(即最基础的,自动刷新模式的那个Screen) 显示速度获得约3 ~ 7 fps 的上升(视真机而定)。

另外,此次附带的最新LGame-Core-0.2.95(指Android与JavaSE两版)基本等价于0.3版LGame主体(剩下那0.5是独立的SLG模块,以及一个webview的内部封装),非必要不会再有变动,至多会改进一些旧有的低效实现,添加两三个新的ActionEvent。当然,假如获得新的BUG反馈小弟也会及时修正。

最后,祝愿大家农历新年快乐,宏“兔”大展,万事如意~



PS:有网友要下面这个塔防示例的JavaSE版,小弟这次也顺便加上了(源码在jar中),解压后可以看到代码除输入接口API及启动程序部分外与Android版完全一致。





_________________________________________



下载地址(内含示例,源码及jar):

http://loon-simple.googlecode.com/files/LGame-0.2.95.7z



此版继续修正0.2.9版(及0.2.94)中所发现的问题并有所扩展。



为Screen增加了runFirstScreen、runLastScreen、runPreviousScreen、runNextScreen、runIndexScreen、addScreen、getScreens、getScreenCount等Screen管理接口,以简化多Screen运行时的处理流程。

增加ActionEvent管理器,并提供了MoveTo、FireTo、JumpTo、FadeTo、RotateTo、CircleTo等自动化事件类,它们是对常用角色行为的封装(就是处理一些固定的事件执行,比如用MoveTo随便指定一个坐标就可以让角色八方向或四方向行走到该处,用FireTo可以直接让角色向指定位置如子弹一样发射出去,以此类推),具体使用方式可见下例。

修正了所有获得用户反馈的前版BUG(准确的说,是小弟上上周来博客所看到的那些……),对一些函数的具体实现有所改进。

下面有一个非常简单的塔防示例,演示了LGame-0.2.95改进后的Layer及新增的ActionEvent机制使用。



示例代码如下(直接拖拽Layer即可显示不同区域画面):




package org.loon.test;
import java.util.HashMap;
import java.util.List;
import org.loon.framework.android.game.action.ActionListener;
import org.loon.framework.android.game.action.FadeTo;
import org.loon.framework.android.game.action.MoveTo;
import org.loon.framework.android.game.action.map.Field2D;
import org.loon.framework.android.game.action.sprite.StatusBar;
import org.loon.framework.android.game.core.LSystem;
import org.loon.framework.android.game.core.graphics.LColor;
import org.loon.framework.android.game.core.graphics.LImage;
import org.loon.framework.android.game.core.graphics.Screen;
import org.loon.framework.android.game.core.graphics.device.LGraphics;
import org.loon.framework.android.game.core.graphics.window.LPaper;
import org.loon.framework.android.game.core.graphics.window.actor.Actor;
import org.loon.framework.android.game.core.graphics.window.actor.ActorLayer;
import org.loon.framework.android.game.core.graphics.window.actor.Layer;
import android.view.MotionEvent;
public class TD extends Screen {
	private int selectTurret = -1;
	private Field2D field;
	private String[] turrets = new String[] { "assets/bulletTurret.png",
			"assets/bombTurret.png", "assets/poisonTurret.png",
			"assets/laserTurret.png", "assets/bullet.png" };
	/**
	 * 子弹用类
	 * 
	 */
	class Bullet extends Actor {
		private int dir;
		private int damage;
		private double x, y;
		private boolean removeFlag;
		public Bullet(String fileName, int dir, int damage) {
			this.dir = dir;
			this.damage = damage;
			this.setImage(fileName);
			this.setDelay(50);
		}
		protected void addLayer(ActorLayer layer) {
			this.x = this.getX();
			this.y = this.getY();
		}
		public void action(long t) {
			if (removeFlag) {
				return;
			}
			Object o = null;
			for (int i = 0; i < 12; i++) {
				// 矫正弹道位置
				double angle = Math.toRadians((double) this.dir);
				this.x += Math.cos(angle);
				this.y += Math.sin(angle);
				this.setLocation((int) this.x
						+ (field.getTileWidth() - this.getWidth()) / 2,
						(int) this.y
								+ (field.getTileHeight() - this.getHeight())
								/ 2);
				o = this.getOnlyCollisionObject(Enemy.class);
			}
			// 当与敌相撞时
			if (o != null) {
				Enemy e = (Enemy) o;
				// 减少敌方HP
				e.hp -= this.damage;
				e.hpBar.setUpdate(e.hp);
				removeFlag = true;
				// 从Layer中删除自身
				getLayer().removeObject(this);
				return;
				// 超出游戏画面时删除自身
			} else if (this.getX() <= 12
					|| this.getX() >= this.getLayer().getWidth() - 96
					|| this.getY() <= 12
					|| this.getY() >= this.getLayer().getHeight() - 96) {
				removeFlag = true;
				this.getLayer().removeObject(this);
			}
		}
	}
	/**
	 * 炮塔用类
	 * 
	 */
	class Turret extends Actor {
		private int range = 50;
		private int delay = 10;
		boolean selected;
		public Turret(String fileName) {
			setImage(fileName);
			setDelay(100);
			setAlpha(0);
		}
		public void addLayer(ActorLayer layer) {
			// 让角色渐进式出现
			FadeTo fade = fadeOut();
			// 监听渐进淡出事件
			fade.setActionListener(new ActionListener() {
				public void process(Actor o) {
				}
				public void start(Actor o) {
				}
				// 当渐进完毕时
				public void stop(Actor o) {
					// 旋转90度
					rotateTo(90);
				}
			});
		}
		public void draw(LGraphics g) {
			if (selected) {
				g.setColor(255, 0, 0, 100);
				g.fillOval(-(range*2-field.getTileWidth())/2, -(range*2-field.getTileHeight())/2, this.range * 2 - 1, this.range * 2 - 1);
				g.setColor(LColor.red);
				g.drawOval(-(range*2-field.getTileWidth())/2,-(range*2-field.getTileHeight())/2, this.range * 2 - 1, this.range * 2 - 1);
			}
		}
		public void action(long t) {
			// 遍历指定半径内所有Enemy类
			List<?> es = this.getCollisionObjects(this.range, Enemy.class);
			// 当敌人存在
			if (!es.isEmpty()) {
				Enemy target = (Enemy) es.get(0);
				// 旋转炮台对准Enemy坐标
				setRotation((int) Math.toDegrees(Math.atan2(
						(target.getY() - this.getY()), (target.getX() - this
								.getX()))));
			}
			// 延迟炮击
			if (this.delay > 0) {
				--this.delay;
			} else if (!es.isEmpty()) {
				// 构造炮弹
				Bullet bullet = new Bullet(turrets[4], this.getRotation(), 2);
				// 计算炮击点
				int x = (int) Math.round(Math.cos(Math.toRadians(this
						.getRotation()))
						* (double) bullet.getWidth() * 2)
						+ this.getX();
				int y = (int) Math.round(Math.sin(Math.toRadians(this
						.getRotation()))
						* (double) bullet.getHeight() * 2)
						+ this.getY();
				// 注入炮弹到Layer
				this.getLayer().addObject(bullet, x, y);
				this.delay = 10;
			}
		}
	}
	/**
	 * 敌兵用类
	 * 
	 */
	class Enemy extends Actor {
		private int startX, startY;
		private int endX, endY;
		private int speed, hp;
		private boolean removeFlag;
		// 使用精灵StatusBar充当血槽
		protected StatusBar hpBar;
		public Enemy(String fileName, int sx, int sy, int ex, int ey,
				int speed, int hp) {
			this.setDelay(300);
			this.setImage(fileName);
			this.hpBar = new StatusBar(hp, hp, -5, 18, 25, 5);
			this.startX = sx;
			this.startY = sy;
			this.endX = ex;
			this.endY = ey;
			this.speed = speed;
			this.hp = hp;
		}
		public void draw(LGraphics g) {
			// 绘制精灵
			hpBar.createUI(g);
		}
		public void action(long t) {
			// 触发精灵事件
			hpBar.update(t);
			if (hp <= 0 && !removeFlag) {
				// 设定死亡时渐变
				FadeTo fade = fadeIn();
				// 渐变时间为30毫秒
				fade.setSpeed(30);
				// 监听渐变过程
				fade.setActionListener(new ActionListener() {
					public void process(Actor o) {
					}
					public void start(Actor o) {
					}
					public void stop(Actor o) {
						Enemy.this.removeActionEvents();
						Enemy.this.getLayer().removeObject(Enemy.this);
					}
				});
				this.removeFlag = true;
			}
		}
		// 首次注入Layer时调用此函数
		public void addLayer(final ActorLayer layer) {
			// 坐标矫正,用以让角色居于瓦片中心
			final int offsetX = (getLayer().getField2D().getTileWidth() - this
					.getWidth()) / 2;
			final int offsetY = (getLayer().getField2D().getTileWidth() - this
					.getHeight()) / 2;
			// 初始化角色在Layer中坐标
			setLocation(startX + offsetX, startY + offsetY);
			// 命令角色向指定坐标(参数为false为四方向寻径,为true时八方向)自动移动,并返回移动控制器
			// PS:endX与endY非显示位置,所以不必矫正
			final MoveTo move = moveTo(endX, endY, false);
			// 启动角色事件监听
			move.setActionListener(new ActionListener() {
				// 截取事件进行中数据
				public void process(Actor o) {
					// 矫正坐标,让角色居中
					o.setLocation(o.getX() + offsetX, o.getY() + offsetY);
					// 获得角色移动方向
					switch (move.getDirection()) {
					case Field2D.TUP:
						// 根据当前移动方向,变更角色旋转方向(以下同)
						o.setRotation(270);
						break;
					case Field2D.TLEFT:
						o.setRotation(180);
						break;
					case Field2D.TRIGHT:
						o.setRotation(0);
						break;
					case Field2D.TDOWN:
						o.setRotation(90);
						break;
					default:
						break;
					}
				}
				public void start(Actor o) {
				}
				// 当角色移动完毕时
				public void stop(Actor o) {
					// 从Layer中删除此角色
					layer.removeObject(o);
				}
			});
			// 设定移动速度
			move.setSpeed(speed);
		}
	}
	// 起始点
	class Begin extends Actor {
		public Begin(String fileName) {
			setImage(fileName);
		}
	}
	// 结束点
	class End extends Actor {
		public End(String fileName) {
			setImage(fileName);
		}
	}
	/**
	 * 拖拽用菜单
	 * 
	 */
	class Menu extends Layer {
		public Menu() {
			super(128, 240);
			// 设定menu层级高于MapLayer
			setLayer(101);
			// 不锁定menu移动
			setLocked(false);
			setLimitMove(false);
			// 锁定Actor拖拽
			setActorDrag(false);
			setDelay(500);
			// 设定Menu背景
			LImage image = LImage.createImage(this.getWidth(),
					this.getHeight(), false);
			LGraphics g = image.getLGraphics();
			g.setColor(LColor.black);
			g.fillRect(0, 0, getWidth(), getHeight());
			g.setColor(LColor.white);
			g.setFont(15);
			g.drawString("我是可拖拽菜单", 12, 25);
			g.dispose();
			setBackground(image);
			LPaper bulletTurret = new LPaper(turrets[0]) {
				// 当选中当前按钮时,为按钮绘制选中框(以下同)
				public void paint(LGraphics g) {
					if (selectTurret == 0) {
						g.setColor(LColor.red);
						g.drawRect(0, 0, this.getWidth() - 2,
								this.getHeight() - 2);
					}
				}
				public void downClick() {
					selectTurret = 0;
				}
			};
			bulletTurret.setLocation(18, 64);
			LPaper bombTurret = new LPaper(turrets[1]) {
				public void paint(LGraphics g) {
					if (selectTurret == 1) {
						g.setColor(LColor.red);
						g.drawRect(0, 0, this.getWidth() - 2,
								this.getHeight() - 2);
					}
				}
				public void downClick() {
					selectTurret = 1;
				}
			};
			bombTurret.setLocation(78, 64);
			LPaper poisonTurret = new LPaper(turrets[2]) {
				public void paint(LGraphics g) {
					if (selectTurret == 2) {
						g.setColor(LColor.red);
						g.drawRect(0, 0, this.getWidth() - 2,
								this.getHeight() - 2);
					}
				}
				public void downClick() {
					selectTurret = 2;
				}
			};
			poisonTurret.setLocation(18, 134);
			LPaper laserTurret = new LPaper(turrets[3]) {
				public void paint(LGraphics g) {
					if (selectTurret == 3) {
						g.setColor(LColor.red);
						g.drawRect(0, 0, this.getWidth() - 2,
								this.getHeight() - 2);
					}
				}
				public void downClick() {
					selectTurret = 3;
				}
			};
			laserTurret.setLocation(78, 134);
			// 用LPaper***敌人增加按钮
			LPaper button = new LPaper("assets/button.png") {
				public void paint(LGraphics g) {
					g.setColor(LColor.white);
					g.drawString("增加敌人", 15, 15);
				}
				public void downClick() {
					// 获得MapLayer
					MapLayer layer = (MapLayer) getBottomLayer();
					// 开始游戏演算
					layer.doStart();
				}
			};
			button.setLocation(27, 196);
			// 复合LPaper到Layer
			add(bulletTurret);
			add(bombTurret);
			add(poisonTurret);
			add(laserTurret);
			add(button);
			setAlpha(0.5F);
		}
		public void downClick(int x, int y) {
			selectTurret = -1;
		}
	}
	/**
	 * 大地图用Layer
	 */
	class MapLayer extends Layer {
		private boolean start;
		private int startX, startY, endX, endY;
		private int index, count;
		@SuppressWarnings("unchecked")
		public MapLayer() {
			super(576, 480, true);
			// 不锁定MapLayer拖拽
			setLocked(false);
			// 锁定MapLayer中角色拖拽
			setActorDrag(false);
			// 设置MapLayer背景元素(键值需要与map.txt文件中标识相对应)
			HashMap pathMap = new HashMap(10);
			pathMap.put(new Integer(0), new LImage("assets/sand.png"));
			pathMap.put(new Integer(1), new LImage("assets/sandTurn1.png"));
			pathMap.put(new Integer(2), new LImage("assets/sandTurn2.png"));
			pathMap.put(new Integer(3), new LImage("assets/sandTurn3.png"));
			pathMap.put(new Integer(4), new LImage("assets/sandTurn4.png"));
			pathMap.put(new Integer(5), new Begin("assets/base.png"));
			pathMap.put(new Integer(6), new End("assets/castle.png"));
			// 为Layer加入简单的2D地图背景,瓦片大小32x32,以rock图片铺底
			setField2DBackground(new Field2D("assets/map.txt", 32, 32),
					pathMap, "assets/rock.png");
			TD.this.field = getField2D();
			// 敌人出现坐标
			this.startX = 64;
			this.startY = 416;
			// 敌人消失坐标
			this.endX = 480;
			this.endY = 416;
			// 设定MapLayer每隔2秒执行一次内部Action
			setDelay(LSystem.SECOND * 2);
		}
		public void action(long t) {
			// 当启动标识为true时执行以下操作
			if (start) {
				if (index < 3) {
					Enemy enemy = null;
					// 根据点击next(增加敌人)的次数变换敌人样式
					switch (count) {
					case 0:
						enemy = new Enemy("assets/enemy.png", startX, startY,
								endX, endY, 2, 4);
						break;
					case 1:
						enemy = new Enemy("assets/fastEnemy.png", startX,
								startY, endX, endY, 4, 6);
						break;
					case 2:
						enemy = new Enemy("assets/smallEnemy.png", startX,
								startY, endX, endY, 3, 10);
						break;
					case 3:
						enemy = new Enemy("assets/bigEnemy.png", startX,
								startY, endX, endY, 1, 16);
						break;
					default:
						count = 0;
						enemy = new Enemy("assets/enemy.png", startX, startY,
								endX, endY, 2, 2);
						break;
					}
					addObject(enemy);
					index++;
					// 否则复位
				} else {
					start = false;
					index = 0;
					count++;
				}
			}
		}
		private Actor o = null;
		public void downClick(int x, int y) {
			// 转换鼠标点击区域为数组地图坐标
			int newX = x / field.getTileWidth();
			int newY = y / field.getTileHeight();
			// 当选中炮塔(参数不为-1)且数组地图参数为-1(不可通过)并且无其它角色在此时
			if ((o = getOnlyCollisionObjectsAt(x, y)) == null
					&& selectTurret != -1 && field.getType(newY, newX) == -1) {
				// 添加炮塔
				addObject(new Turret(turrets[selectTurret]), newX
						* field.getTileWidth(), newY * field.getTileHeight());
			}
			if (o != null) {
				((Turret) o).selected = true;
			}
		}
		public void upClick(int x, int y) {
			if (o != null) {
				((Turret) o).selected = false;
			}
		}
		public void doStart() {
			this.start = true;
		}
	}
	public void onLoad() {
		// 构建地图用Layer
		MapLayer layer = new MapLayer();
		// 居中
		centerOn(layer);
		// 添加MapLayer到Screen
		add(layer);
		// 构建菜单用Layer
		Menu menu = new Menu();
		// 让menu居于屏幕右侧
		rightOn(menu);
		menu.setY(0);
		// 添加menu到Screen
		add(menu);
	}
	public void draw(LGraphics g) {
	}
	public void onTouchDown(MotionEvent e) {
	}
	public void onTouchMove(MotionEvent e) {
	}
	public void onTouchUp(MotionEvent e) {
	}
}


运行画面如下所示:













以上已实现部分待0.3版发布时还会有更进一步的改进,不过目前最主要的还是修订SLG模块,另外在0.2.95遇到BUG的话希望大家能吼一声,小弟争取在0.3中全部改好。

下载地址(内含示例,源码及jar):

http://loon-simple.googlecode.com/files/LGame-0.2.95.7z

——————————————



2011-01-27



不好意思让大家久等了,小弟保险起见等Google维护过了才上传(以前吃过一次亏,那次害小弟倒时差的邮件联系了管理员两天,后来变得不见维护结束不踏实|||),此版本是针对LGame-0.2.9的最终修订版,绝大部分0.2.9的BUG在此版中已不复存在(好吧,小弟承认刚才看留言又发现两个漏网BUG,不过对程序主干没有影响,都是一、二行搞定的细节问题,且不是常用项……)。



应该说0.2.95版至少在易用性上又上了一个台阶,不是小弟自夸,单就开发效率和学习难度而言,绝大多数Android游戏引擎都应该从此版起被Loon甩在了后面——包括某些引擎的Android移植版在内。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: