First, sorry for my bad English, English is not my native language.
I have a problem when I draw a Texture2D in screen. When I move a Texture in screen,
colors in border of the texture flickers. This is my code:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using SharpDX.Direct2D1.Effects;
using System;
using System.Collections.Generic;
namespace PixelTest
{
public class Drawable
{
public Texture2D Image;
public Point Position;
public Point Size;
public Rectangle Source;
}
public class MainGame : Game
{
//PRIVATE READ-ONLY VARIABLES
private readonly GraphicsDeviceManager _graphics;
private readonly List<Drawable> _sprites;
//VARIABLES
private Texture2D _screen;
private Texture2D _tiles;
private SpriteBatch _spriteBatch;
private Point _camera;
private Point _scale;
private bool _byRect;
private KeyboardState _previousKeyState;
private BlendState _state;
private RasterizerState _rState;
//CONSTRUCTOR
public MainGame()
{
_graphics = new GraphicsDeviceManager(this);
_sprites = new List<Drawable>();
_tiles = null;
_spriteBatch = null;
_camera = Point.Zero;
_scale = new Point(1, 1);
Content.RootDirectory = "Content";
IsMouseVisible = true;
IsFixedTimeStep = true;
//_graphics.PreferHalfPixelOffset = true;
_graphics.PreferMultiSampling= true;
//_graphics.SynchronizeWithVerticalRetrace = false;
_state = new BlendState()
{
AlphaBlendFunction = BlendFunction.Add,
AlphaSourceBlend = Microsoft.Xna.Framework.Graphics.Blend.Zero,
AlphaDestinationBlend = Microsoft.Xna.Framework.Graphics.Blend.Zero,
ColorBlendFunction= BlendFunction.Add,
ColorDestinationBlend = Microsoft.Xna.Framework.Graphics.Blend.Zero,
ColorSourceBlend = Microsoft.Xna.Framework.Graphics.Blend.One,
};
_rState = new RasterizerState()
{
MultiSampleAntiAlias = false
};
}
protected override void Initialize()
{
base.Initialize();
_sprites.Add(new Drawable
{
Image = _tiles,
Position = new Point(32, 64),
Size = new Point(8, 8),
Source = new Rectangle(0, 0, 8, 8)
});
}
protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
_tiles = Content.Load<Texture2D>("i001_tiles");
_screen = new Texture2D(GraphicsDevice, _graphics.PreferredBackBufferWidth, _graphics.PreferredBackBufferHeight);
var colors = new Color[_graphics.PreferredBackBufferWidth * _graphics.PreferredBackBufferHeight];
for (var i = 0; i < _graphics.PreferredBackBufferWidth * _graphics.PreferredBackBufferHeight; i++)
colors[i] = Color.Black;
_screen.SetData(colors);
}
protected override void UnloadContent()
{
base.UnloadContent();
_tiles.Dispose();
_screen.Dispose();
}
protected override void Update(GameTime gameTime)
{
base.Update(gameTime);
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
var sKey = Keyboard.GetState();
var translateUnit = Point.Zero;
var scaleUnit = 0;
if (sKey.IsKeyDown(Keys.A))
translateUnit.X = -1;
else if (sKey.IsKeyDown(Keys.D))
translateUnit.X = 1;
else
translateUnit.X = 0;
if (sKey.IsKeyDown(Keys.W))
translateUnit.Y = -1;
else if (sKey.IsKeyDown(Keys.S))
translateUnit.Y = 1;
else
translateUnit.Y = 0;
if (sKey.IsKeyDown(Keys.F))
scaleUnit = -1;
else if (sKey.IsKeyDown(Keys.G))
scaleUnit = 1;
else
scaleUnit = 0;
if (sKey.IsKeyDown(Keys.U) && _previousKeyState.IsKeyUp(Keys.U))
_byRect = !_byRect;
var speed = translateUnit;// * 1;
_camera += speed;// RoundVec(speed);
_scale = new Point(4, 4);
_previousKeyState = sKey;
}
protected override void Draw(GameTime gameTime)
{
base.Draw(gameTime);
GraphicsDevice.Clear(Color.Blue);
_spriteBatch.Begin(SpriteSortMode.Deferred, _state, SamplerState.PointClamp, null, _rState, null, null);
//_spriteBatch.Draw(_screen, Vector2.Zero, Color.White);
foreach (var item in _sprites)
{
if (true)
{
var pos = item.Position;
var size = item.Size;
pos += _camera;
pos *= _scale;
size *= _scale;
var rect = new Rectangle(
(int)pos.X,
(int)pos.Y,
(int)size.X,
(int)size.Y);
_spriteBatch.Draw(
item.Image,
rect,
item.Source,
Color.White,
0F,
Vector2.Zero,
SpriteEffects.None,
0F);
}
else
{
var pos = item.Position;
//pos = RoundVec(pos * _scale) / _scale;
pos += _camera;
pos *= _scale;
_spriteBatch.Draw(
item.Image,
pos.ToVector2(),
item.Source,
Color.White,
0F,
Vector2.Zero,
_scale.ToVector2(),
SpriteEffects.None,
0F);
}
}
_spriteBatch.End();
}
}
}
I dont use floats values for camera position in this test and the flickers continue to happens. I dont know what is happen.
I tried various things, but nothing work.
Resources:
i001_tiles.png (no alpha values)
PrintScreens:
Maybe is just a ottical illusion, or a monitor problem, but the green part of texture merge with the blue background on camera movement, i dont know why.
In Movement Up:
This only occour with the colors different of white, when i movement camera to right, only the one pixel in green in the right merge with blue background.
Related
Currently, when you run my code, a square sprite draws whenever and wherever you click the mouse. They fall with gravity. There is also a static black square in the screen to test for collisions, a red square also appears to show that the collision returned true just for the meantime to test the code. However, it totally doesn't work and the red square appears at the wrong time.
private SpriteBatch _spriteBatch;
public Vector2 Origin;
public float Rotation;
Texture2D staticSprite; //static sprite used to check collision with moving particle("white circle")
//white circle gets generated and added to particle list whenever mouse is clicked
List<Particle> particleList = new List<Particle>();
public bool mReleased = true; //mouse button released
public Vector2 clickedMousePos = Vector2.Zero; //default mouse click position
bool collision = false; // no collision by default
Rectangle tTextureRectangle = new Rectangle(200, 200, 100, 100);// rectangle placed for
Rectangle particleRect;
//public int particleIndex = 0; **code adding later**
MouseState mState = Mouse.GetState();
//PerPixelCollision
Color[] stiffSpriteData;
Color[] tTextureData;
// intersect method takes two rectangles and color data to check for collision
static bool IntersectPixels(Rectangle rectangleA, Color[] dataA, Rectangle rectangleB, Color[] dataB)
{
// Find the bounds of the rectangle intersection
int top = Math.Max(rectangleA.Top, rectangleB.Top);
int bottom = Math.Min(rectangleA.Bottom, rectangleB.Bottom);
int left = Math.Max(rectangleA.Left, rectangleB.Left);
int right = Math.Min(rectangleA.Right, rectangleB.Right);
// Check every point within the intersection bounds
for (int y = top; y < bottom; y++)
{
for (int x = left; x < right; x++)
{
// Get the color of both pixels at this point
Color colorA = dataA[(x - rectangleA.Left) +
(y - rectangleA.Top) * rectangleA.Width];
Color colorB = dataB[(x - rectangleB.Left) +
(y - rectangleB.Top) * rectangleB.Width];
// If both pixels are not completely transparent,
if (colorA.A != 0 && colorB.A != 0)
{
// then an intersection has been found
return true;
}
}
}
// No intersection found
return false;
}
public Game1()
{
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
}
protected override void Initialize()
{
_graphics.PreferredBackBufferWidth = 1280;
_graphics.PreferredBackBufferHeight = 720;
_graphics.ApplyChanges();
base.Initialize();
}
protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
staticSprite = Content.Load<Texture2D>("whiteCircle");
//PerPixelCollision
stiffSpriteData = new Color[staticSprite.Width * staticSprite.Height];
staticSprite.GetData<Color>(stiffSpriteData);
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
collision = false;
mState = Mouse.GetState();
clickedMousePos = new Vector2 (mState.Position.X, mState.Position.Y); // updated mouse position when clicked
//draws a particle ("white circle") with garvity and adds to particleList
if (mState.LeftButton == ButtonState.Pressed && mReleased == true)
{
particleList.Add(new Particle(Content.Load<Texture2D>("whiteCircle"), new Vector2(0,1), new Vector2(clickedMousePos.X, clickedMousePos.Y), 1f));
var listSize = particleList.Count - 1;
//PerPixelCollision
tTextureData = new Color[particleList[listSize].texture.Width * particleList[listSize].texture.Height];
particleList[listSize].texture.GetData<Color>(tTextureData);
//Rectangle generates for first moving particle in list for now
particleRect = new Rectangle((int)particleList[listSize].Position.X, (int)particleList[listSize].Position.Y, particleList[0].texture.Width, particleList[0].texture.Height);
mReleased = false;
}
if (mState.LeftButton == ButtonState.Released)
{
mReleased = true;
}
foreach (Particle particle in particleList)
{
particle.Update(gameTime);
}
// Check collision with person
if (IntersectPixels(tTextureRectangle, tTextureData, particleRect, stiffSpriteData))
{
collision = true;
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
_spriteBatch.Begin();
_spriteBatch.Draw(staticSprite, new Vector2(200, 200), null, Color.Black, Rotation, Origin, 0.1f, SpriteEffects.None, 0);
foreach (Particle particle in particleList)
{
particle.Draw(_spriteBatch);
}
// this is to test wether a collision was actually detected
if (collision == true)
{
_spriteBatch.Draw(staticSprite, new Vector2(500, 500), null, Color.Red, Rotation, Origin, 0.1f, SpriteEffects.None, 0);
}
_spriteBatch.End();
base.Draw(gameTime);
}
The core of your problem(among too many others) is the particleRect variable should not exist in Game1, but needs to reference each particle instance (it needs to be referenced from a foreach loop of each particle).
I have annotated your code with //... comments.
The new Game1.cs:
private SpriteBatch _spriteBatch;
// ...Objection; it is poor form to treat Game1 as a game object, as it makes, among many other things, menus near impossible.
// ... The only variables that should be defined here are those pertinent to the entire game (names, difficulty level, score, lives, avatar, level, hasWon, counters for timed events(I would segment per level, but still appropriate here), draw offsets, matrix transforms, aspect ratios ...)
public Vector2 Origin;
public float Rotation;
// ... Nothing in Game1 should have the above properties, but so be it for the minimal example.
Texture2D staticSprite; //static sprite used to check collision with moving particle("white circle")
// ... same objection as above
//white circle gets generated and added to particle list whenever mouse is clicked
// ...When is it removed?
List<Particle> particleList = new List<Particle>();
// ... Lists cannot be modified while enumerated by a foreach
List<Particle> particleListRemove = new List<Particle>();
// bool collision = false; // no collision by default
// ... Collision needs to be handled per particle.
Rectangle tTextureRectangle = new Rectangle(200, 200, 100, 100);// rectangle placed for
//... Rectangle particleRect;
//public int particleIndex = 0; **code adding later**
// ... bad for this example, see above particleListRemove list with this pattern, and below
MouseState mState = Mouse.GetState();
MouseState omState;
// ... having the previous state is much better than a single button
//PerPixelCollision
Color[] stiffSpriteData; // ... I get the fixed box, may be better as described in the above objection.
// ... tTextureData data is not needed across calls and should be defined locally
// Color[] tTextureData;
// intersect method takes two rectangles and color data to check for collision
// ... I have stopped here.
//static bool IntersectPixels(Rectangle rectangleA, Color[] dataA, Rectangle rectangleB, Color[] dataB)
// {
// Check every point within the intersection bounds
// for (int y = top; y < bottom; y++)
// {
// for (int x = left; x < right; x++)
// {
// // Get the color of both pixels at this point
// Color colorA = dataA[(x - rectangleA.Left) +
// (y - rectangleA.Top) * rectangleA.Width];
Color colorB = dataB[(x - rectangleB.Left) +
// (y - rectangleB.Top) * rectangleB.Width];
// If both pixels are not completely transparent,
// if (colorA.A != 0 && colorB.A != 0)
// {
// then an intersection has been found
// return true;
// }
// }
// }
// No intersection found
return false;
}
public Game1()
{
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
}
protected override void Initialize()
{
_graphics.PreferredBackBufferWidth = 1280;
_graphics.PreferredBackBufferHeight = 720;
_graphics.ApplyChanges();
base.Initialize();
}
protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
staticSprite = Content.Load<Texture2D>("whiteCircle");
//PerPixelCollision
stiffSpriteData = new Color[staticSprite.Width * staticSprite.Height];
staticSprite.GetData<Color>(stiffSpriteData);
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
collision = false;
mState = Mouse.GetState();
clickedMousePos = new Vector2 (mState.Position.X, mState.Position.Y); // updated mouse position when clicked
//draws a particle ("white circle") with garvity and adds to particleList
if (mState.LeftButton == ButtonState.Pressed && mReleased == true)
{
particleList.Add(new Particle(Content.Load<Texture2D>("whiteCircle"), new Vector2(0,1), new Vector2(clickedMousePos.X, clickedMousePos.Y), 1f));
var listSize = particleList.Count - 1;
//PerPixelCollision
tTextureData = new Color[particleList[listSize].texture.Width * particleList[listSize].texture.Height];
particleList[listSize].texture.GetData<Color>(tTextureData);
//Rectangle generates for first moving particle in list for now
particleRect = new Rectangle((int)particleList[listSize].Position.X, (int)particleList[listSize].Position.Y, particleList[0].texture.Width, particleList[0].texture.Height);
mReleased = false;
}
if (mState.LeftButton == ButtonState.Released)
{
mReleased = true;
}
foreach (Particle particle in particleList)
{
particle.Update(gameTime);
}
// Check collision with person
if (IntersectPixels(tTextureRectangle, tTextureData, particleRect, stiffSpriteData))
{
collision = true;
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
_spriteBatch.Begin();
_spriteBatch.Draw(staticSprite, new Vector2(200, 200), null, Color.Black, Rotation, Origin, 0.1f, SpriteEffects.None, 0);
foreach (Particle particle in particleList)
{
particle.Draw(_spriteBatch);
}
// this is to test wether a collision was actually detected
if (collision == true)
{
_spriteBatch.Draw(staticSprite, new Vector2(500, 500), null, Color.Red, Rotation, Origin, 0.1f, SpriteEffects.None, 0);
}
_spriteBatch.End();
base.Draw(gameTime);
}
Your Rectangle intersection code never checks to see if there was an actual collision. Replace:
int top = Math.Max(rectangleA.Top, rectangleB.Top);
int bottom = Math.Min(rectangleA.Bottom, rectangleB.Bottom);
int left = Math.Max(rectangleA.Left, rectangleB.Left);
int right = Math.Min(rectangleA.Right, rectangleB.Right);
With:
// not colliding check
if (!rectangleA.Intersects(rectangleB)) return false;
int top = Math.Max(rectangleA.Top, rectangleB.Top);
int bottom = Math.Min(rectangleA.Bottom, rectangleB.Bottom);
int left = Math.Max(rectangleA.Left, rectangleB.Left);
int right = Math.Min(rectangleA.Right, rectangleB.Right);
'''
I'm writing a bit of code where I animate a hundred copies of the same sprite onto the screen by creating a sprite class. I want the sprites, an animation of four-ring interlocking rings spinning within each other, to be drawn at a certain height, drop down on the screen, and bounce like a ball, with each bounce being progressively less until it they stop completely. I have managed to get this part done; however, I can't seem to find a way to randomize the acceleration and animation speed of each different sprite. Can someone provide some suggestions to my code?
Game 1.cs
namespace lab_6
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Sprite rings;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.PreferredBackBufferHeight = 600;
graphics.PreferredBackBufferWidth = 800;
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
Texture2D rings_texture = Content.Load<Texture2D>("Images/threerings");
//animation
Point frameSize = new Point(75, 75);
Point currentFrame = new Point(0, 0);
Point sheetSize = new Point(6, 8);
int millisecondsPerFrame = 50;
rings = new Sprite(rings_texture, ringsPos,
frameSize, 0, currentFrame, sheetSize, ringsSpeed, millisecondsPerFrame);
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
if (Keyboard.GetState().IsKeyDown(Keys.Escape))
this.Exit();
// TODO: Add your update logic here
rings.Update(gameTime, Window.ClientBounds);
base.Update(gameTime);
}
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
spriteBatch.Begin();
rings.Draw(gameTime, spriteBatch);
spriteBatch.End();
}
}
}
Sprite.cs
namespace lab_6
{
public class Sprite
{
//basics
protected Texture2D rings;
protected Vector2 ringsPos = new Vector2(0,0);
protected Color tint = Color.White;
protected Vector2 ringsSpeed = new Vector2(0,0);
protected Vector2 ringsAccel = new Vector2(0, 1);
//animation
protected Point frameSize = new Point(75,75);
protected Point currentFrame = new Point(0, 0);
protected Point sheetSize = new Point(6,8);
//animation timing
protected int timeSinceLastFrame = 0;
protected int millisecondsPerFrame = 50;
const int defaultMillisecondsPerFrame = 16;
//bounding box offset
protected int collisionOffset;
Random r = new Random(DateTime.Now.Millisecond);
public Sprite(Texture2D rings, Vector2 ringsPos, Point frameSize,
int collisionOffset, Point currentFrame, Point sheetSize, Vector2 ringsSpeed,
int millisecondsPerFrame)
{
this.rings = rings;
this.ringsPos = ringsPos;
this.frameSize = frameSize;
this.collisionOffset = collisionOffset;
this.currentFrame = currentFrame;
this.sheetSize = sheetSize;
this.ringsSpeed = ringsSpeed;
this.millisecondsPerFrame = millisecondsPerFrame;
}
public virtual void Update(GameTime gameTime, Rectangle clientBounds)
{
int maxY = (600 - frameSize.Y );
ringsAccel.Y += (byte)r.Next((1 / 10), 1);
ringsSpeed.Y += ringsAccel.Y;
ringsPos.Y += ringsSpeed.Y;
if (ringsPos.Y > maxY)
{
ringsSpeed *= -0.8f;
ringsPos.Y = maxY;
}
//Update animation frame
millisecondsPerFrame = 50;
millisecondsPerFrame *= ((byte)r.Next(1, 10));
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;
}
}
}
public virtual void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
for(int i = 0; i < 100; )
{
Vector2 newPos = ringsPos + new Vector2((10 * i), (1 * (byte)r.Next((1/10), 1)));
spriteBatch.Draw(rings, newPos,
new Rectangle(currentFrame.X * frameSize.X,
currentFrame.Y * frameSize.Y,
frameSize.X, frameSize.Y),
tint, 0, Vector2.Zero, 1f, SpriteEffects.None, 0);
i++;
r = new Random(DateTime.Now.Second);
}
}
}
}
Move the constructor for ringSpeed and ringAccel to the constructor and randomize them there.
"Rem ad Triarios redisse" Scipio Africanus
I'm programming a platformer and I'm working on the collision, but when it collides a get a stack overflow error;I can't figure it out myself and I would be thankfull if someone knew how to fix it.
The code of the class(main concern):
public class Colliding
{
Rectangle testCollide;
Vector2 playerposition, objectPosition;
Texture2D objectPic;
bool jump;
public Rectangle TestCollide
{
get { return TestCollide; }
set { testCollide = value; }
}
public Vector2 ObjectPosition
{
get { return objectPosition; }
set { objectPosition = value; }
}
public Vector2 Return
{
get { return objectPosition; }
}
public Texture2D ObjectPic
{
set { objectPic = value; }
}
public bool Bool
{
get { return jump; }
}
public void Update()
{
/*if (testCollide.Contains(new Point((int)objectPosition.X, (int)objectPosition.Y + (int)objectPic.Height)) && !
testCollide.Contains(new Point((int)objectPosition.X, (int)objectPosition.Y + (int)objectPic.Height)))
{
objectPosition = new Vector2(objectPosition.X, testCollide.Top - objectPic.Height);
jump = false;
}*/
if (testCollide.Contains(new Point((int)objectPosition.X + (int)objectPic.Width, (int)objectPosition.Y))&&
testCollide.Contains(new Point((int)objectPosition.X + (int)objectPic.Width, (int)objectPosition.Y)))
{
objectPosition = new Vector2(TestCollide.Right - objectPic.Width, ObjectPosition.Y);
jump = false;
}
if (testCollide.Contains(new Point((int)objectPosition.X , (int)objectPosition.Y)) &&
testCollide.Contains(new Point((int)objectPosition.X , (int)objectPosition.Y)))
{
objectPosition = new Vector2(TestCollide.Left +1 , ObjectPosition.Y);
jump = false;
}
The Code of my main(a little messy at the moment)
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
KeyboardState keyState;
KeyboardState prevKeyState;
Texture2D flour,nonAnimPlayer;
Rectangle ground1,ground2,playerRect;
Vector2 playerPosition;
float jumpspeed;
int screenX = 800;
int screenY=480;
float standardMoveSpeed;
bool jumping;
Colliding colGround1=new Colliding ();
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
this.graphics.PreferredBackBufferWidth = screenX;
this.graphics.PreferredBackBufferHeight = screenY;
}
protected override void Initialize()
{
keyState = Keyboard.GetState();
ground1 = new Rectangle(-100, (screenY / 5) * 4, 300,screenY);
ground2 = new Rectangle(400, (screenY / 5) * 4, 800, screenY);
playerRect = new Rectangle(0, 0, 10, 10);
standardMoveSpeed = 300;
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
flour = Content.Load<Texture2D>("background");
nonAnimPlayer = Content.Load<Texture2D>("blok");
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
prevKeyState = keyState;
keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Keys.D))
playerPosition.X += standardMoveSpeed *(float) gameTime.ElapsedGameTime.TotalSeconds;
if (keyState.IsKeyDown(Keys.A))
playerPosition.X -= standardMoveSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
if (keyState.IsKeyDown(Keys.Space)&&prevKeyState.IsKeyUp(Keys.Space ))
{
if (jumpspeed == 0)
jumpspeed = 300;
else
jumpspeed += 35;
jumping = true;
}
playerPosition.Y += standardMoveSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
if(jumping)
{
playerPosition.Y -= standardMoveSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds+jumpspeed*(float)gameTime.ElapsedGameTime.TotalSeconds ;
jumpspeed-=9;
if (jumpspeed <= 0)
jumping = false;
}
if (ground2.Contains(new Point((int)playerPosition.X, (int)playerPosition.Y + (int)nonAnimPlayer.Height)))
{
playerPosition.Y = ground2.Top - nonAnimPlayer.Height;
jumpspeed = 0;
}
colGround1.ObjectPosition = playerPosition;
colGround1.TestCollide = ground1;
colGround1.ObjectPic = nonAnimPlayer;
colGround1.Update();
playerPosition = colGround1.Return;
if (colGround1.Bool)
jumpspeed = 0;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(flour, ground1, Color.White);
spriteBatch.Draw(flour, ground2, Color.White);
spriteBatch.Draw(nonAnimPlayer, playerPosition, Color.White);
spriteBatch.End();
base.Draw(gameTime);
When I press left or up arrow keys the sprite gets out of the window/screen. My code:
Texture2D m_PlayerShipTex;
Rectangle m_PlayerShipHitBox;
Vector2 m_PlayerShipPos = new Vector2(400, 486);
Vector2 m_PlayerShipOrigin;
int m_PlayerShipCurrentFrame = 1;
int m_PlayerShipFrameWidth = 62;
int m_PlayerShipFrameHeight = 64;
float m_Timer = 0f;
float m_Interval = 100;
public void LoadContent(ContentManager Content)
{
m_PlayerShipTex = Content.Load<Texture2D>(".\\gameGraphics\\gameSprites\\playerShip\\playerShipSpriteSheet");
}
public void Update(GameTime gameTime)
{
m_PlayerShipHitBox = new Rectangle(m_PlayerShipCurrentFrame * m_PlayerShipFrameWidth, 0, m_PlayerShipFrameWidth, m_PlayerShipFrameHeight);
m_PlayerShipOrigin = new Vector2(m_PlayerShipHitBox.X / 2, m_PlayerShipHitBox.Y / 2);
MouseState m_MouseState = Mouse.GetState();
KeyboardState m_KeyboardState = Keyboard.GetState();
m_Timer += (float)gameTime.ElapsedGameTime.Milliseconds;
if (m_Timer > m_Interval)
{
m_PlayerShipCurrentFrame++;
m_Timer = 0f;
}
if (m_PlayerShipCurrentFrame == 2)
{
m_PlayerShipCurrentFrame = 0;
}
m_PlayerShipHitBox = new Rectangle(m_PlayerShipCurrentFrame * m_PlayerShipFrameWidth, 0, m_PlayerShipFrameWidth, m_PlayerShipFrameHeight);
m_PlayerShipOrigin = new Vector2(m_PlayerShipHitBox.Width / 2, m_PlayerShipHitBox.Height / 2);
if (m_KeyboardState.IsKeyDown(Keys.Right))
{
m_PlayerShipPos.X += 3;
}
if (m_KeyboardState.IsKeyDown(Keys.Left))
{
m_PlayerShipPos.X -= 3;
}
if (m_KeyboardState.IsKeyDown(Keys.Down))
{
m_PlayerShipPos.Y += 3;
}
if (m_KeyboardState.IsKeyDown(Keys.Up))
{
m_PlayerShipPos.Y -= 3;
}
if (m_PlayerShipPos.X <= 0)
{
m_PlayerShipPos.X = 0;
}
if (m_PlayerShipPos.X + m_PlayerShipTex.Width >= 1141)
{
m_PlayerShipPos.X = 1141 - m_PlayerShipTex.Width;
}
if (m_PlayerShipPos.Y <= 0)
{
m_PlayerShipPos.Y = 0;
}
if (m_PlayerShipPos.Y + m_PlayerShipTex.Height >= 620)
{
m_PlayerShipPos.Y = 620 - m_PlayerShipTex.Height;
}
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(m_PlayerShipTex, m_PlayerShipPos, m_PlayerShipHitBox, Color.White, 0f, m_PlayerShipOrigin, 1.0f, SpriteEffects.None, 0);
}
I don't know what could be wrong, my window is 800x600 but if I set m_PlayerShipTex.Width >= 800 I can get only to half of the screen, that's why I'm using 1141. Same goes for window height... What am I doing wrong and why the ship's out of the "reacheable" area?
To fix the original problem, use this draw function:
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(m_PlayerShipTex, m_PlayerShipPos, m_PlayerShipHitBox, Color.White, 0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0);
}
This will use (0,0) as the origin for drawing; which means that your "edge" calculations will work as originally expected. If you want the centered origin, then you need to account for that adjustment when calculating the edges.
The only reason to change the origin is to make rotation easier; in general, you can just use Vector2.Zero.
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;
}
}