【3D游戏】模型与动画

智能巡逻兵


游戏设计要求:

  • 创建一个地图和若干巡逻兵(使用动画);
  • 每个巡逻兵走一个3~5个边的凸多边型,位置数据是相对地址。即每次确定下一个目标位置,用自己当前位置为原点计算;
  • 巡逻兵碰撞到障碍物,则会自动选下一个点为目标;
  • 巡逻兵在设定范围内感知到玩家,会自动追击玩家;
  • 失去玩家目标后,继续巡逻;
  • 计分:玩家每次甩掉一个巡逻兵计一分,与巡逻兵碰撞游戏结束;

程序设计要求:

  • 必须使用订阅与发布模式传消息
  • 工厂模式生产巡逻兵

巡逻兵动作

  • 巡逻
    每次获取巡逻动作时都会生成一个长度为4到7的随机距离,巡逻兵就会以这个距离的长方形轨迹巡逻。如果感知到了玩家在设定范围内,则巡逻动作被销毁,转为追踪动作。每Update一次,判断一次巡逻兵是否达到一个巡逻凸多边形的端点,若达到则改变方向,否则向目标点移动。
	public static PatrolAction getSSAction(Vector3 location) {
        PatrolAction action = CreateInstance<PatrolAction>();
        action.posX = location.x;
        action.posZ = location.z;
        action.moveLength = UnityEngine.Random.Range(4, 7);
        return action;
    }

    public override void Start() {
        this.gameObject.GetComponent<Animator>().SetBool("run", true);
        data = this.gameObject.GetComponent<PatrolData>();
    }

    public override void Update() {
        if (transform.localEulerAngles.x != 0 || transform.localEulerAngles.z != 0) {
            transform.localEulerAngles = new Vector3(0, transform.localEulerAngles.y, 0);
        }
        if(transform.position.y != 0) {
            transform.position = new Vector3(transform.position.x, 0, transform.position.z);
        }

        goPatrol();

        if(data.ifFollowPlayer && data.areaSign == data.sign) {
            this.destory = true;
            this.callback.SSActoinEvent(this, 0, this.gameObject);
        }
    }

    private void goPatrol() {
        if (isArrivedAnEndPoint) {
            switch (direction) {
                case Direction.EAST:
                    posX -= moveLength;
                    break;
                case Direction.NORTH:
                    posZ += moveLength;
                    break;
                case Direction.WEST:
                    posX += moveLength;
                    break;
                case Direction.SOUTH:
                    posZ -= moveLength;
                    break;
            }
            isArrivedAnEndPoint = false;
        }

        this.transform.LookAt(new Vector3(posX, 0, posZ));
        float distance = Vector3.Distance(transform.position, new Vector3(posX, 0, posZ));

        if(distance > 0.9) {
            transform.position = Vector3.MoveTowards(this.transform.position, new Vector3(posX, 0, posZ), speed * Time.deltaTime);
        }
        else {
            direction += 1;
            if(direction > Direction.SOUTH) {
                direction = Direction.EAST;
            }
            isArrivedAnEndPoint = true;
        }
    }
  • 追踪
    只要玩家进入巡逻兵设定的追踪范围,巡逻兵即追踪玩家,若追踪到玩家发生碰撞玩家即失败。若玩家脱离追踪范围,得分加一。
	public static FollowAction getSSAction(GameObject player) {
        FollowAction action = CreateInstance<FollowAction>();
        action.player = player;
        return action;
    }

    public override void Start() {
        data = this.gameObject.GetComponent<PatrolData>();
    }

    public override void Update() {
        if (transform.localEulerAngles.x != 0 || transform.localEulerAngles.z != 0) {
            transform.localEulerAngles = new Vector3(0, transform.localEulerAngles.y, 0);
        }
        if (transform.position.y != 0) {
            transform.position = new Vector3(transform.position.x, 0, transform.position.z);
        }

        transform.position = Vector3.MoveTowards(this.transform.position, player.transform.position, speed * Time.deltaTime);
        this.transform.LookAt(player.transform.position);

        if (!data.ifFollowPlayer || data.areaSign != data.sign) {
            this.destory = true;
            this.callback.SSActoinEvent(this, 1, this.gameObject);
        }
    }
  • 订阅与发布模式
    发布/订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者),而是通过消息通道广播出去,让订阅改消息主题的订阅者消费到。
public class GameEventManager : MonoBehaviour {
    // 发布分数变化的事件给订阅者
    public delegate void ScoreEvent();
    public static event ScoreEvent ScoreChange;
    // 发布游戏结束的事件给订阅者
    public delegate void GameOverEvent();
    public static event GameOverEvent GameOverChange;
    // 发布水晶减少的事件给订阅者
    public delegate void CrystalEvent();
    public static event CrystalEvent CrystalChange;

    public void playerEscape() {
        if(ScoreChange != null) {
            Debug.Log("Add score!");
            ScoreChange();
        }
    }

    public void gameOver() {
        if(GameOverChange != null) {
            GameOverChange();
        }
    }

    public void ReduceCrystalNum() {
        if(CrystalChange != null) {
            CrystalChange();
        }
    }
}
  • 巡逻兵工厂
public class PatrolFactory : MonoBehaviour {
    private List<GameObject> usedPatrols = new List<GameObject>(); 
    private Vector3[] vec = new Vector3[9];

    public List<GameObject> getPatrols() {
        int[] pos_x = { -6, 4, 13 };
        int[] pos_y = { -4, 6, -13 };
        int index = 0;
        for(int i = 0; i < 3; i++) {
            for(int j = 0; j < 3; j++) {
                vec[index] = new Vector3(pos_x[i], 0, pos_y[j]);
                index++;
            }
        }
        for(int i = 0; i < 9; i++) {
            GameObject patrol = Instantiate(Resources.Load<GameObject>("Prefabs/Patrol"));
            patrol.transform.position = vec[i];
            patrol.GetComponent<PatrolData>().sign = i + 1;
            patrol.GetComponent<PatrolData>().start_position = vec[i];
            usedPatrols.Add(patrol);
        }
        return usedPatrols;
    }

    public void stopPatrol() {
        for(int i = 0; i < usedPatrols.Count; i++) {
            usedPatrols[i].gameObject.GetComponent<Animator>().SetBool("run", false);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值