I have a problem with source Rectangle and because of this my texture does not show on the screen.
When I use Draw method with source as null the texture works.
I have no idea what is wrong with this.
Also if I put this into the constructor: source=new Rectangle((int)position.x,(int)position.Y, texture.Width/frameas, texture.Height). I get the error
"use new keyword to create an object"
There is no error in my Game1 for sure as I only load texture,update, and draw in there.
public class Player
{
public Texture2D texture;
public Vector2 position;
public int speed, width,frames, jump;
public float scale;
public Vector2 velocity;
public float gravity;
public bool hasJumped;
public Rectangle source;
public Player(int x, int y)
{
speed = 5;
position.X = x;
position.Y = y;
scale = 1.8f;
frames = 4;
source = new Rectangle(x,y, 30,30);
}
public void LoadContent(ContentManager Content)
{
texture = Content.Load<Texture2D>("player");
}
public void Update(GameTime gameTime)
{
position += velocity;
KeyboardState keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Keys.D))
{
velocity.X = 3f;
}
if (keyState.IsKeyDown(Keys.A))
{
velocity.X = -3f;
}
if (keyState.IsKeyDown(Keys.Space) && hasJumped==false)
{
position.Y -= 10f;
velocity.Y = -5f;
hasJumped = true;
}
if (hasJumped == true)
velocity.Y += 0.15f;
else
velocity.Y = 0f;
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, source, Color.White, 0f, Vector2.Zero, scale, SpriteEffects.None, 0f);
}
}
}
You can't reference texture within your constructor because it doesn't exist yet. It's not set to an actual value until you load the texture in LoadContent(), so when you try to use it to build your rectangle it's throwing a NullReferenceException.
Create your source rectangle after this line:
texture = Content.Load<Texture2D>("player");
Related
I am trying to create an ellipse in 3D space. Ive used
https://www.youtube.com/watch?v=mQKGRoV_jBc
https://www.youtube.com/watch?v=Or3fA-UjnwU&t=390s
https://www.youtube.com/watch?v=lKfqi52PqHk
to create an ellipse. Now the ellipse is constructed via a xAxis and a yAxis. I need to move the middlepoint of the ellipse a given distance in a certain direction and then tilt the hole plane on which the ellipse is constructed at a certain angle.
Now my idea is to take the transform.position of the constructing empty and offset it in the direction needed and at the distance needed. The idea goes then further by simply rotating the constructing empty the given angle. Unfortunelty I have 0 clue how to. Ive provided you with the Ellipse class creating the Ellipse and the EllipseRenderer-script so you have an idea whats going on.
[System.Serializable]
public class Ellipse
{
float xAxis;
float yAxis;
public Ellipse(float xAxis, float yAxis)
{
this.xAxis = xAxis;
this.yAxis = yAxis;
}
public Vector2 Evaluate(float orbitalProgression)
{
float angle = Mathf.Deg2Rad * 360 * orbitalProgression;
float x = Mathf.Sin(angle) * xAxis;
float y = Mathf.Cos(angle) * yAxis;
return new Vector2(x, y);
}
}
,
public class OrbitMotion : MonoBehaviour
{
public Transform orbitingObject;
public Ellipse orbitPath;
[Range(0f,1f)]
public float orbitProgress = 0f;
public float orbitPeriod = 3f;
public bool orbitActive = false;
void Start()
{
if (orbitingObject == null)
{
orbitActive = false;
return;
}
SetOrbitingObjectPosition();
StartCoroutine(AnimateOrbit());
}
void SetOrbitingObjectPosition()
{
Vector2 orbitPos = orbitPath.Evaluate(orbitProgress);
orbitingObject.position = new Vector3(orbitPos.x, 0, orbitPos.y);
}
IEnumerator AnimateOrbit()
{
if (orbitPeriod < 0.1f)
{
orbitPeriod = 0.1f;
}
float orbitspeed = 1 / orbitPeriod;
while (orbitActive)
{
orbitProgress += Time.deltaTime * orbitspeed;
orbitProgress %= 1f;
SetOrbitingObjectPosition();
yield return null;
}
}
}
and
[RequireComponent(typeof(LineRenderer))]
public class EllipseRenderer : MonoBehaviour
{
[Range(3, 36)]
public int segments = 7;
public LineRenderer lr;
public Ellipse ellipse;
private void Awake()
{
lr = GetComponent<LineRenderer>();
CalculateEllipse();
}
void CalculateEllipse()
{
Vector3[] points = new Vector3[segments + 1];
for (int i = 0; i < segments; i++)
{
Vector2 position2D = ellipse.Evaluate((float)i / (float)segments);
points[i] = new Vector3(position2D.x, position2D.y, 0);
}
points[segments] = points[0];
lr.positionCount = segments + 1;
lr.SetPositions(points);
}
public Vector3 CalculatePosition()
{
}
private void OnValidate()
{
CalculateEllipse();
}
}
As the title says, I'm trying to make a simple 2D game similar to Kitty Cannon in Monogame. However I'm having trouble with aligning the cannonball with the pipe, since it's rotatable. How do I connect the cannonball's spawn point with the correct angle and position?
I'm posting the code I currently have below, hope it's understandable!
class CannonBallSprite
{
private Texture2D texture;public bool shootingActive = false;
public bool shootCannon = false;
public bool keyPressed = false;
public Vector2 position;
public Vector2 origin;
public Vector2 speed = new Vector2(0, 0.1f);
public Vector2 originalSpeed = new Vector2(0, 0.1f);
public Vector2 angle; //Trajectory
public float scale;
public float minPower = 10;
public float maxPower = 15;
public float power = 10;
public CannonBallSprite(Texture2D texture)
{
this.texture = texture;
}
public void Update(float rotation, Sprite sprite)
{
if (Keyboard.GetState().IsKeyDown(Keys.Left) && power > minPower && !keyPressed)
{
power -= 1;
keyPressed = true;
}
else if (Keyboard.GetState().IsKeyDown(Keys.Right) && power < maxPower && !keyPressed)
{
power += 1;
keyPressed = true;
}
if (Keyboard.GetState().IsKeyUp(Keys.Left) && keyPressed)
{
System.Threading.Thread.Sleep(300);
keyPressed = false;
}
else if(Keyboard.GetState().IsKeyUp(Keys.Right) && keyPressed)
{
System.Threading.Thread.Sleep(300);
keyPressed = false;
}
if (Keyboard.GetState().IsKeyDown(Keys.Space) && !shootingActive)
{
position = new Vector2(107, 365); // here maybe?
sprite.hasHit = false;
shootCannon = true;
}
if(shootCannon)
{
Move(angle, power);
speed += new Vector2(0, 0.1f); //standard gravitation
angle = new Vector2((float)Math.Cos(rotation), (float)Math.Sin(rotation));
Debug.Write("test");
position += speed; //Definiera marken
}
else
{
speed = originalSpeed;
}
}
public void Move(Vector2 rot, float shootPower)
{
position.X += rot.X * shootPower;
position.Y += rot.Y * shootPower;
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, null, Color.White, 0, origin, scale, SpriteEffects.None, 0f);
}
}
Game1 Class:
namespace CannonShoot
{
public class Game1 : Game
{
private GraphicsDeviceManager graphics;
private SpriteBatch spriteBatch;
private Texture2D cannon;
private Texture2D cannonball;
private Texture2D man;
private SpriteFont font;
private Sprite spriteCannon;
private Sprite manSprite;
private CannonBallSprite cannonBallSprite;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
font = Content.Load<SpriteFont>("fontfile");
cannon = Content.Load<Texture2D>("cannon");
cannonball = Content.Load<Texture2D>("cannonball");
man = Content.Load<Texture2D>("man");
spriteCannon = new Sprite(cannon)
{
position = new Vector2(100, 400),
origin = new Vector2(cannon.Width / 2, cannon.Height / 2),
scale = 0.12f
};
cannonBallSprite = new CannonBallSprite(cannonball)
{
position = new Vector2(1150, 3750),
scale = 0.2f
};
manSprite = new Sprite(man)
{
position = new Vector2(700, 250),
origin = new Vector2(man.Width / 2, man.Height / 2),
scale = 0.4f
};
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
if(!cannonBallSprite.shootCannon)
{
spriteCannon.Update();
}
//cannonBallSprite = (spriteCannon.position.X, spriteCannon.position.Y);
cannonBallSprite.Update(spriteCannon.rotation, manSprite);
manSprite.UpdateHitbox(cannonBallSprite);
if(cannonBallSprite.position.X >= 1000 || cannonBallSprite.position.Y >= 600) //respawn
{
cannonBallSprite.shootCannon = false;
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteCannon.Draw(spriteBatch);
manSprite.Draw(spriteBatch);
cannonBallSprite.Draw(spriteBatch);
spriteBatch.DrawString(font, "Power: " + cannonBallSprite.power, new Vector2(16, 16), Color.Black);
spriteBatch.DrawString(font, "Hits: " + manSprite.hit, new Vector2(16, 62), Color.Black);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Sprite class:
namespace CannonShoot
{
class Sprite
{
private Texture2D texture;
public Vector2 position;
public Vector2 origin;
public float scale;
public float rotationVelocity = 3f;
public float linearVelocity = 4f;
public float minRot = -1f;
public float maxRot = 0f;
public float rotation;
public float hit = 0;
public bool hasHit = false;
public Sprite(Texture2D texture)
{
this.texture = texture;
}
public void Update()
{
if (rotation <= maxRot && rotation >= minRot)
{
if (Keyboard.GetState().IsKeyDown(Keys.Up))
{
rotation -= MathHelper.ToRadians(rotationVelocity);
}
else if (Keyboard.GetState().IsKeyDown(Keys.Down))
{
rotation += MathHelper.ToRadians(rotationVelocity);
}
if(rotation < minRot)
{
rotation = minRot;
}
if (rotation > maxRot)
{
rotation = maxRot;
}
}
}
public void UpdateHitbox(CannonBallSprite cbSprite) //hitbox och
{
if(cbSprite.position.X >= 700 && cbSprite.position.Y <= 350 && cbSprite.position.Y >= 150 && !hasHit)
{
hit++;
hasHit = true;
cbSprite.shootCannon = false;
}
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, null, Color.White, rotation, origin, scale, SpriteEffects.None, 0f);
}
}
}
Here is how I draw something (object B) at a specific position of something else (object A).
First, you need to have a method (or something) to get the X and Y position of object A:
public float getPosX()
{
return pos.X;
}
Then you simply set the position of your object B in Update method as below:
objectB.setPos(objectA.getposX() + offsetX, objectA.getposY() + offsetY);
I would recommend you draw your object A in a specific scale to your screen's width and height (for example, objectA.width = screenWidth / 10). After doing this, if your object A is moving, your object B will always follow object A's position.
Edit: The image below is the result of my code:
The code to get the barrel position of a rotating object:
angle = new Vector2((float)Math.Cos(rotation), (float)Math.Sin(rotation));
SpawnPosition = position + angle * TextureWidth * scale; // + .5f * TextureHeight * scale; if origin is at 0,0.
The width and height are based on the cannon texture pointing to the right.
I recently started working with monogame and everything went great until this happened.
I am not very experienced so this might just seem stupid but I've tried everything and this is my only option, so this is my constructor:
public void qlayer(Vector2 position, Texture2D texture)
{
this.position = position;
this.texture = texture;
}
"qlayer" is the name of my class but and it keeps saying: "member names cannot be the same as their enclosing type" which would make sense if i didn't want to make a constructor!
Just to be safe, here's the entire class:
class qlayer
{
Vector2 position;
Point speed;
Rectangle hitbox;
Texture2D texture;
Point currentFrame;
int timeSinceLastFrame = 0;
int millisecondsPerFrame;
bool isFront = true;
Point sheetSize = new Point(2,3);
public void qlayer(Vector2 position, Texture2D texture, SpriteBatch spritebatch)
{
this.position = position;
this.texture = texture;
}
enum PlayerAni
{
left, front, right
};
PlayerAni currentAni = PlayerAni.front;
public void Update(GameTime gameTime)
{
timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;
if (timeSinceLastFrame > millisecondsPerFrame)
{
timeSinceLastFrame = 0;
++currentFrame.X;
if (currentFrame.X >= sheetSize.X)
{
currentFrame.X = 0;
++currentFrame.Y;
if (currentFrame.Y >= sheetSize.Y)
currentFrame.Y = 0;
}
}
if (Keyboard.GetState().IsKeyDown(Keys.Left) || Keyboard.GetState().IsKeyDown(Keys.A))
{
position.X -= 3;
currentAni = PlayerAni.left;
}
else
{
if (Keyboard.GetState().IsKeyDown(Keys.Right) || Keyboard.GetState().IsKeyDown(Keys.D))
{
position.X += 3;
currentAni = PlayerAni.right;
}
else
{
currentAni = PlayerAni.front;
}
}
}
public void Draw(GameTime gameTime, SpriteBatch spritebatch)
{
spritebatch.Begin();
spritebatch.Draw(texture,
position, new Rectangle(currentFrame.X * 76,
currentFrame.Y * 54,
76, 54),
Color.White, 0, Vector2.Zero,
1f, SpriteEffects.None, 0);
spritebatch.End();
}
}
public void qlayer
Take out the word void. Constructors don't have a "return" type, including void. Your constructor should look like this:
public qlayer(Vector2 position, Texture2D texture)
and/or
public qlayer(Vector2 position, Texture2D texture, SpriteBatch spritebatch)
How would you see if a key has been released?
I want for example, when the user released the Left key, the animation of the character stops and stays on the frame where he is looking/facing left
Here is my player class:
public class Player
{
#region Animation
int currentFrame;
int frameWidth;
int frameHeight;
float timer;
float interval = 65;
#endregion
private Texture2D texture;
private Vector2 position = new Vector2(64, 200);
private Vector2 velocity;
private Rectangle rectangle;
private bool isMoving;
KeyboardState keyState;
public enum playerStates
{
RIGHT,
LEFT,
WALKINGRIGHT,
WALKINGLEFT
}
playerStates currentPlayerState = playerStates.LEFT;
private bool hasJumped = false;
public Vector2 Position
{
get { return position; }
}
public Player(Texture2D newTexture, Vector2 newPosition, int newFrameWidth, int newFrameHeight)
{
texture = newTexture;
position = newPosition;
frameWidth = newFrameWidth;
frameHeight = newFrameHeight;
isMoving = false;
}
public void LoadContent(ContentManager Content)
{
texture = Content.Load<Texture2D>("Mario/full");
}
public void Update(GameTime gameTime)
{
rectangle = new Rectangle(currentFrame * frameWidth, 0, frameWidth, frameHeight);
position = position + velocity;
#region Key Presses
KeyboardState lastKeyState = keyState;
keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Keys.Left))
{
//position.X -= 1;
AnimateLeft(gameTime);
currentPlayerState = playerStates.LEFT;
isMoving = true;
}
if (keyState.IsKeyDown(Keys.Right))
{
//position.X -= 1;
AnimateRight(gameTime);
currentPlayerState = playerStates.RIGHT;
isMoving = true;
}
//Check for last keypresses
#endregion
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, rectangle, Color.White, 0f, Vector2.Zero, 1.0f, SpriteEffects.None, 1);
}
#region DrawAnimation
public void AnimateLeft(GameTime gameTime)
{
timer += (float)gameTime.ElapsedGameTime.TotalMilliseconds / 2;
if (timer > interval)
{
currentFrame++;
timer = 0;
if (currentFrame > 3 || currentFrame < 2)
{
currentFrame = 2;
}
}
}
public void AnimateRight(GameTime gameTime)
{
timer += (float)gameTime.ElapsedGameTime.TotalMilliseconds / 2;
if (timer > interval)
{
currentFrame++;
timer = 0;
if (currentFrame > 5 || currentFrame < 3)
{
currentFrame = 4;
}
}
}
#endregion
}
If you want to check if a key is "toggled" or pressed, you need to use two KeyboardStates, one for the current frame, and one for the last frame. Looks like you already had some of this going on, but I will just start here
public static KeyboardState CurrentKeyboardState;
public static KeyboardState LastKeyboardState;
In your update method, you need to set these
LastKeyboardState = CurrentKeyboardState;
CurrentKeyboardState = Keyboard.GetState();
For checking if a key was pressed, it must be down one frame, and up the other. So we can check with that.
if (LastKeyboardState.IsKeyDown(Keys.Left) && !CurrentKeyboardState.IsKeyDown(Keys.Left))
//Do Stuff
You can do what I have done, and make a handy extension method so you can simply do if (Keys.Left.IsKeyToggled). If you haven't used extension methods before, you can read about them here. You will need a static class
public static class Extensions
{
}
And just use a method which has the code we used above, Replace "Class" with whatever class has the keyboard states.
public static bool IsKeyToggled(this Keys key)
{
return Class.LastKeyboardState.IsKeyDown(key) && !Class.CurrentKeyboardState.IsKeyDown(key)
}
I always get this error message:
This method does not accept null for this parameter.
Parameter name: texture
MyTexture in the Bullet class is null, but I don't know how to change that.
Could somebody help me, please?
public class Map
{
Texture2D myEnemy;
Player Player;
List<Enemy> enemieslist = new List<Enemy>();
float fNextEnemy = 0.0f;
float fEnemyFreq = 3.0f;
int fMaxEnemy = 3;
Vector2 Startposition = new Vector2(200, 200);
GraphicsDeviceManager graphicsDevice;
public Map(GraphicsDeviceManager device)
{
graphicsDevice = device;
}
public void Load(ContentManager content)
{
myEnemy = content.Load<Texture2D>("gegner");
Player = new Player(graphicsDevice);
Player.Load(content);
}
public void Update(GameTime gameTime)
{
Player.Update(gameTime);
float delta = (float)gameTime.ElapsedGameTime.TotalSeconds;
for(int i = enemieslist.Count - 1; i >= 0; i--)
{
// Update Enemy
Enemy enemy = enemieslist[i];
enemy.Update(gameTime, this.graphicsDevice, Player.spielershape.Position, delta);
// Try to remove an enemy
if (enemy.Remove == true)
{
enemieslist.Remove(enemy);
enemy.Remove = false;
}
}
this.fNextEnemy += delta;
//New enemy
if (fMaxEnemy > 0)
{
if ((this.fNextEnemy >= fEnemyFreq) && (enemieslist.Count < 3))
{
Vector2 enemyDirection = Vector2.Normalize(Player.playershape.Position - Startposition) * 100f;
enemieslist.Add(new Enemy(Startposition, enemyDirection, Player.playershape.Position));
fMaxEnemy -= 1;
fNextEnemy -= fEnemyFreq;
}
}
}
public void Draw(SpriteBatch batch)
{
Player.Draw(batch);
foreach (Enemy enemies in enemieslist)
{
enemies.Draw(batch, myEnemy);
}
}
}
public class Enemy
{
List<Bullet> bulletslist = new List<Bullet>();
Texture2D myBullet;
private float nextShot = 0;
private float shotFrequency = 2.0f;
Vector2 vPos;
Vector2 vMove;
Vector2 vPlayer;
public bool Remove;
public bool Shot;
public Enemy(Vector2 Pos, Vector2 Move, Vector2 Player)
{
this.vPos = Pos;
this.vMove = Move;
this.vPlayer = Player;
this.Remove = false;
this.Shot = false;
}
public void Load(ContentManager content)
{
myBullet = content.Load<Texture2D>("bullet");
}
public void Update(GameTime gameTime, GraphicsDeviceManager graphics, Vector2 PlayerPos, float delta)
{
nextShot += delta;
for (int i = bulletslist.Count - 1; i >= 0; i--)
{
// Update Bullet
Bullet bullets = bulletslist[i];
bullets.Update(gameTime, graphics, delta);
// Try to remove a bullet... Collision, hit, or outside screen.
if (bullets.Remove == true)
bulletslist.Remove(bullets);
bullets.Remove = false;
}
if (nextShot >= shotFrequency)
{
this.Shot = true;
nextShot -= shotFrequency;
}
// Does the enemy shot?
if ((Shot == true) && (bulletslist.Count < 1))
// New bullet
{
Vector2 bulletDirection = Vector2.Normalize(PlayerPos - this.vPos) * 200f;
bulletslist.Add(new Bullet(this.vPos, bulletDirection, PlayerPos));
Shot = false;
}
if (!Remove)
{
this.vMove = Vector2.Normalize(PlayerPos - this.vPos) * 100f;
this.vPos += this.vMove * delta;
if (this.vPos.X > graphics.PreferredBackBufferWidth + 1)
{
this.Remove = true;
}
else if (this.vPos.X < -20)
{
this.Remove = true;
}
if (this.vPos.Y > graphics.PreferredBackBufferHeight + 1)
{
this.Remove = true;
}
else if (this.vPos.Y < -20)
{
this.Remove = true;
}
}
}
public void Draw(SpriteBatch batch, Texture2D myTexture)
{
if (!Remove)
{
batch.Draw(myTexture, this.vPos, Color.White);
}
foreach (Bullet bullets in bulletslist)
{
bullets.Draw(batch, myBullet);
}
}
}
public class Bullet
{
Vector2 vPos;
Vector2 vMove;
Vector2 vPlayer;
public bool Remove;
public Bullet(Vector2 Pos, Vector2 Move, Vector2 Player)
{
this.Remove = false;
this.vPos = Pos;
this.vMove = Move;
this.vPlayer = Player;
}
public void Update(GameTime gameTime, GraphicsDeviceManager graphics, float delta)
{
if (!Remove)
{
this.vPos += this.vMove * delta;
if (this.vPos.X > graphics.PreferredBackBufferWidth +1)
{
this.Remove = true;
}
else if (this.vPos.X < -20)
{
this.Remove = true;
}
if (this.vPos.Y > graphics.PreferredBackBufferHeight +1)
{
this.Remove = true;
}
else if (this.vPos.Y < -20)
{
this.Remove = true;
}
}
}
public void Draw(SpriteBatch spriteBatch, Texture2D myTexture)
{
if (!Remove)
{
spriteBatch.Draw(myTexture, this.vPos, Color.White);
}
}
}
I'm supposing it is this that is where your error is. So you need to add a null check and either draw a default texture or don't draw at all.
public void Draw(SpriteBatch spriteBatch, Texture2D myTexture)
{
if (!Remove)
{
if (null == myTexture)
myTexture = // some default texture, throw an error or skip the draw
if (null != spriteBatch)
spriteBatch.Draw(myTexture, this.vPos, Color.White);
}
}
And/or you can put in the Enemy Load() method:
public void Load(ContentManager content)
{
myBullet = content.Load<Texture2D>("bullet");
Debug.Assert(null != myBullet);
}
You should use asserts whenever you are depending on a value to always be something, ie not null.