一切都是偶然,偶然的位置,偶然的角落,偶然的书架,偶然的拿起了一本书,偶然的翻开了偶然的一页,偶然的看了几眼,于是触发器就这么诞生了。
曾经玩过星际争霸1、2,魔兽争霸 地图编辑器的少年们,一定很熟悉触发器的说。玩家可以在地图上放置任意图层,给图层命名,设置图层的大小,然后在触发器中对这些图层设置触发指令。比如玩家移动到下一图层,或者进攻到下一图层,或者该图层内的建筑爆炸,等等。
当然了,触发器不仅仅是图层这一触发功能,还有时间触发器。非常著名的 星际争霸1中的 7vs1 地图就是基于时间触发器的倒计时rpg地图。怪物每个一段的时间触发怪物创建的指令,然后调用图层触发器,往7个玩家所在的图层进攻过去。 玩家的胜利方式可以是 特定图层内没有地方的建筑,又或者是全地图上都没有地方建筑,单位。
本文只谈谈基于位置的触发器实现,时间触发器的话,改日吧!
在AS中有这么一个可以判断位置的API
[cc lang=”actionscript3″ nowrap=”false”]
Rectangle.contains(x : int, y : int);
[/cc]
有了这么一个API,就能知道目标是否进入了范围。
首先建立触发器接口
[cc lang=”actionscript3″ nowrap=”false”]
package com.Trigger
{
import flash.events.IEventDispatcher;
import flash.geom.Rectangle;
/**
* 触发器接口
*/
public interface ITrigger extends IEventDispatcher
{
function get rect() : Rectangle; // 触发区域
function get name() : String; // 触发器名
function init() : void; // 初始化
function onEnter() : void; // 进入触发
function onExit() : void; // 退出触发
}
}
[/cc]
然后构建一个具体的触发器
这是一个触发前情提要的触发器
[cc lang=”actionscript3″ nowrap=”false”]
package com.Trigger
{
import com.Manages.ChatManager;
import com.Manages.GameStateManager;
import com.Manages.ModelManager;
import com.drama.DramaView;
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.geom.Point;
import flash.geom.Rectangle;
/**
* 游戏前情提要剧情
*/
public class introTrigger implements ITrigger
{
public static const NAME : String = “introTrigger”;
private var pos : Point; //中心点
private var dis : int = 100; //范围
private var range : Rectangle; //触发圈
private var storyStage : Sprite;
private var root : DisplayObjectContainer;
private var disspatcher : EventDispatcher;
public function get rect():Rectangle
{
return range;
}
public function get name():String
{
return NAME;
}
/**
* 初始化建立触发范围
*/
public function init():void
{
disspatcher = new EventDispatcher(this);
pos = new Point(280,380);
range = new Rectangle(pos.x – dis, pos.y – dis, dis * 2, dis * 2);
root = GameStateManager.instance.root;
}
/**
* 调用剧情模块加载剧情
*/
public function onEnter():void
{
ChatManager.instance.hideChatPanel();
storyStage=new Sprite();
storyStage.graphics.beginFill(0,0);
storyStage.graphics.drawRect(0,0,root.stage.stageWidth,root.stage.stageHeight);
storyStage.graphics.endFill();
root.addChild(storyStage);
addEventListener(“DramaEnd”,dramaOver);
DramaView.instance.init(0,”drama01.xml”,storyStage,disspatcher);
}
public function dramaOver(e:Event):void{onExit()};
/**
* 退出触发器,资源销毁
*/
public function onExit():void
{
DramaView.instance.destory();
root.removeChild(storyStage);
ChatManager.instance.showChatPanel();
disspatcher.removeEventListener(“DramaEnd”,dramaOver);
disspatcher = null;
}
public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
{
disspatcher.addEventListener(type,listener,useCapture,priority,useWeakReference);
}
public function dispatchEvent(event:Event):Boolean
{
return disspatcher.dispatchEvent(event);
}
public function hasEventListener(type:String):Boolean
{
return disspatcher.hasEventListener(type);
}
public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void
{
disspatcher.removeEventListener(type,listener,useCapture);
}
public function willTrigger(type:String):Boolean
{
return disspatcher.willTrigger(type);
}
}
}
[/cc]
然后我们需要一个触发管理器来管理这些触发器
[cc lang=”actionscript3″ no-wrap=”false”]
package com.Manages
{
import com.Trigger.ITrigger;
import com.Trigger.endTrigger;
import com.Trigger.introTrigger;
import com.Trigger.trideTrigger;
import com.client.Player;
/**
* 触发器管理
* 基于位置的触发
*
* Create Date:2012-04-15
*/
public class TriggerManager
{
private static var _instance : TriggerManager;
private var triggerArr : Array;
private var mainPlayer : Player;
public static function get instance() : TriggerManager
{
if(!_instance)_instance = new TriggerManager();
return _instance;
}
/**
* 初始化触发器队列
*/
public function init() : void
{
addTrigger(introTrigger); //前情提要触发器
}
/**
* 添加触发器
*/
public function addTrigger(target : Class) : void
{
if(null == triggerArr)triggerArr = new Array();
var cls : Class = target;
var content : ITrigger = new cls() as ITrigger;
content.init();
triggerArr.push(content);
}
/**
* 移除触发器
*/
public function removeTrigger(name : String) : void
{
var trigger : ITrigger;
for each(trigger in triggerArr){
if(trigger.name == name){
triggerArr.splice(triggerArr.indexOf(trigger),1);
}
}
}
/**
* 触发检测
*/
public function update(tick : Number) : void
{
mainPlayer = ModelManager.instance.mainPlayer;
if(null == mainPlayer) return;
var trigger : ITrigger;
for each(trigger in triggerArr){
if(trigger.rect.contains(mainPlayer.x,mainPlayer.z)){ //触发
trigger.onEnter(); //进入触发器
triggerArr.splice(triggerArr.indexOf(trigger),1); //从触发队列移除
}
}
}
/**
* 销毁触发器队列
*/
public function destory() : void
{
var trigger : ITrigger;
while(triggerArr.length>0)
{
trigger = triggerArr.shift();
trigger = null;
}
triggerArr = null;
}
}
}
[/cc]
在初始化函数中,构造需要响应的触发器
在状态机中检测玩家是否达到区域
到达区域后进入触发器,触发具体指令
触发后,将该触发器从触发列表中移除
目前该触发器只针对主角进行触发,如果要制作一款AI,则需要建立一套完善的触发机制,除了位置触发,时间触发外还包括声音触发,范围触发,移动的位置触发,固定的位置触发,以及由此引申的逃避行为,追击行为,防守行为 等等。
其实要做一款类似星际,魔兽的地图编辑器一点也不浮云
未完待续~~