Last active
December 10, 2015 16:19
-
-
Save kb10uy/4460519 to your computer and use it in GitHub Desktop.
保安装置の動作を再現するクラス立ち。
XNA4.0 + IronPython 2.7.3で作成。
※Trainクラス内のマスコン動作のラムダは実際の動作と全然違います
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#coding: shift-jis | |
#保安装置のスクリプトのサンプル | |
#Automatic Nanimo Shinai system | |
#必須インポート | |
import clr | |
from TrainSystemSimulator.Simulate import * | |
from Microsoft.Xna.Framework import * | |
from Microsoft.Xna.Framework.Content import * | |
from Microsoft.Xna.Framework.Graphics import * | |
from Microsoft.Xna.Framework.Media import * | |
#保安装置を表すクラスです。 | |
#名前はProtectiveDeviceにし、IProtectiveDeviceを実装してください。 | |
class ProtectiveDevice(IProtectiveDevice): | |
#以下はプロパティのためのメソッド。インターフェースには含まれません | |
def setdfnp(self,val): | |
self.notch=val | |
def getdfnp(self): | |
return self.notch | |
def setdfn(self,val): | |
self.fook=val | |
def getdfn(self): | |
return self.fook | |
###########################ここからインターフェース用の実装################ | |
#保安装置インスタンス作成時に呼ばれます | |
def Install(self,tool): | |
self.fook=0 | |
self.notch=MasterControl.N | |
return | |
#保安装置の電源が入った時に呼ばれます | |
def Initialize(self): | |
return | |
#描画時に呼ばれます。 | |
#sb引数はXNAにおけるSpriteBatchです。Begin,Endの必要はありません。 | |
def Draw(self,sb): | |
return | |
#更新時に呼ばれます。 | |
def Update(self): | |
return | |
#保安装置側でノッチを制御している時に、そのノッチを返します。 | |
FookedNotchPosition = property(getdfnp,setdfnp) | |
#保安装置でノッチを制御していれば1,そうでなければ0を返してください。 | |
NotchFooked = property(getdfn,setdfn) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Reflection; | |
using Microsoft.Scripting.Hosting; | |
using IronPython.Hosting; | |
using Microsoft.Xna.Framework; | |
using Microsoft.Xna.Framework.Audio; | |
using Microsoft.Xna.Framework.Content; | |
using Microsoft.Xna.Framework.GamerServices; | |
using Microsoft.Xna.Framework.Graphics; | |
using Microsoft.Xna.Framework.Input; | |
using Microsoft.Xna.Framework.Media; | |
using TrainSystemSimulator.Simulate; | |
namespace TrainSystemSimulator | |
{ | |
/// <summary> | |
/// IronPythonを扱いやすくするためのラッパ | |
/// </summary> | |
public class PythonScript | |
{ | |
ScriptEngine engine = Python.CreateEngine(); | |
ScriptSource src; | |
public ScriptScope Scope { get; set; } | |
public PythonScript() | |
{ | |
engine.Runtime.LoadAssembly(typeof(Game1).Assembly); | |
///XNAのて機能なクラスを使って読み込ませる | |
engine.Runtime.LoadAssembly(typeof(Vector2).Assembly); | |
engine.Runtime.LoadAssembly(typeof(Texture2D).Assembly); | |
Scope = engine.CreateScope(); | |
} | |
public void LoadFromFile(string path) | |
{ | |
src = engine.CreateScriptSourceFromFile(path); | |
src.Execute(Scope); | |
} | |
public void loadFromString(string exp) | |
{ | |
src = engine.CreateScriptSourceFromString(exp); | |
src.Execute(Scope); | |
} | |
/// <summary> | |
/// 現在のスコープ内で式を実行して、 | |
/// その結果を返します。 | |
/// </summary> | |
/// <typeparam name="InsType">返して欲しい型</typeparam> | |
/// <param name="defexp">式</param> | |
/// <returns>実行した式の返り値</returns> | |
public InsType GetInstance<InsType>(string defexp) | |
{ | |
return engine.Execute<InsType>(defexp, Scope); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.IO; | |
using Microsoft.Xna.Framework; | |
using Microsoft.Xna.Framework.Audio; | |
using Microsoft.Xna.Framework.Content; | |
using Microsoft.Xna.Framework.GamerServices; | |
using Microsoft.Xna.Framework.Graphics; | |
using Microsoft.Xna.Framework.Input; | |
using Microsoft.Xna.Framework.Media; | |
using TrainSystemSimulator; | |
namespace TrainSystemSimulator.Simulate | |
{ | |
/// <summary> | |
/// 列車が地上子を通過した時に発生するイベントのデリゲート型。 | |
/// </summary> | |
public delegate void BeaconEventHandler(); | |
public delegate void RailwayLoadImageEventHandler(string name); | |
/// <summary> | |
/// マスコンの状態。 | |
/// </summary> | |
public enum MasterControl | |
{ | |
EB = 0, | |
B8, | |
B7, | |
B6, | |
B5, | |
B4, | |
B3, | |
B2, | |
B1, | |
BF, | |
N, | |
P1, | |
P2, | |
P3, | |
P4, | |
P5, | |
} | |
/// <summary> | |
/// 保安装置スクリプトで実装する必要のあるインターフェース。 | |
/// </summary> | |
public interface IProtectiveDevice | |
{ | |
/// <summary> | |
/// 保安装置に関する情報をウンタラカンタラ | |
/// </summary> | |
void Install(PDTool tool); | |
/// <summary> | |
/// 保安装置の電源が入った時。 | |
/// </summary> | |
void Initialize(); | |
/// <summary> | |
/// 描画時。 | |
/// </summary> | |
/// <param name="sb">SpriteBatch</param> | |
void Draw(SpriteBatch sb); | |
/// <summary> | |
/// 更新。 | |
/// </summary> | |
void Update(); //Trainクラスの何かを送る | |
//BeaconEventHandle | |
/// <summary> | |
/// 地上子通り過ぎちまった時 | |
/// </summary> | |
/// <param name="e">e</param> | |
void BeaconPassed(BeaconEventArgs e); | |
/// <summary> | |
/// 保安装置側でノッチを制御している時のノッチ | |
/// </summary> | |
MasterControl FookedNotchPosition { get; } | |
/// <summary> | |
/// 保安装置側でノッチをフックしているか。 | |
/// </summary> | |
int NotchFooked { get; } | |
} | |
/// <summary> | |
/// 保安装置が準備に必要なものを集めます。 | |
/// </summary> | |
public class PDTool | |
{ | |
public GraphicsDevice Device { get; private set; } | |
public Railway RunningRailway { get; private set; } | |
public PDTool(GraphicsDevice d,Railway r) | |
{ | |
Device = d; | |
RunningRailway = r; | |
} | |
public Texture2D LoadImage(string file) | |
{ | |
using (Stream i = File.OpenRead(file)) | |
{ | |
return Texture2D.FromStream(Device, i); | |
} | |
} | |
public void RegistSignalLinkBeacon(int pos, string type) | |
{ | |
RunningRailway.RegistSignalLinkBeacon(type, pos); | |
} | |
} | |
/// <summary> | |
/// そのまま | |
/// </summary> | |
public class BeaconEventArgs : EventArgs | |
{ | |
/// <summary> | |
/// 空っぽで初期化 | |
/// </summary> | |
public BeaconEventArgs() | |
: base() | |
{ | |
PassedBeacon = new Beacon(); | |
} | |
/// <summary> | |
/// 地上子指定で初期化 | |
/// </summary> | |
/// <param name="b">地上子</param> | |
public BeaconEventArgs(Beacon b) | |
{ | |
PassedBeacon = b; | |
} | |
/// <summary> | |
/// 通り過ぎちまった地上子。 | |
/// </summary> | |
public Beacon PassedBeacon { get; private set; } | |
} | |
/// <summary> | |
/// 地上子 | |
/// </summary> | |
public class Beacon | |
{ | |
/// <summary> | |
/// 位置 | |
/// </summary> | |
public int Position { get; set; } | |
/// <summary> | |
/// 種類 | |
/// </summary> | |
public string Type { get; set; } | |
/// <summary> | |
/// 連動している信号 | |
/// </summary> | |
public ExternalSignal LinkedSingal { get; set; } | |
/// <summary> | |
/// 地上子としてのプライドをたもちます。 | |
/// </summary> | |
/// <param name="tp">現在の列車位置</param> | |
/// <param name="ptp">前回の列車位置</param> | |
/// <param name="train">列車</param> | |
public void Update(List<double> tp, List<double> ptp, List<Train> train) | |
{ | |
for (int i = 0; i < tp.Count; i++) | |
{ | |
if (ptp[i] <= Position && tp[i] > Position) | |
{ | |
train[i].ProtectiveDevice.BeaconPassed(new BeaconEventArgs(this)); | |
} | |
} | |
} | |
} | |
/// <summary> | |
/// 列車を模した | |
/// </summary> | |
public class Train | |
{ | |
///<summary>速度</summary> | |
public double Speed { get; protected set; } | |
///<summary>マスコン位置</summary> | |
public MasterControl Control { get; protected set; } | |
///<summary>保安装置</summary> | |
public IProtectiveDevice ProtectiveDevice { get; protected set; } | |
///<summary>保安装置とかのスクリプト</summary> | |
public PythonScript Script { get; protected set; } | |
/// <summary> | |
/// 加速度の対応表 | |
/// </summary> | |
public Dictionary<MasterControl, Func<double, double>> MasterControlLink { get; protected set; } | |
public double FrameRate { get; protected set; } | |
/// <summary> | |
/// 制御に使うスクリプトを指定して初期化。 | |
/// </summary> | |
/// <param name="script">スクリプト</param> | |
public Train(PythonScript script,PDTool tool) | |
{ | |
Speed = 0.0; | |
FrameRate = 60; | |
Control = MasterControl.N; | |
Script = script; | |
MasterControlLink = new Dictionary<MasterControl, Func<double, double>>(); | |
//マスコン対応表 | |
MasterControlLink[MasterControl.EB] = (s) => s - (4.0 / FrameRate); | |
MasterControlLink[MasterControl.B8] = (s) => s - (3.0 / FrameRate); | |
MasterControlLink[MasterControl.B7] = (s) => s - (2.8 / FrameRate); | |
MasterControlLink[MasterControl.B6] = (s) => s - (2.4 / FrameRate); | |
MasterControlLink[MasterControl.B5] = (s) => s - (2.0 / FrameRate); | |
MasterControlLink[MasterControl.B4] = (s) => s - (1.8 / FrameRate); | |
MasterControlLink[MasterControl.B3] = (s) => s - (1.2 / FrameRate); | |
MasterControlLink[MasterControl.B2] = (s) => s - (0.8 / FrameRate); | |
MasterControlLink[MasterControl.B1] = (s) => s - (0.4 / FrameRate); | |
MasterControlLink[MasterControl.BF] = (s) => s; | |
MasterControlLink[MasterControl.N] = (s) => s - (s * 0.001 / FrameRate); | |
MasterControlLink[MasterControl.P1] = (s) => s + (0.7 / FrameRate); | |
MasterControlLink[MasterControl.P2] = (s) => s + (1.5 / FrameRate); | |
MasterControlLink[MasterControl.P3] = (s) => s + (2.0 / FrameRate); | |
MasterControlLink[MasterControl.P4] = (s) => s + (2.6 / FrameRate); | |
MasterControlLink[MasterControl.P5] = (s) => s + (3.3 / FrameRate); | |
ProtectiveDevice = Script.GetInstance<IProtectiveDevice>("ProtectiveDevice()"); | |
ProtectiveDevice.Install(tool); | |
ProtectiveDevice.Initialize(); | |
} | |
/// <summary> | |
/// 描画します。別にUpdateだけでもおk | |
/// </summary> | |
/// <param name="sb">SpriteBatch</param> | |
public void Draw(SpriteBatch sb) | |
{ | |
ProtectiveDevice.Draw(sb); | |
} | |
/// <summary> | |
/// 更新します。毎フレーム必ず呼び出してね。 | |
/// </summary> | |
public void Update() | |
{ | |
ProtectiveDevice.Update(); | |
//速度更新 | |
if (ProtectiveDevice.NotchFooked==1) | |
{ | |
Speed = Math.Max(MasterControlLink[ProtectiveDevice.FookedNotchPosition](Speed),0); | |
} | |
else | |
{ | |
Speed = Math.Max(MasterControlLink[Control](Speed),0); | |
} | |
} | |
/// <summary> | |
/// マスコン状態を設定します。 | |
/// </summary> | |
/// <param name="mc"></param> | |
public void SetNotch(MasterControl mc) | |
{ | |
Control = mc; | |
} | |
} | |
/// <summary> | |
/// 信号の現示 | |
/// </summary> | |
public enum SignalKind | |
{ | |
/// <summary> | |
/// 0km/h | |
/// </summary> | |
R, | |
/// <summary> | |
/// 25km/h | |
/// </summary> | |
YY, | |
/// <summary> | |
/// 45km/h | |
/// </summary> | |
Y, | |
/// <summary> | |
/// 70km/h | |
/// </summary> | |
YG, | |
/// <summary> | |
/// 105km/h | |
/// </summary> | |
YGF, | |
/// <summary> | |
/// 130km/h | |
/// </summary> | |
G, | |
/// <summary> | |
/// 160km/h | |
/// </summary> | |
GG | |
} | |
/// <summary> | |
/// 信号(まあ正確には車外なのでExternal) | |
/// </summary> | |
public class ExternalSignal | |
{ | |
public SignalKind Kind { get; set; } | |
public ExternalSignal() | |
{ | |
Kind = SignalKind.R; | |
} | |
} | |
public class Railway | |
{ | |
/// <summary> | |
/// 列車位置。 | |
/// </summary> | |
public List<double> TrainPosition { get; private set; } | |
/// <summary> | |
/// 前フレーム列車位置。 | |
/// </summary> | |
public List<double> PreviousTrainPosition { get; set; } | |
/// <summary> | |
/// 列車。 | |
/// </summary> | |
public List<Train> Trains { get; private set; } | |
/// <summary> | |
/// 地上子。 | |
/// </summary> | |
public Dictionary<int, List<Beacon>> Beacons { get; private set; } | |
/// <summary> | |
/// 信号。 | |
/// </summary> | |
public Dictionary<int, ExternalSignal> Signals { get; private set; } | |
/// <summary> | |
/// 信号に連動した地上子。 | |
/// </summary> | |
public Dictionary<int, string> SignalLinkBeacons { get; private set; } | |
/// <summary> | |
/// フレームレート | |
/// </summary> | |
public double FrameRate { get; set; } | |
public event RailwayLoadImageEventHandler LoadImage; | |
/// <summary> | |
/// とりあえず初期化。 | |
/// </summary> | |
public Railway() | |
{ | |
TrainPosition = new List<double>(); | |
PreviousTrainPosition = new List<double>(); | |
Trains = new List<Train>(); | |
Beacons = new Dictionary<int, List<Beacon>>(); | |
Signals = new Dictionary<int, ExternalSignal>(); | |
SignalLinkBeacons = new Dictionary<int, string>(); | |
FrameRate = 60.0; | |
} | |
/// <summary> | |
/// 列車を設置します。 | |
/// </summary> | |
/// <param name="train">列車</param> | |
/// <param name="pos">位置</param> | |
public int PutTrain(Train train, double pos = 0) | |
{ | |
Trains.Add(train); | |
TrainPosition.Add(pos); | |
PreviousTrainPosition.Add(0); | |
return Trains.Count - 1; | |
} | |
/// <summary> | |
/// 信号を(ry | |
/// </summary> | |
/// <param name="sig"></param> | |
/// <param name="pos"></param> | |
public void RegistSignal(ExternalSignal sig, int pos) | |
{ | |
Signals[pos] = sig; | |
foreach (var bs in SignalLinkBeacons) | |
{ | |
RegistBeacon(bs.Value, bs.Key); | |
} | |
} | |
/// <summary> | |
/// 信号連動地上子、登録。 | |
/// </summary> | |
/// <param name="type"></param> | |
/// <param name="pos"></param> | |
public void RegistSignalLinkBeacon(string type, int pos) | |
{ | |
SignalLinkBeacons[pos] = type; | |
} | |
/// <summary> | |
/// 地上子、設置。 | |
/// </summary> | |
/// <param name="type"></param> | |
/// <param name="pos"></param> | |
public void RegistBeacon(string type, int pos) | |
{ | |
if (Beacons[pos] != null) | |
{ | |
//モウすでにそこに1個以上あった場合 | |
Beacons[pos].Add(new Beacon { Type = type, LinkedSingal = null, Position = pos }); | |
} | |
else | |
{ | |
//まだそこに何もなかった | |
Beacons[pos] = new List<Beacon>(); | |
Beacons[pos].Add(new Beacon { Type = type, LinkedSingal = null, Position = pos }); | |
} | |
} | |
/// <summary> | |
/// 指定位置が属する閉塞の信号を取得します。 | |
/// </summary> | |
/// <param name="pos">位置(m)</param> | |
/// <returns>信号の現示</returns> | |
public SignalKind GetThereSectionSignal(int pos) | |
{ | |
return Signals | |
.Where(p => p.Key < pos) | |
.OrderBy(p => p.Key) | |
.Last() | |
.Value.Kind; | |
} | |
/// <summary> | |
/// 指定位置が属する閉塞の次の閉塞の信号を取得します。 | |
/// </summary> | |
/// <param name="pos">位置(m)</param> | |
/// <returns>信号の現示</returns> | |
public SignalKind GetNextSectionSignal(int pos) | |
{ | |
return Signals | |
.Where(p => p.Key >= pos) | |
.OrderBy(p => p.Key) | |
.First() | |
.Value.Kind; | |
} | |
/// <summary> | |
/// 更新。 | |
/// </summary> | |
public void Update() | |
{ | |
//地上子更新 | |
foreach (var bs in Beacons) | |
{ | |
foreach (Beacon b in bs.Value) | |
{ | |
b.Update(TrainPosition, PreviousTrainPosition, Trains); | |
} | |
} | |
//あとは | |
/* | |
* 列車をすすめることとか色々 | |
*/ | |
for (int i = 0; i < Trains.Count; i++) | |
{ | |
Trains[i].Update(); | |
TrainPosition[i] += Trains[i].Speed / 3.6 / FrameRate; | |
} | |
//信号状況更新 | |
var sig = Signals.OrderBy((p) => p.Key).ToArray(); | |
for (int i = 0; i < sig.Count(); i++) | |
{ | |
foreach (double p in TrainPosition) | |
{ | |
if (p >= sig[i].Key && i + 1 <= sig.Count() - 1 && p <= sig[i + 1].Key) | |
{ | |
//その信号が指す閉塞内に列車が存在したら | |
Signals[sig[i].Key].Kind = SignalKind.R; | |
if (i - 1 >= 0) Signals[sig[i - 1].Key].Kind = SignalKind.YY; | |
if (i - 2 >= 0) Signals[sig[i - 2].Key].Kind = SignalKind.Y; | |
if (i - 3 >= 0) Signals[sig[i - 3].Key].Kind = SignalKind.YG; | |
if (i - 4 >= 0) Signals[sig[i - 4].Key].Kind = SignalKind.YGF; | |
if (i - 5 >= 0) Signals[sig[i - 5].Key].Kind = SignalKind.G; | |
if (i - 6 >= 0) Signals[sig[i - 6].Key].Kind = SignalKind.GG; | |
} | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment