XNA 3.5 Firing a tank cannon - c#

I have a 2D image of a tanks body (top down) that can be moved left-right across the screen.
On top, there's a second image of the tanks turret. This turret can be rotated across the screen edge following the users mouse movement along the Y axis.
When the user presses'Enter' a bullet appears and moves across the screen at the angle of the turret. However, whilst the angle is fine, the bullet's position seems to vary a lot. At times, it sites where it should (in the centre of the cannon) however, as you move the mouse it seems to get offsetted.
Edit: For some strange reason, my pictures don't seem to be showing up - so here is a direct link: http://img824.imageshack.us/img824/7093/khte.png
Edited Code:
Tank Fire
if (keyBoardState.IsKeyDown(Keys.Enter))
{
shell.Initialize(rotation, new Vector2(location.X + 25, location.Y - 15));
shell.makeAlive();
}
(It is initialized with the location of the tank (+25, -25) so it appears at the end of the turrent. having this set at the tanks location (shell.Initialize(rotation, location);) seems to make no difference to the offset.)
Bullet/Shell:
public void Update(GameTime gameTime)
{
if (alive)
{
movement.X -= speed * (float)Math.Cos(rotation);
movement.Y -= speed * (float)Math.Sin(rotation);
location.X += (int)movement.X;
location.Y += (int)movement.Y;
}
}
public void Draw(SpriteBatch spriteBatch)
{
if (alive)
{
spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
spriteBatch.Draw(texture, location, null, Color.White, rotation - MathHelper.PiOver2, new Vector2(texture.Width / 2, texture.Height / 2), 1.0f, SpriteEffects.None, 0f);
spriteBatch.End();
}
}

If you're trying to get your bullet to rotate about your tank, than I personally draw the bullet on top of the tank do the exact same thing that you do after you've fired your bullet(but with a greater magnitude) to displace it,
But if you want to use the origin parameter of SpriteBatch.Draw, than I'd imagine that it would look something like this:
given the following datapoints:
this.origin = new Vector2(texture.Width / 2, texture.Height / 2);
tank.origin = new Vector2(texture.Width / 2, texture.Height / 2);
// and this is what you'd pass into your sprite-batch.draw method
originToDraw = (tank.position + tank.origin)-(this.position + this.origin)
And you also have to initialize your bullet's position to the appropriate starting point Since I don't actually know where rotation comes from, I can't know for sure, but if it's the angle between your tank and the mouse, than I'd imagine it'd be the following
this.startingPosition = tank.position + tank.origin - this.origin

I asume that shell is a Bullet instance if yes your problem is the origin in Bullet class. It should have set this value in LoadTextures method
public void LoadTextures(Texture2D texture)
{
this.texture = texture;
this.origin = new Vector2(texture.Width, texture.Height);
}
And a little extra in Bullet.Draw method:
spriteBatch.Draw(texture, location, null, Color.White, rotation - 1.5f, origin, 1.0f, SpriteEffects.None, 0f);
change 1.5f to MathHelper.PiOver2 it is more accure when you want to rotate something 90 degrees

You have a nasty roundoff problem here.
You compute the velocity in floating point but switch to integers for the bullet's location. The problem is that while ON AVERAGE the errors even out any given bullet is going to either round up or round down every time.
Lets take an extreme case: The bullet is fired 25 degrees off the vertical axis and it's moving at two pixels per update cycle. Strangely enough the bullet flies directly down the axis.
Or an even more extreme case. The speed is 1/3 pixel per cycle. The bullet stands still.

Related

Need help on monogame screen resolution and intersection

Currently in my game i want trying to move my object towards both x axis and y axis.As I also wanted to put it into center ,I have put a camera.Here is my Camera code-
public class Camera
{
public Matrix transform;
public Viewport view;
public Vector2 origin;
Vector2 baseScreenSize = new Vector2(1136, 720);
float horScaling ;
float verScaling ;
Vector3 screenScalingFactor ;
public Camera(Viewport newView)
{
view = newView;
horScaling = view.Width / baseScreenSize.X;
verScaling = view.Height / baseScreenSize.Y;
screenScalingFactor = new Vector3(horScaling, verScaling, 1);
}
public void update(GameTime gt, ball pl)
{
origin = new Vector2(pl.Position.X + (pl.ballRectangle.Width / 2) - 400, 0);
transform = Matrix.CreateScale(1,1,0) *
Matrix.CreateTranslation(new Vector3(-origin.X, -origin.Y, 0));
}
}
and in Game1.cs file as usual in begin statement i am putting this-
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, null, null, cm.transform*globalTransformation);
ba.Draw(spriteBatch, Color.White);
spriteBatch.End();
Here ba is the object of ball,its just have moving x and y functionalities.
In a separate begin,end statement ,I am drawing rest all of the objects-
spriteBatch.Begin(SpriteSortMode.Immediate, null, null, null, null, null, globalTransformation);
spriteBatch.Draw(mainMenu, new Vector2(0, 0), Color.White);
spriteBatch.Draw(mainMenu1, new Vector2(450, 100), Color.White);
spriteBatch.End();
Here Have applied globaltransformation to acheive independent screen resolution(similar codes like in Camera.cs).
Rest of the objects are working as expected,But intersections of camera object and rest of the objects is not working as expected.
I guess this is due to resolution independency is not applied to Camera object(I am not sure).I have tried lot of codes after searching internet,but none of them is working as expected.
In a simple words-I want to clone this game-
https://play.google.com/store/apps/details?id=com.BitDimensions.BlockyJump
If you see main player is moving along x and y axis,but due to camera its in constant position,but the obstacles are not in camera,How to acheive the intersection between obejct which is in camera draw and objects which are not in camera in this case
Request all to help,I am stuck here from long time...
Never thought this will be this much of easy...Searched all over internet,in
most of the codes they were saying we need to inverse the camera transform.
But this is not the case.As from beginning I was saying my problem is intersection between camera object and non camera object,here is the answer-
First of all we need to find the positions of camera object to form a world space rectangle
Vector2 hj = Vector2.Transform(ba.Position, cm.transform);
Rectangle leftRectangleT1 =
new Rectangle((int)hj.X, (int)hj.Y, ba.tex.Width, ba.tex.Height);
Here ba is the camera object,we need to transform it to camera transform like above codes.
To get transform of ba in case pixel intersection,here is the codes-
Matrix ballTransform = Matrix.CreateTranslation(new Vector3(hj.X, hj.Y, 0.0f));
Thats it you have ball rectangle which is camera object to intersect with real world objects(non camera objects)
I don't understand your question per say, but from what I gathered, you want the camera to follow the target's position, and you also want independent screen resolutions?
Well, for the independent screen resolution, simply create a screen resolution handler that renders the scene to a RenderTarget2D as defined by your sizes. Then draw that to the screen.
For the camera movement. Try adjusting the camera's position to follow the target's position with an offset and slerp interpolation to prevent stuttering and smooth action.
void Update(float gameTime) {
Vector3 camTransform = Camera.Position + cameraTarget;
Vector3 newCameraPosition = Vector3.Slerp(cameraPosition, camTransform, 0.2f);
Camera.Position = newCameraPosition;
}
For your intersection problem try something along this
private bool intersects(rectangle1, rectangle2) {
return rectangle1.x >= rectangle2.x &&
rectangle1.y >= rectangle2.y &&
rectangle1.y <= rectangle2.y + rectangle2.h &&
rectangle1.x <= rectangle2.x + rectangle2.w;
}
private void checkIntersections(gameObjects[]) {
foreach (var obj in gameobjects) {
if (intersects(obj.rectangle, camera.rectangle){
handleIntersections(camera, obj);
}
}
}

GUIText is behind GUITexture

First off I have looked around and I can see many posts about this and they all point towards the Z position of the text, however I have changed this to minus and positive and my text is always drawn behind my GUITexture.
So this is what I have setup
My GUI has 4 text boxes
Score
Lives
Level
Time
Now I have an object called GameManager which uses this code below to draw my two GUI sprites
void OnGUI()
{
float screenHeight = Screen.height / 12f * 1.5f;
GUI.DrawTexture (new Rect (0, 0, Screen.width * 2, screenHeight), textureBand);
GUI.DrawTexture (new Rect (0, Screen.height - screenHeight, Screen.width * 2, screenHeight), textureBand);
}
However what ever I do my text is always drawn below my GUITexture so I can never see my text, could I get a little help with this one.
If you're drawing into the same location, you need to specify the depth of each draw to make sure they're sorted correctly. Take a look at the unity docs here:
http://docs.unity3d.com/ScriptReference/GUI-depth.html
Set a higher depth value for the textures you want drawn further back (behind the text) like so:
GUI.depth = 1;

Why does my game interpret the mouse pointers coordinates wrong

I have an monogame (2D) game I'm making and when I try to get the mouse coordinates they are wrong. I have no idea what the issue is but here is my code where I get the coordinates:
MouseState mouseState;
mouseState = Mouse.GetState();
test = new Tower(TowerTexture, new Vector2(mouseState.X, mouseState.Y));
//test is drawn where mouse pointer is thought to be and it is drawn off
Here is the tower drawing code:
foreach (Tower tower in towers)
{
tower.Draw(spriteBatch);
}
And here is the draw function for the tower:
public virtual void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, center, null, Color.White, rotation,
origin, 1.0f, SpriteEffects.None, 0);
}
One more thing is that as the mouse pointer, the real one is closer, to the upper left corner the offset of the supposed mouse coordinates is less but as you go closer and closer to the lower right corner of the screen the supposed mouse coordinates are farther off.
I honestly have no idea what's wrong but any thoughts on what might be wrong would be appreciated. Thank you!
This is in response to both this question and your question on hold. To fix this problem, you can scale down your image when you draw it. I'm not quite sure what the value of center is, but my guess is that it is a rectangle with its center at the mouse pointer. To scale down the image, try something like this:
Rectangle center;
public Tower(Texture2D TowerTexture, Vector2 location)
{
float scaledown = 10;
float XOffset = TowerTexture.Width / (2 * scaledown); //get an X and Y offset to center the image in the rectangle
float YOffset = TowerTexture.Height / (2 * scaledown);
this.center = new Rectangle(location.X + XOffset, location.Y + YOffset,
XOffset * 2, YOffset * 2);
}
Then Draw this image like you did previously, using center as the destination rectangle. I wrote this code without a compiler or debugging, but I think it should give you a basic idea.
HTH
What is wrong is that the resolution of my image is bigger than the resolution of my screen.

How to calculate cursor delta like in FPS games?

I'm making an XNA game and I'd like the cursor to stop when the mouse button is held down. Right now by setting the cursor position every 1/60 of a second to a certain location makes the cursor look laggy and sometimes if the cursor moves fast enough to reach a screen border, from that moment and until the next position reset the delta position is not calculated correctly. Also, starting at the edge of the screen and moving towards that same edge won't get any correct deltas.
How do I get the correct cursor deltas and not get bummed by cursor stopping at screen edges?
If the position you are locking the mouse to is too close to the edge, you are out of luck.
I suggest you hide the cursor at the beginning of the drag motion, save the location and secretly move the cursor to the center of the screen. When dragging ends just restore the cursor to its previous location.
Easily, supposing I understood what you meant.
In order to move a 1st person camera according to the mouse, we need to calculate the delta each frame, and then move the mouse back to the center of the screen.
To do so we will store the location of the center of the screen. We also need a MouseState variable and a yaw and a pitch floats to store our current camera rotations. I also like to set the rotation speed according the game's resolution:
MouseState currentMouseState;
Vector2 screenCenter;
float YrotationSpeed;
float XrotatiobSpeed;
float yaw = 0;
float pitch = 0;
...
protected override void LoadContent()
{
YrotationSpeed = (float)graphics.PreferredBackBufferWidth / 10000.0f;
XrotatiobSpeed = (float)graphics.PreferredBackBufferHeight / 12000.0f;
screenCenter = new Vector2(graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height) / 2;
}
Now, to calculate how much did the mouse move in the last frame, we will use this function:
private void HandleMouse(GameTime gameTime)
{
currentMouseState = Mouse.GetState();
float amount = (float)gameTime.ElapsedGameTime.TotalMilliseconds / 1000.0f;
if (currentMouseState.X != screenCenter.X)
{
yaw -= YrotationSpeed * (currentMouseState.X - screenCenter.X) * amount;
}
if (currentMouseState.Y != screenCenter.Y)
{
pitch -= XrotatiobSpeed * (currentMouseState.Y - screenCenter.Y) * amount;
if (pitch > MathHelper.ToRadians(90))
pitch = MathHelper.ToRadians(90);
if (pitch < MathHelper.ToRadians(-50)) //Preventing the user from looking all the way down (and seeing the character doesn't have any legs..)
pitch = MathHelper.ToRadians(-50);
}
Mouse.SetPosition((int)screenCenter.X, (int)screenCenter.Y);
}
Finally:
To update the camera and view Matrix, you could use the following function, that should be executed after we update our yaw and pitch:
public void UpdateCamera(float yaw, float pitch, Vector3 position)
{
Matrix cameraRotation = Matrix.CreateRotationX(pitch) * Matrix.CreateRotationY(yaw);
Vector3 cameraOriginalTarget = new Vector3(0, 0, -1);
Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, cameraRotation);
Vector3 cameraFinalTarget = position + cameraRotatedTarget;
Vector3 cameraOriginalUpVector = new Vector3(0, 1, 0);
Vector3 cameraRotatedUpVector = Vector3.Transform(cameraOriginalUpVector, cameraRotation);
view = Matrix.CreateLookAt(position, cameraFinalTarget, cameraRotatedUpVector);
}
EDIT: Well, as I re-read the question I had realized my answer isn't quite what you were asking for. Nevertheless, it does show how to calculate the mouse delta without it getting to the borders of the screen.
To match my answer to your question, all you need are tiny adjustments.
By the way, unless you are willing to draw an image of a mouse in the middle of the screen, any methood WILL look kinda laggy.
Therefore, I highly advice you to hide the cursor.
To do so, just add this line:
this.IsMouseVisible = false;

Having the Background or Camera "Scroll" based on charcter position

I'm working on an RPG game that has a Top-Down view. I want to load a picture into the background which is what the character is walking on, but so far I haven't figured out how to correctly have the background redraw so that it's "scrolling". Most of the examples I find are auto scrolling.
I want the camera to remained centered at the character until you the background image reaches its boundaries, then the character will move without the image re-drawing in another position.
Your question is a bit unclear, but I think I get the gist of it. Let's look at your requirements.
You have an overhead camera that's looking directly down onto a two-dimensional plane. We can represent this as a simple {x, y} coordinate pair, corresponding to the point on the plane at which the camera is looking.
The camera can track the movement of some object, probably the player, but more generally anything within the game world.
The camera must remain within the finite bounds of the game world.
Which is simple enough to implement. In broad terms, somewhere inside your Update() method you need to carry out steps to fulfill each of those requirements:
if (cameraTarget != null)
{
camera.Position = cameraTarget.Position;
ClampCameraToWorldBounds();
}
In other words: if we have a target object, lock our position to its position; but make sure that we don't go out of bounds.
ClampCameraToBounds() is also simple to implement. Assuming that you have some object, world, which contains a Bounds property that represents the world's extent in pixels:
private void ClampCameraToWorldBounds()
{
var screenWidth = graphicsDevice.PresentationParameters.BackBufferWidth;
var screenHeight = graphicsDevice.PresentationParameters.BackBufferHeight;
var minimumX = (screenWidth / 2);
var minimumY = (screnHeight / 2);
var maximumX = world.Bounds.Width - (screenWidth / 2);
var maximumY = world.Bounds.Height - (screenHeight / 2);
var maximumPos = new Vector2(maximumX, maximumY);
camera.Position = Vector2.Clamp(camera.Position, minimumPos, maximumPos);
}
This makes sure that the camera is never closer than half of a screen to the edge of the world. Why half a screen? Because we've defined the camera's {x, y} as the point that the camera is looking at, which means that it should always be centered on the screen.
This should give you a camera with the behavior that you specified in your question. From here, it's just a matter of implementing your terrain renderer such that your background is drawn relative to the {x, y} coordinate specified by the camera object.
Given an object's position in game-world coordinates, we can translate that position into camera space:
var worldPosition = new Vector2(x, y);
var cameraSpace = camera.Position - world.Postion;
And then from camera space into screen space:
var screenSpaceX = (screenWidth / 2) - cameraSpace.X;
var screenSpaceY = (screenHeight / 2) - cameraSpace.Y;
You can then use an object's screen space coordinates to render it.
Your can represent the position in a simple Vector2 and move it towards any entity.
public Vector2 cameraPosition;
When you load your level, you will need to set the camera position to your player (Or the object it should be at)
You will need a matrix and some other stuff, As seen in the code below. It is explained in the comments. Doing it this way will prevent you from having to add cameraPosition to everything you draw.
//This will move our camera
ScrollCamera(spriteBatch.GraphicsDevice.Viewport);
//We now must get the center of the screen
Vector2 Origin = new Vector2(spriteBatch.GraphicsDevice.Viewport.Width / 2.0f, spriteBatch.GraphicsDevice.Viewport.Height / 2.0f);
//Now the matrix, It will hold the position, and Rotation/Zoom for advanced features
Matrix cameraTransform = Matrix.CreateTranslation(new Vector3(-cameraPosition, 0.0f)) *
Matrix.CreateTranslation(new Vector3(-Origin, 0.0f)) *
Matrix.CreateRotationZ(rot) * //Add Rotation
Matrix.CreateScale(zoom, zoom, 1) * //Add Zoom
Matrix.CreateTranslation(new Vector3(Origin, 0.0f)); //Add Origin
//Now we can start to draw with our camera, using the Matrix overload
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default,
RasterizerState.CullCounterClockwise, null, cameraTransform);
DrawTiles(spriteBatch); //Or whatever method you have for drawing tiles
spriteBatch.End(); //End the camera spritebatch
// After this you can make another spritebatch without a camera to draw UI and things that will not move
I added the zoom and rotation if you want to add anything fancy, Just replace the variables.
That should get you started on it.
However, You will want to make sure the camera is in bounds, and make it follow.
Ill show you how to add smooth scrolling, However if you want simple scrolling see this sample.
private void ScrollCamera(Viewport viewport)
{
//Add to the camera positon, So we can see the origin
cameraPosition.X = cameraPosition.X + (viewport.Width / 2);
cameraPosition.Y = cameraPosition.Y + (viewport.Height / 2);
//Smoothly move the camera towards the player
cameraPosition.X = MathHelper.Lerp(cameraPosition.X , Player.Position.X, 0.1f);
cameraPosition.Y = MathHelper.Lerp(cameraPosition.Y, Player.Position.Y, 0.1f);
//Undo the origin because it will be calculated with the Matrix (I know this isnt the best way but its what I had real quick)
cameraPosition.X = cameraPosition.X -( viewport.Width / 2);
cameraPosition.Y = cameraPosition.Y - (viewport.Height / 2);
//Shake the camera, Use the mouse to scroll or anything like that, add it here (Ex, Earthquakes)
//Round it, So it dosent try to draw in between 2 pixels
cameraPosition.Y= (float)Math.Round(cameraPosition.Y);
cameraPosition.X = (float)Math.Round(cameraPosition.X);
//Clamp it off, So it stops scrolling near the edges
cameraPosition.X = MathHelper.Clamp(cameraPosition.X, 1f, Width * Tile.Width);
cameraPosition.Y = MathHelper.Clamp(cameraPosition.Y, 1f, Height * Tile.Height);
}
Hope this helps!

Categories