zoukankan      html  css  js  c++  java
  • Unity3D 学习笔记

    注:本游戏开发环境为Unity 3D v4.6

    老师说这星期作业比较简单,所以我决定写得规整一些。

    开发时间:8小时

    游戏要求:

    小游戏争分夺秒:随机位置生成七个球,控制主角在地图拾取七个球,十秒钟内必须完成,否则失败
    具体要求:
    1 随机位置在地图上生成七个球(球可以用系统自带的球体)
    2 用键盘控制本课程中的角色移动,鼠标左键攻击到达打击帧时,拾取碰到的球。
    3 通过Time类显示每次拾取球花费的时间

    经过试验,十秒根本捡不完= =,15秒还可以。。。

    首先来看看帅气万分的主角Garen哥

    。。。

    额,忘了穿衣服

    将tex_Garen拖到transform_Garon的renderer上

    。。。按90年代的标准还是挺帅的。。。

    当然指的是公元3世纪90年代。。。

    考虑到后面的编程中会使用到盒式碰撞器Box Collider来触发,因此在这里为Garen哥加上Box Collider和Rigidbody组件。

    Box Collider的形状自行调整。

    都加上去之后,新建预制GarenPrefab,保存为预制。

    游戏类图设计:

    1. 由于游戏模型简单,GUI就交给GameModel你了!

    2. 裁判类Judge保持一个列表,列表中保存着此时Garen“身旁”的球对象

      2.1 每个球自带触发器,当Garen的盒式碰撞器进入了球的触发范围的时候(OnTriggerEnter()),球触发器发出一个信息。裁判类Judge接收到这个信息,把这个球对象加入到自己的列表当中。

      2.2 Garen离开(OnTriggerExit())时,球触发器发出信息。Judge将这个球从他的列表中移除。

      2.3 Garen攻击时,发出一个信息。Judge收到这个信息,通知球工厂BallFactory将自己列表中所有的球回收。

      2.4 GarenController, Ball, Judge之间的通信,采用观察者模式,C#中利用Delegate,event实现

    3. 本设计采用Legacy动画,GarenController中同时实现输入采集和动画。不得不指出Legacy动画实现非常麻烦,要自己设计状态机。这里可能会有点小bug,不在此修复,下星期学了Mecanim之后用Mecanim实现。

    4. 这次裁判类总算认真做裁判工作。Judge中保存了游戏中所有重要的数据。GameModel负责调用iJudgeInterface接口来控制游戏状态,计时等等。

    BaseCode:

    using UnityEngine;
    using System.Collections;
    using Com.GarenPickingBalls;
    
    public class BaseCode : MonoBehaviour {
    
        // Use this for initialization
        void Start () {
            SceneController sceneController = SceneController.GetInstance ();
    
            Judge judge = Judge.GetInstance ();
    
            UnityEngine.Camera.main.gameObject.AddComponent<GameModel> ();
        }
        
        // Update is called once per frame
        void Update () {
            
        }
    }

    SceneController:

    using UnityEngine;
    using System.Collections;
    
    
    namespace Com.GarenPickingBalls{
    
        public class SceneController : System.Object {
    
            public Camera mainCam;
            public GameObject Garen;
    
            void initScene (){
                GameObject floor = GameObject.CreatePrimitive (PrimitiveType.Plane);
                floor.name = "floor";
    
                Light light = new GameObject ().AddComponent<Light> ();
                light.gameObject.name = "light";
                light.type = LightType.Point;
                light.transform.position = new Vector3 (0, 2.4f, 0);
    
                mainCam = UnityEngine.Camera.main;
                mainCam.transform.position = new Vector3 (0.185f, 7.734f, 6.42f);
                mainCam.transform.eulerAngles = new Vector3 (54.115f, 183.6038f, 3.777f);
    
                GameObject GarenPrefab = Resources.LoadAssetAtPath ("Assets/Resources/Garen/GarenPrefab.prefab", typeof(GameObject)) as GameObject;
                Garen = GameObject.Instantiate (GarenPrefab, Vector3.zero, Quaternion.identity) as GameObject;
                Garen.name = "Garen";
                Garen.AddComponent<GarenController>();
            }
    
            //Singleton
            public static SceneController _instance;
    
            public static SceneController GetInstance() {
                if (_instance == null){
                    _instance = new SceneController();
                }
                return _instance;
            }
    
            SceneController (){
                initScene ();
            }
        }
    
    
    }

    GameModel:

    using UnityEngine;
    using System.Collections;
    using Com.GarenPickingBalls;
    
    public class GameModel : MonoBehaviour {
    
        BallFactory ballFactory = BallFactory.GetInstance();
        iJudgeInterface iJudge = Judge.GetInstance () as iJudgeInterface;
    
        void OnGUI () {
            GUI.Label (new Rect(20f,20f,300f,20f), "Garon Picking Ball Game");
    
            if (iJudge.getGameStatus () == 0) {
                GUI.Label (new Rect(20f, 40f, 300f, 20f), "Press Space Bar To Begin");
            }
    
            if (iJudge.getGameStatus () == 1) {
                GUI.Label (new Rect(20f, 40f, 300f, 20f), iJudge.getRemainingTime().ToString("0") + " seconds left");
                GUI.Label (new Rect(20f, 60f, 300f, 20f), "Garon Picked Up this ball at: " + iJudge.getLastGaronHit().ToString("0.0") + " seconds");
            }
    
            if (iJudge.getGameStatus () == 2) {
                GUI.Label (new Rect(20f, 40f, 300f, 20f), "Lose, press spacebar to restart");
            }
    
            if (iJudge.getGameStatus () == 3) {
                GUI.Label (new Rect(20f, 40f, 300f, 20f), "Win, press spacebar to restart");
            }
    
    
        }
        
        // Update is called once per frame
        void Update () {
            if (iJudge.getGameStatus() == 0 || iJudge.getGameStatus() == 2 || iJudge.getGameStatus() == 3) {
                if (Input.GetKey(KeyCode.Space)){
                    for (int i = 0; i < 7; i++) {
                        Vector3 pos = new Vector3(Random.Range(-5f,5f), 0, Random.Range(-5f,5f));
                        GameObject ball = ballFactory.getNewBall(pos);
                    }
                    
                    iJudge.startGame();
                }
            }
            
            else if (iJudge.getGameStatus() == 1) {
                iJudge.stepTime();
                
                if (iJudge.getRemainingTime() < 0){
                    iJudge.loseGame();
                }
                
                else if (iJudge.getBallPickedUp() == 7){
                    iJudge.winGame();
                }
            }
        }
    }

    Judge:

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using Com.GarenPickingBalls;
    
    public delegate void onHitActionHandler ();
    public delegate void onGaronInContactWithBall (GameObject ball);
    public delegate void onGaronLeavingTheBall (GameObject ball);
    
    public interface iJudgeInterface {
        int getGameStatus();
    
        void startGame();
    
        void loseGame();
    
        void winGame();
    
        float getLastGaronHit();
    
        float getRemainingTime ();
    
        void stepTime ();
    
        int getBallPickedUp ();
    }
    
    public class Judge : System.Object , iJudgeInterface {
        
        List <GameObject> ballInContact;
        BallFactory ballFactory;
    
        float TimeLimit = 15f;
        float t = 0f;
    
        float lastGaronHit = 0f;
    
        int ballPickedUp = 0;
    
        //game status: 0 for init, 1 for gaming, 2 for win, 3 for lose;
        int gameStatus = 0;
    
        //getting message from ball OnTriggerEnter()
        void GaronEnterContactWithBall (GameObject withBall){
            ballInContact.Add (withBall);
        }
    
        //getting message from ball OnTriggerExit()
        void GaronExitContacWithBall (GameObject withBall) {
            ballInContact.Remove (withBall);
        }
    
        //getting message from Garon onHit()
        void GaronHit (){
            if (ballInContact.Count != 0){
                for (int i = 0; i < ballInContact.Count; i++) {
                    ballFactory.releaseBall(ballInContact[i]);
                }
    
                ballPickedUp += ballInContact.Count;
    
                lastGaronHit = t;
    
                ballInContact.Clear ();
            }
        }
    
        public int getGameStatus (){
            return gameStatus;
        }
    
        public void startGame(){
            t = 0f;
            lastGaronHit = 0f;
            ballPickedUp = 0;
            gameStatus = 1;
        }
    
        public void winGame() {
            gameStatus = 3;
        }
    
        public void loseGame() {
            gameStatus = 2;
            ballFactory.recycleAllBalls ();
        }
    
        public float getLastGaronHit() {
            return lastGaronHit;
        }
    
        public float getRemainingTime (){
            return TimeLimit - t;
        }
    
        public void stepTime () {
            t += Time.deltaTime;
        }
    
        public int getBallPickedUp () {
            return ballPickedUp;
        }
    
        //Singleton
        public static Judge _instance;
        
        public static Judge GetInstance() {
            if (_instance == null){
                _instance = new Judge();
            }
            return _instance;
        }
    
        Judge() {
            ballInContact = new List<GameObject> ();
            ballFactory = BallFactory.GetInstance ();
            
            GarenController.onHit += GaronHit;
            ballTrigger.enterContact += GaronEnterContactWithBall;
            ballTrigger.exitContact += GaronExitContacWithBall;
        }
    }

    GarenController:

    using UnityEngine;
    using System.Collections;
    using Com.GarenPickingBalls;
    
    public class GarenController : MonoBehaviour {
    
        private iJudgeInterface iJudge = Judge.GetInstance () as iJudgeInterface;
    
        private float speed = 3f;
        private float angularSpeed = 10f;
    
        private Animation animation;
        private AnimationState run;
        private AnimationState idle;
        private AnimationState attack;
        
        private bool attackingFlag = false;
    
        public static event onHitActionHandler onHit;
    
        // Use this for initialization
        void Start () {
    
            animation = GetComponent<Animation> ();
    
            run = animation["Run"];
            idle = animation["Idle"];
            attack = animation["Attack1"];
    
            idle.wrapMode = WrapMode.Loop;
    
            AnimationEvent aev = new AnimationEvent ();
            aev.functionName = "attackOnHit";
            aev.time = 0.3f;
            attack.clip.AddEvent (aev);
    
            AnimationEvent finishedAtt = new AnimationEvent ();
            finishedAtt.functionName = "finishedAttack";
            finishedAtt.time = attack.clip.length / 2f;
            attack.clip.AddEvent (finishedAtt);
    
            Idle ();
        }
        
        // Update is called once per frame
        //Some bugs in here, gonna use new mode next time anyway...
        void Update () {
            if (iJudge.getGameStatus () == 1) {
                if (Input.GetKey (KeyCode.A)) {
                    transform.position += Vector3.right * speed * Time.deltaTime;
                    transform.rotation = Quaternion.LookRotation (Vector3.RotateTowards(transform.forward, Vector3.right, angularSpeed * Time.deltaTime, 0.0f));
                    Run ();
                }
                
                if (Input.GetKey (KeyCode.D)){
                    transform.position += Vector3.left * speed * Time.deltaTime;
                    transform.rotation = Quaternion.LookRotation (Vector3.RotateTowards(transform.forward, Vector3.left, angularSpeed * Time.deltaTime, 0.0f));
                    Run ();
                }
                
                if (Input.GetKey (KeyCode.S)){
                    transform.position += Vector3.forward * speed * Time.deltaTime;
                    transform.rotation = Quaternion.LookRotation (Vector3.RotateTowards(transform.forward, Vector3.forward, angularSpeed * Time.deltaTime, 0.0f));
                    Run ();
                }
                
                if (Input.GetKey (KeyCode.W)){
                    transform.position += Vector3.back * speed * Time.deltaTime;
                    transform.rotation = Quaternion.LookRotation (Vector3.RotateTowards(transform.forward, Vector3.back, angularSpeed * Time.deltaTime, 0.0f));
                    Run ();
                }
                
                if (!Input.anyKey && !attackingFlag) {
                    Idle();
                }
                
                if (Input.GetMouseButtonDown(0)) {
                    attackingFlag = true;
                    Attack();
                }
            }
            else{
                Idle ();
            }
        }
    
        public void Idle (float speed = 1f) {
            idle.speed = speed;
            idle.wrapMode = WrapMode.Loop;
            animation.CrossFade (idle.clip.name);
        }
    
        public void Run (float speed = 2f) {
            run.speed = speed;
    //        run.wrapMode = WrapMode.Loop;
            animation.CrossFade (run.clip.name);
        }
    
        public void Attack (float speed = 1f) {
            attack.speed = speed;
            animation.CrossFade (attack.clip.name);
        }
        
        public void finishedAttack (){
            attackingFlag = false;
        }
    
        //Added to Animation Events, sending message out to delegate notifying Garon has hit
        public void attackOnHit (){
            onHit ();
        }
    
    }

    BallFactory & ballTrigger

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using Com.GarenPickingBalls;
    
    public class BallFactory : System.Object {
    
        List<GameObject> usedBalls;
        List<GameObject> usingBalls;
        int ballCount = 0;    
    
        public GameObject getNewBall(Vector3 position){
            GameObject aBall = null;
    
            if (usedBalls.Count == 0){
                aBall = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                aBall.transform.localScale = new Vector3 (0.5f, 0.5f, 0.5f);
                aBall.transform.position = position;
                aBall.name = "ball" + ballCount.ToString();
                ballCount++;
    
                Collider bc = aBall.GetComponent<Collider>();
                bc.isTrigger = true;
    
                aBall.AddComponent<ballTrigger>();
    
                usingBalls.Add(aBall);
            }
            else { 
                aBall = usedBalls[0];
                usedBalls.Remove(aBall);
                usingBalls.Add (aBall);
                aBall.SetActive (true);
                aBall.transform.position = position;
            }
    
            return aBall;
        }
    
        public void releaseBall (GameObject ballToRelease){
    
            ballToRelease.SetActive (false);
            usingBalls.Remove (ballToRelease);
            usedBalls.Add (ballToRelease);
    
        }
    
        public void recycleAllBalls (){
        
            while (usingBalls.Count != 0) {
                releaseBall(usingBalls[0]);
            }
    
        }
    
        //Singleton
        public static BallFactory _instance;
        
        public static BallFactory GetInstance() {
            if (_instance == null){
                _instance = new BallFactory();
            }
            return _instance;
        }
        
        BallFactory (){
            usedBalls = new List<GameObject> ();
            usingBalls = new List<GameObject> ();
        }
    }
    
    public class ballTrigger : MonoBehaviour{
        
        public static event onGaronInContactWithBall enterContact;
        public static event onGaronLeavingTheBall exitContact;
    
        //notifying that Garon has entered the trigger zone
        void OnTriggerEnter (Collider other){
            //delegate
            enterContact (this.gameObject);
    
        }
    
        //notifying that Garon has exited the trigger zone
        void OnTriggerExit  (Collider other) {
            //delegate
            exitContact (this.gameObject);
        }
    }

    。。。

    XDDDD

  • 相关阅读:
    QQ下面功能移动效果
    网页中选择功能
    自定义listview
    android的内存优化分析【转,超级推荐】
    animation的xml定义中的android:interpolator属性(转)
    HOME键与Notification配合使用的bug重现【原创】
    (转载)Android下Affinities和Task(开发者指南)
    职场加薪步步高升的五大法则(转)
    强引用,软引用和弱引用。
    更改字体的ttf。
  • 原文地址:https://www.cnblogs.com/wangsta/p/5397264.html
Copyright © 2011-2022 走看看