【你问我答】Unity实现类似DNF地下城勇士的2D人物移动跳跃

前言

之前有个小伙伴微信找我,想做一个类似DNF地下城勇士的移动跳跃功能,特别是关于2d的跳跃,之前还不是很有头绪,后面去查找相关资料,还真让我找到了,今天就一起来实现一下吧!
在这里插入图片描述

实现类似2.5d的地下城勇士效果,正常来说2d 3d都可以做,但是我还是选择2d,2d操作起来更为简单,而且素材也容易寻找。

先来看看实现的最终效果吧
在这里插入图片描述

人物节点创建

Player挂载刚体和碰撞器,主要控制主角移动
Mbody为人物身体,挂载animator组件,主要控制主角动画切换
Shadow为阴影
在这里插入图片描述

实现简单移动

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerParentMove : MonoBehaviour
{
    
    
    public float moveSpeed = 10;//移动速度(父物体)
    private Vector2 direction;//移动方向(父物体,xy轴平面)
    private Animator ani;//动画控制器(子物体)
    private Rigidbody2D rig;//刚体组件(父物体)
    
    void Start()
    {
    
    
        ani = GetComponentInChildren<Animator>();//初始化获得子物体的动画控制器
        rig = GetComponent<Rigidbody2D>();//初始化获得自身的刚体组件
    }

    void Update()
    {
    
    
        direction.x = Input.GetAxisRaw("Horizontal");//获取键盘x轴输入,赋值给移动方向的x值
        direction.y = Input.GetAxisRaw("Vertical")  *  0.7f;//获取键盘x轴输入,赋值给移动方向的x值(*0.7是因为视觉效果,向里走要慢一点,可根据实际效果改变)
    }


    //之所以在FixUpdate里面执行移动和跳跃方法,是因为父物体移动用的是刚体的Velocity方法,子物体跳跃虽然是用Transform,但是为了跳跃时配合移动不出现卡顿,也放在FixUpdate里面执行
    private void FixedUpdate()
    {
    
    
        Move();//移动方法(父物体)
        Anima();//执行动画控制方法
    }

    void Move()
    {
    
    
        rig.velocity = direction * moveSpeed * 50 * Time.fixedDeltaTime;//父物体沿移动方向移动
        if (rig.velocity.x >= 0.05)
        {
    
    
            transform.rotation = new Quaternion(0, 0, 0, 0);//如果速度向右不翻转
        }
        else if (rig.velocity.x <= -0.05)
        {
    
    
            transform.rotation = new Quaternion(0, 180, 0, 0); //如果速度向左翻转180°
        }
    }

    void Anima() {
    
    }
}

效果
在这里插入图片描述

实现攻击效果

public bool isAttack = false;//攻击状态

void Update()
{
    
    
	//检测键盘攻击键输入并且攻击状态为false
	if(Input.GetMouseButtonDown(0) && !isAttack)
 	{
    
    
     	isAttack = true;//攻击状态赋值为true
     	Accatk();
 	}
}

private void FixedUpdate()
{
    
    
    if (isAttack) direction = new Vector2(0, 0);
}

void Accatk() {
    
    }

效果
在这里插入图片描述

实现跳跃

public float jumpHeight = 5;//跳跃高度
public float aSpeed = -9.8f;//重力加速度
private bool isJump = false;//跳跃状态
private float velocity_Y;//跳跃速度(子物体)
public Transform childTransform;//Transform组件(子物体)
    
void Update()
{
    
    
    //检测键盘跳跃键输入并且跳跃状态为false
    if (Input.GetKeyDown(KeyCode.Space) && !isJump &&!isAttack)
    {
    
    
        isJump = true;//跳跃状态赋值为true
        ReadyJump();//执行准备跳跃方法
    }
}

//之所以在FixUpdate里面执行移动和跳跃方法,是因为父物体移动用的是刚体的Velocity方法,子物体跳跃虽然是用Transform,但是为了跳跃时配合移动不出现卡顿,也放在FixUpdate里面执行
private void FixedUpdate()
{
    
    
   Jump();//跳跃方法(子物体)
}
    
void Jump()
{
    
    
    velocity_Y += aSpeed * Time.fixedDeltaTime;//重力模拟(子物体垂直速度始终受重力加速度影响)
    //判断子物体是在下落状态(velocity小于零)并且距离父物体小于等于0.05
    if (childTransform.position.y <= transform.position.y + 0.05f && velocity_Y < 0)
    {
    
    
        //如果满足
        velocity_Y = 0;// 子物体垂直速度清零
        childTransform.position = transform.position;//子物体position与父物体对齐
        //检测是否对齐,理论上多此一举,但是之前有遇到过位置不准确的情况,所以加一个双保险
        if (childTransform.position == transform.position)
        {
    
    
            //满足位置对齐
            isJump = false;//则将跳跃状态设置为false,等待下一次跳跃
        }
    }
    childTransform.Translate(new Vector3(0, velocity_Y) * Time.fixedDeltaTime);//子物体按照速度移动
}

void ReadyJump()
{
    
    
    velocity_Y = Mathf.Sqrt(jumpHeight * -2f * aSpeed);
}

效果
在这里插入图片描述

人物移动跳跃完整代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerParentMove : MonoBehaviour
{
    
    
    public float moveSpeed = 10;//移动速度(父物体)
    public float jumpHeight = 5;//跳跃高度
    public float aSpeed = -9.8f;//重力加速度

    private Vector2 direction;//移动方向(父物体,xy轴平面)
    private bool isJump = false;//跳跃状态
    public bool isAttack = false;//攻击状态
    private float velocity_Y;//跳跃速度(子物体)

    private Animator ani;//动画控制器(子物体)
    private Rigidbody2D rig;//刚体组件(父物体)

    public Transform childTransform;//Transform组件(子物体)
    void Start()
    {
    
    
        ani = GetComponentInChildren<Animator>();//初始化获得子物体的动画控制器
        rig = GetComponent<Rigidbody2D>();//初始化获得自身的刚体组件
    }

    // Update is called once per frame
    void Update()
    {
    
    
        direction.x = Input.GetAxisRaw("Horizontal");//获取键盘x轴输入,赋值给移动方向的x值
        direction.y = Input.GetAxisRaw("Vertical")  *  0.7f;//获取键盘x轴输入,赋值给移动方向的x值(*0.7是因为视觉效果,向里走要慢一点,可根据实际效果改变)

        //检测键盘跳跃键输入并且跳跃状态为false
        if (Input.GetKeyDown(KeyCode.Space) && !isJump &&!isAttack)
        {
    
    
            isJump = true;//跳跃状态赋值为true
            ReadyJump();//执行准备跳跃方法
        }

        //检测键盘攻击键输入并且攻击状态为false
        if(Input.GetMouseButtonDown(0) && !isAttack && !isJump)
        {
    
    
            isAttack = true;//攻击状态赋值为true
            //Accatk();
        }
    }


    //之所以在FixUpdate里面执行移动和跳跃方法,是因为父物体移动用的是刚体的Velocity方法,子物体跳跃虽然是用Transform,但是为了跳跃时配合移动不出现卡顿,也放在FixUpdate里面执行
    private void FixedUpdate()
    {
    
    
        if (isAttack) direction = new Vector2(0, 0);
            Move();//移动方法(父物体)
            Jump();//跳跃方法(子物体)
            Anima();//执行动画控制方法
    }

    void Move()
    {
    
    
        rig.velocity = direction * moveSpeed * 50 * Time.fixedDeltaTime;//父物体沿移动方向移动
        if (rig.velocity.x >= 0.05)
        {
    
    
            transform.rotation = new Quaternion(0, 0, 0, 0);//如果速度向右不翻转
        }
        else if (rig.velocity.x <= -0.05)
        {
    
    
            transform.rotation = new Quaternion(0, 180, 0, 0); //如果速度向左翻转180°
        }
    }

    void Jump()
    {
    
    
        velocity_Y += aSpeed * Time.fixedDeltaTime;//重力模拟(子物体垂直速度始终受重力加速度影响)
        //判断子物体是在下落状态(velocity小于零)并且距离父物体小于等于0.05
        if (childTransform.position.y <= transform.position.y + 0.05f && velocity_Y < 0)
        {
    
    
            //如果满足
            velocity_Y = 0;// 子物体垂直速度清零
            childTransform.position = transform.position;//子物体position与父物体对齐
            //检测是否对齐,理论上多此一举,但是之前有遇到过位置不准确的情况,所以加一个双保险
            if (childTransform.position == transform.position)
            {
    
    
                //满足位置对齐
                isJump = false;//则将跳跃状态设置为false,等待下一次跳跃
            }
        }
        childTransform.Translate(new Vector3(0, velocity_Y) * Time.fixedDeltaTime);//子物体按照速度移动
    }

    void ReadyJump()
    {
    
    
            velocity_Y = Mathf.Sqrt(jumpHeight * -2f * aSpeed);
    }

    void Anima()
    {
    
    
        ani.SetFloat("Velocity", velocity_Y);
        ani.SetBool("isJump", isJump);

        if(!isJump)
        {
    
    
            if (Mathf.Abs(rig.velocity.x) >= 0.05 || Mathf.Abs(rig.velocity.y) >= 0.05)
            {
    
    
                ani.SetBool("Running", true);
            }
            else ani.SetBool("Running", false);
        }
        else
        {
    
    
            ani.SetBool("Running", false);
        }

        if(isAttack)
        {
    
    
            ani.SetBool("isAttack", true);
        }
    }
}

挂载脚本和参数配置
在这里插入图片描述

人物脚底的影子效果

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerShadow : MonoBehaviour
{
    
    
    public Transform playerTranform;//玩家(子物体)Transform
    public float shadowSizeFloat = 0.5f;//影子最小缩放比例(在原有基础上)

    private float heightDifference;//玩家跳跃高度差
    private Vector3 scale;//初始影子缩放大小
    private PlayerParentMove playerMove;//声明玩家(父物体)移动脚本,主要是获取玩家设置的跳跃高度
    void Start()
    {
    
    
        playerMove = GetComponentInParent<PlayerParentMove>();//得到玩家(父物体)移动脚本
        scale = transform.localScale;//将影子初始缩放赋值给scale
    }

    void Update()
    {
    
    
        heightDifference = playerTranform.position.y - transform.position.y;//高度差计算:子物体y值-父物体y值
        //按照最大跳跃高度和高度差的比例来缩放影子大小,限制影子最小缩放
        //Mathf.Clamp()这里有三个参数,第一个参数是要限制的变量,第二个是最小值,第三个是最大值
        //用scale.x-(heightDifference/playerMove.jumpHeight)*scale.x,计算根据高度差与最大高度比例从0到初始值的变换
        //并且在最小值使用scale.x*shadowSizeFloat,来限制最小值,即使计算出来是0小于最小值,返回值也会是最小值
        //scale.y缩放同理
        transform.localScale = new Vector3(Mathf.Clamp(scale.x-(heightDifference/playerMove.jumpHeight)*scale.x, scale.x * shadowSizeFloat, scale.x), Mathf.Clamp(scale.y - (heightDifference / playerMove.jumpHeight) * scale.y, scale.y * shadowSizeFloat, scale.y), scale.z);
    }
}

脚本挂载在人物Shadow上,并配置参数
在这里插入图片描述
运行效果
在这里插入图片描述

最终运行效果

在这里插入图片描述

源码

链接:https://pan.baidu.com/s/1LL8gEhjeEHLMXzWXQayFwQ
提取码:zcq9

参考

【视频】https://www.bilibili.com/video/BV1EE411p7iC/

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_36303853/article/details/132723380
今日推荐