🚀
【clusterベータ】プレイヤーを追いかけるスクリプトを三次元化
公式の、プレイヤーを追いかけるスクリプトを三次元化します。つまり上下にも追いかけてきます。
なお回転は難しいので、とりあえずは二次元のときのままです。いちおう記事の最後にやり方は書いてあります。
・三次元で追いかけてくるので、重力は使わない設定にします。そのためonPhysicsUpdateではなく、そのままonUpdate内で処理します。
・AddForceAtではなく、プレイヤーとの距離の差を正規化(normalize)してからスピード・経過時間を掛け算したものを現在位置に足して自ら計算し、位置を移動させます。
坂の上まで追いかけてくる
要するに変わる部分はスクリプトの最後のほうの一部、こんな感じです。
if (direction.length() > minDistance) {
direction.normalize().multiplyScalar(force * deltaTime);
$.setPosition(position.add(direction));
}
スクリプト全文
アイテムのRigidbodyのUse Gravity(重力を使用)はオフにしておいてください。
あと、元々はonUpdateとonPhysicsUpdateの両方でpositionを求めていましたが、関数が1つになったので1回にしています。
あと、forceは元のスクリプトでは30でしたが、この場合は3くらいでいいでしょう。
const force = 3;
const maxDistance = 10;
const minDistance = 1;
const rad2deg = (rad) => (rad * 180) / Math.PI;
$.onUpdate((deltaTime) => {
let position = $.getPosition();
let players = $.getPlayersNear(position, maxDistance);
let targetPlayer = null;
let targetDistance = Infinity;
// それぞれのプレイヤーとの距離を計算し、最も近いものを探す
players.forEach((player) => {
let playerPosition = player.getPosition();
let distance = playerPosition.clone().sub(position).length();
if (distance < targetDistance) {
targetDistance = distance;
targetPlayer = player;
}
});
// 最も近いプレイヤーのPlayerHandleを保存
$.state.targetPlayer = targetPlayer;
let player = $.state.targetPlayer;
if (player == null) return;
// 追跡中のプレイヤーがログアウトなどでいなくなっていた場合
if (player.exists() == false) return;
// プレイヤーがいる方向の角度を計算してY軸回転
let direction = player.getPosition().clone().sub(position);
let angle = rad2deg(Math.atan2(direction.x, direction.z)); // atan2は弧度法での角度を返すため、度数法に変換する
let rotation = new Quaternion().setFromEulerAngles(new Vector3(0, angle, 0));
$.setRotation(rotation);
// ここからが違う
// プレイヤーと一定より離れているときに、正面方向に前進
if (direction.length() > minDistance) {
direction.normalize().multiplyScalar(force * deltaTime);
$.setPosition(position.add(direction));
}
});
上下を向かせるアイデア
rotationを出すところ、こんな風にすることで上下の回転を実現することもできます。
let xzLength = new Vector2(direction.x, direction.z).length();
let xRot = Math.atan(-direction.y/xzLength)/Math.PI*180;
let rotation = new Quaternion().setFromEulerAngles(new Vector3(xRot, angle, 0));
まずないとは思いますが、xlLengthが0になってしまったときのため、if(xzLength > 0) { }でくくったほうがより無難かもしれません。0で割り算するとエラーになるので。
(初期位置が同じとかだとありうる)
Discussion