In a .NET C# program, I have to simulate the "mouse" cursor movement with coordinates received in the events of a external controller.
I did get to move the cursor depending on these coordinates.
Is there any possibility to move the cursor of a smoother way between two points?, because when I have 2 away points there is like a "jump" with the cursor.
Thanks in advance.
Edit: Added code, this function is launched each time new coordinates are received (aprox. each 20-30 ms)
//...
private void MoveCursor (int x, int y){
//Added checkup for avoiding noise between closer points
if (Math.Abs(Cursor.Position.X - x)>10 || Math.Abs(Cursor.Position.Y - y)>10){
Cursor.Position = new Point(x,y)
}
}
//...
In addition to my comment, here is a simple solution (syntax untested) that I use in one of my software and that I suggest you to test to see if it fits your needs :
Point _targetPosition;
Point _currentPosition;
private void MoveCursor (int x, int y){
_targetPosition = new Point(x,y);
_currentPosition += (_targetPosition - _currentPosition)*0.08f;
Cursor.Position = _currentPosition;
}
Basically, I maintain a target position which is the last coordinate received. I move the cursor only by a fraction (here 8% of the distance between the current position and the target).
It very efficiently smooths the movement of the mouse but lead to imprecision and a delay that may not be acceptable for brutal movement or changes of direction.
A factor of 8% give good results in my case considering 60 updates/seconds but that factor need to be adapted to your data.
Finally inspired by #Ndech solution I could solve my problem.
I've divided the solution into 2 parts:
This is the event which is raised by my gaze controller (each 20ms aprox). I discard closer points to avoid "jumps" due to the way as gaze controller works.
private void MoveCursorEvent (object sender, GazePointEventArgs e){
if (Math.Abs(Cursor.Position.X - e.X) > 40 || Math.Abs(Cursor.Position.Y - e.Y) > 40){
MoveCursor((int)e.X, (int)e.Y);
}
}
Copying current values of X,Y point of the cursor in a primitive variable since Cursor.Position could change during the process (Check if the first time…) Adding to previous point, average distance between previous point and current point with a weight of 15%. And Updating Cursor.Position with the new position calculated.
//Declare position variables
int previousX = 0;
int previousY = 0;
private void MoveCursor (int newX, int newY){
//If first time, set.
if (previousX == 0)
previousX = newX;
if (previousY == 0)
previousY = newY;
//Calculate new position
previousX = (int)(((newX - previousX) /2) * 0.15f);
previousY = (int)(((newY - previousY) /2) * 0.15f);
//Update position
Cursor.Position = new Point (previousX, previousY);
}
Related
I've started using LightningChart in my real time monitoring application. In my app there are many y axis which use segmented layout (one y axis per segment):
mainChart.ViewXY.AxisLayout.YAxesLayout = YAxesLayout.Segmented;
My goal is that when you mouse click a segment, it gets larger compared to other segments (kinda like zoom effect) and the other segments gets smaller. When you click it again it goes back to normal.
I know I can change the size of the segments with:
mainChart.ViewXY.AxisLayout.Segments[segmentNumber].Height = someValue;
That takes care of the zooming effect.
Now the problem is that how can I solve which segment was actually clicked? I figured out that you get mouse position via MouseClick -event (e.MousePos) but that seem to give only the screen coordinates so i'm not sure that it helps.
I'm using the LightningChart version 8.4.2
You are correct that getting mouse position via MouseClick event is the key here. The screen coordinates you get via e.GetPosition (not e.MousePos) can be converted to chart axis values with CoordToValue() -method. Then you just compare the y-coordinate to each y-axis minimum/maximum value to find out what segment was clicked. Here is an example:
_chart.MouseClick += _chart_MouseClick;
private void _chart_MouseClick(object sender, MouseButtonEventArgs e)
{
var mousePos = e.GetPosition(_chart).Y;
double axisPos = 0;
bool isWithinYRange = false;
foreach (AxisY ay in _chart.ViewXY.YAxes)
{
ay.CoordToValue((float)mousePos, out axisPos, true);
if (axisPos >= ay.Minimum && axisPos <= ay.Maximum)
{
// Segment clicked, get the index via ay.SegmentIndex;
isWithinYRange = true;
}
}
if (!isWithinYRange)
{
// Not in any segment
}
}
After finding out the segment index, you can modify its height as you described:
_chart.ViewXY.AxisLayout.Segments[0].Height = 1.5;
Note Height means segment height compared to other segments.
Hope this is helpful.
I need a little help in my little 2D game I want to create in XNA. I had almost no knowledge of programming before I got interested in XNA and C#, so maybe my problem is simple, but I just can't figure it out.
So basically, I have a base class, and I created an additional class Animation for animating sprites. I implemented some methods so that when the player presses "right" it would change the animation's current texture and increment X by a number of xf; anyway, the main idea is that I'm using just one instance of my class (basically, one object of type animation which changes its texture and properties based on what key is pressed).
So, I had no problems making it run right or left. Works out pretty well. The big problem started when I wanted to implement the jump sprite. So I created the 6 frames necessary for the sprite, but to animate it I have virtually no idea how to do it.
The only thing it does right now is to loop through the frames of the sprite, but the position (both .X and .Y) remain the same. The thing is, I have a Vector2 position which holds the animation's current position, and it's fine with running because I simply increment it. However, when it comes to jumping, I want it to increment .X, but the .Y should be decremented (thus going up) until frame number 3; after frame number 3, until the last frame, I want the .Y position to go down (thus fall) with the corresponding animations (erm, frames).
So, basically, I don't know how to modify the .X and .Y so that it would display the frames that I need in the time I need. I don't know if you really understood what I'm trying to say; basically when I press the "up" key, it loops through the frames but the position remains the same.
My idea was to use a reference to the actual Vector2 position which holds the animation's current position and pass it to the method in the other Animation.cs class, namely the PlayAnimJump, and modify the position after each frame and return it to the actual Game1.cs by reference. Even if I would do that (though I fail to see what good it would be), it wouldn't be updating the position as it should. So, any ideas?
Here is the code for the PlayAnimJump method from the Animation class:
public void PlayAnimJump(GameTime gameTime)
{
elapsed += (float)gameTime.ElapsedGameTime.Seconds;
sourceRect = new Rectangle(currentFrame * frameWidth, 0, frameWidth, frameHeight);
currentFrame = 0;
if (elapsed >= frameTime)
{
if (currentFrame <=3)
{
if (looping)
{
currentFrame++;
}
}
else if (currentFrame > 3)
{
currentFrame++;
}
elapsed = 0;
}
}
The default constructor for that class:
public Animation(ContentManager Content,string asset,float frameSpeed, int numbOfFrames, bool looping,Vector2 positionIT)
{
this.assetName = asset;
this.frameTime = frameSpeed;
this.numbOfFrames = numbOfFrames;
this.looping = looping;
this.animation = Content.Load<Texture2D>(asset);
frameWidth=(animation.Width / numbOfFrames);
frameHeight=animation.Height;
position = positionIT;
}
Here is the code (from the main) when the up key is pressed:
else if (up)
{
check = animation1.GetAsset();
if (check == "eright")
{
animation1.SetFrameSpeed(0.8f);
animation1.SetNumbOfFrames(6);
animation1.ChangeTexture(Content, "SarimCumVreJiorjica");
animation1.PlayAnimJump(gameTime);
/*position1.x +=2f;
position1.Y -=2f;
*/
}
So, I'm not sure how, but I'm supposed to change position1 according to the frame that's displayed by the animation in that second. Am I missing something?
If your animation class had a reference to the object that you wanted to move (i.e the object holding the position field) then you could modify it within the animation class, within the PlayAnimJump method.
Or, to reduce coupling, you could just have PlayAnimJump return a variable indicating how far into the jump you are (maybe a percentage of the jump, from 0 to 1). Then, you could use the percentage outside to set the objects position. So, if the jump is halfway done, the return value would be 0.5f, which you could use in an equation to determine the players y position. An example equation would be:
float percent = animation1.PlayAnimJump(gameTime);
float y = Math.Sin(percent * Math.PI) * maxJumpHeight;
player.positon.y = y;
This uses a sine wave to determine the players height throughout the jump animation. You would just need to write the code that determines the percentage of the way through the jump (currentFrame) in the PlayAnimJump method and return it.
Formula of the frуefall for Y coordinate is
y = g * t ^ 2 / 2 + v0 * t + y0
Characters jump from height y0 vith start velocity v0 by Y axis and gravity gradually slows down and starts to fall.
Calculate deltaY using following formula
deltaY = g * t ^ 2 / 2 + v0 * t
First show the frame on which the character is pushed off the ground, then the frame on which it rises until it reaches the peak of the jump. Once the sign change deltaY from + to - show how the character change pose for fall. Something like that.
SO I currently have an object which moves in the Y axis (up and down). How would I be able to program it so the program knows whether the object is moving up or down?
I understand I'd need an if statement like the following:
if (object is moving up)
{
//set direction to 1
}
else
{
//object must be going down, set direction to 2
}
I just don't understand what syntax I'd need to use. This would be easy if I was holding down the key and it was moving up or down however that's not the case. The object is a bouncing ball and therefore when you set a power the ball jumps, and bounces so it is constantly changing.
Thanks for your help, let me know if this wasn't described well and you need more info.
You need to save the current coordinates so that you can check them after the update method is called. Then you can check the differences between the previous and current location:
Declare it in Game1() constructor:
Point previous = new Point();
previous.X = myObject.InitialX;
previous.Y = myObject.InitialY;
In Update:
int deltaX = object.X - previous.X;
int deltaY = object.Y - previous.Y;
if (deltaX < 0)
{
object is moving upwards
}
else
{
object is moving downwards
}
if (deltaY < 0)
{
object is moving to the left
}
else
{
object is moving to the right
}
//update the previous state
previous.X = myObject.X;
previous.Y = myObject.Y;
When you update the position of the ball you have one position and you calculate the position for the next frame -> You can calculate the distance vector.
With the sign of the y-value of this distance vector you can decide if it's moving upwards, downwards or isn't moving (=0).
I'm trying to throw an arrow in my XNA game, but I'm having a hard time trying to realize a good parabola.
What I need:
The more you hold Enter stronger the arrow goes.
The arrow angle will be always the same, 45 degrees.
This is what I have already have:
private float velocityHeld = 1f;
protected override void Update(GameTime gameTime)
{
if (Keyboard.GetState().IsKeyDown(Keys.Enter) && !released)
{
timeHeld += velocityHeld;
holding = true;
}
else
{
if (holding)
{
released = true;
holding = false;
lastTimeHeld = timeHeld;
}
}
if (released && timeHeld > 0)
{
float alpha = MathHelper.ToRadians(45f);
double vy = timeHeld * Math.Sin(alpha);
double vx = timeHeld * Math.Cos(alpha);
ShadowPosition.Y -= (int)vy;
ShadowPosition.X += (int)vx;
timeHeld -= velocityHeld;
}
else
{
released = false;
}
}
My question is, what do I need to do to make the arrow to go bottom as it loses velocity (timeHeld) to make a perfect parabola?
The solutions discussed above rely on you calculating a new velocity on every iteration, and then calculating the delta (change) from the previous position to determine the current position.
This fits in with the normal logic of a game loop. It is however computationally more complex than it needs to be, and is possibly unstable due to rounding errors.
The simpler and more stable solution is to determine the equation for the parabola and use this to directly work out the position at time t after launch.
Let the arrow start at x=0, y=0. Let the launch velocity be v. At time t after launch the a coordinate of the arrow is x = kt, where k = v*cos(45) = v/sqrt(2).
The y position is a quadratic, y = at^2 + bt + c where we don't know a, b, c.
But when t=0, y=0 so c=0
When t=0, the initial downward velocity is v*sin(45) = v/sqrt(2)
Using a tiny bit of calculus (differentiating position to get velocity), at t=0
v/sqrt(2) = 2at + b = b
Differentiating velocity to get acceleration, we get the initial acceleration at t=0 is 2a. But the only acceleration is due to gravity, so 2a=-g where g is your gravitational constant.
Putting these two equations together, at time t
x(t) = v/sqrt(2);
y(t) = -(g/2)t^2 + vt/sqrt(2)
You know v and t, you define g, so you can work out the x and y co-ordinates at time t directly from this equation.
This is a more straightforward approach and more robust (rounding errors will not accumulate). It is how I personally do it. My hand grenades always follow perfect parabolic arcs, and do so in a computationally efficient manner.
Note: I never heard of XNA until now, but I do use C#. Let me know if this doesn't quite work, though the gist of it should be there.
In your last if-statement, after Enter key is released, you want to increase the downward velocity by a certain (small constant) amount every time you call Update (I assume increasing the y-coordinate makes things move "down" on screen). To do this, as soon as Enter is released, instead of calling double vy = timeHeld * Math.Sin(alpha) every time, save the result into a variable you can reference later, then use a bool value to keep track of when to calculate that value, which is ONLY right after Enter is released.
In other words, it goes something like this:
// extra variables
bool justReleased = false;
double vy, vx;
...
protected override void Update(GameTime gameTime)
{
// ...
if (holding)
{
released = true;
holding = false;
lastTimeHeld = timeHeld;
justReleased = true; // add this here
}
// ...
if (released && timeHeld > 0)
{
float alpha = MathHelper.ToRadians(45f);
// not local variables anymore. Also I flipped the sign - my intention is that initial vertical velocity is "upwards"
if(justReleased)
{
vy = -1 * timeHeld * Math.Sin(alpha);
vx = timeHeld * Math.Cos(alpha);
justReleased = false;
}
ShadowPosition.Y += (int)vy; // Note: I flipped this operator
ShadowPosition.X += (int)vx;
timeHeld -= velocityHeld;
// increase the downward velocity
vy += 2; // or some constant. I can't test this. :\
}
else
{
released = false;
}
}
Hopefully this works, though there might be more efficient ways to do this. Though this isn't a physics site, see this for reference ;-)
So, I have a rectangle "rectangle1", at 160,160.
I want it to move smoothly to cordinates 160,30, with a duration of about 1 second. (time delay)
I've figured out that some basic code to move the shape is
rectangle1.Location = new Point(160,30);
However, when I tried doing a for loop with
rectangle1.Location = new Point(160, rectangle1.Location.Y - 100);
it just moved there instantly. Which I should have expected really. Same occurred with
int count = 0;
while(count != 300)
{
rectangle1.Location = new Point(160, rectangle1.Location.Y -1);
count += 2;
}
So, I assume I need some sort of clock / timer loop, that moves it by x pixels every x milliseconds. Not sure how to do this, so help would be appreciated.
Also, I'm going to be animating two other rectangles horizontally, which will then move up at the same time/speed as rectangle1. I think I'll have to "delay" rectangle1's movement until they are in position, correct?
Thanks.
PS: I've googled a fair bit, but since I'm not entirely sure what I'm looking for, it wasn't very fruitful.
If you need smooth movements, it's great to use timers, threads, backgroundworkers.
Here is what you need to do. Assuming you have the code that increment/decrement x,y points for the shape.
Steps:
set timer interval to for e.g. 100
set an integer int count=0; *
in timer_tick event do the moving work
private void timer1_Tick(object sender, EventArgs e)
// no need to use your while loop anymore :))
{
If(count< 300) //set to your own criteria
{
//e.g. myrect.location=new point(x,y);
// rectangle1.Location = new Point(160, rectangle1.Location.Y -1);
}
count += 2;
}