我正在进行一场乒乓球比赛。在我调试的时候,我一直在使用一个简单的44 x 44 .png红色方块作为我的球。这个广场上的游戏很好用。
当我尝试用方形以外的任何东西替换纹理时,我看不到在屏幕上绘制的球,我无法弄清楚原因。我在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); ;
}
}
答案 0 :(得分:3)
我注意到的两件事情,当你打电话时,我认为你不想把你的矩形尺寸减半
ballRect = new Rectangle(0, 0, texture.Width /2, texture.Height /2);
另外,你在球的顶部画了这个blank
精灵,所以如果它们重叠,你就不会看到球,但如果是这样的话,我就是这样的不知道为什么它与广场一起工作。
答案 1 :(得分:2)
您将ballRect
传递给Draw()
作为源矩形,它指定了纹理在纹理上的位置。如果要使用整个纹理,请指定null
。否则,请确保ballRect
的值始终位于纹理内。
您似乎正在使用它来跟踪精灵在屏幕上的位置 。来自UpdatePosition
功能:
ballRect.X = (int)ballPosition.X;
ballRect.Y = (int)ballPosition.Y;
这会产生纹理边界之外的纹理坐标,这些坐标被采样器钳制。使用完全由红色像素组成的纹理,这似乎有效,因为纹理边缘周围的像素都是红色的。在具有透明边框的纹理中,精灵将被夹紧到该透明色。
答案 2 :(得分:1)
除非您不想绘制整个图像,否则您不应该在绘图调用中将任何内容作为SourceRect参数传递。
现在你设置它的方式是你通过&#39; ballRect&#39;当你试图绘制球时你的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);
然后你可以在你的Draw调用中使用它:
spriteBatch.Draw(texture, ballPosition, sourceRect, Color.White,
RotationAngle, origin, .0f, SpriteEffects.None, 0);
编辑:你也将.0f作为你的&#34;比例&#34;参数因此,当它确实绘制你的球时,它将是0像素的大小,我猜测它不是预期的行为。使用1f作为您的比例将以它的默认大小绘制它。
答案 3 :(得分:0)
我注意到的是行
resetBallPos = new Vector2(ScreenSize.X / 2 + origin.X, ScreenSize.Y / 2 + origin.Y);
构造函数中的是在实际为其赋值之前访问变量'origin'的属性;但是,你确实为它赋值,只比这个值低几行。我会移动这一行:
origin = new Vector2(texture.Width / 2, texture.Height / 2);
高于它。我认为应该解决你的问题;在从红色块到正确图像的过渡中,你可能已经改变了更多的想法。
另外,作为旁注,当您使用XNA时,请尝试主要使用PNG图像。它们很小,负载很快;此外,它们支持透明的背景图像。