本帖最后由 空伊伊 于 2023-11-8 18:10 编辑
话不多说,先看效果!
朝屏幕中心点发射一条射线,并在射击点创建一个特效,同时生成一个气球往垂直于射击点的方向飞行
<video controls src="https://forum.ark.online/forum.php?mod=attachment&aid=MzYwfDliMzJhZmExfDE2OTY5MDUwNjl8MTEzfDExMzg%3D&noupdate=yes"></video>
实现代码
@Component
export default class Line extends Script {
/** 当脚本被实例后,会在第一帧更新前调用此函数 */
protected onStart(): void {
this.useUpdate = true
if (SystemUtil.isClient()) {
// 按下G键,开始射击
InputUtil.onKeyDown(Keys.G, () => {
this.shoot()
})
}
}
/**向屏幕中心点发射一条射线 */
public async shoot() {
// 获取角色
let character = (await Player.asyncGetLocalPlayer()).character
// 射线起点为角色头顶往上200的位置
let startLoc = character.worldTransform.position.clone()
startLoc.z += 200
// 获取从起点到屏幕中心点的方向
let aimDir = getShootDir(character, startLoc, 2000);
// 根据起点和方向算出终点位置
let endLoc = startLoc.clone().add(aimDir.multiply(2000));
// 发射一条射线
let hitInfo = QueryUtil.lineTrace(startLoc, endLoc, false, true);
if (hitInfo.length > 0) {
for (let hitResult of hitInfo) {
// 在碰撞发生的接触点播放一次特效
EffectService.playAtPosition("13595", hitResult.impactPoint)
// 调用自定义的函数,传入接触点和接触点的法线,实现气球飞行的效果
this.objFly(hitResult.impactPoint, hitResult.impactNormal)
}
}
}
/**让物体从startLoc朝着dir进行飞行 */
public async objFly(startLoc: Vector, dir: Vector) {
// 异步创建一个气球
let obj = await GameObject.asyncSpawn("85003")
// 根据传过来的位置和方向,算出终点
let endPos = startLoc.clone().add(dir.multiply(1000))
// 根据起点和终点,算出气球朝向
obj.worldTransform.rotation = endPos.clone().subtract(startLoc).toRotation().add(new Rotation(0, -90, 0))
// 使用Tween让气球飞行
let tween = new Tween(startLoc).to(endPos, 2000).onUpdate((v) => {
obj.worldTransform.position = v
}).onComplete(() => {
// Tween播放结束,删除气球
obj.destroy();
})
tween.start();
}
protected onUpdate(dt: number): void {
TweenUtil.TWEEN.update()
}
}
function getShootDir(chara: Character, startPos: Vector, shootRange: number) {
const camera = Camera.currentCamera;
let start = Vector.zero;
let end = Vector.zero;
let dir = Vector.zero;
if (startPos) {
start = startPos;
}
if (camera) {
end = camera.worldTransform.position.add(camera.worldTransform.getForwardVector().multiply(shootRange));
const hits = QueryUtil.lineTrace(camera.worldTransform.position, end, false, true, [], false, true, chara);
dir = end.subtract(start);
if (hits.length > 0) {
dir = hits[0].impactPoint.subtract(start);
}
}
return dir.normalize();
}
一、射线检测(QueryUtil.lineTrace)
1.基本用法
该API的返回值为Array<HitResult>
let hitInfo = QueryUtil.lineTrace(射线起点, 射线终点, 是否穿透, 是否可视化绘制)
2.HitResult
包含了碰撞到的物体信息(注:没有碰撞到物体,将不会返回HitResult)
 |
参数意义:<br /> blockingHit 用来判断射线是否碰到物体 <br />time(0~1) 用来判断碰到多个物体时的先后顺序 <br />distance 测距 <br />Location 位置点 <br />impactPoint 接触点 <br />normal 位置点的法线 (配合位置点做一些特效) <br />impactNormal 接触点的法线 <br />traceStart 射线起点 <br />traceEnd 射线终点 <br />boneName 骨骼名称 <br />gameObject 碰撞到的物体 |
|
|
二、范围检测
1.矩形范围检测(QueryUtil.boxOverlap)
返回值为Array<GameObject>
QueryUtil.boxOverlap(矩形的中心位置, 盒体的大小, 是否可视化绘制)
2.球形范围检测(QueryUtil.sphereOverlap)
返回值为Array<GameObject>
QueryUtil.sphereOverlap(球体中心位置, 检测半径, 是否可视化绘制)
3.胶囊体范围检测(QueryUtil.capsuleOverlap)
返回值为Array<GameObject>
QueryUtil.capsuleOverlap(胶囊体中心位置, 胶囊体半径, 胶囊体半高, 是否可视化绘制)
三、特殊射线检测
1.盒体射线检测(QueryUtil.boxTrace)
返回值为Array<HitResult>
QueryUtil.boxTrace(起始位置,结束位置,合体半长宽高,盒体朝向,是否穿透检测,是否可视化绘制)
2.球体射线检测(QueryUtil.sphereTrace)
返回值为Array<HitResult>
QueryUtil.sphereTrace(起始位置,结束位置,球体半径,是否穿透检测,是否可视化绘制)
3.胶囊体射线检测(QueryUtil.capsuleTrace)
返回值为Array<HitResult>
QueryUtil.capsuleTrace(起始位置,结束位置,胶囊体半径,胶囊体半高,是否穿透检测,是否可视化绘制)




有用就点个赞吧家人们~