Unity3D开发实战之守护森林

框架视图

守护森林.png

关键代码

Bird

public class Bird : MonoBehaviour
{

    //控制材料中的贴图状态 要知道计时器 每秒总帧数 帧数计算器

    //定义计时器变量

    public float timer = 0;

    //定义帧数量 也就是每秒钟要显示帧数;

    public int frameNumber = 10;

    //定义帧数计数器

    public int frameCount = 0;


    //定义两个变量 是否播放动画 是否控制跳跃;
    public bool animation = false;
    public bool canJump = false;

    void Start()
    {

        //添加刚体组件

        //给刚体施加一个向右的力(速度)
        // gameObject.GetComponent<Rigidbody>().velocity = new Vector3(5,0,0);
        //  gameObject.GetComponent<Rigidbody>().velocity = new Vector3(2, 0, 0);
        //第二种加力的方法;
        // gameObject.GetComponent<Rigidbody>().AddForce(Vector3.right*50,ForceMode.Force);

    }


    void Update()
    {

        //判断是否是可以播放动画的时候
        //if (animation)
        //{
        if (GameMannger._intance.gameState ==GameMannger.GAMESTATE_PLAYING)
        {
            //给一个恒定的速度,测试之用
            //Vector3 vel = gameObject.GetComponent<Rigidbody>().velocity;
            //gameObject.GetComponent<Rigidbody>().velocity = new Vector3(5, vel.y, vel.z);
            //计时
            timer += Time.deltaTime;

            //如果时间超过每秒钟显示的总帧数 帧数++;时间重新归零 
            if (timer >= 1.0f / frameNumber)
            {
                //帧数++;
                frameCount++;
                // timer -= Time.deltaTime ;
                timer -= Time.deltaTime + 0.05f;  //加个时间让她抖动的慢点

                //定义每帧的下标;取余  framrcount++  1/3取余是1 2/3取余是2 3/3取余是0 4/3 取余是1 5/3取余是2 6/3取余是0 或者理解理解成0,1,2,0,1,2...
                int frameIndex = frameCount % 3;
                //更新材质的 偏移值 X;
                //怎样去设置这个偏移值 X 的属性呢?
                //获取本游戏对象下的 渲染组件 的 材质(材质复数时是数组)的设置 贴图偏移值 x

                gameObject.GetComponent<Renderer>().material.SetTextureOffset("_MainTex", new Vector2(0.3333f * frameIndex, 0));//参数1:表示本材质的主要贴图(着色器的主要贴图),参数2:要改变的二维向量;

            }
        }

        //判断是否跳跃的时候才可以跳跃
        //if (canJump)
        //{

        if (GameMannger._intance.gameState == GameMannger.GAMESTATE_PLAYING)
        {
            //判断点击鼠标 给一个向上的速度 向上跳跃

            if (Input.GetMouseButtonDown(0))
            {
                //添加声音后按下跳跃时播放扇动翅膀的声音
                gameObject.GetComponent<AudioSource>().Play();

                //获取当前的速度;
                Vector3 vel2 = gameObject.GetComponent<Rigidbody>().velocity;
                //给y轴向上的速度;

                gameObject.GetComponent<Rigidbody>().velocity = new Vector3(vel2.x, 5.0f, vel2.z);

            }
        }

    }


    /// <summary>
    /// 激活小鸟的方法 用来发送方法来调用的;
    /// </summary>
    public void getLife() {        
        gameObject.GetComponent<Rigidbody>().useGravity = true; 
        gameObject.GetComponent<Rigidbody>().velocity = new Vector3(2,0,0);
    
    }

    /// <summary>
    ///     接触地面后 加大阻力 不让小鸟再次滚动;
    /// </summary>
    /// <param name="coll"></param>
    void OnCollisionEnter(Collision coll) {


      //  Debug.Log(coll.gameObject.name);

        if (coll.gameObject.name == "back")
        {
            //this.gameObject.GetComponent<Rigidbody>().velocity = new Vector3(0, 0, 0);
            this.gameObject.GetComponent<Rigidbody>().drag = 1000f;
            this.gameObject.GetComponent<Rigidbody>().angularDrag = 1000f;

           // Debug.Log(this.gameObject.name);
        }
    
    }
}

FollowBird

public class FollowBird : MonoBehaviour {

    //跟随相机
    //定义一个游戏对象用来寻找小鸟的
    private GameObject bird;

    //为跟随位置定义好的变量
    private Transform birdTransform;

    //定义好一个偏移值的变量;
    Vector3 offset;

    void Start () {

        //寻找游戏对象 小鸟 并且赋值;
        bird = GameObject.FindGameObjectWithTag("Player");//gameobject是单数,不是复数;
        birdTransform = bird.transform;
        //计算偏移值;
         offset = gameObject.GetComponent<Transform>().position - birdTransform.position;   
    }
    

    void Update () {

        Vector3 birdPos = birdTransform.position;

        //判断不要将摄像机超出边界;
        if (birdPos.y>5f)//上界
        {
            birdPos.y = 5f;
        }

        if (birdPos.y<2.5f)
        {
            birdPos.y =2.5f;
        }

        //相机位置跟随 不断补偿偏移值;
       // gameObject.GetComponent<Transform>().position = birdTransform.position + offset;
        gameObject.GetComponent<Transform>().position = birdPos + offset;

    }
}

GameMannger

public class GameMannger : MonoBehaviour {
    
    
    //定义游戏的状态;
    public static int GAMESTATE_MENU = 0;
    public static int GAMESTATE_PLAYING = 1;
    public static int GAMESTATE_END = 2;
    //只有3个背景图,不断循环 进入背景2 的时候 把背景1移到背景3 中去

    public Transform firstBG;


    //每个管道口设置一个触发器,闯过一个得一分;
    
    //定义一个分数的变量;
    public int score=0;
    
    //定义一个游戏状态
    public int gameState = GAMESTATE_MENU;

    //定义一个鸟的游戏对象 并在初始化时赋值
    private GameObject bird;


    //单例模式

    public static GameMannger _intance;

    void Awake() {
        _intance = this;   //单例模式模板 得到的是gamemannger类型;
        //给鸟赋值;
        bird = GameObject.FindGameObjectWithTag("Player");
    }


    void Update() { 
    
        //判断当前的游戏状态;
        if (gameState==GAMESTATE_MENU)
        {
            //判断是否点击屏幕
            if (Input.GetMouseButtonDown(0))
            {
                //设置游戏的状态
                gameState = GAMESTATE_PLAYING;              
                //播放动画 和 是否能跳跃 对鸟设置重力
                //bird.GetComponent<Rigidbody>().useGravity = true;              
                ////添加X轴方向的力;
                //bird.GetComponent<Rigidbody>().velocity = new Vector3(1,0,0);
                //综上 我们可以封装成一个方法 在此调用方法时 发送一个方法名;
                bird.SendMessage("getLife");
            }
        }


        //判断游戏是结束状态,把结束界面显示出来;
        if (gameState == GAMESTATE_END)
        {
            GameMenu._instance.gameObject.SetActive(true);//参数设置为true;
            //把分数转递给结束的界面 显示最后得分
            GameMenu._instance.UpdateScore(score);
        }   
    }
}

GameMenu

using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
public class GameMenu : MonoBehaviour {
    //声明持有两个分数引用的变量;
    public GUIText bestScore;
    public GUIText nowScore;
    //声明持有重新开始的游戏贴图;
    public GUITexture startTexture;

    //单例模式
    public static GameMenu _instance;

    void Awake()
    {
        _instance = this;
        this.gameObject.SetActive(false);  //默认是不调用的;
    }



    //更新分数的方法 公开的 才可以调用
    public void UpdateScore(float currentScore)
    {
        //用来获取最高分数的关键词 piayerprefs;
        float highScore = PlayerPrefs.GetFloat("score", 0);//参数1:通过key关键词 score查找最高分数  参数2:默认是0;因为第一次没有最高分数,默认值设置为0;


        //判断一下 现在传过来的分数跟最高分数对比,更新下最高分;
        if (highScore < currentScore)
        {
            highScore = currentScore;
        }


        //用来保存最高分数的关键词 PlayerPrefs;
        PlayerPrefs.SetFloat("score", highScore);



        //将分数显示出来;
        bestScore.text = highScore.ToString();
        nowScore.text = currentScore.ToString();
        //这个方法会被GameMannger调用

        //判断结束界面之后重新开始;
        //首先判断鼠标点下和游戏处于结束状态
        if (Input.GetMouseButtonDown(0)&&GameMannger._intance.gameState==GameMannger.GAMESTATE_END)
        {
            //获取重新开始游戏贴图的位置 关键语句 GetScreenRect()
            Rect rect = startTexture.GetScreenRect();

            //再次判断点击的位置是否在区域范围内;
            //先获取鼠标的位置
            Vector3 mousePos=Input.mousePosition;

            //判断鼠标点击的范围
            if (mousePos.x>rect.x&&
                mousePos.x<(rect.x+rect.width)&&
                mousePos.y>rect.y&&
                mousePos.y<(rect.y+rect.height)
                )
            {
                ////改变游戏状态;
                //GameMannger._intance.gameState = GameMannger.GAMESTATE_PLAYING;
                ////隐藏本界面
                //this.gameObject.SetActive(false);  //默认是不调用的;
                //重新加载场景
                SceneManager.LoadScene(0);
            }
        }
    }
}

MoveTrigger

public class MoveTrigger : MonoBehaviour {
    //定义一个公开的背景
    public Transform currentBG;
    //定义持有两个管道的应用
    public Pipe pipe1;
    public Pipe pipe2;
    //触发事件 看谁触发了我,判断后 将背景1 移到背景2去

   public  void OnTriggerEnter(Collider coll) {

        if (coll.tag=="Player")
        {
            //第一步 得到放在游戏管理器的第一个bg的Transform;
         Transform firstBg=GameMannger._intance.firstBG;
            //第二步  移动; 改变位置;
         currentBG.transform.position = new Vector3(firstBg.position.x+10f,currentBG.transform.position.y,currentBG.transform.position.z);
            //第三部 把背景图更新为当前的位置;
         GameMannger._intance.firstBG = currentBG;            
            //第四步 随机生成管道的位置;
           //定义 持有管道的引用 调用起方法生成随机位置;
         pipe1.RandomGeneratePosition();
         pipe2.RandomGeneratePosition();
        }    
    }
}

Pipe

public class Pipe : MonoBehaviour { 
    void Start () { 
        //测试是否随机;
        RandomGeneratePosition();
    }
    /// <summary>
    /// 让Y轴的位置随机 随机范围是-0.1至-0.4;
    /// </summary>
    public void RandomGeneratePosition() {
        float pos_Y = Random.Range(-0.4f,-0.1f);  //参数1:最小值 参数2:最大值;
        //本地坐标
        gameObject.transform.localPosition = new Vector3(gameObject.transform.localPosition.x,pos_Y,gameObject.transform.position.z);    
    }

    /// <summary>
    /// 判断是否通过管道,加一分
    /// </summary>
    void OnTriggerExit(Collider coll) { //触犯3 个事件  OnTriggerEnter OnTriggerStay OnTriggerExit

        if (coll.tag=="Player")
        {
            //播放得分声音
            gameObject.GetComponent<AudioSource>().Play();

            //加分 调用单例模式静态的方法 的分数++
            GameMannger._intance.score++;
        }
    
    }

    /// <summary>
    /// ongui事件
    /// </summary>
    void OnGUI() { 
        //显示分数;
       // GUILayout.Label(GameMannger._intance.score.ToString());
        GUILayout.Label("Score:"+GameMannger._intance.score);
    }

}

PipeCollision

public class PipeCollision : MonoBehaviour {
    //定义两个 碰撞的声音 小鸟结束的声音 的变量
    public AudioSource hitMusic;
    public AudioSource dieMusic;

    /// <summary>
    /// 检测小鸟碰撞到管道,游戏结束 在结束前播放碰撞的声音
    /// </summary>
    void OnCollisionEnter(Collision coll)
    {

        if (coll.gameObject.tag == "Player")
        {
            //播放碰撞的声音
            //gameObject.GetComponent<AudioSource>().Play();
            hitMusic.Play();
            //播放小鸟结束的声音
            dieMusic.Play();
            //切换游戏状态
            GameMannger._intance.gameState = GameMannger.GAMESTATE_END;
        }

    }
}

守护森林.gif
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,681评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,710评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,623评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,202评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,232评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,368评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,795评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,461评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,647评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,476评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,525评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,226评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,785评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,857评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,090评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,647评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,215评论 2 341

推荐阅读更多精彩内容