C#XNA SoundEffectMusic落后 [英] C# XNA SoundEffectMusic lagging

查看:65
本文介绍了C#XNA SoundEffectMusic落后的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您好,欢迎来到这个主题。

我先介绍一下布局:



1.计划背景

2.我遇到的问题(音乐滞后)

3.我的想法如何解决它



请注意,第三点(我的想法如何解决它) ),是没有解决问题的想法。然而,这是为了表明我一直在考虑这个问题,并避免将这些解决方案作为答案,因为它不起作用。



我想补充一点,那就是我已经在C#4年工作了,而且XNA工作了4个月。只是为了让你知道你在和谁打交道。但现在,让我们转到话题本身...



1.节目背景

我编写了一个Billard游戏(或者如果是游戏池游戏,你要)。说实话,我用球来球和球到边界碰撞片段,上旋球,以及来自别人项目的幽灵球AI代码(它没有正常工作,我不知道它是否是一个反菜鸟 - 复印机错误,但我不这么想...通常使用矩形解决边界碰撞.Intersects()最好用球半径,距离和数学函数计算...)但其余的是我的工作。游戏有音频类,可以控制音乐。

当一个新游戏开始,一个背景音乐开始播放,并且应该像游戏的背景音乐一样循环。



一个无效的PlayNextMusic()被调用,它只是在线程中调用PlayNextMusic_threaded()。

这会停止当前可能正在播放的任何音乐(意思是背景音乐),并且

创建音乐的新current_instance,稍后播放。

请注意,Audio.Music .....都是结构,包含SoundEffect变量中保存的所有音乐。 />


Hi there and welcome to this thread.
Let me introduce you a layout first:

1. Program background
2. The problem I have (music lagging)
3. My ideas how to solve it

Please notice, that the third point (My ideas how to solve it), were ideas that failed to solve the problem. However, it is here to show that I've been thinking about this problem alot, and to avoid getting these solutions as an answer, because it didn't work.

I would like to add one more thing, and that is that I am working in C# 4 years already, and with XNA like 4 months. Just to give you an idea who are you dealing with. But now, lets move to the topic itself...

1. Program background
I coded a Billard game (or Pool game if you want). To be honest, I used the ball to ball and ball to border collision snippets, topspin calucation, and the ghost ball AI stuff code from someone else's project (it didn't work properly, I dont know whether it was an anti-noob-copier-misstake, but I dont htink so...generally solving the border collision using rectangle.Intersects() is better that calculating with radius of ball, distances and math functions...) but the rest is my work. The game has audio class, wich takes control over music.
when a new game is started, a backgound music starts playing, and is supposed to be looping like background music of the game.

A void PlayNextMusic() is called, and it just calls PlayNextMusic_threaded() in thread.
That stops any music (meaning background music) that may be playing at the moment, and
Creates a new current_instance of the music, wich is later on played.
Please notice, that Audio.Music..... are both structures, containing all music held in SoundEffect variable.

  public struct Audio
        {
            public static SoundEffect CueHit;
            public static SoundEffect WallHit;
            public struct InPocketSounds
            {
                public static List<SoundEffect> sounds = new List<SoundEffect>();
            }
            public struct HitSounds
            {
                public static List<SoundEffect> sounds = new List<SoundEffect>();
            }
            public struct Music
            {
                public static SoundEffectInstance current_instance;
                public static float volume = 0.3f; //0.0f - minimum   1.0f - max
                public static int Index_of_current_music_playing = 0;
                public static List<SoundEffect> music = new List<SoundEffect>();
            }
        }
public static void PlayNextMusic()
        {
            if (MUTE)
                return;

            Thread t = new Thread(PlayNextMusic_threaded);
            t.Priority = ThreadPriority.Highest;
            t.Start();
        }
        public static void PlayNextMusic_threaded()
        {            
            StopMusic(true);

            if (Audio.Music.Index_of_current_music_playing + 1 > Audio.Music.music.Count - 1)
                Audio.Music.Index_of_current_music_playing = 0;


            Audio.Music.current_instance = Audio.Music.music[Audio.Music.Index_of_current_music_playing].CreateInstance();
            Audio.Music.current_instance.Volume = Audio.Music.volume;
            Audio.Music.current_instance.Play();
        }





但请看看电话hiearchy。



Game1是第一个代码运行(在顶部)。它的Update()void调用Menu.Update()来检查菜单中的事件(点击播放图像,点击退出图像等)。当用户点击Play图像(开始新游戏)时,它会调用一个新的游戏Game_Option_clicked(),它会设置新游戏并播放音乐AudioProvider.PlayNextMusic()



为了更容易,这里是架构:



But have a look at the call hiearchy.

Game1 is the first code run (on the top). Its Update() void calls Menu.Update() wich checks for events in menu (clicking on play image, clicking on exit image and so on). When user clicks on Play image (starts new game), it calls a new void Game_Option_clicked(), wich sets up new game AND plays the music AudioProvider.PlayNextMusic()

To make it easier, here is schema:

Game1.Update() -> Menu.Update() -> Game_Option_clicked() -> AudioProvider.PlayNextMusic() -> 
NEW THREAD -> PlayNextMusic_threaded() -> and music plays





现在转移到AI



当用户玩,人工智能玩。因为计算全部(也不是所有的字面意思,请,像40个可能的动作......?)移动需要很长时间,我创建了一个处理它的线程系统。



当用户结束播放时,将调用Play()方法。那主要是调用Play_threaded()IN THREAD。这会产生动作,等等。为了将所有移动添加到数组中,我使用了类似线程系统的东西。现在,请检查代码,我会在代码后继续解释...





Now to move to the AI

When user plays, an AI plays. Because calculating all (nor all literally, please, somthing like 40 possible moves...?) moves takes quite long time, I created a thread system handling it.

When user ends playing, an Play() method is called. That mainly just calls Play_threaded() IN THREAD. That generates the moves, and etc. Now. To add all the moves to the array, I used someething like thread system. Now, please just check the code, and I will continue explaining after the code...

public static void Play()
        {
            if (PoolMechanics.Billard_core.Game_variables.WinStruct.IsGameOver)
                return;

            //only few  sequences of cue will be draws
            PlayerManager.Players[1].Cue_properties.IsCueLocked = true;
            PlayerManager.Players[1].Cue_properties.Cue_Point = new MyVector2D(0, 0);

            //sets the variable so user cant do anything XD
            //PlayerManager.SetSomeonesTurn(false);

            //start in thread so the bonuses, animation and so on will be drawn and rendeered
            Thread t = new Thread(Play_threaded);
            t.Start();

            //variable so player can play is changed IN THREAD because theres a loop waiting for all to be
            //done, wich cant be put in here, because animations of bonuses wouldn't be drawn.
        }
        private static void Play_threaded()
        {          
          //clear previously generated shots
            AI_shoots.Clear();

            Balls_AI_copy = Other.Functions.CopyOneListToAnother(PoolMechanics.Billard_core.Balls);

            PlayerManager.Is_AI_Testing_Shots = true;
            
            //ghost balls
            AllGhostBalls = new List<PoolMechanics.Ball>();
            foreach (PoolMechanics.Ball b in Balls_AI_copy)
            {
                if (b.IsInPocket)
                    continue;

                List<PoolMechanics.Ball> tmp_ghost_balls = GetGhostBalls(b, false);
                foreach (PoolMechanics.Ball ghost_ball in tmp_ghost_balls)
                {                    
                    AllGhostBalls.Add(ghost_ball);
                }
            }
                      
            Threads.active_threads = 0;
            foreach (PoolMechanics.Ball g_ball in AllGhostBalls)
            {
                for (int Strength = 3; Strength < 13; Strength++)
                {
                    Threads.Analyze_Move_in_thread(Strength, g_ball);
                    PlayerManager.Players[1].Cue_properties.Cue_Point = 
                        Other.Functions.FlipPointForCueDirection(g_ball.CentreX, g_ball.CentreY);                   
                }
            }
            Thread.Sleep(2);
            while(Threads.active_threads > 0)
            {
                Thread.Sleep(2000);
            }
           
            //select the best move
            int index = 0;
            int score = int.MinValue;

            int counter = 0;
            lock (AI_shoots)
                foreach (AiShootStruc struc in AI_shoots)
                {
                    if (struc.Score > score)
                    {
                        score = struc.Score;
                        index = counter;
                    }
                    counter++;
                }

            PlayerManager.Is_AI_Testing_Shots = false;

            PlayerManager.Players[1].Cue.Velocity_struc.Selected_velocity = AI_shoots[index].Strength;

            MyVector2D cue_vector = new MyVector2D(AI_shoots[index].CUE_X, AI_shoots[index].CUE_Y);
            PlayerManager.Players[1].Cue_properties.Cue_Point = cue_vector;

            PoolMechanics.Billard_core.StrikedCue(cue_vector, false);

           if(PoolMechanics.FallenBallsProcessing.CanPlayerPlayAgain())
           {
               PlayerManager.SetSomeonesTurn(false);
           }
           else
           {
            //set users turn
            PlayerManager.SetSomeonesTurn(true);
           }           
        }





正如我所说,我创建了一个线程系统来添加移动到数组。

我在这里剪切了代码序列,以便您更容易理解,然后我解释一下。



So as I said, I created a thread system to add the moves to the array.
I cut the sequence of the code here to make it easier to understand for you, and then I explain it.

foreach (PoolMechanics.Ball g_ball in AllGhostBalls)
           {
               for (int Strength = 3; Strength < 13; Strength++)
               {
                   Threads.Analyze_Move_in_thread(Strength, g_ball);
                   PlayerManager.Players[1].Cue_properties.Cue_Point =
                       Other.Functions.FlipPointForCueDirection(g_ball.CentreX, g_ball.CentreY);
               }
           }





所以你看到Threads.Analyze_Move_in_thread(Strength,g_ball);

线程类在同一个类中,只是为了组织代码。



这个想法是:



Threads.Analyze_Move_in_thread调用一个void,调用一个新的void,Analyze_Move_threaded在新的线程。 Analyze_Move_threaded void只做了一些事情,并将移动放到了所有人都可以使用的数组(包括当前的锁定可访问性)。当创建来自Play_threaded()void的新线程时(在上面的for循环中),会增加一个数字变量,计算线程数。然后,Play_threaded()中的代码等待,直到变量为0,以便以其他方式告知,直到所有线程都完成。



您可能会说这是一个糟糕的解决方案,但如果您进一步考虑,如果我不会包含这样的线程系统,它会冻结,并且像这样,它可能在循环中等待线程完成,但是Play_threaded()方法的线程已经被清空......? (thread.sleep(2000)),给应用程序时间做其他的事情,减少工作和优先级,并在线程中泛滥(在我看来)。



再次,我尝试制定呼叫层次结构的整体方案



So. You see the Threads.Analyze_Move_in_thread(Strength, g_ball);
The threads class is in the same class, just to organise the code.

The idea is:

Threads.Analyze_Move_in_thread calls a void, that calls a new void, Analyze_Move_threaded IN NEW THREAD. The Analyze_Move_threaded void just does some stuff, and puts the move to the array that is acesible for all (lock accesibility included ofcourse). When a new thread from Play_threaded() void is created (in the for loop above), a number variable is increased, counting the number of threads. Then, the code in Play_threaded() waits, until the variable is 0, so to tell in in other way, until all threads are finished.

You may say that it is bad solution, but if you think about it further, if i Wouldn't include the thread system like this, it would freeze, and like this, it is maybe waiting in loop until the threads are done, but the thread of Play_threaded() method is sleeped...? (thread.sleep(2000)), wich gives the application time to do other stuff and decrease the work and priority and flood in the thread (in my opinion).

Once again, I try to make overall scheme of the call hiearchy

Game1.Update() //here is checked the user input, like click -> PoolMechanics.Billard_core.StrikedCue() -> NEW THREAD -> PoolMechanics.Billard_core.StrikedCueThreaded() //here is ball movement done and so on, the AI plays -> AI.Play() -> NEW THREAD -> AI.Play_threaded() //moves are generated -> 
AI.Threads.Analyze_Move_in_thread() *** -> NEW THREAD -> Analyze_Move_threaded() //moves are analyzed, and added to an array



请注意我在AI.Threads.Analyze_Move_in_thread()后面写的***。这是因为此时,在调用此方法后,会更改提示位置变量。




Please, notice the "***" I wrote behind the AI.Threads.Analyze_Move_in_thread(). That is because at this moment, after this method is called, a cue location variable is changed.

Threads.Analyze_Move_in_thread(Strength, g_ball);

                    PlayerManager.Players[1].Cue_properties.Cue_Point = 
                        Other.Functions.FlipPointForCueDirection(g_ball.CentreX, g_ball.CentreY);        





在绘制方法中,根据此位置绘制提示,因此我们看到PC如何移动提示。



2.我遇到的问题(音乐滞后)

当提示移动时(PC正在考虑移动,他正在分析它们),音乐是滞后。当PC完成后,打击母球,没关系......



3我的想法如何解决它

我试图将AI线程分配给最低优先级,并将音乐线程分配给最高优先级。我试图增加等待间隔(当AI线程等待所有子线程完成时)。我经历了3次代码以查找是否我错过了一些东西,但是,我没有找到任何东西。我个人的意见是,可能问题出在soundEffect对象或音乐播放的方式......?因为线程似乎是精确完成的。



我会非常感谢任何想法,任何想法,因为我花了几个月做这个项目,我设法绕过了我遇到的所有问题。除了这个。



感谢你的时间,如果你只是将它改为此行。



In draw method, the cue is drawn according to this location, so we see how is PC moving cue.

2. The problem I have (music lagging)
When the cue is moving (PC is thinking about moves, he is analyzing them), the music is lagging. When PC is done and ,,strikes" the cue ball, it is ok...

3 My ideas how to solve it
I tried to assign the AI thread the lowest priority, and the Music thread the highest priority. I tried to increase the waiting interval (when AI thread waits until all sub threads are done). I went through the code like 3 times to find whether I missed something, however, i dod not find anything. My personal opinion is, that maybe the problem is in the soundEffect object or the way the music is played...? Because the threads seem to be done precisely.

I will be really thankfull for any ideas, any ideas at all, because I spent months doing this project, and I managed to bypass all problem I had. Except this one.

Thanks for your time, if you red it just to this line.

推荐答案

你为什么使用新线程播放每个音效?



SoundEffectInstance.Play()p在背景中放置音乐,它不会阻挡。我认为你被卷入了线程,产生了太多。尝试不产生线程,看看你的表现是否有所改善。
Why are you using a new thread to play each sound effect?

SoundEffectInstance.Play() plays the music in the background, its not blocking. I think you are getting caught up in threads, spawning too many. Try it without spawning a thread and see if your performance improves.


这篇关于C#XNA SoundEffectMusic落后的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆