2012-08-08 63 views
7

我正在製作pong遊戲。我一直在調試時一直在使用一個簡單的44 x 44 png的紅色方塊作爲我的球。這個廣場的遊戲效果很好。無法在XNA中繪製超過正方形的圖像

當我嘗試用正方形以外的任何東西替換紋理時,我沒有看到屏幕上畫出的球,我不知道爲什麼。我在photoshop中將圖像製作成完全相同的尺寸,並使用.PNG或.JPG,並得到相同的結果,但我無法想象出我的生活。你認爲可能會導致這個問題?

我已經在下面的文本中留下了我的球的代碼。我的球的更新和繪製方法由GameplayScreen調用(使用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); ; 
     } 
    } 

回答

1

除非您不想繪製整個圖像,否則您不應該在繪製調用中將任何東西作爲SourceRect參數傳遞。

你現在設置的方式是當你試圖繪製你的球時,你傳遞'ballRect'作爲你的SourceRect,並且ballRect參數正在根據球的位置進行更新,所以你試圖畫一個您的圖像部分超出了紋理的大小。

如果你想繪製整個球,只需使用:

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

如果你只是想畫球的左上象限,你可以通過下面的矩形爲您SourceRect:

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

然後你可以使用在你繪製調用:

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

編輯:你是人所以傳遞.0f作爲你的「縮放」參數,所以當它畫出你的球時,它的大小將爲0像素,我猜測這不是預期的行爲。使用1f作爲您的比例將以默認大小繪製它。

+0

就是這樣!我需要將SourceRect更改爲null,並將比例更改爲1.我不是爲什麼它是0,但我猜是因爲我的原始紋理只是一個大塊的紅色塊,它不管它有多大。 – 2012-08-09 09:53:26

3

2的事情,我注意到,我不認爲你想,當你調用

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

也,你在上面繪製此blank精靈權利減半矩形dimentions你所以如果它們重疊,你將不會看到球,但如果是這種情況,我不知道它爲什麼與廣場一起工作。

+0

對不起,當我試圖縮小測試的範圍時,我把紋理減半了。我想我忘了刪除那一行。 我只是在球和蝙蝠碰撞的位置繪製空白精靈(它實際上只是一個白色的塊,塗成Color.LightCoral)。所以一旦它們碰撞,它就會在那裏畫出「空白」的紋理,然後一旦碰到下一隻蝙蝠就將其移除。 – 2012-08-08 18:02:44

0

東西我注意到的是,在該行

​​

構造函數內部訪問變量「原點」之前,你實際上是分配給它的任何值的屬性;然而,你確實給它分配了一個值,只是在這個值的下面幾行。我提出這個行:

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

是它上面。我會認爲這應該解決你的問題;在從紅色塊到正確圖像的過渡中,你可能已經改變了更多,然後你認爲。另外,作爲一個方面說明,當您使用XNA時,嘗試主要使用PNG圖像。它們很小,負載非常快;另外,它們支持透明背景圖像。

+0

我已將原點重新定位到resetballpos行上方。我仍然沒有看到這個球。 我一般都會使用PNG,但我認爲我會在這種情況下嘗試JPG,以驗證它不是透明度問題。 – 2012-08-08 19:03:43

2

你傳遞ballRectDraw()作爲源矩形,其中指定了精靈存在上的紋理。如果要使用整個紋理,請指定null。否則,請確保ballRect的值始終落在紋理內。

您似乎正在使用它來跟蹤屏幕上的精靈的位置。從您的UpdatePosition功能:

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

這是生產的質地紋理的邊界,這是由採樣夾以外的座標。由於完全由紅色像素組成的紋理看起來很有效,因爲紋理邊緣周圍的像素都是紅色的。在具有透明邊框的紋理中,精靈將被固定爲該透明顏色。