Archive

Archive for May, 2010

Carmenta Engine Power Pack Upgrade

I made a few improvements to the Carmenta Engine Power Pack.

Download links:

This version was named 0.2.

Advertisements
Categories: Uncategorized

Puzzle game upgrade

I could not help spending some more time on my math puzzle game. New features are:

  • Sound effects
  • Animations
  • Levels (larger numbers and minus, multiplication and division)
  • Colors

Here is a shot. Click the image to download.

mathpuzzle

Categories: Uncategorized

WPF, WPF, WPF…

It is really easy to write small games in WPF. Here is a small one for math training that I wrote this evening.

minipuzzle

You may download it here.

Categories: Uncategorized

Recommended evening reading (if there is nothing on tv)

I now and then read through the discussions at Scrum Practitioners at Linked in. I think it is a good way of understanding Scrum better since people with experience from many different projects meet there and tell their stories. Today I read through a discussion on  technical debt. I was not entirely familiar with the term so I ended up reading about it in Martin Fowlers blog. I own a copy of his book UML distilled which I never really liked much but his blog was interesting. I recommend the article cannot measure productivity and what is a failure.

Categories: Uncategorized

Programming WPF user interfaces using F# workflows

References: Real world functional programming, First Class Events (Matthew Podwysocki), First Class Events (Don Syme), Cancellation (LukeH)

I rewrote the sample from real world functional programming using F# visual studio 2010 version and I replaced legacy windows forms with WPF. This was the result:

open System.Windows

open System.Windows.Controls

open System.Windows.Controls.Primitives

open System

open System.Windows.Shapes

open System.Drawing

 

let mutable globalGuiContext : System.Threading.SynchronizationContext = null

 

let drawLine(canvas : Canvas, (x1, y1), (x2, y2)) =

    let line = new Line()

    line.X1 <- float x1

    line.Y1 <- float y1

    line.X2 <- float x2

    line.Y2 <- float y2

    line.Stroke <- System.Windows.Media.Brushes.LightSteelBlue

    canvas.Children.Clear()

    canvas.Children.Add(line) |> ignore

 

let rec drawingLoop(canvas : Canvas, from) = async {

    // Wait for the next mouse action

    let! move = Async.AwaitEvent(canvas.MouseMove)

    let pos = move.GetPosition(canvas)

    if move.LeftButton = Input.MouseButtonState.Pressed then

      // Refresh rectangle and continue in the ‘Drawing’ state     

      drawLine(canvas, from, (pos.X, pos.Y))

      return! drawingLoop(canvas, from)

    else 

      // Return end location to the ‘Waiting’ state

      return (pos.X, pos.Y) }

 

let waitingLoop(canvas : Canvas) = async {

    // Repeat the loop after drawing finishes

    while true do

      let! down = Async.AwaitEvent(canvas.MouseDown)     

      do! Async.SwitchToContext(globalGuiContext)

      let downPos = down.GetPosition(canvas)

      if down.LeftButton = Input.MouseButtonState.Pressed then

        // Transition to the ‘Drawing’ state

        let! upPos = drawingLoop(canvas, (downPos.X, downPos.Y))

        do printfn "Drawn line (%A, %A)" downPos upPos }

 

let doLayout() =

    let window = new Window()

    window.Title <- "Interaction test"

    window.Width <- 400.0

    window.Height <- 400.0

    window.Loaded.Add(fun _ -> globalGuiContext <- System.Threading.SynchronizationContext.Current)

    let canvas = new Canvas()

    canvas.Background <- System.Windows.Media.Brushes.Beige

    canvas.Opacity <- 1.0

    window.Content <- canvas

    (window, canvas)

 

let main() =

    let app = Application(ShutdownMode=ShutdownMode.OnMainWindowClose) in

    let (window,canvas) = doLayout()

    Async.StartImmediate(waitingLoop(canvas))

    app.Run(window) |> ignore

 

[<STAThread()>]

do main()

 

Frankly, I think this approach to gui interaction code looks very promising and I hope to have time to play more with it.

Categories: Uncategorized

Carmenta Engine Power Pack

A nice property of Carmenta Engine is the duality between the script interface and the .NET interface. By duality, I mean that

  • the apis are equally powerfull (or at least to 99%)
  • an object that has been created using one api can be accessed later by the other api

The script interface is used, behind the scenes, by the visual configuration tool SpaceLab to create objects. Creating a configuration setup in SpaceLab is quick and the result is readable and maintainable. However, I would argue, the .NET interface tends to be a bit verbose and non-standard. I know that this is about to change for the next major release (a great thing) but meanwhile (and for those who are stuck using the current version) it would be nice to improve. Among the most important things that I wanted to solve was:

  • Online replacement for the two step new-create pattern (var readop = new ReadOp(); readop.Create(…))
  • Conversion from enumerations to carmenta engine collections
  • Conversions to enumerations from carmenta engine collections (using extension methods)

The Carmenta Engine API is very large, however, and it would be an immense task to write such code by hand. Luckily, Visual Studio comes with a code generation toolkit called T4, Text Template Transformation Toolkit Thus, if I could just write down the rules for how to generate the necessary wrapper code I would be in heaven. This sounded too fun not to do! And so I ended up with a library which I named Carmenta Engine Power Pack. Currently the library consists more or less of one large factory class:

namespace CEPowerPack

{

    public static partial class Factory

    {

        public static ReadOp CreateReadOp(String Name, Operator Input = null, DataSet DataSet = null, DataSetQuery Query = null)

        {

            var instance = new ReadOp();

            instance.Create(Name);

            if (Input != null) instance.Input = Input;

            if (DataSet != null) instance.DataSet = DataSet;

            if (Query != null) instance.Query = Query;

            return instance;

        }

 

        public static Points CreatePoints(IEnumerable<Point> elements)

        {

            var result = new Points();

            foreach (Point element in elements) { result.Add(element); }

            return result;

        }

 

        public static List<Point> ToList(this Points elements)

        {

            var result = new List<Point>();

            foreach (Point element in elements) { result.Add(element); };

            return result;

        }

 

        // Lots and lots of more methods…

    }

}

 

First, take a look at the CreateReadOp method. The factory contains one such method for each class and each create method and using this we can replace the new-create pattern with a one liner. Next, the CreatePoints method. The factory contains one such method for each collection class which allows for simple construction from .net enumerations. And last, the ToList method which is an extension method. Each collection will be extended by a ToList method, enabling easy conversion to .net lists.

Using this factory class the code can be significantly shorter and more readable. For example:

class Program

{

    static void Main(string[] args)

    {

        // Collection support (construction from enumerations and tolist extension methods)

        Points polygon = Factory.CreatePoints(new [] { new Point { X = 0, Y = 0 }, new Point { X = 10, Y = 40 }, new Point { X = 40, Y = 10 } });

        IEnumerable<Point> zeroX = polygon.ToList().Where(p => p.X == 0);

 

        // Factory methods

        var wgs84 = Factory.GetRefSystem("WGS84lola");

        var myDs = Factory.CreateInternalStore(Name: "", RefSys: wgs84) as DataSet;

        var geoLine = Factory.CreateGeoLine(DataSet: myDs, Points: polygon);

        var readOp = Factory.CreateReadOp(Name: "", DataSet: myDs) as Operator;

        var lineVis = Factory.CreateLineVis(Name: "", Color: Factory.CreateDirectColorAttributeVariable(0, 128, 128)) as Visualizer;

        var visList = Factory.CreateVisualizers(new[] { lineVis });

        var renderOp = Factory.CreateRenderOp(Name: "", Input: readOp, VisList: visList) as Operator;

        var layer = Factory.CreateOrdinaryLayer(Name: "", Operators: Factory.CreateOperators(new [] { renderOp })) as Layer;

        var drawable = Factory.CreateWindow(Name: "", Width:400, Height:400, X:10, Y:10) as Drawable;

        var geoRect = new Rect { Xmin = -10, Ymin = -10, Xmax = 100, Ymax = 100 };

        var view = Factory.CreateView(Name: "", Drawable: drawable, Layers: Factory.CreateLayers(new [] { layer }), RefSys:wgs84, GeoRect: geoRect);           

 

        // Test

        view.Update();

        Console.ReadLine();

    }

}

 

The library can either be used by referencing the CEPowerPack dll or by including the source files. Not all plugins have generated wrappers but it is easy to add new ones if needed. It should be noted, though, that the sample code above leans heavily on named paramters which is a new feature in C# 4.0. The entire library source code can be downloaded here.

Categories: Uncategorized

Improved edit tools for Carmenta Engine

A tool is an encapsulation of some user interaction with the map such as panning, zooming, creation of objects and editing of objects. All these operations are provided out of the box and as such they are simple and convenient to use. I.e. if I want to enable panning in the map the only thing I need to do is:

axSpaceX.Tool = new PanTool();

 

It is also possible to write your own tool by implementing the ITool interface:

namespace Carmenta.SpatialAce.Interop.SpatialAceX

{

    public interface ITool

    {

        bool StartManipulation(SpaceX spaceX, int msg, int wParam, int lParam);

        bool Manipulate(int msg, int wParam, int lParam);

        ICommand EndManipulation(bool aborted, int msg, int wParam, int lParam);

        IPictureDisp MouseIcon { get; set; }

        MousePointerConstants MousePointer { get; set; }

    }

}

 

The key methods here are

  • StartManipulation – Check if the interaction should start (i.e. left mouse is pressed).
  • Manipulate – When StartManipulation signals that interaction has started this method will be called instead, allowing the tool to perform whatever it is supposed to do
  • EndManipulation – When Manipulate signals that the interaction has finished this method is called, allowing the tool to clean up. A command can be optionally returned that represents the action, enabling support for undo/redo.

Let’s move forward and see how this can help getting around a limitation of the edit tools (i.e. the move tool and the move node tool). The edit tools will only work for datasets that returns references (to modifiable objects) which according to the documentation is InternalStore, MySql and Oracle and possibly custom datasets. The SQLite dataset that I wrote about a while ago does not return references and thus the edit tools does not work. What is worse is that I do not think that it can by adapted to return references. So, the the question then is; can the current edit tools be adapted in some way so that they will work anyway.

The idea is simple; move the objects into a temporary InternalStore while editing and then (re)insert them. Let’s follow this idea and make a configuration like below

config  

having one persistent store (a SQLite dataset) and one temporary store (an InternalStore) that will be used while editing. Next, we will create a abstract base class for a tool that moves the objects that will be manipulated into the temporary store before manipulation begins and then moves them back into the persistent store when finished. Lets call this class EditToolX. Here is the StartManipulation:

public bool StartManipulation(SpaceX spaceX, int msg, int wParam, int lParam)

{

    this.spaceX = spaceX;

    bool started = toolImpl.StartManipulation(spaceX, msg, wParam, lParam);

    if (started)

    {

        toolImpl.EndManipulation(true, 0, 0, 0);

        started = false;

        originalObjects = GetSelectedObjects();

        if (originalObjects.Count > 0)

        {

            temporaryStore.Clear();

            foreach (GeoObject gob in originalObjects)

            {

                persistentStore.Remove(gob.Id);

                temporaryStore.Insert((GeoObject)gob.Clone());

            }

 

            started = toolImpl.StartManipulation(spaceX, msg, wParam, lParam);

        }

    }

 

    return started;

}

 

Note the trick here – the call is forwarded to the real edit tool (i.e. the move tool) to see if the manipulation should start. If so, I directly end the manipulation. Doing this will have the side effect that the edited objects will be selected. Using this information it is possible to move the objects to the temporary store and then restart the manipulation.

Manipulate can then simply forward the call to the real tool.

public bool Manipulate(int msg, int wParam, int lParam)

{

    return toolImpl.Manipulate(msg, wParam, lParam);

}

 

EndManipulate now needs to reinsert the edited object back into the persistent store

public ICommand EndManipulation(bool aborted, int msg, int wParam, int lParam)

{

    if (aborted)

    {

        foreach (GeoObject gob in originalObjects)

        {

            persistentStore.Insert(gob);

        }

 

        return null;

    }

    else

    {

        var cmd = toolImpl.EndManipulation(aborted, msg, wParam, lParam);

        if (cmd != null)

        {

            cmd.Do();

        }

 

        GeoObjects modifiedObjects = temporaryStore.GetAll(null, null, null);

        temporaryStore.Clear();

        return new EditCmdX(spaceX, persistentStore, originalObjects, modifiedObjects);

    }

}

 

As you can see, this is however, not done in EndManipulation in order to support undo/redo but in a new EditCmdX command. Here is the Do method along with the Insert helper

class EditCmdX : ICommand

{

    // … other code left out for brevity …

 

    public void Do()

    {

        Insert();

        spaceX.Refresh();

    }

 

    private void Insert()

    {

        ids = new Identities();

        foreach (GeoObject gob in modifiedObjects)

        {

            ids.Add(persistentStore.Insert(gob));

        }

        spaceX.View().Selection = ids;

    }

}

 

The command also sets the selection in order to keep the edited objects selected.

Using the EditToolX class we can create two derived classes, MoveToolX and MoveNodeToolX, simply by passing MoveTool and MoveNodeTool respectivly, as a parameter to the EditToolX constructor.

Here is the source code to the updated SQLite dataset along with the new edit tools. The code also provides a new create tool using the same idea as above. The create tool is simplified a bit since we do not need to move the current object to a temporary store. It is enough to save the objects into the persistent store when the interaction ends. Also the SQLite dataset has been updated with a selection bug fix.

Categories: Uncategorized