欢迎光临散文网 会员登陆 & 注册

这是你永远抵达不到的真实——用Unity做一个JOJOJump

2019-11-27 18:11 作者:皮皮关做游戏  | 我要投稿

作者:Yumir

嗨大家好我是yumir。

经过上一次2D像素游戏“Seed”的洗礼我决定休息一下换个题材,做一个3D游戏就不会出现自己画素材画哭的情况啦!于是决定实现《jetpack jump》中的跳跃,算是物理系统小练习,大家可以自己搜索安装包试玩,不过不要过渡沉迷,会影响你打代码的~( ̄▽ ̄)~*

但是直接使用unity的免费素材来做游戏,又比较没意思,毕竟unity娘谷歌娘什么的,除了又好看又方便之外还有什么优点吗,没有。我们怎么能满足于这种唾手可得的资源呢,我们要去别的地方找更有意思的东西(其实就是想用自己喜欢的动画片的模型)。

这次的模型是从:spriters-resource.com/上下载的,主要是因为我在别的网站都没有找到JOJO的模型,同学们如果有别的资源来源请务必在评论区分享。

其实找模型有一个方法是通过找MMD作品看有没有好看的想要的模型,以前听大佬说MMD都是要求要把使用的资源链接列在简介里面的(除非资源是自己制作并且不愿意共享的),再看看MMD转Unity的插件教程,就可以让可爱的MMD角色跑起来了。

但是我找JOJO的MMD完全没有看到链接,也许都是自己建模的?或者是我太菜了不会找,我本来心仪的是Q版豆豆眼的那个JOJO,就是这个:

但是想想这么可爱的豆豆眼在地上疯狂摩擦的样子实在是不忍心,所以我决定还是让Dio在地上摩擦吧,于是今天做的是DiavoloJump!JOJOJump?永远抵达不到。

其实我也想过吉良吉影在不能回头的巷子里Jump,但是吧...

这就不是我短时间内能解决的问题了。

然后我掏出了老板的模型。

突然卡兹。
















我们乔斯达家族世世代代都是绅士,绝不会这样就放弃!

然后我下载了blender,同时找到一个可以从unity导出在unity中修改过的模型的插件,但是导出来之后模型的uv就莫得了,对比发现模型导入到blender中修改再导出,该有的材质都有,所以最后是在blender里面帮BOSS把一头秀发修剪整齐了。

之所以使用的是blender主要是因为。

(#`O′)他免费啊!

感觉只要是建模软件应该都能做这一步,但是你要我说是不是肯定都一样我当然是不知道的,毕竟只是一个普普通通的上班族而已。

因为快捷键不一样磨合时间也比较长,所以有别的建模软件经验的小伙伴不必强行下载。这个模型脚底下还有上下牙和舌头,不知道到底是什么游戏,才需要把牙齿做出来,难道是要玩樱桃吗。

所以为了保护同学们的键盘我把我改好的模型上传到了网盘:

https://pan.baidu.com/s/1-JaKrhSOu_Fr48xBRbugZw#list/path=%2F

将模型上传到Mixamo绑骨再下载下来,我们的主要素材就完成啦!什么你还不知道Mixamo是什么?这么好用的网站快保存下来啊!

https://www.mixamo.com/#/?page=1&type=Character



人物的动画是在unity官方下载的,里面的动画正好够用,再在官方商店随便找了两个差不多的场景包再差不多的搭一个场景做个差不多的天空盒我们的前期准备就完成啦。

如果同学们想让游戏时间变得更长的话需要更多的场景素材,itch上不止有免费的游戏还有很多免费的素材,需要的同学可以自己去看看,非常不错。

在画天空盒的时候发现天空盒的颜色也是会反射到场景中的(这不是当然的吗!)于是干脆把天空调成了奇妙的绿色,天空盒的制作方法如下:

1、新建一个材质球,设置Shader为Skybox,这里我设置为Skybox/Panoramic,我比较喜欢这个效果,也可以做六面体。

2、打开ps做一个渐变颜色图片给该天空盒赋值。

3、点击window→rendering→lightingsetting,将skybox material设置为刚才新建的天空盒。

场景的搭建其实是很费时费力的,所以大概搭了个够用的,就是下面这个丑丑的场景↓

没关系,毕竟我做的是DiavoloJump嗒!再下载一个绯红之王套一个打篮球的动作,Boss的“喷射背包”也有了,那么可以开始我们的大工程啦~

------------------不介绍实现功能就开始薅代码的经验分享都是耍流氓------------------


这次做的游戏的玩法就是点击屏幕跳跃,但是如果一个游戏随便跳那就没有意义了,所以是有条件限制的跳,因为是在电脑实现功能所以我做的是按下鼠标左键跳跃,内容如下:

1、游戏中BOSS一直向前奔跑,按下鼠标左键跳跃。

2、如果第一跳的位置正好在起跑线,可以双倍跳跃。

3、如果在落地的瞬间按下鼠标左键,可以双倍跳跃。

4、第三跳是喷射跳跃,在空中可以有若干次加速机会。

5、如果超过起跑线一段时间没有跳跃,游戏失败。

6、如果落地一段时间没有跳跃,游戏失败。

7、Boss永远抵达不到终点。

画了一张图来表示整个游戏流程,不过这次我只做了结算之前的跳跃,会在文末给感兴趣的同学补充一些结算状态的思路。

为了可以一直看到Boss的背影我们需要做一个摄像机跟随,在制作这部分功能的时候考虑到游戏中会有不同的摄像机角度,所以新建了一个空物体先把当前的跟随角度存储起来,后期需要新的角度的时候只需要增加新的空物体和逻辑就可以了。


    public float smooth;                // 平滑度    public Transform cameraFPTran;  //人物活动时摄像机跟随位置    public Transform cameraStartTran;  //摄像机初始位置

    private GameObject player;        // 目标    private Vector3 targetPosition;        // 摄像机移动目标    private bool isStart = true;

    void Start()

    {

        player = GameObject.FindWithTag("Player");

        cameraFPOffset = cameraFPTran.position - player.transform.position;

        //摄像机放在初始位置,置标志位为f        jetSlider.SetActive(false);

    }

    void LateUpdate()

    {

        if (isStart)

        {

            CameraFollow(cameraFPOffset);

        }

    }

    void CameraFollow(Vector3 follow)

    {

        targetPosition = player.transform.position + follow;

        transform.position = Vector3.Lerp(transform.position, targetPosition, Time.deltaTime * smooth);

        transform.LookAt(player.transform);

    }

 

在实现跳跃之前我们需要让模型在游戏场景中往前跑,首先新建Boss的游戏物体,然后进行以下操作:

1、在Boss身上添加碰撞体、刚体以及动画三个组件,新建一个角色控制脚本。

2、把动画的“Apply Root Motion”取消选中。

3、将刚体的旋转角度锁定。

因为我把跑道搭在Z轴上,所以Boss只需要一直在Z轴上面跑就行了,同时我希望Boss在起跑的时候有加速度的过程,于是我做了一个动画混合树,将走路和跑步的动画混合在一起。

尝试过几种移动方法之后发现使用“AddForce”进行移动的效果是最好的。在移动的过程中我们需要控制Boss的移动速度(人类的力量是有极限的)以及悬空的时候不会继续往前加速,所以我们需要对Boss的速度和是否跳跃进行监控,我是这样实现的:

    private void FixedUpdate()

    {

        if (!isJump && playerRigdbody.velocity.z < speed)

        {

            playerRigdbody.AddForce(Vector3.forward * speed);

        }

        playerAnimator.SetFloat("Blend", playerRigdbody.velocity.z / speed);

    }

 

接下来就要实现跳跃功能了,跳跃有:起跳、空中、下落这三个状态,加上本身有一个奔跑状态,而起跳到空中这段动作是不需要条件转换的,我的动画状态机是这样搭建的。

其中指向“Run”的转换条件是“run=true”,指向“JumpStart”的转换条件是“jump=true”指向“JumpEnd”的转换条件是“down=true”,“JumpStart”的动画播放结束自动跳转到“JumpMidAir”。

因为有概率出现明明“run”为True但是却没有从“JumpEnd”跳转到“Run”的情况,我又在“JumpEnd”和“JumpStart”之间增加了一条线。在脚本中定义一个枚举类型区分三个状态就能轻松控制动画的切换了,因为代码太简单就不浪费篇幅了。

画面表现搞定之后就是脚本控制游戏物体移动了,同样的,用AddForce给一个向上的力就可以让Boss上天,但是Boss可以一直上天吗,Boss不行。

于是乎我需要让他只能在脚踩地面的时候上天,这个判断我是通过射线实现的:

解决了Boss上天的问题我开始思考每一次跳跃之间的差别,整个游戏只有按下鼠标左键一个操作,但是每个阶段的操作都是不一样的,可以看出来最大的问题是最后一条需要出现反馈喷射进度的UI,而且是在起跳后一段时间才出现喷射进度条。

我的解决方法利用委托,定义一个没有返回类型没有参数的委托变量,在游戏中每帧调用,在不同状态中更改改委托的内容,这样一来我就可以在游戏的不同时期做不同的事了。

而后我又定义了一个int类型的数用来判断Boss处于第几个阶段(状态),通过Switch语句控制不同阶段的操作,这个方法其实并不好,但是在学习的过程中我们需要灵活运用各种技巧,这个游戏并不会进行后期修改所以可以这样控制。

以第一阶段为例,第一阶段所做的事情是:起跑&第一次跳跃

我设置的起跑线是Z=15,当玩家超过起跑线一段距离(我设置的值是Z大于等于18)时玩家死亡,如果在起跑线浮动范围里面起跳则将“jumpSpeed”翻倍否则不变,起跳时设置动画参数并将表示阶段(第几跳)的变量自增,这样在下一帧执行的便是下一个状态的方法。

 

if (isGround)

{

    isJump = false;

    if (Input.GetMouseButtonDown(0) && playerTransform.position.z < 18.0f)

    {

        if (playerTransform.position.z > 14.5f && playerTransform.position.z < 15.5f)//最佳

        {

            jumpSpeed *= 2;

         }

         SetPlayerAnima(PlayerStateType.Jump);

         playerRigdbody.AddForce((Vector3.up) * jumpSpeed, ForceMode.Impulse);

         jumpNum++;

         jumpTime = 0;

         isJump = true;

    }

    if (playerTransform.position.z >= 18.0f)

    {

         playerMove = PlayerDie;

    }

}

 

第二跳第三跳大同小异,与第一跳不同的地方是第一跳用距离判断是否加倍,后面的跳跃则是用落地时间,所以当Boss落地之后就要开始计时,在起跳的时候将计时器清零。

if (isGround)

{

   jumpTime += Time.deltaTime;

   if (jumpTime > timing){ playerMove = PlayerDie; }

   else if (Input.GetMouseButtonDown(0) && jumpTime <= timing)

   {

        if (jumpTime <= bestTiming){ jumpSpeed *= 2; }

        Jump();

   }

}

 

需要注意的是如何控制动画的播放,当Boss快要落地的时候要切换为“Down”动画,也就是我需要知道他是否下坠,下坠时离地面多高,我通过记录Boss的Y轴数值并比较上一帧和当前帧的Y值大小来判断:

if (lastPosY > playerTransform.position.y && playerTransform.position.y < 2)

{

    SetPlayerAnima(PlayerStateType.Down);

}

lastPosY = playerTransform.position.y;

 

Boss的第三次起跳需要延迟调用,我是用协程来实现的,在协程中对委托进行新的赋值操作,并且解开对Boss刚体的旋转锁定,以及一系列该有的操作。

IEnumerator Jet()

{

    yield return new WaitForSeconds(1);

    playerRigdbody.freezeRotation = false;

    GameManager.instance.jetSlider.SetActive(true);

    jetValue = jetTimes;

    playerMove = PlayerMove02;

}

 

喷射进度条是我自己用PS做的,用了一个和游戏场景比较搭的配色,在场景中新建两个Image,将方格图作为渐变色图的子物体,因为Unity中的UI物体越在列表的下方则越靠近屏幕,自然可以将方格图显示在渐变色的前方。

将渐变色图的参数设置如下,并持有这个游戏物体,我是在GameManager里持有的。

在Boss的控制脚本中“PlayerMove02”中的设置更新该image的Amount并在每次推进中给Boss一个往前的力。当Boss落地的时候将动画暂停播放,隐藏绯红之王,游戏到这里就结束了。

if (isGround)

{

    playerAnimator.speed = 0;

    kingCrimson.SetActive(false);

}

else if (Input.GetMouseButton(0) && jetValue > 0)

{

   --jetValue;

   GameManager.instance.SetJetSlider(jetValue / jetTimes);

   playerRigdbody.AddForce(Vector3.forward * jetSpeed, ForceMode.Impulse);

}

最后可以通过刚体的IsSleeping判断Boss是不是已经停下最后的滑行,在结束的时候弹出游戏结束的各种效果,游戏中的里程可以通过3D Object→3D Text来实现显示,有更多问题欢迎在评论区留言,或者到群里勾搭~

Github:https://github.com/peiyl/JOJOJump



有知友看了上一篇文章成功实现了自己的小项目,在原游戏的基础上做了扩展,虽然我也不是真大佬但是还是感觉很Diohh。

欢迎加入游戏开发群欢乐搅基:869551769

有意向参与线下游戏开发学习的读者可戳这里进一步了解:levelpp.com/


这是你永远抵达不到的真实——用Unity做一个JOJOJump的评论 (共 条)

分享到微博请遵守国家法律