天天看点

【Unity exam02】怎样制作一个回旋斧 2D篇

怎样制作一个回旋斧 2D篇

【Unity exam02】怎样制作一个回旋斧 2D篇

【参考视频】

url:bilibili - 【中文字幕】在2D中重现:战神4奎爷投掷和召回寒冰之斧的攻击方式

这个视频中不仅实现了回旋斧的制作,还实现了相机震动、以及一些特效效果丰富体验。有兴趣的小伙伴可以观看这个视频,这里我只实现普通的回旋斧制作。

【PS:我实现的方式与这位UP有些不同,若是有错误请指正】

一、打开初始资源

下载地址 https://pan.baidu.com/s/1L5APoVJundN1IUDphSNUBg

提取码:v4m2

  1. 打开Scenes文件夹下的第一个场景,这个场景已经实现了部分功能(玩家移动,敌人攻击,按空格敌人血量会减少)。
【Unity exam02】怎样制作一个回旋斧 2D篇
  1. 打开Sprites文件夹,找到weapon斧头,将其拖拽到Player的子物体中,并调整Position和Sorting Layer以显示在正确的位置
    【Unity exam02】怎样制作一个回旋斧 2D篇

    二、在Scripts/01文件夹下新建C#脚本 Weapon

    (1)首先来实现物体的旋转,在点击斧头物体按E进行旋转可知斧头是围绕Z轴进行旋转的。简单的旋转只需以下代码即可:

public class Weapon: MonoBehaviour
{
	[Header("旋转参数")]
    [SerializeField]
    float rotateSpeed = 1000f;  // 旋转速度

    private void Update()
    {
        SelfRotate();
    }

    void SelfRotate()
    {
        // 斧头围绕Z轴顺时针旋转
        transform.Rotate(-Vector3.forward * rotateSpeed * Time.deltaTime);
    }
}
           
【Unity exam02】怎样制作一个回旋斧 2D篇

(2)接下来实现鼠标点击某个位置,斧头会旋转并移动到该位置。

新建两个变量 移动速度moveSpeed , 目标位置 targetPos

[Header("移动参数")]
    [SerializeField]
    float moveSpeed = 10f;  // 移动速度
    Vector2 targetPos;  // 鼠标点击位置
    
    private void Update()
    {
        SelfRotate();
        Movement(); 

        // 点击鼠标左键
        if (Input.GetMouseButtonDown(0))
        {
            targetPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        }
    }
    
    void Movement()
    {
        // 斧头以一定速度移动到目标位置
        transform.position = Vector2.MoveTowards(transform.position, targetPos, moveSpeed * Time.fixedDeltaTime);
    }
           
【Unity exam02】怎样制作一个回旋斧 2D篇

(3)接下来实现武器到达目标点位置后,返回人物手中。

首先声明几个变量, 玩家位置 playerPos, 三个bool值 isRotating 旋转状态, isGo 前进状态, isBack 返回状态。

逻辑:

·点击鼠标时,武器开始旋转,斧头移动到鼠标点击位置(即 isGo = true)。·

·斧头到达目标位置后,开始返回到玩家位置playerPos(即 isGo = false,isBack = true)

Vector2 playerPos;  // 玩家位置

    [Header("bool参数")]
    [SerializeField]
    bool isRotating;  // 旋转状态

    [SerializeField]
    bool isGo;        // 前进状态

    [SerializeField]
    bool isBack;      // 返回状态

	private void Update()
    {
        playerPos = transform.parent.position;

        // 点击鼠标左键 && 斧头是静止状态
        if (Input.GetMouseButtonDown(0) && !isGo && !isBack)
        {
            isRotating = true;  // 开始旋转
            isGo = true;    // 开始前进
            targetPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        }

        if (isRotating)
        {
            SelfRotate();
            Movement();
        }
    }
void Movement()
    {
        // 如果武器到达了目标点
        if (Vector2.Distance(transform.position, targetPos) < 0.01f)
        {
            isBack = true;
            isGo = false;
        }

		// 如果武器返回玩家手中
        if(Vector2.Distance(transform.position, playerPos) < 0.01f)
        {
            isBack = false;
        }

        // 武器处于前进状态 且 不是返回状态
        if (isGo && !isBack)
        {
            // 斧头以一定速度移动到目标位置
            transform.position = Vector2.MoveTowards(transform.position, targetPos, moveSpeed * Time.fixedDeltaTime);
        }

        // 武器处于返回状态 且 不是前进状态
        if (isBack && !isGo)
        {
            // 斧头以一定速度移动到目标位置
            transform.position = Vector2.MoveTowards(transform.position, playerPos, moveSpeed * Time.fixedDeltaTime);
        }
    }


           
【Unity exam02】怎样制作一个回旋斧 2D篇

(4)这时候斧头返回玩家手中时并不会停止旋转,但是,如果用Vector2.Distance()的方法判断斧头是否回到玩家的位置,然后赋值isRotating = false。就会出现错误了!因为武器一直在玩家的位置,所以isRotating会一直会false,根本不会旋转和移动了。

// 错误的方法
		if (Vector2.Distance(transform.position, playerPos) < 0.01f)
        {
            isRotating = false;
            isBack = false;
        }
           

所以我们要添加另外的条件,因为斧头返回状态中isBack是为true的,所以我们可以判断 isBack为true 且 斧头回到玩家位置时, 斧头停止旋转,返回状态为假,这样这个方法就只在 武器回到玩家手中 的时候调用了一次,而不是无限调用

// 正确的方法
		if (isBack && Vector2.Distance(transform.position, playerPos) < 0.01f)
        {
            isRotating = false;
            isBack = false;

            // 返回初始的旋转角度
            transform.rotation = Quaternion.Euler(0, 0, 0);
        }
           
【Unity exam02】怎样制作一个回旋斧 2D篇

(5)两个缺陷:

1.我们注意到,武器回到的位置是玩家中心的位置,而不是回到玩家手上

2.因为武器是玩家的子物体,所以武器会跟随玩家的移动而移动(也就是说玩家的速度会影响到武器的速度),武器和玩家同时运动就会会显得别扭,如果玩家移动速度过快,武器甚至会反向运动。 .

【Unity exam02】怎样制作一个回旋斧 2D篇

有一种方法可以同时解决这两个缺陷,就是将武器的位置替代为一个空物体,然后将武器移出Player作为一个单独的物体,然后改变脚本中的一些参数即可

1.在Player下创建一个空物体weapon_point,并将斧头移动到Player外作为独立的物体

【Unity exam02】怎样制作一个回旋斧 2D篇

2.进入脚本修改一些代码

删掉变量 playerPos,声明一个公共变量Transform point,删掉Update()中对 playerPos 的赋值,然后将所有的playerPos改为point.position即可

不要忘记在unity中对point进行赋值

【Unity exam02】怎样制作一个回旋斧 2D篇

3.这样武器确实不会跟随玩家进行移动了,但是产生了新bug,武器在玩家手中的时候也不会跟随玩家移动了。所以我定义了一个bool值,onHand,默认为true,用来判断武器是否回到玩家手中。

在Update()方法中,当点击鼠标左键时,物体会进行移动,所以此时onHand应为false

在Update()方法中,当onHand = true时,让武器的位置一直为点的位置

在Movement()方法中,当武器回到手中时,onHand应为true

[SerializeField]
    bool onHand = true;      // 在手中

	// 在Update中添加
	private void Update()
    {
    	// 点击鼠标左键 && 斧头是静止状态
        if (Input.GetMouseButtonDown(0) && !isGo && !isBack)
        {
            onHand = false;
        }
        
        if (onHand)
            transform.position = point.position;
    }
	void Movement()
    {
        // 如果武器返回玩家手中
        if (isBack && Vector2.Distance(transform.position, point.position) < 0.01f)
        {
            onHand = true;
        }
    }
           

【PS:这种方法只是相对减少了一些违和感,并不能完全阻止,比如当玩家的移动速度快于斧头的移动速度,如果斧头返回图中玩家也一起移动的话,斧头就会“追”不上玩家,所以还需合理的限制玩家和斧头的速度】

(6)实现攻击

只需给敌人添加collider 2D组件,给斧头添加collider 2D(勾选is trigger),rigidbody 2D(关掉重力)组件,然后用OntriggerEnter2D方法即可

1.在Weapon脚本中新增方法

注意:任何判断碰撞的方法都需要双方物体都有collider组件,且其中一个物体带有rigidbody组件

private void OnTriggerEnter2D(Collider2D collision)
    {
    	// 调用Enemy的脚本中的Hurt方法,参数为25
        if (collision.CompareTag("Enemy"))
            collision.gameObject.SendMessage("Hurt", 25);
    }
           

别忘记给Enemy添加tag Enemy,如果没有请点击Add Tag新增

【Unity exam02】怎样制作一个回旋斧 2D篇

2.打开Enemy脚本,根据写好的参数直接定义Hurt方法

【Unity exam02】怎样制作一个回旋斧 2D篇
public void Hurt(int damage)
    {
        GetComponentInChildren<HealthBar>().hp -= damage;
    }
           

实现效果

【Unity exam02】怎样制作一个回旋斧 2D篇

·完整项目百度云

https://pan.baidu.com/s/1Kkrx8v5MRfHWNPz0RVKFtQ

提取码:zfet

Unity版本:2019.4.3及以上

日期:2020-10-24