2012-08-08 35 views
7

Tôi đang tạo một trò chơi pong. Tôi đã sử dụng một đơn giản 44 x 44 .png của một hình vuông màu đỏ như quả bóng của tôi trong khi tôi đã được gỡ lỗi. Trò chơi hoạt động tốt với hình vuông này.Không thể vẽ hình ảnh trên hình vuông trong XNA

Khi tôi cố gắng thay thế kết cấu bằng bất kỳ thứ gì khác ngoài hình vuông, tôi không thấy bóng được vẽ trên màn hình và tôi không thể hiểu tại sao. Tôi đang làm cho hình ảnh của tôi có kích thước chính xác như nhau trong photoshop, và sử dụng một trong hai .PNG hoặc .JPG và có kết quả tương tự, nhưng tôi không thể tìm ra nó cho cuộc sống của tôi. Bạn nghĩ điều gì có thể gây ra vấn đề này?

Tôi đã để lại mã cho quả bóng của tôi trong văn bản bên dưới. Bản cập nhật và phương thức vẽ của bóng của tôi đang được GameplayScreen gọi (sử dụng mẫu GSM của 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); ; 
     } 
    } 

Trả lời

1

Bạn không nên chuyển bất kỳ thứ gì làm thông số SourceRect trong cuộc gọi vẽ trừ khi bạn không muốn vẽ toàn bộ hình ảnh.

Cách bạn thiết lập ngay bây giờ là bạn đang chuyển 'ballRect' làm SourceRect của bạn khi cố gắng vẽ bóng của bạn và thông số ballRect đang được cập nhật theo vị trí của bóng vì vậy bạn đang cố gắng vẽ một phần của hình ảnh của bạn ở bên ngoài kích thước của kết cấu.

Nếu bạn muốn vẽ toàn bộ quả bóng, chỉ cần sử dụng:

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

Nếu bạn chỉ muốn vẽ các góc phần tư phía trên bên trái của bóng, bạn có thể vượt qua trong hình chữ nhật sau khi SourceRect của bạn:

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

Sau đó, bạn có thể sử dụng trong cuộc gọi Draw của bạn:

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

EDIT: bạn al vì vậy, hãy vượt qua .0f như thông số "tỷ lệ" của bạn để khi nó vẽ bóng của bạn, nó sẽ có kích thước 0 pixel, mà tôi đoán không phải là hành vi dự định. Sử dụng 1f cho quy mô của bạn sẽ vẽ nó ở kích thước mặc định của nó.

+0

Đây là nó! Tôi cần thay đổi SourceRect thành null và thay đổi tỷ lệ thành 1. Tôi không phải lý do tại sao nó là 0, nhưng tôi đoán vì kết cấu ban đầu của tôi chỉ là một khối màu đỏ lớn, rằng nó không quan trọng . –

3

2 điều mà tôi nhận thấy, tôi không nghĩ rằng bạn muốn giảm một nửa Kích thước hình chữ nhật của bạn khi bạn gọi

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

cũng có, bạn đang vẽ blank sprite này trên đầu trang của bạn bóng, để nếu chúng chồng lên nhau, bạn sẽ không nhìn thấy quả bóng, nhưng nếu đó là trường hợp tôi không biết tại sao nó làm việc với hình vuông.

+0

Xin lỗi, tôi đã cắt giảm một nửa vì tôi chỉ cố gắng làm cho nó nhỏ hơn để thử nghiệm. Tôi đoán tôi đã quên xóa dòng đó. Tôi chỉ vẽ hình sprite trống (mà thực sự chỉ là một khối màu trắng, được tô màu Color.LightCoral) tại vị trí nơi quả bóng và gậy va chạm. Vì vậy, một khi chúng va chạm, nó sẽ vẽ kết cấu "trống" ở đó, và sau đó loại bỏ nó khi nó chạm vào con dơi tiếp theo. –

0

Something tôi nhận thấy là trong dòng

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

bên trong constructor của bạn được truy cập vào các tính chất của biến 'nguồn gốc' trước khi bạn thực sự gán bất kỳ giá trị cho nó; tuy nhiên, bạn chỉ định giá trị cho nó, chỉ một vài dòng bên dưới giá trị này. Tôi muốn di chuyển dòng này:

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

để ở trên nó. Tôi nghĩ rằng nên khắc phục vấn đề của bạn; trong quá trình chuyển đổi từ khối màu đỏ sang hình ảnh thích hợp, bạn có thể đã thay đổi nhiều hơn sau đó bạn nghĩ.

Ngoài ra, như một lưu ý phụ, khi bạn đang làm việc với XNA, hãy thử sử dụng chủ yếu là hình ảnh PNG. Chúng nhỏ và tải rất nhanh; ngoài ra, chúng hỗ trợ hình nền trong suốt.

+0

Tôi đã chuyển vị trí gốc về phía trên đường resetballpos. Tôi vẫn không nhìn thấy quả bóng này. Tôi thường sử dụng PNG mọi lúc, nhưng tôi nghĩ tôi sẽ thử JPG ​​trong trường hợp này, chỉ để xác minh rằng đó không phải là vấn đề với tính minh bạch. –

2

Bạn đang đi qua ballRect vào Draw() như nguồn hình chữ nhật, trong đó xác định nơi ma tồn tại trên kết cấu. Nếu bạn muốn sử dụng toàn bộ kết cấu, hãy chỉ định null thay thế. Nếu không, hãy đảm bảo rằng giá trị của ballRect luôn rơi trong kết cấu.

Bạn dường như đang sử dụng nó để theo dõi vị trí của sprite trên màn hình. Từ UpdatePosition chức năng của bạn:

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

này được sản xuất kết cấu phối bên ngoài bờ cõi của các kết cấu, mà đang bị kẹp bởi các sampler. Với một kết cấu bao gồm toàn bộ các điểm ảnh màu đỏ, điều này dường như hoạt động, bởi vì các điểm ảnh xung quanh các cạnh của kết cấu đều có màu đỏ. Trong một kết cấu có đường viền trong suốt, sprite sẽ được gắn vào màu trong suốt đó.

Các vấn đề liên quan