上节加上了小地图:

可以实时显示玩家位置以及车辆、NPC、电脑等的位置。
这节我们加一下行走方向的箭头。
首先之前是获取 rotation.y 这样不如直接拿到相机获取 camera.getWorldPosition(worldPos) 更好。
我们改一下:

// 导出更新标记的函数
export function updateMapMarkers(characterModel, carModel, planeModel, personModel, camera) {
// 更新玩家位置
if (characterModel) {
const worldPos = new THREE.Vector3();
characterModel.getWorldPosition(worldPos);
// 使用相机的实际朝向来计算方向,因为玩家移动是基于相机方向的
let rot = characterModel.rotation.y;
if (camera) {
const forward = new THREE.Vector3();
camera.getWorldDirection(forward);
forward.y = 0;
forward.normalize();
// 计算相机朝向的角度(相对于+Z方向)
rot = Math.atan2(forward.x, forward.z);
}
mapSystem.updateMarker('player', worldPos.x, worldPos.z, rot);
}
// 更新车辆位置
if (carModel) {
const worldPos = new THREE.Vector3();
carModel.getWorldPosition(worldPos);
mapSystem.updateMarker('car', worldPos.x, worldPos.z);
}
// 更新飞机位置
if (planeModel) {
const worldPos = new THREE.Vector3();
planeModel.getWorldPosition(worldPos);
mapSystem.updateMarker('plane', worldPos.x, worldPos.z);
}
// 更新NPC位置
if (personModel) {
const worldPos = new THREE.Vector3();
personModel.getWorldPosition(worldPos);
mapSystem.updateMarker('npc', worldPos.x, worldPos.z);
}
}
用到的地方也改一下:

然后加一下绘制箭头的逻辑:

// 绘制玩家方向指示
drawPlayerDirection(ctx, mapX, mapZ, rotationY) {
const length = 15;
// 计算箭头终点位置
const endX = mapX + Math.sin(rotationY) * length;
const endZ = mapZ - Math.cos(rotationY) * length;
// 绘制箭头线
ctx.strokeStyle = '#ff0000';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(mapX, mapZ);
ctx.lineTo(endX, endZ);
ctx.stroke();
// 绘制箭头头部
const arrowSize = 5;
const angle = Math.atan2(endZ - mapZ, endX - mapX);
ctx.beginPath();
ctx.moveTo(endX, endZ);
ctx.lineTo(
endX - arrowSize * Math.cos(angle - Math.PI / 6),
endZ - arrowSize * Math.sin(angle - Math.PI / 6)
);
ctx.lineTo(
endX - arrowSize * Math.cos(angle + Math.PI / 6),
endZ - arrowSize * Math.sin(angle + Math.PI / 6)
);
ctx.closePath();
ctx.fillStyle = '#ff0000';
ctx.fill();
}
就是基于 rotationY 计算下 cos、sin 的边的长度。
然后画箭头,也就是 3 个 lineTo
看下效果:

这样,箭头就绘制完成了。
案例代码上传了小册仓库
总结
这节我们加上了箭头的绘制。
首先用 camera.getWorldDirection 拿到方向,然后基于这个信息计算箭头的方向来画出箭头。
不断的拿到最新的方向绘制一下就可以了。