You are browsing the archive for 2009 November.

Hidden Object: Episode 14 – Shake it up

November 25, 2009 in Hidden Object Game, Silverlight

So far in the game, we have particles when an item is clicked, a hint to show the location of an unfound item, but what should we do if the player goes berserk and wildly clicks all over the place in hopes of finding a difficult-to-find item? In this episode of Creating a Hidden Object Game is Silverlight 3 we will add an earthquake effect if the player clicks too many times in a 5 second interval.

Let’s first start with the shake effect.  The magnifierCanvas Canvas contains the background image and all Paths for each clickable item. We will create a new storyboard called ShakeStoryboard that will animate the Left property of the Canvas:

 

Each of the 4 key frames set the Left property to a different value as shown in the storyboard XAML:

<Storyboard x:Name="ShakeStoryboard" RepeatBehavior="5x" AutoReverse="False" SpeedRatio="5">
    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
        Storyboard.TargetName="magnifierCanvas"
        Storyboard.TargetProperty="(Canvas.Left)">
            <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
            <EasingDoubleKeyFrame KeyTime="00:00:00.2000000" Value="-10"/>
            <EasingDoubleKeyFrame KeyTime="00:00:00.4000000" Value="10"/>
            <EasingDoubleKeyFrame KeyTime="00:00:00.6000000" Value="0"/>
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

 

The Storyboard has the RepeatBehavior property set to repeat 5 times and the SpeedRatio property set to speed up the animation.

If the player clicks on the background image 10 times within a 5 second interval, then the ShakeStoryboard will play. To accomplish this we need three SetGlobalCounterAction instances and one ControlStoryboardAction added to the UserControl:

The first SetGlobalCounterAction sets the values for the TooManyClicks counter when the UserControl loads:

 

The ControlStoryboardAction plays the ShakeStoryboard when the GlobalCounterMaxReachedTrigger is fired for the TooManyClicks key which we set previously to 10.

When the counter reaches 10 we need to set it back to zero which is what the second SetGlobalCounterAction does:

The final SetGlobalCounterAction uses the TimerTrigger to reset the counter every 5 seconds:

 

The only thing left to do is add the IncrementGlobalCounterAction to the background image to increment the counter by 1:

 

So with 5 Action instances, 3 Trigger types, 1 Storyboard, and 0 lines of code we were able to quickly add this feature to the game.

Zip Source Code

silverlight Demo

Hidden Object: Episode 13 – Give me a Hint

November 17, 2009 in Hidden Object Game, Silverlight

This is episode 13 of Creating a Hidden Object Game is Silverlight 3. In this episode, we will add a hint feature to the game to help the players when they can’t find an item. This will require various animations and a custom behavior.

The hint feature can be segmented into three parts:

  • Recharging hint button
  • Hint overlay image with animation
  • HintBehavior to randomly position the hint overlay image

 

Hint Button

Hint Button

To make the hint button, we will use an image of a laptop, a TextBlock (hintTextBlock), and a ProgressBar (progressBar) wrapped in a Canvas (hintCanvas):

The idea is that the TextBlock will contain the text “HINT” and act as a button to trigger the hint feature. When the TextBlock is clicked, the TextBlock is hidden and the ProgressBar shown. This is accomplished by adding a HintStates group to the main UserControl:

When the HintState is active, the TextBlock is shown and its IsHitTestVisible property is set to true so that it can be clicked. When the RechargeState is active, the TextBlock’s Opacity property is set to 0 and its IsHitTestVisible property is set to false so that it can’t be clicked.

To set the RechargeState, we add a GoToStateAction to the TextBlock:

A storyboard is added to change the value of the ProgressBar to indicate that the hint is recharging.

<Storyboard x:Name="RechargingStoryboard">
    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
        Storyboard.TargetName="progressBar"
        Storyboard.TargetProperty="(RangeBase.Value)">
        <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
        <EasingDoubleKeyFrame KeyTime="00:00:10" Value="100"/>
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

In this example, the storyboard will recharge in 10 seconds. For the game, the recharge duration should be somewhere between 30 seconds and 2 minutes.

This storyboard is started using a ControlStoryboardAction on the TextBlock:

 

The change from RechargeState to HintState is handled by the GoToStateAction and the StoryboardCompletedTrigger waiting on RechargingStoryboard. So as soon as the recharging animation ends, then the Hint button displays again.

 

Hint Overlay

Hint Overlay

The hint overlay was created in Expression Design and consists of 10 starbursts or flares set in a circular pattern. After the image is added to the project, drag it onto the LayoutRoot Canvas and locate it “off screen” (Left = 500, Top = -300). Set the ZIndex of the image to 99 so that it will be over any item on the game screen, but always under the cursor image.

 

When the hint TextBlock is clicked, two storyboards are started. The ShowHintStoryboard changes the opacity from 0% to 80% in 2 seconds and then auto reverses back to 0% over the next 2 seconds. The RotateHintStoryboard uses a RotateTransform to rotate the overlay 360 degrees over 4 seconds.

<Storyboard x:Name="ShowHintStoryboard" AutoReverse="True">
    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
        Storyboard.TargetName="hintFlareImage"
        Storyboard.TargetProperty="(UIElement.Opacity)">
        <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
        <EasingDoubleKeyFrame KeyTime="00:00:02" Value="0.8"/>
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

<Storyboard x:Name="RotateHintStoryboard">
    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
        Storyboard.TargetName="hintFlareImage"
        Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)">
        <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
        <EasingDoubleKeyFrame KeyTime="00:00:04" Value="360"/>
    </DoubleAnimationUsingKeyFrames>
</Storyboard>
 

To start the storyboards, use the ControlStoryboardAction with the EventTrigger:

 

Hint Behavior

The last thing we need to do is figure out where to put the hint overlay image. To do this, we will use a behavior that exposes a ShowHint command as well as a HintItems collection and a HintOverlayName property:

In the same way that the MouseCursorBehavior exposes the CursorName property to allow selection of the cursor, the HintBehavior exposes the HintOverlayName so that we can select the hint overlay image. An EventTrigger causes the ShowHint command to fire when the HINT TextBlock is clicked.

The HintItems collection contains one HintItem object for each item that can have a hint. The HintItem object contains a TargetName property to identify the Path or object representing the item and an X and Y variance for the location of the overlay.

The HintBehavior uses two NameResolver instances (see episode 12). The first NameResolver changes the HintOverlayName into a reference to the overlay image control. The second NameResolver is used once a HintItem is randomly picked to see if the object still exists and if so gets a reference to it. Even though a HintItem exists for all clickable items in the hidden object game, it may no longer exist in the visual tree as it could have been removed by the RemoveElementAction as discussed in episode 4.

When the ShowHint command is executed, the private OnShowHint method is called. This is the heart of the HintBehavior:

private void OnShowHint()
{
  DependencyObject item = null;
 
  if (!this.IsHintOverlayNameSet)
    return;
 
  FrameworkElement hintOverlay = HintOverlay as FrameworkElement;
 
  //mix up the order of item names
  HintItems.Randomize();
 
  for (int index = 0; index < HintItems.Count; index++)
  {
    this.ItemResolver.Name = HintItems[index].TargetName;
    item = this.ItemResolver.Object;
 
    if (item != null)
    {
      double itemX = (double)item.GetValue(Canvas.LeftProperty);
      double itemWidth = (double)item.GetValue(FrameworkElement.ActualWidthProperty);
      double itemY = (double)item.GetValue(Canvas.TopProperty);
      double itemHeight = (double)item.GetValue(FrameworkElement.ActualHeightProperty);
    
      double newX = RandomWithVariance(itemX + (itemWidth / 2) - (hintOverlay.ActualWidth / 2), HintItems[index].OriginXVariance);
      double newY = RandomWithVariance(itemY + (itemHeight / 2) - (hintOverlay.ActualHeight / 2), HintItems[index].OriginYVariance);
 
      hintOverlay.SetValue(Canvas.LeftProperty, newX);
      hintOverlay.SetValue(Canvas.TopProperty, newY);

      break;
    }
  }
}

 

If the HintOverlayName is not set we exit the method, otherwise we get a reference to it. We then randomize the order of the items in the HintItems list. This is done using an extension method called Randomize(). Since some items named in the list may no longer exist on the Canvas, we do a null check after we access an item in the list and resolve it. If the item exists, then we determine the location of the item with its width and height so that we can center the overlay image over the item. The RandomWithVariance method uses the OriginXVariance and OriginYVariance values set on HintItem to make sure that the overlay image is over the item but that the item is not necessarily exactly centered.

 

The hint feature of our hidden object game is fairly simple once we break it into its three main components and work on them individually. Stay tuned for the next episode of Creating a Hidden Object Game in Silverlight 3.

Zip Source Code

silverlight Demo

Video: Creating a Silverlight 3 Casual Game using Blend 3 and Triggers, Actions, and Behaviors

November 9, 2009 in Hidden Object Game, Silverlight

On Saturday, November 7, 2009 at 9:00am I presented at the Desert Code Camp in Phoenix, AZ. The topic of my presentation was Silverlight casual game development. In less than an hour I demonstrated how to use triggers, actions, and behaviors in Blend 3 to create a hidden object game. Because all code was contained in the TABs (Triggers, Actions, and Behaviors) there was no code behind for the main UserControl.

Here is a link to the presentation video in WMV format.

If you like you can see all the episodes and follow along with the tutorial.