人工智能-基于位置的触发器管理

一切都是偶然,偶然的位置,偶然的角落,偶然的书架,偶然的拿起了一本书,偶然的翻开了偶然的一页,偶然的看了几眼,于是触发器就这么诞生了。

曾经玩过星际争霸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,则需要建立一套完善的触发机制,除了位置触发,时间触发外还包括声音触发,范围触发,移动的位置触发,固定的位置触发,以及由此引申的逃避行为,追击行为,防守行为 等等。

其实要做一款类似星际,魔兽的地图编辑器一点也不浮云

未完待续~~

发表评论

电子邮件地址不会被公开。 必填项已用*标注