WillKen's Blog.

3D游戏编程与设计-模型与动画

Word count: 928Reading time: 4 min
2019/10/23 Share

3D游戏编程与设计-模型与动画

智能巡逻兵

  • 游戏设计要求:
    • 创建一个地图和若干巡逻兵(使用动画);
    • 每个巡逻兵走一个3~5个边的凸多边型,位置数据是相对地址。即每次确定下一个目标位置,用自己当前位置为原点计算;
    • 巡逻兵碰撞到障碍物,则会自动选下一个点为目标;
    • 巡逻兵在设定范围内感知到玩家,会自动追击玩家;
    • 失去玩家目标后,继续巡逻;
    • 计分:玩家每次甩掉一个巡逻兵计一分,与巡逻兵碰撞游戏结束;
  • 程序设计要求:
    • 必须使用订阅与发布模式传消息
      • subject:OnLostGoal
      • Publisher: ?
      • Subscriber: ?
    • 工厂模式生产巡逻兵
  • 友善提示1:生成 3~5个边的凸多边型
    • 随机生成矩形
    • 在矩形每个边上随机找点,可得到 3 - 4 的凸多边型
    • 5 ?
  • 友善提示2:参考以前博客,给出自己新玩法

  • 关键部分代码(项目地址

    控制玩家移动

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    public void MovePlayer(float translationX, float translationZ)
    {
    if(!game_over)
    {
    if (translationX != 0 || translationZ != 0)
    {
    player.GetComponent<Animator>().SetBool("run", true);
    }
    else
    {
    player.GetComponent<Animator>().SetBool("run", false);
    }
    //移动和旋转
    if (translationZ > 0) {
    player.transform.rotation = Quaternion.LookRotation(new Vector3(0, 0, 100));
    player.transform.Translate(0, 0, translationZ * player_speed * Time.deltaTime);
    }
    else if(translationZ < 0) {
    player.transform.rotation = Quaternion.LookRotation(new Vector3(0,0,-100));
    player.transform.Translate(0, 0, -translationZ * player_speed * Time.deltaTime);
    }

    if (translationX > 0) {
    player.transform.rotation = Quaternion.LookRotation(new Vector3(100, 0, 0));
    player.transform.Translate(0, 0, translationX * player_speed * Time.deltaTime);
    }
    else if(translationX < 0) {
    player.transform.rotation = Quaternion.LookRotation(new Vector3(-100,0,0));
    player.transform.Translate(0, 0, -translationX * player_speed * Time.deltaTime);
    }

    //防止碰撞带来的移动
    if (player.transform.localEulerAngles.x != 0 || player.transform.localEulerAngles.z != 0)
    {
    player.transform.localEulerAngles = new Vector3(0, player.transform.localEulerAngles.y, 0);
    }
    if (player.transform.position.y != 0)
    {
    player.transform.position = new Vector3(player.transform.position.x, 0, player.transform.position.z);
    }
    }
    }

    相机跟随玩家移动

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class CameraFlow : MonoBehaviour
    {
    public GameObject follow; //跟随的物体
    public float smothing = 5f; //相机跟随的速度
    Vector3 offset; //相机与物体相对偏移位置

    void Start()
    {
    offset = transform.position - follow.transform.position;
    }

    void FixedUpdate()
    {
    Vector3 target = follow.transform.position + offset;
    //摄像机自身位置到目标位置平滑过渡
    transform.position = Vector3.Lerp(transform.position, target, smothing * Time.deltaTime);
    }
    }

    工厂模式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    public class SpiderFactory : MonoBehaviour
    {
    private GameObject spider = null; //spider
    private List<GameObject> used = new List<GameObject>(); //正在被使用的spider
    private Vector3[] vec = new Vector3[9]; //保存每个spider的初始位置
    public FirstSceneController sceneControler; //场景控制器

    //返回spider列表
    public List<GameObject> GetSpiders()
    {
    int[] pos_x = { -8, 4, 13 };
    int[] pos_z = { 8, -3, -13 };
    int index = 0;
    //生成不同的spider初始位置
    for(int i=0;i < 3;i++)
    {
    for(int j=0;j < 3;j++)
    {
    vec[index] = new Vector3(pos_x[j], 0, pos_z[i]);
    index++;
    }
    }
    //加载spider
    for(int i=0; i < 9; i++)
    {
    spider = Instantiate(Resources.Load<GameObject>("Prefabs/Spider"));
    spider.transform.position = vec[i];
    spider.GetComponent<SpiderData>().sign = i + 1;
    spider.GetComponent<SpiderData>().start_position = vec[i];
    used.Add(spider);
    }
    return used;
    }


    //停止巡逻
    public void StopSpider()
    {
    //切换所有spiders的动画
    for (int i = 0; i < used.Count; i++)
    {
    used[i].gameObject.GetComponent<Animator>().SetBool("run", false);
    }
    }
    }

    追捕与逃跑

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class SpiderCollide : MonoBehaviour
    {
    void OnTriggerEnter(Collider collider)
    {
    if (collider.gameObject.tag == "Player")
    {
    //玩家进入spider追捕范围
    this.gameObject.transform.parent.GetComponent<SpiderData>().follow_player = true;
    this.gameObject.transform.parent.GetComponent<SpiderData>().player = collider.gameObject;
    }
    }
    void OnTriggerExit(Collider collider)
    {
    if (collider.gameObject.tag == "Player")
    {
    this.gameObject.transform.parent.GetComponent<SpiderData>().follow_player = false;
    this.gameObject.transform.parent.GetComponent<SpiderData>().player = null;
    }
    }
    }

    追捕成功

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class PlayerCollide : MonoBehaviour
    {

    void OnCollisionEnter(Collision other)
    {
    //当玩家与spider相撞
    if (other.gameObject.tag == "Player")
    {
    other.gameObject.GetComponent<Animator>().SetTrigger("death");
    this.GetComponent<Animator>().SetTrigger("attack");
    Singleton<GameEventManager>.Instance.PlayerGameover();
    }
    }
    }
  • 运行效果

CATALOG
  1. 1. 3D游戏编程与设计-模型与动画
    1. 1.1. 智能巡逻兵