🦵

座る位置を自動調整する椅子のClusterScript

2024/12/16に公開

この記事は「Cluster Script Advent Calendar 2024」の16日目です
昨日は獏星さんのClusterScriptでQuaternionのデータサイズをダイエットする小細工でした!
とても大事!!!!!我々の使える帯域は、細いっ…!!!


こんばんは!!かおもです!!!!

BOOTHで配布している「座る位置を自動調整する椅子」のスクリプトについて簡単に解説をしたいと思います。
BOOTHの方にも書いてありますが、改変可、ワールドに組み込み可、クラフトアイテムに仕込んでの配布可です!!

非ベータなので安心

PlayerScript.getHumanoidBonePositionベータ抜けしたので、実現できました!!!

しかし、PlayerHandle.getHumanoidBonePositionの方はCCK2.30.0時点でベータなので、少々面倒なことをやっています。

ScriptableItem側は座り判定と調整

早速ですがスクリプト全文です。

アイデアの出発点は椅子の前側の角の位置が分かれば、座る位置を調整できるのでは? です。
あとは、足の長さを計算すれば実際に位置調整できます。

ScriptableItem側
//Seatと角の位置と、足の長さから座る位置を調整する

//RidabelItemのSeat
const seat = $.subNode("Seat");
//椅子の前側の角
const edge = $.subNode("Edge");

$.onStart(() => {
    $.state.seatInitial = seat.getPosition();
    $.state.seatGap = edge.getPosition().z - seat.getPosition().z;
});

$.onRide((isGetOn, player) => {
    if(!isGetOn){
        //椅子から降りたら戻す
        resetSeatPosition();
        return;
    }
    //足の長さの計測を依頼する
    //PlayerHandle.getHumanoidBonePositionがベータ抜けしたら、依頼せずに自前で可能
    $.setPlayerScript(player);
    player.send("?legLength", "");
});

$.onReceive((messageType, arg, sender) => {
    if(messageType === "legLength"){
        //足の長さに基づいてSeatを移動させる
        adjustSeatPosition(arg);
    }
}, {player: true, item: true});

const resetSeatPosition = () => {
    seat.setPosition($.state.seatInitial);
};

const adjustSeatPosition = legLength => {
    const seatOffset = new Vector3(0, 0, $.state.seatGap - legLength);
    seat.setPosition(seat.getPosition().add(seatOffset));
};

ざっくりとした流れです。

  1. 座る位置と椅子の角の位置を把握する。
  2. 座ったらPlayerScriptに足の長さの計測を依頼する。
  3. (PlayerScriptは足の長さを計測して、ScriptableItemに返す。)
  4. 足の長さが返ってきたら、椅子の角からの距離と比較して、位置調整をする。

項番3はPlayerScript側に記述されています。

1. 座る位置と椅子の角の位置を把握する。

//RidabelItemのSeat
const seat = $.subNode("Seat");
//椅子の前側の角
const edge = $.subNode("Edge");

$.onStart(() => {
    $.state.seatInitial = seat.getPosition();
    $.state.seatGap = edge.getPosition().z - seat.getPosition().z;
});

subNodeのEdgeは実際の椅子のメッシュに合わせて、GameObjectの位置を変更する必要があります。
このseatとedgeの間の距離(seatGap) と、後で出てくる足の長さの差を計算して、Seatの前後位置を調整する仕組みになっています。

2. 座ったらPlayerScriptに足の長さの計測を依頼する。

$.onRide((isGetOn, player) => {
    if(!isGetOn){
        //椅子から降りたら戻す
        resetSeatPosition();
        return;
    }
    //足の長さの計測を依頼する
    //PlayerHandle.getHumanoidBonePositionがベータ抜けしたら、依頼せずに自前で可能
    $.setPlayerScript(player);
    player.send("?legLength", "");
});

上の方のif(!isGetOn)あたりの処理は、一応降りたときに丁寧に戻しているだけです。
座ったらどうせ移動するので、省いても大丈夫な処理です。

面倒なのはその後の処理で、座ったプレイヤーにplayer.sendで足の長さを計測するように依頼をしています。
コメントにもありますが、PlayerHandle.getHumanoidBonePositionがベータ抜けしたら$.setPlayerScriptplayer.sendも不要です。

余談ですが、筆者は応答すべき何かをsendするときに、messageTypeの頭に?をつけるのが好きです。
?legLengthでsendしたらlegLengthでonReceiveできるという寸法です。

4. 足の長さが返ってきたら、椅子の角からの距離と比較して、位置調整をする。

$.onReceive((messageType, arg, sender) => {
    if(messageType === "legLength"){
        //足の長さに基づいてSeatを移動させる
        adjustSeatPosition(arg);
    }
}, {player: true, item: true});

legLengthで足の長さが返ってきたら位置調整(adjustSeatPosition)をします。
PlayerHandle.getHumanoidBonePositionがベータ抜けしたら、先のsendとこのonReceiveを削除して、onRide内で直接adjustSeatPositionを動かせばOKです。

細かいところですが、PlayerScriptとのやり取りがあるので{player: true, item: true}の指定を忘れないで下さい。

adjustSeatPositionの中身です。

const adjustSeatPosition = legLength => {
    const seatOffset = new Vector3(0, 0, $.state.seatGap - legLength);
    seat.setPosition(seat.getPosition().add(seatOffset));
};

項番1で計算したseatGapと、足の長さlegLengthの差の分だけSubNodeのseatを移動させる、という処理になっています。

PlayerScript側は足の長さの測定

早速ですがスクリプト全文です。

ScriptableItem側
_.onReceive((messageType, arg, sender) => {
    if(messageType === "?legLength"){
        //足の長さを計測して送り返す
        const legLength = getLegLength();
        _.sendTo(sender, "legLength", legLength);
    }
});

const getLegLength = () => {
    const upperLeg = _.getHumanoidBonePosition(HumanoidBone.RightUpperLeg);
    const lowerLeg = _.getHumanoidBonePosition(HumanoidBone.RightLowerLeg);
    const length = upperLeg.sub(lowerLeg).length();
    return length;
};

こっちは足の長さを計測しているだけです。
onReceiveで依頼を受けて、sendToで足の長さを送り返しています。

UpperLegは股関節あたりの位置で、LowerLegは膝の位置になります。
なので、その差が足の長さ(座る時の前後位置に影響する長さ)ということになります。

課題や改変ポイント

VRoidStudio製とclusterのアバターメイカー製で、ボーンに対してのメッシュの付き方がかなり異なるので、この辺を何とかできたら嬉しいですね。

あとは両足の間隔から足の太さ?を予測してSeat高さを調節したりとかも面白いかもしれません。

おわり

よきClusterScriptライフを!!!


明日の記事はヒカゲさんの「スクリプトつながりで、CCK本体(C#)について。回線速度が遅く、何度もアップデートに失敗する人の解決を目指します」です!!
テスト用は1つだからいいけど、本番のは地味に詰まるんですよねw

Discussion