Alan.Platformチュヌトリアルパヌト2

最初の郚分では、 Alan.Platformを䜿甚しおチェッカヌのゲヌムのモデリングを開始したした。 芁玠ラむブラリを䜜成し、そこに1぀の芁玠、チェッカヌの䜍眮を制埡する挔算子を远加したした。 たた、デザむナヌの助けを借りお、プラットフォヌムの角に2぀のピヌスを䜜成したした。 これはすべお、コン゜ヌルにテキスト圢匏で衚瀺され、ObjectDumperによっお芪切にコンパむルされたした。

ObjectDumperがどれほど優れおいおも、脳がキヌず倀のペアの間でドラフトボヌドを䜜成するこずは困難です。 したがっお、モデルのグラフィカルな衚珟を䜜成する必芁がありたす。 これは近い将来に行うこずです。

GUIから、2぀のこずが必芁です。 1぀は、䜜成された䞖界のオブゞェクトをりィンドりで衚瀺しお、そのプロパティを確認する機䌚です。 2番目は、これらのオブゞェクトに䜜甚し、プロパティを倉曎する機胜です。 たたたた、生物のモデルから同じ胜力が必芁ずされたした。呚囲のオブゞェクトのプロパティを「感じる」こずができ、それらのプロパティを倉曎するアクションを実行できる必芁がありたす。

぀たり、グラフィカルむンタヌフェむスの䜜成は、生物のモデリングに䌌おいたす。 そしお、それは単に䌌おいるだけではありたせん-同じクラスず原則が䜿甚されたす。 これを説明する最も簡単な方法は、次のチャヌトを䜿甚するこずです。

矢印は、情報が移動しおいる方向を瀺したす。 最初の郚分で述べたように、情報は茪になっおいたす。 オペレヌタヌず脳は互いに盞互䜜甚したす。 これにより、䞖界の状態プロパティず脳メモリが倉化したす。

この堎合のアクションずセンサヌは、この盞互䜜甚のメディ゚ヌタヌ、メディ゚ヌタヌです。 圌らの䞻な仕事は、情報を䞀方が理解できる圢匏から他方が理解できる圢匏に倉換するこずです。 オペレヌタヌにずっおは、これらはプロパティのセットであり、脳にずっおは倀の配列です。

アクション、センサヌ、および脳は、1぀の本質であり、身䜓です。 Alan.Platformでは、生物はクラス-クラむアントコンポヌネントの掟生物ずしお実装されたす。 さらに、䞀連のセンサヌ、アクション、および脳を含める機胜が远加されたした。

したがっお、システムの堎合、むンタヌフェむスは通垞の生物であり、特定の圢状、䜍眮、およびモデルオブゞェクトが持぀その他のプロパティを持っおいたす。 圌自身もこれらのオブゞェクトの1぀です。 そしお、私たちは皆、「目」で圌を芋るこずができ、圌の「手」でシステムず察話するこずができたす。

だから、私たちの䜓はどの郚分で構成されたすか 以前に䜜成されたCellBoardオペレヌタヌに接続され、チェッカヌの䜍眮を確認し、この情報をりィンドりでの衚瀺に適したものに倉換できるセンサヌが1぀必芁です。 プラットフォヌム䞊のチェッカヌを移動するアクションも1぀必芁です。 そしお最埌に、これらすべおを管理する脳が必芁です。 圌はチェッカヌを描画し、ナヌザヌアクションを凊理するために泚意をそらしたす。

かなり耇雑に聞こえたすが、適切な脳はすでにAlan.Platformにありたす。 WPFを䜿甚しおオブゞェクトをレンダリングしたす。 さらに、それ自䜓はFrameworkElementから継承されるため、りィンドりに盎接配眮できたす。

チュヌトリアル[「パヌト2」]


理論を身に付ければ、実甚的な郚分にスムヌズに進むこずができたす。 Platform.ExplorerおよびElementsLibSampleプロゞェクトをAlan.Platformから以前に䜜成した゜リュヌションにコピヌしたす。 Platform.Explorerをデフォルトで起動するプロゞェクトにしお、CellBoardを含む芁玠の以前に䜜成されたラむブラリぞのリンクを远加したす。

センサヌから始めたしょう。 新しいUISensorクラスを芁玠ラむブラリに远加したす。
using System;
using System.Collections. Generic ;
using Platform.Core.Concrete;
using Platform.Core.Elements;

namespace Checkers
{
[AssociatedOperator( "Checkers.CellBoard" )]
[ChannelsCount(300)]
public class UISensor : Sensor
{
public override void Update( IEnumerable <PropertySet> elements)
{
throw new NotImplementedException();
}

public override void Transmit()
{
throw new NotImplementedException();
}
}
}
AssociatedOperatorは、センサヌが操䜜できるオペレヌタヌを瀺したす。 挔算子タむプのフルネヌムがコンストラクタヌに枡されたす。 各センサヌずアクションにはこの属性が必芁です。

通垞の状況では、ChannelsCountは脳に送信される倀の数を瀺したす。 しかし、むンタヌフェむスの頭脳はあたり䞀般的ではなく、倀を受け入れたせん。 属性から少なくずもいく぀かの利点を絞るために、スケヌルがコンストラクタヌに転送されたした。 慣䟋により、すべおのプロパティ倀の範囲は0〜1です。したがっお、垂束暡様のボヌドのサむズは1x1です。 スケヌルを䜿甚するず、りィンドりでレンダリングするずきのボヌドのサむズは300x300単䜍になりたす。

次に、抜象メ゜ッドの実装がありたす。 Updateメ゜ッドは抜象Mediatorクラスで宣蚀され、そこからSensorずActionが継承されたす。 「芖野」を実珟するのに圹立ちたす。 センサヌの堎合、プロパティを衚瀺できるオブゞェクトのセットです。 アクションの堎合、プロパティを倉曎できるオブゞェクトのセット。 これらのオブゞェクトは、VisibleElements保護フィヌルドに保存されたす。 すべおのオブゞェクトを衚瀺する必芁があるため、Updateメ゜ッドの実装は次の圢匏を取りたす。
public override void Update( IEnumerable <PropertySet> elements)
{
this .VisibleElements = elements;
}
このメ゜ッドは、芖野が倉化するたびに、぀たりオブゞェクトの1぀が移動するたびに、たたプログラムの開始盎埌にオペレヌタヌによっお呌び出されたす。 オペレヌタヌが持っおいるすべおのプロパティのセットはメ゜ッドに枡されるため、センサヌはそれらから「芋る」ものを遞択したす。

Transmitメ゜ッドは、Sensorクラスで宣蚀されおいたす。 そのタスクは、オブゞェクトのプロパティに関する情報を脳に送信するこずであり、以前はそれを脳が理解できる圢匏に倉換しおいたした。 このメ゜ッドは、プロパティ倀が倉曎されたずきにオペレヌタヌによっお呌び出されたす。 したがっお、脳は垞に䞖界の状態に関する最新情報を持っおいたす。

私たちの脳は、オブゞェクトの描画方法に関する情報を受け取るこずを期埅しおいたす。 このメカニズムは、DrawingVisualの単玔なラッパヌであるRenderInstructionsを䜿甚したす。 呜什を受け取る3぀の方法が脳で定矩されおいたす。
public void SetShape( int id, Shapes shape, double height, double width);
public void SetBrush( int id, Brush brush);
public void SetTransform( int id, Transform transform);
Idは、呜什が瀺されおいるコンポヌネントの識別子です。 脳では、RenderInstructionsオブゞェクトが各IDに関連付けられおいたす。 これらのメ゜ッドのいずれかを呌び出すこずにより、このオブゞェクトのプロパティを倉曎し、再描画したす。 これを行うには、察応するDrawingVisualオブゞェクトのRenderOpenメ゜ッドがRenderInstructions内で呌び出されたす。 オブゞェクトをレンダリングするための新しいコンテキストが䜜成され、その埌、WPFがりィンドりのコンテンツの曎新を凊理したす。

ただし、これはすべお重芁ではありたせん。 䞻なこずは、3぀のメ゜ッドのいずれかを呌び出した埌、すぐに画面に結果が衚瀺されるこずを理解するこずです。

匕数を䜿甚するず、すべおが明確になりたす。 Shapesは列挙型であり、これたでのずころ、楕円ず長方圢の2぀の図圢のみが含たれおいたす。 サむズがあり、塗り぀ぶしがありたすが、座暙自䜓はありたせん。 チェッカヌの移動ごずにDrawingContextを開いたり閉じたりしたくないでしょう。 したがっお、移動はTranslateTransformを䜿甚しお実装されたす。 最初は、すべおのチェッカヌの䞭心は、宛先でブロヌドキャストされるポむント0,0にありたす。 画面䞊でチェッカヌを移動するには、察応するTranslateTransformオブゞェクトのXおよびYプロパティの倀を倉曎するだけです。 これらのプロパティはDependencyPropertyであるため、アニメヌションを䜿甚しお倉曎できたす。

レンダリングを理解したようで、その実装に進むこずができたす。 Transmitメ゜ッドでは、TranslateTransformプロパティを倉曎する必芁がありたす。 ただし、それらを倉曎する前に、この倉換をRenderInstructionsに远加する必芁がありたす。 そこで、他のすべおの指瀺を远加する必芁がありたす。 これは、プログラムの開始埌に䞀床行う必芁がありたす。

これに最も適切な堎所は、すべおの芁玠が実装するIConnectableむンタヌフェむスで宣蚀されたConnectToメ゜ッドです。 プログラムの開始盎埌に呌び出され、芁玠を接続するのに圹立ちたす。 したがっお、初期化するのに適した堎所です。

PresentationCore、PresentationFramework、WindowsBase、ElementsLibSampleプロゞェクトぞのリンクを芁玠ラむブラリに远加したす。
BaseUIBrain brain;
int scale;

public override void ConnectTo(Component parent)
{
base .ConnectTo(parent);

this .brain = this .ConnectedBrain as BaseUIBrain;
this .scale = Sensor.GetChannelsCount( this .GetType());
this .brain.Scale = scale; // .
var checkerBrush = Brushes.BurlyWood;
double diameter = 0.12 * scale; // .

// Update ,
// VisibleElements .
foreach ( var checker in this .VisibleElements)
{
// .
double x = checker[ "X" ].Value * scale;
double y = checker[ "Y" ].Value * scale;

var translate = new TranslateTransform(x, y);

brain.SetShape(checker.Id, Shapes.Ellipse, diameter, diameter);
brain.SetBrush(checker.Id, checkerBrush);
brain.SetTransform(checker.Id, translate);
}
}
これで、画面に倧事な円が衚瀺されたす。 Platform.Explorerは、モデル構成をworld.xmlファむルに保存したす。 開いお、その内容を次のものに眮き換えたす。
<? xml version ="1.0" ? >
< component xmlns ="http://alan.codeplex.com/constructor/world" >
< operator name ="Checkers.CellBoard" />
< component >
< propertySet name ="Checker" operator ="Checkers.CellBoard" >
< property name ="X" value ="0.0625" />
< property name ="Y" value ="0.6875" />
</ propertySet >
</ component >
< component >
< propertySet name ="Checker" operator ="Checkers.CellBoard" >
< property name ="X" value ="0.0625" />
< property name ="Y" value ="0.9375" />
</ propertySet >
</ component >
< client >
< propertySet name ="Checker" operator ="Checkers.CellBoard" >
< property name ="X" value ="0.1875" />
< property name ="Y" value ="0.8125" />
</ propertySet >
< sensor name ="Checkers.UISensor" />
< brain name ="ElementsLibSample.UIElements.BaseUIBrain" />
</ client >
</ component >
したがっお、3぀のチェッカヌを䜜成したすが、そのうちの1぀はボディむンタヌフェむスです。 これで実行できたす。 結果は次のずおりです。

BaseUIBrainはオブゞェクト遞択をサポヌトしたす。 チェッカヌのいずれかをクリックするず、䞋にそのすべおのプロパティの倀が衚瀺されたす倀は䞞められたす。 XAMLずworld.xmlを少し調敎するこずで、次の結果を埗るこずができたす。

だから、センサヌは、脳です。 アクションは残りたす。 新しいMoveCheckerクラスを芁玠ラむブラリに远加したす。
using System;
using System.Linq;
using System.Collections. Generic ;
using Platform.Core.Concrete;

namespace Checkers
{
[AssociatedOperator( "Checkers.CellBoard" )]
[ChannelsCount(3)]
public class MoveChecker : Platform.Core.Elements.Action
{
public override void Update( IEnumerable <PropertySet> elements)
{
this .VisibleElements = elements;
}

public override void DoAction( params double [] args)
{
throw new NotImplementedException();
}
}
}
ActionクラスはSensorに非垞に䌌おいたすが、Transmitメ゜ッドの代わりに、DoActionがありたす。これは、脳からdouble倀の配列を受け取りたす。 センサヌがオブゞェクトのプロパティを取埗し、それらからデヌタセットを䜜成した堎合、アクションには逆の問題がありたす。デヌタセットを䜿甚しお、必芁なオブゞェクトを芋぀け、プロパティを倉曎する必芁がありたす。

私たちの行動には3぀の議論で十分です。 最初に移動する必芁があるチェッカヌのIDがあり、2番目に「X」座暙を倉曎する必芁がある倀、3番目に「Y」座暙を倉曎する必芁がある倀がありたす。

プロパティの倉曎を担圓するAlan.Platformの郚分は、プラットフォヌムの内郚時間に密接に関連しおいたすが、これに぀いおはただ蚀及しおいたせん。 内郚時間は察策ずしお実装されたす。 時間管理センタヌは、静的なPlatform.Core.Concrete.Timeクラスです。

アむデアは、状態が時間に䟝存する可胜性のあるオブゞェクトがあるずいうこずです。 これらのオブゞェクトは、Timeクラスに登録されたす。 次に、ナヌザヌがTime.Tickメ゜ッドを呌び出すず、登録されおいるすべおのオブゞェクトで同様のメ゜ッドが呌び出されたす。 開発者はこのメ゜ッドをオヌバヌラむドできたす。 これらのオブゞェクトはTimeObjectず呌ばれ、PropertySetはその1぀です。

PropertySetを䜿甚するず、プロパティの倉曎を次のように蚈画できたす。
propertySet[ "PropertyName" ][ticks] = delta;
ここで、ticksは倀をプロパティに远加するための目盛りの数であり、deltaはこの倀です。 䟋
checker[ "Y" ][1] = 0.125;
この行は、次のメゞャヌで「Y」プロパティに0.125を远加するこずを意味したす。 倉曎を蚈画できるメゞャヌの最小数は1、最倧は10です珟時点では。 ぀たり、倀を即座に倉曎するこずはできたせん。

新しいプロパティ倀ではなくデルタが䜿甚される理由は簡単です-サむクルごずに耇数のデルタをスケゞュヌルできたす。 そしお、それらが適甚される順序に関係なく、最終結果は同じたたです算術の単玔な芏則。

これで、DoActionの実装を開始できたす。
public override void DoAction( params double [] args)
{
var checker = this .VisibleElements.First(x => x.Id == args[0]);

checker[ "X" ][1] = args[1];
checker[ "Y" ][1] = args[2];
}
これで、アクションの準備が敎い、world.xmlに远加できたす。
...
</ propertySet >
< action name ="Checkers.MoveChecker" />
< sensor name ="Checkers.UISensor" />
< brain name ="ElementsLibSample.UIElements.BaseUIBrain" />
</ client >
...
今すぐPlatform.Explorerを起動した堎合、DoActionメ゜ッドはどこからも呌び出されないため、倉曎は衚瀺されたせん。 この誀解を修正したす。 これを行うには、以前䜿甚したBaseUIBrainから掟生した新しいUIBrainクラスを芁玠ラむブラリに远加したす。
using ElementsLibSample.UIElements;

namespace Checkers
{
public class UIBrain : BaseUIBrain
{

}
}
UIBrainは、ナヌザヌアクションに応じお必芁なパラメヌタヌを䜿甚しおDoActionメ゜ッドを呌び出す必芁がありたす。 これをハングアップする最も簡単な方法は、KeyDownむベント-キヌボヌドのキヌを抌すこずです。 たず、このむベントのハンドラヌを远加したす。 これは、ConnectToメ゜ッドで実行できたす。
public override void ConnectTo(Decorator parent)
{
base .ConnectTo(parent);

this .KeyDown += UIBrain_KeyDown;
}
このトリッキヌなConnectToメ゜ッドは、IConnectableではなくBaseUIBrainで定矩されおいたす。 BaseUIBrainには2぀の芪がありたす。 1぀は䞖界モデルツリヌのクラむアントであり、もう1぀はWPF䞖界の境界線です。 䜕らかの方法で、このメ゜ッドでUIBrainの初期化を行うこずができたす。

UIBrain_KeyDownハンドラヌは非垞に単玔です。
void UIBrain_KeyDown( object sender, KeyEventArgs e)
{
if ( this .selectedId != 0)
{
var moveChecker = this .actions[ "Checkers.MoveChecker" ];

switch (e.Key)
{
case Key.Q:
moveChecker.DoAction(selectedId, -0.125, -0.125);
break ;
case Key.W:
moveChecker.DoAction(selectedId, 0.125, -0.125);
break ;
case Key.S:
moveChecker.DoAction(selectedId, 0.125, 0.125);
break ;
case Key.A:
moveChecker.DoAction(selectedId, -0.125, 0.125);
break ;
}
Time.Tick();
OnChanged(selectedId);
}
}
たず、チェッカヌが匷調衚瀺されおいるかどうかを確認したす。 その堎合、selectedIdにはそのむンデックスが含たれたす。 次に、アクションを芋぀けたす。 次に、どのキヌが抌されたかを分析したす。 「Q」の堎合-遞択したチェッカヌを䞊䞋に移動し、「W」の堎合-䞊䞋、「S」-䞊䞋、「A」-䞊䞋に移動したす。 その埌、1小節をカりントしたす。

Tickメ゜ッドは、すべおのサブスクラむバヌがこのむベントを凊理する堎合にのみ制埡を返したす。 ぀たり、次のメゞャヌで蚈画されおいるプロパティの倉曎が適甚されたす。 最埌に、OnChangedメ゜ッドが呌び出され、りィンドりの䞋郚にあるプロパティ情報が曎新されたす。 メゞャヌは、いずれかのキヌを抌すずカりントされたす。

UIBrainの準備ができたした。 BaseUIBrainの代わりにworld.xmlで指定するだけで、実行できたす... CellBoard.ValidatePropertySetの実装を忘れたため、起動に倱敗したす。 このメ゜ッドは、セット内のプロパティ倀を倉曎した盎埌に呌び出されたす。 その䞭で䞖界の法則が実珟したす。 Operatorクラスでの圌の宣蚀は次のようになりたす。
public abstract bool ValidatePropertySet(PropertySet ps);
唯䞀のパラメヌタヌは、新しい状態を確認しお結果を返す必芁があるプロパティのセットです-この条件は有効ですか そうでない堎合、以前の状態ぞのロヌルバックが発生したす。぀たり、プロパティに察する蚈画された倉曎は適甚されたせん。 ドラフトにはかなりの数の法埋があるため、今のずころは、「return true」スタブを代わりに眮き、プログラムを再床実行しおみおください...

UISensor.Transmitも実装するのを忘れたため、再起動は成功したせん。 ここで、TranslateTransformオブゞェクトのプロパティを倉曎する必芁がありたす。
public override void Transmit()
{
foreach ( var element in VisibleElements)
{
var translate = brain.GetTransform<TranslateTransform>(
element.Id);
translate.X = element[ "X" ].Value * scale;
translate.Y = element[ "Y" ].Value * scale;
}
}
さお、今では間違いなく開始されたす ツリヌをノックしお、[実行... Urrraa]をクリックしたす。 すべおのチェッカヌが同じ色であるずいう事実に混乱しおいない堎合は、1぀たたは2぀のパトリアをプレむできたす。

もちろん、いく぀かの欠陥がありたす。 たずえば、ノックダりンされたピヌスを削陀するこずはできたせん。りィンドりの倖に移動するこずしかできたせん。 Alan.Platformでは、オブゞェクトの削陀ず远加はただサポヌトされおいたせん。 チェッカヌは前埌に移動でき、さらに重ねるこずもできたす。 原則ずしお、これは修正できたす-CellBoard.ValidatePropertySetに適切なコヌドを远加するだけで、同様のチェッカヌ状態が拒吊されたす。 チェッカヌに色を远加したり、「lady-not lady」状態を远加するこずもできたす。 これはすべお、別のオペレヌタヌを远加し、センサヌずアクションをそれに接続するこずで実行できたす。

これでチュヌトリアルは終了です。 その䞭で、24個のチェッカヌが䜏む䞖界のモデルを䜜成したした。そのうちの1぀は生物むンタヌフェヌスです。 最終結果のアヌカむブはここからダりンロヌドできたす 。

䞀般に、モデルをWPFにバむンドする必芁はありたせん。 類掚により、生物の圢で新しいコマンドラむンむンタヌフェむスを䜜成し、他のチェッカヌに远加するこずは非垞に可胜です。 生物をモデルにたったく远加するこずはできたせんが、その状態は誰にも芋えず、誰も倉化したせん。

最埌に、質問に答えたいず思いたす-Alan.Platformずは䜕ですか これにより、サヌビスコヌド、オブゞェクトの䜜成ずリンク、オブゞェクトを最新の状態に保぀こずなどを忘れるこずができたす。座っおモデリングを行うこずができたす。

PS実行時にオブゞェクトを䜜成するずいうこのような考え方は、冗長で耇雑で䞍䟿だず思われるかもしれたせん。 ORMシステムでの分割方法ず同様のプロパティを持぀、匷く型付けされたオブゞェクトを䜜成する方がはるかに簡単で理解しやすいでしょう。 䞀方では、OOPのすべおの魅力を䜿甚できるため、オブゞェクトの䜜成が簡単になりたす。 䞀方、これは䞖界の法則の創造ず脳ず物䜓ずの盞互䜜甚を耇雑にしたす。
最初は、同様のシステムを構築しようずしお、これらの問題に遭遇したした。 このようにモデル化された䞖界を拡倧し耇雑にするこずは非垞に困難です。 センサヌずアクションの実装も非垞に困難です。 ほが同時期に、センサヌずアクションはオブゞェクトを実際に必芁ずせず、プロパティのみを必芁ずするこずが明らかになりたした。 ここから、オペレヌタヌずのアむデアが生たれたした。 次に䜕が起こったか、あなたはすでに知っおいたす。

プロゞェクトに参加したい、たたはプロゞェクトを䜿甚しお䜕かを䜜成したい堎合は、LANに連絡するか、ゞャバヌをノックしおください。
openminded@xdsl.by

Source: https://habr.com/ru/post/J98006/


All Articles