WPF 2D 游戏:制作一个跟随 Canvas 上的对象的相机
WPF 2D Game: Making a Camera that follows an object on a Canvas
我正在尝试用 WPF 制作一个简单的 2D 游戏,但遇到了一个我无法解决的问题。
假设我有一个 700x700 Canvas 的播放器,但我的主窗口的宽度和高度设置为 400。
我希望能够有一个类似相机的功能,它跟随 canvas 上的一个矩形对象(这个对象象征着玩家),并在玩家移动时显示 canvas 的相应部分。
理论上我怎样才能实现这样的功能?
WPF 并不是真正适合游戏的技术,最好使用 MonoGame 之类的技术。
不过,要回答您的问题,您可以将 canvas 包装在 ScrollViewer 中:
<ScrollViewer x:Name="theScrollView" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" CanContentScroll="True">
<Canvas x:Name="theCanvas" Width="5000" Height="5000" />
</ScrollViewer>
然后在代码中将视图滚动到相机所在的任何位置:
theScrollView.ScrollToHorizontalOffset(100);
这里有一个关于如何使用 ScrollViewer 执行此操作的粗略示例。使用箭头键移动播放器,同时将其保持在“相机”的视野中。 canvas' 背景设置为径向画笔,以查看相机移动。
MainWindow.xaml
<Window x:Class="WpfApp6.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow"
Background="#222"
Loaded="Window_Loaded"
SizeToContent="WidthAndHeight"
PreviewKeyDown="Window_PreviewKeyDown">
<Grid>
<ScrollViewer x:Name="CanvasViewer"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden">
<Canvas x:Name="Canvas"
IsHitTestVisible="False">
<Canvas.Background>
<RadialGradientBrush>
<GradientStop Offset="0"
Color="Orange" />
<GradientStop Offset="1"
Color="Blue" />
</RadialGradientBrush>
</Canvas.Background>
</Canvas>
</ScrollViewer>
</Grid>
</Window>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
double _playerSize;
Rectangle _playerRect;
Vector _playerPosition;
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
InitializeSizes();
InitializePlayerRect();
}
#region initialize
private void InitializeSizes()
{
_playerSize = 50;
Canvas.Width = 700;
Canvas.Height = 700;
CanvasViewer.Width = 400;
CanvasViewer.Height = 400;
}
private void InitializePlayerRect()
{
_playerRect = new Rectangle
{
Fill = Brushes.Lime,
Width = _playerSize,
Height = _playerSize,
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top
};
Canvas.Children.Add(_playerRect);
}
#endregion
#region move player
private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.Left: MovePlayerLeft(); break;
case Key.Up: MovePlayerUp(); break;
case Key.Right: MovePlayerRight(); break;
case Key.Down: MovePlayerDown(); break;
}
}
private void MovePlayerLeft()
{
var newX = _playerPosition.X - _playerSize;
_playerPosition.X = Math.Max(0, newX);
UpdatePlayerPositionAndCamera();
}
private void MovePlayerUp()
{
var newY = _playerPosition.Y - _playerSize;
_playerPosition.Y = Math.Max(0, newY);
UpdatePlayerPositionAndCamera();
}
private void MovePlayerRight()
{
var newX = _playerPosition.X + _playerSize;
_playerPosition.X = Math.Min(Canvas.Width - _playerSize, newX);
UpdatePlayerPositionAndCamera();
}
private void MovePlayerDown()
{
var newY = _playerPosition.Y + _playerSize;
_playerPosition.Y = Math.Min(Canvas.Height - _playerSize, newY);
UpdatePlayerPositionAndCamera();
}
#endregion
#region update player and camera
private void UpdatePlayerPositionAndCamera()
{
UpdatePlayerPosition();
UpdateCamera();
}
private void UpdatePlayerPosition()
{
// move the playerRect to it's new position
_playerRect.Margin = new Thickness(_playerPosition.X, _playerPosition.Y, 0, 0);
}
private void UpdateCamera()
{
// calculate offset of scrollViewer, relative to actual position of the player
var offsetX = _playerPosition.X / 2;
var offsetY = _playerPosition.Y / 2;
// move the "camera"
CanvasViewer.ScrollToHorizontalOffset(offsetX);
CanvasViewer.ScrollToVerticalOffset(offsetY);
}
#endregion
}
我正在尝试用 WPF 制作一个简单的 2D 游戏,但遇到了一个我无法解决的问题。
假设我有一个 700x700 Canvas 的播放器,但我的主窗口的宽度和高度设置为 400。 我希望能够有一个类似相机的功能,它跟随 canvas 上的一个矩形对象(这个对象象征着玩家),并在玩家移动时显示 canvas 的相应部分。
理论上我怎样才能实现这样的功能?
WPF 并不是真正适合游戏的技术,最好使用 MonoGame 之类的技术。
不过,要回答您的问题,您可以将 canvas 包装在 ScrollViewer 中:
<ScrollViewer x:Name="theScrollView" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" CanContentScroll="True">
<Canvas x:Name="theCanvas" Width="5000" Height="5000" />
</ScrollViewer>
然后在代码中将视图滚动到相机所在的任何位置:
theScrollView.ScrollToHorizontalOffset(100);
这里有一个关于如何使用 ScrollViewer 执行此操作的粗略示例。使用箭头键移动播放器,同时将其保持在“相机”的视野中。 canvas' 背景设置为径向画笔,以查看相机移动。
MainWindow.xaml
<Window x:Class="WpfApp6.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow"
Background="#222"
Loaded="Window_Loaded"
SizeToContent="WidthAndHeight"
PreviewKeyDown="Window_PreviewKeyDown">
<Grid>
<ScrollViewer x:Name="CanvasViewer"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden">
<Canvas x:Name="Canvas"
IsHitTestVisible="False">
<Canvas.Background>
<RadialGradientBrush>
<GradientStop Offset="0"
Color="Orange" />
<GradientStop Offset="1"
Color="Blue" />
</RadialGradientBrush>
</Canvas.Background>
</Canvas>
</ScrollViewer>
</Grid>
</Window>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
double _playerSize;
Rectangle _playerRect;
Vector _playerPosition;
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
InitializeSizes();
InitializePlayerRect();
}
#region initialize
private void InitializeSizes()
{
_playerSize = 50;
Canvas.Width = 700;
Canvas.Height = 700;
CanvasViewer.Width = 400;
CanvasViewer.Height = 400;
}
private void InitializePlayerRect()
{
_playerRect = new Rectangle
{
Fill = Brushes.Lime,
Width = _playerSize,
Height = _playerSize,
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top
};
Canvas.Children.Add(_playerRect);
}
#endregion
#region move player
private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.Left: MovePlayerLeft(); break;
case Key.Up: MovePlayerUp(); break;
case Key.Right: MovePlayerRight(); break;
case Key.Down: MovePlayerDown(); break;
}
}
private void MovePlayerLeft()
{
var newX = _playerPosition.X - _playerSize;
_playerPosition.X = Math.Max(0, newX);
UpdatePlayerPositionAndCamera();
}
private void MovePlayerUp()
{
var newY = _playerPosition.Y - _playerSize;
_playerPosition.Y = Math.Max(0, newY);
UpdatePlayerPositionAndCamera();
}
private void MovePlayerRight()
{
var newX = _playerPosition.X + _playerSize;
_playerPosition.X = Math.Min(Canvas.Width - _playerSize, newX);
UpdatePlayerPositionAndCamera();
}
private void MovePlayerDown()
{
var newY = _playerPosition.Y + _playerSize;
_playerPosition.Y = Math.Min(Canvas.Height - _playerSize, newY);
UpdatePlayerPositionAndCamera();
}
#endregion
#region update player and camera
private void UpdatePlayerPositionAndCamera()
{
UpdatePlayerPosition();
UpdateCamera();
}
private void UpdatePlayerPosition()
{
// move the playerRect to it's new position
_playerRect.Margin = new Thickness(_playerPosition.X, _playerPosition.Y, 0, 0);
}
private void UpdateCamera()
{
// calculate offset of scrollViewer, relative to actual position of the player
var offsetX = _playerPosition.X / 2;
var offsetY = _playerPosition.Y / 2;
// move the "camera"
CanvasViewer.ScrollToHorizontalOffset(offsetX);
CanvasViewer.ScrollToVerticalOffset(offsetY);
}
#endregion
}