HW5-打飞碟

一、游戏说明

飞碟游戏
游戏内容:

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

游戏涉及的知识点:

  1. 世界与屏幕坐标、射线与碰撞、动态修改shader;
  2. 支持mono的单实例、游戏对象工厂、扩展游戏对象属 性与行为的方法。

二、相关知识

1.为什么需要工厂对象

  • 游戏对象的创建与销毁高成本,必须减少销毁次数。如游戏中子弹
  • 屏蔽创建与销毁的业务逻辑,使程序易于扩展

2.diskFactory的设计
在这里插入图片描述

  • 前面游戏,由导演、场记、运动管理师、演员构成。
  • 新游戏中,场记请了记分员、飞碟管理员
  • 其中记分员按飞碟的数据计分,记分员拥有计分规则
  • 场记只需要管理出飞碟规则与管理碰撞就可以了

3.带缓存工厂模式的实现

  • getDisk(ruler) 伪代码
    IF (free list has disk) THEN
    a_disk = remove one from list ELSE
    a_disk = clone from Prefabs
    ENDIF
    Set DiskData of a_disk with the ruler Add a_disk to used list
    Return a_disk
  • FreeDisk(disk)
    Find disk in used list
    IF (not found) THEN THROW exception Move disk from used to free list

三、关键实现分析

1.首先是飞碟信息的存储类
挂在飞碟上制作为预制

//射击当前飞碟得分
    public int score = 1;
    //飞碟颜色设置                               
    public Color color = Color.white;
    //飞碟初始的位置          
    public Vector3 direction;
    //飞碟大小                          
    public Vector3 scale = new Vector3( 1 ,0.5f, 1);

2.飞碟工厂类
主要有的功能为:飞碟预制的生产、飞碟的选择、未使用飞碟的回收

生产:

//在空闲的飞碟列表中尝试找到符合tag的飞碟
        for(int i=0;i<free.Count;i++)
        {
            if(free[i].tag == tag)
            {
                disk_prefab = free[i].gameObject;
                free.Remove(free[i]);
                break;
            }
        }
//如果空闲列表中没有所需求的预制飞碟,则需要生产预制飞碟
        if(disk_prefab == null)
        {
            if (tag == "disk1")
            {
                disk_prefab = Instantiate(Resources.Load<GameObject>("Prefabs/disk1"), new Vector3(0, start_y, 0), Quaternion.identity);
            }
            else if (tag == "disk2")
            {
                disk_prefab = Instantiate(Resources.Load<GameObject>("Prefabs/disk2"), new Vector3(0, start_y, 0), Quaternion.identity);
            }
            else
            {
                disk_prefab = Instantiate(Resources.Load<GameObject>("Prefabs/disk3"), new Vector3(0, start_y, 0), Quaternion.identity);
            }
//设定颜色、位置等属性
            float ran_x = Random.Range(-1f, 1f) < 0 ? -1 : 1;
            disk_prefab.GetComponent<Renderer>().material.color = disk_prefab.GetComponent<DiskData>().color;
            disk_prefab.GetComponent<DiskData>().direction = new Vector3(ran_x, start_y, 0);
            disk_prefab.transform.localScale = disk_prefab.GetComponent<DiskData>().scale;
        }
//添加到使用的列表中
        used.Add(disk_prefab.GetComponent<DiskData>());

飞碟的选择:
不同的回合对应不同的飞碟

if (round == 1)
        {
            choice = Random.Range(0, scope1);
        }
        else if(round == 2)
        {
            choice = Random.Range(0, scope2);
        }
        else
        {
            choice = Random.Range(0, scope3);
        }

飞碟回收:
未被击中的飞碟,将其回收至空闲列表中,并将其移出正在使用的飞碟列表

for(int i = 0;i < used.Count; i++)
        {
            if (disk.GetInstanceID() == used[i].gameObject.GetInstanceID())
            {
                used[i].gameObject.SetActive(false);
                free.Add(used[i]);
                used.Remove(used[i]);
                break;
            }
        }

3.场景控制FirstSceneControl类
负责游戏场景中的各种事件的处理,以及游戏规则如游戏开始结束等的执行。
发送飞碟的处理:

void Update ()
    {
        if(game_start)
        {
            //游戏结束时取消发送飞碟
            if (game_over)
            {
                CancelInvoke("LoadResources");
            }
            //游戏开始的判定
            if (!playing_game)
            {
                InvokeRepeating("LoadResources", 1f, speed);
                playing_game = true;
            }
            SendDisk();
            //难度加大的配置
            if (score_recorder.score >= score_round2 && round == 1)
            {
                round = 2;
                speed = speed - 0.6f;
                CancelInvoke("LoadResources");
                playing_game = false;
            }
            else if (score_recorder.score >= score_round3 && round == 2)
            {
                round = 3;
                speed = speed - 0.5f;
                CancelInvoke("LoadResources");
                playing_game = false;
            }
        }
    }

击中飞碟的相关判断:

public void Hit(Vector3 pos)
    {
        Ray ray = Camera.main.ScreenPointToRay(pos);
        RaycastHit[] hits;
        hits = Physics.RaycastAll(ray);
        bool not_hit = false;
        for (int i = 0; i < hits.Length; i++)
        {
            RaycastHit hit = hits[i];
            if (hit.collider.gameObject.GetComponent<DiskData>() != null)
            {
                for (int j = 0; j < disk_notshot.Count; j++)
                {
                    if (hit.collider.gameObject.GetInstanceID() == disk_notshot[j].gameObject.GetInstanceID())
                    {
                        not_hit = true;
                    }
                }
                if(!not_hit)
                {
                    return;
                }
                disk_notshot.Remove(hit.collider.gameObject);
                score_recorder.Record(hit.collider.gameObject);
                Transform explode = hit.collider.gameObject.transform.GetChild(0);
                explode.GetComponent<ParticleSystem>().Play();
                StartCoroutine(WaitingParticle(0.08f, hit, disk_factory, hit.collider.gameObject));
                break;
            }
        }
    }

回收飞碟

IEnumerator WaitingParticle(float wait_time, RaycastHit hit, DiskFactory disk_factory, GameObject obj)
    {
        yield return new WaitForSeconds(wait_time);
        hit.collider.gameObject.transform.position = new Vector3(0, -9, 0);
        disk_factory.FreeDisk(obj);
    }

4.飞碟飞行动作

public static diskFlyAction GetSSAction(Vector3 direction, float angle, float power)
    {
        diskFlyAction action = CreateInstance<diskFlyAction>();
        if (direction.x == -1)
        {
            action.start_vector = Quaternion.Euler(new Vector3(0, 0, -angle)) * Vector3.left * power;
        }
        else
        {
            action.start_vector = Quaternion.Euler(new Vector3(0, 0, angle)) * Vector3.right * power;
        }
        return action;
    }

5.GUI界面渲染

void OnGUI ()
    {
        bold_style.normal.textColor = new Color(1, 0, 0);
        bold_style.fontSize = 16;
        text_style.normal.textColor = new Color(0,0,0, 1);
        text_style.fontSize = 16;
        score_style.normal.textColor = new Color(1,0,1,1);
        score_style.fontSize = 16;
        over_style.normal.textColor = new Color(1, 0, 0);
        over_style.fontSize = 25;

        if (game_start)
        {
            if (Input.GetButtonDown("Fire1"))
            {
                Vector3 pos = Input.mousePosition;
                action.Hit(pos);
            }

            GUI.Label(new Rect(10, 5, 200, 50), "分数:", text_style);
            GUI.Label(new Rect(55, 5, 200, 50), action.GetScore().ToString(), score_style);

            GUI.Label(new Rect(Screen.width - 120, 5, 50, 50), "血量:", text_style);
            //显示血量
            for (int i = 0; i < life; i++)
            {
                GUI.Label(new Rect(Screen.width - 75 + 10 * i, 5, 50, 50), "+", bold_style);
            }
            if (life == 0)
            {
                high_score = high_score > action.GetScore() ? high_score : action.GetScore();
                GUI.Label(new Rect(Screen.width / 2 - 20, Screen.width / 2 - 250, 100, 100), "游戏结束", over_style);
                GUI.Label(new Rect(Screen.width / 2 - 10, Screen.width / 2 - 200, 50, 50), "你获得的分数:", text_style);
                GUI.Label(new Rect(Screen.width / 2 + 50, Screen.width / 2 - 200, 50, 50), high_score.ToString(), text_style);
                if (GUI.Button(new Rect(Screen.width / 2 - 20, Screen.width / 2 - 150, 100, 50), "重新开始"))
                {
                    life = 6;
                    action.ReStart();
                    return;
                }
                action.GameOver();
            }
        }
        else
        {
            if (GUI.Button(new Rect(Screen.width / 2 - 20, Screen.width / 2-290, 100, 50), "开始游戏"))
            {
                game_start = true;
                action.BeginGame();
            }
        }
    }

四、成品

在这里插入图片描述
在这里插入图片描述

视频
最后感谢师兄的博客给了很大的帮助!不然真的很难实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值