Unity3d——打飞碟小游戏

51人阅读 评论(0) 收藏 举报

打飞碟小游戏

本次打飞碟小游戏,基本上是在上两周面向对象上编程实现的一个小游戏。在课程群里面,老师分享了一个优秀博客,此处引入,作为借鉴。
在本次作业中,我的脚本结构主要是参考上一次动作分离版牧师与魔鬼,保留SSDirector、SSAction与SSActionManager。在这次写代码的过程中,我发现我定义的接口太混乱,所以将所有的接口又再次提出放到了Interface中,这样比较方便debug。在本次代码中,新引入的就是Singleton,以及DiskData与DiskFactory。在此处的DiskFactory是用来管理飞碟出场的,并且是单例的;DiskData是用来对每一个飞碟加入自己的属性,即得分与大小比例,然后加入飞碟的预制中。
以下是上周动作分离设计的UML图:
这里写图片描述
在这个游戏中,稍稍改良,在CCActionManager改为FlyActionManager,下面的CCActionSequence改为了一个动作发生——UFOFlyAction。
在这位同学的博客中,我借鉴了他的爆炸的预设和skybox,好吧,是因为我实在懒得挑了,而且这个天空盒的画风真的太赞了~向这位同学学习学习~

游戏简介

在这个游戏中,一共有三个关卡,第一个关卡只有红色的飞碟,一个飞碟是1分。当得到15分后,即进入第二关,新加入黄色飞碟,击中一个得2分。当得到30分之后,即进入第三关,新加入蓝色飞碟,击中一个得3分。当错过了10个飞碟的话,游戏结束。

具体函数实现

  • 首先介绍FirstController:
    继承MonoBehavior,ISceneController,IUserAction。主要函数如下:
 void Start ()
{
//获取各个实例及各个类
    SSDirector director = SSDirector.getInstance();     
    director.currentScenceController = this;             
    diskFactory = Singleton<DiskFactory>.Instance;
    scoreRecorder = Singleton<ScoreRecorder>.Instance;
    actionManager = gameObject.AddComponent<FlyActionManager>() as FlyActionManager;
    userGUI = gameObject.AddComponent<UserGUI>() as UserGUI;

}

void Update ()
{
    if(isGameStart)
    {
        if (isGameOver)
        {
            CancelInvoke("LoadResources");
        }
        if (!isPlayGame)
        {
            InvokeRepeating("LoadResources", 1f, speed);
            isPlayGame = true;
        }
        SendDisk();
        if (scoreRecorder.score >= scoreRound2 && round == 1)
        {
            round = 2;
            speed = speed - 0.6f;
            CancelInvoke("LoadResources");
            isPlayGame = false;
        }
        else if (scoreRecorder.score >= scoreRound3 && round == 2)
        {
            round = 3;
            speed = speed - 0.5f;
            CancelInvoke("LoadResources");
            isPlayGame = false;
        }
    }
}
//加载资源
public void LoadResources()
{
    diskQueue.Enqueue(diskFactory.GetDisk(round)); 
}
//发送飞碟
private void SendDisk()
{
    float position_x = 16;                       
    if (diskQueue.Count != 0)
    {
        GameObject disk = diskQueue.Dequeue();
        diskNotHit.Add(disk);
        disk.SetActive(true);
        float ran_y = Random.Range(1f, 4f);
        float ran_x = Random.Range(-1f, 1f) < 0 ? -1 : 1;
        disk.GetComponent<DiskData>().direction = new Vector3(ran_x, ran_y, 0);
        Vector3 position = new Vector3(-disk.GetComponent<DiskData>().direction.x * position_x, ran_y, 0);
        disk.transform.position = position;
        float power = Random.Range(10f, 15f);
        float angle = Random.Range(15f, 28f);
        actionManager.UFOFly(disk,angle,power);
    }

    for (int i = 0; i < diskNotHit.Count; i++)
    {
        GameObject temp = diskNotHit[i];
        if (temp.transform.position.y < -10 && temp.gameObject.activeSelf == true)
        {
            diskFactory.FreeDisk(diskNotHit[i]);
            diskNotHit.Remove(diskNotHit[i]);
            userGUI.BloodReduce();
        }
    }
}
//击打飞碟
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 < diskNotHit.Count; j++)
            {
                if (hit.collider.gameObject.GetInstanceID() == diskNotHit[j].gameObject.GetInstanceID())
                {
                    not_hit = true;
                }
            }
            if(!not_hit)
            {
                return;
            }
            diskNotHit.Remove(hit.collider.gameObject);
            scoreRecorder.Record(hit.collider.gameObject);
            Transform explode = hit.collider.gameObject.transform.GetChild(0);
            explode.GetComponent<ParticleSystem>().Play();
            StartCoroutine(WaitingParticle(0.08f, hit, diskFactory, hit.collider.gameObject));
            break;
        }
    }
}
//统计得分
public int GetScore()
{
    return scoreRecorder.score;
}
//重新开始
public void Restart()
{
    isGameOver = false;
    isPlayGame = false;
    scoreRecorder.score = 0;
    round = 1;
    speed = 2f;
}
//游戏结束
public void GameOver()
{
    isGameOver = true;
}

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);
}

public void BeginGame()
{
    isGameStart = true;
}
  • ScoreRecord:
    这个脚本主要是实现计分功能,其代码实现很简单:
public class ScoreRecorder : MonoBehaviour {
    public int score;
    // Use this for initialization
    void Start () {
        score = 0;
    }

    public void Record(GameObject disk)
    {
        int temp = disk.GetComponent<DiskData>().score;
        score += temp;
    }

    public void Reset()
    {
        score = 0;
    }
}
  • 飞碟自身的函数和飞碟工厂的脚本实现如下:
public class DiskData : MonoBehaviour {

    public int score = 1;
    public Vector3 direction;
    public Vector3 scale = new Vector3(1, 1, 1);
}
public class DiskFactory : MonoBehaviour {
    public GameObject diskPrefab = null;
    private List<DiskData> used = new List<DiskData>();
    private List<DiskData> free = new List<DiskData>();

    public GameObject GetDisk(int round)
    {
        int choice = 0;
        int scope = 1, scope1 = 4, scope2 = 7;
        float startY = -10f;
        string tag;
        diskPrefab = null;

        if(round == 1)
            choice = Random.Range(0, scope);
        else if(round == 2)
            choice = Random.Range(0, scope1);
        else if(round == 3)
            choice = Random.Range(0, scope2);

        if(choice <= scope)
            tag = "disk1";
        else if(choice <= scope && choice > scope1)
            tag = "disk2";
        else
            tag = "disk3";

        for(int i = 0; i < free.Count; i++)
        {
            if(free[i].tag == tag)
            {
                diskPrefab = free[i].gameObject;
                free.Remove(free[i]);
                break;
            }
        }
        if(diskPrefab == null)
        {
            if (tag == "disk1")
                diskPrefab = Instantiate(Resources.Load<GameObject>("Prefabs/disk1"), new Vector3(0, startY, 0), Quaternion.identity);
            else if(tag == "disk2")
                diskPrefab = Instantiate(Resources.Load<GameObject>("Prefabs/disk2"), new Vector3(0, startY, 0), Quaternion.identity);
            else if(tag == "disk3")
                diskPrefab = Instantiate(Resources.Load<GameObject>("Prefabs/disk3"), new Vector3(0, startY, 0), Quaternion.identity);

            float ranX = Random.Range(-1f, -1f) < 0 ? -1 : 1;
            diskPrefab.GetComponent<DiskData>().direction = new Vector3(ranX, startY, 0);
            diskPrefab.transform.localScale = diskPrefab.GetComponent<DiskData>().scale;
        }
        used.Add(diskPrefab.GetComponent<DiskData>());
        return diskPrefab;
    }

    public void FreeDisk(GameObject disk)
    {
        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;
            }
        }
    }

}
  • Singleton:
    这个脚本我是按照老师课件上来写的,用来实现飞碟工厂的单例:
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;
        }
    }
}
  • 接下来还有一个实现界面的UserGUI:
void OnGUI ()
    {
        boldStyle.normal.textColor = new Color(1, 0, 0);
        boldStyle.fontSize = 20;
        textStyle.normal.textColor = new Color(0,0,0, 1);
        textStyle.fontSize = 20;
        scoreStyle.normal.textColor = new Color(1,0,1,1);
        scoreStyle.fontSize = 20;
        overStyle.normal.textColor = new Color(1, 0, 0);
        overStyle.fontSize = 25;

        if (gameStart)
        {
            //用户射击
            if (Input.GetButtonDown("Fire1"))
            {
                Vector3 pos = Input.mousePosition;
                action.Hit(pos);
            }

            GUI.Label(new Rect(10, 5, 200, 50), "Score:", textStyle);
            GUI.Label(new Rect(55, 5, 200, 50), action.GetScore().ToString(), scoreStyle);

            GUI.Label(new Rect(Screen.width - 120, 5, 50, 50), "Life:", textStyle);
            //显示当前血量
            for (int i = 0; i < life; i++)
            {
                GUI.Label(new Rect(Screen.width - 75 + 10 * i, 5, 50, 50), "X", boldStyle);
            }
            //游戏结束
            if (life == 0)
            {
                score = action.GetScore();
                GUI.Label(new Rect(Screen.width / 2 - 20, Screen.width / 2 - 250, 100, 100), "Game Over", overStyle);
                GUI.Label(new Rect(Screen.width / 2 - 10, Screen.width / 2 - 200, 50, 50), "Score:", textStyle);
                GUI.Label(new Rect(Screen.width / 2 + 50, Screen.width / 2 - 200, 50, 50), score.ToString(), textStyle);
                if (GUI.Button(new Rect(Screen.width / 2 - 20, Screen.width / 2 - 150, 100, 50), "Restart"))
                {
                    life = 10;
                    action.Restart();
                    return;
                }
                action.GameOver();
            }
        }
        else
        {
            GUI.Label(new Rect(Screen.width / 2 - 30, Screen.width / 2 - 350, 100, 100), "Hit UFO!", overStyle);
            if (GUI.Button(new Rect(Screen.width / 2 - 25, Screen.width / 2 - 250, 100, 50), "Game Start"))
            {
                gameStart = true;
                action.BeginGame();
            }
        }
    }
    public void BloodReduce()
    {
        if(life > 0)
            life--;
    }

再放出游戏界面的截图:
这里写图片描述
这里写图片描述
这里写图片描述

以上就是主要函数了,总体代码请看我的github,这是传送门

查看评论

简单打飞碟游戏

一、鼠标点击小游戏         在写简单飞碟游戏之前,先写一个鼠标点击的小游戏热热身:游戏场景中会随机出现小圆圈,鼠标点击后,圆圈3秒后自动消失。      (1).  首先,创建Terrai...
  • pnxldzw
  • pnxldzw
  • 2016-05-30 15:36:03
  • 808

Unity3D作业五的项目一

题目: 写一篇短文,描述以下游戏需求的实现。请写步骤,贴代码并解释: 实现点击效果。 用 Plane 或其他物体做地面, tag 为“Finish”点击地面后,出现一...
  • PalytoxinRK
  • PalytoxinRK
  • 2017-03-27 19:08:03
  • 270

Unity3D 从入门到放弃(四)----打飞碟

Unity3D 从入门到放弃(五)—–打飞碟填坑计划的万恶之源 写在开头: 本来感觉应该是不会写博客的,而且也不是很擅长写 博客。但在后来,突然醒悟到,博客这个东西,实际上并不是给别人看的(...
  • MyCodecOdecoDecodE
  • MyCodecOdecoDecodE
  • 2017-03-23 14:15:04
  • 447

Unity3D学习笔记(6)-- 打飞碟游戏改进版

一.简要说明 这是上一次打飞碟游戏的改进版本,这次和上次的版本有小些差异,在功能上主要添加了一个物理运动的模块,以下来讲讲这些改动。 二.游戏效果图 三.UML图 先上一张UML图 Physi...
  • x2_yt
  • x2_yt
  • 2017-04-03 21:37:12
  • 412

Unity3D学习(5)之工厂回收利用的3D版飞碟游戏

这一次我们来做的任务是3D版鼠标点击鼠标的游戏。我们先来看一下游戏需求。 案例研究:“鼠标打飞碟”游戏设计 游戏需求:     1. 分多个 round , 飞碟数量每个 round 都是 n ...
  • zzj051319
  • zzj051319
  • 2017-03-26 14:22:08
  • 902

unity打飞碟

unity hw4 1、编写一个简单的鼠标打飞碟(Hit UFO)游戏 游戏的演示视频地址:http://v.youku.com/v_show/id_XMzU0Mjg0NDg3Mg==.htm...
  • DDghsot
  • DDghsot
  • 2018-04-16 18:55:22
  • 42

Unity3D学习笔记(6)—— 飞碟射击游戏

游戏规则:          游戏分多个回合,每个回合有N个飞碟,玩家按空格后,321倒数3秒,飞碟飞出,点击鼠标,子弹飞出。飞碟落地或被击中,则准备下一次射击。每回合飞碟的大小、颜色、发射位置、发射...
  • Simba_Scorpio
  • Simba_Scorpio
  • 2016-04-03 20:43:27
  • 3610

Unity3D 重力下打飞碟

前言本次完成,虽然具体实现不同,代码结构上,很大程度参考了 。。。 ,所以复杂的东西也不写了,贴上代码以供自己以后使用;Diskfactory.cs这个cs文件主要控制了 飞碟的产生和使用using ...
  • qq_28057541
  • qq_28057541
  • 2016-04-15 17:15:12
  • 323

Unity笔记-打飞碟游戏

目的:创建一个打飞碟游戏(简陋)对于学渣来说,这个游戏并非那么容易。各个模块之间的联合本学渣认为还是比较强的。 游戏要求: 游戏要分多个 round , 飞碟数量每个 round 都是 n 个,但...
  • thatwall
  • thatwall
  • 2017-05-08 01:57:01
  • 224

Unity 无重力系统打飞碟

首先设计关卡:Round 1:白色飞碟(大,慢) Round 2 : 白色飞碟 + 蓝色飞碟(小,慢) Round 3: 红色飞碟 (小,快)实验要求是所造的飞碟数不能超过N个,也就是循环利用,...
  • qq_28057541
  • qq_28057541
  • 2016-03-27 21:19:17
  • 467
    个人资料
    等级:
    访问量: 995
    积分: 45
    排名: 180万+
    文章分类
    文章存档
    最新评论