Unity开发微信跳一跳小游戏

unity开发微信跳一跳

目录

建立项目

准备人物、地板、小方块

实现摄像头跟随

实现地板移动

实现小方块自动生成

实现小人跳动

实现小人伸缩

实现小方块自动销毁

实现小方块随机大小和随机颜色

实现分数显示

实现跌落重玩

player完整脚本


建立项目

简单实现一下微信跳一跳小游戏,打包成安卓安装包放手机上玩。

首先建一个3D空项目,要记住项目名称不能有中文、空格、特殊字符(别问我是怎么知道的T_T)。

准备人物、地板、小方块

然后先建个小人出来,弄个player,给他两个子对象,一个球体当头,一个圆柱体当身子。

 可以搞个材料上色,没有颜色也没关系,我一开始先不管,颜色是后面添加材料有的。

再整块Plane当地板,一定要足够大。

最后弄个cube小方块当平台让小人站在上面。

然后我们的东西就基本准备好了。

实现摄像头跟随

我们的主人公是会跳的,所以我们必须让我们的摄像头跟着小人一起跑。

首先手动给摄像头寻找最好的参数视角:

然后写个脚本挂在摄像头上,就让它以我们刚刚找好的偏移时刻跟着我们的player跑。

using UnityEngine;

public class follow_player : MonoBehaviour
{
    public Transform player;
    public Vector3 offset;

    private void FixedUpdate()
    {
        transform.position = player.position + offset;
    }
}

记得把我们的player拉到这里,还有设置好偏移:

实现地板移动

同样的道理,我们的地板也要跟着小人一起移动,为什么呢?因为地板是有大小限制的,小人不停的跑是有可能会跑出边界的,所以我们要让地板一起走。

给地板挂个脚本:

using UnityEngine;

public class Ground : MonoBehaviour
{
    public Transform player;

    // Update is called once per frame
    void Update()
    {
        var position = player.position;
        transform.position = new Vector3(position.x, 0, position.z);
    }
}

有同学可能会问了,那地板跑了,小方块不也跑了?

有道理,但是不给他摩擦力他怎么跑@_@。

实现小方块自动生成

我们要让小人跳到一块小方块就自动生成下一块小方块,写个脚本,为了方便后面脚本都统一挂在小人身上,除了小方块的随机大小和颜色,这个我们后面再说。

我们写一个自动生成小方块的函数,当然在此之前我们先把小方块拖进Asset里面整成预制件。

由于我们的跳一跳是只有两个方向的,所以我们先随机一个方向出来,然后分情况生成,对于位置,我们需要记录前一个小方块的位置,然后在此之上做偏移。

    private void NewCube()
    {
        var random = new System.Random();
        direction = random.Next(0, 2);
        if (direction == 0)
        {
            var cube = Instantiate(cubePrefab, new Vector3(Random.Range(10, 13), 0, 0) + cubePlace,
                Quaternion.identity);
            cubePlace = cube.transform.position;
            cubes.Enqueue(cube);
        }
        else
        {
            var cube = Instantiate(cubePrefab, new Vector3(0, 0, Random.Range(10, 13)) + cubePlace,
                Quaternion.identity);
            cubePlace = cube.transform.position;
            cubes.Enqueue(cube);
        }

        if (cubes.Count > maxCubeNumber)
        {
            var cube = cubes.Dequeue();
            Destroy(cube);
        }
    }

当然你会发现这里多了个队列,这个我们后面销毁小方块会用到。

实现小人跳动

这里是最关键的地方,也是bug最多的地方。

首先简单来说,我们需要记录触摸手机屏幕的时间作为小人冲量的大小。

根据二八原则,80%的代码是为了解决bug出现的,20%的代码就可实现简单功能。

在这里我们只讲那实现简单功能的20%代码,剩下的80%靠大家领悟。

            var touch = Input.touches[0];
            if (touch.phase == TouchPhase.Began)
            {
                start = Time.time;
            }
            else if (touch.phase == TouchPhase.Ended)
            {
                var time = Time.time - start;

                if (direction == 0)
                {
                    playerRigidbody.AddForce(new Vector3(1, 1, 0) * (time * speed), ForceMode.Impulse);
                }
                else
                {
                    playerRigidbody.AddForce(new Vector3(0, 1, 1) * (time * speed), ForceMode.Impulse);
                }

            }

到此,本游戏基本功能基本实现,下面是继续完善版。 

实现小人伸缩

我要的效果就是我摁下去他就变矮变胖。

同时矮了一半了就不能再矮了,跳也不能跳太远,至于不能跳太近是因为那样会引发某个bug,我的解决办法就是当无法解决bug的时候就去禁止导致bug的行为,还有就是在空中飞的时候不能再跳了。

在原来代码的基础上丰富:

        if (Input.touchCount > 0 && inTheAir == false)
        {
            jump = true;
            if (body.transform.localScale.y > 0.5)
            {
                body.transform.localScale += new Vector3(1, -1, 1) * (0.45f * Time.deltaTime);
                head.transform.localPosition += new Vector3(0, -1, 0) * (0.45f * Time.deltaTime);
            }

            var touch = Input.touches[0];
            if (touch.phase == TouchPhase.Began)
            {
                start = Time.time;
            }
            else if (touch.phase == TouchPhase.Ended)
            {
                var time = Time.time - start;
                if (time > 3)
                {
                    time = 3;
                }else if (time < 0.5f)
                {
                    time = 0.5f;
                }

                if (direction == 0)
                {
                    playerRigidbody.AddForce(new Vector3(1, 1, 0) * (time * speed), ForceMode.Impulse);
                }
                else
                {
                    playerRigidbody.AddForce(new Vector3(0, 1, 1) * (time * speed), ForceMode.Impulse);
                }

                body.transform.localScale = new Vector3(1, 1.5f, 1);
                head.transform.localPosition = new Vector3(0, 3.7f, 0);
                inTheAir = true;
            }
        }

实现小方块自动销毁

用过了的就没有利用价值,特别是在视野范围内都看不到你的时候。

我们通过维持一个小方块队列,当队列数量超过一定数目时,销毁队首小方块。

        if (cubes.Count > maxCubeNumber)
        {
            var cube = cubes.Dequeue();
            Destroy(cube);
        }

后期测试的时候发现一个问题,那就是会把第一个预制件销毁,导致后面无法生成小方块,因此需要解脱第一个小方块预制件的身份,让它成为一个普通的克隆件。

实现小方块随机大小和随机颜色

给它挂个小脚本:

using UnityEngine;

public class Cube : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        GetComponent<Renderer>().material.color = new Color(Random.value, Random.value, Random.value);
        var radius = Random.Range(4, 7);
        transform.localScale = new Vector3(radius,Random.Range(4,7),radius);
    }
}

实现分数显示

整一个Canvas,添加一个text

 把text的位置整到左上角

在player的脚本上添加text脚本,时刻更新text:

        scoreText.text = score.ToString();

实现跌落重玩

添加碰撞检测代码,如果碰到地板或者跳了但是还在原来的小方块,重新开始:

    private void OnCollisionEnter(Collision other)
    {
        if (other.gameObject.CompareTag("Ground") || other.gameObject == currentCube && jump)
        {
            // FindObjectOfType<GameManager>().EndGame();
            SceneManager.LoadScene("MainScene");
        }
        else if (other.gameObject != currentCube)
        {
            score += 1;
            inTheAir = false;
            NewCube();
            currentCube = other.gameObject;
        }
    }

player完整脚本

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class Play : MonoBehaviour
{
    public Rigidbody playerRigidbody;
    public GameObject body;
    public GameObject head;
    public GameObject cubePrefab;
    public Vector3 cubePlace;
    private Queue<GameObject> cubes = new Queue<GameObject>();
    public int speed = 10;
    public int direction = 0;
    public int maxCubeNumber = 10;
    public Transform massCenter;
    public GameObject currentCube;
    public Text scoreText;
    public int score = 1;
    private bool jump = false;
    private bool inTheAir = false;
    private float start = 0;

    // Start is called before the first frame update
    void Start()
    {
        var cube = Instantiate(cubePrefab, cubePlace, Quaternion.identity);
        cubes.Enqueue(currentCube);
        cubes.Enqueue(cube);
        GetComponent<Rigidbody>().centerOfMass = massCenter.localPosition;
    }

    private void FixedUpdate()
    {
        if (Input.touchCount > 0 && inTheAir == false)
        {
            jump = true;
            if (body.transform.localScale.y > 0.5)
            {
                body.transform.localScale += new Vector3(1, -1, 1) * (0.45f * Time.deltaTime);
                head.transform.localPosition += new Vector3(0, -1, 0) * (0.45f * Time.deltaTime);
            }

            var touch = Input.touches[0];
            if (touch.phase == TouchPhase.Began)
            {
                start = Time.time;
            }
            else if (touch.phase == TouchPhase.Ended)
            {
                var time = Time.time - start;
                if (time > 3)
                {
                    time = 3;
                }else if (time < 0.5f)
                {
                    time = 0.5f;
                }

                if (direction == 0)
                {
                    playerRigidbody.AddForce(new Vector3(1, 1, 0) * (time * speed), ForceMode.Impulse);
                }
                else
                {
                    playerRigidbody.AddForce(new Vector3(0, 1, 1) * (time * speed), ForceMode.Impulse);
                }

                body.transform.localScale = new Vector3(1, 1.5f, 1);
                head.transform.localPosition = new Vector3(0, 3.7f, 0);
                inTheAir = true;
            }
        }

        scoreText.text = score.ToString();
    }

    private void NewCube()
    {
        var random = new System.Random();
        direction = random.Next(0, 2);
        if (direction == 0)
        {
            var cube = Instantiate(cubePrefab, new Vector3(Random.Range(10, 13), 0, 0) + cubePlace,
                Quaternion.identity);
            cubePlace = cube.transform.position;
            cubes.Enqueue(cube);
        }
        else
        {
            var cube = Instantiate(cubePrefab, new Vector3(0, 0, Random.Range(10, 13)) + cubePlace,
                Quaternion.identity);
            cubePlace = cube.transform.position;
            cubes.Enqueue(cube);
        }

        if (cubes.Count > maxCubeNumber)
        {
            var cube = cubes.Dequeue();
            Destroy(cube);
        }
    }

    private void OnCollisionEnter(Collision other)
    {
        if (other.gameObject.CompareTag("Ground") || other.gameObject == currentCube && jump)
        {
            // FindObjectOfType<GameManager>().EndGame();
            SceneManager.LoadScene("MainScene");
        }
        else if (other.gameObject != currentCube)
        {
            score += 1;
            inTheAir = false;
            NewCube();
            currentCube = other.gameObject;
        }
    }
}

还有一些bug,欢迎发现,解决更好。

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MaolinYe(叶茂林)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值