Unity3d学习笔记(7)--打靶游戏

一.游戏简介:

这是一个简单的打靶游戏,总共有五环,从外到里依次是一到五环,打到一环得一分,二环得二分,依此类推

玩家可以通过方向键或asdw键来控制发射的位置,还有,在游戏当中,还会有风来影响箭的飞行方向


二.游戏效果图:



三.UML图:

Unity3d学习笔记(7)--打靶游戏_第1张图片


四.游戏主要代码和设置说明:

1.游戏中是用了虚拟轴来控制箭的位置,不过移动箭的代码是挂在一个空对象上的,而箭是它的子对象,当箭射出的时候,就把它的parent置为null,这样在

   箭射出后就不能控制箭了,移动的代码如下:

void Update () {
        float translationY = Input.GetAxis("Vertical") * speed;
        float translationX = Input.GetAxis("Horizontal") * speed;
        translationY *= Time.deltaTime;
        translationX *= Time.deltaTime;
        this.gameObject.transform.Translate(0, translationY, 0);
        this.gameObject.transform.Translate(-translationX, 0, 0);
    }

2.游戏中箭的初始方向和初始速度都是固定的

        horizontalSpeed = gameobject.GetComponent().speed;
        direction = Vector3.back;
        rigid = this.gameobject.GetComponent();
        rigid.velocity = direction * horizontalSpeed;
   

3.游戏中靶是有五个圆柱体和一个空对象组成的,圆柱体是空对象的子对象,通过圆柱体细微的高度差异,就可以显示各个环的颜色,

   通过mesh触发器,就可以和箭产生出发事件,各个圆柱的设置差不多,只是其中一个:

Unity3d学习笔记(7)--打靶游戏_第2张图片


4.但各个圆柱的触发区域有重叠的地方,我这里是用一个数组来记录有哪些环出发了,然后选得分最大的那个环

 hitedTarget = new bool[5] { false, false, false, false, false };
 public void setHitedTarget(int ring)
{
    hitedTarget[ring - 1] = true;
}
private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.GetComponent())
        {
            other.gameObject.transform.FindChild("head").gameObject.SetActive(false);
            other.gameObject.GetComponent().isKinematic = true;
            sceneController.setHitedTarget((int)this.gameObject.name[0] - (int)'0'); //环的名字是对应第几环
        }
       
    }

5.游戏中还会有风产生,风是挂载在箭上的脚本,本来是应该归动作管理器管理的,但这里偷懒,直接挂在箭上

void FixedUpdate() {
        if (rigid.useGravity) //当箭射出时,刚体的useGravity属性才会置为true

        {
            rigid.AddForce(force);
        }
}

五.全部源代码

1.ArrowData.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ArrowData : MonoBehaviour {

    public Vector3 size;
    public Color color;
    public float speed;
    public Vector3 direction;
    public bool destroy;
    public bool used;
}

2.ArrowFactory.cs

/**
 * 这个文件是用来生产飞碟的工厂
 */

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ArrowFactory : MonoBehaviour
{

   

    public GameObject ArrowPrefab;
    public GameObject person;

    float time = 0;

    /**
     * used是用来保存正在使用的箭
     * free是用来保存未激活的箭
     */

    private Dictionary used = new Dictionary();
    private List free = new List();
    private List wait = new List();

    private void Awake()
    {
        ArrowPrefab = GameObject.Instantiate(Resources.Load("Prefabs/arrow"), Vector3.zero, Quaternion.identity);
        person = GameObject.Instantiate(Resources.Load("Prefabs/person"), new Vector3(0,0,3), Quaternion.identity);
        ArrowPrefab.SetActive(false);
    }


    public GameObject GetArrow()
    {
        GameObject newArrow = null;
        if (free.Count > 0)
        {
            newArrow = free[0].gameObject;
            free.Remove(free[0]);
        }
        else
        {
            newArrow = GameObject.Instantiate(ArrowPrefab, Vector3.zero, Quaternion.identity);
        }
        
        ArrowData data = newArrow.GetComponent();
        data.destroy = false;
        data.speed = 15f;
        data.used = false;
        data.transform.rotation = Quaternion.identity;
        newArrow.transform.position = new Vector3(0, 0, 3);

        Rigidbody rigid = newArrow.GetComponent();
        rigid.isKinematic = false;
        rigid.useGravity = false;
        rigid.velocity = Vector3.zero;

        used.Add(data.GetInstanceID(), data);
        newArrow.transform.parent = person.transform;
        newArrow.SetActive(true);
        return newArrow;
    }

    public void FreeArrow(GameObject Arrow)
    {
        ArrowData tmp = null;
        int key = Arrow.GetComponent().GetInstanceID();
        if (used.ContainsKey(key))
        {
            tmp = used[key];
        }

        if (tmp != null)
        {
            tmp.gameObject.SetActive(false);
            free.Add(tmp);
            used.Remove(key);
        }
    }

    private void Update()
    {
        time += Time.deltaTime;
        if (time > 10f)
        {
            clear();
            time = 0;
        }

        foreach (var tmp in used.Values)
        {
            
            if (tmp.destroy)
            {
                wait.Add(tmp.GetInstanceID());
            }
        }

        foreach (int tmp in wait)
        {
            FreeArrow(used[tmp].gameObject);
        }
        wait.Clear();
    }

    public void clear()
    {
        foreach (var tmp in used.Values)
        {
            if (tmp.GetComponent().used)
            {
                tmp.gameObject.SetActive(false);
                tmp.destroy = true;
            }

        }
    }
}

3.CCActionManager.cs

  
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CCActionManager : SSActionManager, ISSActionCallback {
    
    public FirstSceneControl sceneController;

    protected void Start()
    {
        sceneController = (FirstSceneControl)Director.getInstance().currentSceneControl;
        sceneController.actionManager = this;
        
    }

    public void SSActionEvent(SSAction source,
        SSActionEventType events = SSActionEventType.Competeted,
        int intParam = 0,
        string strParam = null,
        UnityEngine.Object objectParam = null)
    {

        if (!source.gameobject.activeSelf)
        {
            source.gameobject.GetComponent().destroy = true;
        }

        if (source is CCFlyAction)
        {
            source.gameobject.GetComponent().used = true;
            sceneController.setGameState(GameState.DART_FINISH);
            source.reset();
        }
        
        
    }

    public void StartThrow(GameObject Arrow)
    {
        CCFlyActionFactory cf = Singleton.Instance;
        RunAction(Arrow, cf.GetSSAction(), (ISSActionCallback)this);
        Arrow.transform.parent = null;
        Arrow.GetComponent().useGravity = true;
    }
}

4.CCFlyAction.cs

/**
 * 这个文件是实现飞碟的飞行动作
 */
  
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CCFlyAction : SSAction {


    float horizontalSpeed;

    Vector3 direction;

    Rigidbody rigid;

	public override void Start () {
        enable = true;
        horizontalSpeed = gameobject.GetComponent().speed;
        direction = Vector3.back;
        rigid = this.gameobject.GetComponent();
        rigid.velocity = direction * horizontalSpeed;
        rigid.useGravity = false;
    }

    // Update is called once per frame


    public override void FixedUpdate () {

        if (gameobject.activeSelf && rigid)
        {

            
            if (this.transform.position.y < -4)
            {
                this.destroy = true;
                this.enable = false;
                this.gameobject.SetActive(false);
                this.callback.SSActionEvent(this);
            }

            if (rigid.isKinematic)
            {
                this.enable = false;
                this.callback.SSActionEvent(this);
            }

        }
       
	}

    public static CCFlyAction GetCCFlyAction()
    {
        CCFlyAction action = ScriptableObject.CreateInstance();
        return action;
    }
}


5.CCFlyActionFactory.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CCFlyActionFactory : MonoBehaviour {

    private Dictionary used = new Dictionary();
    private List free = new List();
    private List wait = new List();

    public CCFlyAction Fly;

    // Use this for initialization
    void Start () {
        Fly = CCFlyAction.GetCCFlyAction();
    }
	
	
    private void Update()
    {
        foreach (var tmp in used.Values)
        {
            if (tmp.destroy)
            {
                wait.Add(tmp.GetInstanceID());
            }
        }

        foreach (int tmp in wait)
        {
            FreeSSAction(used[tmp]);
        }
        wait.Clear();
    }

    public SSAction GetSSAction()
    {
        SSAction action = null;
        if (free.Count > 0)
        {
            action = free[0];
            free.Remove(free[0]);
        }
        else
        {
            action = ScriptableObject.Instantiate(Fly);
        }

        used.Add(action.GetInstanceID(), action);
        return action;
    }

    public void FreeSSAction(SSAction action)
    {
        SSAction tmp = null;
        int key = action.GetInstanceID();
        if (used.ContainsKey(key))
        {
            tmp = used[key];
        }

        if (tmp != null)
        {
            tmp.reset();
            free.Add(tmp);
            used.Remove(key);
        }
    }

    public void clear()
    {
        foreach (var tmp in used.Values)
        {
            tmp.enable = false;
            tmp.destroy = true;
            
        }
    }
}


6.CCMoveDartAction.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CCMoveDartAction : MonoBehaviour {

	// Use this for initialization
	void Start () {
		
	}
    float speed = 4f;
    // Update is called once per frame
    void Update () {
        float translationY = Input.GetAxis("Vertical") * speed;
        float translationX = Input.GetAxis("Horizontal") * speed;
        translationY *= Time.deltaTime;
        translationX *= Time.deltaTime;
        this.gameObject.transform.Translate(0, translationY, 0);
        this.gameObject.transform.Translate(-translationX, 0, 0);
    }
}


7.collision.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class collision : MonoBehaviour {

    public FirstSceneControl sceneController;

    // Use this for initialization
    void Start() {
        sceneController = (FirstSceneControl)Director.getInstance().currentSceneControl;
    }
    
    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.GetComponent())
        {
            other.gameObject.transform.FindChild("head").gameObject.SetActive(false);
            other.gameObject.GetComponent().isKinematic = true;
            sceneController.setHitedTarget((int)this.gameObject.name[0] - (int)'0');
        }
       
    }
}


8.Director.cs

/**
 * 这个文件是用来场景控制的,负责各个场景的切换,
 * 虽然目前只有一个场景
 */
  
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Director : System.Object {

    /**
     * currentSceneControl标志目前正在使用的场景
     */

    public ISceneControl currentSceneControl { get; set; }

    /**
     * Director这个类是采用单例模式
     */ 

    private static Director director;

    private Director()
    {

    }

	public static Director getInstance()
    {
        if (director == null)
        {
            director = new Director();
        }
        return director;
    }
}


9. FirstSceneControl.cs

/**
 * 这个文件是用来控制主游戏场景的
 */ 

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FirstSceneControl : MonoBehaviour, ISceneControl, IUserAction {

    /**
     * actionManager是用来指定当前的动作管理器
     */

    public CCActionManager actionManager { get; set; }

    /**
     * scoreRecorder是用来指定当前的记分管理对象的
     */

    public ScoreRecorder scoreRecorder { get; set; }

   
    public bool[] hitedTarget = null;

    /**
     * gameState是用来保存当前的游戏状态
     */

    private GameState gameState;
    private GameObject currentArrow;

    void Awake () {
        Director director = Director.getInstance();
        director.currentSceneControl = this;
        gameState = GameState.DART_START;
        hitedTarget = new bool[5] { false, false, false, false, false };
        this.gameObject.AddComponent();
        this.gameObject.AddComponent();
        this.gameObject.AddComponent();
        scoreRecorder = Singleton.Instance;
        director.currentSceneControl.LoadResources();
    }
	
    private void Update()
    {
        /**
         * 以下代码用来管理游戏的状态
         */


        if (gameState == GameState.DART_FINISH)
        {
            int ring = check();
            scoreRecorder.Record(ring);
            gameState = GameState.DART_START;
        }

        if (gameState == GameState.DART_START)
        {
            ArrowFactory df = Singleton.Instance;
            currentArrow =  df.GetArrow();
            gameState = GameState.WAIT;
        }

        if (gameState == GameState.SHOOT)
        {
            actionManager.StartThrow(currentArrow);
            gameState = GameState.RUNNING;
        }

    }

    public void LoadResources()
    {
        GameObject DartsBoard = GameObject.Instantiate(Resources.Load("Prefabs/dartsboard"));
        GameObject plane = GameObject.Instantiate(Resources.Load("Prefabs/plane"));
        
    }
    
    public string GetWindInfo()
    {
        float wind = currentArrow.GetComponent().GetForce();
        if (wind < 0)
        {
            return "Right " + (-wind).ToString();
        }
        else
        {
            return "Left " + wind.ToString();
        }
       
    }

    public int GetScore()
    {
        return scoreRecorder.score;
    }

    public GameState getGameState()
    {
        return gameState;
    }

    public void setGameState(GameState gs)
    {
        gameState = gs;
    }

    public void setHitedTarget(int ring)
    {
        hitedTarget[ring - 1] = true;
    }

    public int check()
    {
        int result = -1;
        for (int i = 4; i >= 0; i--)
        {
            if (hitedTarget[i])
            {
                result = i;
                break;
            }
        }

        for (int i = 4; i >= 0; i--)
        {
            hitedTarget[i] = false;
        }
        return result + 1;
    }
}


10.ISceneControl.cs

/*
 * 场景控制的必须实现的接口
 */
  
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface ISceneControl  {
    void LoadResources();
}


11.ISSActionCallback.cs

/**
 * 这个接口负责动作与动作管理器间的通信
 */ 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum SSActionEventType:int { Started, Competeted }

public interface ISSActionCallback {
    void SSActionEvent(SSAction source,
        SSActionEventType events = SSActionEventType.Competeted,
        int intParam = 0,
        string strParam = null,
        Object objectParam = null);
	
}

12.IUserAction.cs

/**
 * UI界面与场景管理器通信的接口
 */
  
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum GameState { RUNNING, DART_START, DART_FINISH, WAIT, SHOOT}

public interface IUserAction {
    GameState getGameState();
    void setGameState(GameState gs);
    int GetScore();
    string GetWindInfo();
}

13.ScoreRecorder.cs

/**
 * 这个类是用来记录玩家得分的
 */
  
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ScoreRecorder : MonoBehaviour {

    /**
     * score是玩家得到的总分
     */
      
    public int score;

    /**
     * scoreTable是一个得分的规则表,每种飞碟的颜色对应着一个分数
     */

    private Dictionary scoreTable = new Dictionary();

	// Use this for initialization
	void Start () {
        score = 0;
        scoreTable.Add(0, 0);
        scoreTable.Add(1, 1);
        scoreTable.Add(2, 2);
        scoreTable.Add(3, 3);
        scoreTable.Add(4, 4);
        scoreTable.Add(5, 5);
    }

    public void Record(int ring)
    {
        score += scoreTable[ring];
    }

    public void Reset()
    {
        score = 0;
    }
}


14.Singleton.cs

/**
 * 这是一个实现单例模式的模板,所有的MonoBehaviour对象都用这个模板来实现单实例
 */
  
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Singleton : 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;
        }
    }
}


15.SSAction.cs

/**
 * 所有动作的基类
 */ 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SSAction : ScriptableObject {

    public bool enable = false;
    public bool destroy = false;

    public GameObject gameobject { get; set; }
    public Transform transform { get; set; }
    public ISSActionCallback callback { get; set; }

    protected SSAction() { }

    public virtual void Start () {
        throw new System.NotImplementedException();
	}
	
	// Update is called once per frame
	public virtual void FixedUpdate () {
        throw new System.NotImplementedException();
    }

    public void reset()
    {
        enable = false;
        destroy = false;
        gameobject = null;
        transform = null;
        callback = null;
    }
}

16.SSActionManager.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SSActionManager : MonoBehaviour {

    private Dictionary actions = new Dictionary();        //保存所以已经注册的动作
    private List waitingAdd = new List();                           //动作的等待队列,在这个对象保存的动作会稍后注册到动作管理器里
    private List waitingDelete = new List();                                  //动作的删除队列,在这个对象保存的动作会稍后删除


    // Update is called once per frame
    protected void FixedUpdate()
    {
        //把等待队列里所有的动作注册到动作管理器里
        foreach (SSAction ac in waitingAdd) actions[ac.GetInstanceID()] = ac;
        waitingAdd.Clear();

        //管理所有的动作,如果动作被标志为删除,则把它加入删除队列,被标志为激活,则调用其对应的Update函数
        foreach (KeyValuePair kv in actions)
        {
            SSAction ac = kv.Value;
            if (ac.destroy)
            {
                waitingDelete.Add(ac.GetInstanceID());
            }
            else if (ac.enable)
            {
                ac.FixedUpdate();
            }
        }

        //把删除队列里所有的动作删除
        foreach (int key in waitingDelete)
        {
            SSAction ac = actions[key];
            actions.Remove(key);
            DestroyObject(ac);
        }
        waitingDelete.Clear();
    }

    //初始化一个动作
    public void RunAction(GameObject gameobject, SSAction action, ISSActionCallback manager)
    {
        action.gameobject = gameobject;
        action.transform = gameobject.transform;
        action.callback = manager;
        waitingAdd.Add(action);
        action.Start();
    }
}

17.UserGUI.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UserGUI : MonoBehaviour
{
    private IUserAction action;

	void Start () {
        action = Director.getInstance().currentSceneControl as IUserAction;
	}

    private void OnGUI()
    {
        if (GUI.Button(new Rect(900, 500, 90, 90), "shoot") && (action.getGameState() == GameState.WAIT))
        {
            action.setGameState(GameState.SHOOT);
        }

        GUI.Label(new Rect(500, 90, 90, 90), "Force: " + action.GetWindInfo());
        GUI.Label(new Rect(900, 90, 90, 90), "Score: " + action.GetScore().ToString());

    }

   
}

18.wind.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class wind : MonoBehaviour {

    Vector3 force;
    Rigidbody rigid;

	void Start() {
        float xforce = Random.Range(-0.5f, 0.5f);
        force = new Vector3(xforce, 0, 0);
        rigid = this.gameObject.GetComponent();
	}
	
	
	void FixedUpdate() {
        if (rigid.useGravity)
        {
            rigid.AddForce(force);
        }
        
	}

    public float GetForce()
    {
        return force.x;
    }
}





你可能感兴趣的:(Unity3d学习笔记(7)--打靶游戏)