https://linen.dev logo
ドアの動きについて
# forum
k
ドアが開くときの動き方と閉まるときの動き方を分けたいんですがどうすればいいのでしょうか? ばる様の京急パックのような動作です。
https://www.youtube.com/shorts/_Gr1boXL9lE 動画のような動きです
u
動画のような動きと言われましても わからんので、簡潔でもいいので文字で表現してくださると
k
等速→最後だけ遅く
という感じです
u
ばる様の京急を参考にするならば、主にRenderScript内の`var doorClsSpd`と`function updateDoors()`を中心に調べていけばどのように動いてるかわかると思います
現在どのような状況なのか教えていただけますか?
k
確かhi03さんのドア稼働構文なので一からやり直す必要がありそうです
学校なので午後7時からまた浮上します
戻ってきました
質問なのですが
function updateDoors(dataMap)とは何ですか
u
簡単にいうと~~毎tick(多分)~~ドア状態を更新する関数です
あ、でもrenderだからフレーム毎か
k
これ必須なんですかね
u
これが必須というか相応の処理があった方が楽というか
別にこれをコピーしなければいけないわけではないです
k
なるほどです
u
ドアの動き方を開閉で分けるなら、アニメーション用のドア移動量の変数に、「加算するとき」「減算するとき」で別の処理にする必要があると思います。 そして、数学得意な人ならいい感じの関数を作って対応するんでしょうが…… 私はいつもの脳筋スタイルで、ドア閉の動作をいくつかの段階に分けて、それぞれに違うアニメーション変数の変化量を設定して動きに変化を付けます。
Copy code
js
if(右開かつ、アニメーション変数①が0を上回るなら){アニメーション変数① -= 変化量①
}else if(右開かつ、アニメーション変数①が0以下かつ、アニメーション変数②が0を上回るなら){
アニメーション変数② -= 変化量②
}
//ここに左側ドアの同じ構文
//ドア閉じ動作の分も同じく左右構文記述
みたいな感じ?
k
すべて分けたほうがわかりやすそうですね
今から試してみます
h
ドアモーションのカスタムについては主に2種類のやり方があります。 最終的には"ドアの移動量"を出してアニメーションに適用するのですが、この移動量の計算を自前でやるか、RTMの実装を使ってやるかの二通りになります。 前者の場合は自前で実装する分難易度が高い、再開閉時の移動量の誤差が発生しない、アニメーション時間をカスタムできるといった感じで、 後者は実装が簡単、開扉と閉扉で関数が違う場合は再開閉時に一瞬でドアが動いたりする、アニメーションの時間は固定(3秒)という感じです。 とりあえず後者の方でざっくり説明しますね
Copy code
javascript
var doorLength = 0.6356;//ドアの長さ(移動量)[m]
var isOpenR = (entity.getTrainStateData(4) & 1) === 1;//右ドアスイッチが開か閉か
var isOpenL = (entity.getTrainStateData(4) & 2) === 2;//左ドアスイッチが開か閉か
var doorMoveR = entity.doorMoveR / 60;//右ドアのアニメーション量 3秒かけて 0.0 - 1.0 になる値を返す
var doorMoveL = entity.doorMoveL / 60;//左ドアのアニメーション量 3秒かけて 0.0 - 1.0 になる値を返す
var doorMotionR = 0;
var doorMotionL = 0;

//ドアの挙動は一次関数などを合成して動きをつける

//右ドアスイッチが開のときの挙動
if (isOpenR) {
    //0.0 → 0.7までは早めに動き、最後にゆっくり動く挙動
    if (doorMoveR < 0.7) doorMotionR = lerp(doorMoveR, 0.0, 0.0, 0.7, 0.9);//doorMoveRが0.0のときは0.0、0.7のときは0.9となる一次関数
    else doorMotionR = lerp(doorMoveR, 0.7, 0.9, 1.0, 1.0);//doorMoveRが0.7のときは0.9、1.0のときは1.0となる一次関数
}
//右ドアスイッチが閉のときの挙動
else {
    //1.0 → 0.2までは早く動き、最後にゆっくり動く挙動
    if (doorMoveR > 0.2) doorMotionR = lerp(doorMoveR, 1.0, 1.0, 0.2, 0.1);
    else doorMotionR = lerp(doorMoveR, 0.2, 0.1, 0.0, 0.0);
}
//左ドアスイッチが開のときの挙動
if (isOpenL) {
    if (doorMoveL < 0.7) doorMotionL = lerp(doorMoveL, 0.0, 0.0, 0.7, 0.9);
    else doorMotionL = lerp(doorMoveL, 0.7, 0.9, 1.0, 1.0);
}
//左ドアスイッチが閉のときの挙動
else {
    if (doorMoveL > 0.2) doorMotionL = lerp(doorMoveL, 1.0, 1.0, 0.2, 0.1);
    else doorMotionL = lerp(doorMoveL, 0.2, 0.1, 0.0, 0.0);
}

//右前ドアの描画
GL11.glPushMatrix();
GL11.glTranslatef(0, 0, doorMotionR * doorLength);
doorRF.render(renderer);
GL11.glPopMatrix();
//右後ドアの描画
GL11.glPushMatrix();
GL11.glTranslatef(0, 0, doorMotionR * -doorLength);
doorRB.render(renderer);
GL11.glPopMatrix();

//左前ドアの描画
GL11.glPushMatrix();
GL11.glTranslatef(0, 0, doorMotionL * doorLength);//ドアの移動
doorLF.render(renderer);
GL11.glPopMatrix();
//左後ドアの描画
GL11.glPushMatrix();
GL11.glTranslatef(0, 0, doorMotionL * -doorLength);
doorLB.render(renderer);
GL11.glPopMatrix();

⋮

//線形補間の関数
function lerp(x, x1, y1, x2, y2) {
    return y1 + (y2 - y1) * (x - x1) / (x2 - x1);
}
(動作の検証はしてないので間違ってたらごめんなさい)
k
実装してみます
正常に動作しました。
ありがとうございます。
自前で用意するというのは引用で申し訳ないですが
Copy code
function hi03Linear(par1){
  var m;
  if(par1===1.0){m = 1.0;}
  else if(par1===0.0){m = 0.0;}
  
  else if(par1>0.0&&par1<0.3){
    m = 0.66666 * par1 ;
  }
  else if(par1>=0.3&&par1<=0.8){
    m = 1.4 * par1 - 0.22;
  }
  else if(par1>0.8&&par1<1.0){
    m = par1 * 0.5 + 0.5;
  }      
  return m;
}
このような文ですか?
h
その文はRTM側の実装を使った処理と一緒ですね RTMの実装を使った処理は直線(0.0~1.0)のグラフを条件分岐で折ったり曲げたりのイメージです 自前で実装する処理をやる場合、ドアの開閉率に応じた加速度や値の増減を設定し、変数呼び出し→値を増減→保存を繰り返します(サーバースクリプトで実装する場合は同期も必要)。 値の呼び出し/保存(dataMap)は以下のようにできます
Copy code
javascript
//dataMapの使い方
var dataMap = entity.getResourceState().getDataMap();
var doorMotionR = dataMap.getDouble("doorMotionR");//値呼び出し
var doorMotionL = dataMap.getDouble("doorMotionL");
var maxMove = 1.0;//1.0m
var isOpenR = (entity.getTrainStateData(4) & 1) === 1;//右ドアスイッチが開か閉か
var isOpenL = (entity.getTrainStateData(4) & 2) === 2;//左ドアスイッチが開か閉か

//値を変更する(例)
if (isOpenL && doorMotionL < maxMove) doorMotionL = doorMotionL + 0.01;//ドアが開いているときはドアの位置を0.01mずつ増やす
if (isOpenR && doorMotionR < maxMove) doorMotionR = doorMotionR + 0.01;
if (!isOpenL && doorMotionL > 0) doorMotionL = doorMotionL - 0.01;
if (!isOpenR && doorMotionR > 0) doorMotionR = doorMotionR - 0.01;

//値を保存する
dataMap.setDouble("doorMotionR", doorMotionR, 0);//第3引数のフラグ 0:非同期(スクリプト内のみ) 1:サーバー/クライアント同期(パケット送信あり)
dataMap.setDouble("doorMotionL", doorMotionL, 0);
描画スクリプトだけで完結する場合、スクリプトの実行回数がfpsやpass、材質の数などに応じて一定ではなくなるため、その対策が必要になります
k
Copy code
function render_door(entity){    
    if(entity!=null){
    //dataMapの使い方
    var dataMap = entity.getResourceState().getDataMap();
    var doorMotionR = dataMap.getDouble("doorMotionR");//値呼び出し
    var doorMotionL = dataMap.getDouble("doorMotionL");
    var maxMove = 1.0;//1.0m
    var isOpenR = (entity.getTrainStateData(4) & 1) === 1;//右ドアスイッチが開か閉か
    var isOpenL = (entity.getTrainStateData(4) & 2) === 2;//左ドアスイッチが開か閉か

    //値を変更する(例)
    if (isOpenL && doorMotionL < maxMove) doorMotionL = doorMotionL + 0.01;//ドアが開いているときはドアの位置を0.01mずつ増やす
    if (isOpenR && doorMotionR < maxMove) doorMotionR = doorMotionR + 0.01;
    if (!isOpenL && doorMotionL > 0) doorMotionL = doorMotionL - 0.01;
    if (!isOpenR && doorMotionR > 0) doorMotionR = doorMotionR - 0.01;

    //値を保存する
    dataMap.setDouble("doorMotionR", doorMotionR, 0);//第3引数のフラグ 0:非同期(スクリプト内のみ) 1:サーバー/クライアント同期(パケット送信あり)
    dataMap.setDouble("doorMotionL", doorMotionL, 0);
}

        //右前ドアの描画
    GL11.glPushMatrix();
    GL11.glTranslatef(0, 0, doorMotionR);
    doorR1.render(renderer);
    GL11.glPopMatrix();
        //右後ドアの描画
    GL11.glPushMatrix();
    GL11.glTranslatef(0, 0, doorMotionR);
    doorR2.render(renderer);
    GL11.glPopMatrix();

        //左前ドアの描画
    GL11.glPushMatrix();
    GL11.glTranslatef(0, 0, doorMotionL);//ドアの移動
    doorL1.render(renderer);
    GL11.glPopMatrix();
        //左後ドアの描画
    GL11.glPushMatrix();
    GL11.glTranslatef(0, 0, doorMotionL);
    doorL2.render(renderer);
    GL11.glPopMatrix();

}
今は試しに教えてもらったものをそのまま入れてみたんですが、片方にしか開かないかつ瞬間移動してしまいます。
dataMap.setDoubleを1にすることで動きが早いのは解決しました
どうやらdoorMotionLの-が抜けていたようです
ドアの動きも解決しました。
h
そのまま描画スクリプトで値の増減をするだけではフレームレートに応じて加速したり減速したりします。 自分の京成北総パックに一定のタイミングで処理できる関数があったのでよかったら使ってください
Copy code
javascript
function tickUpdate(entity, pass) {
    //passによって1フレームで4回実行されるため、pass !== 0 で弾く
    //材質の数だけ繰り返し実行されるため、renderer.currentMatId !== 0 で弾く
    if (!entity || pass !== 0 || renderer.currentMatId !== 0) return;

    var dataMap = entity.getResourceState().getDataMap();
    var tick = renderer.getTick(entity);
    var prevTick = dataMap.getInt("tickUpdate_tick");
    dataMap.setInt("tickUpdate_tick", tick, 0);

    //Tickが変わったときだけ実行する(1秒=20ticks) → 再生速度を一定にできる
    if (prevTick !== tick) {
        //この中に値の増減処理、保存処理を書く(描画はしない)



    }
}
k
ありがとうございます
7 Views