Unity笔记-29-ARPG游戏项目-10-完善攀爬

Unity笔记-29-ARPG游戏项目-10-完善攀爬

之前的文章已经说明了攀爬系统的基本思路,这篇文章主要完善一下攀爬在一些场景下的攀爬效果

对于以下这种凸起的地形过渡

在这里插入图片描述

之前的攀爬系统只能做到对于比较平滑的凸起地形的过渡,角度一般要小于45度,但是像这种90度的凸起,是无法过度的,并且会卡模型导致bug,因此这种情况要特殊处理

思路解析

正常来看,我们需要从墙面过渡到另外一个墙面 ,如果是弧形的话之前的攀爬系统就足够做到了,但是现在是直的,因此,首先我们需要先判断当前的情况,墙面过渡凸起的角度问题,角度小的时候,能够自动过渡,角度过大的时候无法自动过渡,这个阈值在哪里?这需要测试得到结果,暂定45度,当角度达到阈值,此时正常过渡无法过渡,需要代码进行特殊过渡,首先从角色本身向墙面射出一条射线,获得当前墙面的法线,在将墙面的法线旋转,使其的朝向朝着人物左方或者右方,之所以要用墙面的法线是因为墙面可能是倾斜的。旋转后的法线乘以微小距离加上人物当前位置获得新的点,此点需要稍微远一点,至少此点的前方已经不再是当前墙面,在将该点向着当前墙面方向移动微小距离,在从移动后的点向过渡的墙面射出射线,获得过渡后的点,直接赋予角色即可。

仅仅看文字不一定看的懂,这里我在画一个图方便解释

在这里插入图片描述

对于以下这种凹陷的地形过渡

在这里插入图片描述

这种的处理和上面差不多。同样的,当角度比较小的时候也能过自动过渡,超过阈值时无法过渡,例如当前的这种近乎90度的凹陷,这种只需要向右或者向左射出射线,判断角度是否达到阈值即可,如果超过,那么直接将射线获得的过渡墙面上的点直接赋予角色即可

代码实例

    public void ClimbToOtherFace_hump()
    {
        RaycastHit hit_wall;
        Vector3 origin = roleTransform.position + roleTransform.up * GameConst.PLAYER_BODYCENTER_OFFSET;
        Physics.Raycast(new Ray(origin, roleTransform.forward), out hit_wall, 0.5f, environmentLayerMask);
        Vector3 verNormal = Quaternion.AngleAxis(-90, roleTransform.up) * hit_wall.normal;//右
        //Debug.Log(verNormal);
        RaycastHit hit_new_l;
        RaycastHit hit_new_r;
        Vector3 newOrigin_l = origin - verNormal * climbToOtherLength;
        Vector3 newOrigin_r = origin + verNormal * climbToOtherLength;
        if(Physics.Raycast(new Ray(newOrigin_l,roleTransform.forward),out hit_new_l, 0.5f, environmentLayerMask)&& !Physics.Raycast(new Ray(origin, -verNormal), climbToOtherLength+0.05f, environmentLayerMask))
        {
            if (Vector3.Angle(hit_wall.normal, hit_new_l.normal) > 40)
            {
                roleTransform.position = hit_new_l.point + hit_new_l.normal * wallOffset;
                return;
            }
        }
        else
        {
            Vector3 newOrigin_other = newOrigin_l + roleTransform.forward * 0.5f;
            RaycastHit newhit;
            if (!Physics.Raycast(new Ray(newOrigin_other, verNormal), out newhit, 1, environmentLayerMask)) return;
            roleTransform.position = newhit.point + newhit.normal * wallOffset;
            roleTransform.rotation = Quaternion.LookRotation(-newhit.normal);
            return;
        }
        if(Physics.Raycast(new Ray(newOrigin_r, roleTransform.forward), out hit_new_r, 0.5f, environmentLayerMask)&& !Physics.Raycast(new Ray(origin, verNormal), climbToOtherLength+0.05f, environmentLayerMask))
        {
            if (Vector3.Angle(hit_wall.normal, hit_new_r.normal) > 40)
            {
                roleTransform.position = hit_new_r.point + hit_new_r.normal * wallOffset;
                return;
            }
        }
        else
        {
            Vector3 newOrigin_other = newOrigin_r + roleTransform.forward * 0.5f;
            RaycastHit newhit;
            if (!Physics.Raycast(new Ray(newOrigin_other, -verNormal), out newhit, 1, environmentLayerMask)) return;
            roleTransform.position = newhit.point + newhit.normal * wallOffset;
            roleTransform.rotation = Quaternion.LookRotation(-newhit.normal);
            return;
        }
    }
    public void ClimbToOtherFace_sunk()
    {
        RaycastHit hit_wall;
        Vector3 origin = roleTransform.position + roleTransform.up * GameConst.PLAYER_BODYCENTER_OFFSET;
        Physics.Raycast(new Ray(origin, roleTransform.forward), out hit_wall, 0.5f, environmentLayerMask);
        Vector3 verNormal = Quaternion.AngleAxis(-90, roleTransform.up) * hit_wall.normal;//右
        RaycastHit hit_l;
        RaycastHit hit_r;
        if(Physics.Raycast(new Ray(origin, -verNormal), out hit_l, climbToOtherLength, environmentLayerMask))//左
        {
            Debug.Log(Vector3.Angle(hit_l.normal, hit_wall.normal));
            if (Vector3.Angle(hit_l.normal, hit_wall.normal) > 45) 
            {
                roleTransform.position = hit_l.point + hit_l.normal * wallOffset;
                roleTransform.rotation = Quaternion.LookRotation(-hit_l.normal);
            }
        }
        if (Physics.Raycast(new Ray(origin, verNormal), out hit_r, climbToOtherLength, environmentLayerMask))//右
        {
            Debug.Log(Vector3.Angle(hit_r.normal, hit_wall.normal));
            if (Vector3.Angle(hit_r.normal, hit_wall.normal) > 45)
            {
                roleTransform.position = hit_r.point + hit_r.normal * wallOffset;
                roleTransform.rotation = Quaternion.LookRotation(-hit_r.normal);
            }
        }
    }

攀爬至墙顶的过渡

这里存在一种情况,就是两个倾斜的墙构成的一个角,这个角是凸起的,当凸起的角度过大时,角色无法过渡,又因为角度不够攀顶,因此角色无法攀顶,就是出现BUG。

修复的思路还是比较简单了,类似于上面的射线测试,通过墙面法线获得平行于墙面向上的向量,向上一定距离再向墙面方向射出射线获得新的墙面,判断角度即可

代码实例

    public void ClimbUpToLand_3()
    {
        RaycastHit hit_wall;
        Vector3 origin = roleTransform.position + roleTransform.up * GameConst.PLAYER_BODYCENTER_OFFSET;
        Physics.Raycast(new Ray(origin, roleTransform.forward), out hit_wall, 0.5f, environmentLayerMask);
        Vector3 upNormal = Quaternion.AngleAxis(90, roleTransform.right) * hit_wall.normal;
        Vector3 newOrigin = origin + upNormal * ClimbUpLength;
        RaycastHit hit_new;
        if(Physics.Raycast(new Ray(newOrigin,roleTransform.forward),out hit_new, 0.5f, environmentLayerMask))
        {
            if (Vector3.Angle(hit_wall.normal, hit_new.normal) < 70)
            {
                if(Vector3.Angle(hit_wall.normal, hit_new.normal) > 45)
                {
                    roleTransform.position = hit_new.point+ hit_new.normal * wallOffset;
                    roleTransform.rotation = Quaternion.LookRotation(-hit_new.normal);
                }
                return;
            }
        }
        ani.CrossFade(GameConst.CLIMBTOUP_STATE, 0f);
        climbLand = true;
        canClimb = false;
        //moveTest.climbUpDelayCounter = climbUpDelayTime;
        //RecoverRotation();
        roleTransform.position += roleTransform.up.normalized * climbUpOffset;
        Invoke("ExitClimb", ani.GetCurrentAnimatorStateInfo(1).length - 0.2f);
    }
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity Mega-Fiers是一款强大的Unity插件,它为开发者提供了许多功能和工具,以帮助他们创建优秀的游戏体验。 首先,Unity Mega-Fiers具有强大的形变功能。开发者可以通过该插件实现各种形状的变换,包括弯曲、挤压、拉伸等。这为游戏中的人物、物体和环境提供了更多的自由度和个性化选项,使其更具动态和真实感。 其次,Unity Mega-Fiers还提供了高度的粒子系统控制能力。开发者可以使用该插件来创建更加逼真的粒子效果,并具有更准确的控制。这包括粒子的大小、颜色、速度等方面,使游戏中的特效更加出色。 另外,Unity Mega-Fiers还支持可编程网格。这意味着开发者可以通过脚本来控制网格的生成和变形,从而实现各种复杂的效果。无论是地形生成、水体模拟还是其他物体的变形,都可以通过该插件实现,并使游戏更加逼真和具有个性化。 除了以上功能,Unity Mega-Fiers还提供了其他诸多辅助工具,如动画控制、特效编辑等,为开发者提供了更丰富的开发选项和提升游戏质量的手段。 总结而言,Unity Mega-Fiers是一款功能强大的Unity插件,为开发者提供了丰富的形变、粒子系统控制和可编程网格等功能。它能够大幅提升游戏的真实感和品质,并为开发者提供更多的创作空间和个性化选项。无论是初学者还是有经验的开发者,都能够从中受益,并创造出出色的游戏作品。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值