Move a 2D sprite in a curved upward arc in XNA? - c#

Alright, so here's my problem.
I've been trying to create a sort of a visual day/night cycle in XNA, where I have an underlying class that updates and holds time and a Sky class which outputs a background based on the time that the class updates.
What I can't figure out though is how to make the moon/sun move in a curved upward arc that spans the screen based on what time of the day it is. The most problematic part is getting the Y axis to curve while the X axis moves as the time progresses.
Anyone that could help me here?
EDIT:
Alright, looks like Andrew Russels example helped me to do what I needed to do.
Although I had to expermient for a bit, I finally reached a suitable solution:
float Time = (float)Main.inGameTime.Seconds / (InGameTime.MaxGameHours * 60 * 60 / 2);
this.Position.X = Time * (Main.Viewport.X + Texture.Width * 2) - Texture.Width;
this.Position.Y = Main.Viewport.Y - (Main.Viewport.Y * (float)Math.Sin(Time * MathHelper.Pi) / 2) - (Main.Viewport.Y / 2) + 50;

Try looking at the Math.Sin or Math.Cos functions. These are the trigonometric functions you're looking for.
Something like this (giving a position for SpriteBatch):
float width = GraphicsDevice.Viewport.Width;
float height = GraphicsDevice.Viewport.Height;
float time = 0.5f; // assuming 0 to 1 is one day
Vector2 sunPosition = new Vector2(time * width,
height - height * (float)Math.Sin(time * width / MathHelper.TwoPi));
(Disclaimer: I haven't tested this code.)

There is also the Curve class.

Related

How to plot an ellipse with given rotation angle in C# WPF using Oxyplot?

OxyPlot is a cross-platform plotting library for .NET, very convenient for making plots,
Now there's a situation here, I have to draw a 95% confidence ellipse to an XY scatter plot.
Oxyplot provides with following annotation:-
Given here Ellipse Annotation(OxyPlot.Annotations) gives only following properties to add ellipse-
We don't have any rotation property or method here, IRender provides several draw methods to override but none of the methods have double angled rotation argument or so. Neither the documentation has provides any direct solution to it:-
Then how to draw this:-
*I was facing this issue for one of my assignment, and came up with a solution after going through the following forums discussion to get hints on how to generate such an ellipse.
https://github.com/oxyplot/oxyplot/issues/268
https://oxyplot.userecho.com/en/communities/1/topics/598-ellipse-annotation-rotation
Please add more solutions if anyone else has :-
Based on the link shared (in Quest.) best and easiest solution here was to draw an ellipse using PolygonAnnotation, which takes List of co-ordinate points,
Let's say if you give four co-ordinate points A,B,C,D--- polygonAnnotation will give me a closed 4-gon~quadrilateral sort of structure based on kind of points taken.
Now if you increase the number of points from 4 to 6--- it will give you hexagon, and so on.
Now at pixel level you can give infinite-number/discrete-number of points eclipsing over 360 degree.
So here we need an algorithm/equation of point on an 2D ellipse- given following inputs (based on this case):-
Center of ellipse (h,k)
rotation angle of the ellipse axis
major axis (a)
minor axis (b)
theta angle from the x-axis
private void GeneratePolygonAsEllipse(PolygonAnnotation polygonAnnotation)
{
double step = 2 * Math.PI / 200;
var h = xCenter;
var k = yCenter;
var rotation = AngleOfRotation;
var a = MajorAxisLength;
var b = MinorAxisLength;
for (double theta = 0; theta < 2 * Math.PI; theta += step)
{
var x = a * Math.Cos(rotation) * Math.Cos(theta) + b * Math.Sin(rotation) * Math.Sin(theta) + h;
var y = b * Math.Cos(rotation) * Math.Sin(theta) + a * Math.Sin(rotation) * Math.Cos(theta) + k;
polygonAnnotation.Points.Add(new DataPoint(x, y));
}
}
I hope above stipulated sample method equation can be useful to other folks like me looking for solution. I couldn't find direct solution anywhere else so I have added my solution here, that can be used as reference.
Result:-
if anyone can come-up with other solutions like how to use IRender or anything else, would be great to look at them.

How to scale Matrix4x4 around point?

I'm writing a custom editor window in Unity in which I would like to be able to both scroll in/out and drag the view around. To do so, I've been setting GUI.matrix to Matrix4x4.TRS(offset, Quaternion.identity, Vector3.one * scale), where I have control over offset and scale. This works fine, except when scrolling in/out, it anchors the top left of the window. I would like it to anchor on the mouse's position.
If this just requires changing the offset when zooming, that's great - I'm just not sure what the offset should be here. Matrix4x4s are out of my comfort zone for math.
Here is how I'm currently handling zooming:
if (Event.current.type == EventType.ScrollWheel)
{
_scale *= Math.Sign(Event.current.delta.y) == 1 ? 1.1f : 1f / 1.1f;
_offset += Math.Sign(Event.current.delta.y) * /*What do I put here?*/;
}
Let's try to understand whatthe GUI matrix does. It represents a transform that takes coordinates in world space (where your GUI objects live) and converts them to GUI space (more or less aligned with your window). Since we have no rotation, we can easily interpret what constructing the matrix with TRS() does to a world-space point pWorld:
pGUI = scale * pWorld + offset
Now you want to change scale to scaleNew. In doing so, you want to keep the same world position under the mouse.
If your mouse position is given in GUI space (e.g., from Event.current.mousePosition), then we first need to find the corresponding world space point:
v3World = (1.0 / scaleOld) * (v3GUI - offsetOld)
And we want to fix this point under the mouse, i.e.:
v3GUI = scaleNew * v3World + offsetNew
v3GUI = scaleNew / scaleOld * (v3GUI - offsetOld) + offsetNew
We can solve this to get the new offset:
v3GUI = scaleNew / scaleOld * v3GUI - scaleNew / scaleOld * offsetOld + offsetNew
(1 - scaleNew / scaleOld) * v3GUI + scaleNew / scaleOld * offsetOld = offsetNew
And that's it.
Btw, you can also do this with matrix operations alone. This is what GUIUtility.ScaleAroundPivot() does. This is how it looks:
newMatrix = T(v3GUI) * S(newScale / oldScale) * T(-v3GUI) * oldMatrix
T represents a translation and S a scaling. The translation pair T(v3GUI) and T(-v3GUI) move the temporary origin of the coordinate system to your mouse position and perform the scaling from there. You could then directly read offset and scale from this matrix.

Updating sprite's alpha as Scale increases

I have a sprite which size changes from 0.6f to 2.0f during an animation.
At the same time I want its alpha value to change from 1.0f to 0 as its scale increase. So the sprite is fully opaque at 0.6f and gradually disappear until the size is 2.0f where it becomes totally transparent.
How do I correlate those values?
spriteBatch.Draw(texture, Vector2.Zero, Color.White*alpha,null,0f,origin,scale,1f);
Where
alpha = MathHelper.Clamp(0, 1 , 1 - (scale - startScale)/deltaScale);
In your case
startScale = 0.6f,deltaScale = 2.0f-0.6f = 1.4f;
It's going to be easier and more expandable if you animate each value separately. In this case scale and alpha, but the same logic could be applied to anything.
Animations are a function of time, so the variable you're missing here is how long you want the animation to last.
Each animation has a startValue and an endValue. From that you can derive 'change per second' like this:
var changePerSecond = (endValue - startValue) / totalSeconds;
Then in each frame, you simply increment the desired property by multiplying by the frame time (deltaTime), e.g.
scale += changePerSecond * deltaTime;
Okay, with the basic concept out of the way you can see how it would work for scale and alpha in your animation (using a 1 second animation as an example).
var scalePerSecond = (2.0f - 0.6f) / 1.0f;
var alphaPerSecond = (0.0f - 1.0f) / 1.0f;
Then in your update method..
scale += scalePerSecond * deltaTime;
alpha += alphaPerSecond * deltaTime;
Note that this is an example of the simplest linear animation off the top of my head to demonstrate the concept. You'll likely need other code to detect the end of the animation and what to do when it finishes.

Galaxian-like Enemy movement

I'm making a galaxian-like shooter, and my enemy objects have a destination Vector which they travel towards, using this bit of code:
position.X -= (Motion.X / Magnitude) * Speed;
position.Y -= (Motion.Y / Magnitude) * Speed;
Motion is worked out by:
this.Motion = InitialPosition - Destination;
This makes them travel in a straight line towards the destination.
However, I want to make them a bit more interesting, and travel on a sin or cos wave, a bit like Galaxian did.
How can I do this?
You might be better off defining a bezier curve for the movement function than simple functions like a sine wave. Galaxian certainly had more complex movements than that.
Here is a link to a primer on the maths of Bezier curves. It's quite a long document, but does a good job of covering the maths involved, with plenty of examples.
Hope that helps inspire you.
One way to do this would be to create an acceleration factor for the horizontal motion and add that factor to the horizontal speed every tick. So if your horizontal speed for a given enemy was 2 to begin, and your acceleration was -.01, then after 200 ticks the enemy would be going straight down, and after another 200 ticks it would be moving at a horizontal speed of -2. This will give a nice curve.
By determining the speed and acceleration randomly for each enemy (within certain limits determined by experimentation) you can create a nice looking variety of attack profiles without too much effort. This would give a very Galaxian-like motion.
You can do the same thing with the vertical as well, though, of course, the acceleration limits would be very different...for the horizontal acceleration you would probably want to determine a range that was equal in magnitude on either side of 0 (say -.02 to +.02), while for the vertical acceleration, you probably always want the ship to end up going down off the bottom of the screen, so you probably want that acceleration to always end up positive (or negative depending on how you're doing screen coordinates.)
You would do this by utilizing waypoint navigation, in line with your current motion code. You would calculate the waypoints by graphing the sine wave. You would do this by using something to the effect of Destination.Y = Math.Sin(Destination.X) - it's a little difficult to say for sure without seeing your code at large.
Creating an oscillator and moving the enemy (even without momentum) perpendicularly to its direction by an offset equals to the sine or cosine of the oscillator would be enough.
The following example, while working, is clearly just a guideline. I hope it can help you.
var dest = new PointF(200, 100);
var pos = new PointF(30, 140);
var oscAngle = 0d;
var dirAngle = Math.Atan2(dest.Y - pos.Y, dest.X - pos.X);
//Constants for your simulation
const int movSpeed = 2;
const int amp = 2;
const double frequency = Math.PI / 5;
//Inappropriate loop condition, change it to proper
while (true)
{
oscAngle += frequency;
//Scalar offset, you can use Cos as well
var oscDelta = Math.Sin(oscAngle);
//Linear movement
var stepVector = new SizeF((float)(Math.Cos(dirAngle) * movSpeed), (float)(Math.Sin(dirAngle) * movSpeed));
//Oscillating movement, making it transversal by adding 90° to the direction angle
var oscNormalAngle = dirAngle + Math.PI / 2;
//Vector for the oscillation
var oscVector = new SizeF((float)(Math.Cos(oscNormalAngle) * oscDelta) * amp, (float)(Math.Sin(oscNormalAngle) * oscDelta) * amp);
pos += stepVector + oscVector;
//Operate below
}

Perspective on 3D objects

I am updating one of our older apps from vb6 to c# and in the process have to recreate a custom control that the original programmer designed. The control simply took the dimensions of an object, rectangular or conical, and placed an outline sketch of the object in 3D (2.5D technically I think). Of course, the code for the control or the algorithim is nowhere to be had.
Knowing nothing about this before hand I have gotten pretty much everything replicated except the perspective. I am using this code that I found on another answer here.
}
double w = 400;
double h = 250;
double t = 0.6; // tilt angle
double X = w / 2 - x;
double Y = h / 2 - y;
double a = h / (h + Y * Math.Sin(t));
double u = a * X + w / 2;
double v = a * Y * Math.Cos(t) + h / 2;
}
The last piece I need help with though is turning the perspective about 30 degrees left-to-right so I'm not looking at straight on.
Thanks for any help.
As the commenter says: You should use matrices to make your live easy.
Rotation could be easily done by multiplying the 2 matrices, a rotation matrix and a perspective matrix this way:
// We don't have a view matrix here
Matrix4x4 modelProjection = Matrix4x4.Perspective(400, 250, Math.PI / 4) * Matrix4x4.RotationX(degree);
// Get a specifics point position, use x and y to determine the screen position and z for the z-order
Vector3 screenPosition = modelProjection * myPosition; // myPosition is a Vector3
For running the code you have to do some things:
Implement a C# matrix, or get it from anywhere else. Here is a excellent source for implementing matrices.

Categories

Resources