I'm trying to draw a bullet in Monogame with a high velocity. When I draw it for about 400px/sec "Which is quite slow" but around 1500px/sec it starts "duplicating" or "ghosting" the Texture. I am fairly new to Monogame and do not have alot of knowledge on Graphics.
How can I move an object with High Velocity without creating a "ghost" effect ?
SpriteBatch Begin :
sb.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearWrap, DepthStencilState.None, RasterizerState.CullNone,
null, Global.Camera.GetViewTransformationMatrix());
Draw Method :
public override void Draw(SpriteBatch sb)
{
Vector2 origin = new Vector2(source.Width / 2, source.Height / 2);
Rectangle tRect = Bounds;
sb.Draw(
texture: TDTGame.GameAssets.Texture,
destinationRectangle: tRect,
sourceRectangle: source,
rotation: MathHelper.ToRadians(Rotation - 270f), //Set rotation to forward of the texture.
color: Color.White,
origin: origin,
layerDepth: 1f
);
}
Edit:
Youtube Link : here
Movement of the bullet :
float traveledDistance;
public override void Update(GameTime gt)
{
float deltaTime = (float)gt.ElapsedGameTime.TotalSeconds;
traveledDistance += Speed * deltaTime;
Position += Forward * Speed * deltaTime;
if (traveledDistance > Range)
{
Destroy();
}
}
This is likely an artifact of low frame rate. The higher the frame rate, the less your brain will register the fact that the bullet's "movement" is simply drawing the same image in multiple and changing locations over time :)
As stated the traces are probably in your eyes, not on the screen. If you want to overcome this effect, you may want to skip some frames (maybe completely remove the bullet from screen or at least skip movement).
Related
I would like to make a simple thing in XNA where the background would move when the character moves to the right.
Any ideas how to do it?
thanks
I think you mean like in the game Mario!
Using Scrolling.
Create the game class.
Load resources as described in the procedures of Drawing a Sprite.
Load the background texture.
private ScrollingBackground myBackground;
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
myBackground = new ScrollingBackground();
Texture2D background = Content.Load<Texture2D>("starfield");
myBackground.Load(GraphicsDevice, background);
}
Determine the size of the background texture and the size of the screen.
The texture size is determined using the Height and Width properties, and the screen size is determined using the Viewport property on the graphics device.
Using the texture and screen information, set the origin of the texture to the center of the top edge of the texture, and the initial screen position to the center of the screen.
// class ScrollingBackground
private Vector2 screenpos, origin, texturesize;
private Texture2D mytexture;
private int screenheight;
public void Load( GraphicsDevice device, Texture2D backgroundTexture )
{
mytexture = backgroundTexture;
screenheight = device.Viewport.Height;
int screenwidth = device.Viewport.Width;
// Set the origin so that we're drawing from the
// center of the top edge.
origin = new Vector2( mytexture.Width / 2, 0 );
// Set the screen position to the center of the screen.
screenpos = new Vector2( screenwidth / 2, screenheight / 2 );
// Offset to draw the second texture, when necessary.
texturesize = new Vector2( 0, mytexture.Height );
}
To scroll the background, change the screen position of the background texture in your Update method.
This example moves the background down 100 pixels per second by increasing the screen position's Y value.
protected override void Update(GameTime gameTime)
{
...
// The time since Update was called last.
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
// TODO: Add your game logic here.
myBackground.Update(elapsed * 100);
base.Update(gameTime);
}
The Y value is kept no larger than the texture height, making the background scroll from the bottom of the screen back to the top.
public void Update( float deltaY )
{
screenpos.Y += deltaY;
screenpos.Y = screenpos.Y % mytexture.Height;
}
// ScrollingBackground.Draw
Draw the background using the origin and screen position calculated in LoadContent and Update.
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
myBackground.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
In case the texture doesn't cover the screen, another texture is drawn. This subtracts the texture height from the screen position using the texturesize vector created at load time. This creates the illusion of a loop.
public void Draw( SpriteBatch batch )
{
// Draw the texture, if it is still onscreen.
if (screenpos.Y < screenheight)
{
batch.Draw( mytexture, screenpos, null,
Color.White, 0, origin, 1, SpriteEffects.None, 0f );
}
// Draw the texture a second time, behind the first,
// to create the scrolling illusion.
batch.Draw( mytexture, screenpos - texturesize, null,
Color.White, 0, origin, 1, SpriteEffects.None, 0f );
}
How can I calculate point of UV texture pressed on object?
For example: I have a ball textured by Earth uv map and I pressed any city and I'd like to get a possition that city on Earth bitmp?
I'm going to try explain :)
I have a code:
bool draw;
int old_position_X;
int old_position_Y;
void __fastcall TForm1::Image3D(TObject *Sender, TShiftState Shift, float X,
float Y, TVector3D &RayPos, TVector3D &RayDir)
{
if (Shift.Contains(ssLeft))
{
if (draw==true)
{
TVector3D HitPos;
Image3D->Context->Pick(X, Y, TProjection::pjCamera, RayPos, RayDir);
RayCastPlaneIntersect(RayPos, RayDir, Image3D->AbsolutePosition, Image3D->AbsoluteDirection, HitPos) ;
HitPos.X -= Image3D->Position->X;
HitPos.Y -= Image3D->Position->Y;
int w=Image3D->Bitmap->Width;
int h=Image3D->Bitmap->Height;
int x=(w/Image3D->Width)*(HitPos.X+Image3D->Width/2.0);
int y=(h/Image3D->Height)*(HitPos.Y+Image3D->Height/2.0);
Image3D->Bitmap->Canvas->BeginScene();
Image3D->Bitmap->Canvas->Stroke->Kind=TBrushKind::bkSolid;
Image3D->Bitmap->Canvas->Stroke->Color=claRed;
Image3D->Bitmap->Canvas->DrawLine(TPointF(old_position_X,old_position_Y),TPointF(x,y),1.0);
Image3D->Bitmap->Canvas->EndScene();
old_position_X=x;
old_position_Y=y;
}
}
else
{
draw=false;
}
}
I can zoom, rotate and move the Image3D and that code make me paint on the Image3D.
By the way I don't understand why I have to divide Image3D width and height by 2 but thats work :) I don't understand dependence between 3D object values (scale, positions etc) and pixels... Especially scale X,Y,Z and Width, Height of 3D objects... And dependence with size of textures and scale of 3D objects...
And now, I'd like to make the same on imported models. How to calculate that position on texture.
I don't expect exactly the code but I would ask for guidance, example code etc
anybody?
The usual way to that is:
Calculate which triangle you have hit, using the ray.
Get the UV coordinates of its three vertices and interpolate.
I'm looking for the best option on how to handle snapping sprites to a tilemap. I'm trying to make a Chu Chu Rocket clone. If you dont know the game. It is a tilebased game where you place arrows on a specfic tile to direct unts around the maps. So I need to snap the sprites to the center of the tile at all times and then detect a collision with either an arrow which takes up a whole tile or a wall or other obstruction. Any ideas on what the based way would be to detect those things since it would require different kinds of collision detection i believe.
The easiest way to snap the sprites to a tile is to draw them centered at a tile. The collision detection can be done in your update function by checking against your level object.
class Mouse
{
public int XTile;
public int YTile;
public int XDelta;
public int YDelta;
}
//in Update
if (Level[mouse.YTile][mouse.XTile] == Tiles.Arrow)
{
//change mouse.XDelta and mouse.YDelta based on the direction of the arrow
}
if (Level[mouse.YTile + YDelta][mouse.XTile + XDelta] == Tiles.Wall)
{
//change mouse.XDelta and mouse.YDelta based on wall rules
}
//in Draw
int tileSize = 32; //or whatever size tile you are using
spriteBatch.Draw(mouseSprite, new Vector2(mouse.XTile * tileSize,
mouse.YTile * tileSize), Color.White);
//or, if the mouseSprite doesn't take up the whole tile
int sizeDifference = tileSize - mouseSprite.Width;
spriteBatch.Draw(mouseSprite, new Vector2(mouse.XTile * tileSize + sizeDifference / 2f,
mouse.YTile * tileSize + sizeDifference / 2f), Color.White);
I'm currently working on a XNA game prototype. I'm trying to achieve a isometric view of the game world (or is it othographic?? I'm not sure which is the right term for this projection - see pictures).
The world should a tile-based world made of cubic tiles (e.g. similar to Minecraft's world), and I'm trying to render it in 2D by using sprites.
So I have a sprite sheet with the top face of the cube, the front face and the side (visible side) face. I draw the tiles using 3 separate calls to drawSprite, one for the top, one for the side, one for the front, using a source rectangle to pick the face I want to draw and a destination rectangle to set the position on the screen according to a formula to convert from 3D world coordinates to isometric (orthographic?).
(sample sprite:
)
This works good as long as I draw the faces, but if I try to draw fine edges of each block (as per a tile grid) I can see that I get a random rendering pattern in which some lines are overwritten by the face itself and some are not.
Please note that for my world representation, X is left to right, Y is inside screen to outside screen, and Z is up to down.
In this example I'm working only with top face-edges. Here is what I get (picture):
I don't understand why some of the lines are shown and some are not.
The rendering code I use is (note in this example I'm only drawing the topmost layers in each dimension):
/// <summary>
/// Draws the world
/// </summary>
/// <param name="spriteBatch"></param>
public void draw(SpriteBatch spriteBatch)
{
Texture2D tex = null;
// DRAW TILES
for (int z = numBlocks - 1; z >= 0; z--)
{
for (int y = 0; y < numBlocks; y++)
{
for (int x = numBlocks - 1; x >=0 ; x--)
{
myTextures.TryGetValue(myBlockManager.getBlockAt(x, y, z), out tex);
if (tex != null)
{
// TOP FACE
if (z == 0)
{
drawTop(spriteBatch, x, y, z, tex);
drawTop(spriteBatch, x, y, z, outlineTexture);
}
// FRONT FACE
if(y == numBlocks -1)
drawFront(spriteBatch, x, y, z, tex);
// SIDE FACE
if(x == 0)
drawSide(spriteBatch, x, y, z, tex);
}
}
}
}
}
private void drawTop(SpriteBatch spriteBatch, int x, int y, int z, Texture2D tex)
{
int pX = OffsetX + (int)(x * TEXTURE_TOP_X_OFFRIGHT + y * TEXTURE_SIDE_X);
int pY = OffsetY + (int)(y * TEXTURE_TOP_Y + z * TEXTURE_FRONT_Y);
topDestRect.X = pX;
topDestRect.Y = pY;
spriteBatch.Draw(tex, topDestRect, TEXTURE_TOP_RECT, Color.White);
}
I tried using a different approach, creating a second 3-tiers nested for loop after the first one, so I keep the top face drawing in the first loop and the edge highlight in the second loop (I know, this is inefficient, I should also probably avoid having a method call for each tile to draw it, but I'm just trying to get it working for now).
The results are somehow better but still not working as expected, top rows are missing, see picture:
Any idea of why I'm having this problem? In the first approach it might be a sort of z-fighting, but I'm drawing sprites in a precise order so shouldn't they overwrite what's already there?
Thanks everyone
Whoa, sorry guys I'm an idiot :) I started the batch with SpriteBatch.begin(SpriteSortMode.BackToFront) but I didn't use any z-value in the draw.
I should have used SpriteSortMode.Deferred! It's now working fine. Thanks everyone!
Try tweaking the sizes of your source and destination rectangles by 1 or 2 pixels. I have a sneaking suspicion this has something to do with the way these rectangles are handled as sort of 'outlines' of the area to be rendered and a sort of off-by-one problem. This is not expert advice, just a fellow coder's intuition.
Looks like a sub pixel precision or scaling issue. Also try to ensure your texture/tile width/height is a power of 2 (32, 64, 128, etc.) as that could make the effect less bad as well. It's really hard to tell just from those pictures.
I don't know how/if you scale everything, but you should try to avoid rounding wherever possible (especially inside your drawTop() method). Every time you round some position/coordinate chances are good you might increase the error/random offsets. Try to use double (or better: float) coordinates instead of integer.
Ok so I have a ship which moves up and down based on the axis regardless of where the ship is facing.
How do I make the ship move in the direction it's facing? i.e. if my ship is facing east, key up makes it go north rather than east.
Your question isn't very clear - I will assume you're using models and matrices (as opposed to SpriteBatch or something else). So, making a guess - I'd say that the order of your matrix operations is incorrect.
This answer to a similar question may help.
Each matrix operation happens around the origin. So if you're doing your rotation after you move your ship into position, your rotation will also effectively "rotate" the direction of movement.
The easiest way is to make an angle and velocity variable so when you click left and right you change the angle and when you click up and down you changle the speed of your ship.
KeyboardState ks;
float speed = 0;
float angle = 0;
protected override void Update(GameTime gameTime)
{
ks = Keyboard.GetState();
if(ks.IsKeyDown(Keys.Up)) speed += 10;
if (ks.IsKeyDown(Keys.Down)) speed -= 10;
if (ks.IsKeyDown(Keys.Right)) angle += 10;
if (ks.IsKeyDown(Keys.Left)) angle -= 10;
}
You need to have direction vector like this
Vector3 direction = Vector3.Transform(Vector3.Forward, Matrix.CreateFromYawPitchRoll(yaw, pitch, roll));
Next, get your velocity vector
Vector3 velocity = direction * speed;
And move your ship
float time (float) = gameTime.ElapsedTime.TotalSeconds;
position += velocity * time;
In this example yaw is angle, pitch and roll keep 0.