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

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

代码说明:

  • SSDirector:用来管理游戏场景的导演类。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SSDirector : System.Object
{

    private static SSDirector _instance;
    public ISceneController CurrentScenceController { get; set; }
    public static SSDirector GetInstance()
    {
        if (_instance == null)
        {
            _instance = new SSDirector();
        }
        return _instance;
    }
}
  • FirstController:游戏的第一个场景,用来加载资源。运用观察者模式,在游戏场景中订阅了分数以及游戏结束的事件,并在该类中实现具体事件。此外还提供了UserGUI可以使用的接口。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum GameState : int { GAMEOVER, RUNNING, RESTART }

public class FirstController : MonoBehaviour, ISceneController, IUserAction
{

    PatrolFactory df = null;
    GameState gamestate;
    private GameObject player;
    private int score;

    void Awake()
    {
        SSDirector director = SSDirector.GetInstance();
        director.CurrentScenceController = this;
        df = Singleton<PatrolFactory>.Instance;
        director.CurrentScenceController.LoadResources();
        gamestate = GameState.RUNNING;
        score = 0;

        this.gameObject.AddComponent<UserGUI>();
        this.gameObject.AddComponent<GameEventManager>();
    }

    public void LoadResources()
    {
        //产生迷宫
        GameObject maze = Instantiate<GameObject>(Resources.Load<GameObject>("prefabs/maze"));
        maze.name = "maze";

        //产生玩家
        player = Instantiate<GameObject>(Resources.Load<GameObject>("prefabs/FreeVoxelGirlBlackhairPrefab 1"));
        player.name = "player";
        player.transform.position = new Vector3(0, 0, 2);

        df.GetPatrol(new Vector3(-13, 0, 8), PatrolDirection.RIGHT);
        df.GetPatrol(new Vector3(3, 0, 8), PatrolDirection.DOWN);
        df.GetPatrol(new Vector3(13, 0, 2), PatrolDirection.LEFT);
        df.GetPatrol(new Vector3(-13, 0, -8), PatrolDirection.UP);
        df.GetPatrol(new Vector3(-3, 0, -2), PatrolDirection.RIGHT);
        df.GetPatrol(new Vector3(13, 0, -2), PatrolDirection.DOWN);
    }

    void OnEnable()
    {
        GameEventManager.OnScoreAction += addScore;
        GameEventManager.OnGameOver += SetGameOver;
    }

    void OnDisable()
    {
        GameEventManager.OnScoreAction -= addScore;
        GameEventManager.OnGameOver -= SetGameOver;
    }

    public GameState getGameState()
    {
        return gamestate;
    }

    public int getScore()
    {
        return score;
    }

    public void SetGameOver()
    {
        gamestate = GameState.GAMEOVER;
    }

    public void setGameState(GameState state)
    {
        gamestate = state;
    }

    public void restart()
    {
        player.transform.position = new Vector3(0, 0, 2);
        gamestate = GameState.RUNNING;
        df.RestartAll();

        score = -1;
    }

    public void addScore()
    {

        score++;
    }

    // Use this for initialization
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {

    }
}
  • IUserAction:场景的一个接口,其他类可以通过调用接口中的函数来与游戏场景进行交互。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface IUserAction
{

    GameState getGameState();
    int getScore();
    void setGameState(GameState state);
    void restart();
    void addScore();
}
  • ISceneController:场景的另一个接口,声明了场景应实现的功能。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface ISceneController
{

    void LoadResources();
}
  • GameEventManager:观察者模式中的事件源,定义了所有事件触发的函数。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameEventManager : MonoBehaviour
{

    public delegate void ScoreAction();
    public static event ScoreAction OnScoreAction;

    public delegate void GameoverAction();
    public static event GameoverAction OnGameOver;

    public void PlayerEscape()
    {
        if (OnScoreAction != null)
        {
            OnScoreAction();
        }
    }

    public void GameOver()
    {
        if (OnGameOver != null)
        {
            OnGameOver();
        }
    }
}
  • Singleton:提供获取单例的方法。使用工厂,事件源等类时都会用到。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    protected static T instance;
    public static T Instance
    {
        get
        {
            if (instance == null)
            {
                instance = (T)FindObjectOfType(typeof(T));
                if (instance == null)
                {
                    Debug.LogError("An instance of " + typeof(T)
                        + " is needed in the scene, but there is none.");
                }
            }
            return instance;
        }
    }
}
  • PatrolFactory:管理巡逻兵的工厂。能产生巡逻兵和在游戏重新开始时将巡逻兵复原。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UserGUI : MonoBehaviour
{

    private IUserAction action;
    private int score;

    // Use this for initialization
    void Start()
    {
        action = SSDirector.GetInstance().CurrentScenceController as IUserAction;
    }

    // Update is called once per frame
    void Update()
    {
        score = action.getScore();
    }

    void OnGUI()
    {
        GUI.Box(new Rect(Screen.width / 2 - 75, 10, 150, 55), "\nYour score:  " + score);
        if (action.getGameState() == GameState.GAMEOVER)
        {
            GUI.Window(0, new Rect(Screen.width / 2 - Screen.width / 12, Screen.height / 2 - Screen.height / 12, Screen.width / 6, Screen.height / 6), game_over_window, "Game Orver!");

        }

    }

    void game_over_window(int id)
    {
        if (GUI.Button(new Rect(Screen.width / 24, Screen.height / 24 + 5, Screen.width / 12, Screen.height / 12), "Restart"))
        {
            Debug.Log("Restart");

            action.restart();
        }
    }
}
  • PatrolData:管理巡逻兵信息以及动作的类。作为观察者,触发事件源。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum state : int { PATROL, CATCH }
public enum PatrolDirection : int { RIGHT, DOWN, LEFT, UP }

public class PatrolData : MonoBehaviour
{


    public state patrolState;
    public PatrolDirection direction;
    public PatrolDirection initDirection;
    public Vector3 target;
    public Vector3 initTarget;
    public float speed = 1f;
    public float catchSpeed = 2f;
    public GameObject player;

    private void Start()
    {
        patrolState = state.PATROL;
    }

    private void Update()
    {
        if (patrolState == state.PATROL)
        {
            this.transform.position = Vector3.MoveTowards(this.transform.position,
                target, speed * Time.deltaTime);
            if (transform.position == target)
            {
                direction = (PatrolDirection)(((int)direction + 1) % 4);
                if (direction == PatrolDirection.RIGHT)
                {
                    target = new Vector3(target.x + 6, target.y, target.z);
                }
                else if (direction == PatrolDirection.DOWN)
                {
                    target = new Vector3(target.x, target.y, target.z - 6);
                }
                else if (direction == PatrolDirection.UP)
                {
                    target = new Vector3(target.x, target.y, target.z + 6);
                }
                else if (direction == PatrolDirection.LEFT)
                {
                    target = new Vector3(target.x - 6, target.y, target.z);
                }
            }
        }
        else if (patrolState == state.CATCH)
        {
            this.transform.position = Vector3.MoveTowards(this.transform.position,
                player.transform.position, catchSpeed * Time.deltaTime);
            if (this.transform.position == player.transform.position)
            {
                Singleton<GameEventManager>.Instance.GameOver();
            }
        }
    }

    void OnTriggerEnter(Collider collider)
    {
        if (collider.gameObject.tag == "Player")
        {
            player = collider.gameObject;
            patrolState = state.CATCH;
        }
    }
    void OnTriggerExit(Collider collider)
    {
        if (collider.gameObject.tag == "Player")
        {
            patrolState = state.PATROL;

            Singleton<GameEventManager>.Instance.PlayerEscape();
        }
    }
}
  • joystick:定义玩家如何利用键盘操纵任务。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class joystick : MonoBehaviour
{

    public float speedX = 5f;
    public float speedY = 5f;
    public float rotate_speed = 1500f;

    // Use this for initialization
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        float translationY = Input.GetAxis("Vertical") * speedY;
        float translationX = Input.GetAxis("Horizontal") * speedX;
        translationX *= Time.deltaTime;
        translationY *= Time.deltaTime;
        transform.Translate(translationX, 0, translationY);
        transform.Rotate(0, translationX * rotate_speed * Time.deltaTime, 0);
        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);
        }
    }
}

你可能感兴趣的:(3D游戏编程与设计)