2

So here is the case. I have a winforms application which is a game. Naturally I want to put some animations like explosions when a bullet hits something. I've tried to achieve this by putting a .gif on my UI, waiting until the animation finishes and then deleting the Control, representing the .gif. I tried achieving that with this code:

public void AnimateAction(Actions Action, int PositionX, int PositionY)
        {
            Thread AnimationThread = null;
                AnimationThread = new Thread(new ThreadStart(() => AnimateAction(Action, PositionX, PositionY, 1500)));
                AnimationThread.Start();
        }

private void AnimateAction(Actions Action, int PositionX, int PositionY, int AnimationDuration)
        {
                Control ActionAnimation = UiHandler.GetInstance().CreateActionItem(Action, PositionX, PositionY);
                this.Controls.Add(ActionAnimation);
                ActionAnimation.BringToFront();

                Thread.Sleep(AnimationDuration);
                this.Controls.Remove(ActionAnimation);

        }

Looks fine, doesn't it? Well.. it is not. Whenever I try to run this code I get an InvalidOperationException thrown, which tells me that I cannot access objects created on other threads. After doing some research on SO and other sources I've realized that I am trying to make unsafe call using threads, which is bad. The way to get around this is to call Invoke() method. However, this causes my animation to be run on the SAME thread that the main window is running, so while the animation thread is sleeping I am forced to wait for the animation to finish before I can see other actions being executed in the UI. Of course, I want to be able to move around etc. while my animation is being animated. How do I achieve this?

Kristof U.
  • 1,263
  • 10
  • 17
Buduls
  • 115
  • 4
  • 12
  • You need to run the animation on your UI thread but if you sleep there everything will freeze. Instead of sleeping should create the control and start a timer. When the timer has been running for the given duration, you can then remove the control. Extending Control with this shouldn't be too difficult. – Neil Smith May 14 '14 at 19:06

1 Answers1

1

I didn't test this code but you have to check if the form itself requires an invoke. Invoke method assures that background thread is synchronized with the main thread. Plus I don't suggest you to use Thread.Sleep.

        public void AnimateAction(Actions Action, int PositionX, int PositionY)
        {
            Thread AnimationThread = null;
                AnimationThread = new Thread(new ThreadStart(() => AnimateAction(Action, PositionX, PositionY, 1500)));
                AnimationThread.Start();
        }

        private void AnimateAction(Actions Action, int PositionX, int PositionY, int AnimationDuration)
        {
            if (form.Controls.InvokeRequired)
            {
                form.Controls.Invoke(new Action(AnimateAction), Action, PositionX, PositionY);
             }
             else
             {
                Control ActionAnimation = UiHandler.GetInstance().CreateActionItem(Action, PositionX, PositionY);
                form.Controls.Add(ActionAnimation);
                ActionAnimation.BringToFront();
                form.Controls.Remove(ActionAnimation);
               }


        }
Bura Chuhadar
  • 3,653
  • 1
  • 14
  • 17
  • This is the code I came up myself when looking for workaround for InvalidOperation exception. And the problem here is that when my animation is being executed I am forced to wait until it is animated. Also - I am up for suggestions, if you have a better way to achieve the animation functionality than Thread.Sleep() I am open for suggestions :) – Buduls May 14 '14 at 19:00
  • @Buduls You can use a timer instead of Thread.Sleep check here: http://stackoverflow.com/questions/14707693/how-to-use-a-timer-to-replace-thread-sleep-in-an-azure-worker-role – Bura Chuhadar May 14 '14 at 19:05