C#吉他英雄克隆,注意动画时间

时间:2012-03-07 16:30:14

标签: c#

我正在使用C#创建一个吉他英雄克隆,并且在同步动画和声音方面遇到了一些麻烦。

我现在所做的事情的简要说明:

  • 读取文件并获取笔记高速公路,记录时间而不是长度(这一切都正确完成)
  • 将笔记放入数组
  • 在歌曲开始之前,我会生成一个故事板,读取整个音符数组,然后创建DoubleAnimations以使矩形对象(音符)向下滚动屏幕。
  • 我将动画的BeginTime设置为预期播放时间之前的1秒(持续时间接近结束),动画持续时间为1秒。然而,我期望发生的事情(同步播放的音符)发生。

以下是创建动画的代码:

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();
            }
        }

    }

我不知道如何解决这个问题,我是否误解了动画的工作原理?使用错误的单位?或者它完全是另一回事?任何提示都非常受欢迎,即使它完全重写我如何显示笔记。

3 个答案:

答案 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时会发生什么,直到显示器。

我希望这是有道理的,我不相信它确实如此:)