Wobbling texture using source rectangle - c#

I'm having a little trouble with a texture2d I'm trying to draw in XNA. Basically, I have a power-up "cooldown fill-effect" going on. I have a texture that I'm trying to draw partially as the cooldown decreases. So, for example, at 10% cooldown done I'm drawing only 10% cooldown of of the texture (the bottom), 20% done only 20% of the bottom of the texture, and so on.
The problem I'm having is, when drawing the texture, it keeps wobbling as it fills up.
Note that below, ActiveSkillTexture is my preloaded fill texture. It's size is the size of the fully filled graphic.
InterfaceDrawer.Draw is a method that calls SpriteBatch.Draw, but does some extra stuff beforehand. For all intents and purposes, it's the same as SpriteBatch.Draw.
Scale is my scale factor, it's just a float between 0 and 1.
MyDest is a pre-calculated position for where this texture should draw (from the top-left, as usual).
Here's a snippet of code:
Rectangle NewBounds = ActiveSkillTexture.Bounds;
float cooldown = GetCooldown(ActiveSkillId);
if (cooldown > 0) //cooldown timer
{
//Code that calculated cooldown percent which I'm leaving out
if (percentdone != 1) //the percentage the cooldown is done
{
//code for fill-from bottom --
float SubHeight = ActiveSkillTexture.Height * percentremaining;
float NewHeight = ActiveSkillTexture.Height * percentdone;
NewBounds.Y += (int) SubHeight;
NewBounds.Height = (int) NewHeight;
MyDest.Y += SubHeight * Scale;
}
}
if (ActiveSkillTexture != null)
InterfaceDrawer.Draw(SpriteBatch, ActiveSkillTexture, MyDest, NewBounds, Color, 0.0f, Vector2.Zero, Scale, SpriteEffects.None, 0.0f);
I know you can't see it, but it's basically wobbling up and done as it fills. I tried printing out the values for the destination, the newbounds rectangle, etc. and they all seemed to consistently increase and not "sway", so I'm not sure what's going on. Interestingly enough, if I fill it from the top, it doesn't happen. But that's probably because I don't have to do math to alter the destination position each time I draw it (because it should draw from the top-left corner each time).
Any help would be greatly appreciated. Thanks!

I think this would be easier if you set the Vector2.Origin parameter of your spriteBatch.Draw as the bottom-left of your texture.
In this way you simply increase your sourceRectangle.Height, with something like this:
sourceRectangle.Height = ActiveSkillTexture.Height * percentdone;
without doing that useless math to find the destination position.

Related

How to make a simple progress bar

var barDisplay : float = 0;
var pos : Vector2 = new Vector2(20,40);
var size : Vector2 = new Vector2(60,20);
var progressBarEmpty : Texture2D;
var progressBarFull : Texture2D;
function OnGUI()
{
// draw the background:
GUI.BeginGroup (new Rect (pos.x, pos.y, size.x, size.y));
GUI.Box (Rect (0,0, size.x, size.y),progressBarEmpty);
// draw the filled-in part:
GUI.BeginGroup (new Rect (0, 0, size.x * barDisplay, size.y));
GUI.Box (Rect (0,0, size.x, size.y),progressBarFull);
GUI.EndGroup ();
GUI.EndGroup ();
}
function Update()
{
// for this example, the bar display is linked to the current time,
// however you would set this value based on your desired display
// eg, the loading progress, the player's health, or whatever.
barDisplay = Time.time * 0.05;
}
How do I make a geometry dash type progress bar in unity using OnGUI? I tried looking it up online, couldn't find it really. I am building a runner game something like Temple run and I want to show the player how much of the map is left to go.
For a progress bar
You can use the Unity scrollbar object to make what you're looking for. There's a good tutorial on it here. Essentially, you add a scrollbar object to your canvas, and then change the slider value from code.
For scrolling textures
If you want a scrolling texture on your progress bar, then you can animate an image placed on the slider. If you don't want to animate it by hand, then it's a little more complicated. Ideally you could set the texture offset of the image in code to get it to scroll, but after looking it up I don't think that Unity allows you to do that on non-3D objects.
If you still want it to scroll and don't want to make a hand-drawn animation for it, you might want to look into combining the UI mask component (tutorial here), and the built-in 2D animation tools (tutorial here).

Monogame - how to automatically move rectangle up and down and repeat?

So I'm working on my menu's background and I Draw() a texture there with a rectangle. How would I have the rectangle wait, move up and then down, wait and repeat? I tried the following:
// Update()
if (Rectangle.Y = -16) // My texture is positioned to -16 initially
Rectangle.Y++;
else if (Rectangle.Y = 0)
Rectangle.Y--;
So my game resolution is 1366x768. To have the background texture move up and down I had to make it have a height > 768. I made it 1366x800. Every time the above code is called it should wait 1-2seconds (not yet implemented), move 16 pixels down, wait again and go back 16 pixels up... But that code doesn't work... Could you guide me as to how this is done?
You can do it with Math.Sin, which will give you a smooth transition from -1 to 1. You will have to keep a copy of your rectangle's center Y position.
double time = gameTime.TotalGameTime.TotalSeconds;
Rectangle.Y = centerY + (int)(Math.Sin(time * transitionSpeed) * maxOffset);
You can play with double transitionSpeed to get the best visual effect. int maxOffset is the max amount of offset from centerY.
If you don't want smooth movements, then just do
int speed = 1; // speed of movement
Then in update
if (Rectangle.Y <= -16 || Rectangle.Y >= 0)
speed *= -1; // reverse move direction
Rectangle.Y += speed;

Drawing a clock timer with a fill

I'm trying to make a timer that mimics a clock, with a ticking hand. I have no problem drawing a clock texture and then a line for the hand, but I also want the space behind the clock hand to have a fill. So as time goes on, I want the clock to "fill up" starting at the origin (0:00) all the way up to the clock hand.
I basically want to do this:
What's the best way for me to do this? I have the foundation, just don't know how to add the fill part.
You should aproximate it building a triangle fan.
int n=0;
VertexPostionColor[] V = new VertexPositionColor[num_triangles+2]
V[0] = Center;
for (var angle = start ;angle<=end; angle += (end - start) / num_triangles)
{
V[++N].Position = new Vector3( Math.Cos(angle), Math.Sin(angle)) * radius + Center;
V[N].Color = CircleColor;
}
Short[] Index = new Short[num_triangles*3];
for (int i = 0; i< num_triangles; i++)
{
Index[i*3] = 0;
Index[i*3+1] = i+1;
Index[i*3+2] = i+2;
}
GraphicsDevice.DrawUserIndexedPrimitives(...);
If you want to get complicated using a spritebatch, you have to use a small sector texture, and draw it multiple times rotating it about the center.
this is an example, it need to be tuned to be precise.
float SectorAngle = Mathhelper.ToRadians(10);
Texture2D SectorTex;
Vector2 Origin = new Vector2(SectorTex.Width/2, SectorTex.Height);
for (var angle=start; angle<=end; angle+=SectorAngle) {
spriteBatch.Draw(SectorTex, Center, null, Color.White, Origin, angle, scale,...)
}
If you want to do it using textures, you should be able to manage it with two simple textures: a semi-circle (exactly half a circle), and a full circle.
First, draw the full circle white. Then it's just a matter of calculating how much of the circle needs to be filled.
If it's less than half, draw the half circle blue, rotated to match the "minute hand". Then draw another half circle white to cover the left side.
If it's more than half, draw the half circle blue, covering the entire right side. Then draw another half circle blue, rotated to match the "minute hand".
Once the fill is complete, you just need to draw the other clock components; the hands and border.

Position of sprite

Vector2 drawPos = (-screenPosition);
drawPos.X *= (float)device.DisplayMode.Width;
drawPos.Y *= (float)device.DisplayMode.Height;
spriteBatch.Draw(
texture,
drawPos,
getRectangle(),
Color.White,
rotation,
getOrigin(),
1.0f / zoom,
SpriteEffects.None,
0);
I have a drawPos essentialy being 0..1 and multiply that with the display width and height. screenposition is obtained by dragging the screen. With other elements, primitives, the position is correct and is exactly being dragged along with the input. However when drawing a sprite the sprite is moving to quickly, faster than the input, giving a sort of parallax effect, not what I want.
I somehow get the feeling I am using the parameters wrong, and spriteBatch.Draw(..) does not need pixelcoordinates..
Width and height is obtained by texture loader.
public Vector2 getOrigin()
{
return new Vector2(width / 2, height / 2);
}
public Rectangle getRectangle()
{
return new Rectangle(
0,
0,
width,
height);
}
Also, I am developing for Windows Phone.
The getRectangle() method is basically useless, you are specifying a source rectangle which is the same size as the texture - use null instead (unless ofcourse you've just simplified your code for us).
How is screenPosition defined? I don't understand why you'd times it by -1. You are also using the screen that the window is on to get width/height with device.DisplayMode which is something you should avoid because this will only work when your window is the same size as the screen.
Try drawing the sprite to Vector2.Zero without an origin, and with the sourceRectangle set to null. Slowly add back in your other parameters and see where the error is occuring. Can't really say much else without more information!
spriteBatch.Draw(
texture,
Vector2.Zero,
null,
Color.White,
0,
Vector2.Zero,
1,
SpriteEffects.None,
1);
This is what I would use to make sure the sprite is actually displaying properly.

mouse picking a rotating sprite in an Xna game

I am working on a simple game where you click on square sprites before they disappear. I decided to get fancy and make the squares rotate. Now, when I click on the squares, they don't always respond to the click. I think that I need to rotate the click position around the center of the rectangle(square) but I am not sure how to do this. Here is my code for the mouse click:
if ((mouse.LeftButton == ButtonState.Pressed) &&
(currentSquare.Contains(mouse.X , mouse.Y )))
And here is the rotation logic:
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
RotationAngle += elapsed;
float circle = MathHelper.Pi * 2;
RotationAngle = RotationAngle % circle;
I am new to Xna and programming in general, so any help is appreciated.
Thanks a lot,
Bill
So you're trying to determine if a point is in a rectangle, but when the rectangle is rotated?
The Contains() method will only work if the current rotation is 0 (I guess currentSquare is a rectangle representing the image position without rotation?).
What you will have to do is do the opposite rotation of the image on the mouse coordinates (the mouse coordinates should rotate around the origin of your image), then calculate if the new position is within currentSquare. You should be able to do all of this using vectors.
(Untested)
bool MouseWithinRotatedRectangle(Rectangle area, Vector2 tmp_mousePosition, float angleRotation)
{
Vector2 mousePosition = tmp_mousePosition - currentSquare.Origin;
float mouseOriginalAngle = (float)Math.Atan(mousePosition.Y / mousePosition.X);
mousePosition = new Vector2((float)(Math.Cos(-angleRotation + mouseOriginalAngle) * mousePosition.Length()),
(float)(Math.Sin(-angleRotation + mouseOriginalAngle) * , mousePosition.Length()));
return area.Contains(mousePosition);
}
If you dont need pixel pefect detection you can create bounding sphere for each piece like this.
var PieceSphere = new BoundingSphere()
{
Center =new Vector3(new Vector2(Position.X + Width/2, Position.Y + Height/2), 0f),
Radius = Width / 2
};
Then create another bounding sphere around mouse pointer.For position use mouse coordinates and for radius 1f. Because mouse pointer will be moving it will change its coordinates so you have to also update the sphere's center on each update.
Checking for clicks would be realy simple then.
foreach( Piece p in AllPieces )
{
if ((mouse.LeftButton == ButtonState.Pressed) && p.BoundingSphere.Intersects(MouseBoundingSphere))
{
//Do stuff
}
}
If you are lazy like me you could just do a circular distance check.
Assuming mouse and box.center are Vector2
#gets us C^2 according to the pythagorean Theorem
var radius = (box.width / 2).squared() + (box.height / 2).square
#distance check
(mouse - box.center).LengthSquared() < radius
Not perfectly accurate but the user would have a hard time noticing and inaccuracies that leave a hitbox slightly too large are always forgiven. Not to mention the check is incredibly fast just calculate the radius when the square is created.

Categories

Resources