Problem bei SpriteAnimation

  • VB.NET

    Problem bei SpriteAnimation

    Ich bin momentan dabei eine kleine Sidescroller Engine aufzubauen. Diese funktioniert mit Direct2D und soll dem Programmierer eine Vielzahl an vorgegebenen Funktionen bieten, welche ihm die Programmierarbeit erleichtern soll.

    Ich habe eine Struktur namens Stage, welche alle Objekte beinhaltet und diese dann zeichnet. Dann habe ich noch eine Klasse namens Sprite, welche ein Objekt mit Bild und eigener Physik darstellen soll, welches man der Stage hinzufügen kann. Außerdem gibt es noch die Klasse Animation, welche einen Array von Bitmaps beinhaltet. Wenn man eine neue Animation instanziiert, dann kann man das Play-Event dieser Animation in einem Sprite aufrufen, sodass dieser Sprite dann in einem angegebenen Abstand sein Image wechselt, wodurch eine Animation entsteht.

    Allerdings funktioniert das Play-Event nicht wie gewollt, da (wie ich per Debugger festgestellt habe) die Variablen immer wieder neu initialisiert werden, und somit nie das nächste Bild angezeigt wird. Ich suche jetzt schon seit ein paar Tagen (keine Scherz!!!) nach irgendeinem dummen Denkfehler, welcher das New-Event der Animation-Struktur immer wieder erneut aufruft.

    Es ist wahrscheinlich einer dieser Fehler, nach denen man tagelang sucht und irgendwann fällt einem auf, dass man eine Anweisung um eine Zeile verschieben muss. Doch mittlerweile bin ich das suchen Leid und hab mich daher entschieden euch mal danach suchen zu lassen.

    Also, viel Spass mit folgendem Code:

    Hauptform:

    Quellcode

    1. Stage Stage1;
    2. Sprite star;
    3. System.Drawing.Bitmap[] Frames = { _2DSidescrollerEngine.Properties.Resources.star_1, _2DSidescrollerEngine.Properties.Resources.star_2, _2DSidescrollerEngine.Properties.Resources.star_3, _2DSidescrollerEngine.Properties.Resources.star_4};
    4. Animation anim;
    5. private void Form1_Shown(object sender, EventArgs e)
    6. {
    7. //Instantiate Stage:
    8. Stage1 = new Stage(null, System.Drawing.Color.CornflowerBlue, new Size(2500, this.Height), 60, this);
    9. //Initialize Stage:
    10. star = new Sprite(new Rectangle2(new Vector2(100, 100), new Size2(9, 9)), _2DSidescrollerEngine.Properties.Resources.star_1, Stage1.RenderTarget);
    11. anim = new Animation("StarBlinking", 4, Frames, 0.5F, Stage1.RenderTarget);
    12. star.AddAnimation(anim);
    13. Stage1.AddSprite(star);
    14. //Run Stage
    15. Stage1.Run();
    16. }


    Stage-Klasse:

    Quellcode

    1. public class Stage
    2. {
    3. private SharpDX.Direct2D1.Bitmap backImgV;
    4. private Size SizeV;
    5. private Rectangle2 cameraBounds;
    6. public int BackgroundImageStretchMode;
    7. private System.Threading.Thread renderThread;
    8. private Stopwatch FPSSW;
    9. private float targetFPSV;
    10. private float FPSV;
    11. private float maxFPSV;
    12. private bool stopGame;
    13. private Color4 backgroundColorV;
    14. private bool showFPSV = true;
    15. private RenderTarget Target;
    16. private SharpDX.DirectWrite.Factory textFactory;
    17. private List<Sprite> spriteList;
    18. /// <summary>
    19. /// Instantiates a new Stage to play on.
    20. /// </summary>
    21. /// <param name="backgroundImage">The Image drawn at the back of the scene. "null" to have nothing as background.</param>
    22. /// <param name="backgroundColor">The Color the Stage gets cleared with from frame to frame.</param>
    23. /// <param name="stageSize">The Size of the Stage in Pixels.</param>
    24. /// <param name="targetFPS">The maximum FPS to run the game with.</param>
    25. /// <param name="targetForm">The Form the stage will be drawn on.</param>
    26. public Stage(Image backgroundImage, System.Drawing.Color backgroundColor, Size stageSize, int targetFPS, Form targetForm)
    27. {
    28. //Get the Size of the Stage:
    29. SizeV = stageSize;
    30. //Set the Camera Bounds:
    31. cameraBounds = new Rectangle2(new Vector2(0, 0), new Size2(targetForm.Width, targetForm.Height));
    32. //Get the targetFPS:
    33. targetFPSV = targetFPS;
    34. //Start Stopwatch:
    35. FPSSW = new Stopwatch();
    36. //Initialize Direct2D:
    37. HwndRenderTargetProperties props;
    38. SharpDX.Direct2D1.Factory d2dFactory;
    39. d2dFactory = new SharpDX.Direct2D1.Factory(SharpDX.Direct2D1.FactoryType.MultiThreaded);
    40. props = new HwndRenderTargetProperties();
    41. props.Hwnd = targetForm.Handle;
    42. props.PixelSize = new SharpDX.Size2(targetForm.ClientSize.Width, targetForm.ClientSize.Height);
    43. props.PresentOptions = PresentOptions.RetainContents;
    44. Target = new WindowRenderTarget(d2dFactory, new RenderTargetProperties(), props);
    45. Target.DotsPerInch = new Size2F(96, 96);
    46. textFactory = new SharpDX.DirectWrite.Factory();
    47. //Convert the Background-Image as Drawing.Image to a SharpDX.Bitmap
    48. if (backImgV != null)
    49. {
    50. backImgV = Graphics2D.ConvertBitmap(Target, new System.Drawing.Bitmap(backgroundImage));
    51. }
    52. //Instantiate a new List of Sprites:
    53. spriteList = new List<Sprite>();
    54. }
    55. /// <summary>
    56. /// The Background-Color the stage is getting cleared with.
    57. /// </summary>
    58. public System.Drawing.Color BackColor {
    59. get { return Graphics2D.AsDrawingColor(backgroundColorV); }
    60. set { backgroundColorV = Graphics2D.AsColor4(value); }
    61. }
    62. /// <summary>
    63. /// The Size of the Stage.
    64. /// </summary>
    65. public Size Size {
    66. get { return SizeV; }
    67. set { SizeV = value; }
    68. }
    69. /// <summary>
    70. /// The time in seconds, that is past from the Run()-Call till now.
    71. /// </summary>
    72. public double GameTime {
    73. get { return FPSSW.ElapsedMilliseconds / 1000; }
    74. }
    75. /// <summary>
    76. /// The user-defined limit of FPS that can be reached.
    77. /// </summary>
    78. public float TargetFPS {
    79. get { return targetFPSV; }
    80. set { targetFPSV = value; }
    81. }
    82. /// <summary>
    83. /// The Maximum FPS that can be reached without any FPS-limitation.
    84. /// </summary>
    85. public float MaxFPS {
    86. get { return maxFPSV; }
    87. }
    88. /// <summary>
    89. /// Shows if the Stage is actually running or not.
    90. /// </summary>
    91. public bool IsRunning {
    92. get { return !stopGame; }
    93. }
    94. /// <summary>
    95. /// Shows whether the FPS should be shown or not.
    96. /// </summary>
    97. public bool FPSVisible {
    98. get { return showFPSV; }
    99. set { showFPSV = value; }
    100. }
    101. public RenderTarget RenderTarget {
    102. get { return Target; }
    103. }
    104. /// <summary>
    105. /// A List of the Sprites that are drawn in the Stage.
    106. /// </summary>
    107. public List<Sprite> Sprites {
    108. get { return spriteList; }
    109. }
    110. /// <summary>
    111. /// Adds a new Sprite to draw in the stage.
    112. /// </summary>
    113. /// <param name="sprite">The Sprite that needs to be added.</param>
    114. public void AddSprite(Sprite sprite) {
    115. spriteList.Add(sprite);
    116. }
    117. /// <summary>
    118. /// Starts running the internal gameloop of the Stage with its drawing and gamelogic.
    119. /// </summary>
    120. public void Run()
    121. {
    122. //New Thread for maximum Performance:
    123. renderThread = new System.Threading.Thread(GameLoop);
    124. //Start the GameLoop:
    125. renderThread.Start();
    126. //Start the GameTime-Counter:
    127. FPSSW.Start();
    128. }
    129. private void GameLoop()
    130. {
    131. while (!stopGame)
    132. {
    133. long Duration = FPSSW.ElapsedMilliseconds;
    134. if (renderThread.TrySetApartmentState(System.Threading.ApartmentState.MTA) == false)
    135. {
    136. //Singlethreaded:
    137. Application.DoEvents();
    138. }
    139. //Calculation:
    140. GameLogic();
    141. //Rendering:
    142. Draw();
    143. while (FPSSW.ElapsedMilliseconds - Duration < 1) { /*Wait for interval to get bigger than one*/};
    144. maxFPSV = Convert.ToSingle(1000 / (FPSSW.ElapsedMilliseconds - Duration));
    145. while (FPSSW.ElapsedMilliseconds - Duration < 1000 / targetFPSV)
    146. {
    147. //Wait for next Frame
    148. }
    149. FPSV = Convert.ToSingle(1000 / (FPSSW.ElapsedMilliseconds - Duration));
    150. //It is normal to have the FPSV a bit lower than the targetFPS
    151. }
    152. }
    153. private void GameLogic()
    154. {
    155. spriteList[0].PlayAnimation("StarBlinking", GameTime);
    156. }
    157. private void Draw()
    158. {
    159. var T = Target;
    160. T.BeginDraw();
    161. //Clear the surface:
    162. T.Clear(backgroundColorV);
    163. //Paint the Background:
    164. if (backImgV != null)
    165. {
    166. if (BackgroundImageStretchMode == 0)//Don't stretch or tile the Background-Image
    167. {
    168. T.DrawBitmap(backImgV, 1F, BitmapInterpolationMode.Linear);
    169. }
    170. else if (BackgroundImageStretchMode == 1)//Stretch the Background-Image to the Size of the Stage
    171. {
    172. T.DrawBitmap(backImgV, new SharpDX.RectangleF(0, 0, SizeV.Width, SizeV.Height), 1F, BitmapInterpolationMode.Linear);
    173. }
    174. else if (BackgroundImageStretchMode == 2)//Tile the Background-Image on the X- and Y-Axes
    175. {
    176. for (int i = 0; i <= SizeV.Width / backImgV.PixelSize.Width; i++)
    177. {
    178. for (int j = 0; j <= SizeV.Height / backImgV.PixelSize.Height; j++)
    179. {
    180. T.DrawBitmap(backImgV, new SharpDX.RectangleF(i * backImgV.PixelSize.Width, j * backImgV.PixelSize.Height, backImgV.PixelSize.Width, backImgV.PixelSize.Height), 1F, BitmapInterpolationMode.Linear);
    181. }
    182. }
    183. }
    184. else if (BackgroundImageStretchMode == 3)//Tile the Background-Image on the X-Axis
    185. {
    186. for (int i = 0; i <= SizeV.Width / backImgV.PixelSize.Width; i++)
    187. {
    188. T.DrawBitmap(backImgV, new SharpDX.RectangleF(i * backImgV.PixelSize.Width, 0, backImgV.PixelSize.Width, backImgV.PixelSize.Height), 1F, BitmapInterpolationMode.Linear);
    189. }
    190. }
    191. else if (BackgroundImageStretchMode == 4)//Tile the Background-Image on the Y-Axis
    192. {
    193. for (int j = 0; j <= SizeV.Height / backImgV.PixelSize.Height; j++)
    194. {
    195. T.DrawBitmap(backImgV, new SharpDX.RectangleF(0, j * backImgV.PixelSize.Height, backImgV.PixelSize.Width, backImgV.PixelSize.Height), 1F, BitmapInterpolationMode.Linear);
    196. }
    197. }
    198. }
    199. //Draw here:
    200. for (int i = 0; i < spriteList.Count; i++) {
    201. T.DrawBitmap(spriteList[i].Image, new SharpDX.RectangleF(spriteList[i].Position.ToPointF(cameraBounds).X, spriteList[i].Position.ToPointF(cameraBounds).Y, spriteList[i].Width, spriteList[i].Height), 1F, BitmapInterpolationMode.Linear);
    202. }
    203. //Drawing the FPS:
    204. if (showFPSV)
    205. {
    206. T.DrawText(FPSV.ToString() + " FPS", new SharpDX.DirectWrite.TextFormat(textFactory, "Arial", 16), new SharpDX.RectangleF(5, 5, 100, 100), new SharpDX.Direct2D1.SolidColorBrush(Target, new Color4(1F, 0F, 0F, 1F)));
    207. }
    208. T.EndDraw();
    209. }
    210. /// <summary>
    211. /// Stops running the Stage and drawing it onto the Form.
    212. /// </summary>
    213. public void Close()
    214. {
    215. //Close the Thread:
    216. stopGame = true;
    217. renderThread.Abort();
    218. }
    219. }


    Sprite-Struktur:

    Quellcode

    1. public struct Sprite
    2. {
    3. private SharpDX.Direct2D1.Bitmap imgV;
    4. private Rectangle2 boundsV;
    5. private List<Animation> anims;
    6. public Sprite(Rectangle2 Bounds, Image stdImg, RenderTarget Target)
    7. {
    8. boundsV = Bounds;
    9. imgV = Graphics2D.ConvertBitmap(Target, new System.Drawing.Bitmap(stdImg));
    10. anims = new List<Animation>();
    11. }
    12. public Vector2 Position
    13. {
    14. get { return boundsV.Position; }
    15. set { boundsV.Position = value; }
    16. }
    17. public Size2 Size
    18. {
    19. get { return boundsV.Size; }
    20. set { boundsV.Size = value; }
    21. }
    22. public float X
    23. {
    24. get { return boundsV.X; }
    25. set { boundsV.X = value; }
    26. }
    27. public float Y
    28. {
    29. get { return boundsV.Y; }
    30. set { boundsV.Y = value; }
    31. }
    32. public float Width
    33. {
    34. get { return boundsV.Width; }
    35. set { boundsV.Width = value; }
    36. }
    37. public float Height
    38. {
    39. get { return boundsV.Height; }
    40. set { boundsV.Height = value; }
    41. }
    42. public SharpDX.Direct2D1.Bitmap Image
    43. {
    44. get { return imgV; }
    45. set { imgV = value; }
    46. }
    47. public void AddAnimation(Animation anim){
    48. anims.Add(anim);
    49. }
    50. public void PlayAnimation(string animationName, double gameTime) {
    51. for (int i = 0; i < anims.Count; i++)
    52. {
    53. if (anims[i].Name == animationName)
    54. {
    55. anims[i].Play(gameTime, ref imgV);
    56. break;
    57. }
    58. }
    59. }
    60. }


    Animation-Struktur:

    Quellcode

    1. public struct Animation {
    2. private SharpDX.Direct2D1.Bitmap[] framesV;
    3. private int frameCountV;
    4. private float frameIntervalV;
    5. private string nameV;
    6. private Stopwatch AnimSW;
    7. private bool isPlayingV;
    8. private double startTime;
    9. private int index;
    10. public Animation(string name, int frameCount, System.Drawing.Bitmap[] frames, float frameInterval, RenderTarget Target) {
    11. nameV = name;
    12. frameCountV = frameCount;
    13. framesV = new SharpDX.Direct2D1.Bitmap[frames.Length];
    14. for (int i = 0; i < frames.Length; i++) {
    15. framesV[i] = Graphics2D.ConvertBitmap(Target, frames[i]);
    16. }
    17. frameIntervalV = frameInterval;
    18. AnimSW = new Stopwatch();
    19. framesV = new SharpDX.Direct2D1.Bitmap[frameCount];
    20. isPlayingV = false;
    21. startTime = 0;
    22. index = 0;
    23. }
    24. public string Name {
    25. get { return nameV; }
    26. set { nameV = value; }
    27. }
    28. public float FrameInterval {
    29. get { return frameIntervalV; }
    30. set { frameIntervalV = value; }
    31. }
    32. public int FrameCount {
    33. get { return frameCountV; }
    34. set { frameCountV = value; }
    35. }
    36. public SharpDX.Direct2D1.Bitmap[] Frames {
    37. get { return framesV; }
    38. set { framesV = value; }
    39. }
    40. public bool IsPlaying {
    41. get { return isPlayingV; }
    42. }
    43. public void Play(double gameTime, ref SharpDX.Direct2D1.Bitmap img) {
    44. if (startTime + frameIntervalV <= gameTime)
    45. {
    46. img = framesV[index];
    47. index++;
    48. if (index >= framesV.Length) {
    49. index = 0;
    50. }
    51. startTime = gameTime;
    52. }
    53. }
    54. }


    Sorry wenn das ein bisschen viel Code ist, aber ich weiß echt nicht mehr, wo der Fehler liegen könnte, also wollte ich mal auf Nummer sicher gehen. ^^
    Dateien
    Auch Dunkelheit kann Erleuchtung bringen...

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Karabonga“ ()