2015年4月1日水曜日

DetailedInfoプロパティ

プログラミングガイドには出ていないけど、SpaceEngineersのインストールフォルダの中のToolsというフォルダの中にDocumentationというヘルプファイルがあり
その中にクラスの詳細が書いてあって
IMyTerminalBlockの項にDetailedInfoというプロパティが存在する
何かな~って思っていたら


画面右下のCurrent position: 0.0mってところ
これが全部Stringで格納されている

つまり、ピストンがどれくらいの長さになっているかを知りたければ、この文字列から切り出せばOKってこと

ランディングギアが黄色(Ready To Lock)状態かを取得したくて調べていたのですが、これを使えば取得できそうです(^-^


ちなみに確認に使ったコードはこれ

void Main()
{
    IMyTerminalBlock block = GridTerminalSystem.GetBlockWithName("Piston") as IMyTerminalBlock;
    IMyTextPanel textpanel = GridTerminalSystem.GetBlockWithName("Text panel") as IMyTextPanel;
   
    string text = "";
   
    text = block.DetailedInfo;
    textpanel.WritePublicText(text);
}

普通に読み取れます

ヘルプには他にもプロパティが載っているのですが、どういう値なのか説明がないのが難点・・・

2015年3月29日日曜日

Automatic Landing

自動で着陸してくれるシステム作ってみた
現バージョンではダンパーをオフにして前につけたセンサーが反応したところまで進み
その後ランディングギアがロックされるまで降下するだけのもの

必要なパーツ
センサー(プレイヤーはOFF、船等をONにする。範囲はお好みで)
スラスター
コックピット
タイマーブロック(1~2秒くらいがおすすめ、アクションにはプログラムブロックを指定)

使い方は""の部分を自分の船に合わせて書き換える(コードでもパーツ名をあわせてもOK)

static string FRONT_SENSOR = "Sensor";
前のセンサー名

static string THRUSTER_F = "Small Thruster 3";
前向きのスラスター名

static string THRUSTER_D = "Small Thruster 4";
下向きのスラスター名
static string COCKPIT ="Cockpit";
コックピット名

static string TIMER = "Timer Block";
タイマーブロック名

あとはコードを走らせるだけ(母艦は静止させること)
サポートできないので使用は自己責任で!

課題
旋回運動はしないので、そのあたりの姿勢制御をどうするかが悩みどころ
(上下のない宇宙だから、着地先の状態をどうやって取得するか・・・)
あとは自機の速度管理もしていないのでランディングギアが壊れるかも(レーザー測距ブロック実装希望)


↓ここから下をプログラムブロックに貼り付ける
//Automatic Landing ver0.1

static string FRONT_SENSOR = "Sensor";
static string THRUSTER_F = "Small Thruster 3";
static string THRUSTER_D = "Small Thruster 4";
static string COCKPIT ="Cockpit";
static string GYRO = "Gyroscope";
static string TIMER = "Timer Block";
static int GEARNUM = 1;

IMySensorBlock f_sensor;
IMyFunctionalBlock thrst_f;
IMyFunctionalBlock thrst_d;
IMyTextPanel textpanel;
IMyCockpit cockpit;
IMyTimerBlock timerb;

double x;
double y;
double z;
double oldx;
double oldy;
double oldz;
long CurrentTime;
long OldTime;
double speed;
string text = "";

static string mode;

void Main()
{
    List<IMyTerminalBlock> TL = new List<IMyTerminalBlock>();
    GridTerminalSystem.SearchBlocksOfName(THRUSTER_F,TL);
    thrst_f = TL[0] as IMyThrust;
    GridTerminalSystem.SearchBlocksOfName(THRUSTER_D,TL);
    thrst_d = TL[0] as IMyThrust;

    f_sensor = GridTerminalSystem.GetBlockWithName(FRONT_SENSOR) as IMySensorBlock;
    textpanel = GridTerminalSystem.GetBlockWithName(TEXTBLOCKNAME) as IMyTextPanel;
    //IMyGryo gyro = GridTerminalSystem.GetBlockWithName(GYRO) as IMyGyro;
    cockpit = GridTerminalSystem.GetBlockWithName(COCKPIT) as IMyCockpit;
    timerb = GridTerminalSystem.GetBlockWithName(TIMER) as IMyTimerBlock;
    text = "";
 
    getSpd();
 
    if(!getSensorF())
    {
        mode = "Forward";
    }
    if (getSensorF() && speed > 0 && mode !="Down")
    {
        mode = "Stop";
    }
    if (mode != "Forward" && speed == 0)
    {
        mode = "Down";
    }
 
    text += "MODE : " + mode + "\n\n";
 
    if(mode == "Forward")
    {
        getForward();
    }
    if(mode == "Stop")
    {
        getHold();
    }
    if (mode == "Down")
    {
        getDown();
    }

    if (!getLanding())
    {
        ITerminalAction action = timerb.GetActionWithName("Start");
        action.Apply(timerb);
    } else {
        getHold();
        damperOff();
    }
}

void getSpd()
{
    var Time1 = System.DateTime.Now;
    OldTime = CurrentTime;
    CurrentTime = Time1.ToBinary();

    oldx = x;
    oldy = y;
    oldz = z;

    x = Math.Round(f_sensor.GetPosition().GetDim(0),4);
    y = Math.Round(f_sensor.GetPosition().GetDim(1),4);
    z = Math.Round(f_sensor.GetPosition().GetDim(2),4);
 
    double distance = 0;
    distance = Math.Sqrt((x - oldx) * (x - oldx) + (y - oldy) * (y - oldy) + (z - oldz) * (z - oldz));
 
    var Time0 = DateTime.FromBinary(OldTime);
    var TimeDelta = (Time1 - Time0).TotalSeconds;

    speed = 0.0;
    speed = distance / TimeDelta;
 
    text += "Distance : " + distance + "\n";
    text += "Speed : " + speed + "\n";
    text += "TimeDelta : " + TimeDelta + "\n";
}

void damperOn()
{
    if (!cockpit.DampenersOverride)
    {
        ITerminalAction action = cockpit.GetActionWithName("DampenersOverride");
        action.Apply(cockpit);
    }
}

void damperOff()
{
    if (cockpit.DampenersOverride)
    {
        ITerminalAction action = cockpit.GetActionWithName("DampenersOverride");
        action.Apply(cockpit);
    }
}

bool getSensorF()
{
    if (f_sensor.IsActive)
    {
        text += "Sensor F is Active\n";
        return true;
    } else {
        text += "Sensor F is not Active\n";
        return false;
    }
}

void getHold()
{
    thrst_f.SetValueFloat("Override",0);
    thrst_d.SetValueFloat("Override",0);
    damperOn();
}

void getForward()
{
    damperOff();
 
    ITerminalAction action = thrst_f.GetActionWithName("IncreaseOverride");
 
    if (speed == 0)
    {
        action.Apply(thrst_f);
    } else {
        thrst_f.SetValueFloat("Override",0);
    }
}

void getDown()
{
    damperOff();
 
    ITerminalAction action = thrst_d.GetActionWithName("IncreaseOverride");
 
    if (speed == 0)
    {
        action.Apply(thrst_d);
    } else {
        thrst_d.SetValueFloat("Override",0);
    }
}

bool getLanding()
{
    List<IMyTerminalBlock> TL = new List<IMyTerminalBlock>();
    GridTerminalSystem.GetBlocksOfType<IMyLandingGear>(TL);
 
    int prox = 0;
 
    for (int i = 0; i < TL.Count; i++)
    {
        var lgvalue = new StringBuilder();
        TL[i].GetActionWithName("SwitchLock").WriteValue(TL[i], lgvalue);
        if (lgvalue.ToString() == "Locked")
        {
            prox++;
        }
    }
    text += "LandingGear : " + prox.ToString() + "\n";
 
    if (prox >= GEARNUM)
    {
        return true;
    } else {
        return false;
    }
}

2015年3月28日土曜日

Hello SpaceEngineers!

static string TEXTBLOCKNAME = "Text panel";

void Main()
{
    string text ="Hello SpaceEngineers!";

    IMyTextPanel textpanel = GridTerminalSystem.GetBlockWithName(TEXTBLOCKNAME) as IMyTextPanel;
   
    textpanel.WritePublicText(text);
}



何かと値を確認するのに使うテキストパネルの使い方メモ

TEXTBLOCKNAMEにテキストパネルの名前をいれておき、textに表示内容を入れるだけ

数値の場合はi.ToString()とすれば変数iを文字列に変換

改行は\n

デバッグ時に良く使うかな

2015年3月26日木曜日

通路で自動エアロック

標準ブロックでプログラミングブロックを使わずにエアロックっぽいものを作ってみた

用意したのは

ドア2枚
センサー
タイマーブロック




通路の中にセンサーを仕掛けておき、通路内だけが反応するようにFrontを2mであとは1mにする
Actionは反応したとき(左)をTrigger Now、そうでないとき(右)をStart

タイマーブロックは
Delayは1sにしておく
動作はドアを2つともClose

これで通路内に入ると瞬時にセンサーが働いてドアを閉めてくれるため、次のドアを開けても空気が全て漏れ出すことはない
その上、通路から出るとセンサー外となってドアを閉めるため、開けっ放しにもならない

通路内にセンサーを置きたくないなら、天井の上に設置して、距離を調整してもいいかな


2015年3月25日水曜日

バイクが欲しい

近未来風のバイクを作れないかなって

AKIRAとかに出てきそうなアレです

で、プロトタイプを作ったけど


こうなりました
タイヤ幅が1ブロックではなくスペース込みで2ブロック&サスペンションで2ブロックの横幅が最低限必要なため
対称にしたら3m以上必要になってバイクっぽくならない上に重心がずれるとこけます

仕方ないのでタイヤを内向きに4個配置


上から見るとこうなります

車両のキモはArtificial Mass
これに動力通すと重力発生器の重力を受けることができるようになるため、必須ですよね
ただ、重心に気をつけるのと2000kg毎に1つつけないと1G加速は得られないことかな

あとはタイヤが別船体になるため全体のバランス調整が恐ろしく難しい
基本的に飛行時はArtificial Massをオフにすれば無重力になるため、その状態で製作するけど
飛ばすとなると無茶苦茶になります

効果用のコンテナで下ろして走り回るのが現実的かも

あと、コックピットでControl thrustersとControl wheelsを切り替えてあげないと走りながら飛んじゃったりします
Artificial MassとControlをタイマーブロックでまとめて切り替えるのが楽かも



2015年3月21日土曜日

駆逐艦を作ってみる

ラージサイズの船という事で駆逐艦を作ってみた





酸素が実装されたため、これに対応すべく奮闘

下の画像のように左右後部に置いたリアクター付近にジェネレーターを置き
そこから艦橋までコンベヤーチューブを引き、途中で居室等にベントを置いていってます
左右同じつくりにして途中で接続してますので、どちらかのジェネレーターが破損しても大丈夫

まぁ、戦闘艦なのでそこまで気を使う必要は無いかもしれませんが
居室で寝ていたらデブリを喰らって真空状態、なんてのは避けたいですしね~


なんにしても配管はちょっと大変でした
配管って他のブロックにくっついていないので、途中を切っちゃうとそこから先はやりなおし・・・

後で気付きましたが、要所要所にコンベヤーを挟んでおくといいかも

Programming Block

とりあえず基本的なプログラミングブロックで命令を実行するだけのもの
これだけなら、わざわざプログラミングブロックを使わなくていいんですけど、自分のコピペ用

void Main()
{
    IMyTerminalBlock block01;

    ITerminalAction action;

    block01 = GridTerminalSystem.GetBlockWithName("rotor 1");

    action = block01.GetActionWithName("Reverse");

    action.Apply(block01);
}