Unity: 第三人称视野移动+瞄准线+发射弧线球打击方块(方块可以识别受击方向)demo
功能描述:
演示
demo版本1.0 demo版本2.0
说明补充 和 下载链接
两个场景资源包,免费下载
网盘链接:
链接:https://pan.baidu.com/s/1P9Uj7i6v-NPlrIB6rE-0Dg 提取码:f8sd
第一个使用的手动添加力和赋予初速度(没用用重力)的方法,不同角度发射小球运动轨迹相同(在碰到物体前),小球碰到物体后运动比较梦幻。代码自己写的。
第二个场景用了重力,不同角度发射小球运动轨迹不同,小球碰到物体后运动会下落。因为项目的临时变化,才改用了重力,由于赶时间,在计算轨迹上用了别人的代码【Unity】预计算刚体运动轨迹_萧然-CSDN博客_unity 轨迹线
部分细节
子弹发射部分(注意,最后把施加力的代码放在了FixedUpdate里面,这点非常重要,后面有简单的讲解)
- 由于镜头会移动、要用刚体控制,而且目标位置不是固定的,所以实现子弹弧线运动没有我想的那么简单
(该方法已经弃用)
在Fire类
//向前运动
bulletSon.GetComponent<Rigidbody>().velocity = bulletSon.transform.forward * speedZ;
在新的子弹类里面跟新子弹自身竖直方向的力
private void Update()
{
t += Time.deltaTime;
deltaForce = 1f / 2 * a * t * t;
gameObject.GetComponent<Rigidbody>().AddForce(gameObject.transform.up * (gameObject.GetComponent<BulletParameter>().deltaForce*(-1)));
}
(已弃用)
其实AddForce需要一直存在,才能实现现实生活中的力的效果,如果只在函数里面调用一次AddForce,就相当于只附加了一个初速度。
(现在用的此方法)
然后稍微优化了一下结构,把速度放在子弹的类里面
public class BulletParameter : MonoBehaviour
{
public float deltaForce = 0 ;
private float a = 10.5f;
private float t = 0;
private float speedFront = 9f;
private void Start()
{
//不能放在update里面,会覆盖速度
//向前运动
gameObject.GetComponent<Rigidbody>().velocity = transform.forward * speedFront;
}
private void Update()
{
t += Time.deltaTime;
deltaForce = 1f / 2 * a * t * t;
//相当于自身的竖直方向
gameObject.GetComponent<Rigidbody>().AddForce(gameObject.transform.up * (gameObject.GetComponent<BulletParameter>().deltaForce*(-1)));
}
}
只是当子弹碰撞物体后,就会很鬼畜地乱飞,还挺有意思的。如果以世界坐标应该就不会有这种情况,但是这样的话就需要改变镜头的控制方式,不满足需求。
(最终采用的方法)
如果需要平抛运动可以这样,力放在FixedUpdate里面这点非常非常重要,不然后面根据公式计算的辅助线会和运动轨迹不重合!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletParameter : MonoBehaviour
{
private float speedFront = 9f;//向前运动的速度
private float forceVertical = -0.3f;//竖直方向的力
//已弃用
//public float deltaForce = 0 ;//力的变化
//private float a = 11f;//力的变化速率
//private float t = 0;//运动时间
private void Start()
{
//不能放在update里面,会覆盖速度
//向前运动
gameObject.GetComponent<Rigidbody>().velocity = transform.forward * speedFront;
}
private void FixedUpdate()
{
//t += Time.deltaTime;
//deltaForce = 1f / 2 * a * t * t;
//相当于自身的竖直方向,此为类平抛运动
//gameObject.GetComponent<Rigidbody>().AddForce(gameObject.transform.up * (gameObject.GetComponent<BulletParameter>().deltaForce*(-1)));
//此为平抛运动
gameObject.GetComponent<Rigidbody>().AddForce(gameObject.transform.up * forceVertical);
}
}
bulletSon.GetComponent<Rigidbody>().collisionDetectionMode = CollisionDetectionMode.Continuous;//bulletSon是我自己的子弹类
- 让子弹自身的坐标和当前相机一致,有助于控制不同角度发射子弹和辅助线瞄准的功能
bulletSon.transform.rotation = gameObject.transform.rotation;
轨迹弧线部分
- 因为Linerenderer画的线我用着有些地方有些卡手,不方便,画的线是扁的所以我就用预制体代替点,描出运动轨迹。轨迹点通过物理公式计算得到。
- 可能有人会想直接抛出一个物体记录轨迹点,就可以省去计算的过程。实际上,物体抛出后,需要时间运动,这个时间会带来巨大的延迟,当你稍微移动一下视野,等半天才能得到轨迹。所以需要直接计算出来。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DrawLineObject : MonoBehaviour
{
public BulletParameter bullet;
public GameObject camera;//获得相机
public GameObject pointObject;//充当辅助线点 的预制体
private GameObject[] points;//辅助线的点
private float speedFront;//向前运动的速度
private float forceVertical;//竖直方向力
private float lineTime;//线能触及到子弹运动的时长
private int pointNums;//点的个数
private void Awake()
{
speedFront = bullet.speedFront;
//camera = GameObject.Find("MainCamera");
forceVertical = bullet.forceVertical;
lineTime = 0.5f;
pointNums = 5;
points = new GameObject[pointNums];
for(int i = 0; i < pointNums; i++)
{
points[i] = Instantiate(pointObject);
}
}
private void Update()
{
//获得单位时间,用单位时间算点的位移
float interval = lineTime / pointNums;
for (int i = 1; i <= pointNums; i++)
{
Vector3 pointNow = camera.transform.position;
//pointNow = camera.transform.position;
pointNow += camera.transform.forward * speedFront * interval * i;
pointNow += camera.transform.up * forceVertical * 0.5f * Mathf.Pow((interval * i), 2);
points[i - 1].transform.position = pointNow;
}
}
}
方向判断
当发生碰撞时,用子弹的坐标和方块的坐标减,得到新坐标,新坐标xyz中绝对值最大的轴和它的正负即可判断被击中的面
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum Direction
{
Up=2,
Down=-2,
Right=1,
Left=-1,
Front=3,
Back=-3
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SideJudge : MonoBehaviour
{
private void OnCollisionEnter(Collision collision)
{
if(collision.gameObject.tag == "bullet")
{
Vector3 Direct = collision.transform.position - this.transform.position;//坐标相减
var dir = CollDirection(Direct);//判断方向
print(gameObject.name + "的" + dir + "边,坐标为:" + Direct + "被击中");
}
}
Direction CollDirection(Vector3 direct)
{
int index = 0;
float[] array = new float[] { direct.x, direct.y, direct.z };
//根据数值最大轴的正负判断
for (int i = 0; i < 3; i++)
{
if (Mathf.Abs(direct[i]) > Mathf.Abs(direct[index]))
{
index = i;
}
}
return (Direction)( (index + 1) * (int)(direct[index] / Mathf.Abs(direct[index]) ) );
}
}
镜头移动
只需要一个看向点、读取鼠标状态,然后改变位置即可。
|