XNA: How can I draw only a "pizza slice" of my sprite? - c#

I am currently building a game about infrastructure building and management in XNA(C#).
What I am currently trying to achieve is to make the game draw 'bends' between train tracks. I want to do this by drawing only a certain part of a circle texture.
In other words, I only want to draw a "pizza slice" of this texture. The slice of the circle that needs to be drawn is based on three points:
The center of the sprite;
A variable position 'a';
A variable position 'b';
These three points together determine how much of my circle is drawn on the screen e.g. how big the pizza slice is.
To put it simply: If I have a circle and cut it from the centre to a point 'a' and then again from the centre to a point 'b', how can I only draw the part I've just cut out?
This slice has to be altered in real-time, so the slice becomes bigger and smaller based on those two positions 'a' and 'b'.
What is the best way to achieve this effect?

This can be done entirely in the shader with relatively simple trig. In your pixel shader (effect) try something like:
float dX = b.x - a.x;
float dY = b.y - a.y;
float theta = Math.Atan2(dY, dX);
Note that theta will be in radians. Then just check if theta is within your limits. Say, between 0 and pi/2. If it is, then sample the texture, if not then return a float4 with no alpha (transparent). That should give you the top right quarter of your texture with the rest masked out. If you want to convert theta to degrees you can do that too, but I recommend staying with radians as it makes your math so much easier.
You'll have to set your limits with
effect.Parameters['thetamin']=/*minTheta*/;
effect.Parameters['thetamax']=/*maxTheta*/;
Before you call EffectPass.Apply().

Related

How to rotate a Vector3 of dimensions by a Vector3 of angles?

I have a Vector 3 of how many blocks in a grid a piece is along each axis. For example if one of these vectors was ( 1, 2, 1 ) it would be 1 block long on the x-axis, 2 blocks long on the y-axis, and one block long on the z-axis. I also have a Vector 3 of angles that denote rotations along each axis. For example if one of these vectors was ( 90, 180, 0 ) the piece would be rotated by 90 degrees around the x-axis, 180 degrees around the y-axis, and 0 degrees around the z-axis. What I can't figure out is how to rotate the dimensions of a piece by its vector of rotation angles so i know what points in space its occupying.
public class Block
{
private Vector3 localOrientation;
private Vector3 dimensions;
public Vector3 GetRotatedDimensions()
{
//your implementation here
}
}
If I understand correctly, there is something fundamentally wrong with your question. There can be no "rotated dimensions". Let's use a rectangle to demonstrate this. (I didn't undestand correctly)
Suppose there's this initial rectangle:
and you rotate it. This is what you get:
Using a single Vector2, you can't differentiate a "rotated x*y rectangle" from a "initial (x')*(y') rectangle". To sufficiently describe the position of a rectangle, you need to keep the size AND the rotation in your block-describing variable.
Is x' and y' what you wanted to know? I doubt it. Oh, you do? Great!
In 3 dimensions, I would define what you're looking for as
The minimum dimensions of a rectangular box that
1. has its faces parallel to the XY, XZ and YZ planes and
2. contains another rectangular box of known dimensions and orientation.
There are possibly more elegant solutions, but I'd brute force it like this:
Make 8 Vector3 objects (one for each vertex of your block),
Rotate all of them around the x-axis.
Rotate them (the new ones you got from "2") around the y-axis.
Rotate them (the new ones you got from "3") around the z-axis.
Find the min and max values of the x, y and z coordinates among all your points.
Your new dimensions would be (x_max-x_min), (y_max-y_min), (z_max-z_min).
I'm not 100% sure about this though, so make sure you verify the results!

Scale Sprite up and Down to give illusion of a jump

I have some code that I wrote that works, but I feel it could be better and wanted to get some feedback.
The goal I had is to have a Sprite Scale up and back down in a timely fashion when a button is pushed so that it gives the illusion of jumping in a "Top Down" view of the game. Like the character is jumping off the screen. I already know how to draw scaled images I'm more interested in the logic of the timing aspect.
This works, just not sure it's the best. Thought maybe there was some equation, a math friend told me maybe a linear equation or like a parabola or second order equation. Not being great with math.
Anyway.
Class Properties
private double _jumpingStartedAt;
private double _totalJumpTimeInSeconds = 0.7;
private double _totalJumpFrames = 14;
private double _timeSinceLastScale;
private double _jumpingHalfWayAt;
When button is pushed for the first time I start the "Jump Logic". This runs once per jump. My thought was that I'd mark the "start" time and determine the "halfway" time by the totalJumpTimeInSeconds.
_jumpingStartedAt = gameTime.TotalGameTime.TotalSeconds;
_jumpingHalfWayAt = _jumpingStartedAt + MillisecondsBetweenFrame() * (_totalJumpFrames / 2);
And then this is run on each Update() until my "jump" is complete or isJumping = false. The logic here is that I would scale up every 1 "frame" until half way point then scale back down.
_timeSinceLastScale += gameTime.ElapsedGameTime.TotalSeconds;
if (_timeSinceLastScale > MillisecondsBetweenFrame() && gameTime.TotalGameTime.TotalSeconds < _jumpingHalfWayAt)
{
Scale += 0.2f;
_timeSinceLastScale = 0;
}
else if (gameTime.TotalGameTime.TotalSeconds > _jumpingHalfWayAt)
{
Scale -= 0.2f;
if (Scale < 1.0) Scale = 1; //probably don't need this was worried if it went passed 0
if (Scale == 1.0) _isJumping = false;
}
private double SecondsBetweenFrame()
{
return _totalJumpTimeInSeconds / this._totalJumpFrames;
}
Now this works, but seems a little convoluted to me.
Stretching image when jumping - side view
Yeah, it's pretty complicated, what you created.
I assume your sprite is also moving up and down when jumping. That you have some sort of Vector2 velocity, which you change by dv = gravityAcceleration * dt in every update, and so you change Vector2 position by dp = velocity * dt. If so, I would rather use my velocity.Y value to calculate how the sprite should stretch. I think it's more natural. And your code will become much more simple.
Here's an image to describe better what I mean:
However, you can probably face the other problem here: just at the beginning of the jump your sprite will suddenly get high velocity, when still being near the ground, which can cause it to cross through the floor for a moment. To prevent that you can artificially move your sprite upwards by the smallest needed value for the time of jump. The problem is described by the image below:
As you can very well see, the first stretched ball moved upwards a little bit, but not enough. You have to calculate difference between sizes before and after stretching and then move your sprite up by that distance.
If you do it like that, your Update should shorten to just a few lines. I believe you can do simple calculations on your own.
Easier approach
...Unless you'd rather like your sprite behave like you want. Then you could modify scale according to your Y position:
if (KeyboardState.IsKeyDown(Keys.Space))
{
isJumping = true;
jumpStartPosition = Position;
}
if (!isJumping) Scale = 1f;
else
{
Scale = StretchFactor * (Position.Y - jumpStartPosition.Y);
}
where:
- isJumping is a bool,
- jumpStartPosition is a Vector2,
- Position is a Vector2 property of your sprite,
- StretchFactor is a float property of your sprite telling how much does it stretch.
And you also need to have end-of-jump condition - for example when the sprite's Position.Y becomes smaller than the jumpStartPosition.Y. But generally this solution (as well as yours) has one disadvantage - there will be problems, if you will want to start jump from one height, and end it on another:
so I would rather recommend my first solution. There you can make stop-jump condition by collision check.
Stretching image when jumping - top-down view
Bummer. Since originally it wasn't specified that it is a top-down game, like those first GTA's, I really misunderstood the question, so the answer doesn't fit much. So the answer goes now.
If you wan't it to be realistic, you should use some basic principles of perspective. As we look at the character jumping from the top, it goes closer to us, so it's image grows. Why's that? Look at the pic below.
There are two things, that are needed for perspective to work: the center of perspective and the screen. The center of perspective is the point, where all "rays" are crossing. "Ray" is a line from the any point in the world to the center of our eye. Now the screen is the plane, where image of 3d world is being created. The points of the real world are being cast into screen along their rays. Of course your game is pseudo-3d, but it shouldn't matter in that case.
When z grows, sprite comes closer to the center of perspective. If you imagine ray from the center of perspective to the edge of the sprite, the angle of ray changes, as it's distance to the center of perspective becomes lesser. And the change of angle makes the point's image on the screen moving. That's why image grows, or becomes smaller.
Now we can wonder: ok, how now put this into numbers? Look at the picture below:
I deliberately translated whole world by -C so the z coord of the center of perspective could become 0. That makes calculations simplier. What are we trying to find, is the x' - coord of the point on the screen. Let the Z* = |z - C|. If we look at this picture it becomes clear, that we can find what we need by pretty simple proportion:
Using the same method you can calculate y'. If your character is always at the center of the screen, all that you need will be x'/x = y'/y = S, i.e. your scale. That's because x in this scenario is, in fact, the half-width of the sprite, and y is the half-height. However, if your character will be able to move freely around the screen, you may want to scale & translate it, so it would be more natural:
The white square is the on-the-ground sprite, the gray square is the jumping sprite. In this case you will have to know l (left), r (right), t (top) and b (bottom) coords of the sprite's boundaries (top-bottom means Y-axis, not Z-axis). Then using the same proportion you can get l', r', t' and b' - boundaries of the sprite's image on screen. From this data you should be able to calculate both scale and translation.
Note: L is the parameter of our calculation which you have to choose yourself. Assuming, that the screen has constant width Ws and height Hs, L strictly corresponds with FOV (field of view). You can acquire it also using proportions. So L = (cos(FOV/2) * Ws)/2. I would recommend FOV = 60 deg. If you will make FOV too big, you may face the fisheye problem.

Get the bounds of the plane visible at a specific z coordinate

Using OpenTK, I've created a window (800x600) with a vertical FOV of 90°.
I want to make a 2D game with a background image that fits on the whole screen.
What I want is the plane at a variable z coordinate as a RectangleF.
Currently my code is:
var y = (float)(Math.Tan(Math.PI / 4) * z);
return new RectangleF(aspectRatio * -y, -y, 2 * aspectRatio * y, 2 * y);
The rectangle calculated by this is always a little to small, this effect seems to decrease with z increasing.
Hoping someone will find my mistake.
I want to make a 2D game with a background image that fits on the whole screen.
Then don't bother with perspective calculations. Just switch to an orthographic projection for drawing the background, disabling depth writes. Then switch to a perspective projection for the rest.
OpenGL is not a scene graph, it's a statefull drawing API. Make use of that fact.
To make a 2D game using OpenGL, you should use an orthographic projection, like this tutorial shows.
Then its simple to fill the screen with whatever image you want because you aren't dealing with perspective.
However, IF you were to insist on doing things the way you say, then you'd have to gluProject the 4 corners of your screen using the current modelview matrix and then draw a quad in 3D space with those corners. Even with this method, it is likely that the quad might not cover the entire screen sometimes due to floating point errors.

C#/HLSL & XNA - Blending 2 colors together via percentage in HLSL

I'm creating a fog feature in my Effect file.. in the pixel shader, I calculate the distance from the camera position and the input's position, as so:
float x = distance(_in.pos3d, CameraPosition);
float fd;
if(Fog)
{
if(x > FogDistance)
fd = ((x-FogDistance) * FogIntensity > 100) ? 100 : ((x-FogDistance) * FogIntensity);
//_in.color = ???;
}
Where:
x is the distance from the camera position and vertex position,
fd is the percentage of fog color,
FogDistance is the distance where objects won't be affected by fog, and
FogIntensity is how intense the fog is.
What I'm trying to get is a color that contains (fd %) of the fog color. For example, if the fog color was orange, the input was white, and fd was 25%, the color generated would be white + 25% orange.
EDIT: By the way, sorry for the unmaintainable setting code.
EDIT 2: I noticed that having two transparent layers have a transparent outcome, so I cleaned up the question a bit. There's no percentage for the vertex input.
You want the lerp function (MSDN). That is the "linear interpolation" function.
Colours in pixel shaders are essentially the same thing as vectors, so you can use any vector functions on them.
Rather than a percentage (in the range 0 to 100), the lerp function takes a value between 0 and 1.
So your code will probably look something like the following:
_in.color = lerp(_in.color, someOtherColor, fogAmount);

Calculating the bounding points for the area of a "Pie Segment" and "sub areas"

Background:
I was recently playing around with GDI+ to draw a "Disc" displaying a sweeping color change through 360 degrees. (I dug up some HSL to RGB code to loop through HSL(1,1,1) -> HSL(360,1,1))
Regarding the disc, I first drew a full solid circle using the above, and then a second circle in Grey over the center to give the following
So this is all fine... but I realised that GDI+ is insulating us from a lot of the tricky match that's going on here by way of the FillPie method. Also, FillPie requires you to supply a bounding rectangle for the pie as opposed to a Radius Length. It also does a full segment fill and doesnt allow you to specify a part of that segment only.
Question:
Can anyone point me in the direction of some Math functions or give any explanation on what forumla I would need to calculate the area & plot points of the following "Green Filled Area" given:
Point `c` - an x,y co-ordinate
Angle `A` - an angle from horizontal
Angle `B - an angle from horizontal where `B` - `A` == the sweep angle
Length `r` - a distance from `c`
Length `r2` - a distance from `c` where `r2` - `r` == the `height` of the segment to be filled.
Links to Math sources are fine but I've had a quick google & look at Wolfram Math and could find what I was looking for. Also, if there was some way to generate a sequence of bounding (x,y) co-or's that could be passed as a Point[] to Graphics.FillPolygon, that'd be cool too.
The area is the difference of the outer and inner disc parts. The area of a disc part is proportional to the angle sweep:
area = (b-a)*((r+r2)^2-r^2)/2
a and b must be expressed in radians.
For b-a = 2*Pi, area = Pi*(r+r2)^2 - Pi*r^2 is the difference of the areas of the outer and inner discs.
You can generate points on the inner / outer circle using
x = cx + r * cos(t) / x = cx + (r+r2) * cos(t)
y = cy + r * sin(t) / y = cy + (r+r2) * sin(t)
Where t varies from a to b.
Hope this helps. The second part provides a method for calculating the area of a sector of a circle
http://www.wikihow.com/Calculate-the-Area-of-a-Circle
The area of a segment of a circle is simply the angle of the arc (in radians) times the radius. So the area of the green circle is obviously:
(B-A) * r2
You need to draw lines (this pseudo code):
for aa from A to B
set color to required color // you could use aa in an equation with HSL to get something like your sample
x1=r*cos(aa)+x
y1=r*sin(aa)+y
x2=r1*cos(aa)+x
y2=r1*sin(aa)+y
draw line between (x1,y1) and (x2,y2)
for a small-enough increment in the angles, and small-enough radii, this should be OK.
The points you're looking for are (x1,y1) and (x2,y2) for each angle aa

Categories

Resources