So I just finished up doing a class for my wandering & pursuing enemies yet once I've gone through and declared the class and done the necessary coding when I run the game I get a NullReferenceException pop up which then tells me that the field Virtual_Alien is never assigned and will always have the default value of null.
What am I doing wrong here?
main game code:
private Roaming_Aliens roamingAlien;
private Virtual_Aliens virtualAlien;
public Vector2 playerPosition;
public Player mainPlayer = new Player();
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
mainPlayer.position = playerPostion;
// now assign that image to each of the characters we have
roamingAlien.LoadContent(Content);
virtualAlien.LoadContent(Content);
mainPlayer.LoadContent(Content);
score.LoadContent(Content);
// mainBackground.LoadContent(Content);
}
protected override void Update(GameTime gameTime)
{
currentKey = Keyboard.GetState();
if (currentKey.IsKeyDown(Keys.Escape))
{
this.Exit();
}
mainPlayer.Update(gameTime);
score.Update(gameTime);
virtualAlien.Update(gameTime);
roamingAlien.Wander();
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
//mainBackground.Draw(spriteBatch);
mainPlayer.Draw(spriteBatch);
virtualAlien.Draw(spriteBatch);
roamingAlien.Draw(spriteBatch);
spriteBatch.End();
}
Virtual alien code:
public class Virtual_Aliens
{
private enum TankAiState
{
Chasing,
Wander
}
private float maxSpeed;
private float maxRotation;
private float chaseDistance;
private float hysteresis;
private Texture2D texture;
private Vector2 drawingOrigin;
private Vector2 position;
private TankAiState tankState = TankAiState.Wander;
private float orientation;
private Random random = new Random();
private Rectangle viewportbounds;
public Rectangle boundingBox;
public Vector2 playerPosition;
private Vector2 heading;
public Virtual_Aliens(Rectangle pos, Rectangle b)
{
position = new Vector2 (100, 100);
boundingBox = new Rectangle(pos.X, pos.Y, pos.Width, pos.Height);
viewportbounds = new Rectangle(b.X, b.Y, b.Width, b.Height);
orientation = 0.0f;
heading = new Vector2(0, 0);
maxSpeed = 2.0f;
maxRotation = 0.20f;
random = new Random();
hysteresis = 15.0f;
chaseDistance = 250.0f;
}
public void LoadContent(ContentManager Content)
{
texture = Content.Load<Texture2D>("images/asteroid");
}
private Vector2 OrientationAsVector(float orien)
{
Vector2 orienAsVect;
orienAsVect.X = (float)Math.Cos(orien);
orienAsVect.Y = (float)Math.Sin(orien);
return orienAsVect;
}
Vector2 wanderPosition = new Vector2();
public void Wander()
{
// The wander effect is accomplished by having the character aim in a random
// direction. Every frame, this random direction is slightly modified.
// the max +/- the agent will wander from its current position
float wanderLimits = 0.5f;
// this defines what proportion of its maxRotation speed the agent will turn
float turnFactor = 0.15f;
// randomly define a new position
wanderPosition.X += MathHelper.Lerp(-wanderLimits, wanderLimits, (float)random.NextDouble());
wanderPosition.Y += MathHelper.Lerp(-wanderLimits, wanderLimits, (float)random.NextDouble());
// normalize the wander position, ...
if (wanderPosition != Vector2.Zero)
wanderPosition.Normalize();
// now find the new orientation based on the wanderPosition
orientation = TurnToFace(wanderPosition, orientation, turnFactor * maxRotation);
// determine the heading vector based on orientation
heading = OrientationAsVector(orientation);
// finally update the agents position based upon the new heading and its speed
// assume a wandering agent only moves at 0.5 of maxSpeed
position += heading * 0.5f * maxSpeed;
WrapForViewport();
}
private void WrapForViewport()
{
if (position.X < 0)
{
position.X = viewportbounds.Width;
}
else if (position.X > viewportbounds.Width)
{
position.X = 0;
}
if (position.Y < 0)
{
position.Y = viewportbounds.Height;
}
else if (position.Y > viewportbounds.Height)
{
position.Y = 0;
}
}
private float WrapAngle(float radian)
{
while (radian < -MathHelper.Pi)
{
radian += MathHelper.TwoPi;
}
while (radian > MathHelper.Pi)
{
radian -= MathHelper.TwoPi;
}
return radian;
}
private float TurnToFace(Vector2 steering, float currentOrientation, float turnSpeed)
{
float newOrientation;
float desiredOrientation;
float orientationDifference;
float x = steering.X;
float y = steering.Y;
// the desiredOrientation is given by the steering vector
desiredOrientation = (float)Math.Atan2(y, x);
// find the difference between the orientation we need to be
// and our current Orientation
orientationDifference = desiredOrientation - currentOrientation;
// now using WrapAngle to get result from -Pi to Pi
// ( -180 degrees to 180 degrees )
orientationDifference = WrapAngle(orientationDifference);
// clamp that between -turnSpeed and turnSpeed.
orientationDifference = MathHelper.Clamp(orientationDifference, -turnSpeed, turnSpeed);
// the closest we can get to our target is currentAngle + orientationDifference.
// return that, using WrapAngle again.
newOrientation = WrapAngle(currentOrientation + orientationDifference);
return newOrientation;
}
public void Update(GameTime gameTime)
{
if (tankState == TankAiState.Wander)
{
chaseDistance -= hysteresis / 2;
}
else if (tankState == TankAiState.Chasing)
{
chaseDistance += hysteresis / 2;
}
// Second, now that we know what the thresholds are, we compare the tank's
// distance from the cat against the thresholds to decide what the tank's
// current state is.
float distanceFromPlayer = Vector2.Distance(position, playerPosition);
if (distanceFromPlayer > chaseDistance)
{
// just like the mouse, if the tank is far away from the cat, it should
// idle.
tankState = TankAiState.Wander;
}
else
{
tankState = TankAiState.Chasing;
}
// Third, once we know what state we're in, act on that state.
float currentTankSpeed;
if (tankState == TankAiState.Chasing)
{
// the tank wants to chase the cat, so it will just use the TurnToFace
// function to turn towards the cat's position. Then, when the tank
// moves forward, he will chase the cat.
orientation = TurnToFace(playerPosition, orientation, maxRotation);
currentTankSpeed = maxSpeed;
}
else if (tankState == TankAiState.Wander)
{
Wander();
}
}
public void Draw(SpriteBatch spriteBatch)
{
drawingOrigin = new Vector2(texture.Width / 2, texture.Height / 2);
spriteBatch.Draw(texture, position, null, Color.White, orientation, drawingOrigin, 1.0f, SpriteEffects.None, 0.0f);
}
public Vector2 PlayerPosition
{
set
{
playerPosition = value;
}
get
{
return playerPosition;
}
}
}
You declare (twice actually) a variable called virtualAlien (of type Virtual_Aliens). However, you never assign it anything (while using it all over the place.
You declaration needs to look like:
Virtual_Alien virtualAlien = new Virtual_Alien();
This is assigns it to a new instance of the Virtual_Alien class, allowing you to use it later on. If you need parameters that aren't available until later, put the instantiation at the point when all needed information is available, and add null checks around any use of the variable that could happen before the instantiating code is called.
The romaingAlien member appears to have a similar problem.
Related
I have a rotating circle sprite in Unity.
private void Update()
{
transform.Rotate(0, 0, 10 * Time.deltaTime);
}
and in my Start method I want to split this sprite into several pieces. I put in an array of colors as a parameter.
private void SetColors(Color[] colors)
{
// divide into color pieces
}
For example I pass in red, blue, green, yellow the circle should look like this
The amount of possible colors is unlimited.
The circle itself got a circle trigger attached. When detecting a trigger collision I want to detect which color was hit.
private void OnTriggerEnter2D(Collider2D col)
{
if (col.gameObject == ball)
{
// Color hitColor = the color that was hit
}
}
Is it possible with a simple circle sprite?
Update:
Maybe this problem might be easier to solve if I say that when the circle gets hit by something it's always at the top of the circle
I might calculate the current hit color by using the rotation speed over time.
Maybe a bit late but I found this interresting so:
This component is placed on an empty GameObject within a Canvas. It is responsible for creating and updating the segments (and for the simulation controles the cursor object with a circle collider)
public class CircleController : MonoBehaviour
{
public RectTransform rectTransform;
public List<Color> InitialColors = new List<Color>();
private List<Circlesegment> segments = new List<Circlesegment>();
public Circlesegment circleSeggmentPrefab;
public float firstSegmentAngleOffset = 0f;
// maximum vertices to use for the circle
// equally spread over all segments so not always uses all of them
public int totalMaxVertices = 50;
private void Awake()
{
rectTransform = GetComponent<RectTransform>();
// if 0 start first segment at top
var startAngle = firstSegmentAngleOffset;
var anglePerSegment = 360f / InitialColors.Count;
var verticesPerSegment = totalMaxVertices / InitialColors.Count;
foreach (var initialColor in InitialColors)
{
var segment = Instantiate(circleSeggmentPrefab, transform);
segment.Initialize(this, initialColor, verticesPerSegment, rectTransform.rect.width / 2f, startAngle, anglePerSegment);
segments.Add(segment);
startAngle += anglePerSegment;
}
}
// Used this to simulate the collisions using the mouse
private CircleCollider2D cursor;
//used this to simulate the collision using mouse
private void Update()
{
if (!cursor)
{
cursor = new GameObject("cursor simulator", typeof(CircleCollider2D)).GetComponent<CircleCollider2D>();
cursor.radius = 10;
cursor.enabled = false;
}
cursor.transform.position = Input.mousePosition;
if (Input.GetMouseButtonDown(0))
{
cursor.enabled = true;
}
else if (Input.GetMouseButtonUp(0))
{
cursor.enabled = false;
}
}
public void RemoveSegment(Circlesegment segment)
{
segments.Remove(segment);
Destroy(segment.gameObject);
if (segments.Count == 0)
{
Debug.Log("GameOver!");
return;
}
var startAngle = firstSegmentAngleOffset;
var anglePerSegment = 360f / segments.Count;
var verticesPerSegment = totalMaxVertices / segments.Count;
foreach (var circleSegment in segments)
{
circleSegment.AnimateTowards(verticesPerSegment, startAngle, anglePerSegment);
startAngle += anglePerSegment;
}
}
}
This component is attached to the circleSegmentPrefab
[RequireComponent(typeof(RectTransform))]
[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(EdgeCollider2D))]
[RequireComponent(typeof(Image))]
public class Circlesegment : MonoBehaviour
{
[SerializeField] Image image;
[SerializeField] EdgeCollider2D collider;
[SerializeField] Rigidbody2D rigidBody;
[SerializeField] RectTransform rectTransform;
[SerializeField] private int _segments;
[SerializeField] private float _startAngle;
[SerializeField] private float _segmentAngle;
private float _radius;
private CircleController circleController;
public Color Color;
private void OnCollisionEnter2D(Collision2D other)
{
circleController.RemoveSegment(this);
}
public void Initialize(CircleController controller, Color color, int segments, float radius, float startAngle, float segmentAngle)
{
Color = color;
circleController = controller;
_radius = radius;
if (!image) image = GetComponent<Image>();
if (!collider) collider = GetComponent<EdgeCollider2D>();
if (!rigidBody) rigidBody = GetComponent<Rigidbody2D>();
if (!rectTransform) rectTransform = GetComponent<RectTransform>();
image.color = color;
rectTransform.sizeDelta = new Vector2(radius * 2, radius * 2);
UpdateSegment(segments, startAngle, segmentAngle);
}
public void AnimateTowards(int segments, float startAngle, float segmentAngle, float duration = 1f)
{
StopAllCoroutines();
StartCoroutine(AnimateTowardsroutine(segments, startAngle, segmentAngle, duration));
}
private IEnumerator AnimateTowardsroutine(int segments, float startAngle, float segmentAngle, float duration)
{
var timePassed = 0f;
var currentStartAngle = _startAngle;
var currentSegmentAngle = _segmentAngle;
while (timePassed <= duration)
{
var lerpFactor = timePassed / duration;
UpdateSegment(segments, Mathf.LerpAngle(currentStartAngle, startAngle, lerpFactor), Mathf.LerpAngle(currentSegmentAngle, segmentAngle, lerpFactor));
timePassed += Mathf.Min(duration - timePassed, Time.deltaTime);
yield return null;
}
UpdateSegment(segments, startAngle, segmentAngle);
}
public void UpdateSegment(int segments, float startAngle, float segmentAngle)
{
_segments = segments;
_startAngle = startAngle;
_segmentAngle = segmentAngle;
var arcPoints = new List<Vector2>();
var angle = 0f;
var arcLength = segmentAngle;
if (!Mathf.Approximately(Mathf.Abs(segmentAngle), 360)) arcPoints.Add(Vector2.zero);
// calculate procedural circle vertices
for (var i = 0; i <= segments; i++)
{
var x = Mathf.Sin(Mathf.Deg2Rad * angle) * _radius;
var y = Mathf.Cos(Mathf.Deg2Rad * angle) * _radius;
arcPoints.Add(new Vector2(x, y));
angle += (arcLength / segments);
}
if (!Mathf.Approximately(Mathf.Abs(segmentAngle), 360)) arcPoints.Add(Vector2.zero);
image.fillAmount = arcLength / 360f;
rigidBody.rotation = startAngle;
collider.points = arcPoints.ToArray();
}
// For testing
[ContextMenu("UpdateSegment")]
private void UpdateSegment()
{
UpdateSegment(_segments, _startAngle, _segmentAngle);
}
//For testing
[ContextMenu("AnimateTowards")]
private void AnimateTowards()
{
AnimateTowards(_segments, _startAngle, _segmentAngle);
}
}
Demo
Image settings on the prefab
looks shitty because of the default Knob texture .. you should use a better quality circle texture.
I'm new to this so not completely sure whether I am posting this correctly, but I have been having a few issues when creating my game. My main goal is to create a topdown shooter styled game, using movement where the 'player' rotates based on the current position of the mouse and can press 'w' to move towards it at a set speed.
The main issue is, when the game loads, the movement works exactly how I want it to, but the texture itself is not moving, but only the drawRectangle.
Game1.cs:
player = new Player(Content, #"graphics\Player1", 500, 500, spritePosition);
spritePosition = new Vector2(player.CollisionRectangle.X, player.CollisionRectangle.Y);
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
KeyboardState keyboard = Keyboard.GetState();
MouseState mouse = Mouse.GetState();
IsMouseVisible = true;
distance.X = mouse.X - spritePosition.X;
distance.Y = mouse.Y - spritePosition.Y;
//Works out the rotation depending on how far away mouse is from sprite
rotation = (float)Math.Atan2(distance.Y, distance.X);
// TODO: Add your update logic here
spritePosition = spriteVelocity + spritePosition;
spriteOrigin = new Vector2(player.DrawRectangle.X / 2, player.DrawRectangle.Y / 2);
if (Keyboard.GetState().IsKeyDown(Keys.W))
{
spriteVelocity.X = (float)Math.Cos(rotation) * tangentialVelocity;
spriteVelocity.Y = (float)Math.Sin(rotation) * tangentialVelocity;
}
else if(spriteVelocity != Vector2.Zero)
{
Vector2 i = spriteVelocity;
spriteVelocity = i -= friction * i;
}
This is the main movement code from the Update function as well as where the new player has been created.
Player.cs:
class Player
{
Texture2D sprite;
Rectangle drawRectangle;
int health = 100;
public Player(ContentManager contentManager, string spriteName, int x , int y, Vector2 velocity)
{
LoadContent(contentManager, spriteName, x, y, velocity);
}
public Rectangle CollisionRectangle
{
get { return drawRectangle; }
}
public Rectangle DrawRectangle
{
get { return drawRectangle; }
set { drawRectangle = value; }
}
public int Health
{
get { return health; }
set {
health = value;
if (health <= 0)
health = 0;
if (health > 100)
health = 100;
}
}
public Vector2 Velocity
{
get { return Velocity; }
set { Velocity = value; }
}
public void Update(GameTime gameTime, KeyboardState keyboard, MouseState mouse)
{
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(sprite, drawRectangle, Color.White);
}
private void LoadContent(ContentManager contentManager, string spriteName, int x, int y, Vector2 velocity)
{
sprite = contentManager.Load<Texture2D>(spriteName);
drawRectangle = new Rectangle(x - sprite.Width / 2, y - sprite.Height / 2, sprite.Width, sprite.Height);
}
}
I didn't know what to include in the Update function of the player.cs, whether the code for movement should go in there or the main Game1.cs.
Hopefully this is enough code for you guys to be able to help. Sorry for there being quite a lot of code, but I'm just unsure where the error is occurring.
Thanks in advance
For the rotation you would want to use 'another' kind of spriteBatch.Draw, because the draw function can have more parameters than your currently using.
The full draw function is as followed:
SpriteBatch.Draw(Texture2D texture, Vector2 position, Rectangle sourceRectangle, Color color, float rotation, Vector2 origin, float scale, SpriteEffects effects, float layerdepht)
As you can see, now we have a parameter for rotation that can be used.
So your code will look something like this:
spriteBatch.Draw(sprite, drawRectangle, null, Color.White, rotation, Vector2.Zero, 1, SpriteEffects.None, 0);
As for your question for where your code should go. It is good to learn yourself to put the code where it belongs, in this case the player. Because when your programs become bigger, it would be very messy to do it this way.
To call the update function in your player class, you can just simply call player.Update(gameTime, keyboard, mouse) in the Update of Game1.
I am drawing a line in XNA which I want to never end. I also have a tool that moves forward in X-direction and a camera which is centered at this tool. However, when I reach the end of the viewport the lines are not drawn anymore. Here are some pictures to illustrate my problem:
At the start the line goes across the whole screen, but as my tool moves forward, we reach the end of the line.
Here are the method which draws the lines:
private void DrawEvenlySpacedSprites (Texture2D texture, Vector2 point1, Vector2 point2, float increment)
{
var distance = Vector2.Distance (point1, point2); // the distance between two points
var iterations = (int)(distance / increment); // how many sprites with be drawn
var normalizedIncrement = 1.0f / iterations; // the Lerp method needs values between 0.0 and 1.0
var amount = 0.0f;
if (iterations == 0)
iterations = 1;
for (int i = 0; i < iterations; i++) {
var drawPoint = Vector2.Lerp (point1, point2, amount);
spriteBatch.Draw (texture, drawPoint, Color.White);
amount += normalizedIncrement;
}
}
Here are the draw method in Game. The dots are my lines:
protected override void Draw (GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.Black);
nyVector = nextVector (gammelVector);
GraphicsDevice.SetRenderTarget (renderTarget);
spriteBatch.Begin ();
DrawEvenlySpacedSprites (dot, gammelVector, nyVector, 0.9F);
spriteBatch.End ();
GraphicsDevice.SetRenderTarget (null);
spriteBatch.Begin (SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, null, null, camera.transform);
spriteBatch.Draw (renderTarget, new Vector2 (), Color.White);
spriteBatch.Draw (tool, new Vector2(toolPos.X - (tool.Width/2), toolPos.Y - (tool.Height/2)), Color.White);
spriteBatch.End ();
gammelVector = new Vector2 (nyVector.X, nyVector.Y);
base.Draw (gameTime);
}
Can anyone point me in the right direction here? I'm guessing it has to do with the viewport.width, but I'm not quite sure how to solve it. Thank you for reading!
I read this and thought it would be a fun exercise this morning, so I decided to write this for fun.
The implementation is pretty simple, keep adding lines at the end of each other until the last line is outside of the viewable area.
The following code will draw a line infinitely going right. As an added optimization, the lines on the left side of the screen are deleted as you pass them. You could easily make it retain the lines that were there previously, or also create lines going left as well. I will leave these exercises to you.
Take a look at the following Line class, which will define a single line on screen:
public class Line
{
Texture2D Texture;
Color Color;
public Vector2 PointA;
public Vector2 PointB;
float Width;
public Line(Vector2 pointA, Vector2 pointB, float width, Color color, Texture2D texture)
{
Texture = texture;
PointA = pointA;
PointB = pointB;
Width = width;
Color = color;
}
public void Draw(SpriteBatch spritebatch)
{
float angle = (float)Math.Atan2(PointB.Y - PointA.Y, PointB.X - PointA.X);
float length = Vector2.Distance(PointA, PointB);
spritebatch.Draw(Texture, PointA, null, Color, angle, Vector2.Zero, new Vector2(length, Width), SpriteEffects.None, 0);
}
}
I wrote the implementation inside of a game class, since I was speedcoding. You can see the Game class below:
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Camera Camera;
Texture2D LineTexture;
List<Line> Lines;
Random Random;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
Camera = new Camera(GraphicsDevice.Viewport, 1f);
LineTexture = new Texture2D(GraphicsDevice, 1, 1);
LineTexture.SetData<Color>(new Color[] { Color.White });
Random = new Random();
Lines = new List<Line>();
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
//handle input
KeyboardState kbState = Keyboard.GetState();
if (kbState.IsKeyDown(Keys.Escape))
this.Exit();
if (kbState.IsKeyDown(Keys.OemMinus))
Camera.Zoom -= 0.015f;
else if (kbState.IsKeyDown(Keys.OemPlus))
Camera.Zoom += 0.015f;
if (kbState.IsKeyDown(Keys.Up))
Camera.Move(new Vector2(0, -30));
else if (kbState.IsKeyDown(Keys.Down))
Camera.Move(new Vector2(0, 30));
if (kbState.IsKeyDown(Keys.Left))
Camera.Move(new Vector2(-30, 0));
else if (kbState.IsKeyDown(Keys.Right))
Camera.Move(new Vector2(30, 0));
//check if line is still in viewport - if not remove it
for (int i = 0; i < Lines.Count; i++)
{
if (Lines[i].PointB.X < Camera.Viewport.X)
{
Lines.RemoveAt(i);
i--;
}
}
//if there are no lines, create one to get started
if (Lines.Count == 0)
{
Vector2 p1 = new Vector2(Camera.Viewport.X, Random.Next(Camera.Viewport.Y + 50, Camera.Viewport.Height - 100));
Vector2 p2 = new Vector2(p1.X + Random.Next(5, 20), p1.Y + Random.Next(-5, 5));
Line line = new Line(p1, p2, 1, Color.Black, LineTexture);
Lines.Add(line);
}
//Check if we need to add some lines to the right of our last list item
while (Lines[Lines.Count - 1].PointB.X < Camera.Viewport.X + Camera.Viewport.Width)
{
Vector2 p1 = new Vector2(Lines[Lines.Count - 1].PointB.X, Lines[Lines.Count - 1].PointB.Y); ;
Vector2 p2 = new Vector2(p1.X + Random.Next(5, 20), p1.Y + Random.Next(-5, 5));
Line line = new Line(p1, p2, 1, Color.Black, LineTexture);
Lines.Add(line);
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(new Color(30, 90, 150));
spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, Camera.View);
foreach (Line line in Lines)
line.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
}
I've also included the Camera class for your convenience:
public class Camera
{
private const float zoomUpperLimit = 1.5f;
private const float zoomLowerLimit = 0.1f;
private float _zoom;
private Vector2 _pos;
private int ViewportWidth, ViewportHeight;
#region Properties
public float Zoom
{
get { return _zoom; }
set
{
_zoom = value;
if (_zoom < zoomLowerLimit)
_zoom = zoomLowerLimit;
if (_zoom > zoomUpperLimit)
_zoom = zoomUpperLimit;
}
}
public Rectangle Viewport
{
get
{
int width = (int)((ViewportWidth / _zoom));
int height = (int)((ViewportHeight / _zoom));
return new Rectangle((int)(_pos.X - width / 2), (int)(_pos.Y - height / 2), width, height);
}
}
public void Move(Vector2 amount)
{
_pos += amount;
}
public Vector2 Position
{
get { return _pos; }
set { _pos = value; }
}
public Matrix View
{
get
{
return Matrix.CreateTranslation(new Vector3(-_pos.X, -_pos.Y, 0)) *
Matrix.CreateScale(new Vector3(Zoom, Zoom, 1)) *
Matrix.CreateTranslation(new Vector3(ViewportWidth * 0.5f, ViewportHeight * 0.5f, 0));
}
}
#endregion
public Camera(Viewport viewport, float initialZoom)
{
_zoom = initialZoom;
_pos = Vector2.Zero;
ViewportWidth = viewport.Width;
ViewportHeight = viewport.Height;
}
}
I have a sprite called Tool that moves with a speed represented as a float and in a direction represented as a Vector2. When I click the mouse on the screen the sprite change its direction and starts to move towards the mouseclick. In addition to that I rotate the sprite so that it is facing in the direction it is heading. However, when I add a camera that is suppose to follow the sprite so that the sprite is always centered on the screen, the sprite won't move in the given direction and the rotation isn't accurate anymore. This only happens when I add the Camera.View in the spriteBatch.Begin(). I was hoping anyone could maybe shed a light on what I am missing in my code, that would be highly appreciated.
Here is the camera class i use:
public class Camera
{
private const float zoomUpperLimit = 1.5f;
private const float zoomLowerLimit = 0.1f;
private float _zoom;
private Vector2 _pos;
private int ViewportWidth, ViewportHeight;
#region Properties
public float Zoom
{
get { return _zoom; }
set
{
_zoom = value;
if (_zoom < zoomLowerLimit)
_zoom = zoomLowerLimit;
if (_zoom > zoomUpperLimit)
_zoom = zoomUpperLimit;
}
}
public Rectangle Viewport
{
get
{
int width = (int)((ViewportWidth / _zoom));
int height = (int)((ViewportHeight / _zoom));
return new Rectangle((int)(_pos.X - width / 2), (int)(_pos.Y - height / 2), width, height);
}
}
public void Move(Vector2 amount)
{
_pos += amount;
}
public Vector2 Position
{
get { return _pos; }
set { _pos = value; }
}
public Matrix View
{
get
{
return Matrix.CreateTranslation(new Vector3(-_pos.X, -_pos.Y, 0)) *
Matrix.CreateScale(new Vector3(Zoom, Zoom, 1)) *
Matrix.CreateTranslation(new Vector3(ViewportWidth * 0.5f, ViewportHeight * 0.5f, 0));
}
}
#endregion
public Camera(Viewport viewport, float initialZoom)
{
_zoom = initialZoom;
_pos = Vector2.Zero;
ViewportWidth = viewport.Width;
ViewportHeight = viewport.Height;
}
}
And here is my Update and Draw-method:
protected override void Update (GameTime gameTime)
{
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
TouchCollection touchCollection = TouchPanel.GetState ();
foreach (TouchLocation tl in touchCollection) {
if (tl.State == TouchLocationState.Pressed || tl.State == TouchLocationState.Moved) {
//direction the tool shall move towards
direction = touchCollection [0].Position - toolPos;
if (direction != Vector2.Zero) {
direction.Normalize ();
}
//change the direction the tool is moving and find the rotationangle the texture must rotate to point in given direction
toolPos += (direction * speed * elapsed);
RotationAngle = (float)Math.Atan2 (direction.Y, direction.X);
}
}
if (direction != Vector2.Zero) {
direction.Normalize ();
}
//move tool in given direction
toolPos += (direction * speed * elapsed);
//change cameracentre to the tools position
Camera.Position = toolPos;
base.Update (gameTime);
}
protected override void Draw (GameTime gameTime)
{
graphics.GraphicsDevice.Clear (Color.Blue);
spriteBatch.Begin (SpriteSortMode.BackToFront, BlendState.AlphaBlend, null, null, null, null, Camera.View);
spriteBatch.Draw (tool, new Vector2 (toolPos.X, toolPos.Y), null, Color.White, RotationAngle, originOfToolTexture, 1, SpriteEffects.None, 1);
spriteBatch.End ();
base.Draw (gameTime);
}
You need to convert your cursor position into world position:
Vector2 adjustedPosition = Vector2.Transform(touchCollection[0].Position, Matrix.Invert(camera.View));
Then your direction would be:
direction = adjustedPosition - toolPos;
I'm working on a pong game, since i'm new at programming, i don't know how to get acess to another class variable. I have seperate classes, green and blue paddles, a ball, and game1.cs.
I control the ball movement with bool movingUp, movingLeft;
It bounces off the borders of the screen, but i don't know how to make it work with the paddles. Basically, how do i check the position of the paddle, and make so when the ball touches the paddle, it bounces off? I mean, how to detect the collision?
public class Ball
{
ParticleEngine particleEngine;
GraphicsDeviceManager graphics;
Texture2D texture;
Vector2 position;
Boolean movingUp, movingLeft;
Vector2 origin;
public Ball()
{
position = new Vector2(800 / 2, 330);
}
public void LoadContent(ContentManager Content)
{
texture = Content.Load<Texture2D>("ball");
movingLeft = true;
//Particle Engine
List<Texture2D> textures = new List<Texture2D>();
textures.Add(Content.Load<Texture2D>("pixel"));
particleEngine = new ParticleEngine(textures, new Vector2(400, 240));
}
public void Update(GameTime gameTime)
{
float speed = 2.5f;
//Physics
if (movingUp)
{
position.Y -= 3;
}
if (movingLeft)
{
position.X -= 3;
}
if (!movingUp)
{
position.Y += 3;
}
if (!movingLeft)
{
position.X += 3;
}
if (position.X <= 0 && movingLeft) movingLeft = false;
if (position.Y <= 85 && movingUp) movingUp = false;
if (position.X >= 800 - texture.Width && !movingLeft) movingLeft = true;
if (position.Y >= 500 - texture.Height && !movingUp) movingUp = true;
origin = new Vector2(position.X + texture.Width / 2, position.Y + texture.Height / 2);
//Particles
particleEngine.EmitterLocation = new Vector2(origin.X, origin.Y);
particleEngine.Update();
}
public void Draw(SpriteBatch spriteBatch)
{
particleEngine.Draw(spriteBatch);
spriteBatch.Draw(texture, position, Color.White);
}
}
One of the paddle classes (they look the same exept the name and movement keys):
public class GreenPaddle
{
Texture2D texture;
Vector2 position;
float speed = 2f;
public GreenPaddle()
{
position = new Vector2(10, 230);
}
public void LoadContent(ContentManager Content)
{
texture = Content.Load<Texture2D>("greenpaddle");
}
public void Update(GameTime gameTime)
{
KeyboardState keyState = Keyboard.GetState();
//Check If Keys Are Pressed // Movement
if (keyState.IsKeyDown(Keys.W))
position.Y -= speed;
if (keyState.IsKeyDown(Keys.S))
position.Y += speed;
//Check Border
if (position.Y < 87)
{
position.Y = 87;
}
if (position.Y > 396)
{
position.Y = 396;
}
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, Color.White);
}
}
Thanks in advance, i really wish to learn things like this :D
Declare the variables you want to access as public, or create get methods.
For public variables you would do:
public Vector2 Position;
And to access it, you would call:
Ball ball;
ball.Position
For get method implement:
public Vector2 getPosition()
{
return Position;
}
And you would call that method to get the position.