This sounds like a very n00b question, but bear with me here:
I'm trying to access the position of my bat (paddle) in my pong game and use it in my ball class. I'm doing this because I want a particle effect to go off at the point of contact where the ball hits the bat.
Each time the ball hits the bat, I receive an error stating that I haven't created an instance of the bat. I understand that I have to (or can use a static class), but I'm not sure of how to do so in this example.
I've included both my Bat and Ball classes.
namespace Pong
{
#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
#endregion
public class Ball
{
#region Fields
private readonly Random rand;
private readonly Texture2D texture;
private readonly SoundEffect warp;
private double direction;
private bool isVisible;
private float moveSpeed;
private Vector2 position;
private Vector2 resetPos;
private Rectangle size;
private float speed;
private bool isResetting;
private bool collided;
private Vector2 oldPos;
private ParticleEngine particleEngine;
private ContentManager contentManager;
private SpriteBatch spriteBatch;
private bool hasHitBat;
private AIBat aiBat;
private Bat bat;
#endregion
#region Constructors and Destructors
/// <summary>
/// Constructor for the ball
/// </summary>
public Ball(ContentManager contentManager, Vector2 ScreenSize)
{
moveSpeed = 15f;
speed = 0;
texture = contentManager.Load<Texture2D>(@"gfx/balls/redBall");
direction = 0;
size = new Rectangle(0, 0, texture.Width, texture.Height);
resetPos = new Vector2(ScreenSize.X / 2, ScreenSize.Y / 2);
position = resetPos;
rand = new Random();
isVisible = true;
hasHitBat = false;
// Everything to do with particles
List<Texture2D> textures = new List<Texture2D>();
textures.Add(contentManager.Load<Texture2D>(@"gfx/particle/circle"));
textures.Add(contentManager.Load<Texture2D>(@"gfx/particle/star"));
textures.Add(contentManager.Load<Texture2D>(@"gfx/particle/diamond"));
particleEngine = new ParticleEngine(textures, new Vector2());
}
#endregion
#region Public Methods and Operators
/// <summary>
/// Checks for the collision between the bat and the ball. Sends ball in the appropriate
/// direction
/// </summary>
public void BatHit(int block)
{
if (direction > Math.PI * 1.5f || direction < Math.PI * 0.5f)
{
hasHitBat = true;
particleEngine.EmitterLocation = new Vector2(aiBat.Position.X, aiBat.Position.Y);
switch (block)
{
case 1:
direction = MathHelper.ToRadians(200);
break;
case 2:
direction = MathHelper.ToRadians(195);
break;
case 3:
direction = MathHelper.ToRadians(180);
break;
case 4:
direction = MathHelper.ToRadians(180);
break;
case 5:
direction = MathHelper.ToRadians(165);
break;
}
}
else
{
hasHitBat = true;
particleEngine.EmitterLocation = new Vector2(bat.Position.X, bat.Position.Y);
switch (block)
{
case 1:
direction = MathHelper.ToRadians(310);
break;
case 2:
direction = MathHelper.ToRadians(345);
break;
case 3:
direction = MathHelper.ToRadians(0);
break;
case 4:
direction = MathHelper.ToRadians(15);
break;
case 5:
direction = MathHelper.ToRadians(50);
break;
}
}
if (rand.Next(2) == 0)
{
direction += MathHelper.ToRadians(rand.Next(3));
}
else
{
direction -= MathHelper.ToRadians(rand.Next(3));
}
AudioManager.Instance.PlaySoundEffect("hit");
}
/// <summary>
/// JEP - added method to slow down ball after powerup deactivates
/// </summary>
public void DecreaseSpeed()
{
moveSpeed -= 0.6f;
}
/// <summary>
/// Draws the ball on the screen
/// </summary>
public void Draw(SpriteBatch spriteBatch)
{
if (isVisible)
{
spriteBatch.Begin();
spriteBatch.Draw(texture, size, Color.White);
spriteBatch.End();
// Draws sprites for particles when contact is made
particleEngine.Draw(spriteBatch);
}
}
/// <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 position;
}
/// <summary>
/// Checks for the current size of the ball (for the powerups)
/// </summary>
public Rectangle GetSize()
{
return size;
}
/// <summary>
/// Grows the size of the ball when the GrowBall powerup is used.
/// </summary>
public void GrowBall()
{
size = new Rectangle(0, 0, texture.Width * 2, texture.Height * 2);
}
/// <summary>
/// Was used to increased the speed of the ball after each point is scored.
/// No longer used, but am considering implementing again.
/// </summary>
public void IncreaseSpeed()
{
moveSpeed += 0.6f;
}
/// <summary>
/// Check for the ball to return normal size after the Powerup has expired
/// </summary>
public void NormalBallSize()
{
size = new Rectangle(0, 0, texture.Width, texture.Height);
}
/// <summary>
/// Check for the ball to return normal speed after the Powerup has expired
/// </summary>
public void NormalSpeed()
{
moveSpeed += 15f;
}
/// <summary>
/// Checks to see if ball went out of bounds, and triggers warp sfx
/// </summary>
public void OutOfBounds()
{
// Checks if the player is still alive or not
if (isResetting)
{
AudioManager.Instance.PlaySoundEffect("warp");
{
// Used to stop the the issue where the ball hit sfx kept going off when detecting collison
isResetting = false;
AudioManager.Instance.Dispose();
}
}
}
/// <summary>
/// Speed for the ball when Speedball powerup is activated
/// </summary>
public void PowerupSpeed()
{
moveSpeed += 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;
}
// Used to stop the the issue where the ball hit sfx kept going off when detecting collison
isResetting = true;
position = resetPos; // 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()
{
size = 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;
}
/// <summary>
/// Updates position of the ball
/// </summary>
public void UpdatePosition()
{
size.X = (int)position.X;
size.Y = (int)position.Y;
oldPos.X = position.X;
oldPos.Y = position.Y;
position.X += speed * (float)Math.Cos(direction);
position.Y += speed * (float)Math.Sin(direction);
bool collided = CheckWallHit();
particleEngine.Update();
// Stops the issue where ball was oscillating on the ceiling or floor
if (collided)
{
position.X = oldPos.X + speed * (float)Math.Cos(direction);
position.Y = oldPos.Y + speed * (float)Math.Sin(direction);
}
}
#endregion
#region Methods
/// <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 (position.Y <= 0 || (position.Y > resetPos.Y * 2 - size.Height))
{
direction = 2 * Math.PI - direction;
return true;
}
return true;
}
#endregion
}
}
namespace Pong
{
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using System;
public class Bat
{
public Vector2 Position;
public float moveSpeed;
public Rectangle size;
private int points;
private int yHeight;
private Texture2D leftBat;
public float turbo;
public float recharge;
public float interval;
public bool isTurbo;
/// <summary>
/// Constructor for the bat
/// </summary>
public Bat(ContentManager contentManager, Vector2 screenSize, bool side)
{
moveSpeed = 7f;
turbo = 15f;
recharge = 100f;
points = 0;
interval = 5f;
leftBat = contentManager.Load<Texture2D>(@"gfx/bats/batGrey");
size = new Rectangle(0, 0, leftBat.Width, leftBat.Height);
// True means left bat, false means right bat.
if (side) Position = new Vector2(30, screenSize.Y / 2 - size.Height / 2);
else Position = new Vector2(screenSize.X - 30, screenSize.Y / 2 - size.Height / 2);
yHeight = (int)screenSize.Y;
}
public void IncreaseSpeed()
{
moveSpeed += .5f;
}
/// <summary>
/// The speed of the bat when Turbo is activated
/// </summary>
public void Turbo()
{
moveSpeed += 8.0f;
}
/// <summary>
/// Returns the speed of the bat back to normal after Turbo is deactivated
/// </summary>
public void DisableTurbo()
{
moveSpeed = 7.0f;
isTurbo = false;
}
/// <summary>
/// Returns the bat to the nrmal size after the Grow/Shrink powerup has expired
/// </summary>
public void NormalSize()
{
size = new Rectangle(0, 0, leftBat.Width, leftBat.Height);
}
/// <summary>
/// Checks for the size of the bat
/// </summary>
public Rectangle GetSize()
{
return size;
}
/// <summary>
/// Adds point to the player or the AI after scoring. Currently Disabled.
/// </summary>
public void IncrementPoints()
{
points++;
}
/// <summary>
/// Checks for the number of points at the moment
/// </summary>
public int GetPoints()
{
return points;
}
/// <summary>
/// Sets thedefault starting position for the bats
/// </summary>
/// <param name="position"></param>
public void SetPosition(Vector2 position)
{
if (position.Y < 0)
{
position.Y = 0;
}
if (position.Y > yHeight - size.Height)
{
position.Y = yHeight - size.Height;
}
this.Position = position;
}
/// <summary>
/// Checks for the current position of the bat
/// </summary>
public Vector2 GetPosition()
{
return Position;
}
/// <summary>
/// Controls the bat moving up the screen
/// </summary>
public void MoveUp()
{
SetPosition(Position + new Vector2(0, -moveSpeed));
}
/// <summary>
/// Controls the bat moving down the screen
/// </summary>
public void MoveDown()
{
SetPosition(Position + new Vector2(0, moveSpeed));
}
/// <summary>
/// Updates the position of the AI bat, in order to track the ball
/// </summary>
/// <param name="ball"></param>
public virtual void UpdatePosition(Ball ball)
{
size.X = (int)Position.X;
size.Y = (int)Position.Y;
}
/// <summary>
/// Resets the bat to the center location after a new game starts
/// </summary>
public void ResetPosition()
{
SetPosition(new Vector2(GetPosition().X, yHeight / 2 - size.Height));
}
/// <summary>
/// Used for the Growbat powerup
/// </summary>
public void GrowBat()
{
// Doubles the size of the bat collision
size = new Rectangle(0, 0, leftBat.Width * 2, leftBat.Height * 2);
}
/// <summary>
/// Used for the Shrinkbat powerup
/// </summary>
public void ShrinkBat()
{
// 1/2 the size of the bat collision
size = new Rectangle(0, 0, leftBat.Width / 2, leftBat.Height / 2);
}
/// <summary>
/// Draws the bats
/// </summary>
public virtual void Draw(SpriteBatch batch)
{
batch.Draw(leftBat, size, Color.White);
}
}
}