Between the Lines
2Jul/102

Windows 7 and WPF 4.0 Multitouch: Inertia

WPF 4.0's manipulation events certainly made things easier to write an application that supports multitouch gestures. After you start playing with these gestures, however, you've found yourself disappointed.

You want more. There's something missing. It's just not like it used to be. "It's not you, Manipulation events," you say. "No...it's me." But then? A spark! You find out something new about them! Your relationship is saved! "Why, Manipulation events, I never knew you could handle...inertia!"

Having a long-term relationship with APIs aside, you've certainly landed on something interesting. WPF 4.0's Manipulation events can also be used to handle inertia, which allows your UI to look a little more natural and fun.

For those of you who didn't pay attention in 4th grade science, inertia is Newton's Second Law of Motion. This law states that objects in motion tend to stay in motion, unless acted upon by an outside force. In other words: Ugg move stuff. Ugg let go. Stuff still move. Ugg hungry.

Science.

The idea behind inertia in WPF's Manipulation events is to make objects that are being manipulated behave as a user would expect. When a user spins a card on a table, he can let go and it will continue spinning until it decelerates to a stop. Adding inertia to your manipulable objects makes users giddy to see things on a computer imitate the physical world.

Let's start with the same Window as I used in the manipulation post.

In order to handle inertia, we need to create an event handler for our new inertia event, ManipulationInertiaStarting. This goes right along with your ManipulationDelta and ManipulationStarting events.

<Window x:Class="NewTouchTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        ManipulationStarting="Window_ManipulationStarting" ManipulationDelta="HandleManipulation" ManipulationInertiaStarting="HandleInertia">

The rest of the XAML is the same.

    <Grid x:Name="AppGrid">
        <Rectangle Fill="Blue" Height="100" Width="200" VerticalAlignment="Top" HorizontalAlignment="Left" x:Name="ManRect1" IsManipulationEnabled="True">
            <Rectangle.RenderTransform>
                <MatrixTransform>
                    <MatrixTransform.Matrix>
                        <Matrix OffsetX="250" OffsetY="200"/>
                    </MatrixTransform.Matrix>
                </MatrixTransform>
            </Rectangle.RenderTransform>
        </Rectangle>
 
        <Rectangle Fill="Red" Height="100" Width="200" VerticalAlignment="Top" HorizontalAlignment="Left" x:Name="ManRect2" IsManipulationEnabled="True">
            <Rectangle.RenderTransform>
                <MatrixTransform>
                    <MatrixTransform.Matrix>
                        <Matrix OffsetX="50" OffsetY="50"/>
                    </MatrixTransform.Matrix>
                </MatrixTransform>
            </Rectangle.RenderTransform>
        </Rectangle>
    </Grid>
</Window>

For the code behind, we once again see our old friends.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }
 
    private void Window_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
    {
        e.ManipulationContainer = this;
        e.Handled = true;
    }

Once the user stops performing the gesture, ManipulationInertiaStarting is fired. Our event handler, HandleInertia, is actually a very simple method. It is used to set the values of deceleration for the various manipulation components.

You can set deceleration for each of the transformations supported by manipulation: translation, scaling, and rotation. Don't get too worried about the numbers we have here (I pulled this from the inertia explanation on MSDN originally, I think). You don't have to be so specific to take into account your DPI to ensure you have the exact right deceleration in physical terms. These values work pretty well, though.

    private void HandleInertia(object sender, ManipulationInertiaStartingEventArgs e)
    {
        // Decrease the velocity of the Rectangle's movement by 
        // 10 inches per second every second.
        // (10 inches * 96 pixels per inch / 1000ms^2)
        e.TranslationBehavior.DesiredDeceleration = 10 * 96.0 / (1000.0 * 1000.0);
 
        // Decrease the velocity of the Rectangle's resizing by 
        // 0.1 inches per second every second.
        // (0.1 inches * 96 pixels per inch / (1000ms^2)
        e.ExpansionBehavior.DesiredDeceleration = 0.1 * 96 / 1000.0 * 1000.0;
 
        // Decrease the velocity of the Rectangle's rotation rate by 
        // 2 rotations per second every second.
        // (2 * 360 degrees / (1000ms^2)
        e.RotationBehavior.DesiredDeceleration = 720 / (1000.0 * 1000.0);
 
        e.Handled = true;
    }

Once it has set these deceleration values, it once again fires the ManipulationDelta event - if you recall, this is the event whose handler applies all of the transformations. It populates its ManipulationDeltaEventArgs with the previous values, decreased by our deceleration values. It continues to fire the event with diminishing values, causing the object to slowly come to a stop.

Since we are just reusing our already-defined ManipulationDelta handler, inertia is an incredibly easy addition to make to your manipulable objects.

    private void HandleManipulation(object sender, ManipulationDeltaEventArgs e)
    {
        Rectangle rectToManipulate = e.OriginalSource as Rectangle;
 
        Rect shapeBounds = rectToManipulate.RenderTransform.TransformBounds(new Rect(rectToManipulate.RenderSize));
        Rect containingRect = new Rect(((FrameworkElement)this).RenderSize);
        ManipulationDelta manipDelta = e.DeltaManipulation;

The only change we have to make to our handler is to check to make sure our object doesn't fly away. This is a simple solution where, if the object goes out of the window, it completes the inertia and provides a bounce effect to give feedback to the user it has reached the edge of the screen. ***Correction: the e.Complete() method now appears to cancel the ReportBoundaryFeedback method (I wrote this application while everything was in beta). You can have the bounce effect without the e.Complete(), but your rectangle then flies out of the window. Let me know if you have a simple solution for allowing both to happen, as I likely won't put any effort into it...*** You could easily change the behavior here to make the object more realistically react to its bounds if you like.

        // Check if the rectangle is completely in the window.
        // If it is not and intertia is occuring, stop the manipulation.
        if (e.IsInertial && !containingRect.Contains(shapeBounds))
        {
            // if both are uncommented, e.Complete() overrides e.ReportBoundaryFeedback()
 
            // comment out for a bounce, uncomment to stop the rectangle
            e.Complete();
            // comment out to stop the rectangle, uncomment for a bounce
            // e.ReportBoundaryFeedback(bounceDelta);
        }
 
        Matrix rectsMatrix = ((MatrixTransform)rectToManipulate.RenderTransform).Matrix;
        Point rectManipOrigin = rectsMatrix.Transform(new Point(rectToManipulate.ActualWidth / 2, rectToManipulate.ActualHeight / 2));
 
        // Rotate the Rectangle.
        rectsMatrix.RotateAt(manipDelta.Rotation, rectManipOrigin.X, rectManipOrigin.Y);
 
        // Resize the Rectangle.  Keep it square 
        // so use only the X value of Scale.
        rectsMatrix.ScaleAt(manipDelta.Scale.X, manipDelta.Scale.Y, rectManipOrigin.X, rectManipOrigin.Y);
 
        // Move the Rectangle.
        rectsMatrix.Translate(manipDelta.Translation.X, manipDelta.Translation.Y);
 
        // Apply the changes to the Rectangle.
        rectToManipulate.RenderTransform = (MatrixTransform)(new MatrixTransform(rectsMatrix).GetAsFrozen());
 
        e.Handled = true;
    }
}

That concludes my series on WPF 4.0 multitouch. Let me know in the comments what kinds of UI elements you've touchified with these new events.

24Jun/101

Delay of Game

Back when I reflected on last year, I shared that I had a daughter on the way. Taking that and my recent inactivity into account, you may have been able to piece together that yes, indeed, I am now a father. Adalae Claire Eichacker was born on April 21st (I know, its been awhile).

Of course she has completely changed my life and I'm now in the shell shock phase of figuring out what the "new normal" is. To make things harder, my grandma passed away just a couple of weeks later.   After taking three weeks off for paternity and bereavement leave, I came back to work just as a big release was being finished up and a new project was beginning.  Now, the World Cup is going and I've started a side project (more on that later).

So suffice it to say, I've been a bit busy and this blog is getting LONELY.

Do not fear, however!  This has happened before, and will likely happen again.  I have plenty of posts in my drafts to finish or write, and I'm sure I'll have plenty more as I figure out how to balance being a father, husband, gamer, and programmer.  Oh, and blogger.  Also, superhero.

Ok, ok.  Scratch that last one.

Tagged as: , 1 Comment
25Apr/106

Windows 7 and WPF 4.0 Multitouch: Manipulation

In a recent post, I showed you how to react to touch events in WPF 4.0. You can use that to implement the showcase multitouch gestures: scaling, rotating, and translation. It's not too hard. Really, I've done it. Just dust off your geometry and trigonometry hats and get to it.

Are you done yet? No? Too lazy? Well, how about we make this easier. As I like to say regarding programmers: if necessity is the mother of invention, laziness is most certainly the father.

Luckily for us, Windows 7 has multitouch gesture recognition built in, and WPF now supports listening for it in its upcoming 4.0 release. Here's how you can implement these gestures in your application.

We'll first define a window that will contain two rectangles to manipulate.

The containing control defines handlers for the ManipulationStarting and ManipulationDelta events. These events are fired when a multitouch gesture is first recognized and when it changes, respectively.

<Window x:Class="NewTouchTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        ManipulationStarting="Window_ManipulationStarting" ManipulationDelta="HandleManipulation">

The IsManipulationEnabled property is set to true for each object that we plan to manipulate. This property tells WPF to watch for gestures on manipulable controls. I would guess that forcing you to explicitly define the elements that react to gestures improves the performance of gesture recognition.

    <Grid x:Name="AppGrid">
        <Rectangle Fill="Blue" Height="100" Width="200" VerticalAlignment="Top" HorizontalAlignment="Left" x:Name="ManRect1" IsManipulationEnabled="True">
            <Rectangle.RenderTransform>
                <MatrixTransform>
                    <MatrixTransform.Matrix>
                        <Matrix OffsetX="250" OffsetY="200"/>
                    </MatrixTransform.Matrix>
                </MatrixTransform>
            </Rectangle.RenderTransform>
        </Rectangle>
 
        <Rectangle Fill="Red" Height="100" Width="200" VerticalAlignment="Top" HorizontalAlignment="Left" x:Name="ManRect2" IsManipulationEnabled="True">
            <Rectangle.RenderTransform>
                <MatrixTransform>
                    <MatrixTransform.Matrix>
                        <Matrix OffsetX="50" OffsetY="50"/>
                    </MatrixTransform.Matrix>
                </MatrixTransform>
            </Rectangle.RenderTransform>
        </Rectangle>
    </Grid>
</Window>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

The ManipulationStarting handler sets up the manipulation container in order to specify a frame of reference that the values will be relative to. For example, it establishes the origin (0,0) for x and y coordinates.

    private void Window_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
    {
        e.ManipulationContainer = this;
        e.Handled = true;
    }

The ManipulationDelta handler is used to perform the transformations as the gesture is being performed. It will fire continuously as long as the gesture is changing.

    private void HandleManipulation(object sender, ManipulationDeltaEventArgs e)
    {
        Rectangle rectToManipulate = e.OriginalSource as Rectangle;
        ManipulationDelta manipDelta = e.DeltaManipulation;

First, grab the rectangle's current transform matrix so we can use that as a baseline.

        Matrix rectsMatrix = ((MatrixTransform)rectToManipulate.RenderTransform).Matrix;

Re-establishing the base line each time is important, as the values that the ManipulationDelta sends are not absolute. Each time the handler is called, the values are relative to the previous event firing. For example, if a user gestures a total rotation of 30 degrees, the events would look something like this:

# of Events e.DeltaManipulation.Rotation Total Rotation
1 5 5
2 5 10
3 5 15
4 5 20
5 5 25
6 5 30

Next, we establish an origin to use for the following manipulations. This specifies the point around which the rectangle will rotate and scale. Here, we're setting it up at the middle of the rectangle.

        Point rectManipOrigin = rectsMatrix.Transform(new Point(rectToManipulate.ActualWidth / 2, rectToManipulate.ActualHeight / 2));

Finally, we apply the transformations to the baseline matrix and set this matrix to the sending rectangle's RenderTransform as frozen.

        rectsMatrix.RotateAt(manipDelta.Rotation, rectManipOrigin.X, rectManipOrigin.Y);
        rectsMatrix.ScaleAt(manipDelta.Scale.X, manipDelta.Scale.Y, rectManipOrigin.X, rectManipOrigin.Y);
        rectsMatrix.Translate(manipDelta.Translation.X, manipDelta.Translation.Y);
 
        rectToManipulate.RenderTransform = (MatrixTransform)(new MatrixTransform(rectsMatrix).GetAsFrozen());
        e.Handled = true;
    }
}

See? Easy. Now, maybe you should get to that housework you've been putting off.

16Apr/100

Just a Bit: Improving Graphics Card Performance

I spent a little of time with some people over at AMD the other day, looking at ways to better utilize the video card using WPF.

A useful little chunk that came from that was using the Freeze method on UI elements that are being manipulated. This tells the video card to use the texture already in video memory instead of unloading the old one, performing the manipulation, and loading a new texture into memory. Since this is the most expensive action that can be done with a video card, using Freezable members can make things look much smoother.

Here's an example:

private void Window_TouchMove(object sender, TouchEventArgs e)
{
    Point touchLoc = e.GetTouchPoint(this).Position;
    TranslateTransform unfrozenTransform = new TranslateTransform(touchLoc.X, touchLoc.Y);
    ManipulatingChild.RenderTransform = (TranslateTransform)unfrozenTransform.GetAsFrozen();
}

2Apr/100

Windows 7 and WPF 4.0 Multitouch: Touch Points

Update: if you're looking to just implement standard multitouch gestures, check out my post on manipulation.

One of the most popular posts on this blog is my writeup on getting multitouch events in Windows 7 using WPF and .NET 3.5. Now that .NET 4.0 is in open beta, its time for an update. That's a lot of periods in two sentences.

Microsoft has made it much easier to access touch events in WPF. The touch events are likened to the mouse events you are likely very comfortable with, but with a little more information in order to support multitouch.

I'll lay out a full application for you to play with. First, the XAML of the main window class:

<Window x:Class="NewTouchTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" 
        TouchDown="Window_TouchDown" TouchMove="Window_TouchMove" TouchUp="Window_TouchUp">
    <Grid x:Name="AppGrid">
 
    </Grid>
</Window>

Did you see that? I hooked up multitouch events in my XAML. GAME CHANGER.

Yes, it is that easy. You are already set up to receive touch events. Wizardry!

Now, let's do something worthwhile with our new found power. This application will create squares for every touch point and show its associated ID. This kind of application is useful when messing with new hardware to see how accurate the touch is. It is basically an expanded version of the last example, supporting INFINITE touch points. Infinite up to a certain power of 2, anyway.

We'll start with an array of colors to choose from for our infinite points.

public partial class MainWindow : Window
{
    Brush[] ColorList = new Brush[] { Brushes.Black, Brushes.Yellow, Brushes.Turquoise, Brushes.Purple, Brushes.Orange, Brushes.Navy, Brushes.Pink, Brushes.Brown, Brushes.DarkKhaki };
    public MainWindow()
    {
        InitializeComponent();
    }

Upon the first touch, we create a new Border and move it to the corresponding location using a TranslateTransform. We also create a child TextBlock in order to display the touch point's ID.

The ID is very important when doing something more interesting with multitouch, as it signifies a unique finger. If you are coding any gestures, you'll need to make sure you keep track of your fingers. Actually, that's probably a pretty sound piece of advice for life in general.

    private void Window_TouchDown(object sender, TouchEventArgs e)
    {
        Border newTouch = new Border();
        TextBlock idText = new TextBlock();
        int id = e.GetTouchPoint(this).TouchDevice.Id;
        idText.Text = id.ToString();
        idText.Foreground = Brushes.White;
        newTouch.Child = idText;
        newTouch.Background = ColorList[id % ColorList.Length];
        newTouch.Width = 20;
        newTouch.Height = 20;
        newTouch.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
        newTouch.VerticalAlignment = System.Windows.VerticalAlignment.Top;
        AppGrid.Children.Add(newTouch);
        Point touchLoc = e.GetTouchPoint(this).Position;
        newTouch.RenderTransform = new TranslateTransform(touchLoc.X, touchLoc.Y);
    }

We update the position on every subsequent move event, finding the associated Border by its child TextBlock.

    private void Window_TouchMove(object sender, TouchEventArgs e)
    {
        foreach (UIElement child in AppGrid.Children)
        {
            if (child is Border)
            {
                TouchPoint touch = e.GetTouchPoint(this);
                if (((TextBlock)((Border)child).Child).Text == touch.TouchDevice.Id.ToString())
                {
                    Point touchLoc = touch.Position;
                    child.RenderTransform = new TranslateTransform(touchLoc.X, touchLoc.Y);
                    break;
                }
            }
        }
    }

After the touch is released, we remove the associated border.

    private void Window_TouchUp(object sender, TouchEventArgs e)
    {
        foreach (UIElement child in AppGrid.Children)
        {
            if (child is Border)
            {
                TouchPoint touch = e.GetTouchPoint(this);
                if (((TextBlock)((Border)child).Child).Text == touch.TouchDevice.Id.ToString())
                {
                    AppGrid.Children.Remove(child);
                    break;
                }
            }
        }
    }
}

There. Easy! Keep an eye out for a post regarding the new gesture events.

5Mar/100

Buzzwords: Managed and Unmanaged Code

Buzzwords will be a recurring segment where I explain some of the words and phrases I pick up on as I grow in my development knowledge. Some will be simple definitions; others will delve further into the concepts being presented to explore their meaning.

After I started at HP, my vocabulary was challenged every day with new abbreviations and HP jargon. There were also a few technical terms, two of which came up rather frequently: managed and unmanaged code. Using context clues, I quickly figured it out, but it was something I hadn't been exposed to during school.

Unmanaged code is code that compiles into machine language to be executed using the computer's hardware. That is to say, that there is no intermediary between your executable and the instructions given to your computer. Standard usage of C, C++, assembly, etc. can create binaries with these instructions.

Managed code is a term used to describe code that depends on .NET's Common Language Runtime (CLR). C#, C++/CLI, VB.NET, etc. all will build assemblies with an Intermediate Language (IL). The CLR will interpret this language and compile each part into machine language when it is to be used (this is called Just-in-Time [JIT] compiling). This methodology allows some help for the programming, such as garbage collection and security checking (though at a cost to performance, since it is automatic).

The distinction between the two is important in Microsoft's world, as managed code can be written in a variety of languages. .NET supports C++ (C++/CLI, above), so assuming that all of a C++ program is being compiled into machine code and executes without .NET might be incorrect.

The term "managed" is usually applied to applications that use .NET, specifically; however, I've also heard people use the term when referring to Java. While the term was coined by Microsoft to distinguish .NET code, I don't see any harm in using it to describe Java, which uses similar concepts in its underbelly.

Post a comment on which you use most frequently. Be sure to list the advantages that made you make this decision.

19Feb/104

GameFly Is Actually Pretty Great

The way I play games has changed pretty drastically recently, as I've subscribed to GameFly. I really can't suggest it enough to hardcore console gamers (sadly, but as is expected these days, there's no support for PC games on GameFly). There are a few reasons for my enthusiasm:

  • Its cheaper. If you're like me, you want to buy 1-2 games during the slow months of the year and 2-4 games during the busier months. That ends up as a big hunk of change, especially if buying the latest releases. GameFly ends up costing around $240/year for me, which equals out to the cost of four games per year. I usually end up buying some of the games I really enjoy anyway, but I can play them when they come out (or close to) and buy them when they've gotten a little more affordable. Even with those and the PC games I buy, I still spend less than I would otherwise.
  • I can play games I wouldn't have otherwise. I haven't rented a game since middle school; I just don't have the time to get through a game in the week they allot for you. Buying games is expensive, so I would never buy a game I didn't fully expect to enjoy. With a flat monthly fee and any game I want to play, I end up trying things out a lot more and expand my horizons. I never would have played Call of Juarez: Bound in Blood without GameFly, but I can honestly say that the game enriched my perspective as a gamer.
  • I don't have to buy a game I would only play once. Another negative to buying games is you might only play it once, then all you can do is sell it back at a terrible rate, put it out on craigslist, or let it collect dust on your shelf. There's no way I would play Prototype again, but it was fun enough to complete and send back.
  • I can keep it if I like it. If I end up really liking a game and not wanting to wait for it to get cheaper, I can just keep what I have.  This was really nice when I kept Call of Duty: Modern Warfare 2 because it was a brand new copy and I got it for $10 off the retail price.
  • It helps manage my backlog. I typically have a list of games I want to play at any given time.  Having a queue of games helps me to keep track of the games I want to get to, as well as eventually get them to me.

It also changed the way I play games. Before, I would play a game to completion, no matter what I thought of it. Now that I have a list of 30 games that I'm interested in playing, I might stop playing a game before I finish it in order to get the next one. It might be that I didn't like it (e.g. Scribblenauts, which wasn't fun beyond its "summon anything" gimmick), or it just stopped being fun (e.g. X-Men Origins: Wolverine was actually really fun, but got quite repetitive).

Thinking of getting GameFly?  You can sign up here and get me some referral cash for me to spend on the next game I keep (yes, they have a refer-a-friend program as well).

5Feb/100

Attaching to WndProc in WPF

WPF, like any other UI program, has an inner loop that continually runs in order to update the state of the application and render the UI.  One part of this loop is a call to the function WndProc, which is the function through which Windows communicates the messages your window is receiving (be it input or system notifications).

WPF hides this function from you (presumably to make things easier) and instead just fires events off for anything [it thinks] you'll ever need.  Sometimes, however, it is useful to attach to this loop in order to address messages that don't have a related WPF event, such as messages sent by other applications.

Here's how you do it.

In your window's SourceInitialized event, create an HwndSource object from your window's handle. Use the AddHook method to attach an event handler to all of your window's events using the supplied function.

private void Window_SourceInitialized(object sender, EventArgs e)
{
    IntPtr windowHandle = (new WindowInteropHelper(this)).Handle;
    HwndSource src = HwndSource.FromHwnd(windowHandle);
    src.AddHook(new HwndSourceHook(WndProc));
}

As its always good practice to define the methods you reference, be sure to define WndProc and, hopefully, do something useful with it. Its parameters describe the message by giving you its ID, as well as the parameters sent along with it. For some more on windows messages, check out my earlier post regarding emulating those messages. If your desired message has been captured and handled, be sure to set handled to true.

private IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    // address the messages you are receiving using msg, wParam, lParam
    if (msg == WM_LOOK_FOR_DROIDS)
    {
        if (wParam == DROIDS_IM_LOOKING_FOR)
        {
            CaptureDroids(lParam);
            handled = true;
        }
        else
        {
            AskToMoveAlong(lParam);
        }
    }
    return IntPtr.Zero;
}

Lastly, be sure to remove the hook when your window is closing.

private void Window_Closed(object sender, EventArgs e)
{
    IntPtr windowHandle = (new WindowInteropHelper(this)).Handle;
    HwndSource src = HwndSource.FromHwnd(windowHandle);
    src.RemoveHook(new HwndSourceHook(this.WndProc));
}

Easy as pie. If you're feeling nostalgic and don't want to use events, you can implement your entire application in the WndProc method (other than the rendering, which WPF also hides from you). I wouldn't recommend it, though...

22Jan/101

Video Game Review: Assassin’s Creed II (360)

It's been awhile since I've done a review, and, to commemorate the occasion, I'm going to change the format again!  I found the positives vs. negatives approach rather stifling, but didn't want to stick myself to a particular template.  So, I'm just going to write about whatever I feel deserves mentioning.

Yes, that's correct.  My new format is no format.  Free the birds, whisper to the trees, and run naked down the beach.  Down with the restrictions of video game review formats.

Once you've gotten your clothes back on, come on back and read my review for Assassin's Creed II.

In this sequel to one of my favorite games of 2007, Desmond explores the life of another of his assassin ancestors - an Italian named Ezio who lived during the Renaissance.  My first impressions of the assassins of this game were that they seemed far less epic than they did in the previous game. Altaïr's assassins appeared to be in training for the majority of their lives, whereas Ezio becomes an assassin as a young adult and immediately becomes accustomed to the skills an assassin requires. There are other assassins, from Ezio's pudgy old uncle to the angsty, pissy historian, who detracted from the mystery and skill apparent in the Altaïr's brethren.

Desmond's story isn't very prevalent in Assassin's Creed 2, much to my dismay.   The back-and-forth of revelations was an interesting narrative approach in the first game, and there is far less of it here. I like where it is headed, though; they are exploring the effects of the Animus, as well as pushing Desmond toward becoming a member of the modern-day assassins.

Ezio's story, luckily, is fully fleshed out and just as interesting.  Ezio is a much more developed character than Altaïr, making it easy to relate to him; though, admittedly, it leaves much less mystery around him.  The interaction between Ezio and the supporting cast is excellent, with Leonardo da Vinci as my favorite NPC to visit.

The missions are greatly varied and each has a unique purpose, unlike the repetitious tasks of the previous entry. An unfortunate side effect of this is that the concept of performing in-depth research on a target before striking is mostly lost, making Ezio’s skills seem far from Altaïr's methodical approach.

As I started to relearn the controls, I remembered that the puppetry metaphor they use (assigning face buttons to specific parts of the body) can make things a little confusing.  The button for interacting with an object depends on the interaction itself, unlike the dedicated interaction button used in most games. Movement is also complicated; you must hold down three buttons simultaneously to run and climb, which is what you are doing about 80% of the time. All of the face buttons are context-sensitive, making it hard to pick up at first. How many other games have you seen that have the controls as part of the HUD?

After I was reacclimated to the controls, the game started to feel familiar. Remaining hidden and eluding enemies is much easier with the ability to hide in any group and hire people to distract the guards.  Assassinations are easier to execute without being discovered, but you are still always forced to run after the fact.  The combat is still very counter-based, forcing you to be more strategic and precise.  It is greatly improved by the ability to strip an enemy of his weapon and use it against him; however, if you didn’t enjoy the combat from the last game, there will be little here to change your opinion.

Exploration is a blast, as you can explore the culture and architecture of the Renaissance.  You can research painters and landmarks from the time, which satisfies the history nut in me.  There are also story-related unlockables strewn about the city, motivating you to explore the world more completely.

One of the story-related unlockables is a series of puzzles revealing a video that unravels more about the origin of the Pieces of Eden.  The challenge of solving the puzzles ranges from mentally stimulating to mind-numbingly difficult, as some make little sense.  They often have you translating symbols to numbers, but the symbols often don’t translate in a logical way.  As an example, one in particular (spoiler for the rest of the paragraph) had the symbols depicting a base 3 number system using dots and lines (∙,∙∙, |, |∙, |∙∙, etc.).  This much I got on my own; though I doubt someone who hadn’t studied number systems would pick up on it very easily.  What I didn’t get was why the number system started at an arbitrary point – that is, instead of starting with a single dot (∙), the series starts in the middle and wraps around.  That makes the series, from 0-9, (||, ||∙, ||∙∙, |||, |||∙, ∙, ∙∙, |, |∙, |∙∙).  There are clues in a series of several pictures – that is to say, in one picture, there’s a two, and in another, the symbol “||∙∙”.  But these pictures are small and hard to see, with the symbols cryptically hidden within.

Lastly, I have to mention that the game comes with some serious technical problems.  Ezio would occasionally lose his ability to grip some objects or would become permanently affixed to something he was climbing.  The direction at which he would jump would not always feel consistent with the direction I was pushing towards, causing Ezio to fall to his death.  Strange graphical glitches would occur as well, contorting Ezio’s body in strange directions.  It was playable most of the time, but there were areas that were consistently problematic that I had to avoid.

Assassin’s Creed II left me very satisfied, but ready for more.  The fact that we’ve explored two unique landscapes within the same story has been amazing, making me disappointed to hear that Assassin’s Creed III will continue exploring the Renaissance period with Ezio.  I remain excited about the series, however, and can’t wait to see it conclude.

Have you played Assassin's Creed II?  What are your thoughts?

10Jan/102

The New HP TouchSmart PCs

For the past year and a half, I've been working on software for HP's TouchSmart all-in-one PCs. I develop and manage the deliverables for some of the tiles found within the TouchSmart software suite.  Allow me to take a moment and give you a TouchSmart commercial, explain my role in its creation, and how you can develop on the platform.

Two New TouchSmarts

HP released (in October - yes, this post is a tad late) two new TouchSmarts to coincide with the release of Windows 7, the 300 and 600 series. The 600 is the more performant and larger of the two, but both retain the same touch technology and form factor.  It sports the Core 2 Duo, while the smaller brother uses a 64-bit AMD processor.  You can pick and choose various components for the 300 and 600 at HP's shopping site, so be sure to check out the specs there if you're interested in more details.

The TouchSmarts use optical touch solutions, using two infrared sensors to triangulate the positions of up to two touches. This 2-camera system presents some inaccuracies when two touches are involved, and it certainly created some challenges for my own development. These restrictions are found in all of the multi-touch all-in-ones currently in the market, as they are all based on the same technology, but our mathemagicians perform some voodoo on the data to more accurately approximate the location of the user's fingers. It is a much more cost-effective solution when compared to capacitive touch screens, such as the iPhone's, as the cost for that type of screen exponentially increases with surface area.

The TouchSmart software suite has seen quite a few changes itself. In case you are not familiar with the TouchSmart software for the 500 and 800 series (TouchSmart 2.0), it is a collection of touch-based applications displayed in two scrollable rows of "tiles". These tiles are not interactive in this view, but the user can view information in each tile. To interact with the tile, the user taps on it and enters the full view of the application. You can find a video showing the framework here.

TouchSmart 2.0

TouchSmart 2.0

The big change in TouchSmart 3.0 is interactive tiles. The top row's tiles have been widened and the user can now interact within each tile. Not only that, but the list of TouchSmart applications has grown beyond 20, and each of the existing applications have seen major enhancements.  A video for the new framework can be viewed here.

TouchSmart 3.0

My Role

The four applications for which I am responsible are:

Canvas
Create collages and tag your photos using multitouch gestures or voice commands. I was the developer on this application, which sprung from a sample application that I wrote to show our vendors how to calculate the touch gestures. You may have seen some of the results of that sample early if you've been traveling through Chicago recently, as the application being demoed is using a library I wrote.  Here, you can find a tutorial video (without voice commands but surely some bugs, since the video was shot far before we shipped).

Hulu
Watch videos on Hulu through the touch-friendly interface of Hulu Desktop, residing in the TouchSmart framework. This application was developed by Hulu, but I manage the deliverables for it, provide technical consultation for its integration, as well as ensure it passes through our qualification process.

Twitter
Twitter client for TouchSmart. If you're into Twitter, you'll know what's here (it's the standard fare for Twitter apps). If you're not, you don't care anyway. My responsibilities for this app are similar to my responsibilities for Hulu.

Clock
Clock application for TouchSmart. It's identical to the TouchSmart 2.0 version, but has been updated to work with 3.0 and ported to Windows 7.

As I mentioned above, there are over 20 applications for the TouchSmart, so what I've done barely scratches the surface. The two teams working on the suite worked incredibly hard and have pulled off some amazing stuff. There are apps from photo editing to recipe management. For a full description of all of the applications, you can find them here.

How You Can Get Involved

You are free to create your own TouchSmart tiles if you have an idea for a touch application that would fit well within the TouchSmart framework. It is rather simple - in fact, an existing windows application can be living nicely in TouchSmart within a couple hours of development.

You can find the TouchSmart 3.0 SDK at the TouchSmart Dev Zone, a community based around TouchSmart application development.  Be sure to get involved here, as there are plenty of people willing to aid you in your development, and you can submit your completed application to this site for distribution.

The biggest highlight to this new SDK is that there is now a library for WPF to help you through some of the requirements for TouchSmart applications.  In it, you'll find a Window class that will define your window with the necessary properties for a tile (no chrome, layout notifications, off-screen launching, etc).  There are also helper classes for common functions (loading localized language files, creating notifications in TouchSmart, sending requests to TouchSmart, etc).  Check the SDK for details and feel free to send any questions my way.

If you aren't developing using WPF, it includes all of the information you need in order to create an application without the library.

Sound off in the comments any ideas you have for apps, as well as your interest in TouchSmart development.