首先要避開,如果我錯過了某些非常明顯的東西,我很抱歉,我在這方面還是比較新的。XNA遊戲在非常奇怪的情況下不會啓動
無論如何,我一直在研究XNA中的小行星克隆,並且由於某些原因,如果點擊「開始調試」按鈕,它偶爾不會啓動。我將問題追蹤到了我的AsteroidsManager類,該類使用初始小行星的int來生成最小和最大速度和旋轉速度以及兩個用於小行星和粒子的紋理列表。現在的怪事:
temp = new AsteroidManager(1, 20, 50, 1, 2, asteroids, particles, true); //With this constructor, the game always starts fine...
但如果我殺青初步的小行星數量:
temp = new AsteroidManager(10, 20, 50, 1, 2, asteroids, particles, true); //This seems to start about 1/3 times in the Visual Studio debugger, but if I launch it without debugging or from the bin folder, it works fine.
最後,如果我設置的小行星超過〜20,它永遠不會發生在調試器,如果我嘗試從文件夾中啓動它,該進程將出現在任務管理器中,但是沒有任何事情發生。或者它只是在發佈時崩潰。老實說,我不知道是什麼導致了這一點,並在必要時會很樂意提供任何代碼,但在這裏就是我認爲是相關的:
完全AsteroidManager:
public class AsteroidManager
{
#region Declarations
public List<GameObject> Asteroids { get; set; }
public bool RegenerateAsteroids { get; set; }
public readonly int InitialAsteroids;
public readonly float MinVelocity;
public readonly float MaxVelocity;
public readonly float MinRotationalVelocity; //in degrees
public readonly float MaxRotationalVelocity; //in degrees
public readonly List<Texture2D> Textures;
public readonly List<Texture2D> ExplosionParticleTextures;
List<ParticleEmitter> emitters;
Random rnd;
const int MINPARTICLES = 50;
const int MAXPARTICLES = 200;
const int PARTICLEFTL = 40;
#endregion
public AsteroidManager(
int initialAsteroids,
float minVel,
float maxVel,
float minRotVel,
float maxRotVel,
List<Texture2D> textures,
List<Texture2D> explosionParticleTextures,
bool regenAsteroids)
{
rnd = new Random();
InitialAsteroids = initialAsteroids;
MinVelocity = minVel;
MaxVelocity = maxVel;
MinRotationalVelocity = minRotVel;
MaxRotationalVelocity = maxRotVel;
Textures = textures;
ExplosionParticleTextures = explosionParticleTextures;
RegenerateAsteroids = regenAsteroids;
Asteroids = new List<GameObject>();
emitters = new List<ParticleEmitter>();
for (int i = 0; i < InitialAsteroids; i++)
addAsteroid();
}
public void Update(GameTime gameTime)
{
for (int i = 0; i < Asteroids.Count; i++)
Asteroids[i].Update(gameTime);
for (int i = 0; i < emitters.Count; i++)
emitters[i].Update(gameTime);
if (Asteroids.Count < InitialAsteroids && RegenerateAsteroids)
addAsteroid();
}
public void Draw(SpriteBatch spriteBatch)
{
for (int i = 0; i < Asteroids.Count; i++)
Asteroids[i].Draw(spriteBatch);
for (int i = 0; i < emitters.Count; i++)
emitters[i].Draw(spriteBatch);
}
public void DestroyAsteroid(GameObject asteroid)
{
int x = rnd.Next(MINPARTICLES, MAXPARTICLES);
List<Color> colors = new List<Color>();
colors.Add(Color.White);
emitters.Add(new ParticleEmitter(//TODO: Test
x,
asteroid.WorldCenter,
ExplosionParticleTextures,
colors,
PARTICLEFTL,
true,
1,
x,
1f,
0.3f,
0f,
180f));
Asteroids.Remove(asteroid);
}
protected void addAsteroid()
{
GameObject tempAsteroid;
bool isOverlap = false;
do //Do-While to ensure that the asteroid gets generated at least once
{
Texture2D text = Textures.PickRandom<Texture2D>();
float rot = MathHelper.ToRadians((float)rnd.NextDouble(0f, 359f));
float rotVel = MathHelper.ToRadians((float)rnd.NextDouble(MinRotationalVelocity, MaxRotationalVelocity));
int colRadius = (((text.Width/2) + (text.Height/2))/2); //Get the mean of text's height & width
Vector2 vel = Vector2.Multiply(//calculate a random velocity
rot.RotationToVectorFloat(),
(float)rnd.NextDouble(MinVelocity, MaxVelocity));
Vector2 worldPos = new Vector2(
rnd.Next(Camera.WorldRectangle.X, Camera.WorldRectangle.Width),
rnd.Next(Camera.WorldRectangle.Y, Camera.WorldRectangle.Height));
tempAsteroid = new GameObject(//init a temporary asteroid to check for overlaps
text, worldPos, vel, Color.White, false, rot, rotVel, 1f, 0f, colRadius);
foreach (GameObject asteroid in Asteroids)
{
if (tempAsteroid.BoundingBox.Intersects(asteroid.BoundingBox))
{
isOverlap = true;
break;
}
}
} while (isOverlap); //if overlapping, loop
Asteroids.Add(tempAsteroid); //add the temp asteroid
}
}
全部遊戲對象:
public class GameObject
{
#region Declarations
public Texture2D Texture { get; set; }
public Vector2 Origin { get; set; }
public Color TintColor { get; set; }
public float Rotation { get; set; } //radians
public float RotationalVelocity { get; set; }
public float Scale { get; set; }
public float Depth { get; set; }
public bool Active { get; set; }
public SpriteEffects Effects { get; set; }
public Vector2 WorldLocation { get; set; }
public Vector2 Velocity { get; set; }
public int CollisionRadius { get; set; } //Radius for bounding circle collision
public int BoundingXPadding { get; set; }
public int BoundingYPadding { get; set; } //Padding for bounding box collision
public int TotalFrames
{
get //simple get
{ return totalFrames; }
set //check if given totalFrames is in possible range
{
if (value <= (Rows * Columns))
totalFrames = value;
else
throw new ArgumentOutOfRangeException();
}
} //Used in spritesheet animation
private int totalFrames;
public int CurrentFrame
{
get { return currentFrame; }
set
{
currentFrame = (int)MathHelper.Clamp(value, 0, totalFrames);
}
}
private int currentFrame;
public int Rows { get; set; }
public int Columns { get; set; }
public bool Animating { get; set; }
public float RotationDegrees
{
get { return MathHelper.ToDegrees(Rotation); }
set { Rotation = MathHelper.ToRadians(value); }
}
public float RotationVelocityDegrees
{
get { return MathHelper.ToDegrees(RotationalVelocity); }
set { RotationalVelocity = MathHelper.ToRadians(value); }
}
public const float VELOCITYSCALAR = 1.0f/60.0f; //Default to 60fps standard movement
#endregion
#region Properties
public int GetWidth { get { return Texture.Width/Columns; } } //Width of a frame
public int GetHeight { get { return Texture.Height/Rows; } } //Height of a frame
public int GetRow { get { return (int)((float)CurrentFrame/(float)Columns); } } //Current row
public int GetColumn { get { return CurrentFrame % Columns; } } //Current column
public Vector2 SpriteCenter
{ get { return new Vector2(GetWidth/2, GetHeight/2); } } //Get this Sprite's center
public Rectangle WorldRectangle //get rectangle in world coords with width of sprite
{
get
{
return new Rectangle(
(int)WorldLocation.X,
(int)WorldLocation.Y,
GetWidth,
GetHeight);
}
}
public Rectangle BoundingBox //get bounding box for use in collision detection
{
get
{
return new Rectangle(//Get bounding box with respect to padding values
(int)WorldLocation.X + BoundingXPadding,
(int)WorldLocation.Y + BoundingYPadding,
GetWidth - (BoundingXPadding * 2),
GetHeight - (BoundingYPadding * 2));
}
}
public Vector2 ScreenLocation
{ get { return Camera.GetLocalCoords(WorldLocation); } } //get screen coordinates
public Rectangle ScreenRectangle
{ get { return Camera.GetLocalCoords(WorldRectangle); } } //get screen rectangle
public Vector2 WorldCenter
{
get { return WorldLocation + SpriteCenter; }
set { WorldLocation = value - SpriteCenter; }
} //gets/sets the center of the sprite in world coords
public Vector2 ScreenCenter
{ get { return Camera.GetLocalCoords(WorldLocation + SpriteCenter); } } //returns the center in screen coords
#endregion
public GameObject(//main constructor, /w added optional parameters and call to SpriteBase init
Texture2D texture,
Vector2 worldLocation,
Vector2 velocity,
Color tintColor,
bool animating = false,
float rotation = 0f, //default to no rotation
float rotationalVelocity = 0f,
float scale = 1f, //default to 1:1 scale
float depth = 0f, //default to 0 layerDepth
int collisionRadius = 0, //collision radius used in bounding circle collision, default to 0 or no bounding circle
int xPadding = 0, //amount of x padding, used in bounding box collision, default to 0, or no bounding box
int yPadding = 0, //amount of y padding, used in bounding box collision, default to 0, or no bounding box
SpriteEffects effects = SpriteEffects.None,
int totalFrames = 0,
int rows = 1,
int columns = 1)
{
if (texture == null) { throw new NullReferenceException("Null texture reference."); }
Texture = texture; //assign parameters
WorldLocation = worldLocation;
TintColor = tintColor;
Rotation = rotation;
RotationalVelocity = rotationalVelocity;
Scale = scale;
Depth = depth;
Effects = effects;
Velocity = velocity;
Animating = animating;
Active = true;
BoundingXPadding = xPadding; BoundingYPadding = yPadding; CollisionRadius = collisionRadius; //assign collision data
Rows = rows; Columns = columns; this.TotalFrames = totalFrames; //assign animation data
Origin = SpriteCenter; //assign origin to the center of a frame
}
#region Methods
public virtual void Update(GameTime gameTime)
{
if (Active) //if object is active
{
WorldLocation += Velocity * (1f/60f);
Rotation += RotationalVelocity; //Rotate according to the velocity
//Move by Velocity times a roughly 60FPS scalar
if (TotalFrames > 1 && Animating)
{
CurrentFrame++;
if (CurrentFrame >= TotalFrames)
CurrentFrame = 0; //Loop animation
}
if (Camera.IsObjectInWorld(this.WorldRectangle) == false)
{
if (Camera.LOOPWORLD) //if world is looping and the object is out of bounds
{
Vector2 temp = WorldCenter; //temporary Vector2 used for updated position
//X-Axis Component
if (WorldCenter.X > Camera.WorldRectangle.Width)
temp.X = Camera.WorldRectangle.X - (GetWidth/2); //If X is out of bounds to the right, move X to the left side
if (WorldCenter.X < Camera.WorldRectangle.X)
temp.X = Camera.WorldRectangle.Width + (GetWidth/2); //If X is out of bound to the left, move X to the right side
//Y-Axis Component
if (WorldCenter.Y > Camera.WorldRectangle.Height)
temp.Y = Camera.WorldRectangle.Y - (GetHeight/2); //If Y is out of bounds to the bottom, move Y to the top
if (WorldCenter.Y < Camera.WorldRectangle.Y)
temp.Y = Camera.WorldRectangle.Height + (GetHeight/2); //If Y is out of bounds to the top, move Y to the bottom
WorldCenter = temp; //Assign updated position
}
if (Camera.LOOPWORLD == false)
{
Active = false; //if the object is outside the world but the LOOPWORLD constant is false, set inactive
}
}
}
}
public virtual void Draw(SpriteBatch spriteBatch)
{
if (Active)
{
if (TotalFrames > 1 && Camera.IsObjectVisible(WorldRectangle)) //if multi-frame animation & object is visible
{
Rectangle sourceRectangle = new Rectangle(GetWidth * GetColumn,
GetHeight * GetRow, GetWidth, GetHeight); //get source rectangle to use
spriteBatch.Draw(
Texture,
ScreenCenter,
sourceRectangle, //use generated source rectangle
TintColor,
Rotation,
Origin,
Scale,
Effects,
Depth);
}
else //if single frame sprite
{
if (Camera.IsObjectVisible(WorldRectangle)) //check if sprite is visible to camera
{
spriteBatch.Draw(
Texture,
ScreenCenter, //center of the sprite in local coords
null, //full sprite
TintColor,
Rotation,
Origin,
Scale,
Effects, //spriteeffects
Depth); //layerdepth
}
}
}
}
public bool IsBoxColliding(Rectangle obj) //bounding box collision test
{
return BoundingBox.Intersects(obj);
}
public bool IsBoxColliding(GameObject obj) //overload of previous which takes a GameObject instead of a rectangle
{
if (BoundingBox.Intersects(obj.BoundingBox))
return true;
else
return false;
}
public bool IsCircleColliding(Vector2 objCenter, float objRadius)
{
if (Vector2.Distance(WorldCenter, objCenter) <
(CollisionRadius + objRadius)) //if the distance between centers is greater than the sum
return true; //of the radii, collision has occurred
else
return false; //if not, return false
}
public bool IsCircleColliding(GameObject obj) //overload of previous which takes a GameObject instead of loose values
{
if (Vector2.Distance(this.WorldCenter, obj.WorldCenter) <
(CollisionRadius + obj.CollisionRadius))
return true;
else
return false;
}
public void RotateTo(Vector2 point) //rotates the GameObject to a point
{
Rotation = (float)Math.Atan2(point.Y, point.X);
}
protected Vector2 rotationToVector()
{
return Rotation.RotationToVectorFloat();
} //local version of extension method
#endregion
}
Game1 Draw:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(); //BEGIN SPRITE DRAW
fpsDisplay.Draw(spriteBatch);
temp.Draw(spriteBatch);
spriteBatch.End(); //END SPRITE DRAW
base.Draw(gameTime);
}
Game1更新:
protected override void Update(GameTime gameTime)
{
InputHandler.Update(); //update InputHandler
if (InputHandler.IsKeyDown(Keys.Left))
Camera.Position += new Vector2(-3f, 0f);
if (InputHandler.IsKeyDown(Keys.Right))
Camera.Position += new Vector2(3f, 0f);
if (InputHandler.IsKeyDown(Keys.Up))
Camera.Position += new Vector2(0f, -3f);
if (InputHandler.IsKeyDown(Keys.Down))
Camera.Position += new Vector2(0f, 3f);
fpsDisplay.Value = (int)Math.Round(1/gameTime.ElapsedGameTime.TotalSeconds, 0);
//calculate framerate to the nearest int
temp.Update(gameTime);
base.Update(gameTime);
}
現在很好用,謝謝!我甚至沒有考慮到一個無限循環是問題。 – Lexusjjss
當然要注意,如果它找不到小行星的地方,它將被踢出。因此,如果您指定了20個小行星,則最終只能有16個。 –