2012-08-08 15 views
7

Estoy haciendo un juego de pong. He estado usando un simple 44 x 44 .png de un cuadrado rojo como mi bola mientras he estado depurando. El juego funciona bien con este cuadrado.No se puede dibujar una imagen más que un cuadrado en XNA

Cuando trato de reemplazar la textura con algo que no sea un cuadrado, no veo la bola dibujada en la pantalla, y no puedo entender por qué. Estoy haciendo que mis imágenes tengan exactamente el mismo tamaño en photoshop, y use .PNG o .JPG y tenga el mismo resultado, pero no puedo entenderlo por mi vida. ¿Qué crees que podría estar causando este problema?

He dejado el código para mi bola en el texto a continuación. El GameplayScreen está llamando a los métodos de actualización y dibujo de mi bola (usando la muestra MS 'GSM).

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

Respuesta

1

No debe pasar nada como su parámetro SourceRect en su llamada a dibujar a menos que no desee dibujar toda la imagen.

La forma en que la tiene configurada ahora es que está pasando 'ballRect' como su SourceRect cuando trata de dibujar su bola, y ese parámetro ballRect se está actualizando de acuerdo con la posición de la bola, por lo que está tratando de dibujar un porción de su imagen que está fuera del tamaño de la textura.

Si desea dibujar toda la pelota, sólo tiene que utilizar:

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

Si sólo quería dibujar el cuadrante superior izquierdo de la pelota, que podría pasar en el rectángulo siguiente como su sourceRect:

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

Posteriormente, se podría utilizar eso en su llamada Draw:

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

EDIT: usted es al Pasando .0f como parámetro de "escala" para que cuando dibuje tu bola tenga 0 píxeles de tamaño, lo que supongo que no es el comportamiento previsto. Si usa 1f para su escala, lo dibujará en su tamaño predeterminado.

+0

¡Esto fue todo! Necesitaba cambiar el SourceRect a nulo, y cambiar la escala a 1. No soy el motivo por el que estaba en 0, pero supongo que porque mi textura original era solo un bloque rojo grande, que no importaba cuán grande fuera . –

3

2 cosas que estoy notando, no creo que usted quiere reducir a la mitad sus Dimensiones del rectángulo cuando se llama

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

también, que está dibujando este blank de sprites en la parte superior de su bola, de modo que si se superponen, no verás la pelota, pero si ese es el caso, no sé por qué funcionó con el cuadrado.

+0

Lo siento, corté la textura por la mitad ya que estaba tratando de hacerla más pequeña para una prueba. Supongo que olvidé eliminar esa línea. Solo dibujo el sprite en blanco (que en realidad es solo un bloque blanco, pintado en Color.LightCoral) en el lugar donde colisionan la bola y el murciélago. Entonces, una vez que colisionan, dibuja la textura "en blanco" allí y luego la elimina una vez que golpea al siguiente murciélago. –

0

Algo que he notado es que, en la línea

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

dentro de su constructor es tener acceso a las propiedades del 'origen' variable antes de que realmente se asigna ningún valor a la misma; sin embargo, le asigna un valor, solo unas líneas debajo de este valor. Me gustaría mover esta línea:

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

estar por encima. Creo que eso debería arreglar tu problema; en la transición del bloque rojo a la imagen adecuada, es posible que haya cambiado más de lo que pensaba.

Además, como nota al margen, cuando trabaje con XNA, trate de usar principalmente imágenes PNG. Son pequeños y cargan muy rápido; adicionalmente, admiten imágenes de fondo transparentes.

+0

He reubicado el origen desde arriba de la línea resetballpos. Todavía no estoy viendo esta pelota. Generalmente uso PNG todo el tiempo, pero pensé que probaría JPG en esta instancia, solo para verificar que no fuera un problema con la transparencia. –

2

Usted está pasando en ballRectDraw() como el rectángulo fuente, que especifica dónde existe el sprite en la textura. Si desea usar toda la textura, especifique null en su lugar. De lo contrario, asegúrese de que el valor de ballRect siempre esté dentro de la textura.

Parece que lo está usando para realizar un seguimiento de la posición del sprite en la pantalla. Desde su UpdatePosition función:

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

Esta es la producción de coordenadas de textura fuera de los límites de la textura, los cuales son bien apretado por el muestreador. Con una textura que consta completamente de píxeles rojos, parece que funciona, porque los píxeles alrededor del borde de la textura son todos rojos. En una textura con un borde transparente, el sprite se fijará a ese color transparente en su lugar.

Cuestiones relacionadas