XNA Finding mouse position with 2D camera - c#

I have tried every way I found online to get the mouse position relative to the camera, but nothing will work. The selection tile always draws far away from the mouse. Also how would I only change the tile I am clicking on and not every tile with the same texture
Camera Class
public class Camera : Game1
{
protected float _zoom;
public Matrix _transform;
public Vector2 _pos;
protected float _rotation;
public Camera()
{
_zoom = 1.0f;
_rotation = 0.0f;
_pos = Vector2.Zero;
}
public float Zoom
{
get { return _zoom; }
set { _zoom = value; if (_zoom < 0.1f) _zoom = 0.1f; } // Negative zoom will flip image
}
public float Rotation
{
get { return _rotation; }
set { _rotation = value; }
}
public void Move(Vector2 amount)
{
_pos += amount;
}
public Vector2 Pos
{
get { return _pos; }
set { _pos = value; }
}
public Matrix get_transformation()
{
_transform =
Matrix.CreateTranslation(new Vector3(-_pos.X, -_pos.Y, 0)) *
Matrix.CreateRotationZ(Rotation) *
Matrix.CreateScale(_zoom) *
Matrix.CreateTranslation(new Vector3(1024 * 0.5f, 768 * 0.5f, 0));
return _transform;
}
public void Update()
{
Input();
}
protected virtual void Input()
{
KeyboardState _keyState;
_keyState = Keyboard.GetState();
if (_keyState.IsKeyDown(Keys.A))
{
_pos.X -= 5f;
}
if (_keyState.IsKeyDown(Keys.D))
{
_pos.X += 5f;
}
if (_keyState.IsKeyDown(Keys.W))
{
_pos.Y -= 5f;
}
if (_keyState.IsKeyDown(Keys.S))
{
_pos.Y += 5f;
}
}
}
Tile Class
class TileGeneration
{
public Block[] tiles = new Block[3];
public int width, height;
public int[,] index;
public Texture2D grass, dirt, selection;
bool selected;
MouseState MS;
Vector2 mousePos;
Camera camera;
public TileGeneration()
{
}
public void Load(ContentManager content, GraphicsDevice g)
{
grass = content.Load<Texture2D>(#"Tiles/grass");
dirt = content.Load<Texture2D>(#"Tiles/dirt");
selection = content.Load<Texture2D>(#"Tiles/selection");
tiles[0] = new Block { Type = BlockType.Grass, Position = Vector2.Zero, texture = grass};
tiles[1] = new Block { Type = BlockType.Dirt, Position = Vector2.Zero, texture = dirt};
width = 50;
height = 50;
index = new int[width, height];
camera = new Camera();
Random rand = new Random();
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
index[x,y] = rand.Next(0,2);
}
}
}
public void Update()
{
MS = Mouse.GetState();
Matrix inverseViewMatrix = Matrix.Invert(camera.get_transformation());
Vector2 mousePosition = new Vector2(Mouse.GetState().X, Mouse.GetState().Y);
Vector2 worldMousePosition = Vector2.Transform(mousePosition, inverseViewMatrix);
mousePos = worldMousePosition;
Console.WriteLine(mousePos);
if (MS.LeftButton == ButtonState.Pressed)
{
Console.WriteLine("Selected");
selected = true;
}
}
public void Draw(SpriteBatch spriteBatch)
{
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
spriteBatch.Draw(tiles[index[x,y]].texture, new Rectangle(x * 64, y * 64, 64, 64),
Color.White);
if (selected && IsMouseInsideTile(x, y))
{
if (tiles[index[x,y]].texture == grass)
tiles[index[x,y]].texture = dirt;
}
if(IsMouseInsideTile(x, y))
spriteBatch.Draw(selection, new Rectangle(x * 64, y * 64, 64, 64), Color.White);
}
}
}
public bool IsMouseInsideTile(int x, int y)
{
return (mousePos.X >= x * 64 && mousePos.X <= (x + 1) * 64 &&
mousePos.Y >= y * 64 && mousePos.Y <= (y + 1) * 64);
}
Game1 Draw
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, null, null, null, null,
camera.get_transformation());
tile.Draw(this.spriteBatch);
player.Draw(this.spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}

There may be a better way, but:
// absoluteMouseX will be the value from your MouseState, and camera will be an instance of your class
// You may need to convert your rotation to radians.
float relativeMouseX = absoluteMouseX + camera.Pos.X;
float relativeMouseY = absoluteMouseY + camera.Pos.Y;

I don't have XNA right now to test it, but I recall having problems with this.
A snippet of code I have which may help:
Vector2 mouse = new Vector2(ms.X, ms.Y);
Matrix transform = Matrix.Invert(camera.ViewMatrix);
Vector2.Transform(ref mouse, ref transform, out mouse);
selectedRow = (int)(mouse.Y / Tile.SIZE);
if (selectedRow < 0) selectedRow = 0;
else if (selectedRow >= rows) selectedRow = rows - 1;
selectedCol = (int)(mouse.X / Tile.SIZE);
if (selectedCol < 0) selectedCol = 0;
else if (selectedCol >= cols) selectedCol = cols - 1;
Two things:
1. Notice how the row depends on the Y component of the Mouse, and the column on the X component.
2. Notice that it's considerably faster to directly get which tile the Mouse lays on rather than asking every single tile if it has the Mouse "inside".

Related

2D Continous Collision Detection in Monogame/Xna Framework

I'm working on a custom physics engine for a potential game - based in Monogame/the XNA framework. While the physics itself works pretty well, I'm running into an issue with collision. When the player comes out of a jump, they can often end up inside the floor.
See image below. I did a couple hours of research on my own and found out that what I probably need is continous collision detection (CCD) similar to how something like Unity might implement it, but all the questions I've found here or other places haven't really worked, and neither has any of my solutions, so I'm asking the strangers on the internet who are smarter than me.
Here's game 1:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using MonoGame.Extended;
using AmethystDawn.Utilities;
namespace AmethystDawn
{
internal class Game1 : Game
{
Texture2D spritesheet;
Texture2D spritesheetFlipped;
Texture2D activeSpritesheet;
Texture2D platform;
float timer; // millisecond timer
int threshold;
Rectangle[] sourceRectangles;
byte previousAnimationIndex;
byte currentAnimationIndex;
RectangleF playerCollider;
RectangleF groundCollider;
PhysicsCalculator physics = new();
Vector2 PlayerPos = new Vector2(0, 0);
private GraphicsDeviceManager graphics;
private SpriteBatch sprites;
private SpriteFont font;
public Game1() : base()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsFixedTimeStep = true;
IsMouseVisible = true;
IsFixedTimeStep = false;
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
graphics.PreferredBackBufferWidth = GraphicsDevice.DisplayMode.Width;
graphics.PreferredBackBufferHeight = GraphicsDevice.DisplayMode.Height;
graphics.IsFullScreen = true;
graphics.HardwareModeSwitch = false;
graphics.ApplyChanges();
sprites = new SpriteBatch(GraphicsDevice);
font = Content.Load<SpriteFont>("Fonts/november");
spritesheet = Content.Load<Texture2D>("Sprites/Player/player spritesheet");
spritesheetFlipped = Content.Load<Texture2D>("Sprites/Player/player spritesheet flipped");
platform = Content.Load<Texture2D>("Sprites/platform");
activeSpritesheet = spritesheet;
timer = 0;
threshold = 100;
sourceRectangles = new Rectangle[4];
sourceRectangles[0] = new Rectangle(0, 0, 32, 40);
sourceRectangles[1] = new Rectangle(34, 0, 28, 40);
sourceRectangles[2] = new Rectangle(66, 0, 28, 40);
sourceRectangles[3] = new Rectangle(96, 0, 32, 40);
previousAnimationIndex = 2;
currentAnimationIndex = 1;
base.LoadContent();
}
protected override void UnloadContent()
{
base.UnloadContent();
}
protected override void Update(GameTime gameTime)
{
if (timer > threshold) // check if the timer has exceeded the threshold
{
if (currentAnimationIndex == 1) // if sprite is in the middle sprite of the animation
{
if (previousAnimationIndex == 0) // if the previous animation was the left-side sprite, then the next animation should be the right-side sprite
{
currentAnimationIndex = 2;
}
else
{
currentAnimationIndex = 0; // if not, then the next animation should be the left-side sprite
}
previousAnimationIndex = currentAnimationIndex;
}
else
{
currentAnimationIndex = 1; // if not in the middle sprite of the animation, return to the middle sprite
}
timer = 0;
}
else
{
// if the timer has not reached the threshold, then add the milliseconds that have past since the last Update() to the timer
timer += (float)gameTime.ElapsedGameTime.TotalMilliseconds;
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
sprites.Begin();
sprites.Draw(platform, new Vector2(0, GraphicsDevice.Viewport.Height - platform.Height - 50), Color.White);
groundCollider = new RectangleF(0, GraphicsDevice.Viewport.Height - platform.Height - 50, platform.Width, platform.Height);
var kstate = Keyboard.GetState();
playerCollider = new(PlayerPos.X, PlayerPos.Y, sourceRectangles[currentAnimationIndex].Width, sourceRectangles[currentAnimationIndex].Height);
if (IsColliding(groundCollider, playerCollider))
{
physics.UpdatePhysicValues(false);
/*if (PlayerPos.Y + playerCollider.Height + 100 > groundCollider.Y)
{
PlayerPos.Y = groundCollider.Y - groundCollider.Height;
}*/
if (kstate.IsKeyDown(Keys.Space))
{
physics.Jump(3f);
}
}
else
{
physics.UpdatePhysicValues(true);
if (kstate.IsKeyDown(Keys.Space))
{
physics.MidairJump(3f);
}
else
{
physics.LockJump();
}
}
if (kstate.IsKeyDown(Keys.A))
{
physics.ApplyWalkingForce(new Vector2(-1, 0), 0.5f);
activeSpritesheet = spritesheetFlipped;
sourceRectangles[0] = new Rectangle(0, 0, 32, 40);
sourceRectangles[1] = new Rectangle(34, 0, 28, 40);
sourceRectangles[2] = new Rectangle(66, 0, 28, 40);
sourceRectangles[3] = new Rectangle(96, 0, 32, 40);
}
else if (kstate.IsKeyDown(Keys.D))
{
physics.ApplyWalkingForce(new Vector2(1, 0), 0.5f);
activeSpritesheet = spritesheet;
sourceRectangles[0] = new Rectangle(96, 0, 32, 40);
sourceRectangles[1] = new Rectangle(66, 0, 28, 40);
sourceRectangles[2] = new Rectangle(34, 0, 28, 40);
sourceRectangles[3] = new Rectangle(0, 0, 32, 40);
}
else
{
}
if (kstate.IsKeyDown(Keys.S) && !IsColliding(groundCollider, playerCollider))
{
physics.ApplyExtraGravity(1f);
}
if (kstate.IsKeyDown(Keys.R))
{
PlayerPos = new Vector2(0, 0);
}
PlayerPos = physics.position(PlayerPos);
// is player on the bounds of the screen
if (PlayerPos.X < 0)
{
PlayerPos.X = 0;
physics.HitWall();
}
else if (PlayerPos.X > GraphicsDevice.Viewport.Width - 32)
{
PlayerPos.X = GraphicsDevice.Viewport.Width - 32;
physics.HitWall();
}
sprites.Draw(activeSpritesheet, PlayerPos, sourceRectangles[currentAnimationIndex], Color.White, 0f, new Vector2(0, 0), 1f, SpriteEffects.None, 0f);
sprites.End();
base.Draw(gameTime);
}
private bool IsColliding(RectangleF rect1, RectangleF rect2)
{
return rect1.Intersects(rect2);
}
}
}
And here's the physics calculator:
using System.Diagnostics;
using Microsoft.Xna.Framework;
namespace AmethystDawn.Utilities
{
internal class PhysicsCalculator
{
private float directionalForce;
private Vector2 direction;
private const float directionalForceMax = 10f;
private float walkingForce;
private const float walkingForceMax = 0.5f;
private float gravityForce;
private const float gravityForceMax = 25f;
private float jumpForce;
private const float jumpForceMax = 5f;
private int framesInAir;
private const int framesInAirMax = 90;
public void UpdatePhysicValues(bool falling)
{
if (directionalForce > 0)
{
directionalForce -= 0.5f;
}
if (walkingForce > 0)
{
walkingForce -= 0.02f;
}
else
{
walkingForce = 0;
}
if (gravityForce > jumpForce)
{
if (falling && !(gravityForce > gravityForceMax))
{
gravityForce += 0.2f;
}
else if (!falling)
{
gravityForce = 0;
direction.Y = 0;
framesInAir = 0;
}
}
else
{
jumpForce -= 0.3f;
}
FixDirection();
}
public void ApplyDirectionalForce(Vector2 directionHit, float forceToApply)
{
direction += directionHit;
directionalForce += forceToApply;
if (directionalForce > directionalForceMax) directionalForce = directionalForceMax;
}
public void ApplyWalkingForce(Vector2 directionWalked, float forceToApply)
{
direction += directionWalked;
walkingForce += forceToApply;
if (walkingForce > walkingForceMax) walkingForce = walkingForceMax;
}
public void Jump(float force)
{
direction += new Vector2(0, -1);
jumpForce += force;
if (jumpForce > jumpForceMax) jumpForce = jumpForceMax;
}
public void MidairJump(float force)
{
framesInAir++;
if (framesInAir > framesInAirMax) return;
jumpForce += force;
if (jumpForce > jumpForceMax) jumpForce = jumpForceMax;
}
public void LockJump()
{
framesInAir = framesInAirMax;
}
public void ApplyExtraGravity(float amount)
{
gravityForce += amount;
}
public Vector2 position(Vector2 currentPosition)
{
currentPosition += new Vector2(0, gravityForce);
currentPosition += new Vector2(direction.X * directionalForce, direction.Y * directionalForce);
currentPosition += new Vector2(direction.X * walkingForce, direction.Y * walkingForce);
currentPosition += new Vector2(0, direction.Y * jumpForce);
return currentPosition;
}
public void HitWall()
{
direction.X = 0;
}
private void CorrectGravity()
{
}
private void FixDirection()
{
if (direction.X > 20) direction.X = 20;
if (direction.Y > 20) direction.Y = 20;
if (direction.X < -20) direction.X = -20;
if (direction.Y < -15) direction.Y = -15;
if (walkingForce <= 0 && directionalForce <= 0) direction.X = 0;
}
}
}
And the image:
I remember watching a tutorial that explained the way of handling continious collision, but that was done in GameMaker Studio 2.
I'll try to translate it to XNA.
In short: You need to check for collision ahead of you with calculating the collision with the current speed beforehand, then let the player approach the solid object 1 pixel at a time through a while loop, and once it hits, then set the velocity in that direction to 0.
Original GMS2 code:
if place_meeting(x+hspeed_, y, o_solid) {
while !place_meeting(x+sign(hspeed_), y, o_solid) {
x += sign(hspeed_);
}
hspeed_ = 0;
}
x += hspeed_;
translated to XNA (dummy code as quick example):
private bool IsColliding(RectangleF rect1, RectangleF rect2, int vspeed)
{
if (rect1.Intersects(new Rectangle(rect2.x, rect2.y + vspeed, rect2.Width, rect2.Height))
{
while (!rect1.Intersects(new Rectangle(rect2.x, rect2.y+Sign(vspeed), rect2.Width, rect2.Height)
{
rect1 += Sign(vspeed) //moves towards the collision 1 pixel at a time
}
return true;
}
return false;
}
//Sign is a build-in function in GMS2 that only returns 1, 0 or -1, depending if the number is positive, 0 or negative
private int Sign(value)
{
return (value > 0) ? 1 : (value < 0) ? -1 : 0;
}
Source: https://youtu.be/zqtT_9eWIkM?list=PL9FzW-m48fn3Ya8QUTsqU-SU6-UGEqhx6

How can I add remove more number of objects at runtime?

The script is a bit long I'm not sure what I can reduce I will try.
When I'm running the program it's starting by making the square formation.
What I'm trying to archive is that at each time in runtime if I change the numberOfSquadMembers value up or down add/remove to each squad the more/less value of squad members.
Same for the numberOfSquads value.
The problem is I'm not sure how to do it in the Update() how to add more squads/squadmemebers or destroy when the values are less then the current ?
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class Formations : MonoBehaviour
{
enum Formation
{
Square, Circle, Triangle
}
[Header("Main Settings")]
[Space(5)]
[Range(4, 100)]
public int numberOfSquadMembers = 20;
[Range(1, 20)]
public int numberOfSquads = 1;
[Range(0, 4)]
public int columns = 4;
public int gaps = 10;
public int circleRadius = 10;
public float yOffset = 0;
[Range(3, 50)]
public float moveSpeed = 3;
[Range(3, 50)]
public float rotateSpeed = 1;
public float threshold = 0.1f;
public bool randomSpeed = false;
[Range(1, 100)]
public int randSpeedMin = 1;
[Range(1, 100)]
public int randSpeedMax = 1;
public bool startRandomFormation = false;
public string currentFormation;
private Formation formation;
private List<Quaternion> quaternions = new List<Quaternion>();
private List<Vector3> newpositions = new List<Vector3>();
private bool move = false;
private bool squareFormation = false;
private List<GameObject> squadMembers = new List<GameObject>();
private float[] step;
private int[] randomSpeeds;
private int index = 0;
private bool ready = false;
private GameObject[] squads;
private Vector3 startVector;
private Vector3 total;
private List<Vector3> endpositions = new List<Vector3>();
public void InitFormations()
{
if (startRandomFormation)
{
formation = (Formation)UnityEngine.Random.Range(0, Enum.GetNames(typeof(Formation)).Length);
}
else
{
formation = Formation.Square;
}
squads = GameObject.FindGameObjectsWithTag("Squad");
for (int i = 0; i < squads.Length; i++)
{
foreach (Transform squadMember in squads[i].transform)
{
squadMembers.Add(squadMember.gameObject);
}
}
foreach (GameObject unit in squadMembers)
{
if (unit != null)
{
total += unit.transform.position;
}
}
Vector3 center = total / squadMembers.Count;
//Vector3 endPos = GameObject.Find("Cube").transform.position;
foreach (GameObject unit in squadMembers)
{
startVector = unit.transform.position - center;
endpositions.Add(/*endPos + */startVector);
}
currentFormation = formation.ToString();
ChangeFormation();
randomSpeeds = RandomSpeeds(randSpeedMin, randSpeedMax, squadMembers.Count);
step = new float[squadMembers.Count];
ready = true;
}
private void Start()
{
InitFormations();
}
// Update is called once per frame
void Update()
{
if (ready == true)
{
if (Input.GetKeyDown(KeyCode.C))
{
randomSpeeds = RandomSpeeds(randSpeedMin, randSpeedMax, squadMembers.Count);
foreach (int speedV in randomSpeeds)
{
if (index == randomSpeeds.Length)
index = 0;
step[index] = speedV * Time.deltaTime;
index++;
}
ChangeFormation();
}
if (move == true)
{
MoveToNextFormation();
}
}
}
private void ChangeFormation()
{
switch (formation)
{
case Formation.Square:
FormationSquare();
break;
case Formation.Circle:
FormationCircle();
break;
case Formation.Triangle:
FormationTriangle();
break;
}
}
private void FormationTriangle()
{
newpositions = new List<Vector3>();
int height = Mathf.CeilToInt((Mathf.Sqrt(8 * squadMembers.Count + 1f) - 1f) / 2);
int slots = (int)(height * (height + 1f) / 2f);
float verticalModifier = 1.25f; // * 1.25f to increase horizontal space
float horizontalModifier = 0.8f; // * 0.8f to decrease "vertical" space
float width = 0.5f * (height - 1f);
Vector3 startPos = new Vector3(width * horizontalModifier, 0f, (float)(height - 1f) * verticalModifier);
int finalRowCount = height - slots + squadMembers.Count;
for (int rowNum = 0; rowNum < height && newpositions.Count < squadMembers.Count; rowNum++)
{
for (int i = 0; i < rowNum + 1 && newpositions.Count < squadMembers.Count; i++)
{
float xOffset = 0f;
if (rowNum + 1 == height)
{
// If we're in the last row, stretch it ...
if (finalRowCount != 1)
{
// Unless there's only one item in the last row.
// If that's the case, leave it centered.
xOffset = Mathf.Lerp(
rowNum / 2f,
-rowNum / 2f,
i / (finalRowCount - 1f)
) * horizontalModifier;
}
}
else
{
xOffset = (i - rowNum / 2f) * horizontalModifier;
}
float yOffset = (float)rowNum * verticalModifier;
Vector3 position = new Vector3(
startPos.x + xOffset, 0f, startPos.y - yOffset);
newpositions.Add(position);
}
}
move = true;
formation = Formation.Square;
}
private Vector3 FormationSquarePositionCalculation(int index) // call this func for all your objects
{
float posX = (index % columns) * gaps;
float posY = (index / columns) * gaps;
return new Vector3(posX, posY);
}
private void FormationSquare()
{
newpositions = new List<Vector3>();
quaternions = new List<Quaternion>();
for (int i = 0; i < squadMembers.Count; i++)
{
Vector3 pos = FormationSquarePositionCalculation(i);
//squadMembers[i].transform.position = new Vector3(transform.position.x + pos.x, 0, transform.position.y + pos.y);
squadMembers[i].transform.Rotate(new Vector3(0, -90, 0));
//newpositions.Add(new Vector3(transform.position.x + pos.x, 0, transform.position.y + pos.y));
newpositions.Add(new Vector3(endpositions[i].x + pos.x, 0, endpositions[i].y + pos.y));
}
move = true;
squareFormation = true;
formation = Formation.Circle;
}
private Vector3 FormationCirclePositionCalculation(Vector3 center, float radius, int index, float angleIncrement)
{
float ang = index * angleIncrement;
Vector3 pos;
pos.x = center.x + radius * Mathf.Sin(ang * Mathf.Deg2Rad);
pos.z = center.z + radius * Mathf.Cos(ang * Mathf.Deg2Rad);
pos.y = center.y;
return pos;
}
private void FormationCircle()
{
newpositions = new List<Vector3>();
quaternions = new List<Quaternion>();
Vector3 center = transform.position;
float radius = (float)circleRadius / 2;
float angleIncrement = 360 / squadMembers.Count;//(float)numberOfSquadMembers;
for (int i = 0; i < squadMembers.Count; i++)//numberOfSquadMembers; i++)
{
Vector3 pos = FormationCirclePositionCalculation(center, radius, i, angleIncrement);
var rot = Quaternion.LookRotation(center - pos);
if (Terrain.activeTerrain == true)
pos.y = Terrain.activeTerrain.SampleHeight(pos);
pos.y = pos.y + yOffset;
newpositions.Add(pos);
quaternions.Add(rot);
}
move = true;
squareFormation = false;
formation = Formation.Triangle;
}
private void MoveToNextFormation()
{
if (randomSpeed == false)
{
if (step.Length > 0)
step[0] = moveSpeed * Time.deltaTime;
}
for (int i = 0; i < squadMembers.Count; i++)
{
squadMembers[i].transform.LookAt(newpositions[i]);
if (randomSpeed == true)
{
squadMembers[i].transform.position =
Vector3.MoveTowards(squadMembers[i].transform.position, newpositions[i], step[i]);
}
else
{
squadMembers[i].transform.position =
Vector3.MoveTowards(squadMembers[i].transform.position, newpositions[i], step[0]);
}
if (Vector3.Distance(squadMembers[i].transform.position, newpositions[i]) < threshold)
{
if (squareFormation == true)
{
Vector3 degrees = new Vector3(0, 0, 0);
Quaternion quaternion = Quaternion.Euler(degrees);
squadMembers[i].transform.rotation = Quaternion.Slerp(squadMembers[i].transform.rotation, quaternion, rotateSpeed * Time.deltaTime);
}
else
{
squadMembers[i].transform.rotation = Quaternion.Slerp(squadMembers[i].transform.rotation, quaternions[i], rotateSpeed * Time.deltaTime);
}
}
}
}
private static int[] RandomSpeeds(int min, int max, int howMany)
{
int[] myNumbers = new int[howMany];
for (int i = 0; i < howMany; i++)
{
myNumbers[i] = UnityEngine.Random.Range(min, max);
}
return myNumbers;
}
}
This is the script that generate the squads and number of squads members first time :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SquadsGenerator : MonoBehaviour
{
public GameObject squadPrefab;
public int numberOfSquads;
public int numberOfMembersInsquad;
private GameObject squadsParent;
private void Start()
{
squadsParent = GameObject.Find("Squads");
GenerateSquads(numberOfSquads, numberOfMembersInsquad, squadPrefab);
}
// Update is called once per frame
void Update()
{
}
public void GenerateSquads(int squadsCount,
int numberOfMembers,
GameObject squadMemberPrefab)
{
for (int i = 0; i < squadsCount; i++)
{
GameObject newSquad = new GameObject();
newSquad.name = "Squad " + i;
newSquad.tag = "Squad";
newSquad.transform.parent = squadsParent.transform;
for (int x = 0; x < numberOfMembers; x++)
{
var go = Instantiate(squadMemberPrefab);
go.name = "Member " + x;
go.tag = "Squad Member";
go.transform.parent = newSquad.transform;
switch (i % 6)
{
case 0: ColorSquad(go, Color.green); break;
case 1: ColorSquad(go, Color.red); break;
case 2: ColorSquad(go, Color.blue); break;
case 3: ColorSquad(go, Color.yellow); break;
case 4: ColorSquad(go, Color.cyan); break;
case 5: ColorSquad(go, Color.magenta); break;
}
}
}
}
private void ColorSquad(GameObject squad, Color color)
{
Renderer rend = squad.GetComponent<Renderer>();
rend.material.SetColor("_Color", color);
}
}
Update :
What I have tried so far :
I added this part to the Update()
if(oldNumOfSquadMemebers != numberOfSquadMembers)
{
var tt = numberOfSquadMembers - oldNumOfSquadMemebers;
for (int i = 0; i < tt; i++)
{
var go = Instantiate(squadMemberPrefab);
squadMembers.Add(go);
}
oldNumOfSquadMemebers = numberOfSquadMembers;
FormationSquare();
}
The problem now is in the FormationSquare method :
private void FormationSquare()
{
newpositions = new List<Vector3>();
quaternions = new List<Quaternion>();
for (int i = 0; i < squadMembers.Count; i++)
{
Vector3 pos = FormationSquarePositionCalculation(i);
squadMembers[i].transform.Rotate(new Vector3(0, -90, 0));
newpositions.Add(new Vector3(endpositions[i].x + pos.x, 0, endpositions[i].y + pos.y));
}
move = true;
squareFormation = true;
formation = Formation.Circle;
}
Now I'm making a new instance for the newpositions List so each time I change the number of squad members there are more members but less newpositions so at some time I'm getting out of index exception.
If I don't make a new instance for the List then it will work but then after some time it will throw the out of index exception this time because it keep adding more and more new positions to the list.
So this newpositions List I'm stuck with it. Not sure how to solve it.

C# How to zoom to cursor location using SkiaSharp control?

I have a 2D map I want to zoom in to based on the cursor X and Y coordinates. Currently I have some working code, but if I move the cursor to a new position after an initial zoom the next zoom is slightly off. I've been trying to figure this out for a while but I can't get my head around the math. Its probably something simple I just can't visualize the right way to do this.
Sample code.
float ZoomMax = 7f;
float ZoomMin = 1f;
private float[] MapPan = new float[] { 0, 0 };
private float MapScale = 1f;
protected override void OnMouseWheel(MouseEventArgs e)
{
var coordinates = panelMap.PointToClient(Cursor.Position);
if (e.Delta > 0)
{
if (MapScale < ZoomMax)
{
MapScale += 0.2f;
ZoomToMouse(coordinates.X, coordinates.Y);
}
else
{
MapScale = ZoomMax;
}
}
else if (e.Delta < 0)
{
if (MapScale > ZoomMin)
{
MapScale -= 0.2f;
ZoomToMouse(coordinates.X, coordinates.Y);
}
else
{
MapPan[0] = 0;
MapPan[1] = 0;
MapScale = ZoomMin;
}
}
}
private void ZoomToMouse(int x, int y)
{
float xScaled = x * MapScale;
float xScaled = y * MapScale;
float X = x - xScaled;
float Y = y - yScaled;
MapPan[0] = X / MapScale;
MapPan[1] = Y / MapScale;
}
private void map_PaintSurface(object sender, SKPaintGLSurfaceEventArgs e)
{
SKCanvas skCanvas = e.Surface.Canvas;
skCanvas.Scale(MapScale);
skCanvas.Translate(MapPan[0], MapPan[1]);
using(SKPaint skPaint = new SKPaint())
{
skCanvas.DrawText("Hello", 0, 0, skPaint);
}
}
This is what I came up with if anyone has a similar problem.
private float ZoomMax = 7f;
private float ZoomMin = 1f;
private PointF MapPan = new PointF(0, 0);
private float MapScale = 1f;
protected override void OnMouseWheel(MouseEventArgs e)
{
if (FindControlAtCursor(this) != map) { return; }
var coordinates = map.PointToClient(Cursor.Position);
float ScrollDelta = e.Delta * 0.002f;
float prevScale = MapScale;
MapScale = Clamp(MapScale + ScrollDelta,ZoomMin,ZoomMax);
ZoomToMouse(coordinates, prevScale);
}
public static Control FindControlAtCursor(Form form)
{
Point pos = Cursor.Position;
if (form.Bounds.Contains(pos))
return FindControlAtPoint(form, form.PointToClient(pos));
return null;
}
public static float Clamp(float value, float min, float max)
{
return (value < min) ? min : (value > max) ? max : value;
}
private void ZoomToMouse(PointF Mouse, float PreviousScale)
{
PointF TranslatedMouse = new PointF((Mouse.X / PreviousScale) - MapPan.X, (Mouse.Y / PreviousScale) - MapPan.Y);
PointF ScaledMouse = new PointF(TranslatedMouse.X * MapScale, TranslatedMouse.Y * MapScale);
PointF NewPosition = new PointF((Mouse.X - ScaledMouse.X) / MapScale, (Mouse.Y - ScaledMouse.Y) / MapScale);
float currentWidth = map.Width * MapScale;
float currentHeight = map.Height * MapScale;
float diffX = (currentWidth - map.Width) / MapScale;
float diffY = (currentHeight - map.Height) / MapScale;
MapPan.X = Clamp(NewPosition.X, -diffX, 0);
MapPan.Y = Clamp(NewPosition.Y, -diffY, 0);
}
private void map_PaintSurface(object sender, SKPaintGLSurfaceEventArgs e)
{
SKCanvas skCanvas = e.Surface.Canvas;
skCanvas.Scale(MapScale);
skCanvas.Translate(MapPan.X, MapPan.Y);
using (SKPaint skPaint = new SKPaint())
{
skCanvas.DrawText("Hello", 0, 0, skPaint);
}
}

Movement very fast

I have a monogame project, where I want to move the player based on the the keyboard input. But my code just makes the movement super fast.
I tried around with different speed limits and checked if it might work if with different GameTime properties.
Where is the problem with my code?
public class Map {
private Map() {
Position = new Vector2(0, 0);
}
public string Data { get; set; }
public string[][] MapData { get; set; }
public ContentManager Content { get; set; }
public SpriteBatch SpriteBatch { get; set; }
public Vector2 Position { get; set; }
private Vector2 ArrayPosition;
private readonly int Speed_X = 40;
private readonly int Speed_Y = 32;
public static Map Parse(string path) {
var map = new Map();
var stream = TitleContainer.OpenStream(Path.Combine("Content", path));
using (var sr = new StreamReader(stream)) {
map.Data = sr.ReadToEnd();
}
var lines = map.Data.Split(new string[1] { Environment.NewLine }, StringSplitOptions.None);
var mapHeight = lines.Count();
map.MapData = new string[mapHeight][];
for (int i = 0; i < lines.Count(); i++) {
var elements = lines[i].Split(';');
map.MapData[i] = elements;
}
return map;
}
public void DrawMap(SpriteBatch spriteBatch, ContentManager content, GameTime gametime) {
this.SpriteBatch = spriteBatch;
this.Content = content;
for (int y = 0; y < MapData.Count(); y++) {
var current = MapData[y];
for (int x = 0; x < current.Count(); x++) {
switch (current[x]) {
case "e":
drawEnemy(x, y);
break;
case "P":
case ".":
drawTile(x, y);
break;
case "w":
drawWall(x, y);
break;
}
}
}
drawPlayer();
}
public void Move(Direction pdirection, GameTime gametime) {
var direction = Vector2.Zero;
var speed = Vector2.Zero;
var y = Math.Floor(this.ArrayPosition.Y);
var x = Math.Floor(this.ArrayPosition.X);
switch (pdirection) {
case Direction.Up:
if (y > 0 && y < 16) {
direction = new Vector2(0, -1);
speed.Y = Speed_Y;
}
break;
case Direction.Down:
if (y < 16 && y >= 0) {
direction = new Vector2(0, 1);
speed.Y = Speed_Y;
}
break;
case Direction.Left:
if (x > 0 && x < 16) {
direction = new Vector2(-1, 0);
speed.X = Speed_X;
}
break;
case Direction.Right:
if (x < 16 && x >= 0) {
direction = new Vector2(1, 0);
speed.X = Speed_X;
}
break;
}
ArrayPosition = (this.Position + (direction * speed)) / new Vector2(Speed_X, Speed_Y);
var newPosition = this.Position + (direction * speed * gametime.ElapsedGameTime.Milliseconds);
if (this.MapData[(int)Math.Floor(ArrayPosition.Y)][(int)Math.Floor(ArrayPosition.X)] != "w") {
this.Position = newPosition;
}
}
private void drawPlayer() {
var x = Position.X;
var y = Position.Y;
drawTile((int)x, (int)y);
var texture = Content.Load<Texture2D>("Sprites/player");
this.SpriteBatch.Draw(texture, new Vector2(x, y), Color.White);
}
private void drawEnemy(int x, int y) {
drawTile(x, y);
drawTexture(Content.Load<Texture2D>("Sprites/enemy"), x, y);
}
private void drawTile(int x, int y) {
drawTexture(Content.Load<Texture2D>("Tiles/grass"), x, y);
}
private void drawWall(int x, int y) {
drawTexture(Content.Load<Texture2D>("Tiles/wall"), x, y);
}
private void drawTexture(Texture2D texture, int x, int y) {
var rectangle = new Rectangle(x * 40, y * 32, 40, 32);
this.SpriteBatch.Draw(texture, rectangle, Color.White);
}
}
You should be using the TotalSeconds property instead of Milliseconds in GameTime.ElapsedGameTime. The latter is an int which is not useful for fractional computations whereas the former is a double which is. Due to it being an int it also explains why your movement is very fast.
In your Move() method change this line:
var newPosition = this.Position +
(direction * speed *
gametime.ElapsedGameTime.Milliseconds);
...to:
var newPosition = this.Position +
(direction * speed *
gametime.ElapsedGameTime.TotalSeconds);
However contrary to what the other poster says, it is not necessary to perform a deltatime=0; because ElapsedGameTime is defined as:
The amount of elapsed game time since the last update - MSDN
You don't want to go resetting time intervals as they will just lead to animation which is not particularly smooth.
Tell me more
Your First Game - XNA Game Studio in 2D
use something like this in function Move:
float deltatime=0;
public void Move(Direction pdirection, GameTime gametime) {
deltaTime= (float)gameTime.ElapsedGameTime.TotalSeconds;
//calculate your object position using deltatime
}

Object reference is not set to an object

I am trying to create collision between my bullets and the enemy. I have created bounding boxes for each and placed them into their own class. However, I am getting a Null reference error in my HandleCollision function, specifically at the if statement with the bounding boxes. I will also post the rest of my code.
I discussed this with two lecturers and some peers and they asy it is because bullet and enemy are equal to null. This is because it takes a couple of seconds for the enemy to spawn and the bullet only spawns once it is fired. To counter this I added an if statement to check if the bullet or enemy is null yet it still throws up the same error.
HandleCollision Function
private void HandleCollision()//collision
{
Sprite toRemove = null;
if (bullet != null || enemyTexture != null)
{
foreach (EnemySprite e in enemyList) //checks each enemy sprite
{
if (bullet.BoundingBox.Intersects(enemy.BoundingBox))
{
enemyList.Remove(enemy); //removes enemy
//toRemove = enemy;
break;
}
}
}
}
Game1.cs
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Rectangle spriteRectangle;
Rectangle bulletBounds;
Rectangle enemyBounds;
Sprite player;
Bullets bullet;
EnemySprite enemy;
Texture2D enemyTexture;
List<EnemySprite> enemyList = new List<EnemySprite>();
List<Bullets> bulletsList = new List<Bullets>();
//Pause
bool paused = false;
Texture2D pauseTexture;
Rectangle pauseRectangle;
KeyboardState pastKey;
Vector2 enemyPos = new Vector2(100, 400);
Vector2 Position;
Vector2 Distance;
Vector2 spriteOrigin;
Vector2 spriteVelocity;
const float tangentialVelocity = 5f;
float friction = 0.1f;
float rotation;
float timer = 0f;
float dropInterval = 2f;
float speed = 4f;
float angle;
Random random;
enum GameState
{
MainMenu,
Options,
Help,
Playing,
Exit,
}
GameState CurrentGameState = GameState.MainMenu;
// Screen adjustments
int screenWidth = 800, screenHeight = 600;
cButton btnPlay;
cButtonExit btnExit;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
random = new Random();
Position = new Vector2(150, 150);
this.IsMouseVisible = true;
base.Initialize();
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
player = new Sprite();
player.Texture = Content.Load<Texture2D>("graphics/player");
// Screen stuff
graphics.PreferredBackBufferWidth = screenWidth;
graphics.PreferredBackBufferHeight = screenHeight;
//graphics.IsFullScreen = true;
graphics.ApplyChanges();
IsMouseVisible = true;
btnPlay = new cButton(Content.Load<Texture2D>("Graphics/play"), graphics.GraphicsDevice);
btnPlay.setPosition(new Vector2(350, 190));
btnExit = new cButtonExit(Content.Load <Texture2D>("Graphics/exit"), graphics.GraphicsDevice);
btnExit.setPosition(new Vector2(350, 220));
enemyTexture = Content.Load<Texture2D>("graphics/enemy");
player.Texture = Content.Load<Texture2D>("Graphics/player");
int screenCenterX = GraphicsDevice.Viewport.Width / 2;
player.Position = new Vector2(screenCenterX - (player.Texture.Width / 2), screenHeight - player.Texture.Height - 20);
pauseTexture = Content.Load<Texture2D>("graphics/paused");
pauseRectangle = new Rectangle(0, 0, pauseTexture.Width, pauseTexture.Height);
Bullets.BulletTexture = Content.Load<Texture2D>("graphics/bullet");
}
protected override void Update(GameTime gameTime)
{
MouseState mouse = Mouse.GetState();
IsMouseVisible = true;
switch (CurrentGameState)
{
case GameState.MainMenu:
if (btnPlay.isClicked == true) CurrentGameState = GameState.Playing;
btnPlay.Update(mouse);
if (btnExit.isClicked == true) CurrentGameState = GameState.Help;
btnExit.Update(mouse);
if (btnExit.isClicked == true) CurrentGameState = GameState.Options;
btnExit.Update(mouse);
if (btnExit.isClicked == true) CurrentGameState = GameState.Exit;
btnExit.Update(mouse);
break;
case GameState.Playing:
timer += (float)gameTime.ElapsedGameTime.TotalSeconds;
if (timer >= dropInterval)
{
int yPos = random.Next(GraphicsDevice.Viewport.Height - 50);
enemyList.Add(new EnemySprite(enemyTexture, new Vector2(GraphicsDevice.Viewport.Width + 100, yPos)));
timer = 0f;
}
HandleCollision();
HandleMovingEnemy();
MouseState curMouse = Mouse.GetState();
Vector2 mouseLoc = new Vector2(curMouse.X, curMouse.Y);
Vector2 direction = mouseLoc - Position;
spriteRectangle = new Rectangle((int)Position.X, (int)Position.Y,
player.Texture.Width, player.Texture.Height);
Position = spriteVelocity + Position;
spriteOrigin = new Vector2(spriteRectangle.Width / 2, spriteRectangle.Height / 2);
Distance.X = mouse.X - Position.X;
Distance.Y = mouse.Y - Position.Y;
rotation = (float)Math.Atan2(Distance.Y, Distance.X); //calculates the rotation(trigonometry)
//angle = (float)(Math.Atan2(direction.Y, direction.X));
KeyboardState keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Keys.A))
Position.X -= 2;
if (keyState.IsKeyDown(Keys.D))
Position.X += 2;
if (keyState.IsKeyDown(Keys.W))
Position.Y -= 2;
if (keyState.IsKeyDown(Keys.S))
Position.Y += 2;
//right and left edge detection
if (Position.X < 0)
Position = new Vector2(0, Position.Y);
int rightEdge = GraphicsDevice.Viewport.Width - player.Texture.Width;
if (Position.X > rightEdge)
Position = new Vector2(rightEdge, Position.Y);
//bottom and top edge detection
if (Position.Y < 0)
Position = new Vector2(Position.X, 0);
int bottomEdge = GraphicsDevice.Viewport.Height - player.Texture.Height;
if (Position.Y > bottomEdge)
Position = new Vector2(Position.X, bottomEdge);
if (!paused)
{
if (Keyboard.GetState().IsKeyDown(Keys.Escape))
{
paused = true;
btnPlay.isClicked = false; //so that everytime its paused I can pause it again
}
enemy.Update();
}
else if(paused)
{
if (btnPlay.isClicked)
{
paused = false;
speed = 4;
}
if (btnExit.isClicked)
Exit();
btnPlay.Update(mouse);
btnExit.Update(mouse);
}
if (Keyboard.GetState().IsKeyDown(Keys.C))
{
spriteVelocity.X = (float)Math.Cos(rotation) * tangentialVelocity;
spriteVelocity.Y = (float)Math.Sin(rotation) * tangentialVelocity;
}
else if (spriteVelocity != Vector2.Zero)
{
float i = spriteVelocity.X;
float j = spriteVelocity.Y;
spriteVelocity.X = i -= friction * i;
spriteVelocity.Y = j -= friction * j;
}
if (Keyboard.GetState().IsKeyDown(Keys.Space) && pastKey.IsKeyUp(Keys.Space))
Fire();
pastKey = Keyboard.GetState();
UpdateBullets();
break;
case GameState.Exit:
this.Exit();
break;
}
base.Update(gameTime);
}
public void UpdateBullets()
{
foreach (Bullets bullet in bulletsList)
{
bullet.position += bullet.velocity;
if(Vector2.Distance(bullet.position, Position) > 500) //finds position
bullet.isVisible = false;
}
for (int i = 0; i < bulletsList.Count; i++)
{
if (!bulletsList[i].isVisible)
{
bulletsList.RemoveAt(i);
i--;
}
}
}
//function to handle movement of enemies
private void HandleMovingEnemy()
{
List<EnemySprite> toRemove = new List<EnemySprite>();
foreach (EnemySprite e in enemyList)
{
if (e.Position.X < (-20))
{
toRemove.Add(e);
}
else
e.Position -= new Vector2(speed, 0);
}
if (toRemove.Count > 0)
{
foreach (EnemySprite e in toRemove)
{
enemyList.Remove(e);
}
}
}
private void HandleCollision()//collision
{
Sprite toRemove = null;
if (bullet != null || enemyTexture != null)
{
foreach (EnemySprite e in enemyList) //checks each enemy sprite
{
if (bullet.BoundingBox.Intersects(enemy.BoundingBox)) //checks if a sprite has intersected an enemy
{
enemyList.Remove(enemy); //removes enemy
//toRemove = enemy;
break;
}
}
}
}
public void Fire()
{
Bullets newBullet = new Bullets(Content.Load<Texture2D>("graphics/bullet"));
Bullets.BulletTexture = Content.Load<Texture2D>("graphics/bullet");
//newBullet.LoadContent(LoadContent);
newBullet.velocity = new Vector2((float)Math.Cos(rotation), (float)Math.Sin(rotation)) * 5f + spriteVelocity;
newBullet.position = Position + newBullet.velocity * 5;
newBullet.isVisible = true;
if (bulletsList.Count() < 20)
bulletsList.Add(newBullet);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
switch (CurrentGameState)
{
case GameState.MainMenu:
spriteBatch.Draw(Content.Load<Texture2D>("Graphics/SeaSideDefenderMainMenu"), new Rectangle(0,0,screenWidth,screenHeight),Color.White);
btnPlay.Draw(spriteBatch);
btnExit.Draw(spriteBatch);
break;
case GameState.Playing:
spriteBatch.Draw(Content.Load<Texture2D>("Graphics/leveltest"), new Rectangle(0, 0, screenWidth, screenHeight), Color.White);
enemy = new EnemySprite();
enemy.Texture = Content.Load<Texture2D>("graphics/enemy");
enemy.Draw(spriteBatch);
spriteBatch.Draw(player.Texture, Position, null, Color.White, rotation, spriteOrigin, 1f, SpriteEffects.None, 0);
//player.Draw(spriteBatch);
foreach (EnemySprite e in enemyList)
{
e.Draw(spriteBatch);
}
foreach (Bullets bullet in bulletsList)
bullet.draw(spriteBatch);
/*for (int i; i < enemyList.Count; i++)
{
enemyList[i].Draw(spriteBatch);
}*/
if (paused)
{
speed = 0;
spriteBatch.Draw(Content.Load<Texture2D>("graphics/paused"), new Rectangle(0, 0, screenWidth, screenHeight), Color.White);
btnPlay.Draw(spriteBatch);
btnExit.Draw(spriteBatch);
}
break;
}
spriteBatch.End();
base.Draw(gameTime);
}
}
Bullets.cs
public class Bullets
{
public Texture2D texture;
public static Texture2D BulletTexture;
public Vector2 position;
public Vector2 velocity;
public Vector2 origin;
public bool isVisible;
public Rectangle BoundingBox
{
get { return new Rectangle((int)position.X, (int)position.Y, texture.Width, texture.Height); }
}
public Bullets(Texture2D newTexture)
{
texture = newTexture;
isVisible = false;
}
public void draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture,position,null,Color.White,0f,origin,1f, SpriteEffects.None, 0);
}
public void LoadContent(ContentManager Content)
{
BulletTexture = Content.Load<Texture2D>(#"graphics/bullet");
}
}
enemy.cs
public class EnemySprite
{
public Texture2D Texture { get; set; }
public Vector2 Position {get; set; }
public Vector2 origin;
public Vector2 velocity;
public Rectangle rectangle;
float rotation = 0f;
bool right;
float distance;
float oldDistance;
public Rectangle BoundingBox
{
get { return new Rectangle((int)Position.X, (int)Position.Y, Texture.Width, Texture.Height); } //uses enemy position and wiwdth to create bounding box
}
public EnemySprite() { }
public EnemySprite(Texture2D texture, Vector2 position)
{
Texture = texture;
Position = position;
oldDistance = distance;
}
float mouseDistance;
public void Update()
{
Position += velocity;
origin = new Vector2(Texture.Width / 2, Texture.Height / 2);
if (distance <= 0)
{
right = true;
velocity.X = 1f;
}
else if(distance <= oldDistance)
{
right = false;
velocity.X = -1f;
}
if (right) distance += 1; else distance -= 1;
MouseState mouse = Mouse.GetState();
mouseDistance = mouse.X - Position.X;
if (mouseDistance >= -200 && mouseDistance <= 200)
{
if (mouseDistance < -1)
velocity.X = -1f;
else if (mouseDistance > 1)
velocity.X = 1f;
else if (mouseDistance == 0)
velocity.X = 0f;
}
}
public void Draw(SpriteBatch spriteBatch)
{
if (Texture != null)
spriteBatch.Draw(Texture, Position, Color.White);
if (velocity.X > 0)
{
spriteBatch.Draw(Texture, Position, null, Color.White, rotation, origin, 1f, SpriteEffects.FlipHorizontally, 0f);
}
else
{
spriteBatch.Draw(Texture, Position, null, Color.White, rotation, origin, 1f, SpriteEffects.None, 0f);
}
}
}
You've not initialized the global variable Bullet anywhere in your game1.cs, therefore you would never get bullet != null as true. Whereas, you'll always get enemyTexture != null as true since you've already initialized enemyTexture in the LoadContent().
Which means you'll always enter the if block while having the Bullet variable not initialized.
Hope this will lead you to the solution.
PS: Do mark the answer as 'Accepted' if this was the most helpful one.

Categories