Unity3D游戏编程-鼠标打飞碟

本文介绍了使用Unity3D开发的一款游戏,包含多个round和trial,玩家通过鼠标控制击中飞碟并计算得分。主要涉及SceneController、UserAction接口和子类,如FristSceneControl、ActionManager、CCFlyAction等,以及ScoreRecorder用于记录得分。
摘要由CSDN通过智能技术生成

游戏规则:

游戏有 n 个 round,每个 round 都包括10 次 trial;
每个 trial 的飞碟的色彩、大小、发射位置、速度、角度、同时出现的个数都可能不同。它们由该 round 的 ruler 控制;
每个 trial 的飞碟有随机性,总体难度随 round 上升;
鼠标点中得分,得分规则按色彩、大小、速度不同计算,规则可自由设定。
 

基本代码实现:

SceneController

SceneController也是一个接口,但这一次的游戏并不需要预先加载角色(上次要加载牧师、恶魔、船之类的对象,但这次没有),所以loadResources在FirstController的实现为空。

public interface ISceneControl
{
    void loadResources();
}
UserAction

UserAction是门面模式,与用户交互相关的,与玩家动作有关:

public enum GameState { ROUND_START, ROUND_FINISH, RUNNING, PAUSE, START, FUNISH }

public interface IUserAction
{
    GameState getGameState();//获取游戏状态
    void setGameState(GameState gameState);//设置游戏状态
    int getScore();//获取当前积分
    void hit(Vector3 pos);//
    bool getActionMode();//获取模式状态(运动学还是动力学)
    void setActionMode(bool mode);//设置模式
}
FristSceneControl

FristSceneControl就要实现上面(SceneController、UserAction)两个类的函数。

        public ActionManagerAdapter actionManager { set; get; }//适配器
        public ScoreRecorder scoreRecorder { set; get; }       //成绩记录器
        public Queue<GameObject> diskQueue = new Queue<GameObject>();//飞碟对象队列
        private int diskNumber = 0;//飞碟的数量,主要用于设定每一轮抛出的飞碟数量
        private int currentRound = -1;//当前进行到第几局
        private float time = 0;//时间控制,用来做抛飞碟的时候用到
        private GameState gameState = GameState.START;//游戏状态
        UserGUI userGUI;//挂载GUI
        private bool isPhysical = false;//用于判断是否使用物理引擎
        void Awake()
        {
            Director director = Director.getInstance();//获取导演
            director.current = this;
            diskNumber = 10;//初始化每轮抛出的飞碟数
            this.gameObject.AddComponent<ScoreRecorder>();//挂载ScoreRecorder
            this.gameObject.AddComponent<DiskFactory>();//挂载DiskFactory
            scoreRecorder = Singleton<ScoreRecorder>.Instance;
            userGUI = gameObject.AddComponent <UserGUI>() as UserGUI;//挂载UserGUI

            director.current.loadResources();
        }
public void loadResources()
        {
        }
        public void hit(Vector3 pos)
        {
            RaycastHit[] hits = Physics.RaycastAll(Camera.main.ScreenPointToRay(pos));
            for (int i = 0; i < hits.Length; i++)
            {
                RaycastHit hit = hits[i];
                if (hit.collider.gameObject.GetComponent<DiskData>() != null)
                {
                    scoreRecorder.record(hit.collider.gameObject);
                    hit.collider.gameObject.transform.position = new Vector3(0, -5, 0);
                }
            }
        }
private void Update()
        {
            //因为需要依赖actionManager的功能
            // 注意actionManager是适配器,根据isPhysical的值采用不同的actionManager
            if (actionManager == null)
            {
                return;
            }

            if (actionManager.getDiskNumber() == 0 && gameState == GameState.RUNNING)//飞碟已经出完,并且游戏进行中,就表示round结束
            {
                gameState = GameState.ROUND_FINISH;
                if (currentRound == 2)//如果round = 2,表示已经完成了三局游戏,游戏结束
                {
                    gameState = GameState.FUNISH;
                    return;
                }
            }

            if (actionManager.getDiskNumber() == 0 && gameState == GameState.ROUND_START)//飞碟数为空,并且是round开始状态,则准备开始下一round游戏
            {
                currentRound++;//回合数增加
                nextRound();//下一回合的准备
                actionManager.setDiskNumber(10);//重置飞碟数目
                gameState = GameState.RUNNING;//改变游戏状态
            }

            if (time > 1 && gameState != GameState.PAUSE)//其他时候执行抛飞碟的动作
            {
                throwDisk();
                time = 0;
            }
            else
            {
                time += Time.deltaTime;//time主要用来控制抛飞碟的时间间隔
            }
        }
        private void nextRound()
        {
            DiskFactory diskFactory = Singleton<DiskFactory>.Instance;//获取飞碟工厂单例
            for (int i = 0; i < diskNumber; i++)
            {
                diskQueue.Enqueue(diskFactory.getDisk(currentRound,isPhysical));//根据当前round数和是否使用物理引擎(启动刚体)来取出飞碟,并且让它加入本局抛的飞碟队列
            }
            actionManager.startThrow(diskQueue);//开始抛飞碟(执行动作)
        }
        void throwDisk()
        {
            if (diskQueue.Count != 0)
            {
                GameObject disk = diskQueue.Dequeue();//从队列取出一个飞碟
                Vector3 pos = new Vector3(-disk.GetComponent<DiskData>().getDirection().x * 10, Random.Range(0f, 4f), 0);
                disk.transform.position = pos;//设置目标位置
                disk.SetActive(true);
            }
        }
    public interface ActionManagerAdapter
    {
        void setDiskNumber(int dn);//设置飞碟数目
        int getDiskNumber();//给继承的类获得飞碟数目
        SSAction getSSAction();//设置动作方式
        void freeSSAction(SSAction action);//释放某个动作
        void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Completed, int intPram = 0, string strParm = null, Object objParm = null);
        //callback的函数,用于告诉类某个动作已经完成
        void startThrow(Queue<GameObject> diskQueue);//开始抛飞碟(执行动作)
    }
    protected void Start()
    {
        sceneControl = (FirstSceneControl)Director.getInstance().current;
        sceneControl.actionManager = this;
        flys.Add(CCFlyAction.getCCFlyAction());
        base.flag = true;//这个flag如果是true表示使用运动学,false表示使用物理学
    }

    private new void Update()
    {
        if (sceneControl.getGameState() == GameState.RUNNING)
            base.Update();
    }
    protected void Start()
    {
        sceneControl = (FirstSceneControl)Director.getInstance().current;
        sceneControl.actionManager = this;
        flys.Add(CCFlyAction.getCCFlyAction());
        base.flag = false;//使用物理学
    }

    private new void Update()                                     
    {
        if (sceneControl.getGameState() == GameState.RUNNING)
        {
            base.Update();
            base.startRigidbodyAction();//启动刚体
        } 
        else
        {
            base.stopRigidbodyAction();//停止刚体
        }
    }
SSActionManager

ActionManager跟上次作业的基本相似,多了要判断哪一种运动方式用不同的update:

protected void Update()
    {
        //......

        foreach (KeyValuePair<int, SSAction> i in actions)
        {
            SSAction value = i.Value;
            if (value.destroy)
            {
                waitingDelete.Add(value.GetInstanceID());
            }
            else if (value.enable && flag)//flag就是对应上面说使用哪种运动方式的变量
            {
                value.Update();
            }
            else if(value.enable && !flag)
            {
                value.FixedUpdate();
            }
        }

        //......
    }
    public void stopRigidbodyAction()
    {
        foreach (SSAction action in actions.Values)
        {
            action.rigidbodyStopAction();
        }
    }

    public void startRigidbodyAction()
    {
        foreach (SSAction action in actions.Values)
        {
            action.rigidbodyStartAction();
        }
    }
CCFlyAction

CCFlyAction是负责实现飞碟飞行动作的类,它负责设置了大部分的变量参数。

    float acceleration;//加速度
    float horizontalSpeed;//水平速度
    Vector3 direction;
    float time;
    bool flag=false;//记录游戏是否经过暂停状态
    Vector3 temp;//记录游戏暂停时刚体游戏对象的速度矢量
    Rigidbody rigidbody; //物理运动,添加刚体

    //变量的初始化
    public override void Start()
    {
        enable = true;
        acceleration = 9.8f;
        time = 0;
        horizontalSpeed = gameObject.GetComponent<DiskData>().getSpeed();
        direction = gameObject.GetComponent<DiskData>().getDirection();
        //执行行为的对象如果有刚体性质,则需要设置刚体的速度属性
        rigidbody = gameObject.GetComponent<Rigidbody>();
        if (rigidbody)
        {
            rigidbody.velocity = horizontalSpeed * direction;
            temp = rigidbody.velocity;
        }
    }
    public override void Update()
    {
        if (gameObject.activeSelf)
        {
            time += Time.deltaTime;
            transform.Translate(Vector3.down * acceleration * time * Time.deltaTime);
            transform.Translate(direction * horizontalSpeed * Time.deltaTime);
            //运用运动学的方式,需要我们自己手动使用transform.Translate函数并且给出计算公式
            if (this.transform.position.y < -4)
            {
                this.destroy = true;
                this.enable = false;
                this.callback.SSActionEvent(this);
            }
        }
    }

    public override void FixedUpdate()//物理学方式的运动
    {
        if (gameObject.activeSelf)
        {
            //对比运动学方式就没有了要自行使用transform.Translate的步骤
            if (this.transform.position.y < -4)
            {
                this.destroy = true;
                this.enable = false;
                this.callback.SSActionEvent(this);
            }
        }
    }
DiskFactory

对于一个飞碟,有以下的一些参数:

    private Vector3 size;//大小
    private Color color;//颜色
    private float speed;//运动速度
    private Vector3 direction;//位置
    public List<DiskData> used = new List<DiskData>();
    public List<DiskData> free = new List<DiskData>();

    private void Awake()
    {
        diskPrefab = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/Disk"), Vector3.zero, Quaternion.identity);
        diskPrefab.SetActive(false);
    }
ScoreRecorder

ScoreRecorder就是拿来记录不同颜色的飞碟对应的分数,以及当玩家击中飞碟时计算总得分。
因此它的初始化是设置总分为0、设置各种颜色飞碟对应多少分:

        void Start()                                        /* 初始化各种颜色的分数值 */
        {
            score = 0;
            scoreTable.Add(Color.white, 1);
            scoreTable.Add(Color.gray, 2);
            scoreTable.Add(Color.black, 4);
        }
        public void record(GameObject disk)
        {
            score += scoreTable[disk.GetComponent<DiskData>().getColor()];
        }

演示视频:

Unity3D游戏编程-鼠标打飞碟

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值