![]() |
![]() |
| Ecranul principal | Auto layout (asezare automata) |
Explicatii:
Editorul de grafuri de stari a fost creat pentru grafurile de stari ale AI-ului jocului Silent Hunter 4.
Elementele grafului sunt stari iar arcele sunt tranzitii intre stari.
Conteaza ordinea arcelor care ies dintr-o stare.
O tranzitie are mai multe elemente constituente:
- prioritate
- conditie
- actiuni de executat (conteaza ordinea actiunilor)
![]()
Aplicatia deschide fisierele create (in Notepad pentru Silent Hunter III) si salveaza folosind acelasi format. Scrierea datelor in mod text are mai multe avantaje:Aceste fisiere arata in felul urmator:
- Datele pot fi inspectate cu orice editor de text
- Se poate folosi Beyond Compare pentru integrarea versiunilor
- Este pastrata compatibilitatea cu vechea versiune (sunt refolosite absolut toate grafurile existente fara sa existe un nou converter de format)
graph navigator_officer { state Start { type initial; arc Stalker_Idle { input true; output OrderMngInit; } } state Stalker_Idle { arc Stalker_WaitOrder { prio 2; % As result of interface command (camera focus on character) input Camera(on); output EyeballSetTarget(CrtCamera); output PlayAnimIntr(NA_turn_d); } arc Stalker_ExecuteOrder_Talk { prio 2; input Order(AnyNavigation); output PlayAnimIntr(NA_confirm); output PlayMsg(ChE_K_,Yes_Sir); } ... } ... }
Informatiile de layout in "pagina" sunt salvate intr-un alt fisier (prin serializarea datelor de layout existente la runtime).
Limbaj:
Aplicatia a fost dezvoltata in C# (Visual Studio .Net 2003).
Problema editarii de proprietati a fost rezolvata prin customizarea PropertyGrid-ului din .Net Framework. Avantajele sunt
- Controlul este deja creat de Microsoft.
- Numar dinamic (nelimitat) de proprietati asociate cu un obiect.
- Verificarea automata a datelor introduse pe baza tipului asociat.
- Editoare grafice dedicate pentru anumite proprietati. Exemple:
- un numar float care reprezinta un unghi exprimat in radiani este mult mai usor de modificat cu un control dedicat
- autocomplete pentru campurile de siruri de caractere
Fereastra care se deschide si care ofera autocomplete pe mai multe nivele (foarte util pentru o gramatica mod text (in stilul Visual Assist) )
Libraria de diagrame a fost realizata tot de mine si permite:
- structura arborescenta logica de clase pentru Business Logic si User Logic (gen Document / View).
- interactiune cu utilizatorul plugin-abila: view-ul isi inregistreaza tool-urile de care are nevoie (fiecare view conectat la acelasi document poate avea alte unelte pentru interactiunea cu obiectele).
- Obiectele pot fi manipulate de un numar nelimitat (dinamic) de Handle-uri, draggable sau clickable.
- Fiecare view arata propria fereastra asupra documentului (definita prin offset in document si nivelul de scalare).
- Documentul se poate (de)serializa intr-un stream (fisier pe disc sau in memorie (util pentru Undo sau Copy/Paste) )
- Exista un namespace dedicat layout-ului automat al grafurilor care defineste structuri de date care sa mapeze un graf la modul general si minimal, algoritmi de layout (Branch & Bound pe o functie de cost (suma distantelor)) si controalele pentru interfata cu utilizatorul
Inainte:
Dupa:
Pentru structurarea interfetei utilizator s-a folosit Magic Library v1.7.4 (ultima versiune free). Avantajele sunt:
- Utilizatorul isi poate aranja interfata cum doreste: sa mute, sa dimensioneze, sa ascunda sau sa elimine orice control din interfata
- Modificarile sunt pastrate de la o rulare la alta aplicatiei

"Momente de programare:"
CustomTypeDescriptor-ul pentru afisarea colectiei generice de proprietati (inlocuieste reflection-ul):
|
#regionGenericPropertyCollection_CustomTypeDescriptor /// <summary> /// a GenericPropertyCollection that in a PropertyGid displays the inner generic properties instead of the /// reflection-reachable C# properties /// </summary> [Serializable] public class GenericPropertyCollection_CustomTypeDescriptor : GenericPropertyCollection, ICustomTypeDescriptor { #region ICustomTypeDescriptor Members public TypeConverter GetConverter() { return TypeDescriptor.GetConverter( this, true ); } EventDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetEvents() { return TypeDescriptor.GetEvents( this, true ); } public object GetPropertyOwner(PropertyDescriptor pd) { return this; } public PropertyDescriptorCollection GetProperties(Attribute[] attributes) { return this.PropertyDescriptorCollection; } ... } |
Apelarea modulului de automatic layout:
|
public void AutomaticLayout() { GridObjectState[] GridObjects = null; GridLink[] GridLinks = null; foreach( object o in Document ) if( o is DGraphState ) { (o as DGraphState).GetDataForAutomaticLayout( out GridObjects, out GridLinks ); break; } AutomaticLayoutForm dlg = new AutomaticLayoutForm( GridObjects, GridLinks ); if( DialogResult.OK == dlg.ShowDialog() ) { DNodeState s = null; foreach( GridObjectState go in dlg.Grid.Objects ) { go.state.Center = go.GridPoint.Position; s = go.state; } s.Parent.Bounds = s.Bounds; CenterAllObjects(); } dlg.Dispose(); } |
Lista ordonata pentru Branch & Bound din modulul de automatic layout:
|
public class LayoutList { public ArrayList List = new ArrayList(); public Grid Grid; public int CurrentIndex = 0; public LayoutList( Grid g ) { this.Grid = g; List.Add( new GridLayout( g ) ); } /// <summary> /// return true if the new layout is better. Next MUST NOT be called /// </summary> /// <param name="L"></param> /// <returns></returns> public bool Add( GridLayout L ) { if( L.Cost > Current.Cost /* * 1.00f avoid local solutions*/ ) return false; foreach( GridLayout gl in List ) { if( gl.IsTheSameWith( L ) ) return false; } bool equal = false; /// (DateTime.Now.Second % 2) == 1; int index = -1; foreach( GridLayout gl in List ) { ++ index; if( index < CurrentIndex ) continue; if( gl.IsTheSameWith( L ) ) return false; if( equal ? L.Cost <= gl.Cost : L.Cost < gl.Cost ) { List.Insert( index, L ); return true; } } List.Add( L ); return false; } public bool Finished { get { return CurrentIndex > 0 && CurrentIndex == List.Count - 1; } } public void Next() { if( ! Finished ) ++ CurrentIndex; } public GridLayout Current { get { return (GridLayout) List[CurrentIndex]; } } } |