Unity3D 实现方块跑酷

                                          跑酷

一.功能需求.... 1

1.1 UI 界面自适应.... 1

1.2地图生成算法.... 1

1.3.角色控制.... 1

1.4.角色与地图交互.... 1

1.5 Android 打包.... 2

1.6.其他技术.... 2

二.UI界面自适应.... 2

2.1 自己添加一个分辨率 1080X1920. 2

2.2 固定分辨率.... 3

三.地图生成算法.... 3

3.1>地图基本生成(地面加墙壁).... 3

3.2>地图数据存储(List+Array).... 3

3.3>连续生成(判断角色位置)... 8

3.4>地面塌陷(协程定时销毁)... 9

3.5>路障生成(随机算法+协程实现动画).... 10

四.角色的控制.... 12

4.1 实现的思路.... 12

4.2实现的代码.... 12

五.角色与地图交互.... 13

5.1>蜗牛痕迹(渲染地面模型)... 13

5.2>死亡判断(List+触发)... 15

5.3>得分判断(List 位移+触发).... 16

六.Android 打包.... 17

1>JDK 和 SDK 配置.... 17

2>APK 打包细节设置.... 18

3>触屏操作控制.... 20

七.其他技术.... 21

1>游戏逻辑重置.... 21

2>PlayerPrefs 存储数据.... 22

3>摄像机跟随.... 22

八.部分效果展示.... 24

8.1 游戏开始.... 24

8.2游戏中.... 24

8.3 角色死亡.... 25

 

一.功能需求

1.1 UI 界面自适应

该案例自适应所有 16:9 分辨率的手机

1.2地图生成算法

1>地图基本生成(地面加墙壁)

2>地图数据存储(List+Array)

3>连续生成(判断角色位置)

4>地面塌陷(协程定时销毁)

5>路障生成(随机算法+协程实现动画)

1.3.角色控制

1>基本行走(List+Array)

2>边界控制(List+Array)※

1.4.角色与地图交互

1>蜗牛痕迹(渲染地面模型)

2>死亡判断(List+触发)

3>得分判断(List 位移+触发)

1.5 Android 打包

1>JDK 和 SDK 配置

2>APK 打包细节设置

3>触屏操作控制

1.6.其他技术

1>游戏逻辑重置

2>PlayerPrefs 存储数据

3>摄像机跟随

二.UI界面自适应

2.1 自己添加一个分辨率 1080X1920

 

2.2 固定分辨率

 

三.地图生成算法

3.1>地图基本生成(地面加墙壁)

3.2>地图数据存储(List+Array)

单排地图

 

双排地图

 

public void CreateMapItem(int x(定义的偏移量))

    {

       

     

        ///单排地图

        for (int i = 0; i < 10; i++)//生成的行数即3维坐标(x,y,z)Z的值

        {

            GameObject[] tiles1 = new GameObject[6];//定义一个存放游戏对象的数组并初始化长度为6. 用于存放单排的瓷砖和墙

            for (int j = 0; j <6; j++)//生成的列数即3维坐标(x,y,z)X的值.

            {

                Vector3 pos = new Vector3(j * lenth, 0, i * lenth + x * lenth);//定义每块瓷砖的生成位子

                Vector3 rot = new Vector3(-90, 45, 0);//定义每块瓷砖的旋转角度

             

                Color dp = new Color(134 / 255f, 113 / 255f, 173 / 255f); //定义每块瓷砖的颜色

     

                 if (j == 0 || j == 5)//每一列的最开始和最后的一个生成墙壁

                 {

                                     tile = Instantiate(pre_wall2, pos, Quaternion.Euler(rot)); //生成墙

                      tile.GetComponent<Transform>().SetParent(m_tf);//把每块墙设置为Mapmanager的子物体

                      tile.GetComponent<MeshRenderer>().material.color = new Color(115 / 255f, 86 / 255f, 139 / 255f);// 改变每块墙的颜色

                    

                    

                 }

                 else

                 {

                     int pr = CalcPR(); //定义一个值获取概率函数产生的值即(0-3)

                     switch (pr)

                     {

                                   case 0:

                                          tile = Instantiate (pre_tile, pos, Quaternion.Euler (rot));

                                          tile.GetComponent<Transform> ().SetParent (m_tf);

                                          tile.GetComponent<Transform> ().Find ("normal_a2").gameObject.GetComponent<MeshRenderer> ().material.color = dp;

                                          Transform tile_transform = tile.GetComponent<Transform> ();

                                          int pre_gem = CalcGamePR ();  //在产生瓷砖的前提下,如果 pre_gem=1 则在瓷砖上方产生金币。

                                          if (pre_gem == 1) {

                                                 GameObject gem=      Instantiate(pre_Gem,tile_transform.position+new Vector3(0.0f,0.06f,0.0f),Quaternion.identity);

                                                 gem.GetComponent<Transform>().SetParent (tile_transform); //把金币设置为瓷砖的子物体,实现没被吃掉的金币同瓷砖一起崩塌。

                                          }

                            break;

                          case 1:

                               GameObject  tile = new GameObject();

                            tile.GetComponent<Transform>().position = pos;//设置瓷砖的位子

                            tile.GetComponent<Transform>().SetParent(m_tf);//设置瓷砖的父物体

                            break;

                          case 2:

                            tile = Instantiate(pre_moving_spikes, pos, Quaternion.Euler(rot));

                            tile.GetComponent<Transform>().SetParent(m_tf);

                            break;///地面陷阱

                          case 3:

                            tile = Instantiate(pre_smashing_spikes, pos, Quaternion.Euler(rot));

                            tile.GetComponent<Transform>().SetParent(m_tf);

                            break;///天空陷阱

                     }

                  

                 }

                 tiles1[j] = tile; //存放每一行的瓷砖和墙壁到数组中

               

            }

            list.Add(tiles1); //把10行单排的地图存放在List中

            ///双排地图

            GameObject[] tiles2 = new GameObject[5]; 定义一个存放游戏对象的数组并初始化长度为5 用于存放双排的瓷砖和墙

            for (int j = 0; j < 5; j++) //生产双排瓷砖的列数

            {

                Vector3 pos1 = new Vector3(lenth / 2.0f + j * lenth, 0, i * lenth + lenth / 2.0f + x * lenth);

                Vector3 rot = new Vector3(-90, 45, 0);

                Color dp = new Color(146 / 255f, 120 / 255f, 180 / 255f);

                 int pr = CalcPR();

                    

             

                switch (pr)

                {

                    case 0:

                                    tile = Instantiate(pre_tile, pos1, Quaternion.Euler(rot));

                        tile.GetComponent<Transform>().SetParent(m_tf);

                        tile.GetComponent<Transform>().Find("normal_a2").gameObject.GetComponent<MeshRenderer>().material.color = dp;

                                   Transform tile_transform = tile.GetComponent<Transform> ();

                                   int pre_gem = CalcGamePR ();//同上的生成金币

                                   if (pre_gem == 1) {

                                          GameObject gem=      Instantiate(pre_Gem,tile_transform.position+new Vector3(0.0f,0.06f,0.0f),Quaternion.identity);

                                          gem.GetComponent<Transform> ().SetParent (tile_transform);

                                   }

                                   break;

                            case 1:

                        tile = new GameObject();

                        tile.GetComponent<Transform>().position = pos1;

                        tile.GetComponent<Transform>().SetParent(m_tf);

                        break;

                    case 2:

                        tile = Instantiate(pre_moving_spikes, pos1, Quaternion.Euler(rot));

                        tile.GetComponent<Transform>().SetParent(m_tf);

                      

                        break;///地面陷阱

                    case 3:

                         tile = Instantiate(pre_smashing_spikes, pos1, Quaternion.Euler(rot));

                        tile.GetComponent<Transform>().SetParent(m_tf);

                        break;///天空陷阱

                }

                tiles2[j] = tile; 

            }

          

            list.Add(tiles2);

        }

  

3.3>连续生成(判断角色位置)

3.3.1 实现的思路

1.当Player移动时到达指定的行数(高度)即Z值等于指定的数值(List长度减去一定的数值)时实现地图的连续生成.
2.第一张地图是游戏开始就生成的,第2张地图的生成点如图容易知道为x+10*lenth(对角线长度的一半),第3张则为x+20*lenth以此类推。

 

3.新地图主要是Z的值在改变,x和y的值不变

Vector3 pos = new Vector3(j * lenth, 0, i * lenth + x * lenth)

3.3.2.主要实现的代码

public void UpdateMap()

    {

        if (z == m_MapManager.list.Count - 10) //当z等于List(每一个地图的list=20)长度减去10时,即z在每个地图的中间时开始生成下一个地图

        {

            m_MapManager.CreateMapItem((j++) * 10);//j一开始等于1,调用生成地图的函数实现生成下一个地图。

            m_MapManager.AddPR();//每生成一个地图相应陷阱的生产概率也随之增加。

        }

    }

3.4>地面塌陷(协程定时销毁)

3.4.1 实现的思路

1.循环遍历list 为每个游戏对象添加钢体
2.当崩塌赶上了Player后停止崩塌

3.4.2 实现的主要代码

private IEnumerator TileDown()

    {

      

        for (int i = 0; i < list.Count; i++)

        {

                     if (i == m_player.z) //崩塌赶上了角色停止崩塌

           {

               StopTileDown();

                            if (m_player.life) {

                                   m_player.gameObject.AddComponent<Rigidbody>();

                                   m_player.StartCoroutine ("gameover");

                            }              

          }

            for (int j = 0; j < list[i].Length; j++)

            {

                Rigidbody rib= list[i][j].AddComponent<Rigidbody>();

           rib.angularVelocity = new Vector3(Random.Range(-1.0f, 1.0f), Random.Range(-1.0f, 1.0f), Random.Range(-1.0f, 1.0f)) * 3.0f;

                Destroy(list[i][j], 2);

            }

            yield return new WaitForSeconds(0.3f);//0.3s后实现下一行的崩塌

         

}

    }

3.5>路障生成(随机算法+协程实现动画)

3.5.1 随机算法

  private int CalcPR() //路障的随机算法

    {

        int rd = Random.Range(1, 101);//定义一个随机范围(1-100)

        if (rd <=pr_hole)//坑

        {return 1;}

        else if (rd >31&& rd<=31+ms) //地面刺

        {return 2;}

        else if(rd >61&&rd<=61+ss)//天空陷阱

        {return  3;}

              else 

        return 0;

    }

    /// <summary>

    /// 增加概率

    /// </summary>

    public void AddPR()//路障产生的概率增加

    {

        pr_hole+=2;

        ms+=1;

        ss+=1;

    }

       private int CalcGamePR(){ //金币产生的随机算法

              int rd = Random.Range (1, 101);

              if (rd <= goal) {

                     return 1;

              } else

                     return 0;

}

3.5.2 协程实现

    private IEnumerator Up()//实现地面的陷阱的刺向上刺

    {

        while (true)

        {

            m_sontransform.position = Vector3.Lerp(m_sontransform.position, targetPosition, Time.deltaTime*3.0f);

            yield return null;

        }

    }

    private IEnumerator Down()//实现地面的陷阱的刺向下

    {

        while (true)

        {

            m_sontransform.position = Vector3.Lerp(m_sontransform.position, nomalPosition, Time.deltaTime*3.0f);

            yield return null;

        }

    }

    private IEnumerator UpAndDown()

    {

        while (true)

        {

            StartCoroutine("Up"); //开始向上刺

            yield return new WaitForSeconds(6);//6秒后

            StopCoroutine("Up");//停止向上移动

            StartCoroutine("Down");//开始向下移动

            yield return new WaitForSeconds(6);//停止6s后

            StopCoroutine("Down");//停止向下移动

//目的是为了向上移动的时候只向上移动,向下移动的时候只向下移动。

        }

}

四.角色的控制

4.1 实现的思路

1.向左边移动,当z为奇数且x>0的时候 x才会减一,并且x不等于0时z才可以继续移动

2.向右移动时 如果z不是奇数时且x不等于4 Z才可以改变,如果Z时偶数且x小于4 x的值才可以发生改变

4.2实现的代码

public void PlayerMove()

    {

        if (Input.GetKeyDown(KeyCode.A))

        {

            Left();

        }

        if (Input.GetKeyDown(KeyCode.D))

        {

            Right();

        }

    }

    public void Left()

    {

        if (life)//向左移动

        {

            if (x != 0) { z++; }

            if (z % 2 == 1 && x > 0)

            {

                x = x - 1;

            }

            Setposition();

        }

       

    }

    public void Right()//向右移动

    {

        if (life)

        {

            if (!(z % 2 == 1 && x == 4)) { z++; }

            if (z % 2 == 0 && x < 4)

            {

                x = x + 1;

            }

            Setposition();

        }

       

        

}

五.角色与地图交互

5.1>蜗牛痕迹(渲染地面模型)

5.1.1实现的思路

1.通过获取list[z][x]来获取该物体并获取其Meshrender组件的material下的color属性实现对Player走过的路径奇偶行的颜色不一样。

2.实现的代码

  public void Setposition()

    {

        Transform tileTransform = m_MapManager.GetList()[z][x].GetComponent<Transform>();

         m_transform.position = tileTransform.position + new Vector3(0, m_MapManager.Lenth / 2.0f, 0);

        m_transform.rotation = tileTransform.rotation;

        if (z % 2 == 1)

        {

            if (tileTransform.tag == "tile")

            { tileTransform.Find("normal_a2").gameObject.GetComponent<MeshRenderer>().material.color = new Color(0.5f, 0.5f, 0.5f); }

            else if (tileTransform.tag == "moving_spikes")

            { tileTransform.Find("moving_spikes_a2").gameObject.GetComponent<MeshRenderer>().material.color = new Color(0.5f, 0.5f, 0.5f); }

            else if (tileTransform.tag == "smashing_spikes")

            { tileTransform.Find("smashing_spikes_a2").gameObject.GetComponent<MeshRenderer>().material.color = new Color(0.5f, 0.5f, 0.5f); }

            else

            {

                gameObject.AddComponent<Rigidbody>();

                StartCoroutine("gameover");

            }

        }

        else

        {

            if (tileTransform.tag == "tile")

            { tileTransform.Find("normal_a2").gameObject.GetComponent<MeshRenderer>().material.color = new Color(0.9f, 0.9f, 0.9f); }

            else if (tileTransform.tag == "moving_spikes")

            { tileTransform.Find("moving_spikes_a2").gameObject.GetComponent<MeshRenderer>().material.color = new Color(0.9f, 0.9f, 0.9f); }

            else if (tileTransform.tag == "smashing_spikes")

            { tileTransform.Find("smashing_spikes_a2").gameObject.GetComponent<MeshRenderer>().material.color = new Color(0.9f, 0.9f, 0.9f); }

            else

            {

                gameObject.AddComponent<Rigidbody>();

                StartCoroutine("gameover");

            }

        }

        UpdateMap();

              AddScoreCount ();

    }

5.2>死亡判断(List+触发)

1.被天空刺刺到

调用

  private IEnumerator gameover()

    {

        

                 life = false;

            Music.PlayOneShot(GameOver);

            bg_Music.Stop();

                    

                     SaveData ();

            yield return null;

            StartCoroutine("GameReset");  

    }

2.被地面陷阱刺到

同上

3.掉到坑里

{

                gameObject.AddComponent<Rigidbody>();

                StartCoroutine("gameover");

            }

4.被崩塌追赶到

if (i == m_player.z)

           {

               StopTileDown();

                            if (m_player.life) {

                                   m_player.gameObject.AddComponent<Rigidbody>();

                                   m_player.StartCoroutine ("gameover")

}    

5.3>得分判断(List 位移+触发)

1.每走一步分数加一

       private void AddScoreCount(){

      

              score_count++;

              //print ("Score_count:" + score_count);

        m_game.UpdateGame(gem_score, score_count);

       }

2.吃一金币,金币数加一

       private void AddGemCount(){

              gem_score++;

              //print ("gem_score:" + gem_score);

        m_game.UpdateGame(gem_score, score_count)

       }

六.Android 打包

1>JDK 和 SDK 配置

 

2>APK 打包细节设置

 

3>触屏操作控制

1.添加一个透明度为0的图片并附加Ui button (左半边屏幕)

 

2.添加点击事件

 

3.添加一个透明度为0的图片并附加Ui button (右半边屏幕)

 

4.添加点击事件

 

七.其他技术

1>游戏逻辑重置

    private IEnumerator GameReset()

    {

        yield return new WaitForSeconds(2);

        //角色重置

        PLayerReset();

        //地图重置

        m_MapManager.MapReset();

        //UI重置

        m_game.UIReset();

        //摄像机重置

        m_ca.CameraReset();

     

        yield return null;

    }

2>PlayerPrefs 存储数据

private void SaveData(){

      

              PlayerPrefs.SetInt ("gem", gem_score);//存储金币数到注册表

              if (score_count > PlayerPrefs.GetInt ("score", 0))

                     PlayerPrefs.SetInt ("score", score_count);//当移动分数大于注册表的数值实现更新,即存储最高分

       }

3>摄像机跟随

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class Camerafollow : MonoBehaviour {

    private Transform m_player;

    private Transform m_transform;

    private Vector3 m_nextPos;

    private bool startFollow = false;

    private Vector3 m_nomal;

       // Use this for initialization

    void Start()

    {

    

        m_transform = gameObject.GetComponent<Transform>();

        m_player=GameObject.Find("cube_books").GetComponent<Transform>();

        m_nextPos=new Vector3(m_transform.position.x,m_transform.position.y,m_player.position.z);

        m_nomal = m_transform.position;

    }     

       // Update is called once per frame

       void Update () {

        if (startFollow)

        {

            Follow();

        }

       

       }

    public void SetStartFollow(bool startfollow)

    {

        startFollow = startfollow;

    }

   

    /// <summary>

    /// 启动摄像机跟随

    /// </summary>

    public void Follow()

    {

     

            m_nextPos = new Vector3(m_transform.position.x, m_transform.position.y, m_player.position.z);//只改变z的值

            m_transform.position = Vector3.Lerp(m_transform.position, m_nextPos, Time.deltaTime);//平滑的过度

       

    }

    public void CameraReset()

    {

     

        m_transform.position = m_nomal;

        SetStartFollow(false);

       

    }

}

八.部分效果展示

8.1 游戏开始

 

8.2游戏中

 

8.3 角色死亡

 

原文地址:https://www.cnblogs.com/VastTry/p/8028509.html