主頁 >  其他 > 【WPF學習】第五十七章 使用代碼創建故事板

【WPF學習】第五十七章 使用代碼創建故事板

2020-09-18 07:27:04 其他

  在“【WPF學習】第五十章 故事板”中討論了如何使用代碼創建簡單影片,以及如何使用XAML標記構建更復雜的故事板——具有多個影片以及播放控制功能,但有時采用更復雜的故事板例程,并在代碼中實作全部復雜功能是合理的,實際上,這種情況十分常見,當需要處理多個影片并且預先不知道將有多少個影片或不知道如何配置影片時,就會遇到這種情況,如果希望在不同的視窗中使用相同的影片,或者只是希望從標記中靈活地分離出所有與影片相關的細節以以方便重用,也會遇到這種情況,

  通過撰寫代碼創建、配置和啟動故事板并不難,只需要創建影片和故事板物件,并將影片添加到故事板中,然后啟動故事板即可,在影片結束后可回應Storyboard.Completed事件以執行所有清理作業,

  在接下來的示例中,將看到如何創建下圖中顯示的游戲,在該例中,投下的一系列炸彈的速度始終不斷增加,玩家必須單擊每個炸彈以逐一拆除,當達到設定的極限時——默認情況下是落下5個炸彈——游戲i結束,

  在這個示例中,投下的每顆炸彈都有自己的包含兩個影片的故事板,第一個影片使炸彈下落(通過為Canvas.Top屬性應用影片),而第二個影片稍微前后旋轉炸彈,使其就有逼真的擺動效果,如果用戶單擊一顆下落的炸彈,這些影片就會停止,并且會發生另外兩個影片,使炸彈傾斜,悄然間離開Canvas面板的側邊,最后,每次結束一個影片,應用程式都會進行檢查,一查看該影片是標示炸彈被拆除了還是落下了,并相應地更新計數,

一、創建主視窗

  BombDropper示例中的主視窗十分簡單,它包含一個具有兩列的Grid面板,在左側是一個Border元素,該Border元素包含標示游戲表面的Canvas面板:

<Border BorderBrush="SteelBlue" BorderThickness="1" Margin="5">
            <Grid>
                <Canvas x:Name="canvasBackground" SizeChanged="canvasBackground_SizeChanged" MinWidth="50">
                    <Canvas.Background>
                        <RadialGradientBrush>
                            <GradientStop Color="AliceBlue" Offset="0"></GradientStop>
                            <GradientStop Color="White" Offset="0.7"></GradientStop>
                        </RadialGradientBrush>
                    </Canvas.Background>
                </Canvas>
            </Grid>
        </Border>

  當第一次為Canvas面板設定尺寸或改變尺寸時(當用戶改變視窗的尺寸時),會運行下面的代碼變設定裁剪區域:

private void canvasBackground_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            RectangleGeometry rect = new RectangleGeometry();
            rect.Rect = new Rect(0, 0, canvasBackground.ActualWidth, canvasBackground.ActualHeight);
            canvasBackground.Clip = rect;
        }

  這是需要的,否則即使Canvas面板的子元素位于顯示區域外,Canvas面板也會繪制其子元素,在投彈游戲中,這會導致炸彈飛出勾勒的Canvas面板輪廓的方框,

  在主視窗的右側是一個面板,該面板顯示游戲統計資訊、當前拆除的炸彈數量和落下的炸彈數量,以及一個用于開始游戲的按鈕:

<Border Grid.Column="1" BorderBrush="SteelBlue" BorderThickness="1" Margin="5">
            <Border.Background>
                <RadialGradientBrush GradientOrigin="1,0.7" Center="1,0.7" RadiusX="1" RadiusY="1">
                    <GradientStop Color="Orange"  Offset="0"></GradientStop>
                    <GradientStop Color="White" Offset="1"></GradientStop>
                </RadialGradientBrush>
            </Border.Background>
            <StackPanel Margin="15" VerticalAlignment="Center" HorizontalAlignment="Center">
                <TextBlock FontFamily="Impact" FontSize="35" Foreground="LightSteelBlue">Bomb Dropper</TextBlock>
                <TextBlock x:Name="lblRate" Margin="0,30,0,0" TextWrapping="Wrap" FontFamily="Georgia" FontSize="14"></TextBlock>
                <TextBlock x:Name="lblSpeed" Margin="0,30" TextWrapping="Wrap" FontFamily="Georgia" FontSize="14"></TextBlock>
                <TextBlock x:Name="lblStatus" 
             TextWrapping="Wrap" FontFamily="Georgia" FontSize="20">No bombs have dropped.</TextBlock>
                <Button x:Name="cmdStart" Padding="5" Margin="0,30" Width="80" Content="Start Game" Click="cmdStart_Click"></Button>
            </StackPanel>

        </Border>

二、創建Bomb用戶控制元件

  下一步創建炸彈的圖形劃線,盡管可使用靜態影像(只要具有透明的背景就可以),但使用更靈活的WPF形狀總是更好一些,通過使用形狀,當改變炸彈尺寸時不會導致變形,并且可以修改圖畫中的單個部分或為其應用影片,這個影片中顯示的炸彈是直接從Miscrosoft Word的在線剪貼畫集合繪制的,炸彈剪貼畫被轉換為XAML,具體方法是首先將剪貼畫插入到Word檔案中,然后將Word檔案保存為XPS檔案,

  用于Bomb類的XAML稍微做了簡化(洗掉不必要的用于包含炸彈的額外Canvas元素以及用于縮放炸彈的變換),然后將XAML插入到新的名為Bomb的用戶控制元件中,通過這種方法,住頁面可通過創建Bomb用戶控制元件并將其添加到布局容器(如Canvas面板)中來顯示炸彈,

  在單獨的用戶控制元件中放置圖形,可是的在用戶界面中實體化該圖形的多個副本更加容易,還可通過為用戶控制元件添加代碼來封裝相關的功能,在投彈示例中,只需要為代碼添加一個細節——跟蹤炸彈當時是否正在下落的Boolean屬性:

public partial class Bomb : UserControl
    {
        public Bomb()
        {
            InitializeComponent();
        }
        public bool IsFalling
        {
            get;
            set;
        }
    }

  用于炸彈的標記包含RotateTransform變換,影片代碼使用該變換為下落中的炸彈應用擺動效果,盡管可通過撰寫代碼創建并添加這個RotateTransform變換,但在炸彈的XAML檔案中定義該變換更加合理:

<UserControl x:Class="BombDropper.Bomb"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            >
    <UserControl.RenderTransform>
        <TransformGroup>
            <RotateTransform Angle="20"  CenterX="50" CenterY="50"></RotateTransform>
            <ScaleTransform ScaleX="0.5" ScaleY="0.5"></ScaleTransform>
        </TransformGroup>
    </UserControl.RenderTransform>
    <Canvas>


        <Path Data="M 11.989,50.026 L 24.381,37.08 L 19.097,53.862 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FFF2CC0C"/>
            </Path.Fill>
        </Path>
        <Path Data="M 0.46098,31.997 L 17.945,28.449 L 4.1114,39.19 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FFF2CC0C"/>
            </Path.Fill>
        </Path>
        <Path Data="M 9.9713,7.3517 L 22.075,20.49 L 5.7445,14.16 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FFF2CC0C"/>
            </Path.Fill>
        </Path>
        <Path Data="M 58.484,29.408 L 40.712,31.997 L 57.523,37.367 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FFF2CC0C"/>
            </Path.Fill>
        </Path>
        <Path Data="M 51.663,10.229 L 38.694,22.408 L 55.506,17.325 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FFF2CC0C"/>
            </Path.Fill>
        </Path>
        <Path Data="M 32.354,0.25535 L 31.682,18.092 L 40.039,2.7487 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FFF2CC0C"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 105.84,186.87 L 110.84,183.99 L 115.45,180.64 L 119.58,176.9 L 123.33,172.77 L 126.69,168.36 L 129.47,163.76 L 131.88,158.87 L 133.8,153.79 L 135.14,148.51 L 136.01,143.14 L 136.39,137.77 L 136.3,132.21 L 135.53,126.74 L 134.28,121.37 L 132.45,116 L 130.05,110.73 L 128.61,108.14 L 127.17,105.74 L 125.54,103.34 L 123.81,101.14 L 121.98,99.029 L 120.06,97.015 L 118.04,95.097 L 115.93,93.275 L 113.82,91.549 L 111.61,89.919 L 109.3,88.481 L 106.9,87.138 L 104.5,85.891 L 102,84.741 L 99.503,83.782 L 96.909,82.823 L 94.316,82.055 L 91.722,81.48 L 89.032,81.001 L 86.342,80.617 L 83.556,80.329 L 80.867,80.233 L 78.081,80.233 L 75.391,80.329 L 72.605,80.617 L 69.915,81.096 L 67.129,81.672 L 64.44,82.343 L 61.75,83.206 L 59.06,84.165 L 56.37,85.316 L 53.777,86.563 L 48.781,89.44 L 44.17,92.796 L 40.039,96.536 L 36.293,100.66 L 33.027,104.97 L 30.145,109.67 L 27.743,114.56 L 25.918,119.65 L 24.477,124.83 L 23.612,130.2 L 23.324,135.66 L 23.42,141.13 L 24.189,146.59 L 25.438,152.06 L 27.263,157.43 L 29.664,162.7 L 31.105,165.29 L 32.546,167.69 L 34.179,170.09 L 35.909,172.29 L 37.734,174.4 L 39.655,176.42 L 41.672,178.34 L 43.69,180.16 L 45.899,181.88 L 48.109,183.51 L 50.414,184.95 L 52.72,186.3 L 55.217,187.54 L 57.619,188.69 L 60.213,189.65 L 62.71,190.61 L 65.304,191.38 L 67.994,191.95 L 70.684,192.43 L 73.374,192.82 L 76.063,193.1 L 78.753,193.2 L 81.539,193.2 L 84.325,193.1 L 87.015,192.82 L 89.801,192.34 L 92.49,191.76 L 95.18,191.09 L 97.87,190.23 L 100.56,189.27 L 103.25,188.12 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="F 1 M 125.92,112.84 L 125.92,112.84 L 128.13,117.63 L 129.86,122.62 L 131.01,127.51 L 131.68,132.5 L 131.78,137.68 L 131.4,142.66 L 130.63,147.65 L 129.38,152.44 L 127.65,157.05 L 125.44,161.55 L 122.94,165.77 L 119.77,169.9 L 116.31,173.64 L 112.57,177.09 L 108.34,180.16 L 103.73,182.75 L 107.96,190.99 L 113.34,187.83 L 118.33,184.19 L 122.85,180.16 L 126.88,175.65 L 130.44,170.95 L 133.51,165.97 L 136.1,160.69 L 138.22,155.13 L 139.66,149.38 L 140.62,143.62 L 141,137.87 L 140.91,131.92 L 140.04,125.98 L 138.7,120.13 L 136.78,114.37 L 134.18,108.62 L 134.18,108.62 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="F 1 M 55.89,90.686 L 55.89,90.686 L 58.195,89.44 L 60.693,88.481 L 63.191,87.522 L 65.688,86.754 L 68.09,86.179 L 70.78,85.604 L 73.181,85.124 L 75.679,84.932 L 78.081,84.836 L 80.867,84.836 L 83.268,84.932 L 85.862,85.22 L 88.36,85.508 L 90.857,85.987 L 93.163,86.467 L 95.468,87.138 L 97.87,88.097 L 100.27,88.96 L 102.48,90.015 L 104.79,91.166 L 107,92.412 L 109.01,93.659 L 111.03,95.193 L 112.95,96.728 L 114.97,98.454 L 116.79,100.28 L 118.62,102.1 L 120.25,104.02 L 121.79,106.03 L 123.33,108.14 L 124.67,110.44 L 125.92,112.84 L 134.18,108.62 L 132.55,105.84 L 131.01,103.34 L 129.28,100.66 L 127.36,98.262 L 125.34,95.961 L 123.33,93.755 L 121.12,91.741 L 118.91,89.823 L 116.6,87.905 L 114.2,86.179 L 111.61,84.549 L 109.01,83.11 L 106.52,81.768 L 103.73,80.521 L 101.14,79.466 L 98.35,78.507 L 95.468,77.644 L 92.586,76.973 L 89.704,76.493 L 86.823,76.014 L 83.845,75.726 L 80.867,75.63 L 78.081,75.63 L 75.103,75.726 L 72.029,76.11 L 69.051,76.589 L 66.169,77.165 L 63.191,77.932 L 60.309,78.891 L 57.427,79.85 L 54.545,81.192 L 51.663,82.439 L 51.663,82.439 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="F 1 M 33.795,160.6 L 33.795,160.6 L 31.586,155.8 L 29.857,150.81 L 28.704,145.83 L 28.031,140.84 L 27.935,135.66 L 28.223,130.68 L 28.992,125.78 L 30.337,120.99 L 31.97,116.29 L 34.179,111.88 L 36.773,107.56 L 39.847,103.54 L 43.306,99.796 L 47.052,96.344 L 51.279,93.275 L 55.89,90.686 L 51.663,82.439 L 46.284,85.604 L 41.288,89.248 L 36.773,93.275 L 32.738,97.783 L 29.28,102.39 L 26.11,107.47 L 23.516,112.84 L 21.499,118.3 L 19.962,123.87 L 19.001,129.72 L 18.713,135.66 L 18.809,141.42 L 19.674,147.36 L 21.019,153.31 L 22.94,159.06 L 25.534,164.81 L 25.534,164.81 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="F 1 M 103.73,182.75 L 103.73,182.75 L 101.42,183.99 L 98.927,184.95 L 96.429,185.91 L 93.931,186.68 L 91.53,187.25 L 88.936,187.83 L 86.438,188.31 L 84.037,188.5 L 81.539,188.6 L 78.753,188.6 L 76.352,188.5 L 73.854,188.21 L 71.356,187.93 L 68.859,187.45 L 66.361,186.97 L 64.151,186.3 L 61.846,185.34 L 59.348,184.47 L 57.235,183.42 L 54.833,182.27 L 52.816,181.02 L 50.702,179.77 L 48.685,178.24 L 46.668,176.71 L 44.746,174.98 L 42.921,173.16 L 41.096,171.34 L 39.463,169.42 L 37.926,167.4 L 36.389,165.29 L 35.044,162.99 L 33.795,160.6 L 25.534,164.81 L 27.167,167.6 L 28.704,170.09 L 30.433,172.77 L 32.354,175.17 L 34.372,177.47 L 36.389,179.68 L 38.598,181.69 L 40.712,183.61 L 43.113,185.53 L 45.515,187.25 L 48.013,188.88 L 50.606,190.32 L 53.2,191.67 L 55.89,192.91 L 58.58,193.97 L 61.27,194.93 L 64.248,195.79 L 67.129,196.46 L 70.011,196.94 L 72.893,197.42 L 75.775,197.71 L 78.753,197.8 L 81.539,197.8 L 84.613,197.71 L 87.591,197.32 L 90.665,196.84 L 93.451,196.27 L 96.429,195.5 L 99.311,194.54 L 102.19,193.58 L 105.07,192.24 L 107.96,190.99 L 107.96,190.99 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 105.84,186.87 L 110.84,183.99 L 115.45,180.64 L 119.58,176.9 L 123.33,172.77 L 126.69,168.36 L 129.47,163.76 L 131.88,158.87 L 133.8,153.79 L 135.14,148.51 L 136.01,143.14 L 136.39,137.77 L 136.3,132.21 L 135.53,126.74 L 134.28,121.37 L 132.45,116 L 130.05,110.73 L 128.61,108.14 L 127.17,105.74 L 125.54,103.34 L 123.81,101.14 L 121.98,99.029 L 120.06,97.015 L 118.04,95.097 L 115.93,93.275 L 113.82,91.549 L 111.61,89.919 L 109.3,88.481 L 106.9,87.138 L 104.5,85.891 L 102,84.741 L 99.503,83.782 L 96.909,82.823 L 94.316,82.055 L 91.722,81.48 L 89.032,81.001 L 86.342,80.617 L 83.556,80.329 L 80.867,80.233 L 78.081,80.233 L 75.391,80.329 L 72.605,80.617 L 69.915,81.096 L 67.129,81.672 L 64.44,82.343 L 61.75,83.206 L 59.06,84.165 L 56.37,85.316 L 53.777,86.563 L 48.781,89.44 L 44.17,92.796 L 40.039,96.536 L 36.293,100.66 L 33.027,104.97 L 30.145,109.67 L 27.743,114.56 L 25.918,119.65 L 24.477,124.83 L 23.612,130.2 L 23.324,135.66 L 23.42,141.13 L 24.189,146.59 L 25.438,152.06 L 27.263,157.43 L 29.664,162.7 L 31.105,165.29 L 32.546,167.69 L 34.179,170.09 L 35.909,172.29 L 37.734,174.4 L 39.655,176.42 L 41.672,178.34 L 43.69,180.16 L 45.899,181.88 L 48.109,183.51 L 50.414,184.95 L 52.72,186.3 L 55.217,187.54 L 57.619,188.69 L 60.213,189.65 L 62.71,190.61 L 65.304,191.38 L 67.994,191.95 L 70.684,192.43 L 73.374,192.82 L 76.063,193.1 L 78.753,193.2 L 81.539,193.2 L 84.325,193.1 L 87.015,192.82 L 89.801,192.34 L 92.49,191.76 L 95.18,191.09 L 97.87,190.23 L 100.56,189.27 L 103.25,188.12 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF000000"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 58.195,51.081 L 20.538,70.548 L 18.809,71.507 L 19.674,73.233 L 37.734,107.85 L 38.022,108.52 L 38.791,108.71 L 38.983,108.81 L 39.367,108.91 L 40.039,109.1 L 40.808,109.19 L 41.769,109.39 L 42.921,109.48 L 44.266,109.58 L 45.707,109.67 L 47.34,109.58 L 49.069,109.48 L 50.991,109.19 L 52.912,108.81 L 55.025,108.24 L 57.139,107.56 L 59.444,106.7 L 61.75,105.55 L 64.632,103.92 L 67.129,102.39 L 69.339,100.76 L 71.26,99.221 L 72.989,97.687 L 74.334,96.248 L 75.487,94.906 L 76.448,93.563 L 77.216,92.316 L 77.889,91.262 L 78.273,90.207 L 78.657,89.44 L 78.849,88.672 L 78.945,88.193 L 79.041,87.809 L 79.041,87.617 L 79.041,87.042 L 78.849,86.467 L 60.789,51.848 L 59.925,50.218 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 60.021,102.1 L 58.292,102.96 L 56.562,103.63 L 54.929,104.21 L 53.392,104.69 L 51.855,105.07 L 50.414,105.36 L 49.069,105.55 L 47.724,105.65 L 46.476,105.74 L 45.419,105.74 L 44.362,105.74 L 43.402,105.65 L 42.537,105.55 L 41.865,105.45 L 41.192,105.36 L 40.712,105.26 L 23.997,73.137 L 58.292,55.396 L 75.103,87.713 L 74.815,88.576 L 74.238,89.823 L 73.278,91.357 L 71.933,93.18 L 70.011,95.193 L 67.418,97.399 L 64.151,99.7 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF000000"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 50.222,155.32 L 47.917,150.33 L 46.284,145.16 L 45.323,140.07 L 44.939,134.89 L 45.131,129.81 L 45.995,124.92 L 47.34,120.22 L 49.262,115.72 L 47.532,116 L 45.995,116.19 L 44.458,116.19 L 43.017,116.19 L 41.672,116.1 L 40.424,115.81 L 39.271,115.52 L 38.214,115.24 L 36.101,119.74 L 34.564,124.44 L 33.699,129.43 L 33.315,134.51 L 33.603,139.79 L 34.564,144.96 L 36.197,150.14 L 38.406,155.22 L 40.135,158.2 L 41.961,160.98 L 44.074,163.66 L 46.284,166.06 L 48.589,168.27 L 51.087,170.28 L 53.68,172.1 L 56.37,173.73 L 59.156,175.17 L 61.942,176.32 L 64.92,177.28 L 67.898,178.05 L 70.876,178.53 L 73.854,178.72 L 76.928,178.72 L 79.906,178.53 L 77.696,177.95 L 75.391,177.28 L 73.181,176.51 L 71.068,175.55 L 68.955,174.5 L 66.937,173.35 L 64.92,172.01 L 62.903,170.57 L 61.077,169.03 L 59.252,167.4 L 57.523,165.68 L 55.89,163.76 L 54.353,161.84 L 52.816,159.73 L 51.471,157.62 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 102.87,110.63 L 98.35,116.29 L 98.734,116.87 L 99.215,117.54 L 99.599,118.11 L 100.08,118.78 L 100.46,119.36 L 100.85,120.03 L 101.14,120.61 L 101.52,121.28 L 101.81,121.76 L 102,122.24 L 102.29,122.72 L 102.48,123.2 L 104.02,122.72 L 108.15,120.7 L 107.67,119.26 L 107.09,117.92 L 106.42,116.58 L 105.84,115.33 L 105.07,114.09 L 104.4,112.84 L 103.63,111.69 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 116.12,113.8 L 115.35,112.45 L 114.59,111.02 L 113.72,109.77 L 112.95,108.43 L 111.99,107.18 L 111.03,105.93 L 110.07,104.69 L 109.11,103.54 L 105.27,108.24 L 106.13,109.39 L 107,110.63 L 107.86,111.98 L 108.63,113.32 L 109.4,114.66 L 110.07,116.19 L 110.74,117.63 L 111.32,119.26 L 117.37,116.48 L 117.08,115.81 L 116.79,115.14 L 116.51,114.47 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 101.71,104.21 L 105.36,99.7 L 104.02,98.742 L 102.58,97.783 L 101.14,96.919 L 99.599,96.056 L 98.062,95.289 L 96.525,94.618 L 94.988,93.947 L 93.355,93.275 L 90.473,98.837 L 91.722,99.221 L 93.067,99.796 L 94.508,100.28 L 95.853,100.95 L 97.294,101.62 L 98.734,102.39 L 100.27,103.25 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 88.744,102.29 L 85.574,108.43 L 86.823,108.81 L 88.167,109.29 L 89.416,109.77 L 90.569,110.35 L 91.818,110.92 L 92.971,111.59 L 94.123,112.26 L 95.18,113.03 L 99.695,107.37 L 98.254,106.41 L 96.813,105.65 L 95.372,104.88 L 94.027,104.21 L 92.586,103.63 L 91.338,103.15 L 89.993,102.67 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 112.95,97.974 L 114.39,99.413 L 115.83,100.95 L 117.18,102.48 L 118.43,104.11 L 119.68,105.84 L 120.93,107.66 L 121.98,109.48 L 123.04,111.4 L 125.15,116.1 L 126.79,120.89 L 127.94,125.69 L 128.61,130.58 L 128.71,135.47 L 128.42,140.36 L 127.55,145.06 L 126.4,149.76 L 124.67,154.27 L 122.56,158.68 L 119.96,162.8 L 117.08,166.73 L 113.72,170.38 L 109.97,173.73 L 105.94,176.71 L 101.42,179.29 L 97.966,180.93 L 94.508,182.27 L 90.953,183.32 L 87.399,184.09 L 83.845,184.67 L 80.29,184.95 L 76.64,184.95 L 73.085,184.67 L 69.627,184.19 L 66.169,183.51 L 62.71,182.56 L 59.348,181.31 L 56.082,179.87 L 53.008,178.24 L 49.934,176.32 L 47.052,174.21 L 50.03,176.8 L 53.104,179.1 L 56.37,181.12 L 59.732,182.94 L 63.287,184.47 L 66.841,185.72 L 70.588,186.68 L 74.334,187.45 L 78.177,187.83 L 82.019,188.02 L 85.958,187.83 L 89.801,187.35 L 93.643,186.58 L 97.486,185.53 L 101.23,184.09 L 104.98,182.36 L 109.49,179.77 L 113.53,176.8 L 117.27,173.45 L 120.64,169.8 L 123.52,165.87 L 126.11,161.75 L 128.23,157.33 L 129.86,152.83 L 131.11,148.13 L 131.88,143.33 L 132.26,138.44 L 132.07,133.55 L 131.49,128.66 L 130.34,123.87 L 128.71,119.07 L 126.59,114.37 L 125.25,111.98 L 123.81,109.67 L 122.17,107.47 L 120.54,105.36 L 118.72,103.34 L 116.89,101.43 L 114.97,99.605 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF383838"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 52.624,63.739 L 69.243,95.865 L 69.723,95.385 L 70.203,95.002 L 70.588,94.522 L 71.068,94.138 L 71.452,93.659 L 71.74,93.275 L 72.125,92.892 L 72.413,92.508 L 56.466,61.725 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF383838"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 47.628,66.328 L 64.728,99.317 L 65.4,98.837 L 66.073,98.358 L 66.649,97.974 L 67.225,97.495 L 50.318,64.89 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF383838"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 44.554,70.26 L 46.187,69.397 L 47.724,68.438 L 49.262,67.575 L 50.702,66.616 L 52.143,65.657 L 53.392,64.698 L 54.641,63.739 L 55.794,62.78 L 56.851,61.821 L 57.811,60.862 L 58.676,59.903 L 59.444,58.944 L 60.117,58.081 L 60.693,57.218 L 61.173,56.355 L 61.462,55.492 L 61.75,54.245 L 61.75,53.19 L 61.558,52.327 L 61.27,51.656 L 61.077,51.368 L 60.885,51.081 L 60.597,50.697 L 60.309,50.409 L 59.925,50.122 L 59.444,49.834 L 58.868,49.546 L 58.292,49.355 L 57.427,49.163 L 56.466,48.971 L 55.41,48.875 L 54.257,48.971 L 53.008,48.971 L 51.759,49.163 L 50.414,49.45 L 49.069,49.738 L 47.532,50.122 L 46.091,50.601 L 44.554,51.081 L 42.921,51.656 L 41.384,52.327 L 39.751,52.999 L 38.022,53.766 L 36.389,54.629 L 34.564,55.588 L 32.642,56.739 L 30.913,57.794 L 29.184,58.944 L 27.551,60.191 L 26.014,61.342 L 24.573,62.588 L 23.228,63.835 L 22.075,65.082 L 21.115,66.328 L 20.346,67.575 L 19.674,68.822 L 19.29,69.972 L 19.193,71.123 L 19.29,72.178 L 19.674,73.233 L 19.866,73.521 L 20.058,73.808 L 20.346,74.096 L 20.634,74.384 L 21.115,74.767 L 21.595,75.055 L 22.075,75.343 L 22.748,75.534 L 23.612,75.726 L 24.573,75.918 L 25.63,75.918 L 26.686,75.918 L 27.935,75.822 L 29.184,75.63 L 30.529,75.439 L 31.97,75.151 L 33.411,74.767 L 34.852,74.288 L 36.389,73.808 L 38.022,73.233 L 39.559,72.562 L 41.192,71.89 L 42.921,71.123 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 23.132,71.411 L 23.132,71.219 L 23.132,71.027 L 23.132,70.836 L 23.228,70.548 L 23.805,69.397 L 24.765,68.055 L 26.11,66.616 L 27.839,64.986 L 29.857,63.26 L 32.354,61.534 L 35.14,59.807 L 38.214,58.081 L 39.847,57.314 L 41.384,56.547 L 42.921,55.876 L 44.458,55.3 L 45.803,54.725 L 47.244,54.245 L 48.589,53.862 L 49.838,53.478 L 50.991,53.286 L 52.143,52.999 L 53.2,52.903 L 54.161,52.807 L 55.025,52.807 L 55.794,52.807 L 56.466,52.903 L 57.043,52.999 L 57.331,53.095 L 57.523,53.19 L 57.715,53.382 L 57.811,53.478 L 57.907,53.766 L 57.811,54.149 L 57.619,54.629 L 57.331,55.204 L 56.947,55.971 L 56.37,56.643 L 55.602,57.506 L 54.833,58.369 L 53.873,59.328 L 52.72,60.287 L 51.471,61.342 L 50.03,62.397 L 48.397,63.451 L 46.668,64.602 L 44.746,65.657 L 42.729,66.808 L 41.096,67.575 L 39.559,68.342 L 38.022,69.013 L 36.485,69.589 L 35.14,70.164 L 33.699,70.644 L 32.354,71.027 L 31.105,71.315 L 29.953,71.603 L 28.8,71.794 L 27.743,71.986 L 26.783,72.082 L 25.918,72.082 L 25.149,72.082 L 24.477,71.986 L 23.901,71.794 L 23.612,71.699 L 23.42,71.603 L 23.228,71.507 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF000000"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 41.769,58.752 L 40.52,57.698 L 39.079,56.451 L 37.542,54.917 L 36.197,53.286 L 35.044,51.56 L 34.179,49.93 L 33.891,48.396 L 34.083,46.957 L 35.332,43.697 L 36.101,41.012 L 36.389,38.614 L 36.197,36.504 L 35.62,34.586 L 34.66,32.86 L 33.507,31.038 L 32.066,29.12 L 31.586,28.545 L 31.105,27.874 L 30.625,27.298 L 30.145,26.627 L 30.145,26.627 L 29.568,26.148 L 28.896,25.86 L 28.127,25.86 L 27.455,26.243 L 26.975,26.819 L 26.686,27.49 L 26.686,28.257 L 26.975,28.929 L 26.975,28.929 L 27.551,29.6 L 28.031,30.271 L 28.512,30.942 L 28.992,31.518 L 30.241,33.052 L 31.201,34.491 L 31.97,35.833 L 32.354,37.272 L 32.45,38.806 L 32.162,40.628 L 31.586,42.834 L 30.529,45.423 L 29.953,48.204 L 30.433,51.081 L 31.778,53.766 L 33.603,56.259 L 35.524,58.369 L 37.446,60.095 L 38.791,61.342 L 39.463,61.821 L 39.463,61.821 L 40.135,62.205 L 40.904,62.205 L 41.576,61.917 L 42.153,61.438 L 42.537,60.766 L 42.537,59.999 L 42.249,59.328 L 41.769,58.752 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FFFF1900"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 59.925,139.59 L 60.597,130.2 L 27.167,127.61 L 26.398,137 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF000000"/>
            </Path.Fill>
        </Path>
    </Canvas>

</UserControl>
Bomb.XAML

  通過使用上述代碼,可使用<bomb:Bomb>元素將炸彈插入到視窗中,就像為主視窗插入Title用戶控制元件一樣,然而,在這個示例中以編程方式創建炸彈更加合理,

三、投彈

  為了投彈,應用程式使用DispatcherTimer,這是一種能很好地用于WPF用戶界面的計時器,因為它在用戶界面執行緒觸發事件,選擇事件間隔,此后DispatcherTime會在該時間間隔內引發周期性的Tick事件,

 // Fires events on the user interface thread.
        private DispatcherTimer bombTimer = new DispatcherTimer();
        public MainWindow()
        {
            InitializeComponent();
            bombTimer.Tick += bombTimer_Tick;
        }

  在BombDropper游戲中,計時器最初被設定為每隔1.3秒引發一次,當用戶單擊按鈕開始游戲時,計時器隨之啟動:

 // Keep track of how many are dropped and stopped.
        private int droppedCount = 0;
        private int savedCount = 0;

// Initially, bombs fall every 1.3 seconds, and hit the ground after 3.5 seconds.
        private double initialSecondsBetweenBombs = 1.3;
        private double initialSecondsToFall = 3.5;
        private double secondsBetweenBombs;
        private double secondsToFall;

// Start the game.
        private void cmdStart_Click(object sender, RoutedEventArgs e)
        {
            cmdStart.IsEnabled = false;

            // Reset the game.
            droppedCount = 0;
            savedCount = 0;
            secondsBetweenBombs = initialSecondsBetweenBombs;
            secondsToFall = initialSecondsToFall;

            // Start bomb dropping events.            
            bombTimer.Interval = TimeSpan.FromSeconds(secondsBetweenBombs);
            bombTimer.Start();
        }

  每次引發計時器事件時,代碼創建一個新的Bomb物件并設定其再Canvas面板上的位置,炸彈放在Canvas面板的頂部邊緣,使其可以無縫地落入試圖,炸彈的水平位置是隨機的,位于Canvas面板的左側和右側之間:

 // Drop a bomb.
        private void bombTimer_Tick(object sender, EventArgs e)
        {
            // Create the bomb.
            Bomb bomb = new Bomb();
            bomb.IsFalling = true;

            // Position the bomb.            
            Random random = new Random();
            bomb.SetValue(Canvas.LeftProperty,
                (double)(random.Next(0, (int)(canvasBackground.ActualWidth - 50))));
            bomb.SetValue(Canvas.TopProperty, -100.0);

           ...
        }

  然后代碼動態創建故事板為炸彈應用影片,這里使用例兩個影片:一個影片通過修改Canvas.Top附加屬性使炸彈下落,另一個影片通過修改旋轉變換的角度使炸彈擺動,因為Storyboard.TargetElement和Storyboard.TargetProperty是附加屬性,所以必須使用Storyboard.SetTargetElement和Storyboard.SetTargetProperty()方法設定它們:

// Attach mouse click event (for defusing the bomb).
            bomb.MouseLeftButtonDown += bomb_MouseLeftButtonDown;

            // Create the animation for the falling bomb.
            Storyboard storyboard = new Storyboard();
            DoubleAnimation fallAnimation = new DoubleAnimation();
            fallAnimation.To = canvasBackground.ActualHeight;
            fallAnimation.Duration = TimeSpan.FromSeconds(secondsToFall);

            Storyboard.SetTarget(fallAnimation, bomb);
            Storyboard.SetTargetProperty(fallAnimation, new PropertyPath("(Canvas.Top)"));
            storyboard.Children.Add(fallAnimation);

            // Create the animation for the bomb "wiggle."
            DoubleAnimation wiggleAnimation = new DoubleAnimation();
            wiggleAnimation.To = 30;
            wiggleAnimation.Duration = TimeSpan.FromSeconds(0.2);
            wiggleAnimation.RepeatBehavior = RepeatBehavior.Forever;
            wiggleAnimation.AutoReverse = true;

            Storyboard.SetTarget(wiggleAnimation, ((TransformGroup)bomb.RenderTransform).Children[0]);
            Storyboard.SetTargetProperty(wiggleAnimation, new PropertyPath("Angle"));
            storyboard.Children.Add(wiggleAnimation);

  這兩個影片均可使用影片緩動以得到更逼真的行為,但這個示例使用基本的線性影片以使代碼保持簡單,

  新創建的故事板存盤在字典集合中,從而可以在其他事件處理程式中很容易地檢索故事板,字典集合存盤為主視窗類的一個欄位:

// Make it possible to look up a storyboard based on a bomb.
private Dictionary<Bomb, Storyboard> storyboards = new Dictionary<Bomb, Storyboard>();

  下面的代碼將故事板添加到跟蹤集合中:

...
// Add the storyboard to the tracking collection.            
storyboards.Add(bomb, storyboard);
...

  接下來,關聯當故事板結束fallAnimation影片時進行回應的事件處理程式,當炸彈落地時fallAnimation影片結束,最后,啟動股市板并執行影片:

 // Configure and start the storyboard.
storyboard.Duration = fallAnimation.Duration;
storyboard.Completed += storyboard_Completed;
storyboard.Begin();

  用于投彈的代碼還需要最后一個細節,隨著游戲的進行,游戲難度加大,更頻繁地引發計時器事件,從而炸彈之間的距離越來越近,并且介紹了下落時間,為實作這些變化,每經過一定的時間間隔就調整一次計時器代碼,默認情況下,BombDropper每隔15秒調整一次,下面是控制調整的欄位:

// "Adjustments" happen periodically, increasing the speed of bomb
// falling and shortening the time between bombs.
private DateTime lastAdjustmentTime = DateTime.MinValue;

// Perform an adjustment every 15 seconds.
private double secondsBetweenAdjustments = 15;
// After every adjustment, shave 0.1 seconds off both.
private double secondsBetweenBombsReduction = 0.1;
private double secondsToFallReduction = 0.1;

  下面的代碼位于DispatcherTime.Tick事件處理程式的末尾處,這些代碼檢查是否需要對計時器進行一次調整,并執行適當的修改:

// Perform an "adjustment" when needed.
            if ((DateTime.Now.Subtract(lastAdjustmentTime).TotalSeconds >
                secondsBetweenAdjustments))
            {
                lastAdjustmentTime = DateTime.Now;

                secondsBetweenBombs -= secondsBetweenBombsReduction;
                secondsToFall -= secondsToFallReduction;

                // (Technically, you should check for 0 or negative values.
                // However, in practice these won't occur because the game will
                // always end first.)

                // Set the timer to drop the next bomb at the appropriate time.
                bombTimer.Interval = TimeSpan.FromSeconds(secondsBetweenBombs);

                // Update the status message.
                lblRate.Text = String.Format("A bomb is released every {0} seconds.",
                    secondsBetweenBombs);
                lblSpeed.Text = String.Format("Each bomb takes {0} seconds to fall.",
                    secondsToFall);
            }

  通過上面的代碼,這款游戲已經具有以不斷增加的速率投彈的功能,不過,游戲仍缺少回應炸彈落下以及被拆除的代碼,

四、攔截炸彈

  用戶通過在炸彈達到Canvas面板底部之前單擊炸彈來進行拆除,因為每個炸彈都是單獨的Bomb用戶控制元件實體,所以攔截滑鼠單擊很容易——需要做的全部作業就是處理MouseLeftButtonDown事件,當單擊炸彈的任意部分時會引發該事件(但如果單擊背景上的某個地方,例如炸彈圈邊緣的周圍,不會引發該事件),

  當單擊炸彈時,第一步是獲取適當的炸彈物件,并設定其IsFalling屬性以指示不再下降(在處理影片完成的事件處理程式中會使用IsFalling屬性),

private void bomb_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            // Get the bomb.
            Bomb bomb = (Bomb)sender;
            bomb.IsFalling = false;

            // Get the bomb's current position.
            Storyboard storyboard = storyboards[bomb];
            double currentTop = Canvas.GetTop(bomb);
            ...
           }

  接下來查找控制炸彈的影片的故事板,從而可以停止影片,為查找故事板,需要在游戲的跟蹤集合中查找,當前,WPF沒有提供任何查找影響給定元素的影片的標準方式,

// Get the bomb's current position.
Storyboard storyboard = storyboards[bomb];
// Stop the bomb from falling.
storyboard.Stop();

  單擊炸彈后,使用另一個影片集將炸彈移除螢屏,將炸彈拋向上方、拋向左側或右側(屈居于距離哪一側最近),盡管可創建全新的故事板以實作該效果,但BombDropper游戲清空用于炸彈的當前故事板并為其添加新影片,處理完畢后,啟動新的故事板:

// Reuse the existing storyboard, but with new animations.
            // Send the bomb on a new trajectory by animating Canvas.Top
            // and Canvas.Left.
            storyboard.Children.Clear();

            DoubleAnimation riseAnimation = new DoubleAnimation();
            riseAnimation.From = currentTop;
            riseAnimation.To = 0;
            riseAnimation.Duration = TimeSpan.FromSeconds(2);

            Storyboard.SetTarget(riseAnimation, bomb);
            Storyboard.SetTargetProperty(riseAnimation, new PropertyPath("(Canvas.Top)"));
            storyboard.Children.Add(riseAnimation);

            DoubleAnimation slideAnimation = new DoubleAnimation();
            double currentLeft = Canvas.GetLeft(bomb);
            // Throw the bomb off the closest side.
            if (currentLeft < canvasBackground.ActualWidth / 2)
            {
                slideAnimation.To = -100;
            }
            else
            {
                slideAnimation.To = canvasBackground.ActualWidth + 100;
            }
            slideAnimation.Duration = TimeSpan.FromSeconds(1);
            Storyboard.SetTarget(slideAnimation, bomb);
            Storyboard.SetTargetProperty(slideAnimation, new PropertyPath("(Canvas.Left)"));
            storyboard.Children.Add(slideAnimation);

            // Start the new animation.
            storyboard.Duration = slideAnimation.Duration;
            storyboard.Begin();

  現在,游戲已經具有足夠的代碼用于投下炸彈并當用戶拆除它們彈出螢屏,然而,為跟蹤哪些炸彈被拆了以及那些炸彈落下了,需要回應在影片結束時引發的Storyboard.Completed事件,

五、統計炸彈和清理作業

  正如在前面看到的,BombDropper采用兩種方式使用故事板:為下落的炸彈應用影片以及為拆除的炸彈應用影片,可使用不同的事件處理程式處理這些故事板的結束事件,但為使代碼保持簡單,BombDropper只使用一個事件處理程式,通過檢查Bomb.IsFalling屬性來區分爆炸的炸彈和拆除的炸彈,

// End the game at maxDropped.
        private int maxDropped = 5;

        private void storyboard_Completed(object sender, EventArgs e)
        {
            ClockGroup clockGroup = (ClockGroup)sender;

            // Get the first animation in the storyboard, and use it to find the
            // bomb that's being animated.
            DoubleAnimation completedAnimation = (DoubleAnimation)clockGroup.Children[0].Timeline;
            Bomb completedBomb = (Bomb)Storyboard.GetTarget(completedAnimation);

            // Determine if a bomb fell or flew off the Canvas after being clicked.
            if (completedBomb.IsFalling)
            {
                droppedCount++;
            }
            else
            {
                savedCount++;
            }
            ...
        

  無論采用哪種方式,代碼都會接著更新顯示測驗,指示已經落下的拆除的炸彈數量:

// Update the display.
lblStatus.Text = String.Format("You have dropped {0} bombs and saved {1}.",
                droppedCount, savedCount);

  接下來,代碼進行檢查以查看落下炸彈是否達到了最大值,如果達到了最大值,游戲結束,停止計時器并移除所有炸彈和故事板:

 // Check if it's game over.
            if (droppedCount >= maxDropped)
            {
                bombTimer.Stop();
                lblStatus.Text += "\r\n\r\nGame over.";

                // Find all the storyboards that are underway.
                foreach (KeyValuePair<Bomb, Storyboard> item in storyboards)
                {
                    Storyboard storyboard = item.Value;
                    Bomb bomb = item.Key;

                    storyboard.Stop();
                    canvasBackground.Children.Remove(bomb);
                }
                // Empty the tracking collection.
                storyboards.Clear();

                // Allow the user to start a new game.
                cmdStart.IsEnabled = true;
            }
            else
            {
                Storyboard storyboard = (Storyboard)clockGroup.Timeline;
                storyboard.Stop();

                storyboards.Remove(completedBomb);
                canvasBackground.Children.Remove(completedBomb);
            }

  本例完整XAML標記:

<Window x:Class="BombDropper.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="500" Width="600">
    <Grid x:Name="LayoutRoot">
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition Width="280"></ColumnDefinition>
        </Grid.ColumnDefinitions>


        <Border BorderBrush="SteelBlue" BorderThickness="1" Margin="5">
            <Grid>
                <Canvas x:Name="canvasBackground" SizeChanged="canvasBackground_SizeChanged" MinWidth="50">
                    <Canvas.Background>
                        <RadialGradientBrush>
                            <GradientStop Color="AliceBlue" Offset="0"></GradientStop>
                            <GradientStop Color="White" Offset="0.7"></GradientStop>
                        </RadialGradientBrush>
                    </Canvas.Background>
                </Canvas>
            </Grid>
        </Border>

        <Border Grid.Column="1" BorderBrush="SteelBlue" BorderThickness="1" Margin="5">
            <Border.Background>
                <RadialGradientBrush GradientOrigin="1,0.7" Center="1,0.7" RadiusX="1" RadiusY="1">
                    <GradientStop Color="Orange"  Offset="0"></GradientStop>
                    <GradientStop Color="White" Offset="1"></GradientStop>
                </RadialGradientBrush>
            </Border.Background>
            <StackPanel Margin="15" VerticalAlignment="Center" HorizontalAlignment="Center">
                <TextBlock FontFamily="Impact" FontSize="35" Foreground="LightSteelBlue">Bomb Dropper</TextBlock>
                <TextBlock x:Name="lblRate" Margin="0,30,0,0" TextWrapping="Wrap" FontFamily="Georgia" FontSize="14"></TextBlock>
                <TextBlock x:Name="lblSpeed" Margin="0,30" TextWrapping="Wrap" FontFamily="Georgia" FontSize="14"></TextBlock>
                <TextBlock x:Name="lblStatus" 
             TextWrapping="Wrap" FontFamily="Georgia" FontSize="20">No bombs have dropped.</TextBlock>
                <Button x:Name="cmdStart" Padding="5" Margin="0,30" Width="80" Content="Start Game" Click="cmdStart_Click"></Button>
            </StackPanel>

        </Border>
    </Grid>
</Window>
BombDropper.xaml
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace BombDropper
{
    /// <summary>
    /// MainWindow.xaml 的互動邏輯
    /// </summary>
    public partial class MainWindow : Window
    {
        // Fires events on the user interface thread.
        private DispatcherTimer bombTimer = new DispatcherTimer();
        public MainWindow()
        {
            InitializeComponent();
            bombTimer.Tick += bombTimer_Tick;
        }
        private void canvasBackground_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            RectangleGeometry rect = new RectangleGeometry();
            rect.Rect = new Rect(0, 0, canvasBackground.ActualWidth, canvasBackground.ActualHeight);
            canvasBackground.Clip = rect;
        }

        // "Adjustments" happen periodically, increasing the speed of bomb
        // falling and shortening the time between bombs.
        private DateTime lastAdjustmentTime = DateTime.MinValue;

        // Perform an adjustment every 15 seconds.
        private double secondsBetweenAdjustments = 15;

        // Initially, bombs fall every 1.3 seconds, and hit the ground after 3.5 seconds.
        private double initialSecondsBetweenBombs = 1.3;
        private double initialSecondsToFall = 3.5;
        private double secondsBetweenBombs;
        private double secondsToFall;

        // After every adjustment, shave 0.1 seconds off both.
        private double secondsBetweenBombsReduction = 0.1;
        private double secondsToFallReduction = 0.1;

        // Make it possible to look up a storyboard based on a bomb.
        private Dictionary<Bomb, Storyboard> storyboards = new Dictionary<Bomb, Storyboard>();

        

        // Start the game.
        private void cmdStart_Click(object sender, RoutedEventArgs e)
        {
            cmdStart.IsEnabled = false;

            // Reset the game.
            droppedCount = 0;
            savedCount = 0;
            secondsBetweenBombs = initialSecondsBetweenBombs;
            secondsToFall = initialSecondsToFall;

            // Start bomb dropping events.            
            bombTimer.Interval = TimeSpan.FromSeconds(secondsBetweenBombs);
            bombTimer.Start();
        }

        // Drop a bomb.
        private void bombTimer_Tick(object sender, EventArgs e)
        {
            // Perform an "adjustment" when needed.
            if ((DateTime.Now.Subtract(lastAdjustmentTime).TotalSeconds >
                secondsBetweenAdjustments))
            {
                lastAdjustmentTime = DateTime.Now;

                secondsBetweenBombs -= secondsBetweenBombsReduction;
                secondsToFall -= secondsToFallReduction;

                // (Technically, you should check for 0 or negative values.
                // However, in practice these won't occur because the game will
                // always end first.)

                // Set the timer to drop the next bomb at the appropriate time.
                bombTimer.Interval = TimeSpan.FromSeconds(secondsBetweenBombs);

                // Update the status message.
                lblRate.Text = String.Format("A bomb is released every {0} seconds.",
                    secondsBetweenBombs);
                lblSpeed.Text = String.Format("Each bomb takes {0} seconds to fall.",
                    secondsToFall);
            }

            // Create the bomb.
            Bomb bomb = new Bomb();
            bomb.IsFalling = true;

            // Position the bomb.            
            Random random = new Random();
            bomb.SetValue(Canvas.LeftProperty,
                (double)(random.Next(0, (int)(canvasBackground.ActualWidth - 50))));
            bomb.SetValue(Canvas.TopProperty, -100.0);

            // Attach mouse click event (for defusing the bomb).
            bomb.MouseLeftButtonDown += bomb_MouseLeftButtonDown;

            // Create the animation for the falling bomb.
            Storyboard storyboard = new Storyboard();
            DoubleAnimation fallAnimation = new DoubleAnimation();
            fallAnimation.To = canvasBackground.ActualHeight;
            fallAnimation.Duration = TimeSpan.FromSeconds(secondsToFall);

            Storyboard.SetTarget(fallAnimation, bomb);
            Storyboard.SetTargetProperty(fallAnimation, new PropertyPath("(Canvas.Top)"));
            storyboard.Children.Add(fallAnimation);

            // Create the animation for the bomb "wiggle."
            DoubleAnimation wiggleAnimation = new DoubleAnimation();
            wiggleAnimation.To = 30;
            wiggleAnimation.Duration = TimeSpan.FromSeconds(0.2);
            wiggleAnimation.RepeatBehavior = RepeatBehavior.Forever;
            wiggleAnimation.AutoReverse = true;

            Storyboard.SetTarget(wiggleAnimation, ((TransformGroup)bomb.RenderTransform).Children[0]);
            Storyboard.SetTargetProperty(wiggleAnimation, new PropertyPath("Angle"));
            storyboard.Children.Add(wiggleAnimation);

            // Add the bomb to the Canvas.
            canvasBackground.Children.Add(bomb);

            // Add the storyboard to the tracking collection.            
            storyboards.Add(bomb, storyboard);

            // Configure and start the storyboard.
            storyboard.Duration = fallAnimation.Duration;
            storyboard.Completed += storyboard_Completed;
            storyboard.Begin();
        }

        private void bomb_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            // Get the bomb.
            Bomb bomb = (Bomb)sender;
            bomb.IsFalling = false;

            // Get the bomb's current position.
            Storyboard storyboard = storyboards[bomb];
            double currentTop = Canvas.GetTop(bomb);

            // Stop the bomb from falling.
            storyboard.Stop();

            // Reuse the existing storyboard, but with new animations.
            // Send the bomb on a new trajectory by animating Canvas.Top
            // and Canvas.Left.
            storyboard.Children.Clear();

            DoubleAnimation riseAnimation = new DoubleAnimation();
            riseAnimation.From = currentTop;
            riseAnimation.To = 0;
            riseAnimation.Duration = TimeSpan.FromSeconds(2);

            Storyboard.SetTarget(riseAnimation, bomb);
            Storyboard.SetTargetProperty(riseAnimation, new PropertyPath("(Canvas.Top)"));
            storyboard.Children.Add(riseAnimation);

            DoubleAnimation slideAnimation = new DoubleAnimation();
            double currentLeft = Canvas.GetLeft(bomb);
            // Throw the bomb off the closest side.
            if (currentLeft < canvasBackground.ActualWidth / 2)
            {
                slideAnimation.To = -100;
            }
            else
            {
                slideAnimation.To = canvasBackground.ActualWidth + 100;
            }
            slideAnimation.Duration = TimeSpan.FromSeconds(1);
            Storyboard.SetTarget(slideAnimation, bomb);
            Storyboard.SetTargetProperty(slideAnimation, new PropertyPath("(Canvas.Left)"));
            storyboard.Children.Add(slideAnimation);

            // Start the new animation.
            storyboard.Duration = slideAnimation.Duration;
            storyboard.Begin();
        }

        // Keep track of how many are dropped and stopped.
        private int droppedCount = 0;
        private int savedCount = 0;

        // End the game at maxDropped.
        private int maxDropped = 5;

        private void storyboard_Completed(object sender, EventArgs e)
        {
            ClockGroup clockGroup = (ClockGroup)sender;

            // Get the first animation in the storyboard, and use it to find the
            // bomb that's being animated.
            DoubleAnimation completedAnimation = (DoubleAnimation)clockGroup.Children[0].Timeline;
            Bomb completedBomb = (Bomb)Storyboard.GetTarget(completedAnimation);

            // Determine if a bomb fell or flew off the Canvas after being clicked.
            if (completedBomb.IsFalling)
            {
                droppedCount++;
            }
            else
            {
                savedCount++;
            }

            // Update the display.
            lblStatus.Text = String.Format("You have dropped {0} bombs and saved {1}.",
                droppedCount, savedCount);

            // Check if it's game over.
            if (droppedCount >= maxDropped)
            {
                bombTimer.Stop();
                lblStatus.Text += "\r\n\r\nGame over.";

                // Find all the storyboards that are underway.
                foreach (KeyValuePair<Bomb, Storyboard> item in storyboards)
                {
                    Storyboard storyboard = item.Value;
                    Bomb bomb = item.Key;

                    storyboard.Stop();
                    canvasBackground.Children.Remove(bomb);
                }
                // Empty the tracking collection.
                storyboards.Clear();

                // Allow the user to start a new game.
                cmdStart.IsEnabled = true;
            }
            else
            {
                Storyboard storyboard = (Storyboard)clockGroup.Timeline;
                storyboard.Stop();

                storyboards.Remove(completedBomb);
                canvasBackground.Children.Remove(completedBomb);
            }
        }
    }
}
BombDropper.xaml.cs
<UserControl x:Class="BombDropper.Bomb"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            >
    <UserControl.RenderTransform>
        <TransformGroup>
            <RotateTransform Angle="20"  CenterX="50" CenterY="50"></RotateTransform>
            <ScaleTransform ScaleX="0.5" ScaleY="0.5"></ScaleTransform>
        </TransformGroup>
    </UserControl.RenderTransform>
    <Canvas>
        <Path Data="M 11.989,50.026 L 24.381,37.08 L 19.097,53.862 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FFF2CC0C"/>
            </Path.Fill>
        </Path>
        <Path Data="M 0.46098,31.997 L 17.945,28.449 L 4.1114,39.19 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FFF2CC0C"/>
            </Path.Fill>
        </Path>
        <Path Data="M 9.9713,7.3517 L 22.075,20.49 L 5.7445,14.16 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FFF2CC0C"/>
            </Path.Fill>
        </Path>
        <Path Data="M 58.484,29.408 L 40.712,31.997 L 57.523,37.367 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FFF2CC0C"/>
            </Path.Fill>
        </Path>
        <Path Data="M 51.663,10.229 L 38.694,22.408 L 55.506,17.325 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FFF2CC0C"/>
            </Path.Fill>
        </Path>
        <Path Data="M 32.354,0.25535 L 31.682,18.092 L 40.039,2.7487 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FFF2CC0C"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 105.84,186.87 L 110.84,183.99 L 115.45,180.64 L 119.58,176.9 L 123.33,172.77 L 126.69,168.36 L 129.47,163.76 L 131.88,158.87 L 133.8,153.79 L 135.14,148.51 L 136.01,143.14 L 136.39,137.77 L 136.3,132.21 L 135.53,126.74 L 134.28,121.37 L 132.45,116 L 130.05,110.73 L 128.61,108.14 L 127.17,105.74 L 125.54,103.34 L 123.81,101.14 L 121.98,99.029 L 120.06,97.015 L 118.04,95.097 L 115.93,93.275 L 113.82,91.549 L 111.61,89.919 L 109.3,88.481 L 106.9,87.138 L 104.5,85.891 L 102,84.741 L 99.503,83.782 L 96.909,82.823 L 94.316,82.055 L 91.722,81.48 L 89.032,81.001 L 86.342,80.617 L 83.556,80.329 L 80.867,80.233 L 78.081,80.233 L 75.391,80.329 L 72.605,80.617 L 69.915,81.096 L 67.129,81.672 L 64.44,82.343 L 61.75,83.206 L 59.06,84.165 L 56.37,85.316 L 53.777,86.563 L 48.781,89.44 L 44.17,92.796 L 40.039,96.536 L 36.293,100.66 L 33.027,104.97 L 30.145,109.67 L 27.743,114.56 L 25.918,119.65 L 24.477,124.83 L 23.612,130.2 L 23.324,135.66 L 23.42,141.13 L 24.189,146.59 L 25.438,152.06 L 27.263,157.43 L 29.664,162.7 L 31.105,165.29 L 32.546,167.69 L 34.179,170.09 L 35.909,172.29 L 37.734,174.4 L 39.655,176.42 L 41.672,178.34 L 43.69,180.16 L 45.899,181.88 L 48.109,183.51 L 50.414,184.95 L 52.72,186.3 L 55.217,187.54 L 57.619,188.69 L 60.213,189.65 L 62.71,190.61 L 65.304,191.38 L 67.994,191.95 L 70.684,192.43 L 73.374,192.82 L 76.063,193.1 L 78.753,193.2 L 81.539,193.2 L 84.325,193.1 L 87.015,192.82 L 89.801,192.34 L 92.49,191.76 L 95.18,191.09 L 97.87,190.23 L 100.56,189.27 L 103.25,188.12 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="F 1 M 125.92,112.84 L 125.92,112.84 L 128.13,117.63 L 129.86,122.62 L 131.01,127.51 L 131.68,132.5 L 131.78,137.68 L 131.4,142.66 L 130.63,147.65 L 129.38,152.44 L 127.65,157.05 L 125.44,161.55 L 122.94,165.77 L 119.77,169.9 L 116.31,173.64 L 112.57,177.09 L 108.34,180.16 L 103.73,182.75 L 107.96,190.99 L 113.34,187.83 L 118.33,184.19 L 122.85,180.16 L 126.88,175.65 L 130.44,170.95 L 133.51,165.97 L 136.1,160.69 L 138.22,155.13 L 139.66,149.38 L 140.62,143.62 L 141,137.87 L 140.91,131.92 L 140.04,125.98 L 138.7,120.13 L 136.78,114.37 L 134.18,108.62 L 134.18,108.62 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="F 1 M 55.89,90.686 L 55.89,90.686 L 58.195,89.44 L 60.693,88.481 L 63.191,87.522 L 65.688,86.754 L 68.09,86.179 L 70.78,85.604 L 73.181,85.124 L 75.679,84.932 L 78.081,84.836 L 80.867,84.836 L 83.268,84.932 L 85.862,85.22 L 88.36,85.508 L 90.857,85.987 L 93.163,86.467 L 95.468,87.138 L 97.87,88.097 L 100.27,88.96 L 102.48,90.015 L 104.79,91.166 L 107,92.412 L 109.01,93.659 L 111.03,95.193 L 112.95,96.728 L 114.97,98.454 L 116.79,100.28 L 118.62,102.1 L 120.25,104.02 L 121.79,106.03 L 123.33,108.14 L 124.67,110.44 L 125.92,112.84 L 134.18,108.62 L 132.55,105.84 L 131.01,103.34 L 129.28,100.66 L 127.36,98.262 L 125.34,95.961 L 123.33,93.755 L 121.12,91.741 L 118.91,89.823 L 116.6,87.905 L 114.2,86.179 L 111.61,84.549 L 109.01,83.11 L 106.52,81.768 L 103.73,80.521 L 101.14,79.466 L 98.35,78.507 L 95.468,77.644 L 92.586,76.973 L 89.704,76.493 L 86.823,76.014 L 83.845,75.726 L 80.867,75.63 L 78.081,75.63 L 75.103,75.726 L 72.029,76.11 L 69.051,76.589 L 66.169,77.165 L 63.191,77.932 L 60.309,78.891 L 57.427,79.85 L 54.545,81.192 L 51.663,82.439 L 51.663,82.439 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="F 1 M 33.795,160.6 L 33.795,160.6 L 31.586,155.8 L 29.857,150.81 L 28.704,145.83 L 28.031,140.84 L 27.935,135.66 L 28.223,130.68 L 28.992,125.78 L 30.337,120.99 L 31.97,116.29 L 34.179,111.88 L 36.773,107.56 L 39.847,103.54 L 43.306,99.796 L 47.052,96.344 L 51.279,93.275 L 55.89,90.686 L 51.663,82.439 L 46.284,85.604 L 41.288,89.248 L 36.773,93.275 L 32.738,97.783 L 29.28,102.39 L 26.11,107.47 L 23.516,112.84 L 21.499,118.3 L 19.962,123.87 L 19.001,129.72 L 18.713,135.66 L 18.809,141.42 L 19.674,147.36 L 21.019,153.31 L 22.94,159.06 L 25.534,164.81 L 25.534,164.81 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="F 1 M 103.73,182.75 L 103.73,182.75 L 101.42,183.99 L 98.927,184.95 L 96.429,185.91 L 93.931,186.68 L 91.53,187.25 L 88.936,187.83 L 86.438,188.31 L 84.037,188.5 L 81.539,188.6 L 78.753,188.6 L 76.352,188.5 L 73.854,188.21 L 71.356,187.93 L 68.859,187.45 L 66.361,186.97 L 64.151,186.3 L 61.846,185.34 L 59.348,184.47 L 57.235,183.42 L 54.833,182.27 L 52.816,181.02 L 50.702,179.77 L 48.685,178.24 L 46.668,176.71 L 44.746,174.98 L 42.921,173.16 L 41.096,171.34 L 39.463,169.42 L 37.926,167.4 L 36.389,165.29 L 35.044,162.99 L 33.795,160.6 L 25.534,164.81 L 27.167,167.6 L 28.704,170.09 L 30.433,172.77 L 32.354,175.17 L 34.372,177.47 L 36.389,179.68 L 38.598,181.69 L 40.712,183.61 L 43.113,185.53 L 45.515,187.25 L 48.013,188.88 L 50.606,190.32 L 53.2,191.67 L 55.89,192.91 L 58.58,193.97 L 61.27,194.93 L 64.248,195.79 L 67.129,196.46 L 70.011,196.94 L 72.893,197.42 L 75.775,197.71 L 78.753,197.8 L 81.539,197.8 L 84.613,197.71 L 87.591,197.32 L 90.665,196.84 L 93.451,196.27 L 96.429,195.5 L 99.311,194.54 L 102.19,193.58 L 105.07,192.24 L 107.96,190.99 L 107.96,190.99 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 105.84,186.87 L 110.84,183.99 L 115.45,180.64 L 119.58,176.9 L 123.33,172.77 L 126.69,168.36 L 129.47,163.76 L 131.88,158.87 L 133.8,153.79 L 135.14,148.51 L 136.01,143.14 L 136.39,137.77 L 136.3,132.21 L 135.53,126.74 L 134.28,121.37 L 132.45,116 L 130.05,110.73 L 128.61,108.14 L 127.17,105.74 L 125.54,103.34 L 123.81,101.14 L 121.98,99.029 L 120.06,97.015 L 118.04,95.097 L 115.93,93.275 L 113.82,91.549 L 111.61,89.919 L 109.3,88.481 L 106.9,87.138 L 104.5,85.891 L 102,84.741 L 99.503,83.782 L 96.909,82.823 L 94.316,82.055 L 91.722,81.48 L 89.032,81.001 L 86.342,80.617 L 83.556,80.329 L 80.867,80.233 L 78.081,80.233 L 75.391,80.329 L 72.605,80.617 L 69.915,81.096 L 67.129,81.672 L 64.44,82.343 L 61.75,83.206 L 59.06,84.165 L 56.37,85.316 L 53.777,86.563 L 48.781,89.44 L 44.17,92.796 L 40.039,96.536 L 36.293,100.66 L 33.027,104.97 L 30.145,109.67 L 27.743,114.56 L 25.918,119.65 L 24.477,124.83 L 23.612,130.2 L 23.324,135.66 L 23.42,141.13 L 24.189,146.59 L 25.438,152.06 L 27.263,157.43 L 29.664,162.7 L 31.105,165.29 L 32.546,167.69 L 34.179,170.09 L 35.909,172.29 L 37.734,174.4 L 39.655,176.42 L 41.672,178.34 L 43.69,180.16 L 45.899,181.88 L 48.109,183.51 L 50.414,184.95 L 52.72,186.3 L 55.217,187.54 L 57.619,188.69 L 60.213,189.65 L 62.71,190.61 L 65.304,191.38 L 67.994,191.95 L 70.684,192.43 L 73.374,192.82 L 76.063,193.1 L 78.753,193.2 L 81.539,193.2 L 84.325,193.1 L 87.015,192.82 L 89.801,192.34 L 92.49,191.76 L 95.18,191.09 L 97.87,190.23 L 100.56,189.27 L 103.25,188.12 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF000000"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 58.195,51.081 L 20.538,70.548 L 18.809,71.507 L 19.674,73.233 L 37.734,107.85 L 38.022,108.52 L 38.791,108.71 L 38.983,108.81 L 39.367,108.91 L 40.039,109.1 L 40.808,109.19 L 41.769,109.39 L 42.921,109.48 L 44.266,109.58 L 45.707,109.67 L 47.34,109.58 L 49.069,109.48 L 50.991,109.19 L 52.912,108.81 L 55.025,108.24 L 57.139,107.56 L 59.444,106.7 L 61.75,105.55 L 64.632,103.92 L 67.129,102.39 L 69.339,100.76 L 71.26,99.221 L 72.989,97.687 L 74.334,96.248 L 75.487,94.906 L 76.448,93.563 L 77.216,92.316 L 77.889,91.262 L 78.273,90.207 L 78.657,89.44 L 78.849,88.672 L 78.945,88.193 L 79.041,87.809 L 79.041,87.617 L 79.041,87.042 L 78.849,86.467 L 60.789,51.848 L 59.925,50.218 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 60.021,102.1 L 58.292,102.96 L 56.562,103.63 L 54.929,104.21 L 53.392,104.69 L 51.855,105.07 L 50.414,105.36 L 49.069,105.55 L 47.724,105.65 L 46.476,105.74 L 45.419,105.74 L 44.362,105.74 L 43.402,105.65 L 42.537,105.55 L 41.865,105.45 L 41.192,105.36 L 40.712,105.26 L 23.997,73.137 L 58.292,55.396 L 75.103,87.713 L 74.815,88.576 L 74.238,89.823 L 73.278,91.357 L 71.933,93.18 L 70.011,95.193 L 67.418,97.399 L 64.151,99.7 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF000000"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 50.222,155.32 L 47.917,150.33 L 46.284,145.16 L 45.323,140.07 L 44.939,134.89 L 45.131,129.81 L 45.995,124.92 L 47.34,120.22 L 49.262,115.72 L 47.532,116 L 45.995,116.19 L 44.458,116.19 L 43.017,116.19 L 41.672,116.1 L 40.424,115.81 L 39.271,115.52 L 38.214,115.24 L 36.101,119.74 L 34.564,124.44 L 33.699,129.43 L 33.315,134.51 L 33.603,139.79 L 34.564,144.96 L 36.197,150.14 L 38.406,155.22 L 40.135,158.2 L 41.961,160.98 L 44.074,163.66 L 46.284,166.06 L 48.589,168.27 L 51.087,170.28 L 53.68,172.1 L 56.37,173.73 L 59.156,175.17 L 61.942,176.32 L 64.92,177.28 L 67.898,178.05 L 70.876,178.53 L 73.854,178.72 L 76.928,178.72 L 79.906,178.53 L 77.696,177.95 L 75.391,177.28 L 73.181,176.51 L 71.068,175.55 L 68.955,174.5 L 66.937,173.35 L 64.92,172.01 L 62.903,170.57 L 61.077,169.03 L 59.252,167.4 L 57.523,165.68 L 55.89,163.76 L 54.353,161.84 L 52.816,159.73 L 51.471,157.62 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 102.87,110.63 L 98.35,116.29 L 98.734,116.87 L 99.215,117.54 L 99.599,118.11 L 100.08,118.78 L 100.46,119.36 L 100.85,120.03 L 101.14,120.61 L 101.52,121.28 L 101.81,121.76 L 102,122.24 L 102.29,122.72 L 102.48,123.2 L 104.02,122.72 L 108.15,120.7 L 107.67,119.26 L 107.09,117.92 L 106.42,116.58 L 105.84,115.33 L 105.07,114.09 L 104.4,112.84 L 103.63,111.69 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 116.12,113.8 L 115.35,112.45 L 114.59,111.02 L 113.72,109.77 L 112.95,108.43 L 111.99,107.18 L 111.03,105.93 L 110.07,104.69 L 109.11,103.54 L 105.27,108.24 L 106.13,109.39 L 107,110.63 L 107.86,111.98 L 108.63,113.32 L 109.4,114.66 L 110.07,116.19 L 110.74,117.63 L 111.32,119.26 L 117.37,116.48 L 117.08,115.81 L 116.79,115.14 L 116.51,114.47 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 101.71,104.21 L 105.36,99.7 L 104.02,98.742 L 102.58,97.783 L 101.14,96.919 L 99.599,96.056 L 98.062,95.289 L 96.525,94.618 L 94.988,93.947 L 93.355,93.275 L 90.473,98.837 L 91.722,99.221 L 93.067,99.796 L 94.508,100.28 L 95.853,100.95 L 97.294,101.62 L 98.734,102.39 L 100.27,103.25 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 88.744,102.29 L 85.574,108.43 L 86.823,108.81 L 88.167,109.29 L 89.416,109.77 L 90.569,110.35 L 91.818,110.92 L 92.971,111.59 L 94.123,112.26 L 95.18,113.03 L 99.695,107.37 L 98.254,106.41 L 96.813,105.65 L 95.372,104.88 L 94.027,104.21 L 92.586,103.63 L 91.338,103.15 L 89.993,102.67 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 112.95,97.974 L 114.39,99.413 L 115.83,100.95 L 117.18,102.48 L 118.43,104.11 L 119.68,105.84 L 120.93,107.66 L 121.98,109.48 L 123.04,111.4 L 125.15,116.1 L 126.79,120.89 L 127.94,125.69 L 128.61,130.58 L 128.71,135.47 L 128.42,140.36 L 127.55,145.06 L 126.4,149.76 L 124.67,154.27 L 122.56,158.68 L 119.96,162.8 L 117.08,166.73 L 113.72,170.38 L 109.97,173.73 L 105.94,176.71 L 101.42,179.29 L 97.966,180.93 L 94.508,182.27 L 90.953,183.32 L 87.399,184.09 L 83.845,184.67 L 80.29,184.95 L 76.64,184.95 L 73.085,184.67 L 69.627,184.19 L 66.169,183.51 L 62.71,182.56 L 59.348,181.31 L 56.082,179.87 L 53.008,178.24 L 49.934,176.32 L 47.052,174.21 L 50.03,176.8 L 53.104,179.1 L 56.37,181.12 L 59.732,182.94 L 63.287,184.47 L 66.841,185.72 L 70.588,186.68 L 74.334,187.45 L 78.177,187.83 L 82.019,188.02 L 85.958,187.83 L 89.801,187.35 L 93.643,186.58 L 97.486,185.53 L 101.23,184.09 L 104.98,182.36 L 109.49,179.77 L 113.53,176.8 L 117.27,173.45 L 120.64,169.8 L 123.52,165.87 L 126.11,161.75 L 128.23,157.33 L 129.86,152.83 L 131.11,148.13 L 131.88,143.33 L 132.26,138.44 L 132.07,133.55 L 131.49,128.66 L 130.34,123.87 L 128.71,119.07 L 126.59,114.37 L 125.25,111.98 L 123.81,109.67 L 122.17,107.47 L 120.54,105.36 L 118.72,103.34 L 116.89,101.43 L 114.97,99.605 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF383838"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 52.624,63.739 L 69.243,95.865 L 69.723,95.385 L 70.203,95.002 L 70.588,94.522 L 71.068,94.138 L 71.452,93.659 L 71.74,93.275 L 72.125,92.892 L 72.413,92.508 L 56.466,61.725 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF383838"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 47.628,66.328 L 64.728,99.317 L 65.4,98.837 L 66.073,98.358 L 66.649,97.974 L 67.225,97.495 L 50.318,64.89 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF383838"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 44.554,70.26 L 46.187,69.397 L 47.724,68.438 L 49.262,67.575 L 50.702,66.616 L 52.143,65.657 L 53.392,64.698 L 54.641,63.739 L 55.794,62.78 L 56.851,61.821 L 57.811,60.862 L 58.676,59.903 L 59.444,58.944 L 60.117,58.081 L 60.693,57.218 L 61.173,56.355 L 61.462,55.492 L 61.75,54.245 L 61.75,53.19 L 61.558,52.327 L 61.27,51.656 L 61.077,51.368 L 60.885,51.081 L 60.597,50.697 L 60.309,50.409 L 59.925,50.122 L 59.444,49.834 L 58.868,49.546 L 58.292,49.355 L 57.427,49.163 L 56.466,48.971 L 55.41,48.875 L 54.257,48.971 L 53.008,48.971 L 51.759,49.163 L 50.414,49.45 L 49.069,49.738 L 47.532,50.122 L 46.091,50.601 L 44.554,51.081 L 42.921,51.656 L 41.384,52.327 L 39.751,52.999 L 38.022,53.766 L 36.389,54.629 L 34.564,55.588 L 32.642,56.739 L 30.913,57.794 L 29.184,58.944 L 27.551,60.191 L 26.014,61.342 L 24.573,62.588 L 23.228,63.835 L 22.075,65.082 L 21.115,66.328 L 20.346,67.575 L 19.674,68.822 L 19.29,69.972 L 19.193,71.123 L 19.29,72.178 L 19.674,73.233 L 19.866,73.521 L 20.058,73.808 L 20.346,74.096 L 20.634,74.384 L 21.115,74.767 L 21.595,75.055 L 22.075,75.343 L 22.748,75.534 L 23.612,75.726 L 24.573,75.918 L 25.63,75.918 L 26.686,75.918 L 27.935,75.822 L 29.184,75.63 L 30.529,75.439 L 31.97,75.151 L 33.411,74.767 L 34.852,74.288 L 36.389,73.808 L 38.022,73.233 L 39.559,72.562 L 41.192,71.89 L 42.921,71.123 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF777777"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 23.132,71.411 L 23.132,71.219 L 23.132,71.027 L 23.132,70.836 L 23.228,70.548 L 23.805,69.397 L 24.765,68.055 L 26.11,66.616 L 27.839,64.986 L 29.857,63.26 L 32.354,61.534 L 35.14,59.807 L 38.214,58.081 L 39.847,57.314 L 41.384,56.547 L 42.921,55.876 L 44.458,55.3 L 45.803,54.725 L 47.244,54.245 L 48.589,53.862 L 49.838,53.478 L 50.991,53.286 L 52.143,52.999 L 53.2,52.903 L 54.161,52.807 L 55.025,52.807 L 55.794,52.807 L 56.466,52.903 L 57.043,52.999 L 57.331,53.095 L 57.523,53.19 L 57.715,53.382 L 57.811,53.478 L 57.907,53.766 L 57.811,54.149 L 57.619,54.629 L 57.331,55.204 L 56.947,55.971 L 56.37,56.643 L 55.602,57.506 L 54.833,58.369 L 53.873,59.328 L 52.72,60.287 L 51.471,61.342 L 50.03,62.397 L 48.397,63.451 L 46.668,64.602 L 44.746,65.657 L 42.729,66.808 L 41.096,67.575 L 39.559,68.342 L 38.022,69.013 L 36.485,69.589 L 35.14,70.164 L 33.699,70.644 L 32.354,71.027 L 31.105,71.315 L 29.953,71.603 L 28.8,71.794 L 27.743,71.986 L 26.783,72.082 L 25.918,72.082 L 25.149,72.082 L 24.477,71.986 L 23.901,71.794 L 23.612,71.699 L 23.42,71.603 L 23.228,71.507 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF000000"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 41.769,58.752 L 40.52,57.698 L 39.079,56.451 L 37.542,54.917 L 36.197,53.286 L 35.044,51.56 L 34.179,49.93 L 33.891,48.396 L 34.083,46.957 L 35.332,43.697 L 36.101,41.012 L 36.389,38.614 L 36.197,36.504 L 35.62,34.586 L 34.66,32.86 L 33.507,31.038 L 32.066,29.12 L 31.586,28.545 L 31.105,27.874 L 30.625,27.298 L 30.145,26.627 L 30.145,26.627 L 29.568,26.148 L 28.896,25.86 L 28.127,25.86 L 27.455,26.243 L 26.975,26.819 L 26.686,27.49 L 26.686,28.257 L 26.975,28.929 L 26.975,28.929 L 27.551,29.6 L 28.031,30.271 L 28.512,30.942 L 28.992,31.518 L 30.241,33.052 L 31.201,34.491 L 31.97,35.833 L 32.354,37.272 L 32.45,38.806 L 32.162,40.628 L 31.586,42.834 L 30.529,45.423 L 29.953,48.204 L 30.433,51.081 L 31.778,53.766 L 33.603,56.259 L 35.524,58.369 L 37.446,60.095 L 38.791,61.342 L 39.463,61.821 L 39.463,61.821 L 40.135,62.205 L 40.904,62.205 L 41.576,61.917 L 42.153,61.438 L 42.537,60.766 L 42.537,59.999 L 42.249,59.328 L 41.769,58.752 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FFFF1900"/>
            </Path.Fill>
        </Path>
        <Path
      Data="M 59.925,139.59 L 60.597,130.2 L 27.167,127.61 L 26.398,137 Z ">
            <Path.Fill>
                <SolidColorBrush Color="#FF000000"/>
            </Path.Fill>
        </Path>
    </Canvas>
</UserControl>
Bomb.xmal
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BombDropper
{
    /// <summary>
    /// Bomb.xaml 的互動邏輯
    /// </summary>
    public partial class Bomb : UserControl
    {
        public Bomb()
        {
            InitializeComponent();
        }
        public bool IsFalling
        {
            get;
            set;
        }
    }
}
Bomb.xmal.cs

  現在已經完成了BombDropper游戲的代碼,然而,可進行諸多改進,例如,可執行如下改進:

  •   為炸彈添加爆炸影片效果,這種效果使炸彈周圍的火焰閃耀或發射在Canvas面板上四處飛濺的炸彈碎片,
  •   為背景添加影片,此改進易于實作,可添加精彩的可視化效果,例如,可創建上移的線性漸變,產生移動感,或創建在兩種顏色之間過渡的效果,
  •   添加深度,實作這一改進比想象得更容易,基本技術是為炸彈設定不同尺寸,更大的炸彈應當具有更高的ZIndex值,確保大炸彈重疊在小炸彈之上,而且應為大炸彈設定更短的影片時間,從而確保他們下落得更快,還可使炸彈半透明,從而當一個炸彈下落時,仍能看到它背后的其他炸彈,
  •   添加音效,可是準確計時的聲音效果以強調炸彈爆炸或拆除,
  •   使用影片緩動,如果希望炸彈在下落、彈離螢屏時加速,或更自然地擺動,可為此處使用的影片緩動函式,并且,正如所期望的,可使用代碼構造緩動函式,就像在XAML中構建緩動函式一樣容易,
  •   調整引數,可為修改行為提供更多細節(例如,當游戲運行時設定如何修改炸彈運動時間、軌跡以及投放頻率的變數),還可插入更多隨機因素(例如,使拆除的炸彈以稍有不同的方式彈離Canvas面板)

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/71839.html

標籤:其他

上一篇:WebApi-控制器路由

下一篇:(26)ASP.NET Core2.2 EF保存(基本保存、保存相關資料、級聯洗掉、使用事務)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more