(Before you read, I'm very nervous about posting here since my previous question got a lot of negative responses... Please try and be nice. I am a student and can't write "Perfect" code yet)
I'm currently trying to figure out how to make a mosquito (Texture2D) swoop downwards and then come back up to it's original position.
Currently the mosquitoes simply move left and right within the screen bounds, with no Y movement.
I've stepped it through a debugger and observed it's Y coordinate. My mosquitoes are indeed swooping down and then back upwards again... However, they do it so quickly that it isn't visible to the human eye.
Therefore I need a way to smoothly swoop them down so that it's actually visible.
I am currently unable to embed images into my posts, however I have made a GIF demonstrating the effect that I want.
Here's a link to my GIF
Things I've tried:
Copied the first line of my movement code (seen below) and changed it so that it would only affect the Y coordinates.
Result: Mosquitoes were still swooping too fast to see.
Changing my mosquitoe's velocity.Y to include a Y that isn't 0, so that my movement code will also change the Y position instead of just the X position.
Result: Game was stuck in an infinite loop since my movement code is found in the Update() function, and the code never got out of the loop so that it could update the position...
Here's the movement code I have in my Update.
The mosquitoes move all the way to the right, then all the way to the left.
internal void Update(GameTime GameTime)
{
position += velocity * (float)GameTime.ElapsedGameTime.TotalSeconds;
// Reverses the direction of the mosquito if it hits the bounds
if (position.X <= gameBoundingBox.Left ||
position.X + animationSequence.CelWidth > gameBoundingBox.Right)
{
velocity.X *= -1;
}
}
And here's the actual Swoop() code that I have...
internal void Swoop(GameTime gameTime)
{
float originalYPosition = position.Y;
bool currentlySwooping = true;
while (currentlySwooping)
{
position.Y++;
if (this.BoundingBox.Bottom >= gameBoundingBox.Bottom)
{
currentlySwooping = false;
}
}
while (!currentlySwooping && position.Y > originalYPosition)
{
position.Y--;
}
}
I don't ask questions on here too often, so I'm sorry if I'm using an incorrect format or if I've given too little information.
If you need to know anything else then please let me know.
There are many ways of implementing this, but this should do it.
float originalYPosition = position.Y;
int swoopDirection = 0;
internal void Update(GameTime GameTime)
{
/* Same update code */
if (swoopDirection != 0)
{
position.Y += swoopDirection;
if (swoopDirection == 1 && this.BoundingBox.Bottom >= gameBoundingBox.Bottom)
{
swoopDirection = -1;
}
else if (swoopDirection == -1 && position.Y <= originalYPosition)
{
swoopDirection = 0;
}
}
}
internal void Swoop()
{
swoopDirection = 1;
}
Basically, we have a variable swoopDirection that changes depending on the state of the swoop (1 when going down and -1 when going up). In the update method we check that swoopDirection != 0 (we are swooping). If we are swooping we add the direction to the Y axis and check that we aren't out of bounds. If we touch the bottom we set swoopDirection to -1 so we go up. If we are at the original position swoopDirection is set to 0 and we stop swooping.
Related
I have written this code for my controller in Unity. The problem is that the jump in Y axis has different height than the jump for X and Y axis simultaneously.
// Update is called once per frame
void FixedUpdate()
{
Debug.Log(rigidbody.velocity);
float inputX = Input.GetAxis("Horizontal");
//Movement X
if(inputX != 0 && isGrounded)
{
animator.SetBool("isWalking", true);
rigidbody.velocity = new Vector2(inputX*speed, 0);
//Turn left & right
if(inputX > 0)
{
spriteRenderer.flipX = false;
} else if (inputX < 0)
{
spriteRenderer.flipX = true;
}
} else
{
animator.SetBool("isWalking", false);
}
//Jump
if(Input.GetAxis("Jump") > 0 && isGrounded)
{
rigidbody.AddForce(Vector2.up * jumpImpulse, ForceMode2D.Impulse);
}
}
if i understand your code right, you only gives force to X when you are in ground, so i suggest to remove isgrounded variable and use it just for jump for example in your update method
if(isGround){
if(keypress == y){
addforce in Y
}
}
actually im a bit oxided in unity but i hope to be usefull about logical
I am pretty bad myself when it comes to the jumping physics, but i found these links maybe these will help you.
Unity 2d jumping script
https://answers.unity.com/questions/710765/2d-c-jump-script-addforce-1.html
I also want to know which jump is higher. You stated that there is a height difference when you jump without moving vs when you are moving. Which of the two jumps higher? Are you actually sure that one jumps higher than the other or does it just look like one jumps higher? You can test this by placing a platform an test if you can make it.
Sorry I can't me of more help and can only speculate of what might cause the problem. I would recommend however that when you do movement that you multiply it by Time.DeltaTime. This makes the movement time based instead of frame based. This will make the movement feel smoother.
I'm trying to make it possible to drag an object. This object can only rotate so much. (Similair to a door).
Here is the code abit edited that rotates an object which works.
I have 2 vectors for maxrotation and minrotation.
This code will be called whenever the user is dragging the interactible object. (like update but only when dragged)
if (GestureManager.Instance.IsNavigating &&
HandsManager.Instance.FocusedGameObject == gameObject)
{
//speed and navigiation of rotation
float rotationFactor;
rotationFactor = ManipulationManager.Instance.ManipulationPosition.y * RotationSensitivity;
totransform.Rotate(new Vector3(rotationFactor, 0, 0));
}
It would be great if I could use an if statement here. And I tried quite some things but it's still not working.
As stated the code paste here works. The object should be dragable but only up to a certain points.
totransform is the transform that will be rotated
Any ideas would be great and most appreciated.
Kind regards.
I think you want to look at eulerAngles. Check the values you're getting then set an if-statement before doing the rotation. This is a sample code for you to find the values you want:
if (GestureManager.Instance.IsNavigating &&
HandsManager.Instance.FocusedGameObject == gameObject)
{
//speed and navigiation of rotation
float rotationFactor = ManipulationManager.Instance.ManipulationPosition.y * RotationSensitivity;
Debug.Log(totransform.eulerAngles);
if (totransform.eulerAngles.x < 100) {
totransform.Rotate(new Vector3(rotationFactor, 0, 0));
}
}
So here is the solution that worked for me. First I declare the movement variable (not seen down below, which is 2 in this case). Then I track the distance covered and put a limit on that.
Of course there are some improvements to this code like use movement instead of 2. But because of time constraints I didn't do it.
if (GestureManager.Instance.IsNavigating &&
HandsManager.Instance.FocusedGameObject == gameObject)
{
//here we get the movement direction and set it in movement.
if (GestureManager.Instance.NavigationPosition.y > 0)
{
movement = 2;
}
else if (GestureManager.Instance.NavigationPosition.y < 0)
{
movement = -2;
}
//the first part is false if we reach higher then maxdistance and the movement is going up
//the second part is false if we reach the lower distance and the movement is going down.
if ((!(distance > maxdistance.x) || movement < 0) && ((!(distance < mindistance.x) || movement > 0)))
{
//here we add the movement to the distance so we know if it gets closer or further
distance += movement;
//here we rotate
totransform.Rotate(new Vector3(movement, 0, 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 ;-)
I have 2 images(bar and greenBall1). bar can be move up and down depends on the user response. While, greenBall1 is moving around the screen. I want to do an image collision if both the images touch each other, greenBall1 will change its velocity. The codes that I have for greenBall1 are as below.
private void OnUpdate(object sender, object e)
{
Canvas.SetLeft(this.GreenBall1, this.greenBallVelocityX + Canvas.GetLeft(this.GreenBall1));
Canvas.SetTop(this.GreenBall1, this.greenBallVelocityY + Canvas.GetTop(this.GreenBall1));
var greenBallPositionX1 = Canvas.GetLeft(this.GreenBall1);
var greenBallPositionY1 = Canvas.GetTop(this.GreenBall1);
var maximumGreenBallX = ActualWidth - this.GreenBall1.ActualWidth;
var maximumGreenBallY = 400 - this.GreenBall1.ActualHeight; //Improvise: Instead of 360, get maximum height of canvas
if (greenBallPositionX1 > maximumGreenBallX || greenBallPositionX1 < 0)
{
this.greenBallVelocityX *= -1;
}
if (greenBallPositionY1 > maximumGreenBallY || greenBallPositionY1 < 0)
{
this.greenBallVelocityY *= -1;
}
}
I don't see a reference to the bar object in your code. But the detection of the collision is much easier than the physics of handling the collision. There are several schools of thought to something as simple as Pong collision, and the way you choose to handle it depends on the gameplay you want.
Here is an easy way to detect and handle the collision, simply by negating the X velocity just as you are handling the wall collisions:
if(greenBallPositionX1 < leftBar.X || greenBallPositionX1 > rightBar.X)
{
this.greenBallVelocityX *= -1;
}
Keep in mind you might also have to take into account the width of the bar or the ball depending on where the coordinate is in relation to the image. For example:
if(greenBallPositionX1 < (leftBar.X + leftBar.Width) || greenBallPositionX1 > rightBar.X)
{
this.greenBallVelocityX *= -1;
}
You may also want to at this point move the ball away from the paddle one step to avoid the collision being detected more than once.
Hopefully this answers what you were asking, but if you were looking for a more complex reaction to the collision detection, then you may want to check out the following discussion on Pong type collisions here.
i think this might help you ....
.
Rectangle ballRect = new Rectangle((int)ballposition.X, (int)ballposition.Y, ballsprite.Width, ballsprite.Height);
Rectangle handRect = new Rectangle((int)paddlePosition.X, (int)paddlePosition.Y, paddleSprite.Width, paddleSprite.Height/2);
if (ballRect.Intersects(handRect))
{
// Increase ball speed
ballSpeed.Y += 50;
if (ballSpeed.X < 0)
ballSpeed.X -= 50;
else
ballSpeed.X += 50;
// Send ball back up the screen
ballSpeed.Y *= -1;
}
in this whenever the ball will collide with hand it will increase its speed and change its direction i think that is the think you are looking for as it is also a rectangular collision.
make a class which will give you value that wether two rects will collide or not
public bool Intersects(Rect r1,Rect r2)
{
r1.Intersect(r2);
if(r1.IsEmpty)
{
return false;
}
else
{
return true;
}
}
then you can use
if(Intersects(r1,r2))
{
MessageBox.Show("Collison Detected");
}
I'm a starter in XNA and I'm trying to make a pong-game.
I've been able to make a pong game, but all the code was in one class. So I wanted to try to add a little bit of OOP and I've made a class for the ball and one for the pad.
The ball moves perfectly, but I don't seem to able to make the ball bounce from the pads.
These are the codes I use:
To move the pads
Game1.cs
#region left
if (_KBS.IsKeyDown(Keys.W) || _KBS.IsKeyDown(Keys.Z))
Left.MoveUp();
else if (_KBS.IsKeyDown(Keys.S))
Left.MoveDown();
#endregion
#region right
if (_KBS.IsKeyDown(Keys.Up))
Right.MoveUp();
else if (_KBS.IsKeyDown(Keys.Down))
Right.MoveDown();
#endregion
pad.cs
public void MoveUp() {
if (!paused)
RecPad.Offset(0, -speed);
CheckBorders();
}
public void MoveDown() {
if (!paused)
RecPad.Offset(0, speed);
CheckBorders();
}
private void CheckBorders() {
MathHelper.Clamp(recPad.Y, borders.Top, borders.Bottom - recPad.Height);
}
To check if the ball bounces
ball.cs
public void CheckBounce() {
if ((myBounds.Intersects(left) && movement.X < 0) || (myBounds.Intersects(right) && movement.X > 0))
movement.X *= -1;
}
public void Draw(SpriteBatch sBatch, Texture2D texture, Color color, Rectangle left, Rectangle right) {
this.left = left;
this.right = right;
Move();
sBatch.Begin();
sBatch.Draw(texture, myBounds, color);
sBatch.End();
}
pad.cs
public Rectangle RecPad {
get { return recPad; }
private set { recPad = value; }
}
Game1.cs
Ball.Draw(spriteBatch, ball, Color.White, Left.RecPad, Right.RecPad);
I seemed to get the pads back to work
The problem seems to be solved by using the originel recPad instead of the constructor RecPad
Now I only need to get my boundries working, because the MathHelper.Clamp doesn't seem to work
See my code for more info
This code now fixed my border-problem
private void CheckBorders() {
if (recPad.Top < borders.Top)
recPad.Location = new Point(recPad.X, borders.Top);
if (recPad.Bottom > borders.Bottom)
recPad.Location = new Point(recPad.X, borders.Bottom - recPad.Height);
}
This immediately stands out to me (from CheckBounce):
movement.X *= 1;
Could be a copying error, or you forgot to put a '-'.
Also, consider using the Rectangle.Contains/Intersects method(s) to streamline some collision code, and MathHelper.Clamp to keep your paddles in bounds. This is more just for future reference, since your methods work, but it's nice to take advantage of the helpful tools in XNA.
Edit: Concerning those 'helpful tools':
The Rectangle class has the methods Intersect and Contains, which can tell you if that rectangle is intersecting another rectangle or containing a certain point, respectively. You say your ball is just a top left position and a texture, but I see in your collision checking you also check for the radius of the ball. I think you'd have an easier time defining a Rectangle bounding area for your ball and using the Intersects method to check for collision. That simplifies your collision code to:
public void CheckBounce()
{
if (myBounds.Intersects(LeftPaddle.Bounds) || myBounds.Intersects(RightPaddle.Bounds))
movement.X *= -1;
}
Fairly simple, but not entirely safe-- if the ball manages to move far enough into a paddle that one frame of movement wouldn't free it from that paddle's bounds, you'd be stuck perpetually inverting the X velocity, producing a 'stuck ball' effect. So we can add just a bit more checking code to avoid that:
public void CheckBounce()
{
if ((myBounds.Intersects(LeftPaddle.Bounds) && movement.X < 0) ||
(myBounds.Intersects(RightPaddle.Bounds) && movement.X > 0))
movement.X *= -1;
}
I apologize if the inline conditionals are a little too dense. What this means is, if the ball is moving left and hits the right paddle, invert the X. Likewise, if it's moving right and hits the left paddle, invert the X. This removes the 'sticking'.
Now, as for MathHelper.Clamp, in your situation I would use it to restrict paddle movement. MathHelper.Clamp simply clamps a value between an upper and lower bound. It's the equivalent of using Math.Min, then Math.Max.
private void CheckBorders()
{
//clamps a value to a min and a max
MathHelper.Clamp(recPad.Y, borders.Top, borders.Bottom - recPad.Height);
}
This clamps the Y position of your rectangle between the top of your borders, and the bottom of your borders minus the height of the rectangle. That last bit keeps the bottom of your rectangle from clipping the bottom of the borders by taking the height into account.