我正在使用C#创建一个吉他英雄克隆,并且在同步动画和声音方面遇到了一些麻烦。
我现在所做的事情的简要说明:
以下是创建动画的代码:
private void StartNote(MidiNoteEvent evnt)
{
const double length = 0;
int[] highwayArray = evnt.Highway;
for (int i = 1; i <= highwayArray.Length; i++ )
{
var highway = highwayArray[i-1];
if (highway > 0)
{
string name = evnt.Time.ToString() + "|" + highway.ToString();
var rect = new Rectangle {Tag=name, Height = length+5, Width = 50 };
Canvas.SetTop(rect,-6);
int offset;
if (i == 1)
{
offset = 20;
rect.Fill = new SolidColorBrush(Colors.Green);
}
else if (i == 2)
{
offset = 120;
rect.Fill = new SolidColorBrush(Colors.Red);
}
else if (i == 3)
{
offset = 220;
rect.Fill = new SolidColorBrush(Colors.Yellow);
}
else if (i == 4)
{
offset = 320;
rect.Fill = new SolidColorBrush(Colors.Blue);
}
else
{
offset = 420;
rect.Fill = new SolidColorBrush(Colors.Orange);
}
rect.Margin = new Thickness(offset, 0, 0, 0);
guitarCanvas.Children.Add(rect);
var duration = new Duration(TimeSpan.FromSeconds(1));
var myDoubleAnimation2 = new DoubleAnimation
{Duration = duration, BeginTime = TimeSpan.FromSeconds(evnt.Time-1)};
_notes.Children.Add(myDoubleAnimation2);
Storyboard.SetTarget(myDoubleAnimation2, rect);
// Set the attached properties of Canvas.Left and Canvas.Top
// to be the target properties of the two respective DoubleAnimations
Storyboard.SetTargetProperty(myDoubleAnimation2, new PropertyPath("(Canvas.Top)"));
myDoubleAnimation2.To = guitarCanvas.Height;
myDoubleAnimation2.Completed += new EventHandler(myDoubleAnimation2_Completed);
// Begin the animation.
//sb.Begin();
}
}
}
我不知道如何解决这个问题,我是否误解了动画的工作原理?使用错误的单位?或者它完全是另一回事?任何提示都非常受欢迎,即使它完全重写我如何显示笔记。
答案 0 :(得分:2)
我建议您使用UserControl并使用绘制事件绘制FillRectangle并更改控件的位置以使用Timer Tick事件制作矩形动画。
编辑1 :要提高用户控制的性能并避免闪烁效果,请查看here。
编辑2:计时器在后台运行,启用和禁用它可以像这样写一个公共字段:
private Timer _timer;
public bool TimerEnabled
{
get { return _timer.Enabled; }
set { _timer.Enabled = value; }
}
void InitializeTimer()
{
_timer = new Timer();
_timer.Interval = 1; //One millisecond
_timer.Enabled = false;
_timer.Tick += new EventHandler(_timer_Tick);
}
void _timer_Tick(object sender, EventArgs e)
{
//Example
Location = new Point(Location.X, Location.Y + 1);
}
答案 1 :(得分:2)
你是怎么播放声音的?我做了类似的视频。我在同一个故事板中启动了视频,因为我放置了其他动画,所以他们都在同一个计时器上。所以我的故事板上有一个MediaTimeline,然后将我的其他动画添加到同一个故事板。
工作得很好。只需确保在故事板上将SlipBehavior设置为“Slip”。
在单击按钮的操作中,我有:
<BeginStoryboard Name="playVideoSB">
<Storyboard SlipBehavior="Slip" Completed="Storyboard_Completed" FillBehavior="Stop">
<MediaTimeline Source="{Binding Filename}" Storyboard.TargetName="video" Name="mediaTime"/>
</Storyboard>
</BeginStoryboard>
我在代码中添加了那个故事板,如下所示:
BooleanAnimationUsingKeyFrames bukf = new BooleanAnimationUsingKeyFrames();
Storyboard.SetTargetProperty(bukf, new PropertyPath(PropertyFoo));
Storyboard.SetTarget(bukf, myObject);
bukf.KeyFrames.Add(new DiscreteBooleanKeyFrame(true, KeyTime.FromTimeSpan(start)));
bukf.KeyFrames.Add(new DiscreteBooleanKeyFrame(false, KeyTime.FromTimeSpan(end)));
playVideoSB.Storyboard.Children.Add(bukf);
我碰巧使用布尔动画,但它应该适用于双打。
答案 2 :(得分:1)
我的答案并非特定于C#,而是针对一般的音频/视频同步。它还取决于用于播放声音的音响系统。对我来说,听起来你遇到的问题是你的动画时钟不能与你的音频时钟同步。
通常,当您编写一些必须使音符流与音轨保持同步的代码时,您可以将动画更新直接绑定到声源上的时钟,而不是依赖于渲染器帧事件。
当你说“播放这个动画”时有许多动画系统,在内部更新循环很可能会执行一个可变的时间步动画,逐渐将你的对象从A移动到B到T.这一切都很好,直到你想要的东西与音频定时一样精确地发生(节奏动作游戏的必要性)。我不会详细介绍它背后的细节,但问题的关键在于,你的帧频时钟和音频时间的时钟可能没有完全相同的时间。
解决方案相对简单(虽然我的解释可能不太好):以每帧为基础更新您的音符位置,并且不依赖于动画系统来使其正确。
你知道,因为他们正在向下滚动每个音符在 t 时 STRONG>。使用 t =(来自音频时钟的时间值),您可以计算出在任何给定时间应该使用类似的东西绘制p的位置: p = laneLength - t 其中laneLength是您车道的顶部(假设1.0)。然后音符将与音频时钟准确地向下滚动超过0。当他们点击或传递0时会发生什么,直到显示器。
我希望这是有道理的,我不相信它确实如此:)