MMORPG programming in Silverlight Tutorial (11) Map Mask

Coordinator
Mar 2, 2010 at 2:25 AM
Edited Mar 2, 2010 at 5:03 AM

    I introduce map presentation in the previous chapters. In general, it is enough to simple games; but we need to spend more energy on the map to simulate real world and achieve more realistic effect. This chapter will focus on how to implement map mask.

    First, let’s have a look at what a complete map should include.

image 

    From the picture above, we can see that the bottom picture is the original map, shown in the game. We have discussed it before. Now let’s put our attention on the top picture. It is a tree, when the sprite moves behind the tree, he will be masked by the tree, so we called it “mask”.

   We cut this tree from the original picture, make the image’s background transparent. And last, we add all these picture in the canvas, the sequence from top to bottom is: mask, sprite, map. Make sure all the masks are put in their proper position where they stay before in their original picture.

   The principle sound reasonable. Let’s implement it in code now.

   In our demo, we use this picture as our map:

    Obviously, there are 3 obstructions, I mark them in green grid. And there are two trees in the map, they are both mask, I cut them from the map, and named them Mask1.png and Mask2.png, as follows:

   

 

    OK, let’s modify the code base on the demo in Chapter 10.

    1st, set up 3 obstructions in the method InitMatrix.

for (int y = 22; y <= 24; y++)
{
    for (int x = 5; x <= 16; x++)
    {
        //障碍物在矩阵中用0表示
        matrix[x, y] = 0;

        rect = new Rectangle()
        {
            Fill = new SolidColorBrush(Colors.Green),
            Opacity = 0.3,
            Stroke = new SolidColorBrush(Colors.Gray),
            Width = gridSize,
            Height = gridSize
        };

        Carrier.Children.Add(rect);

        Canvas.SetLeft(rect, x * gridSize);
        Canvas.SetTop(rect, y * gridSize);
    }
}

for (int y = 11; y <= 14; y++)
{
    for (int x = 27; x <= 31; x++)
    {
        matrix[x, y] = 0;

        rect = new Rectangle()
        {
            Fill = new SolidColorBrush(Colors.Green),
            Opacity = 0.3,
            Stroke = new SolidColorBrush(Colors.Gray),
            Width = gridSize,
            Height = gridSize
        };

        Carrier.Children.Add(rect);

        Canvas.SetLeft(rect, x * gridSize);
        Canvas.SetTop(rect, y * gridSize);
    }
}

for (int y = 18; y <= 21; y++)
{

    for (int x = 33; x <= 37; x++)
    {
        matrix[x, y] = 0;

        rect = new Rectangle()
        {
            Fill = new SolidColorBrush(Colors.Green),
            Opacity = 0.3,
            Stroke = new SolidColorBrush(Colors.Gray),
            Width = gridSize,
            Height = gridSize
        };

        Carrier.Children.Add(rect);

        Canvas.SetLeft(rect, x * gridSize);
        Canvas.SetTop(rect, y * gridSize);
    }
}    

    2nd, set up two mask.

//create mask
Image mask1 = new Image();
Image mask2 = new Image();

private void InitMask()
{
    mask1.Width = 238;
    mask1.Height = 244;
    mask1.Source = new BitmapImage((new Uri(@"Map/Mask1.png", UriKind.Relative)));
    mask1.Opacity = 0.7;

    Carrier.Children.Add(mask1);
    Canvas.SetZIndex(mask1, 10000);
    Canvas.SetLeft(mask1, 185);
    Canvas.SetTop(mask1, 220);

    mask2.Width = 198;
    mask2.Height = 221;
    mask2.Source = new BitmapImage((new Uri(@"Map/Mask2.png", UriKind.Relative)));
    mask2.Opacity = 0.7;

    Carrier.Children.Add(mask2);
    Canvas.SetZIndex(mask2, 10000);
    Canvas.SetLeft(mask2, 466);
    Canvas.SetTop(mask2, 11);
} 

    From the code above, I set the mask1’s ZIndex property to 10000 in the canvas, because the map size is less than 10000 in width and height, the mask will always in front of the sprite.

    You can also find I set the mask1.Opacity to 0.7, so if the sprite move behind the tree, he won’t be hidden by the tree completely, we can still see him, because it’s easy to control the sprite, although the sprite image is not so clear, more or less.

    OK, press Ctrl+F5, and move the sprite behind the tree, we can see that the sprite was “hidden” from our view.

    But, when we move the sprite in front of the tree, we find a strange appearance, the sprite is still be hidden by the tree. So we must modify our code to fix this issue. We need to set sprite’s ZIndex property as the sprite moves in y-coordinate:

double y = Canvas.GetTop(sprite);
Canvas.SetZIndex(sprite, (int)y);    

    And we also need to set the mask’s ZIndex property to its actual value, rather than 10000.

double y = Canvas.GetTop(mask1);
Canvas.SetZIndex(mask1, (int)y);

    But it is not the right time to do this modification, I will leave this issue until I set up a sprite control, I will set up a DependencyProperty in it and implement this dependency between the top and the ZIndex properties.

    BTW, in the game domain, we call this technique that hidden-appear in multiple layers as Painter Algorithm.

 

Summary: This chapter introduces map mask and part of the Painter Algorithm.

    Next chapter, we will focus on another map type, Instance, which can help us to detect the region by picking up the colors. Please focus on it.

    Chinese friend, you can also visit this Chinese blog if you feel difficult to read English, http://www.cnblogs.com/alamiye010/archive/2009/06/17/1505346.html, part of my article is base on it.

    Demo download: http://silverlightrpg.codeplex.com/releases/view/40978