微信跳一跳项目总结

微信跳一跳项目总结

一、UGUI

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

1.开始游戏

提示Tip(text)

得分Score(text)

2.结束游戏

最终得分FinalScore(text)

游戏结束 GameOver(text)

重新开始按钮RestartBtn(button)

RestartButton.onClick.AddListener(() => { SceneManager.LoadScene(0); });

广告弹窗 含两个按钮

二、脚本控制

游戏体量不大这里用了一个脚本实现所有功能

1.生成台阶

首先拿到预制体 声明一个数组Boxtemplates[ ] 里面存放圆形台阶和方形台阶

然后克隆上面的台阶库,并设定位置、大小、颜色

prefab=Boxtemplates[ Random.range(0,Boxtemplates.Length) ]

NextStage=GameObject.Instantiate(prefab).transform

2.鼠标控制

首先MouseButtonDown 记录鼠标按下开始时间 用于后面计算跳跃力度

然后 GetMouseButton中改变玩家和台阶的Scale 实现蓄力效果

最后GetMouseButtonUp中 运行 跳跃功能函数方法 运用DOTween插件

Bug 1

玩家在空中还是可以点击鼠标进行跳跃

解决方法:设置一个bool变量EnableInput 再触发碰撞后才为true 一开始为false 并且 松开鼠标变为false 就可以解决 在这里插入图片描述

Bug2

通过试玩发现 玩家飞在空中是点击鼠标不放 落在台阶后松开鼠标 玩家会弹飞 这里是 落在台阶EnableInput为true 时 鼠标状态为Input.GetMouseButton 跳过了Input.GetMouseDown这一环节 使StartTime 还为上一条的StartTime 导致 elapse>1

解决方法:类似于Bug1 增加一个bool变量 isMouseDown 只有Input.GetMouseButtonDown 后才能获取MouseButton MouseButtonUp的操作。 一开始isMouseDown为false 只有Input.GetMouseButtonDown操作后为true 后面在MouseButtonUp变为false 即可解决。

增加一个判断条件

if (Input.GetMouseButton(0)&&isMouse==true)

if (Input.GetMouseButtonUp(0)&&isMouse==true)

3.跳跃功能

确定方向

用到了生成台阶方法中NextStage的Pos 两个位置相减并且normalized 得到方向 为了减少误差可以让Y=0 最后用DOTween插件实现玩家跳跃翻转的效果 这里注意下normalized的误差 有的时候会0.9几 所以设置判定条件的时候不要写 1

计算力度

Rig.AddForce(new Vector3(0, 5f, 0) + jumpDirection * elapse * Force, ForceMode.Impulse);

AddForce的常用API 一个表示xyz三个方向力度的vec3 和力的模式

4.OnCollisionEnter

判断是否落在台阶上

给台阶预制体创建一个子物体RolesPos 将玩家的位置赋给子物体 再用子物体的localposition 判断玩家落在了台阶的什么位置 从而确定是否成功落在台阶上在这里插入图片描述

成功落在台阶上则 生成台阶 增加分数 移动相机 使EnaleInput 为true

5.增加分数AddScore

首先获取玩家人物位置 然后计算人物位置与台阶的位置(中心)的距离

targetDistance = Vector3.Distance(hitPos, CurrentStage.transform.position)

实现双倍得分功能

最后显示再UI界面上 ScoreText=“得分”+Score 这里会自动转换成string 显示在ui界面上

6.MoveCamera

这里使用DOTween插件

Camera.main.transform.DOMove(transform.position + CameraRelativePosition, 1);
最后附上源码
	using DG.Tweening;
	using System.Collections;
	using System.Collections.Generic;
	using UnityEngine;
	using UnityEngine.SceneManagement;
	using UnityEngine.UI;

	public class Player : MonoBehaviour
	{
    //添加的力
    private float Force = 4;
    //最大距离,指的是盒子生成的最大距离
    private float MaxDistance=2f;
    //第一个盒子
    public GameObject Stage;
    //盒子仓库
    public GameObject[] BoxTemplates;
    //右上角的得分文本
    public Text ScoreText;
    //人物身上的粒子效果
    public GameObject Particle;
    //人物的头部和身体的Transform
    public Transform Head;
    public Transform Body;
    //游戏结束的时候,提示游戏结束的文本
    public GameObject GameOver;
    //游戏结束的时候显示的分数面板
    public Text FinalScore;
    //重新开始游戏的按钮
    public Button RestartButton;
    //角色身上的音频源组件
    public AudioSource audioSource;
    // 成功跳到盒子上面的音效
    //蓄力的音效
    //开始游戏的音效
    //失败的音效
    public AudioClip SuccessAudio, AddForceAudio, StartAudio, FallAudio;
    //角色身上的刚体组件
    public Rigidbody Rig;
    //开始加力的时间,
    private float StartAddForceTime;
    //当前的盒子
    private GameObject CurrentStage;
    //相机相对的位置
    private Vector3 CameraRelativePosition;
    //本局的分数统计
    public int Score;
    //盒子生成的方向数组
    Vector3[] Directions = new Vector3[] { new Vector3(1,0,0), new Vector3(0, 0, 1) };
    //启用输入与否,也就是限制当前能否控制玩家用的
    private bool EnableInput = false;
    //舞台的初始位置
    private Vector3 StageInitPos;
    private Vector3 StageInitScale;
    //上次奖励的分数
    private int LastReward=1;
    //下一个盒子
    private Transform NextStage;

    GoogleAdMob googleAdMob;//谷歌广告的脚本
    private Button LookBtn;//观看和取消的按钮
    private Button CancelBtn;
    private Transform AdMobTips;//提示的窗口
    private GameObject gooleAdMobGO;
    public  GameObject gooleAdMobPrefabs;
    public Text LoveText;
    private bool isMouse=false;
    void Start()
    {
        CurrentStage = Stage;
        //相机的位置减去人物的位置,获得他们的相对距离
        CameraRelativePosition = Camera.main.transform.position - transform.position;
        StageInitPos = Stage.transform.localPosition;
        StageInitScale = Stage.transform.localScale;
        //点击重新开始按钮,重新加载一次场景
        RestartButton.onClick.AddListener(() => { SceneManager.LoadScene(0); });
        Rig.centerOfMass = Vector3.zero;
       

        
        SpawnStage();//生成出舞台
       
        
        
        
        //播放开始游戏的音效   
        PlayAudio(StartAudio);
        gooleAdMobGO = GameObject.Find("GoogleAdMob");//查询谷歌广告脚本的物体
        if (gooleAdMobGO == null)
        {
            gooleAdMobGO = GameObject.Instantiate(gooleAdMobPrefabs);
            gooleAdMobGO.name = "GoogleAdMob";

        }
        googleAdMob = gooleAdMobGO.GetComponent<GoogleAdMob>();
        AdMobTips = GameObject.Find("Canvas").transform.Find("AdMobTips").transform;
        LookBtn = AdMobTips.transform.Find("LookBtn").GetComponent<Button>();
        CancelBtn = AdMobTips.transform.Find("CancelBtn").GetComponent<Button>();
       
        LookBtn.onClick.AddListener(googleAdMob.PlayAdsense);
        CancelBtn.onClick.AddListener(OnGameOver);
    }

    /// <summary>
    /// 生成舞台
    /// </summary>
    private void SpawnStage()
    {
        //从仓库中随机取出一个舞台
        GameObject prefab = BoxTemplates[Random.Range(0, BoxTemplates.Length)];
        NextStage = GameObject.Instantiate(prefab).transform;
        //随机设置在上一个盒子的上方或者右边
        NextStage.position = CurrentStage.transform.position + Directions[Random.Range(0, Directions.Length)] * Random.Range(1.2f, MaxDistance);
        var randomScale = Random.Range(0.5f, 1);
        //随机设置缩放
        NextStage.transform.localScale = new Vector3(randomScale, 0.5f, randomScale);
   
        //随机设置颜色
        NextStage.GetComponent<MeshRenderer>().material.color =
            new Color(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f));
    }

    // Update is called once per frame
    void Update()
    {

        Rig.WakeUp();//避免刚体自动休眠
        if (EnableInput)
        {
            if (Input.GetMouseButtonDown(0))
            {  isMouse = true; 
                //当允许人物控制且鼠标左键被按下的时候记录开始蓄力的时间
                StartAddForceTime = Time.time;
                Particle.SetActive(true);
                //播放音效
                PlayAudio(AddForceAudio);
            }
           if (Input.GetMouseButton(0)&&isMouse==true)
            {
                //鼠标在按住的期间要把舞台往下移动,且缩小人物Y轴的缩放
                //限制缩小的最大限度
               if (CurrentStage.transform.localScale.y>0.4f)
                {
                    //身体缩小
                    Body.transform.localScale += new Vector3(1.5f, -1f, 1.5f) * 0.05f * Time.deltaTime;
                    //随着身体缩小,头部也要往下移动
                    Head.transform.localPosition += new Vector3(0, -1, 0) * 0.1f * Time.deltaTime;
                    //盒子位置和缩放调整
                    CurrentStage.transform.localScale += new Vector3(0, -1, 0) * 0.15f * Time.deltaTime;
                    CurrentStage.transform.localPosition += new Vector3(0, -1, 0) * 0.15f * Time.deltaTime;
                }
            }
            if (Input.GetMouseButtonUp(0)&&isMouse==true)
            {
             isMouse = false;
                //放开鼠标左键的时候
                audioSource.Stop();
                //获取到总共蓄力了多少时间
                var elapse = Time.time - StartAddForceTime;
                Debug.Log(elapse);
                if (elapse > 1)
                {
                    //添加限制,最多蓄力一秒,
                    elapse = 1;
                }
                //关闭蓄力的粒子
                Particle.SetActive(false);
                //起跳
                OnJump(elapse);   
                //还原人物形状
                Body.transform.DOScale(0.1f, 0.2f);
                Head.transform.DOLocalMoveY(0.29f, 0.2f);
                //还原盒子的形状
                CurrentStage.transform.DOLocalMoveY(StageInitPos.y, 0.4f);
                CurrentStage.transform.DOScaleY(StageInitScale.y, 0.4f);
              EnableInput = false;
            }
        }


     
    }
    /// <summary>
    /// 进入跳跃
    /// </summary>
    /// <param name="elapse"></param>
    private void OnJump(float elapse)
    {
        //通过目标位置-人物位置 求出跳跃的方向
        Vector3 jumpDirection = (NextStage.position - transform.position).normalized;
       
        jumpDirection.y = 0; 
        Debug.Log(jumpDirection);  
        //给刚体加力
        Rig.AddForce(new Vector3(0, 5f, 0) + jumpDirection * elapse * Force, ForceMode.Impulse);
  
        if (jumpDirection.x>=0.9)
        {
            transform.DOLocalRotate(new Vector3(0, 0, -360), 0.6f, RotateMode.LocalAxisAdd);
        }
        else
        {
            transform.DOLocalRotate(new Vector3(-360, 0, 0), 0.6f, RotateMode.LocalAxisAdd);
        }
    
    }
    /// <summary>
    /// 碰撞的事件
    /// </summary>
    /// <param name="collision"></param>
    private void OnCollisionEnter(Collision collision)
    {

        Rig.Sleep();

        if (GameOver.activeInHierarchy)
        {
            return;
        }
        if (!collision.transform.CompareTag("Stage"))
        {
            PlayerDie();
            return;
        }      
        Transform rolesPos = collision.transform.Find("RolesPos");
        rolesPos.position = transform.position;

       
        if(rolesPos.localPosition.x<0.5f&& rolesPos.localPosition.x > -0.5f)
        {

            if(rolesPos.localPosition.z < 0.5f && rolesPos.localPosition.z > -0.5f)
            {
                //当我们的身体有一半在舞台的外部,就算游戏结束。
                //说明没有掉下舞台
                if (CurrentStage != collision.gameObject)
                {//如果碰撞到的不是当前的舞台 //把碰撞到的舞台设置为当前的
                    CurrentStage = collision.gameObject;
                    //添加分数
                    AddScore();               
                    //生成出新的舞台
                    SpawnStage();
                    //移动相机
                    MoveCamera();
                    //重新允许用户输入
                    EnableInput = true;
                    //播放音效
                    PlayAudio(SuccessAudio);
                }
                else
                {
                    EnableInput = true;
                }
            }
            else
            {
                //游戏结束
                PlayerDie();
            }
        }
        else
        {
            //游戏结束
            PlayerDie();
        }

    }
    /// <summary>
    /// 角色死亡处理
    /// </summary>
    private void PlayerDie()
    {
        EnableInput = false;
	#if UNITY_ANDROID//如果是安卓平台,
        OpendAdMobTips(); //提示是否观看广告
	#elif UNITY_IPHONE//如果是IPHONE
           OpendAdMobTips(); //提示是否观看广告
	#else//如果不是安卓也不是IPHONE平台的
        OnGameOver();
	#endif

        //播放失败的音效
        PlayAudio(FallAudio);
    }
    /// <summary>
    /// 提示是否观看广告
    /// </summary>
    private void OpendAdMobTips()
    {
        AdMobTips.gameObject.SetActive(true);
    }


    //添加分数
    private void AddScore()
    {
        //首先获取人物的位置,也就是命中的位置
        Vector3 hitPos = transform.position;
        hitPos.y = CurrentStage.transform.position.y;
        //计算与目标距离
        float targetDistance = Vector3.Distance(hitPos, CurrentStage.transform.position);
        if (targetDistance < 0.1f)
        {
            //如果离中心非常近,要加的分数翻倍
            LastReward *= 2;
        }
        else
        {
            LastReward = 1;
        }
        Score += LastReward;
        ScoreText.text = "得分:" + Score;
      
    }
    /// <summary>
    /// 移动摄像机跟随人物
    /// </summary>
    private void MoveCamera()
    {
        Camera.main.transform.DOMove(transform.position + CameraRelativePosition, 1);
    }
    /// <summary>
    /// 结束游戏 首先是PC端,人物死亡后调用
    /// 然后移动端,看完广告之后调用
    /// </summary>
    public void OnGameOver()
    {
        AdMobTips.gameObject.SetActive(false);      
        //显示最终得分
        FinalScore.text = "最终得分:" + Score;
        //开启重新开始的按钮
        RestartButton.gameObject.SetActive(true);
        FinalScore.gameObject.SetActive(true);
        GameOver.SetActive(true);
    }
    /// <summary>
    /// 播放音效
    /// </summary>
    /// <param name="audioClip"></param>
    private void PlayAudio(AudioClip audioClip)
    {
        audioSource.clip = audioClip;
        audioSource.Play();
    }
	}
  • 9
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

大橘915818

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

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

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

打赏作者

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

抵扣说明:

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

余额充值