赞
踩
目录
Unity 游戏实例开发集合 之 JumpJump (简单跳一跳) 休闲小游戏快速实现
Unity 游戏实例开发集合,使用简单易懂的方式,讲解常见游戏的开发实现过程,方便后期类似游戏开发的借鉴和复用。
本节介绍,JumpJump (简单跳一跳) 休闲小游戏快速实现的方法,希望能帮到你,若有不对,请留言。
1、游戏开始,会自动生成平台
2、鼠标按下左键角色会自动朝向平台方向,长按住右键进行蓄力
3、松开鼠标左键,角色就会根据蓄力多少,进行抛物线跳跃
4、落到平台上,则对应加分,落下平台,游戏就结束
5、游戏结束后,这里会自动重新开始游戏
1、MonoBehaviour 生命周期函数:Awake,Start,Update,Destroy,OnGUI
2、Input 按键的监控鼠标按键的状态
3、GameObject.Instantiate 物体的生成,GameObject.Destroy 物体的销毁
4、Camera 的跟随管理
5、Rigidbody2D 重力效果,添加 Collider ,进行 碰撞检测
6、GUIStyle GUI样式,GUI.Label 添加文字的功能使用
7、Vector3.Lerp 位移向量插值使用,Vector3.Distance 位置距离函数的使用
8、一些数据,路径等的统一常量管理
9、Transform.Rotate 旋转使用
10、IEnumerator 协程 , StartCoroutine 开始协程 和 StopAllCoroutines 停止所有协程的使用
11、物体简单抛物线运动的使用
12、Action<int> OnChangeValue 属性变化中委托的使用
13、Resources.Load<GameObject>() 代码加载预制体的使用
14、Fog 雾效的简单使用,和渐变背景的简单实现
15、 SceneManager.LoadScene 加载,和 SceneManager.GetActiveScene() 当前场景的获取
16、Lighting Settings 场景光线烘培的简单使用
17、等等
这是一个 3D 游戏,主要用到 SpriteRenderer 、2D Collider,2D Rigidbody,以及 TextMesh 等资源组件,所有资源都是Unity自带,没有导入其他外部贴图模型资源。
1、首先,做一个简单的渐变的背景,添加一个 Plane ,设置如下,并添加一个材质
2、打开设置,开启雾效Fog,这里是渐变背景断网关键
3、在Lighting 的 Other Settings 中勾选 Fog,设置颜色,Mode 为 Liner ,处设置 Start 10,End 13(后面在调整细节)
3、添加一个 Cube,设置 scale 为 (1,8,1)
4、设置 Sky_Plane 的 Transform 和 Main Camera(旋转摄像机是为了渐变从下到上(上面显示 Sky_Plane的颜色)) 的 Transform 如图,效果大概如下(设置竖屏(800x1280))
5、再次调整 Sky_Plane 的 Rotation X,和 Lighting 的 Other Settings Fog 的 Start 和 End,最后效果如下
6、这里我们不需要 Sky_Plane 接收投影和 Collider ,这里去掉 Mesh Collider 组件
7、新建一个空物体GameObject,Reset 其 Transform ,把 MainCamera 和 Sky_Plane 作为其子物体,并改为为 CameraGroup,便于后期跟随主角 Player 移动
8、根据 Cube ,创建平台几种颜色的 Platform,并取消他们 投射阴影 Cast Shadows 为 off (注意:他们的子物体都取消 Collider 组件)
9、创建一个空物体 GameObject ,改名为 Player,添加一个 Rigbody ,FreezeRotation 的 X Y Z
10、Player 添加一个 Capsule,改名为 Player_Capsule,Scale根据 Platform 的 比例进行调整,所以这里调小为 (0.5,0.5,0.5),这里调整 Position 的 Y 为 0.5 是为了使得Player_Capsule的底部至于 Player 局部坐标的原点,便于 Y 上 Scale 的变化(变化的基点从底部缩放)如图,最后 Sphere 作为前方向的辨识使用而已(去掉Collider 组件)
11、在 Player 添加 TrailRenderer ,添加运动的拖尾效果(效果根据实际效果调整),这里设置宽度为 0.5 的渐变减小,时间为 0.5,颜色如图,添加 TrailRenderer 材质,,材质 shader 为 Particles /Additive,效果如下
12、把 Player 作为预制体,放在 resources/Prefabs 文件夹下
13、添加一个 UI Text ,用来显示分数
14、添加空物体GameObject,改名为 World,把CameraGroup,置于其下,并合理设置 GameObject 的 PlayerSpawnPos ,FirstPlatFormCubeSpawnPos位置,作为 Player 和Platform 的初始化生成位置
15、在工程中添加 Platform 脚本,主要功能是继承 MonoBehaviour,在 Update 中控制 Platform 的生成动画,和 Player 跳入和触发 OnCollisionEnter 事件,进行 生成下一个 Platform,以及增加分数
16、Platform 中的主要函数,PlatformSpawnAniamtion 和 FirstOnCollisionEnter
- /// <summary>
- /// 平台的上升动画
- /// </summary>
- void PlatformSpawnAniamtion() {
- if (m_IsSpawnAnimation == true)
- {
- m_MoveDeltra += 1f / GameConfig.PLATFRM_SPAWN_ANIMATION_MOVE_SPEED * Time.deltaTime;
- transform.position = Vector3.Lerp(transform.position, m_TargetPos, m_MoveDeltra);
- if (Vector3.Distance(transform.position, m_TargetPos) <= 0.01f)
- {
- transform.position = m_TargetPos;
-
- m_IsSpawnAnimation = false;
- }
- }
- }
-
- /// <summary>
- /// 第一次碰撞进入平台,触发对应事件
- /// 这里事件主要是 生成下一个 Platform 和 增加分数
- /// </summary>
- private void FirstOnCollisionEnter()
- {
- if (m_IsOnCollisionEntered == false)
- {
- m_IsOnCollisionEntered = true;
- m_OnCollisionEnterAction?.Invoke(this.transform.position);
-
- }
- }
17、在工程中添加 PlatformManager 脚本,主要功能是,加载所有类型的 Platform 预制体,初始化第一个随机 Platform 平台生成,并且设置平台生成下一个 Platform 的事件,并控制游戏中保留的 Platform 的总数,多则删除最先的 Platform
18、PlatformManager 脚本的主要函数:LoadPlatformPrefabs() 加载 Platform 预制体,SetOnPlatformCubeEnterAction() 设置平台回调事件,SpawnNext(Vector3 curPos, int score, Transform parent = null)随机生成下一个 Platform 方向,并 生成下一个 Platform, Spawn(Vector3 pos, int score, Transform parent = null, bool isMoveAnimation = false) 随机生成一个 Platform,JudgePlatformQueueCount() 控制场景中 Platform 的数量,过多则删除最初的 Platform
- /// <summary>
- /// 加载 Platform 预制体
- /// </summary>
- void LoadPlatformPrefabs() {
- foreach (string resPath in ResPathDefine.PLATFORM_RES_PATH_LIST)
- {
- GameObject prefab = Resources.Load<GameObject>(resPath);
- if (prefab != null)
- {
- m_PlatformPrefabList.Add(prefab);
- }
- else {
- Debug.LogError(GetType()+ "/LoadPlatformPrefabs()/ prefab is null, resPath = " + resPath );
- }
- }
- }
-
- /// <summary>
- /// 设置平台回调事件(这个主要是分数事件)
- /// </summary>
- /// <param name="onPlatformEnterAction"></param>
- void SetOnPlatformCubeEnterAction(Action<int> onPlatformEnterAction)
- {
- m_OnPlatformEnterAction = onPlatformEnterAction;
- }
-
- /// <summary>
- /// 随机生成下一个 Platform 方向,并 生成下一个 Platform
- /// </summary>
- /// <param name="curPos">位置</param>
- /// <param name="score">增加的分数</param>
- /// <param name="parent">附载的父物体</param>
- /// <returns></returns>
- GameObject SpawnNext(Vector3 curPos, int score, Transform parent = null)
- {
- int rand = UnityEngine.Random.Range(0, (int)Dir.ENUM_COUNT);
- m_CurDir = (Dir)rand;
- switch (m_CurDir)
- {
- case Dir.Right:
- curPos.x += GameConfig.PLATFRM_CUBE_DISTANCE;
-
- break;
- case Dir.Forword:
- curPos.z += GameConfig.PLATFRM_CUBE_DISTANCE;
- break;
- case Dir.ENUM_COUNT:
- break;
- default:
- break;
- }
-
- return Spawn(curPos, score,parent, true);
-
- }
-
- /// <summary>
- /// 随机生成一个 Platform
- /// </summary>
- /// <param name="curPos">位置</param>
- /// <param name="score">增加的分数</param>
- /// <param name="parent">附载的父物体</param>
- /// <param name="isMoveAnimation">是否进行上升动画</param>
- /// <returns></returns>
- GameObject Spawn(Vector3 pos, int score, Transform parent = null, bool isMoveAnimation = false)
- {
- int randValue = UnityEngine.Random.Range(0, m_PlatformPrefabList.Count);
- GameObject go = GameObject.Instantiate(m_PlatformPrefabList[randValue], parent);
- m_PlatformsQueue.Enqueue(go);
- Platform platform = go.GetComponent<Platform>();
- if (platform==null)
- {
- platform = go.AddComponent<Platform>();
- }
-
- platform.Init(
- (curPos) => {
- m_CurPlatformCube = m_NextPlatformCube;
- m_NextPlatformCube = SpawnNext(curPos, score, parent);
-
- if (m_OnPlatformEnterAction!=null)
- {
- m_OnPlatformEnterAction.Invoke(score);
- }
- },
- pos,
- isMoveAnimation);
-
- return go;
- }
-
- /// <summary>
- /// 控制场景中 Platform 的数量
- /// 过多则删除最初的 Platform
- /// </summary>
- void JudgePlatformQueueCount() {
- if (m_PlatformsQueue.Count> GameConfig.PLATFORM_EXIST_COUNT)
- {
- GameObject.Destroy(m_PlatformsQueue.Dequeue());
- }
- }
19、在工程中添加 Player 脚本,主要功能是,监听 Jump 相关事件(鼠标左键按下,抬起等),根据按下蓄力时长,生成运动轨迹,并监听 Player 是否坠落 Platform ,继承 Monobehaviour ,监听碰撞事件等相关功能
20、Player 脚本主要函数:UpdateJumpOperation() ump 跳一跳相关鼠标监听事件,OnCollisionEnter(Collision collision) 碰撞事件,在平台才能 Jump
- /// <summary>
- /// Jump 跳一跳相关鼠标监听事件
- /// </summary>
- public void UpdateJumpOperation()
- {
- if (m_IsFallen == true)
- {
- return;
- }
-
- JudgeFallen();
-
- if (m_IsCanJump == false)
- {
- return;
- }
-
- if (Input.GetMouseButtonDown(0))
- {
-
- UpdatePlayerRotate();
- m_PressTime = 0;
-
- }
- if (Input.GetMouseButton(0))
- {
-
- m_PressTime += Time.deltaTime;
- if (m_PressTime >= GameConfig.MOUSE_PRESSING_TIME_LENGTH)
- {
- m_PressTime = GameConfig.MOUSE_PRESSING_TIME_LENGTH;
-
- }
-
- SmallScaleYAnimation();
- }
- if (Input.GetMouseButtonUp(0))
- {
-
- StartCoroutine(Jump());
- BackOriScale();
- m_IsCanJump = false;
- }
-
- }
-
-
- #region Unity Functions
-
- /// <summary>
- /// 碰撞事件,在平台才能 Jump
- /// </summary>
- /// <param name="collision"></param>
- private void OnCollisionEnter(Collision collision)
- {
- m_IsCanJump = true;
-
- // 第一碰撞平台的基础数据设置
- if (m_IsInitCollisionEnter == false)
- {
- m_IsInitCollisionEnter = true;
- m_ModelOriPos = this.transform.position;
-
- }
-
- }
-
- #endregion
21、Player 脚本主要函数:IEnumerator Jump() 协程,进行跳跃实现, JumpMoving(float jumpLength) 根据蓄力结果,生成跳跃轨迹,YParabola(float x, float k, float top)计算抛物线的 Y 值,这里需要简单的抛物线知识,进行一些转化,有兴趣的同学也可以自行实现
- /// <summary>
- /// 协程,进行跳跃实现
- /// </summary>
- /// <returns></returns>
- IEnumerator Jump()
- {
- float jumpLength = m_PressTime * GameConfig.PLAYER_MODEL_JUMP_LENGTH_SMOOTH_VALUE;
- oriPos = this.transform.localPosition;
- Vector3 nextPos = oriPos + transform.forward * jumpLength;
- movePos = nextPos - oriPos;
- m_JumpTime = m_JumpTime_Length;
-
- while (true)
- {
- if (m_JumpTime < 0)
- {
- break;
- }
- JumpMoving(jumpLength);
- yield return new WaitForEndOfFrame();
- }
- }
-
- /// <summary>
- /// 根据蓄力结果,生成跳跃轨迹
- /// </summary>
- /// <param name="jumpLength"></param>
- void JumpMoving(float jumpLength)
- {
- m_JumpTime -= Time.deltaTime;
-
- float deltra = (m_JumpTime_Length - m_JumpTime) / m_JumpTime_Length;
- var x = oriPos.x + movePos.x * deltra;
- var y = oriPos.y + YParabola(jumpLength * deltra, jumpLength / 2, GameConfig.PLAYER_MODEL_JUMP_TOP_DISTANCE);
- var z = oriPos.z + movePos.z * deltra;
- this.transform.localPosition = new Vector3(x, y, z);
-
- }
-
- /// <summary>
- /// 计算抛物线的 Y 值
- /// </summary>
- /// <param name="x"></param>
- /// <param name="k"></param>
- /// <param name="top">抛物线最高的点高度</param>
- /// <returns></returns>
- float YParabola(float x, float k, float top)
- {
- if (k == 0)
- {
- k = 1;
- }
-
- return top - (top * (x - k) * (x - k) / (k * k));
- }
22、Player 脚本主要函数:UpdatePlayerRotate()根据 Platform 位置,Player 进行转向,SmallScaleYAnimation()蓄力 Player 的动画,BackOriScale()回到蓄力动画前,JudgeFallen()判断 Player 是否坠落 Platform
- /// <summary>
- /// 根据 Platform 位置,Player 进行转向
- /// </summary>
- void UpdatePlayerRotate()
- {
- float angle = 0;
-
- switch (m_PlatformManager.CurDir)
- {
- case Dir.Right:
- angle = Vector3.Angle(transform.forward, Vector3.right);
- this.transform.Rotate(Vector3.up, angle);
- break;
- case Dir.Forword:
- angle = Vector3.Angle(transform.forward, Vector3.forward);
- this.transform.Rotate(Vector3.up, -angle);
- break;
-
- default:
- break;
- }
- }
-
- /// <summary>
- /// 蓄力 Player 的动画
- /// </summary>
- void SmallScaleYAnimation()
- {
- if (this.transform.localScale.y <= m_ModelMinScaleY)
- {
- return;
- }
-
- this.transform.localScale = Vector3.Lerp(this.transform.localScale,
- m_ModelMinScale,
- Time.deltaTime * GameConfig.PLAYER_MODEL_SCALE_Y_SAMLL_SPEED);
- }
-
- /// <summary>
- /// 回到蓄力动画前
- /// </summary>
- void BackOriScale()
- {
- this.transform.localScale = m_ModelOriScale;
- }
-
- /// <summary>
- /// 判断 Player 是否坠落 Platform
- /// </summary>
- void JudgeFallen()
- {
- if (this.transform.position.y < m_ModelOriPos.y - GameConfig.PLAYER_MODEL_FALL_DISTANCE_FROM_PLATFORM)
- {
- m_IsFallen = true;
- }
- }
23、在工程中添加 PlayerManager 脚本,主要功能是获取 Player 预制体,在场景中生成 Player
24、 PlayerManager 脚本主要函数是:IsFallen() Player 是否坠落,SpawnPlayer(Vector3 pos,Transform parent) 指定位置生成 Player
- /// <summary>
- /// Player 是否坠落
- /// </summary>
- /// <returns></returns>
- public bool IsFallen() {
- return m_Player.IsFallen;
- }
-
-
- /// <summary>
- /// 指定位置生成 Player
- /// </summary>
- /// <param name="pos">位置</param>
- /// <param name="parent">父物体</param>
- /// <returns></returns>
- Player SpawnPlayer(Vector3 pos,Transform parent) {
- Player player = null;
-
- if (m_PlayerPrefab==null)
- {
- GameObject prefab = Resources.Load<GameObject>(ResPathDefine.PLAYER_RES_PATH);
- if (prefab != null)
- {
- m_PlayerPrefab = (prefab);
- }
- else
- {
- Debug.LogError(GetType() + "/LoadPlatformPrefabs()/ prefab is null, resPath = " + ResPathDefine.PLAYER_RES_PATH);
- }
- }
-
- player = GameObject.Instantiate<GameObject>(m_PlayerPrefab, pos, Quaternion.identity).AddComponent<Player>();
- player.transform.SetParent(parent);
-
- return player;
- }
25、在工程中添加 CameraManager 脚本,主要功能是,使得 Camera 跟随 Player 跳到的 Platform ,进行移动,追随 Player,SetOffSet() Camera 和 Platform 的位置差值
26、CameraManager 脚本主要函数:SetCameraTransPos() Camera 动画移动到指定 Platform
- /// <summary>
- /// Camera 动画移动到指定 Platform
- /// </summary>
- void SetCameraTransPos()
- {
- if (m_PlatformManager.CurPlatformCube != null)
- {
- m_CameraTrans.position = Vector3.Lerp(m_CameraTrans.position,
- m_PlatformManager.CurPlatformCube.transform.position - m_OffsetPos,
- Time.deltaTime * GameConfig.CAMERA_FOLLOW_PLAYER_SPEED);
-
- }
- }
-
- /// <summary>
- /// Camera 和 Platform 的位置差值
- /// </summary>
- void SetOffSet()
- {
- m_OffsetPos = m_PlatformManager.CurPlatformCube.transform.position - m_CameraTrans.position;
- }
27、在工程中添加 ScoreManager 脚本,主要功能是,进行分数的统计,和分数变化事件的触发
28、在工程中添加 GameManager 脚本,主要功能是,获取场景中的一些游戏物体,管理各个 Manager 的初始化,Update ,Destroy 等,判断游戏是否结束,结束则重新开始游戏
29、GameManager 脚本主要函数是:Awake(),Start(),Update(),OnDestroy() 进行管理对应 Manager 的相关初始化,Update,Destroy 函数,OnGUI() 设置简单的操作说明
- public void Awake()
- {
- PlatformManager = new PlatformManager();
- PlayerManager = new PlayerManager();
- CameraManager = new CameraManager();
- ScoreManager = new ScoreManager();
- }
-
- public void Start()
- {
- FindGameObjectInScene();
-
- PlatformManager.Init(OnPlatformEnterAction, m_FirstPlatFormCubeSpawnPosTrans.position, GameConfig.PLATFORM_ADD_SCORE, m_FirstPlatFormCubeSpawnPosTrans);
- PlayerManager.Init(m_PlayerSpawnPosTrans, PlatformManager);
- CameraManager.Init(m_CameraGroupTrans,PlatformManager);
-
- ScoreManager.Score = 0;
- ScoreManager.OnValueChanged += (socre) => { m_ScoreText.text = ScoreManager.Score.ToString(); };
- }
-
- public void Update()
- {
- JudgeGameOver();
-
- PlatformManager.Update();
- PlayerManager.Update();
- CameraManager.Update();
- }
-
- public void OnDestroy()
- {
- PlatformManager.Destroy();
- PlayerManager.Destroy();
- CameraManager.Destroy();
-
- m_WorldTrans = null;
- m_UITrans = null;
- m_FirstPlatFormCubeSpawnPosTrans = null;
- m_PlayerSpawnPosTrans = null;
- m_CameraGroupTrans = null;
- m_ScoreText = null;
- m_IsGameOver = false;
-
- PlatformManager = null;
- PlayerManager = null;
- CameraManager = null;
- ScoreManager = null;
- }
-
- public void OnGUI()
- {
- // 游戏操作说明
- GUIStyle fontStyle = new GUIStyle();
- fontStyle.normal.background = null; //设置背景填充
- fontStyle.normal.textColor = new Color(1, 0, 0); //设置字体颜色
- fontStyle.fontSize = 32; //字体大小
- GUI.Label(new Rect(10, 10, 200, 200),
- "操作说明:\n1、按下鼠标左键蓄力;\n2、松开鼠标左键起跳;\n3、坠落,重新开始;",
- fontStyle);
-
- }
30、GameManager 脚本主要函数是:FindGameObjectInScene() 获取场景中的游戏物体,JudgeGameOver()判断游戏是否结束,OnPlatformEnterAction(int score)分数增加委托
- /// <summary>
- /// 获取场景中的游戏物体
- /// </summary>
- private void FindGameObjectInScene()
- {
- m_WorldTrans = GameObject.Find(GameObjectPathInSceneDefine.WORLD_PATH).transform;
- m_UITrans = GameObject.Find(GameObjectPathInSceneDefine.UI_PATH).transform;
- m_FirstPlatFormCubeSpawnPosTrans = m_WorldTrans.Find(GameObjectPathInSceneDefine.FIRST_PLATFORM_CUBE_SPAWN_POS_PATH);
- m_PlayerSpawnPosTrans = m_WorldTrans.Find(GameObjectPathInSceneDefine.PLAYER_SPAWN_POS_PATH);
- m_CameraGroupTrans = m_WorldTrans.Find(GameObjectPathInSceneDefine.CAMERA_GROUP_PATH);
- m_ScoreText = m_UITrans.Find(GameObjectPathInSceneDefine.CANVAS_SCORE_TEXT_PATH).GetComponent<Text>() ;
- }
-
- /// <summary>
- /// 判断游戏是否结束
- /// </summary>
- void JudgeGameOver()
- {
- if (PlayerManager.IsFallen() == true)
- {
- if (m_IsGameOver == false)
- {
- m_IsGameOver = true;
- SceneManager.LoadScene(SceneManager.GetActiveScene().name);
- }
- }
- }
-
- /// <summary>
- /// 分数增加委托
- /// </summary>
- /// <param name="score"></param>
- void OnPlatformEnterAction(int score) {
- ScoreManager.Score += score;
- }
31、在工程中添加 GameStart 脚本,主要功能是,整个游戏的入口,管理对应 GameManager 的 Awake(),Start(),Update(),OnDestroy() ,OnGUI() 对应函数功能
32、在工程中添加 Enum、GameConfig、GameObjectPathInSceneDefine、ResPathDefine脚本,Enum 管理所有枚举,GameConfig 一些控制游戏效果的游戏配置常量定义,GameObjectPathInSceneDefine 管理场景中游戏物体的路径常量定义,ResPathDefine 是 Resources 管理预制体的路径常量定义
33、在场景中添加 GameObject 空物体,改名为 GameStart,并且挂载 GameStart 脚本
34、运行场景,场景会自动,生成 Platform 、 Player 和分数显示等,通过鼠标即可对应操作了
35、因为这里进行了自动灯光处理,所以这里,进行场景的光线效果烘焙
36、烘培之后,效果如下,明显光亮艳丽多了
github 地址:GitHub - XANkui/UnityMiniGameParadise: Unity 游戏开发集合代码集
的 MGP_003JumpJump 工程
游戏的好不好玩,趣味性,视觉化等诸多因素影响,下面简单介绍几个方面拓展游戏的方向,仅做参考
1、可以根据自己需要修改游戏资源,换肤什么的等
2、可以根据需要添加加分特效,音效,背景更多的细节变化等等
3、添加 UI 面板等,美化游戏
4、可不设置不同的平台除了基础分数的特殊事件,比例在平台停留超过多久,触发特殊分数或者事件等等
5、平台现在每次的间距固定,可以随机间距间于范围内即可;
6、添加最高分数保留,和游戏排行榜等;
7、优化 Platform 管理,使用对象池管理优化性能等等;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。