首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

WPF 開發 2D 遊戲實戰:超級瑪利歐原型

     編輯:關於.NET

專案概覽

使用 WPF 2D 繪圖能力打造超級瑪利歐原型,已實作:角色走動/跳躍動畫、發射子彈、邊界檢測、場景捲軸。未含關卡設計與敵人 AI。

遊戲截圖

動畫實作兩種方案

方案一:Image + ObjectAnimationUsingKeyFrames 切換 Source

<Storyboard x:Key="walkLeftStoryboard">
  <ObjectAnimationUsingKeyFrames Duration="00:00:00.4" RepeatBehavior="Forever"
      Storyboard.TargetName="marioImage" Storyboard.TargetProperty="Source" />
</Storyboard>
<Image Name="marioImage">
  <Image.RenderTransform>
    <TranslateTransform x:Name="marioTranslate" X="0" Y="0"/>
  </Image.RenderTransform>
</Image>

C# 動態新增關鍵幀(需切割大圖,使用 System.Drawing,無法移植 Silverlight):

public static BitmapSource CreateBitmapSource(System.Drawing.Bitmap frame) {
    return Imaging.CreateBitmapSourceFromHBitmap(frame.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
}
internal static void AddKeyFrames(ObjectAnimationUsingKeyFrames animation, params System.Drawing.Bitmap[] frames) {
    double percent = 0, pace = 1.0 / frames.Length;
    foreach (var frame in frames) {
        animation.KeyFrames.Add(new DiscreteObjectKeyFrame(CreateBitmapSource(frame), KeyTime.FromPercent(percent)));
        percent += pace;
    }
}

方案二:ImageBrush + ViewBox 切換(單一圖集)

<Storyboard x:Key="walkLeftStoryboard">
  <ObjectAnimationUsingKeyFrames Duration="00:00:00.4" RepeatBehavior="Forever"
      Storyboard.TargetName="marioImage" Storyboard.TargetProperty="CurrentFrame" />
</Storyboard>
<game:AnimatedImage x:Name="marioImage" Image="/SuperMario;component/Images/mario.png"
    CurrentFrame="0, 0, 0.5, 0.5" Width="134" Height="131">
  <game:AnimatedImage.RenderTransform>
    <TranslateTransform x:Name="marioTranslate" X="0" Y="0"/>
  </game:AnimatedImage.RenderTransform>
</game:AnimatedImage>

自訂控制項 AnimatedImage 模板:

<Style TargetType="local:AnimatedImage">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="local:AnimatedImage">
        <Border BorderThickness="0">
          <Border.Background>
            <ImageBrush ImageSource="{Binding Image, RelativeSource={RelativeSource TemplatedParent}}"
                        Stretch="UniformToFill" AlignmentX="Left" AlignmentY="Top"
                        Viewbox="{Binding CurrentFrame, RelativeSource={RelativeSource TemplatedParent}}"/>
          </Border.Background>
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

C# 新增關鍵幀(使用 Rect 結構):

internal static void AddKeyFrames(ObjectAnimationUsingKeyFrames animation, Rect[] frames) {
    double percent = 0, pace = 1.0 / frames.Length;
    foreach (var frame in frames) {
        animation.KeyFrames.Add(new DiscreteObjectKeyFrame(frame, KeyTime.FromPercent(percent)));
        percent += pace;
    }
}
Silverlight TileBrush 缺少 ViewBox 屬性,此方案無法移植。

遊戲主迴圈

掛載於 CompositionTarget.Rendering 事件:

GameLoop gameLoop;
private void Window_Loaded(object sender, RoutedEventArgs e) {
    gameLoop = new GameLoop(player, Scenes.Level1);
    CompositionTarget.Rendering += CompositionTarget_Rendering;
}
void CompositionTarget_Rendering(object sender, EventArgs e) {
    gameLoop.ProcessChanges();
}

物理與碰撞邏輯

public void ProcessChanges() {
    TimeSpan timeSpan = DateTime.Now - lastTime;
    double step = timeSpan.TotalSeconds;
    lastTime = DateTime.Now;

    double x = Sprite.X, y = Sprite.Y;
    double dx = step * Sprite.Speed;

    // 水平移動與場景捲軸
    if (Sprite.IsWalkingLeft) { x -= dx; Scene.ScrollRight(x, dx); }
    else if (Sprite.IsWalkingRight) { x += dx; Scene.ScrollLeft(x, dx); }
    if (Map.CanMoveTo(x, Sprite.Y, Sprite.Width, Sprite.Height)) Sprite.X = x;

    // 跳躍物理
    if (Sprite.IsJumping) {
        y -= (1 - Sprite.JumpTime) * step * 400;
        if (Sprite.JumpTime < 1 && Map.CanMoveTo(Sprite.X, y, Sprite.Width, Sprite.Height)) {
            Sprite.Y = y; Sprite.JumpTime += step;
        } else { Sprite.IsJumping = false; Sprite.IsFalling = true; Sprite.JumpTime = 0; }
    }
    // 下落物理
    else if (Sprite.IsFalling) {
        y += 800 * Sprite.FallTime * step;
        if (Map.CanMoveTo(Sprite.X, y, Sprite.Width, Sprite.Height)) {
            Sprite.Y = y; Sprite.FallTime += step;
        } else { Sprite.IsFalling = false; Sprite.FallTime = 0; }
    }
    // 站立檢測
    else {
        y += 1;
        if (Map.CanMoveTo(Sprite.X, y, Sprite.Width, Sprite.Height)) {
            Sprite.Y = y; Sprite.IsFalling = true; Sprite.FallTime = step;
        }
    }
}

下一步規劃

改用 XAML 向量圖形繪製動畫與場景物件,優勢:任意縮放不失真、動畫更流暢。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved