问题描述
比方说,我有一个玩家位于X: 100,Y: 100,Z: 100
,我想找出以下哪个点最接近并获得其ID。
ID: 1,X: 200; Y: 200; Z: 100,ID: 2,X: 150; Y: 300; Z: 300,ID: 3,X: 300; Y: 200; Z: 100,ID: 4,X: 50; Y: 100; Z: 200
我该怎么办?它背后的数学是什么?如果有帮助,我已经有以下代码:
var returnVehicles = [];
mp.vehicles.forEachInRange(player.position,100,(vehicle) => {
if(vehicle.ownerID == player.id) {
returnVehicles.push(vehicle.position,vehicle.id);
}
}
);
它循环遍历范围为100的车辆,并将属于玩家的ID和位置添加到数组中。但是,我不知道该怎么办。
有人向我推荐.sort()方法,但这似乎不起作用,因为它只能获得最小的坐标,而不是最近的坐标。
@EDIT:我的完整代码
function distance3D(posA,posB) {
const dX = posA.X - posB.X;
const dY = posA.Y - posB.Y;
const dZ = posA.Z - posB.Z;
return Math.sqrt(dX * dX + dY * dY + dZ * dZ);
}
const vehiclesAnddistances = [];
function lockPlayerVehicle (player) {
let vehicle = player.vehicle;
if (vehicle) {
//IRRELEVANT
}
else {
mp.vehicles.forEachInRange(player.position,40,(vehicle) => {
if(vehicle.ownerID == player.id) {
vehiclesAnddistances.push({vehicle,distance: distance3D(player,vehicle),});
}
}
);
vehiclesAnddistances.sort((a,b) => a.distance - b.distance);
player.outputChatBox("Lista Pequena: " + String(vehiclesAnddistances[0]));
console.log(vehiclesAnddistances[0],vehiclesAnddistances[0].vehicle.model)
};
}
mp.events.add("keypress:DOWNARROW",lockPlayerVehicle);
解决方法
对于少量车辆,只需使用Pythagorean algorithm查找车辆与玩家之间的距离就足够了。 (对于不止几个(或者如果您需要经常循环),您可能需要研究空间分割算法(例如四叉树),以使查找更有效。)
// Assumes posA and posB are both objects with X,Y,Z members.
function distance3D(posA,posB) {
const dX = posA.X - posB.X;
const dY = posA.Y - posB.Y;
const dZ = posA.Z - posB.Z;
return Math.sqrt(dX * dX + dY * dY + dZ * dZ);
}
// Stores objects of shape `{vehicle: ...,distance: number}`
const vehiclesAndDistances = [];
mp.vehicles.forEachInRange(player.position,100,(vehicle) => {
if (vehicle.ownerID == player.id) {
vehiclesAndDistances.push({
vehicle,distance: distance3D(player,vehicle),});
}
});
// Sort the array by the distance
vehiclesAndDistances.sort((a,b) => a.distance - b.distance);
编辑:如评论中所述,如果只需要最近点,则可以将其重新表示为
let closestDistance = undefined;
let closestVehicle = undefined;
mp.vehicles.forEachInRange(player.position,(vehicle) => {
if (vehicle.ownerID === player.id) {
const distance = distance3D(player,vehicle);
if (closestDistance === undefined || distance < closestDistance) {
closestVehicle = vehicle;
closestDistance = distance;
}
}
});
,
您可以使用distance formula。将其应用于每个点并选择最小值。时间复杂度是线性的,但是您可能每帧循环运行一次,因此总体复杂度是二次的。有可用的优化。见
不改变时间复杂度的可能的微优化包括避免平方根运算,一分钟保存最小值等。
const dist = (a,b) => Math.sqrt(
(b.X - a.X) ** 2 +
(b.Y - a.Y) ** 2 +
(b.Z - a.Z) ** 2
);
const closest = (target,points,eps=0.00001) => {
const distances = points.map(e => dist(target,e));
const closest = Math.min(...distances);
return points.find((e,i) => distances[i] - closest < eps);
};
const player = {X: 100,Y: 100,Z: 100};
const points = [
{ID: 1,X: 200,Y: 200,Z: 100},{ID: 2,X: 150,Y: 300,Z: 300},{ID: 3,X: 300,{ID: 4,X: 50,Z: 200}
];
console.log(closest(player,points));
您可以将dist
推广到以下任意维度:
const dist = (a,b) => Math.sqrt(
Object.keys(a).map(k => (b[k] - a[k]) ** 2)
.reduce((a,e) => a + e)
);
,
您可以使用欧式距离计算公式。将所有坐标放在一个数组中,并使用地图创建一个新的距离数组,该距离是通过实现欧几里得公式得出的。您可以按升序或降序对数组元素进行排序并找到距离
let currData = [{
ID: 1,Z: 100
},{
ID: 2,Z: 300
},{
ID: 3,{
ID: 4,Z: 200
}
]
const vehlPos = {
X: 250,Y: 400,Z: 600
};
let getDist = currData.map((item) => {
const xdiff = Math.pow((vehlPos.X - item.X),2);
const ydiff = Math.pow((vehlPos.Y - item.Y),2);
const zdiff = Math.pow((vehlPos.Z - item.Z),2);
return Math.sqrt(xdiff + ydiff + zdiff)
});
console.log(getDist)
,
您可以将对象转换为点并使用矢量函数。
这是3D矢量类别的somewhat-complete example。
const main = () => {
const player = { X: 100,Z: 100 };
const points = [
{ ID: 1,Z: 100 },{ ID: 2,Z: 300 },{ ID: 3,{ ID: 4,X: 50,Z: 200 }
];
console.log(findClosestPoint(player,points));
};
const findClosestPoint = (player,points) => {
let { X,Z } = player;
const pos = new Vector3D(X,Z),minDist = points.reduce((res,point,index) => {
let { X,Z } = point;
const value = pos.distanceTo(new Vector3D(X,Z));
return value < res.value ? { index,value } : res;
},{ index: -1,value: Number.MAX_VALUE });
console.log('Min distance:',minDist.value);
return points[minDist.index];
};
class Vector3D {
constructor (x,y,z) {
this.x = x;
this.y = y;
this.z = z;
}
distanceTo (other) {
return Math.sqrt(
Math.pow(this.x - other.x,2) +
Math.pow(this.y - other.y,2) +
Math.pow(this.z - other.z,2)
);
}
}
main();
.as-console-wrapper { top: 0; max-height: 100% !important; }
输出
Min distance: 111.80339887498948
{
"ID": 4,"X": 50,"Y": 100,"Z": 200
}