提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
想要了解这篇文章再讲什么,要先看前一篇文章,在前一篇文章中,我们完成了制作地图,实现人物动画和移动脚本,制作单例模式和对象池,制作手枪pistol和子弹bullet和子弹壳bulletShell,制作散弹枪shotgun的功能。接下来我们要做的是扩展武器库制作火箭筒,镭射枪,冲锋枪。事不宜迟立刻开始这期学习吧。
一、导入素材
把上一期内容素材再放一遍:
https://o-lobster.itch.io/simple-dungeon-crawler-16x16-pixel-pack
https://humanisred.itch.io/weapons-and-bullets-pixel-art-asset
二、制作流程
1.制作火箭筒RocketLanucher和火箭Rocket
代码如下(示例):
同样作为一个Gun的Varient生成一个预制体prefab:
通用制作动画:
创建一个同名脚本让它继承自Gun:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RocketLauncher : Gun
{
public int rocketNum = 4;
public float rocketAngle = 30;
protected override void Fire()
{
animator.SetTrigger("Shoot");
StartCoroutine(DelayFire(0.2f));
}
private IEnumerator DelayFire(float delay)
{
yield return new WaitForSeconds(delay);
int med = rocketNum / 2;
for (int i = 0; i < rocketNum; i++)
{
GameObject rocket = ObjectPool.Instance.GetObject(bulletPrefab);
rocket.transform.position = muzzleTrans.position;
if (rocketNum % 2 == 1)
{
rocket.transform.right = Quaternion.AngleAxis(rocketAngle * (i - med), Vector3.forward) * direction;
}
else
{
rocket.transform.right = Quaternion.AngleAxis(rocketAngle * (i - med) + rocketAngle / 2f, Vector3.forward) * direction;
}
rocket.GetComponent<Rocket>().SetTarget(mousePos);
}
}
}
可以看到,我们在重写Fire()方法时使用了协程延迟火箭弹的发射时间,而且我们并没有接着使用bullet预制体也不需要bulletshell,而是新建一个游戏对象rocket:
给它创建一个同名脚本rocket.cs:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rocket : MonoBehaviour
{
public float lerp;
public GameObject explosionPrefab;
public float speed = 15f;
private Rigidbody2D rb2d;
private Vector3 targetPos;
private Vector3 direction;
private bool arrived; //用arrived来判断是否到达终点坐标
private void Awake()
{
rb2d = GetComponent<Rigidbody2D>();
}
private void FixedUpdate()
{
direction = (targetPos - transform.position).normalized;
if(!arrived)
{
//在两个向量之间进行球面插值,tran.position和targetPos离得越远速度越快
transform.right = Vector3.Slerp(transform.right, direction, lerp / Vector2.Distance(transform.position, targetPos));
rb2d.velocity = transform.right * speed;
}
if(Vector2.Distance(transform.position, targetPos) < 1f && !arrived)
{
arrived = true;
}
}
//可以看到我们用SetTarget取代了以往的SetSpeed,将鼠标位置=target即终点坐标
public void SetTarget(Vector2 target)
{
arrived = false;
targetPos = target;
}
private void OnTriggerEnter2D(Collider2D other)
{
if(other.gameObject.layer == LayerMask.NameToLayer("Wall"))
{
GameObject exp = ObjectPool.Instance.GetObject(explosionPrefab);
exp.transform.position = transform.position;
rb2d.velocity = Vector2.zero;
StartCoroutine(PushObject(0.3f));
}
}
//延迟自身对象进入对象池
private IEnumerator PushObject(float delay)
{
yield return new WaitForSeconds(delay);
ObjectPool.Instance.PushObject(gameObject);
}
}
这个Slerp的解释我看了一下,反正感觉是绕着一个轴(这里我们设置的是X轴)做插值运动,这解释能看懂你也不会来看我这篇文章了
最后我们设置好参数:
2.制作镭射枪LaserGun和火箭Rocket
这是个有个性的枪,因为它既不需要子弹又不需要子弹壳,要实现这种效果我们可以使用LineRenderer来实现激光效果:
给它制作动画,和之前用trigger参数不同,这次我们使用bool来控制动画转换:
我们想要激光变得更多样化还得使用URP插件编写shader graph
在Package Manager中找到URP并下载导入:
回到project中创建New Renderer Data
在project setting中设置graphics
记得保存好后升级整个项目:
回到camera中勾选后处理选项Post Processing:
为项目创建一个Global Volume:
然后到哦我们编写shader graph的时候了:
有了shader graph就到我们创建material的时候:
回到LineRenderer中赋值Material:
给LaserGun创建一个同名脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LaserGun : Gun
{
private GameObject effect;
private LineRenderer line;
private bool isShooting;
protected override void Start()
{
base.Start();
line = muzzleTrans.GetComponent<LineRenderer>();
effect = transform.Find("Effect").gameObject;
}
protected override void Shoot()
{
direction = (mousePos - new Vector2(transform.position.x, transform.position.y)).normalized;
transform.right = direction;
if(Input.GetKeyDown(KeyCode.Mouse0))
{
isShooting = true;
line.enabled = true; //注意:我们要在项目运行游戏前将line的组件关闭掉!
effect.SetActive(true);
}
if (Input.GetKeyUp(KeyCode.Mouse0))
{
isShooting = false;
line.enabled = false;
effect.SetActive(false);
}
animator.SetBool("Shoot", isShooting);
if (isShooting)
{
Fire();
}
}
protected override void Fire()
{
RaycastHit2D hit2d = Physics2D.Raycast(muzzleTrans.position, direction, 30f);
line.SetPosition(0, muzzleTrans.position); //射线起点是muzzleTrans的位置
line.SetPosition(1, hit2d.point); //将射线终端位置设置为hit2d碰到的那个点位置
effect.transform.position = hit2d.point;
effect.transform.forward = -direction;
}
}
这里我们还差一个effect即Partical System没实现:
直接给你们上参数:
3.制作冲锋枪Rifle和冲锋枪子弹RifleBullet
最终是冲锋枪,按道理来说它的pistol实现的原理都差不多所以我们只需要重写Fire函数即可
给它一个同名脚本并继承自Gun.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rifle : Gun
{
protected override void Fire()
{
animator.SetTrigger("Shoot");
RaycastHit2D hit2d = Physics2D.Raycast(muzzleTrans.position, direction, 30f);
GameObject bullet = ObjectPool.Instance.GetObject(bulletPrefab);
LineRenderer line = bullet.GetComponent<LineRenderer>();
line.enabled = true;
line.SetPosition(0, muzzleTrans.position);
line.SetPosition(1, hit2d.point);
GameObject bulletShell = ObjectPool.Instance.GetObject(bulletShellPrefab);
bulletShell.transform.position = bulletShellTrans.position;
bulletShell.transform.rotation = bulletShellTrans.rotation;
}
}
我们可以使用LineRenderer来实现Bullet预制体的效果:
给它一个同名脚本BulletTracer:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletTracer : MonoBehaviour
{
public float fadeSpeed = 0.1f;
private LineRenderer line;
private float alpha;
private void Awake()
{
line = GetComponent<LineRenderer>();
alpha = line.endColor.a;
}
private void OnEnable()
{
line.endColor = new Color(line.endColor.r, line.endColor.g, line.endColor.b, alpha);
StartCoroutine(Fade());
}
private IEnumerator Fade()
{
//LineRenderer淡出效果实现,每固定帧line.endColor.a - fadeSpeed即可
while (line.endColor.a > 0f)
{
line.endColor = new Color(line.endColor.r, line.endColor.g, line.endColor.b, line.endColor.a - fadeSpeed);
yield return new WaitForFixedUpdate();
}
//回收该对象
ObjectPool.Instance.PushObject(gameObject);
}
}
最后的最后,别忘了把这三把新武器添加到PlayerController.cs的Guns[]数组中:
总结
最终效果如下所示:
made这个冲锋枪的LineRenderer消失太快了我截图不到,反正你们自己做的时候看得到即可(我这地上有弹壳的):