TL; DR
Buy Kerbal Space Program now (available on Steam)
Download ckan.exe and execute
Install any of kRPC: Remote Procedure Call Server / kOS: Scriptable Autopilot System / MechJeb
gl hf!
Kerbal Space Program (KSP) とは
Kerbal Space Program 1.3: Away with Words - 予告編 https://t.co/sSGnQTSXzV
— haeena (@haeena) December 11, 2017
自分だけの宇宙開発プログラム立ち上げよう!
謎の緑の宇宙人1とミニチュアの太陽系2にリアルな物理シミュレーション3 を載せて!
KSPとは一言でいうとそんなゲームです。
このゲームの面白いところは、物理シミュレーションが容赦なくあなたの打ち上げるロケットを襲うあたりにあり、当初はロケットを惑星の周回軌道に乗ることすら難しいのですが、一度わかってしまえば月旅行や宇宙ステーション建造、外惑星への探査旅行すら可能4という自由度にあります。
開発元はメキシコに拠点を置くSquadという会社ですが、先日リリースされた v1.3 にて日本語対応を果たし、横文字の苦手なお年寄りから小さいお子様まで実際安心になりました。
Vanilla も大変プレイアブルなのですが、KSPは皆さんの大好きな mod の開発も大変盛んで、UI変更・空力シミュレーションモデルの変更・パーツ追加・宇宙基地・変形・合体・ワープです!、と各種取りそろえられておりますが、中でも今回は プログラムを書くことで宇宙船を操縦する5 modを導入して、KSPのシミュレータを遊び倒す方法をご紹介したいと思います。
未購入の方は、とりあえず買ってから考えましょう。
なぁに、最悪でも積んでるゲームが一つ増えるだけですって
-> Buy Kerbal Space Program now (available on Steam)
ckan の導入 / mod の install
ckan は 有志によってメンテされている、KSPのmodマネージャです。
KSPのmod配布は CurseForge / Spacedock / KSP Forum / mod作者のgithub 等の複数サイトで行われており6、希望のmodを一通りそろえて、定期的に最新のmodに更新していくのは一苦労です。
KSP本体も比較的ちょいちょいバージョンが上がっており、古いmodは容赦なく動かなくなる傾向にあります。
ckan は各種modの配布URLや依存関係などのメタデータをメンテナンス・配布することで、それらmodの導入・更新を飛躍的に容易にしてくれるすばらしいツールです。
ckan は .NET Framework 上にC#で書かれていますが、Monoでも動く7とのこと。
ckan を起動すると上記のようなGUIからmodの一覧を選択できます。
KSPがinstall済みならKSPのパスは自動で検知してくれるはずですが、環境によっては手動で設定するようdialogが出るかもしれません。
虫眼鏡のアイコンを Filter(Compatible)
に設定すると、現在installされているKSPのバージョンと互換なmodのみがリスト表示されます。リストの中から導入したいmodのcheckboxにcheckを入れ、Apply Changes
ボタンで download & install です。
どんなmodがあるのか一覧を眺めて、名前の気に入ったmodのHomepageに飛ぶだけでも楽しいものです。
人気のあるmodであれば、HomepageからYouTubeの紹介動画なんかも見られるかもしれませんね。
さて、プログラマブルなmodの紹介に移ります。
MechJeb
Source Code (github) / [Document] (http://wiki.mechjeb.com/index.php?title=Manual) / Forum
難易度: かんたん / 言語: Visual Programming / Editor: GUI
こいつは使い方は簡単です。Easy modeです。
一つだけ注意することがあるとすれば、VAB/SPH(宇宙船組み立て画面)でCommand and Control
カテゴリからMechJebのパーツを選んで、宇宙船にくっつけてあげる必要があります。
MechJebのついているロケットを打ち上げようとすると、Lunchpad(打ち上げ画面)にMechJebのメニューが表示されますので、その中の Scripting Module (Beta)
を選んであげると、スクリプトエディタが現れます。
あとはちょいちょいとAdd Action
で動作を指定してあげて、START
を押したら打ち上げるだけです。
画像が見にくいですが、今回は下記を指定しています。
Kerbalから打ち上げて、Munの高度200kmの周回軌道に入ってくれるはずです。
ASCENT GUIDANCE (100km)
Target Celestial Body: Mun
Hohmann Transfer to Target: Schedule the burn in next transfer window
Execute next node
Fine tune closest approach to target: 200,000m
Warp to: SOI transition Lead time: 0s
Execute next node
Change Apoapsis: New apoapsis: 200km schedule the burn at the next peripsis
Execute next node
それだけです。
打ち上げ中の角度調整やステージ切り離し、トランスファウィンドウの計算はすべてMechJebがやってくれます。
ね、簡単でしょう?8
kOS
Source Code (github) / Document / Forum
難易度: ほどほど / 言語: kerboscript (独自) / Editor: In Game (or telnet)
このmodもVAB/SPHで宇宙船にパーツをつけてあげる必要があります。
Command and Control
カテゴリの中、 KOSProcessor
という属性のあるパーツです。
KOSProcessorを宇宙船に取り付けることができたら、Lunchpadに移ります。
MenuBar(画面右端)にkOS
のiconがありますので、それをクリックしてkOSのメニューを開きましょう。
ターミナルのアイコンを押すとGame内のターミナルが開くので、そこにコマンドを打ち込んで行くこともできますが、今回はTELNET
ボタンを押して手元のtelnet teminalから下記のExampleスクリプトを流し込んでみました。
print "Launching".
lock steering to heading(90,80).
lock throttle to 1.
stage.
wait until altitude > 5000.
lock steering to heading(90,60).
wait until altitude > 15000.
lock steering to heading(90,45).
wait until altitude > 25000.
lock steering to heading(90,30).
until apoapsis > 80000 {
print "apoapsis is " + round(apoapsis,0).
wait 0.
}
lock throttle to 0.
どうやらスクリプトが流し込まれた時点で動作が始まってしまったようです。
ざっと中身を読む限り、スロットル全開で打ち上げ、高度が上がる毎に方位を水平に倒して、遠地点高度が80kmに達した時点でエンジンカットオフしてくれるようですね。
ふむ。遠地点付近で再度エンジンを噴射してあげなければ、そのまま地面に真っ逆さまのはずですが、このスクリプトの例では、どうやらその部分は省略されているようですね。なるほど9
kRPC
Source Code (github) / Document / Forum
難易度: そこそこ / 言語: C#, C++, Java, Lua, Python, Ruby, Haskell / Editor: お好みのもの
こいつにはVAB/SPHでのパーツ追加は不要です。
Lunchpadに移ったら、networkっぽいiconをクリックします。中央に水平に伸びた線から上に四角が2つ、下に四角1つ生えてるやつです。
kRPCのMenuが出てくるので、Start Server
を押してあげると、Game側でRPC serverが立ち上がります。
あとは、お好きな言語、お好きな環境でRPC clientを上げて、ゲームに接続してあげましょう。
localhost以外から接続を受け入れたいなら、add server
からAddressをAny
にしたserverを追加してあげましょう。
Clientはいくつかの言語に対応していますが、Pythonであれば
# pip install kRPC
から
import krpc
conn = krpc.connect(name='Hello World')
vessel = conn.space_center.active_vessel
print(vessel.name)
で、 機体の名前が表示されるはずです。
ClientからServerへの接続時、Server側で「なんかRPCで繋ぎに来た子がいるけど相手していいの?」みたいなdialogが出るので、OKしてあげてください。いちいちServer側を触るのがうるさいときは、Advanced Options
のAuto-start server
とAuto-accept new clients
をcheckすると煩わしさが減ります。
さて、kRPCはうれしいことに、機体を制御しようと思うとたくさんのコードを書けます。
ほぼdocumentの example ですが、高度90kmの周回軌道に乗せようと思うと、下記ぐらいの分量になります。
import math
import time
import krpc
TURN_START_ALTITUDE = 250
TURN_END_ALTITUDE = 45000
TARGET_ALTITUDE = 90000
ASCENT_HEADING = 0
def main():
conn = krpc.connect(name='Launch into orbit')
vessel = conn.space_center.active_vessel
obt_frame = vessel.orbit.body.non_rotating_reference_frame
# Set up streams for telemetry
ut = conn.add_stream(getattr, conn.space_center, 'ut')
altitude = conn.add_stream(getattr, vessel.flight(), 'mean_altitude')
apoapsis = conn.add_stream(getattr, vessel.orbit, 'apoapsis_altitude')
time_to_apoapsis = conn.add_stream(getattr, vessel.orbit, 'time_to_apoapsis')
stage_2_resources = vessel.resources_in_decouple_stage(stage=2, cumulative=False)
srb_fuel = conn.add_stream(stage_2_resources.amount, 'SolidFuel')
# Pre-launch setup
vessel.control.sas = True
vessel.control.rcs = False
vessel.control.throttle = 1.0
# Countdown...
print("3...")
time.sleep(1)
print("2...")
time.sleep(1)
print("1...")
time.sleep(1)
print("Launch!")
# Activate the first stage
vessel.control.activate_next_stage()
vessel.auto_pilot.engage()
vessel.auto_pilot.target_pitch_and_heading(90, ASCENT_HEADING)
# Main ascent loop
srbs_separated = False
apoapsis_near = False
apoapsis_reached = False
turn_angle = 0
while True:
# Gravity turn
if altitude() > TURN_START_ALTITUDE and altitude() < TURN_END_ALTITUDE:
print("Gravity turn")
frac = ((altitude() - TURN_START_ALTITUDE) /
(TURN_END_ALTITUDE - TURN_START_ALTITUDE))
new_turn_angle = frac * 90
if abs(new_turn_angle - turn_angle) > 0.5:
turn_angle = new_turn_angle
vessel.auto_pilot.target_pitch_and_heading(90-turn_angle, ASCENT_HEADING)
# Separate SRBs when finished
if not srbs_separated:
if srb_fuel() < 0.1:
srbs_separated = True
print("SRB separation")
vessel.control.activate_next_stage()
# Decrease throttle when approaching target apoapsis
if not apoapsis_reached:
if apoapsis_near and apoapsis() < TARGET_ALTITUDE:
apoapsis_reached = True
print("Target apoapsis reached")
vessel.control.throttle = 0.0
elif apoapsis() > TARGET_ALTITUDE*0.9:
apoapsis_near = True
print("Approaching target apoapsis")
vessel.control.throttle = 0.25
if srbs_separated and apoapsis_reached:
break
# Wait until out of atmosphere
print("Coasting out of atmosphere")
while altitude() < 70500:
pass
# Plan circularization burn (using vis-viva equation)
print("Planning circularization burn")
mu = vessel.orbit.body.gravitational_parameter
r = vessel.orbit.apoapsis
a1 = vessel.orbit.semi_major_axis
a2 = r
v1 = math.sqrt(mu*((2./r)-(1./a1)))
v2 = math.sqrt(mu*((2./r)-(1./a2)))
delta_v = v2 - v1
node = vessel.control.add_node(
ut() + vessel.orbit.time_to_apoapsis, prograde=delta_v)
# Calculate burn time (using rocket equation)
F = vessel.available_thrust
Isp = vessel.specific_impulse * 9.82
m0 = vessel.mass
m1 = m0 / math.exp(delta_v/Isp)
flow_rate = F / Isp
burn_time = (m0 - m1) / flow_rate
# Orientate ship
print("Orientating ship for circularization burn")
vessel.auto_pilot.reference_frame = obt_frame
vessel.auto_pilot.target_direction = node.direction(obt_frame)
vessel.auto_pilot.wait()
# Wait until burn
print("Waiting until circularization burn")
burn_ut = ut() + vessel.orbit.time_to_apoapsis - (burn_time/2.0)
lead_time = 5
conn.space_center.warp_to(burn_ut - lead_time)
# Execute burn
print("Ready to execute burn")
while time_to_apoapsis() - (burn_time/2.0) > 0:
pass
print("Executing burn")
vessel.control.throttle = 1.0
time.sleep(burn_time - 0.1)
print("Fine tuning")
vessel.control.throttle = 0.05
remaining_delta_v = conn.add_stream(getattr, node, "remaining_delta_v")
min_delta_v = remaining_delta_v()
point_passed = False
while remaining_delta_v() > 0.1 and not point_passed:
if min_delta_v < remaining_delta_v():
point_passed = True
else:
min_delta_v = remaining_delta_v()
vessel.control.throttle = 0.0
node.remove()
print("Launch complete")
if __name__ == "__main__":
main()
たのしくなってきましたね!
おわりに
みんなももっとKSPすればいいとおもうよ!
-
Kerbolシステム。ちっちゃい ↩
-
Unityが許す限りにおいて ↩
-
あなたの作るロケットが十分効率的で、Delta-V が許せば ↩
-
VanillaではMouse+KeyboardないしGamePadで宇宙船を操縦することになります ↩
-
リリース当初は開発元のSquadがmod配布をホスティングしていましたが、2014年頃にCurseForgeへ移行…したのですが、ぶっちゃけCurseForgeが使いにくいので流行ってない ↩
-
試したことはない。ゲーム機はWindowsに限る。GPU積んでないマシンは帰ってくれないか ↩
-
この後、宇宙船は無事にMunの地表に激突し、3名のkerbalは病院送りとなりました。近点距離を調整するノードを設定したあとに、実行する指示を忘れていたのが敗因と思われます。宇宙開発の進歩に犠牲はつきものだ ↩
-
またkerbalが病院送りに。再突入は大分熱そうであった ↩