Giu*_*ore 8 wpf xna animation xaml
我试图在WPF之外完全使用XAML,特别是在XNA应用程序中.到目前为止,我已经管理(很容易,我很惊讶地承认)从XAML文件中加载我的XNA应用程序中的一些数据.当我决定要为我班级的一个属性设置动画时,问题就开始了......没有任何反应:(
这是我从XAML文件加载的主要类:
[ContentPropertyAttribute("Animation")]
public class Test : FrameworkContentElement
{
public string Text { get; set; }
public Vector2 Position { get; set; }
public Color Color { get; set; }
public Storyboard Animation { get; set; }
public static DependencyProperty RotationProperty =
DependencyProperty.Register("Rotation", typeof(double), typeof(Test), new PropertyMetadata(0.0));
public double Rotation { get { return (double)GetValue(RotationProperty); } set { SetValue(RotationProperty, value); } }
}
Run Code Online (Sandbox Code Playgroud)
这是XAML文件:
<l:Test xmlns:l="clr-namespace:XAMLAndXNA;assembly=XAMLAndXNA"
xmlns:a1="clr-namespace:System.Windows.Media.Animation;assembly=PresentationFramework"
xmlns:a2="clr-namespace:System.Windows.Media.Animation;assembly=PresentationCore"
Text="Testo" Position="55,60" Color="0,255,255,255">
<a1:Storyboard>
<a2:DoubleAnimation a1:Storyboard.TargetProperty="Rotation"
From="0"
To="360"
Duration="00:00:10.0"/>
</a1:Storyboard>
</l:Test>
Run Code Online (Sandbox Code Playgroud)
这是加载和动画启动(尝试):
Test test = XamlReader.Load(new XmlTextReader("SpriteBatchStuff.xaml")) as Test;
test.Animation.Begin(test);
Run Code Online (Sandbox Code Playgroud)
我好奇心死了:)
虽然XAML独立于WPF,但视觉元素却不是.特别是,动画和布局是 WPF的一部分,并且取决于WPF管道存在-通过应用对象,PresentationSource诸如HwndSource,所述XBAP PresentationHost.exe等
因此,您可以在XAML中读取并获取具有子Storyboard对象的Test对象的对象图,但该Test对象在放置在WPF上下文中之前不会连接到动画或布局引擎.XAML给你的所有东西都是一个愚蠢的内存对象图:它是WPF,而不是XAML,它使对象"活着".
正如Ben所说,你可能最终需要自己"推动或刺激"动画.我不知道有关如何执行此操作的任何文档,但是从Reflector中进行探讨,看起来关键API是Storyboard.SeekAlignedToLastTick,其中文档说:
值会立即更新以反映SeekAlignedToLastTick引起的更改,即使屏幕在屏幕更新之前未反映这些更改.
注意第二个条款.通常,WPF会在视觉对象值发生变化时处理屏幕更新.如果您没有使用WPF,那么由您来读取更改后的值并相应地重新绘制屏幕:您没有WPF布局管理器来为您处理它.
最后,请注意我没有测试SeekAlignedToLastTick是否可以在没有加载WPF管道的环境中工作.它听起来应该是这样,因为它不关心它是WPF还是驱动时钟的用户代码,但我无法做出任何承诺......虽然我承认你让我很好奇!
更新:我快速给了它,它似乎确实有效.这是一个在Windows窗体中托管动画的演示(在这种情况下使用普通的'Windows窗体计时器,但在XNA中,我想框架将为您提供游戏计时器 - 没试过,因为我不知道XNA).假设您有一个带有计时器(timer1)和标签(label1)的vanilla窗体,并且该项目引用了WPF程序集.
首先,我的班级简化版:
[ContentProperty("Animation")]
public class Fie : DependencyObject
{
public double Test
{
get { return (double)GetValue(TestProperty); }
set { SetValue(TestProperty, value); }
}
public static readonly DependencyProperty TestProperty =
DependencyProperty.Register("Test", typeof(double), typeof(Fie),
new FrameworkPropertyMetadata(0.0));
public Storyboard Animation { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
现在,WPF代码从XAML加载其中一个婴儿并开始动画:
private Fie _f;
private DateTime _startTime;
public Form1()
{
InitializeComponent();
string xaml =
@"<local:Fie xmlns:local=""clr-namespace:AnimationsOutsideWpf;assembly=AnimationsOutsideWpf""
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty=""Test""
From=""0""
To=""360""
Duration=""00:00:10.0""/>
</Storyboard>
</local:Fie>";
_f = (Fie)XamlReader.Load(XmlReader.Create(new StringReader(xaml)));
Storyboard.SetTarget(_f.Animation, _f);
_f.Animation.Begin();
_startTime = DateTime.Now;
timer1.Enabled = true;
}
Run Code Online (Sandbox Code Playgroud)
请注意,我必须将storyboard的目标设置为我刚刚加载的XAML对象.这不会自动发生.我尝试在XAML中使用Storyboard.TargetName执行此操作,但这似乎不起作用 - 您可能会有更多的运气.
最后一行只是为定时器回调设置:
private void timer1_Tick(object sender, EventArgs e)
{
TimeSpan sinceStart = DateTime.Now - _startTime;
_f.Animation.SeekAlignedToLastTick(sinceStart);
label1.Text = _f.Test.ToString();
}
Run Code Online (Sandbox Code Playgroud)
我已经存储了动画的开始时间,并使用它来计算我们动画的距离.WinForms定时器有点粗糙,但这足以证明概念; 毫无疑问,XNA会有更好的东西.然后我调用Storyboard.SeekAlignedToLastTick,它会更新动画值.没有任何东西会自动显示,因为我的XAML对象没有连接显示,但我可以检查它的Test属性并验证它确实是动画.实际上,我会使用它来更新XAML对象所代表的任何XNA视觉元素的位置或方向.
仅供参考,我现在将记录我如何成功地使用 XNA 来完成这项工作。感谢 itowlson 提供了缺失的链接:否则我必须创建一个带有不可见窗口的空应用程序...
我们在 XAML 中定义该类及其动画(注意 xmlns 指令):
<l:Test
xmlns:l="clr-namespace:XAMLAndXNA;assembly=XAMLAndXNA"
xmlns:a1="clr-namespace:System.Windows.Media.Animation;assembly=PresentationFramework"
xmlns:a2="clr-namespace:System.Windows.Media.Animation;assembly=PresentationCore"
Text="Testo" Position="55,60" Color="0,255,255,255">
<a1:Storyboard>
<a2:DoubleAnimation a1:Storyboard.TargetProperty="Rotation"
From="0"
To="6.28"
Duration="00:00:2.0"
RepeatBehavior="Forever"/>
</a1:Storyboard>
</l:Test>
Run Code Online (Sandbox Code Playgroud)
“代码隐藏”类 Test 如下:
[ContentPropertyAttribute("Animation")]
public class Test : DependencyObject
{
public string Text { get; set; }
public Vector2 Position { get; set; }
public Color Color { get; set; }
public Storyboard Animation { get; set; }
public static DependencyProperty RotationProperty =
DependencyProperty.Register("Rotation", typeof(double), typeof(Test), new PropertyMetadata(0.0));
public double Rotation { get { return (double)GetValue(RotationProperty); } set { SetValue(RotationProperty, value); } }
}
Run Code Online (Sandbox Code Playgroud)
在 XNA Game 类的 Initialize 函数中,我们反序列化 xaml 文件并启动动画:
test = XamlReader.Load(new XmlTextReader("SpriteBatchStuff.xaml")) as Test;
Storyboard.SetTarget(test.Animation, test);
test.Animation.Begin();
Run Code Online (Sandbox Code Playgroud)
Update 函数将 GameTime 作为输入,它提供 TotalGameTime 字段,该字段存储自应用程序启动以来经过的时间量的 TimeSpan:这正是 Storyboard 需要勾选的内容:
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
test.Animation.SeekAlignedToLastTick(gameTime.TotalGameTime);
base.Update(gameTime);
}
Run Code Online (Sandbox Code Playgroud)
在绘制方法中,我们可以使用 Rotation 属性绘制一些文本,现在可以正确地对其进行动画处理:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.DrawString(Content.Load<SpriteFont>("font"), test.Text, test.Position, test.Color, (float)test.Rotation, Vector2.Zero, 1.0f, SpriteEffects.None, 0.0f);
spriteBatch.End();
base.Draw(gameTime);
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1585 次 |
最近记录: |