2012-08-08 7 views
7

Ich mache ein Pong-Spiel. Ich habe ein einfaches 44 x 44 Png eines roten Quadrats als meinen Ball verwendet, während ich debugging. Das Spiel funktioniert gut mit diesem Quadrat.Kann kein Bild über als Quadrat in XNA

Wenn ich versuche, die Textur durch etwas anderes als ein Quadrat zu ersetzen, sehe ich den Ball nicht auf dem Bildschirm gezeichnet, und ich kann nicht herausfinden, warum. Ich mache meine Bilder die gleiche Größe in Photoshop, und entweder mit. PNG oder. JPG und mit dem gleichen Ergebnis, aber ich kann es nicht für das Leben von mir herausfinden. Was denkst du könnte dieses Problem verursachen?

Ich habe den Code für meinen Ball im Text unten gelassen. Die Update- und Draw-Methoden meines Balls werden vom GameplayScreen aufgerufen (mit dem GSM-Beispiel von MS).

public class Ball : IGameEntity 
{ 
    #region Fields 

    private Random rand;    // Random var 
    private Texture2D texture;   // Texture for the ball 
    private double direction;   // Directon the ball is traveling in     
    private bool isVisible; 
    private bool hasHitLeftBat;   // Checked to see if the ball and bat have just collided 
    private bool hasHitRightBat;  // Checked to see if the ball and bat have just collided 
    private Vector2 ballPosition, resetBallPos, oldBallPos; 
    private Rectangle ballRect; 
    public float Speed; 
    private SpriteBatch spriteBatch; // Spritebatch 
    private bool isBallStopped; 
    private Vector2 origin;    // Locate the mid-point of the ball 
    public float RotationAngle; 
    private AIBat rightBat;    // Player's Bad 
    private Bat leftBat;    // AI Bat 
    private float ballRelativePos; 
    private Rectangle rectangle3;  // Used to draw the collison rectangle 
    private Texture2D blank;   // Texture to be drawn on the collision rectangle 

    GameplayScreen gameplayScreen;  // Creates an instance of the GameplayScreen 
    Game1 gameInstance;     // Creates an instance of the Game1 class 
    int selectedStage;     // Pass this into GameplayScreen for selecting easy, medium, or hard 


    #endregion 

    #region Constructors and Destructors 

    /// <summary> 
    /// Constructor for the ball 
    /// </summary> 
    public Ball(ContentManager contentManager, Vector2 ScreenSize, Bat bat, AIBat aiBat) 
    { 
     Speed = 15f; 
     texture = contentManager.Load<Texture2D>(@"gfx/balls/redBall"); 
     direction = 0; 
     ballRect = new Rectangle(0, 0, texture.Width /2, texture.Height /2); 
     resetBallPos = new Vector2(ScreenSize.X/2 + origin.X, ScreenSize.Y/2 + origin.Y); 
     ballPosition = resetBallPos; 
     rand = new Random(); 
     isVisible = true; 
     origin = new Vector2(texture.Width/2, texture.Height/2); 
     leftBat = bat; // Creates a new instance of leftBat so that I can access Position.X/Y for LeftBatPatcicles() 
     rightBat = aiBat;// Creates a new instance of leftBat so that can access Position.X/Y for RightBatPatcicles() 
     gameplayScreen = new GameplayScreen(null, selectedStage); 
     gameInstance = new Game1(); 
     Rectangle rectangle3 = new Rectangle(); 
     blank = contentManager.Load<Texture2D>(@"gfx/blank");    

     // pes = new ParticleEmitterService(game); 
    } 

    public Ball(Bat myBat) 
    { 
     leftBat = myBat;   // this assigns and instantiates the member bat 
            // with myBat which was passed from the constructor 
    } 

    #endregion 

    #region Methods 

    /// <summary> 
    /// Draws the ball on the screen 
    /// </summary> 
    public void Draw(SpriteBatch spriteBatch) 
    { 
     if (isVisible) 
     { 
      // Draws the rotaing ball 
      spriteBatch.Draw(texture, ballPosition, ballRect, Color.White, 
           RotationAngle, origin, .0f, SpriteEffects.None, 0); 

      spriteBatch.Draw(blank, rectangle3, Color.LightCoral); 
     } 
    } 

    /// <summary> 
    /// Updates position of the ball. Used in Update() for GameplayScreen. 
    /// </summary> 
    public void UpdatePosition(GameTime gameTime) 
    { 
     ballRect.X = (int)ballPosition.X; 
     ballRect.Y = (int)ballPosition.Y; 
     oldBallPos.X = ballPosition.X; 
     oldBallPos.Y = ballPosition.Y; 

     ballPosition.X += Speed * ((float)Math.Cos(direction)); 

     ballPosition.Y += Speed * ((float)Math.Sin(direction)); 
     bool collided = CheckWallHit(); 


     // Stops the issue where ball was oscillating on the ceiling or floor 
     if (collided) 
     { 
      ballPosition.X = oldBallPos.X + Speed * (float)1.5 * (float)Math.Cos(direction); 
      ballPosition.Y = oldBallPos.Y + Speed * (float)Math.Sin(direction); 
     } 

     // As long as the ball is to the right of the back, check for an update 
     if (ballPosition.X > leftBat.BatPosition.X) 
     { 
      // When the ball and bat collide, draw the rectangle where they intersect 
      BatCollisionRectLeft(); 
     } 

     // As longas the ball is to the left of the back, check for an update 
     if (ballPosition.X < rightBat.BatPosition.X) 
     { // When the ball and bat collide, draw the rectangle where they intersec 
      BatCollisionRectRight(); 
     } 

     // The time since Update was called last. 
     float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds; 

     // Rotation for the ball 
     RotationAngle += elapsed; 
     float circle = MathHelper.Pi * 2; 
     RotationAngle = RotationAngle % circle; 

     //  base.Update(gameTime); 
     gameInstance.update(); 

    } 


    /// <summary> 
    /// Checks for the current direction of the ball 
    /// </summary> 
    public double GetDirection() 
    { 
     return direction; 
    } 

    /// <summary> 
    /// Checks for the current position of the ball 
    /// </summary> 
    public Vector2 GetPosition() 
    { 
     return ballPosition; 
    } 

    /// <summary> 
    /// Checks for the current size of the ball (for the powerups) 
    /// </summary> 
    public Rectangle GetSize() 
    { 
     return ballRect; 
    } 



    /// <summary> 
    /// Checks to see if ball went out of bounds, and triggers warp sfx. Used in GameplayScreen. 
    /// </summary> 
    public void OutOfBounds() 
    { 
     AudioManager.Instance.PlaySoundEffect("Muzzle_shot"); 
    } 

    /// <summary> 
    /// Speed for the ball when Speedball powerup is activated 
    /// </summary> 
    public void PowerupSpeed() 
    { 
     Speed += 20.0f; 
    } 

    /// <summary> 
    /// Check for where to reset the ball after each point is scored 
    /// </summary> 
    public void Reset(bool left) 
    { 
     if (left) 
     { 
      direction = 0; 
     } 
     else 
     { 
      direction = Math.PI; 
     } 

     ballPosition = resetBallPos; // Resets the ball to the center of the screen 
     isVisible = true; 
     Speed = 15f; // Returns the ball back to the default speed, in case the speedBall was active 
     if (rand.Next(2) == 0) 
     { 
      direction += MathHelper.ToRadians(rand.Next(30)); 
     } 
     else 
     { 
      direction -= MathHelper.ToRadians(rand.Next(30)); 
     } 
    } 

    /// <summary> 
    /// Shrinks the ball when the ShrinkBall powerup is activated 
    /// </summary> 
    public void ShrinkBall() 
    { 
     ballRect = new Rectangle(0, 0, texture.Width/2, texture.Height/2); 
    } 

    /// <summary> 
    /// Stops the ball each time it is reset. Ex: Between points/rounds 
    /// </summary> 
    public void Stop() 
    { 
     isVisible = true; 
     Speed = 0; 
     isBallStopped = true; 
    } 

    /// <summary> 
    /// Checks for collision with the ceiling or floor. 2*Math.pi = 360 degrees 
    /// </summary> 
    private bool CheckWallHit() 
    { 
     while (direction > 2 * Math.PI) 
     { 
      direction -= 2 * Math.PI; 
      return true; 
     } 

     while (direction < 0) 
     { 
      direction += 2 * Math.PI; 
      return true; 
     } 

     if (ballPosition.Y <= 0 || (ballPosition.Y > resetBallPos.Y * 2 - ballRect.Height)) 
     { 
      direction = 2 * Math.PI - direction; 
      return true; 
     } 
     return true; 
    } 

    /// <summary> 
    /// Used to determine the location where the particles will initialize when the ball and bat collide 
    /// </summary> 
    private void BatCollisionRectLeft() 
    { 
     // For the left bat 
     if (ballRect.Intersects(leftBat.batRect)) 
     { 
      rectangle3 = Rectangle.Intersect(ballRect, leftBat.batRect); 
     } 
    } 

    /// <summary> 
    ///Checks for collision of Right Bat 
    /// </summary> 
    private void BatCollisionRectRight() 
    { 
     // for the right bat 
     if (ballRect.Intersects(rightBat.batRect)) 
     { 
      rectangle3 = Rectangle.Intersect(ballRect, rightBat.batRect); ; 
     } 
    } 

Antwort

1

Sie sollten nichts als Ihren SourceRect-Parameter in Ihrem Zeichenaufruf übergeben, außer Sie möchten nicht das gesamte Bild zeichnen.

Die Art, wie Sie es jetzt einrichten, ist, dass Sie 'ballRect' als SourceRect übergeben, wenn Sie versuchen, Ihren Ball zu zeichnen, und dieser ballRect-Parameter wird entsprechend der Position des Balls aktualisiert Teil Ihres Bildes, der weit außerhalb der Größe der Textur liegt.

Wenn Sie die gesamte Kugel zeichnen möchten, verwenden Sie einfach:

spriteBatch.Draw(texture, ballPosition, null, Color.White, 
          RotationAngle, origin, .0f, SpriteEffects.None, 0); 

Wenn Sie nur den linken oberen Quadranten der Ball ziehen wollte, Sie in der folgenden Rechteck als sourceRect passieren könnte:

Rectangle sourceRect = new Rectangle(0, 0, texture.Width/2, texture.Height/2); 

Dann könnten Sie, dass in Ihrem Draw-Aufruf verwenden:

spriteBatch.Draw(texture, ballPosition, sourceRect, Color.White, 
          RotationAngle, origin, .0f, SpriteEffects.None, 0); 

EDIT: Du bist al also übergeben Sie .0f als Ihren "Skalier" -Parameter, wenn er also Ihren Ball zeichnet, wird er 0 Pixel groß sein, was, wie ich vermute, nicht das beabsichtigte Verhalten ist. Wenn Sie 1f für Ihre Waage verwenden, wird sie mit der Standardgröße gezeichnet.

+0

Das war es! Ich musste den SourceRect auf null setzen und den Maßstab auf 1 ändern. Ich bin nicht der Grund, warum es auf 0 stand, aber ich vermute, weil meine ursprüngliche Textur nur ein großer roter Block war, war es egal, wie groß dieser war . –

3

2 Dinge, die ich bemerkt habe, ich glaube nicht, dass Sie Ihr Rechteck dimentions halbieren wollen, wenn Sie

nennen
ballRect = new Rectangle(0, 0, texture.Width /2, texture.Height /2); 

auch, du bist dieses blank Sprite auf Zeichnung Ihrer Ball, so dass, wenn sie sich überlappen, Sie den Ball nicht sehen werden, aber wenn das der Fall ist, weiß ich nicht, warum es mit dem Quadrat arbeitete.

+0

Entschuldigung, ich hatte die Textur in zwei Hälften geschnitten, weil ich nur versuchte, sie für einen Test kleiner zu machen. Ich glaube, ich habe vergessen, diese Zeile zu entfernen. Ich zeichne nur das leere Sprite (das ist wirklich nur ein weißer Block, lackiert Color.LightCoral) an der Stelle, wo der Ball und Bat kollidieren. Sobald sie kollidieren, zeichnet sie die "leere" Textur und entfernt sie, sobald sie die nächste Fledermaus trifft. –

0

Etwas, das ich ist aufgefallen, dass in der Linie

resetBallPos = new Vector2(ScreenSize.X/2 + origin.X, ScreenSize.Y/2 + origin.Y); 

in Ihrem Konstruktor wird die Eigenschaften der Variable ‚Herkunft‘ Zugriff, bevor Sie tatsächlich einen beliebigen Wert zuweisen; Sie weisen ihm jedoch nur wenige Zeilen unter diesem Wert einen Wert zu. Ich würde diese Linie verschieben:

origin = new Vector2(texture.Width/2, texture.Height/2); 

darüber zu sein. Ich würde denken, dass sollte dein Problem beheben; Im Übergang vom roten Block zum richtigen Bild haben Sie sich vielleicht mehr verändert, als Sie dachten.

Auch, als eine Nebenbemerkung, wenn Sie mit XNA arbeiten, versuchen Sie hauptsächlich PNG-Bilder zu verwenden. Sie sind klein und laden sehr schnell; Zusätzlich unterstützen sie transparente Hintergrundbilder.

+0

Ich habe seither den Ursprung über die resetballpos Zeile verlagert. Ich sehe diesen Ball immer noch nicht. Normalerweise verwende ich PNG die ganze Zeit, aber ich dachte, ich würde JPG in diesem Fall versuchen, nur um zu überprüfen, dass es kein Problem mit Transparenz war. –

2

Sie vorbei ballRect in Draw() als Quellrechteck, die angibt, wo das Sprite auf die Textur existiert. Wenn Sie die gesamte Textur verwenden möchten, geben Sie stattdessen null an. Stellen Sie andernfalls sicher, dass der Wert ballRect immer in die Textur fällt.

Sie scheinen es zu verwenden, um die Position des Sprites auf dem Bildschirm zu verfolgen. Von Ihrer UpdatePosition Funktion:

ballRect.X = (int)ballPosition.X; 
ballRect.Y = (int)ballPosition.Y; 

Diese Textur produziert Koordinaten außerhalb der Grenzen der Textur, die durch den Abtaster eingespannt werden. Bei einer Textur, die ausschließlich aus roten Pixeln besteht, scheint dies zu funktionieren, da die Pixel rund um den Rand der Textur rot sind. In einer Textur mit einem transparenten Rand wird das Sprite stattdessen an diese transparente Farbe geklammert.

Verwandte Themen