tag:blogger.com,1999:blog-16257924817023955372024-03-20T05:09:36.181-07:00Cabo TrafalgarAlberto Navarrohttp://www.blogger.com/profile/09204067651273342753noreply@blogger.comBlogger16125tag:blogger.com,1999:blog-1625792481702395537.post-64895087837386597162016-01-07T02:35:00.001-08:002016-01-07T02:35:46.304-08:00Music for my earsCabo Trafalgar will have original music for next version<br />
<br />
Thanks Enrique Gomez-Cabrero Fernandez for your gift.<br />
https://soundcloud.com/enrique-gomez-cabrero<br />
<br />Alberto Navarrohttp://www.blogger.com/profile/09204067651273342753noreply@blogger.com0tag:blogger.com,1999:blog-1625792481702395537.post-3923409203996385102015-09-01T15:31:00.001-07:002015-09-01T15:31:46.633-07:00Templated Nifty XML with FreeMarkerI finally managed to add a most missed feature (in my opinion) in nifty-gui, though I had to add it on top of my nifty-flow add-on.<br />
<br />
Benefits, quite clear to me, for (more or less) the same screen, let me show you the comparison on code and difference in the paradigm. It also allows you to focus in a single way of working and not needing to learn two ways of making the same job, including style. I hate working on front end.<br />
<br />
OLD VERSION, Using Java Builder because there's a dynamic number of lists to render. <br />
<br />
<pre style="background-color: white; color: black; font-family: 'DejaVu Sans Mono'; font-size: 8.8pt;"><span style="color: navy; font-weight: bold;">public final class </span>SelectKeyboardControlsScreenGenerator <span style="color: navy; font-weight: bold;">implements </span>ScreenGenerator {
<span style="color: olive;">@Autowired</span><span style="color: olive;"> </span><span style="color: navy; font-weight: bold;">private </span>Nifty <span style="color: #660e7a; font-weight: bold;">nifty</span>;
<span style="color: olive;">@Autowired</span><span style="color: olive;"> </span><span style="color: navy; font-weight: bold;">private </span>SelectKeyboardControlsScreenController <span style="color: #660e7a; font-weight: bold;">controller</span>;
<span style="color: grey; font-style: italic;">/**</span><span style="color: grey; font-style: italic;"> * Singleton</span><span style="color: grey; font-style: italic;"> */</span><span style="color: grey; font-style: italic;"> </span><span style="color: olive;">@Autowired</span><span style="color: olive;"> </span><span style="color: navy; font-weight: bold;">private </span>GameConfiguration <span style="color: #660e7a; font-weight: bold;">gameConfiguration</span>;
<span style="color: olive;">@Override</span><span style="color: olive;"> </span><span style="color: navy; font-weight: bold;">public void </span>buildScreen(String screenUniqueId) {
<span style="color: navy; font-weight: bold;">if </span>(<span style="color: #660e7a; font-weight: bold;">nifty</span>.getScreen(screenUniqueId) != <span style="color: navy; font-weight: bold;">null</span>) {
<span style="color: #660e7a; font-weight: bold;">nifty</span>.removeScreen(screenUniqueId);
}
buildScreenNow(screenUniqueId);
}
<span style="color: navy; font-weight: bold;">public void </span>buildScreenNow(String screenUniqueId) {
Collection<KeyboardCommandStateListener> keyListeners
= <span style="color: #660e7a; font-weight: bold;">gameConfiguration</span>.getPreGameModel().getByType(KeyboardCommandStateListener.<span style="color: navy; font-weight: bold;">class</span>);
<span style="color: grey; font-style: italic;">//sorting commands in alphabetical order of command name</span><span style="color: grey; font-style: italic;"> </span>List<KeyboardCommandStateListener> sortedCommands = <span style="font-style: italic;">newArrayList</span>(keyListeners);
Collections.<span style="font-style: italic;">sort</span>(sortedCommands, <span style="color: navy; font-weight: bold;">new </span>Comparator<KeyboardCommandStateListener>() {
<span style="color: olive;">@Override</span><span style="color: olive;"> </span><span style="color: navy; font-weight: bold;">public int </span>compare(KeyboardCommandStateListener o1, KeyboardCommandStateListener o2) {
<span style="color: navy; font-weight: bold;">return </span>o1.toString().compareTo(o2.toString());
}
});
<span style="color: navy; font-weight: bold;">final </span>PanelBuilder outerPanelBuilder = <span style="color: navy; font-weight: bold;">new </span>PanelBuilder(<span style="color: green; font-weight: bold;">"PartitionPanel"</span>) {
{
height(<span style="color: green; font-weight: bold;">"80%"</span>);
childLayoutHorizontal();
}
};
<span style="color: navy; font-weight: bold;">final </span>PopupBuilder popupBuilder = <span style="color: navy; font-weight: bold;">new </span>PopupBuilder(<span style="color: green; font-weight: bold;">"popup"</span>) {
{
text(<span style="color: green; font-weight: bold;">"some text"</span>);
}
};
List<List<KeyboardCommandStateListener>> partitionedSorted = Lists.<span style="font-style: italic;">partition</span>(sortedCommands, <span style="color: blue;">4</span>);
<span style="color: navy; font-weight: bold;">int </span>partitionIndex = <span style="color: blue;">0</span>;
<span style="color: navy; font-weight: bold;">for </span>(List<KeyboardCommandStateListener> currentPartition : partitionedSorted) {
<span style="color: navy; font-weight: bold;">final </span>PanelBuilder partitionPanelBuilder = <span style="color: navy; font-weight: bold;">new </span>PanelBuilder(<span style="color: green; font-weight: bold;">"Partition" </span>+ partitionIndex++ + <span style="color: green; font-weight: bold;">"Panel"</span>) {
{
height(<span style="color: green; font-weight: bold;">"80%"</span>);
childLayoutVertical();
}
};
<span style="color: navy; font-weight: bold;">for </span>(<span style="color: navy; font-weight: bold;">final </span>KeyboardCommandStateListener currentCommandListener : currentPartition) {
<span style="color: navy; font-weight: bold;">final </span>PanelBuilder commandNamePanelBuilder = <span style="color: navy; font-weight: bold;">new </span>PanelBuilder(currentCommandListener.toString() + <span style="color: green; font-weight: bold;">"Panel"</span>) {
{
childLayoutHorizontal();
text(<span style="color: navy; font-weight: bold;">new </span>TextBuilder(<span style="color: green; font-weight: bold;">"text"</span>) {
{
text(<span style="color: #660e7a;">currentCommandListener</span>.toString());
style(<span style="color: green; font-weight: bold;">"nifty-label"</span>);
alignCenter();
valignCenter();
height(<span style="color: green; font-weight: bold;">"10%"</span>);
margin(<span style="color: green; font-weight: bold;">"1%"</span>);
}
});
control(<span style="color: navy; font-weight: bold;">new </span>ListBoxBuilder(currentCommandListener.toString()) {
{
displayItems(<span style="color: blue;">4</span>);
selectionModeSingle();
optionalHorizontalScrollbar();
optionalVerticalScrollbar();
alignCenter();
valignCenter();
height(<span style="color: green; font-weight: bold;">"10%"</span>);
width(<span style="color: green; font-weight: bold;">"10%"</span>);
margin(<span style="color: green; font-weight: bold;">"1%"</span>);
}
});
}
};
partitionPanelBuilder.panel(commandNamePanelBuilder);
}
outerPanelBuilder.panel(partitionPanelBuilder);
}
Screen screen = <span style="color: navy; font-weight: bold;">new </span>ScreenBuilder(screenUniqueId) {
{
controller(<span style="color: #660e7a; font-weight: bold;">controller</span>); <span style="color: grey; font-style: italic;">// Screen properties</span><span style="color: grey; font-style: italic;">
</span><span style="color: grey; font-style: italic;"> // <layer></span><span style="color: grey; font-style: italic;"> </span>layer(<span style="color: navy; font-weight: bold;">new </span>LayerBuilder(<span style="color: green; font-weight: bold;">"Layer_ID"</span>) {
{
childLayoutVertical(); <span style="color: grey; font-style: italic;">// layer properties, add more...</span><span style="color: grey; font-style: italic;">
</span><span style="color: grey; font-style: italic;"> // <panel></span><span style="color: grey; font-style: italic;"> </span>panel(<span style="color: #660e7a;">outerPanelBuilder</span>);
<span style="color: grey; font-style: italic;">// </panel></span><span style="color: grey; font-style: italic;"> </span>panel(<span style="color: navy; font-weight: bold;">new </span>PanelBuilder(<span style="color: green; font-weight: bold;">"Panel_ID"</span>) {
{
height(<span style="color: green; font-weight: bold;">"20%"</span>);
childLayoutHorizontal();
control(<span style="color: navy; font-weight: bold;">new </span>ButtonBuilder(<span style="color: green; font-weight: bold;">"PreviousButton"</span>, <span style="color: green; font-weight: bold;">"Back"</span>) {
{
alignCenter();
valignCenter();
interactOnClick(<span style="color: green; font-weight: bold;">"back()"</span>);
}
});
control(<span style="color: navy; font-weight: bold;">new </span>ButtonBuilder(<span style="color: green; font-weight: bold;">"NextButton"</span>, <span style="color: green; font-weight: bold;">"Next"</span>) {
{
alignCenter();
valignCenter();
interactOnClick(<span style="color: green; font-weight: bold;">"next()"</span>);
}
});
control(<span style="color: navy; font-weight: bold;">new </span>LabelBuilder(<span style="color: green; font-weight: bold;">"RepeatError"</span>) {
{
alignRight();
valignCenter();
text(<span style="color: green; font-weight: bold;">""</span>);
width(<span style="color: green; font-weight: bold;">"50%"</span>);
color(<span style="color: navy; font-weight: bold;">new </span>Color(<span style="color: green; font-weight: bold;">"#ff0"</span>));
}
});
}
});
}
});
<span style="color: grey; font-style: italic;">// </layer></span><span style="color: grey; font-style: italic;"> </span>}
}.build(<span style="color: #660e7a; font-weight: bold;">nifty</span>);
}</pre>
<br />
<br />
NEW VERSION, two files, some preparation of data in the Generator<br />
<br />
<pre style="background-color: white; color: black; font-family: 'DejaVu Sans Mono'; font-size: 8.8pt;"><span style="color: navy; font-weight: bold;">public final class </span>SelectKeyboardControlsScreenGeneratorXML <span style="color: navy; font-weight: bold;">extends </span>FtlTemplateGenerator {
<span style="color: grey; font-style: italic;">/**</span><span style="color: grey; font-style: italic;"> * Singleton</span><span style="color: grey; font-style: italic;"> */</span><span style="color: grey; font-style: italic;"> </span><span style="color: olive;">@Autowired</span><span style="color: olive;"> </span><span style="color: navy; font-weight: bold;">private </span>GameConfiguration <span style="color: #660e7a; font-weight: bold;">gameConfiguration</span>;
<span style="color: navy; font-weight: bold;">public </span>SelectKeyboardControlsScreenGeneratorXML(Nifty nifty) <span style="color: navy; font-weight: bold;">throws </span>IOException {
<span style="color: navy; font-weight: bold;">super</span>(nifty, <span style="color: green; font-weight: bold;">"/mod/common/interface_keyboardselector.xml"</span>);
}
<span style="color: olive;">@Override</span><span style="color: olive;"> </span><span style="color: navy; font-weight: bold;">protected </span>Map injectProperties() {
Collection<KeyboardCommandStateListener> keyListeners
= <span style="color: #660e7a; font-weight: bold;">gameConfiguration</span>.getPreGameModel().getByType(KeyboardCommandStateListener.<span style="color: navy; font-weight: bold;">class</span>);
<span style="color: grey; font-style: italic;">//sorting commands in alphabetical order of command name</span><span style="color: grey; font-style: italic;"> </span>List<KeyboardCommandStateListener> sortedCommands = <span style="font-style: italic;">newArrayList</span>(keyListeners);
Collections.<span style="font-style: italic;">sort</span>(sortedCommands, <span style="color: navy; font-weight: bold;">new </span>Comparator<KeyboardCommandStateListener>() {
<span style="color: olive;">@Override</span><span style="color: olive;"> </span><span style="color: navy; font-weight: bold;">public int </span>compare(KeyboardCommandStateListener o1, KeyboardCommandStateListener o2) {
<span style="color: navy; font-weight: bold;">return </span>o1.toString().compareTo(o2.toString());
}
});
<span style="color: navy; font-weight: bold;">final </span>List<List<KeyboardCommandStateListener>> partitionedSorted = Lists.<span style="font-style: italic;">partition</span>(sortedCommands, <span style="color: blue;">4</span>);
<span style="color: navy; font-weight: bold;">return new </span>HashMap() {{ put(<span style="color: green; font-weight: bold;">"partitionedKeyboardCommands"</span>, <span style="color: #660e7a;">partitionedSorted</span>);}};
}
<span style="color: navy; font-weight: bold;">public void </span>setGameConfiguration(GameConfiguration gameConfiguration) {
<span style="color: navy; font-weight: bold;">this</span>.<span style="color: #660e7a; font-weight: bold;">gameConfiguration </span>= gameConfiguration;
}
}</pre>
<br />
PLUS the XML with some extra intelligence<br />
<br />
<pre style="background-color: white; color: black; font-family: 'DejaVu Sans Mono'; font-size: 8.8pt;"><span style="font-style: italic;"><?</span><span style="background-color: #efefef; color: blue; font-weight: bold;">xml version=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"1.0" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">encoding=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"UTF-8"</span><span style="font-style: italic;">?></span><span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">nifty </span><span style="background-color: #efefef; color: blue; font-weight: bold;">xmlns=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"http://nifty-gui.sourceforge.net/nifty.xsd" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">xmlns:</span><span style="background-color: #efefef; color: #660e7a; font-weight: bold;">xsi</span><span style="background-color: #efefef; color: blue; font-weight: bold;">=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"http://www.w3.org/2001/XMLSchema-instance" </span><span style="background-color: #efefef; color: green; font-weight: bold;"> </span><span style="background-color: #efefef; color: blue; font-weight: bold;">xsi:schemaLocation=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"http://nifty-gui.sourceforge.net/nifty.xsd http://nifty-gui.sourceforge.net/nifty.xsd"</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">useStyles </span><span style="background-color: #efefef; color: blue; font-weight: bold;">filename=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"nifty-default-styles.xml" </span><span style="background-color: #efefef;">/></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">useControls </span><span style="background-color: #efefef; color: blue; font-weight: bold;">filename=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"nifty-default-controls.xml" </span><span style="background-color: #efefef;">/></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">screen </span><span style="background-color: #efefef; color: blue; font-weight: bold;">id=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"${screenUniqueId}" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">controller=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"com.navid.trafalgar.mod.common.SelectKeyboardControlsScreenController"</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">layer </span><span style="background-color: #efefef; color: blue; font-weight: bold;">id=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"background" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">childLayout=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"center"</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">layer</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">layer </span><span style="background-color: #efefef; color: blue; font-weight: bold;">id=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"foreground" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">childLayout=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"vertical" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">style=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"nifty-panel-no-shadow"</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">panel </span><span style="background-color: #efefef; color: blue; font-weight: bold;">id=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"panel_top" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">height=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"15%" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">width=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"75%" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">align=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"center" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">childLayout=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"center"</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">text </span><span style="background-color: #efefef; color: blue; font-weight: bold;">text=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"Select the keys..." </span><span style="background-color: #efefef; color: blue; font-weight: bold;">font=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"Interface/Fonts/Default.fnt" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">width=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"100%" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">height=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"100%" </span><span style="background-color: #efefef;">/></span>
<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">panel</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">panel </span><span style="background-color: #efefef; color: blue; font-weight: bold;">id=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"panel_mid" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">height=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"70%" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">width=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"75%" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">align=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"center" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">childLayout=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"horizontal" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">style=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"nifty-panel-red"</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">panel </span><span style="background-color: #efefef; color: blue; font-weight: bold;">id=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"panel_mid_left" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">width=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"100%" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">align=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"center" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">childLayout=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"horizontal"</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span>#list partitionedKeyboardCommands as partition>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">panel </span><span style="background-color: #efefef; color: blue; font-weight: bold;">id=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"partition_${partition?counter}" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">width=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"50%" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">align=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"center" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">childLayout=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"vertical"</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span>#list partition as keyboardCommands>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">panel </span><span style="background-color: #efefef; color: blue; font-weight: bold;">id=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"keyboardCommands_${keyboardCommands}" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">align=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"center" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">childLayout=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"horizontal"</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">control </span><span style="background-color: #efefef; color: blue; font-weight: bold;">id=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"${keyboardCommands}" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">name=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"listBox" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">displayItems=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"4" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">forceSelection=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"true" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">horizontal=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"off" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">width=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"30%" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">align=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"left" </span><span style="background-color: #efefef;">/></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">text </span><span style="background-color: #efefef; color: blue; font-weight: bold;">text=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"${keyboardCommands}" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">font=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"Interface/Fonts/Default.fnt" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">align=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"right" </span><span style="background-color: #efefef;">/></span>
<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">panel</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">text </span><span style="background-color: #efefef; color: blue; font-weight: bold;">text=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">font=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"Interface/Fonts/Default.fnt" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">align=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"right" </span><span style="background-color: #efefef;">/></span>
<span style="background-color: #efefef;"></</span>#list>
<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">panel</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"></</span>#list>
<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">panel</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">panel</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">panel </span><span style="background-color: #efefef; color: blue; font-weight: bold;">id=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"panel_bottom" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">height=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"15%" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">width=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"75%" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">align=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"center" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">childLayout=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"horizontal"</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">panel </span><span style="background-color: #efefef; color: blue; font-weight: bold;">id=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"panel_bottom_right" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">height=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"50%" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">width=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"25%" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">valign=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"center" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">childLayout=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"center"</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">control </span><span style="background-color: #efefef; color: blue; font-weight: bold;">name=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"button" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">label=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"Back" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">id=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"QuitButton" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">align=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"center" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">valign=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"center" </span><span style="background-color: #efefef; color: green; font-weight: bold;"> </span><span style="background-color: #efefef; color: blue; font-weight: bold;">visibleToMouse=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"true" </span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">interact </span><span style="background-color: #efefef; color: blue; font-weight: bold;">onClick=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"back()"</span><span style="background-color: #efefef;">/></span>
<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">control</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">panel</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">panel </span><span style="background-color: #efefef; color: blue; font-weight: bold;">id=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"panel_bottom_right3" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">height=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"50%" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">width=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"25%" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">valign=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"center" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">childLayout=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"center"</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">control </span><span style="background-color: #efefef; color: blue; font-weight: bold;">name=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"button" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">label=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"Select ship" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">id=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"PlayButton" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">align=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"center" </span><span style="background-color: #efefef; color: blue; font-weight: bold;">valign=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"center" </span><span style="background-color: #efefef; color: green; font-weight: bold;"> </span><span style="background-color: #efefef; color: blue; font-weight: bold;">visibleToMouse=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"true" </span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">interact </span><span style="background-color: #efefef; color: blue; font-weight: bold;">onClick=</span><span style="background-color: #efefef; color: green; font-weight: bold;">"next()"</span><span style="background-color: #efefef;">/></span>
<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">control</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">panel</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">panel</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">layer</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">screen</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">nifty</span><span style="background-color: #efefef;">></span></pre>
<br />
Please notice the use of Freemarker commands like list or .counter.<br />
<br />
Already uploaded to version 0.4.0 in https://github.com/albertonavarro/nifty-flowAlberto Navarrohttp://www.blogger.com/profile/09204067651273342753noreply@blogger.com0tag:blogger.com,1999:blog-1625792481702395537.post-64818566829623859122015-08-29T14:55:00.000-07:002015-08-29T14:55:33.501-07:00Input processing in Cabo Trafalgar (and 2)Another of the risks to face when creating Cabo Trafalgar is making the inclusion of any new element expensive, in terms of work needed due to interactions with elements already existing in the game.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLESpMyH99tbBgoQAOO03nCxgVIDPOMz36ro69YtiInjnJzNsPFXnfz24RciKKzszWkiZRAIJrhWIAWHQlK-ab8ypU4xP39cV_qbwJWGpZOrxaZOSjdowERwkgTpIBzwBN0OiZx1_Kk8Nq/s1600/Control+combinations.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLESpMyH99tbBgoQAOO03nCxgVIDPOMz36ro69YtiInjnJzNsPFXnfz24RciKKzszWkiZRAIJrhWIAWHQlK-ab8ypU4xP39cV_qbwJWGpZOrxaZOSjdowERwkgTpIBzwBN0OiZx1_Kk8Nq/s1600/Control+combinations.png" /></a></div>
<br />
<br />
If you didn't design the way of creating new ships correctly, you might end up adding code per command relative to every possible different input available in the system. Likewise, you don't want to modify your ship's commands if you added a new input to your game.<br />
Keeping the work in O(1) is paramount (yes, complexity can be applied to you as a worker).<br />
<br />
My strategy for solving this problem is converting one 2-dimensional array into two 1-dimensional ones. Conceptually like this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXR-jBwL8HenTk6b6k95BU2d6m4eTi2xDVc-M1kGfzpip4xtH6u9sVodCrsJHcZr0T_pNLpkTmo_fGk16WOJWaPcUo2WfV7Pbq25GBq7dA5YZj8W6WALWAuNVqHeXGOeqog3kfAAvtK63J/s1600/Commands+array.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXR-jBwL8HenTk6b6k95BU2d6m4eTi2xDVc-M1kGfzpip4xtH6u9sVodCrsJHcZr0T_pNLpkTmo_fGk16WOJWaPcUo2WfV7Pbq25GBq7dA5YZj8W6WALWAuNVqHeXGOeqog3kfAAvtK63J/s1600/Commands+array.png" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxtRA0mWa59P-Wn-1E0dnShjUmgh_IKKnYoFh2YfrJwrxCjEuHT4JZn1gJ3Tc1cKDM_oDiO8R6aBjW8Gugq0LMSPMfZtRC6zFBoDxMC62ueqQgYaMCzCvE8wF7GpvjRBDq3Im-0V6HNtFK/s1600/Input+array.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxtRA0mWa59P-Wn-1E0dnShjUmgh_IKKnYoFh2YfrJwrxCjEuHT4JZn1gJ3Tc1cKDM_oDiO8R6aBjW8Gugq0LMSPMfZtRC6zFBoDxMC62ueqQgYaMCzCvE8wF7GpvjRBDq3Im-0V6HNtFK/s1600/Input+array.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxtRA0mWa59P-Wn-1E0dnShjUmgh_IKKnYoFh2YfrJwrxCjEuHT4JZn1gJ3Tc1cKDM_oDiO8R6aBjW8Gugq0LMSPMfZtRC6zFBoDxMC62ueqQgYaMCzCvE8wF7GpvjRBDq3Im-0V6HNtFK/s1600/Input+array.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxtRA0mWa59P-Wn-1E0dnShjUmgh_IKKnYoFh2YfrJwrxCjEuHT4JZn1gJ3Tc1cKDM_oDiO8R6aBjW8Gugq0LMSPMfZtRC6zFBoDxMC62ueqQgYaMCzCvE8wF7GpvjRBDq3Im-0V6HNtFK/s1600/Input+array.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxtRA0mWa59P-Wn-1E0dnShjUmgh_IKKnYoFh2YfrJwrxCjEuHT4JZn1gJ3Tc1cKDM_oDiO8R6aBjW8Gugq0LMSPMfZtRC6zFBoDxMC62ueqQgYaMCzCvE8wF7GpvjRBDq3Im-0V6HNtFK/s1600/Input+array.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxtRA0mWa59P-Wn-1E0dnShjUmgh_IKKnYoFh2YfrJwrxCjEuHT4JZn1gJ3Tc1cKDM_oDiO8R6aBjW8Gugq0LMSPMfZtRC6zFBoDxMC62ueqQgYaMCzCvE8wF7GpvjRBDq3Im-0V6HNtFK/s1600/Input+array.png" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxtRA0mWa59P-Wn-1E0dnShjUmgh_IKKnYoFh2YfrJwrxCjEuHT4JZn1gJ3Tc1cKDM_oDiO8R6aBjW8Gugq0LMSPMfZtRC6zFBoDxMC62ueqQgYaMCzCvE8wF7GpvjRBDq3Im-0V6HNtFK/s1600/Input+array.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"> </a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
In plain English, what this mean is that I decouple actions from actions consumers.<br />
<br />
On one side, all I care when I create a new Ship is that it creates "Commands", these are classes able to execute Ship's functions, they represents what a user might want to do. What a ship might or might not do will be determined by the collection of Commands it returns and nothing else. O(1).<br />
<br />
On the other side, all I care when I'm creating a new input adapter is that it's able to use commands, generically. It's a simple interface with an execute, so I can focus in the WiiFit complicated bluetooth bridge or the Remote Controll connection, without needing to thing on the other end of the command. O(1) <br />
<br />
This is the design implemented in Cabo Trafalgar with the flexibility and "inexpensiveness" in mind.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuiN9FJgozg25UfP36n09qa3dz80ksShMWFQfLAOGegWQAaB1hEZWaGOjnPJM3AKse_aaSVQW-UFIjyt4drU_1ZaFI8QqhNSgmQ8zDb1LJp2arTESICbo9-mOX5n_ZoD-3DjLPgoIU2uf-/s1600/Input+classes.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuiN9FJgozg25UfP36n09qa3dz80ksShMWFQfLAOGegWQAaB1hEZWaGOjnPJM3AKse_aaSVQW-UFIjyt4drU_1ZaFI8QqhNSgmQ8zDb1LJp2arTESICbo9-mOX5n_ZoD-3DjLPgoIU2uf-/s1600/Input+classes.png" /></a></div>
<br />
<br />
The story beings with a set of Command, provided by a particular ship (see AShipModelInteractive in the previous post http://cabo-trafalgar.blogspot.co.uk/2015/08/input-processing-in-cabo-trafalgar.html), these are the functionality our ship offers and we need to map it to inputs.<br />
<br />
The first step is asking GeneratorBuilder what CommandGenerators are there available for each Command. A CommandGenerator represents a different input, they must be registered in GeneratorBuilder declaring what subclass of Command they support (so far, all CommandGenerators support all Commands, I haven't found an example of subclassing).<br />
<br />
So here we have KeyboardCommandGenerator, registered in the GeneratorBuilder (using "registerBuilder" and declaring itself available for each Command it's asked.<br />
<br />
As a user, we asked for CommandGenerators for some commands, and we retrieved a list of CommandGenerators per Command, now if that list was longer than 1, we should decide per command how we're going to use it. In this example, we have only KeyboardCommandGenerator so there's little point to choose, only one option per command.<br />
<br />
Now we have a command and a "chosen" CommandGenerator, it's time to associate them by invoking on generateCommandStateListener, it takes the Command now, they keycode comes later.<br />
<br />
Now we have a collection of KeyboardCommandStateListener, it's time to associate it with keys, up to the user, and the job's done. Each time that key is pressed, the Command in the Ship will be invoked.<br />
<br />
The advantage of this design is the ease of adding more CommandGenerators, as I have a screen for choosing the right CommandGenerator per command, I can mix them in the same game.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyVHMYAv3avNe4eRpKSaAjECw0Cykb-_jL3O43sxNGCMMxK1jZmGVQsbmFAZWOswQ9Pi-gsI7uKd_tT7LDjW02vcS7kiPEC4apXoPwiv8ruu1q_iobvnBlXZv-EQWstgfs3KlsFcmcyZUB/s1600/chooseCommandGenerator.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="505" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyVHMYAv3avNe4eRpKSaAjECw0Cykb-_jL3O43sxNGCMMxK1jZmGVQsbmFAZWOswQ9Pi-gsI7uKd_tT7LDjW02vcS7kiPEC4apXoPwiv8ruu1q_iobvnBlXZv-EQWstgfs3KlsFcmcyZUB/s640/chooseCommandGenerator.png" width="640" /> </a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjViTsuY83UjKgKJiCLErIGzkIic84JNGqlulxYtMr4vUlbqkBQO7KfeADg91m0TEqfAw93ptQ779evi10wOfPFWpuo3znZ0MJdpqN7Md_pI1zTx6NZFTKuGSHEI129lSKBLfbpEgJuc3Ki/s1600/chooseCommandGenerator1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="504" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjViTsuY83UjKgKJiCLErIGzkIic84JNGqlulxYtMr4vUlbqkBQO7KfeADg91m0TEqfAw93ptQ779evi10wOfPFWpuo3znZ0MJdpqN7Md_pI1zTx6NZFTKuGSHEI129lSKBLfbpEgJuc3Ki/s640/chooseCommandGenerator1.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />Alberto Navarrohttp://www.blogger.com/profile/09204067651273342753noreply@blogger.com0tag:blogger.com,1999:blog-1625792481702395537.post-45471481688861789412015-08-29T07:47:00.003-07:002015-08-29T07:47:57.943-07:00Input processing in Cabo Trafalgar<b>If you haven't read <a href="http://cabo-trafalgar.blogspot.co.uk/2015/08/multiplayer-modes-in-cabotrafalgar.html">multiplayer-modes-in-cabotrafalgar</a>, you should do it now, as "mode 0 - 3" are explained there, otherwise you won't fully understand this article.</b> <br />
<br />
This should be the first of a series of articles to explain how to extend Cabo Trafalgar with more and different controls, modules and ships (these are, not by chance, the three dimensions Cabo Trafalgar relies on).<br />
<br />
The aim of this article today is explaining why it's not a good idea to rely in the Jme3 Input Manager directly if you're planning to have several multiplayer modes like Cabo Trafalgar does. <br />
<br />
In little words, we need to cover the following cases:<br />
<br />
<br />
<b>Player's input to local game</b><br />
Player -> Keyboard Input -> Ship calculations locally -> Render locally<br />
<br />
<br />
<b>Ghost representing past game by same (local file) or (recordserver online service) another player</b><br />
Downloaded game -> Ship position is set externally -> Render locally<br />
<br />
<br />
<b>Remote input to local game (multiplayer mode 1)</b><br />
Remote player -> Remote input -> Ship calculations locally -> Render locally<br />
<br />
<br />
<b>Multiplayer (multiplayer mode 2 and 3)</b><br />
Player -> Keyboard Input -> Transmitted to server<br />
<b>and</b><br />
Server position calculations for all ships -> Ship position is set externally -> Render locally<br />
<br />
<br />
<b>Player's game is stored in local file or remote server for future ghost/reference</b><br />
Player -> Keyboard Input -> Ship calculations locally -> Store to file / server<br />
<br />
<br />
As you can see, if you want to cover at least two of these modes, you need to detach the following elements and combine them according to your needs:<br />
<br />
Renderization <i>(AShipModelZ):</i> What we render is a representation of a ship (and other elements), whose position, rotation and scale is known to us, but not how or where they have been calculated. They can come from:<br />
<ol>
<li>Remotely calculated ship <i>(ShipModelZGhost):</i> This element takes a stream of data from a server (mode 2 and 3) or a file (mode 0) to know what's the position of the ship every frame.</li>
<li>Locally calculated ship <i>(ShipModelZPlayer):</i> This element calculates following position, rotation and scale from previous + input. Input can be:</li>
<ol>
<li>Local input (keyboard, wiifit, joystick...) (InputManager -> KeyboardGenerator -> ShipModelZControlProxy)</li>
<li>Remote input (mode 1) (RemoteInputCommandGenerator ->ShipModelZControlProxy)</li>
</ol>
</ol>
Also, in mode2 and mode3, there's a need for transmitting user's input. It hasn't been implemented yet, but it would take InputManager -> KeyboardGenerator -> ShipModelZControlProxy -> ShipModelZTransmitter (inexistent yet). <br />
<br />
Input will deserve another post itself, as it can be more complicated than it seems :)<br />
<br />
In the diagram below, green classes belongs to the api, no real meaningful functionality on them, in yellow, ShipModelZ implementation of them:<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiohbaIGtEncbEB872I3t71QY_ctUe5yh3udWt1v-aVfY3PjOlKtCPNPvALsr8rIJ8fYr6p8MJwGUDI39qyc4vxlqk5zLZbkZCBBmIsnhuYUokAiEzDMnldyAYpEHLPQRSt3jq40VNJVhaK/s1600/Player+classes.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiohbaIGtEncbEB872I3t71QY_ctUe5yh3udWt1v-aVfY3PjOlKtCPNPvALsr8rIJ8fYr6p8MJwGUDI39qyc4vxlqk5zLZbkZCBBmIsnhuYUokAiEzDMnldyAYpEHLPQRSt3jq40VNJVhaK/s640/Player+classes.png" width="640" /></a></div>
<br />
<br />
<br />
Alberto Navarrohttp://www.blogger.com/profile/09204067651273342753noreply@blogger.com0tag:blogger.com,1999:blog-1625792481702395537.post-43853463117150606172015-08-28T16:43:00.002-07:002015-08-28T16:43:57.630-07:00Multiplayer modes in CaboTrafalgar<h2>
Multiplayer modes in CaboTrafalgar</h2>
<h3>
Commands and Generators</h3>
Some common vocabulary needed for understanding following text.<br />
<br />
Commands are the smaller representation of an action that a user can do, and it´s declared and generated by each Ship individually. Some ships will offer "rudder left", "right", "mainsail in", "out", while other can offer the same four plus "move weight right", "left". Commands are, therefore, up to the Ship creator and this game takes them and tries to find who can implement them.<br />
<br />
Generators come into play then, once we have some commands, we ask the Generator Manager (or similar) how many generators we have available for each one.<br />
There are some generic Generators like Keyboard, able to map all Commands, also Remote is able to map everything, but we might find other Generators restricted about the type of commands able to deal with.<br />
<br />
Once we have Commands and the possible Generators, it´s up to the user map each command with the desired generator (they could be keyboard, remote, and also wiifit, joystick, or mouse, just as example).<br />
<br />
Finally, each Command is mapped to the chosen generator through a finest specification, in case of keyboard, associating a key. <br />
<br />
<h3>
Multiplayer Mode 0, Offline competition (DONE)</h3>
This was the first multiplayer mode done in CaboTrafalgar, for which I have "recordserver". It stores all verified user´s games and best are shared so other users can see, learn and compete against them.<br />
<br />
It offers a ranking with times and users to enhance competition.<br />
Information uploaded comprises position, rotation and commands executed per frame, this would be later (not yet) validated by recordserver, who shares back positions per frame, but erases commands.<br />
<br />
This way, another player can´t simply take other person´s record as his, commands are needed and game reexecuted to validate authenticity (not yet again).<br />
<br />
In order to make this mode, I needed to introduce a Ghost class able to reposition a Ship every frame, which gave me the idea of the current class atlas (to be explained in other post).<br />
<br />
<h3>
Multiplayer Mode 1, Shared controls on a local game (DONE)</h3>
We now offer the option of sharing an arbitrary number of Commands to another player, but all calculations are still made locally (your computer, not any of CaboTrafalgar servers) and the rendering is also local to your sole screen. This is, you must be sharing with somebody in your room.<br />
<br />
The transfer is made through a barcode able to be read by any SmartPhone that can open a web application with those shared controls on it (this uses our servers), or you could use our app for that (in progress).<br />
<br />
As a result, commands travel from your guest´s device to our servers, only to be transfered back with no alteration to your computer, where they´re interpreted just like your own input. As much this is a local collaboration that these results would be uploadable to RecordServer as they were yours alone.<br />
<h3>
</h3>
<h3>
Multiplayer Mode 2, Multiplayer game</h3>
Little explanation here, who doesn´t know what´s this about? Game doesn´t happen in your computer anymore, you´re just rendering the movements our server will tell you, like they were Mode0 ghosts, and your input will travel far from your computer like it was a Mode1 SmartPhone.<br />
<br />
Of course, not everything is always so simple, and some calculation could be done at your computer for fluidity´s and optimization´s sake, but the principles are the same, we need a server online where the calculations are done, and new speeds and positions are redistributed for clients to render.<br />
<h3>
</h3>
<h3>
Multiplayer Mode 3, Shared multiplayer game</h3>
This is the goal I aim from the first day, this game was always defined as a collaborative multiplayer naval battle simulator. A captain that delegates functions in other players inside the ship, and with help of other ships, fights another number of players collaborating in other ships.<br />
<br />
Game again happens remotely, but controls can be shared remotelly as roles, or locally as controls, as a mix of Mode 1 and 2.<br />
<br />
<br />
<br />Alberto Navarrohttp://www.blogger.com/profile/09204067651273342753noreply@blogger.com0tag:blogger.com,1999:blog-1625792481702395537.post-57326558672435572902015-07-08T15:16:00.002-07:002015-07-08T15:16:19.333-07:00Nifty-flow code releasedI finally managed to separate my nifty-flow from cabotrafalgar, and it's started to be ready to open to other users.<br />
<br />
What's nifty-flow?<br />
<ul>
<li>A library that helps you to create series of screens to be played in order.</li>
<li>A library that helps you to share screens, as they won't need to
know where to point next, screens are no longer pointing to other
screens.</li>
<li>A library that helps you to reuse the same screen, accesible from different screens, allowing decoupling content and routing.</li>
<li>A library that (will) help you to apply template technologies to save time creating dynamic screens avoiding java builders.</li>
<li>If you're using Spring or Guice for wiring your instances, we won't
complain, it's generic enough to accept instances from any system (as
long as you build the bridge <img alt="wink" class="emoji" height="20" src="http://jme-hub-cdn.jmonkeyengineor.netdna-cdn.com/images/emoji/twitter/wink.png?v=0" title=":wink:" width="20" />)</li>
</ul>
It's build on the top of nifty 1.3.3, and fully compatible with jme3 AFAIK.<br />
Code and example here: <a href="https://github.com/albertonavarro/nifty-flow" rel="nofollow">https://github.com/albertonavarro/nifty-flow</a><br />Feedback is welcome, the project works for me though <img alt="smile" class="emoji" height="20" src="http://jme-hub-cdn.jmonkeyengineor.netdna-cdn.com/images/emoji/twitter/smile.png?v=0" title=":smile:" width="20" /><br />
<br />
http://hub.jmonkeyengine.org/t/nifty-meets-flow/33139Alberto Navarrohttp://www.blogger.com/profile/09204067651273342753noreply@blogger.com0tag:blogger.com,1999:blog-1625792481702395537.post-78785133183839337212015-05-03T10:33:00.002-07:002015-05-03T10:34:36.337-07:00Understanding CaboTrafalgar Physics 1 - Tidal forces in shipModelZIndex:<br /><br />(To come)<br /><br /><br />This is the first entry of a series to explain where we are now with physics in the game, and where we want to be. <br /><br />Most of the entries will refer this "dinghy", ShipModelZ, in regards of movement and commands.<br /><br />This post is actually an easy win, and that's the best way to start a path, with a victory in an apparently difficult topic as "Tidal movement".<br /><br />During the hundredths of seconds a frame lasts, several calculations are made to try to simulate movement realistically, considering real or apparent wind, boat position, sail position, rudder position and weight location. In this calculation, tide is not considered, as we're calculating movement OVER the tide (same way, we don't consider the movement of the earth around the Sun for highway speed calculation).<br /><br />Once we know what's the tri-dimensional distance we want to move over the sea, we need to add the absolute movement of the water, giving as the final distance we have moved.<br /><br />Code explanation:<br /><br />private void updatePosition(float tpf) {<br /> Vector3f shipOrientation3f = this.getGlobalDirection();<br /> this.move(shipOrientation3f.x * localSpeed * tpf, 0, shipOrientation3f.z * localSpeed * tpf);<br /> this.move(getContext().getWater().getMovement(this.getGlobalDirection()).mult(-30 * tpf));<br /> shipDirection.setValue(shipOrientation3f);<br /> }<br /><br />For this model, all movement is calculated in the direction of the keel, no lateral movement has been modelled yet. Direction of the keel is "this.getGlobalDirection()"<br /><br />Local speed is the speed "ahead", direction defined by the keel, it acts as the modulus of a vector, while the keel is the direction of the vector.<br /><br />As we're just interested in horizontal movement, we take first and third elements in the vector, times the speed, times tpf (time per frame) to get the final distance we've moved over the sea. <br />On top of this, we apply the movement of the tide for that particular location (this is a bug, we should be passing position, not orientation, but it doesn't matter, the implementation of water context is not as complex yet for it to matter), times some handy constant times time per framework.<br /><br />So magic is done, on top of the ship movement, we have tide speed complicating everything.<br /><br />That's it for today.. :)<br />Alberto Navarrohttp://www.blogger.com/profile/09204067651273342753noreply@blogger.com0tag:blogger.com,1999:blog-1625792481702395537.post-75922130425525579502015-04-02T17:06:00.001-07:002015-04-02T17:06:33.969-07:00New model under test<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVBYQrGhNPbdlux35qAvatEi7yqLkO7MBQbYPevuX5FmjtLrvcHL06cjSbk4W_JXnMd8u4j-Z-cIsyp8jN3Wa252QF0HsiOIfHMo6yVkKdo8GAAMN5W_YeDXzctYtk7puZt_pLuKgS-ngi/s1600/scaleproblem.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVBYQrGhNPbdlux35qAvatEi7yqLkO7MBQbYPevuX5FmjtLrvcHL06cjSbk4W_JXnMd8u4j-Z-cIsyp8jN3Wa252QF0HsiOIfHMo6yVkKdo8GAAMN5W_YeDXzctYtk7puZt_pLuKgS-ngi/s1600/scaleproblem.png" height="252" width="320" /></a></div>
<br />
New model under test (Javi Leyton's) and considering... a change of my scale of valuesAlberto Navarrohttp://www.blogger.com/profile/09204067651273342753noreply@blogger.com0tag:blogger.com,1999:blog-1625792481702395537.post-72944664892220334572015-03-25T16:53:00.002-07:002015-03-26T02:42:49.092-07:00Trailer Cabo-Trafalgar v0.9 finally released<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dwy4CrXt89mzleVNSkQWEn7AFR-qnVyFgrooY5RhVWBAfS9VRbcYdOmaHil9yxW6WaovZk5Z9ig9iiYeo5U2w' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<br />
Better quality version:<br />
<a href="https://drive.google.com/file/d/0Bw6os0HPcqEodmlvUEtjV2h1WEk/view?usp=sharing">https://drive.google.com/file/d/0Bw6os0HPcqEodmlvUEtjV2h1WEk/view?usp=sharing</a><br />
<br />
Also available in our new facebook page<br />
<a href="https://www.facebook.com/pages/Cabo-Trafalgar-Simulator/571841286286097">https://www.facebook.com/pages/Cabo-Trafalgar-Simulator/571841286286097</a><br />
<br />
Download code and binaries from<br />
<a href="https://github.com/albertonavarro/cabotrafalgar/releases/tag/v0.9">https://github.com/albertonavarro/cabotrafalgar/releases/tag/v0.9</a><br />
<br />
<br />
<br />
Next one will surprise you, I promise!!<br />
<br />
Cabo Trafalgar TeamAlberto Navarrohttp://www.blogger.com/profile/09204067651273342753noreply@blogger.com0tag:blogger.com,1999:blog-1625792481702395537.post-91496887559215802162015-01-25T12:22:00.001-08:002015-01-25T12:22:23.567-08:00LazyLogin 1.4, what's coming<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbeCL2xhcE6FvSDMj9ARZ8TV9IQgTLS9DOcITgS7SQB6G3Y6_XM0qfnVqxbHNAEi70a3-93fRMaONRFKnHRKgq7Vxz52LIidTMmc9Mk1i4lQrOPmi5ygUBqdWBtzChMFhFucP6-m5Q3wf6/s1600/CaboTrafalgar+Systems+2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbeCL2xhcE6FvSDMj9ARZ8TV9IQgTLS9DOcITgS7SQB6G3Y6_XM0qfnVqxbHNAEi70a3-93fRMaONRFKnHRKgq7Vxz52LIidTMmc9Mk1i4lQrOPmi5ygUBqdWBtzChMFhFucP6-m5Q3wf6/s1600/CaboTrafalgar+Systems+2.png" height="460" width="640" /></a></div>
<br />
Maybe because I'm a software engineer, maybe because I'm not good with words, this is my preferred way of explaining what's coming with next version of LazyLogin.<br />
<br />
I'm quite happy with current status of 1.3, simple protocol and execution, simple service, and it was enough for the main public release so far for Cabo Trafalgar (0.9).<br />
<br />
Now it's time for preparing it for the upcoming developments, and finishing the original ideas that were just half done, promising myself I'd finish them when I saw the concept working.<br />
<br />
First, I need to decouple the embedded AMQ, and maybe replacing it with another MQ system. Once done this, LL will publish user information (properly protected, but bearing in mind that this system is meant to be closed and some information can be shared among systems). By all means, I'll try to keep email absolutely enclosed to LL, but I'll need some replacement for private key in the meantime for unverified users.<br />
<br />
To these changes, we need to add a proper way to measure performance, securing endpoints with some SSL protection, a better coverage of test across component, integration, sanity and unit, and adding performance testing for first time.<br />
<br />
Finally, a notification service integrated in LL would allow our services to send notification emails to users without knowing their address, keeping it safe forever.<br />
<br />
I plan to spend some months with this, then, much more to come..Alberto Navarrohttp://www.blogger.com/profile/09204067651273342753noreply@blogger.com0tag:blogger.com,1999:blog-1625792481702395537.post-79965487446980975702015-01-13T15:21:00.002-08:002015-01-15T15:40:13.312-08:00Cabo Trafalgar v0.9 Released!<div class="markdown-body">
Big one!<br />
<br />
Changes:<br />
Connected with LazyLogin and RecordServer services to provide online services.<br />
Profile manager screen.<br />
Control selection to be ready for more than keyboard, and key selection screens.<br />
New Ship introduced, with weight balance control apart from MainSail and Rudder.<br />
Map selection screen now with descriptions and graphic maps for a better understanding.<br />
Introduced tidal sea movement (sea currents) as a possible element in the maps.<br />
Win installer.<br />
Enhanced dynamics, more realistic.<br />
A thousand bugs and aesthetical details fixed. Probably another two thousands created.<br />
And an exit button!!<br />
<br />
Tickets:<br />
<a href="https://github.com/albertonavarro/cabotrafalgar/issues?q=milestone%3A0.9+">https://github.com/albertonavarro/cabotrafalgar/issues?q=milestone%3A0.9+</a><br />
<br />
Windows users: Download caboTrafalgar.exe<br />
Linux users: Download JMonkeyClient-0.9.jar and execute it with java -jar JMonkeyClient-0.9.jar<br />
<br />
Required: Oracle Java 1.7, Openjdk 1.7 or Oracle Java 1.8, as well as a good graphic card.<br />
<br />
Download from: <a href="https://github.com/albertonavarro/cabotrafalgar/releases/tag/v0.9">https://github.com/albertonavarro/cabotrafalgar/releases/tag/v0.9 </a></div>
Alberto Navarrohttp://www.blogger.com/profile/09204067651273342753noreply@blogger.com0tag:blogger.com,1999:blog-1625792481702395537.post-68895202511320893922014-09-09T12:38:00.000-07:002014-09-09T12:38:12.935-07:00Not far from Cabo Trafalgar 0.8It's been long time since I announced version 0.4. That version was a simple game made in a simple way. I can't say it has evolved much as a game, but now it's in position of growing way more way faster.<br />
<br />
Version 0.6, one year ago, I introduced Maven for easier configuration and compilation, also I tried to build up a Continuous Integration based on Jenkins. I didn't do bad, and I improved the realism of the movement of my only boat by a lot.<br />
I've recently completed a couple of RYA sailing courses and validated that actually almost all my models and dynamics are about right :) About this time, I moved to git as well.<br />
<br />
For Version 0.8, I bought an HP microserver (N54L) and 16GB of RAM, and took it really seriously.<br />
<br />
<ul>
<li>Architecture:</li>
<ul>
<li>Lots of vms for having my own infrastructure at home, based on Chef-Server, Xen and OpenSuse.</li>
<li>Dev environments, Jenkins, Artifactory, Ssh, Apache and Zabbix.</li>
<li>At the end, after some months of setting up, I'm really happy with the infrastructure that's helping me to develop independently, and all I've learned.</li>
</ul>
<li>Continuous Integration / Continuous Delivery</li>
<ul>
<li>You can take a look in ci.cabotrafalgar.mooo.com, it's not always up, I need to save energy and money!</li>
<li>All code is still open source and freely available, included the recipes, so Chef-Server is the responsible of carrying credentials.</li>
<li>Pipeline in place so the time between pushing of code and it's in production sanity tested is about 10 mins.</li>
<ul>
<li>Build, component-test, deploy to dev, integration test, deploy to prod, sanity test. I'm quite proud of this.</li>
<li>All deployed by chef-server in local (hp microserver) and remote (rented remote vms).</li>
</ul>
<li>Uniqueness of compilations and production versions.</li>
<li>Binaries and source in artifactory.</li>
</ul>
<li>Product</li>
<ul>
<li>LazyLogin</li>
<ul>
<li>My own implementation for an easy and confortable autentication protocol, passwordless and without need of keeping sensitive information.</li>
<li>Made on Maven, Java, Spring, MySQL, Jetty, WSDL, CXF, Logback and another bunch of technologies I've learned recently.</li>
</ul>
<li>RecordServer</li>
<ul>
<li>With the intention of storing and sharing boat counterclock games, I've created this server that uses LazyLogin to authenticate users and provides ranking services.</li>
<li>Made on the previous plus WADL (WSDL for Rest), Couchdb, Ektorp... among others.</li>
</ul>
<li>Cabo trafalgar</li>
<ul>
<li>Now improved with Spring, modularized, implementation of screen flows and now using RecordServer and LazyLogin for more interactivity. Not ready for multiplayer games though.</li>
</ul>
</ul>
</ul>
I hope you like these changes, I've enjoyed getting this knowledge<br />
<br />
Soon I'll have more news :)<br />
<br />
Alberto <br />
Alberto Navarrohttp://www.blogger.com/profile/09204067651273342753noreply@blogger.com0tag:blogger.com,1999:blog-1625792481702395537.post-28898441677281315432013-01-11T14:30:00.000-08:002013-01-12T04:23:28.649-08:00Cabo Trafalgar 0.4.0 Released!!!<h2>
Cabo Trafalgar 0.4.0 Released!!!</h2>
<div>
After another two months from the last updated, I managed to finish all I had in mind for this release:</div>
<div>
<br /></div>
<div>
<ul>
<li>Complete internal refactoring, now it's easier to make it grow, yet learning, and almost ready for full modularity. </li>
<li>Now maps are selectable, only two now. No collisions yet, sorry, so no islands or things like that.</li>
<li>Now ships are selectable, only two now, but it's been a good research for providing something a bit closer to reality than a surface of wood. It doesn't move, but the polar curve is a bit closer to reality.</li>
<ul>
<li>As a consequence, ShipModelOne is more difficult to use, but gives better results. </li>
</ul>
<li>WindTunnel, for me, for making the ship development easier, for you, maybe you want to learn a bit more about how your ship behaves.</li>
<li>Ghost ship (default enabled). The game is recording your positions, and playing it back when playing again, so you can compete with yourself.</li>
<li>Local ranking for every map.</li>
<li>Red arrow for wind (is it supposed to improve?)</li>
<li>All in a jar, directly executable with java -jar jarname.jar</li>
<li>Lots of bugs introduced.</li>
<li>Lots of bugs fixed.</li>
<li>Mavenized</li>
<li>Professional build environment: Jenkins, Artifactory, Sonar.</li>
</ul>
<div>
<br /></div>
</div>
<div>
And thousands of ideas for next releases :)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<br /><iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/R350SzoAN3c?feature=player_embedded' frameborder='0'></iframe></div>
<br /></div>
Alberto Navarrohttp://www.blogger.com/profile/09204067651273342753noreply@blogger.com0tag:blogger.com,1999:blog-1625792481702395537.post-50282081201984392372012-11-11T16:05:00.000-08:002012-11-11T16:05:05.631-08:00Little update 11/11/2012Hi all<br />
<br />
I better go explaining what I'm doing during this long period between releases.<br />
<br />
Right now, I'm "investing" some time in having a "Wind Tunnel", a small universe where I can control better the wind and the ship position, without bothering of other game mechanism as the ticking clock, the ghost configuration and the camera movements.<br />
<br />
In this wind tunnel, I enforce the ship not to move, but the ship itself is still calculating its own movements, they'll be collected and it'll be useful for a ship development.<br />
I'll also have control over the position and the power of a wind generator, and over the ship control themselves, and the output in terms of speed and inclinations will be printed on screen.<br />
<br />
By doing this work, I've also worked in the modularity of the whole system, trying to make easier to create mods for the game. It's not ready though, lots of work to do yet, specially in the Game Builder, it must allow registration of objects from every mod, so the Wind Tunnel would be able to ask "what ships are available to test" and the builder would respond with the registered data.<br />
<br />
Many ideas, and little time.<br />
<br />Alberto Navarrohttp://www.blogger.com/profile/09204067651273342753noreply@blogger.com0tag:blogger.com,1999:blog-1625792481702395537.post-66383918684866833062012-09-04T12:21:00.002-07:002012-09-04T12:22:35.543-07:00TO-DO list for version 0.2Not yet really closed, I have a draft for the improvements for version 0.2, quite ambitious though.<br />
<br />
<br />
<ol>
<li>Record positions and movements for an user.</li>
<li>Ghost player shown.</li>
<li>Create a server for storing user's records online.</li>
<li>Map Champion's ghost.</li>
<li>Extend definition file for specifying ship type (implementing class).</li>
<li>Create a new screen for Millestone games.</li>
<li>Model and create the logic for a new ship.</li>
<li>New integrated control for compass and wind representation.</li>
<li>(Defect) FlyByCamera fails when ship is not visible.</li>
<li>Activate physics and collitions.</li>
<li>Include terrains in the scenario.</li>
</ol>
<br />
<br />Alberto Navarrohttp://www.blogger.com/profile/09204067651273342753noreply@blogger.com0tag:blogger.com,1999:blog-1625792481702395537.post-2714827041020382322012-09-02T08:53:00.000-07:002012-09-03T00:25:30.379-07:00Releasing 0.1!!<br />
<br />
About two months since I started working for third time in this personal project, I can say I have something playable, and good enough for showing!<br />
<br />
<h2>
Download:</h2>
<a href="http://code.google.com/p/cabo-trafalgar/downloads/detail?name=CaboTrafalgar-0.1.zip">http://code.google.com/p/cabo-trafalgar/downloads/detail?name=CaboTrafalgar-0.1.zip</a><br />
<br />
<h2>
Features:</h2>
<ul>
<li>Not networked.</li>
<li>Poorly modelled one rigid sail ship.</li>
<li>Default water, using shader.</li>
<li>One player.</li>
<li>One mode, against the clock.</li>
<li>Not ready for plugins.</li>
<li>Fixed key definitions.</li>
<li>Fixed graphics configuration. </li>
</ul>
<h2>
Technologies and tools: </h2>
<ul>
<li>Java</li>
<li>JMonkeyEngine + Nifty-GUI</li>
<li>Netbeans</li>
<li>Blender</li>
</ul>
<h2>
Some pictures:</h2>
<div>
<br /></div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsKc9ufWuFHVP3P4TR-jxCjG-xVgWd1sRCoVTCd2tdf0XxiItQmXb3r2PG8kiLyESnek35gLiEHfVvWeIJ6UdfzRlxf7Ghv8OlLIRxuoleStSXnH7Rwe_1sSd4Jk-Srm6HNhS9c7MoXXb6/s1600/game1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsKc9ufWuFHVP3P4TR-jxCjG-xVgWd1sRCoVTCd2tdf0XxiItQmXb3r2PG8kiLyESnek35gLiEHfVvWeIJ6UdfzRlxf7Ghv8OlLIRxuoleStSXnH7Rwe_1sSd4Jk-Srm6HNhS9c7MoXXb6/s320/game1.png" width="288" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
The best window isn't mine :)</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2k8v2sdncmqMHHO7nc3OAFOxqA6BEBGJn2hTkyGa7k_05vls-OLciN7F2SlOT5-6gIjcp6flAwott_tdT83wK4eXZ8tBsN6aQtB6558_8zsO76qmlifqS_UtJPwoLero0ZYsUr7w6RwzL/s1600/game2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="246" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2k8v2sdncmqMHHO7nc3OAFOxqA6BEBGJn2hTkyGa7k_05vls-OLciN7F2SlOT5-6gIjcp6flAwott_tdT83wK4eXZ8tBsN6aQtB6558_8zsO76qmlifqS_UtJPwoLero0ZYsUr7w6RwzL/s320/game2.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
Not even this picture, direct from nifty-gui example.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRde4fWK91xi2EgsMLBt1bjnKA91Y3gI_-oe3XnpuXRpRaeg_FO_qT8KwAvLqoRAVbLtMOaDCRmgu1sxg2lzsbxiaxdaIyQuu4aVTzl5CUjTJqZIVVWtLCf-se7mV7wFBO2YtfbwEhHBEt/s1600/game3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="246" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRde4fWK91xi2EgsMLBt1bjnKA91Y3gI_-oe3XnpuXRpRaeg_FO_qT8KwAvLqoRAVbLtMOaDCRmgu1sxg2lzsbxiaxdaIyQuu4aVTzl5CUjTJqZIVVWtLCf-se7mV7wFBO2YtfbwEhHBEt/s320/game3.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
Top menu, some cameras, useful info at top left, debug info bottom left.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiS_Mp-C8FyVCFuMqx0YqYBFvHHYs9ekF6f_1_JCZZR3YVO79_B8ZJLssu0otqTlFAz-Rh8SNYwdHFDWoD7sbgyfh49AWP6H_X-ex5N1rh91c4vR6plogi5y7pIg3gi_jMmFFPMN3q0ZO9m/s1600/game4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="246" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiS_Mp-C8FyVCFuMqx0YqYBFvHHYs9ekF6f_1_JCZZR3YVO79_B8ZJLssu0otqTlFAz-Rh8SNYwdHFDWoD7sbgyfh49AWP6H_X-ex5N1rh91c4vR6plogi5y7pIg3gi_jMmFFPMN3q0ZO9m/s320/game4.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
Popups when pressed ESC or X menu button.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWKGrnOWdkbFz_6X2IdJzrF27k2Sc69FKYf7lySikvjtdcaoQYVTHVIlUSXHUmkZ8jwfLNJH1ePfzdpDcEM-r862xKDP_TIxPmLkuDedzewH0zSRQUUu9D-jehxk0WXUjPgxXPEOjg0i1Z/s1600/game5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="246" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWKGrnOWdkbFz_6X2IdJzrF27k2Sc69FKYf7lySikvjtdcaoQYVTHVIlUSXHUmkZ8jwfLNJH1ePfzdpDcEM-r862xKDP_TIxPmLkuDedzewH0zSRQUUu9D-jehxk0WXUjPgxXPEOjg0i1Z/s320/game5.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
And now the game, you have to use the rudder and the sails for taking the wind (little red arrow over the hull) and touch those red millestones.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhN-x0BUkJn9UZqlaL3dHcEkC53YbYTwSjPDI4tR-0yfulVYL-J1SophHvg0i32woTQquRssW9SwB9lGonI_KXnXRIsWNYnsIyBq4oBa4yeg4mRv4V9qupSzZHl-PfCss0d0JWEtDKnCS7k/s1600/game6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="246" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhN-x0BUkJn9UZqlaL3dHcEkC53YbYTwSjPDI4tR-0yfulVYL-J1SophHvg0i32woTQquRssW9SwB9lGonI_KXnXRIsWNYnsIyBq4oBa4yeg4mRv4V9qupSzZHl-PfCss0d0JWEtDKnCS7k/s320/game6.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
Another camera, targetCamera, will allow you to see in every moment your ship and the next millestone at the same time. Your ship'll become transparent for a better visibility of the millestones.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5snvt9Zwcbi4tJ1wF94O_FUgFkQHePiF5vz6h79qxhyphenhyphen4WWHdLjNdnaC_1JJHX2NB-rGiqiIlPrSfJZaZPuU7ROyffZKN0c4OrwwcjiAfLu9MEXE5NZxIo_LeF_dsP5m6dGe-h4S3csXCG/s1600/game7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="246" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5snvt9Zwcbi4tJ1wF94O_FUgFkQHePiF5vz6h79qxhyphenhyphen4WWHdLjNdnaC_1JJHX2NB-rGiqiIlPrSfJZaZPuU7ROyffZKN0c4OrwwcjiAfLu9MEXE5NZxIo_LeF_dsP5m6dGe-h4S3csXCG/s320/game7.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
Millestones will turn green once touched, and camera will change to next untouched one.</div>
<br /></div>
<div>
<br /></div>
<div>
<h2>
Video demo:</h2>
</div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dyrt6ORJwL7p9ZdrcuauQseTpaD3h3r-JFJSBskyLu_DYnBADBmRjn20A52CkoebKhxKr3zHyO49iHoDO4Cpg' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<br /></div>
<div>
<br /></div>
Alberto Navarrohttp://www.blogger.com/profile/09204067651273342753noreply@blogger.com0