I am making a game, using a onscreen/virtual joystick. The joystick it self works fine.
What I want is when you turn the joystick, a bullet is fired in that direction. I got that working too. Now the problems arises when shooting a bullet when the joystick is not at the edge/radius.
When the joystick is at the edge/radius, the bullet move at maximum speed, exactly what I want. But when the joystick is, lets say, somewhere between the radius and the center of the joystick, the bullets move slower. This is logical because of the radians and stuff.
But it is not what I want. What should happen is that the bullets always move at the maximum speed.
Does anyone know how this could be achieved? I am completely stuck at this.
Thanks!
EDIT: since I still dont understand this at all, basically what I want is that I have a point in radians within a circle and I want to get the position of that point at the edge of the circle.
So let's say I have this Vector2 in radians.
Vector2(-0.3, 0.3);
and the radius of the circle is 40.
The length from the center of the circle to the Vector2 point would propably be somewhere around
radius = 40 * 0.3 = 12
Now what would the Vector2 point be when the length is 40?
I can't seems to figure this out. Trigonometry is definetely not my strongest point.
I fixed it! I just multiplied to localPosition of the joystick with a very large number, so that the localPosition woul fall outside of the radius. Then I just use clampMagnitude to get it at the edge of the radius. Now I get the correct behaviour.
Related
i am creating a 3d top down shooter with unity and wanted to create an aim assist for it since hitting enemies is difficult. my idea was to create a trigger that slows down the rotation of the joystick on the weapon when the player aims at an enemy. i implement my rotation as follows:
float eulerY = (Mathf.Atan2(_JoystickShoot.Direction.x, _JoystickShoot.Direction.y) * 180 / Mathf.PI);
However, I don't know how to implement the slowdown now. The player should rotate slower than the actual rotation of the joystick.
My approaches have not really been successful so far.
does anyone have any idea?
thanks :)
You can add a variable that scales the rotation. Set it to 1, except when you're pointing at an enemy, where you set it to a value between 0 and 1 that feels good for you.
float eulerY = rotationScaling * (Mathf.Atan2(_JoystickShoot.Direction.x, _JoystickShoot.Direction.y) * 180 / Mathf.PI);
If you want to draw the crosshair towards an enemy, you can calculate the angle (or distance) to the closest enemy. If it is below a certain threshold you can adjust your rotation function to favor rotations towards the enemy over rotations away from it. You can use something like this:
float eulerY = (Mathf.Atan2(_JoystickShoot.Direction.x, _JoystickShoot.Direction.y) * 180 / Mathf.PI);
if (closest enemy is within threshold range)
if (eulerY * (difference in Y angle to closest enemy) < 0) // if we rotate away from the enemy we scale the rotation down
eulerY *= 0.5;
else // if we rotate towards the enemy we scale it up
eulerY *= 1.5;
You can adjust this for multiple angles as well, but just doing the same calculation for X and Y direction might feel a bit awkward. The reason is that in that case you have to compare it against the "true" angle/distance, not against the X and Y angles/distances individually.
I think it is more useful to talk about 'direction' rather than 'rotation'.
Presumably your ship travels and/or shoots in the same direction as the joystick is pointing in. This is a natural and intuitive relationship. "slowing down rotation" will most likely break this, making your interface less intuitive to use. There are also usually ways to go directly from a direction-vector to a rotation, for example Quaternion.LookRotation, avoiding the need to deal angles directly.
You could instead check if there is any enemy within a small arc, select the enemy closest to the center of the arc, and use the direction towards that enemy to fire in. Note that this can fail if enemies are moving and shots are slow, since it can prevent 'leading' your shots.
Other alternatives could be to simply make your enemies easier to hit. Make the enemies or shots larger, or possibly, just make the hitboxes larger. Or increase fire-rate and/or dispersion.
I have objects that I want to rotate towards a collision point, but only on the Y-axis. Here's what I mean:
The arrows show which direction the balls hit the pins.
First
The object rotates on it's Y-axis to face the collision point.
Second
I suspect what I need is to convert the Vector3 of the collision point into rotational degrees, that can then be plugged into the object's Y axis. I have no idea how to do this, or if it's even possible. Can anyone help me?
Why don't you simply use Unity's LookAt function like this:
transform.LookAt(new Vector3(Target.position.x, transform.position.y, Target.position.z));
I know there's so many stuff on the internet about this, and I have looked at quite a lot of it, but I just can't get it to work with my code. I kinda know the maths behind it, but again struggling to get it into code.
I have 2 speed variables for the ball float xSpeed, ySpeed. Both are equal to 3 (or -3 depending on collision - I just have basic collision atm). I'm also using a rectangle for ball ballRect as well as the paddle paddleRect.
I'm updating the position as so:
ballRect.X += xSpeed;
ballRect.Y += ySpeed;
I've found bits of code, and tried doing it myself, but they just were really buggy. One would (I think) work on the first hit, but when it came to the next hit it would stick to the paddle.
double relativeBallPos = (paddleRect.X + ballRect.X);
double ballVelx = xSpeed;
double ballVely = ySpeed;
double angleRads = Math.Tan((ballVelx / relativeBallPos));
double angleInDeg = angleRads * (180 / Math.PI);
double angleOfReflection = (angleInDeg * 2);
ballVelx = ballVelx * angleOfReflection;
if (ballRect.X + (ballRect.Width / 2) < paddleRect.X + (paddleRect.Width / 2))
{
xSpeed = (float)-ballVelx;
}
else if (ballRect.X + (ballRect.Width / 2) > paddleRect.X + (paddleRect.Width / 2))
{
xSpeed = (float)ballVelx;
}
(This goes off at a (probably incorrect) angle and just goes straight up after the first hit)
Thanks for any help :)
If your ball intersects any horizontal threshold (the horizontal sides of the bricks, or of the paddle), negate ySpeed. If it intersects any vertical threshold, negate xSpeed. There, now you have a functional breakout game.
You can add a bit more polish by changing the angle of the ball when it hits the paddle based on the position of the collision along it, with center being a full reflect (ie negate ySpeed) and xSpeed getting a factor of the distance (positive or negative) of the distance from the center.
Yes, what you are seeing is completely normal, if your objects are moving very fast and game tick speed is slow, you may have glitches like sticking to the paddle or even missing the paddle completely, and just going straight through.
The solution to missing the paddle is increase game tick speed, i.e. process game moves more frequently.
Ball to paddle stickiness can be alleviated by doing a roll back of object movement in time. For example you have objects A and B, which are colliding at some point in time. If you simply reverse their X and Y speeds, you may end up with colliding again in the next point in time, so you would then reverse their speeds again, and so on, which appears as though it's stuck. It can sometimes get stuck on one only axis, so it will slide on the paddle, and then go straight down, which is just another side effect of the same issue.
How to do a roll back? You know where A is moving, and suppose B is a paddle, so it's static. You know that A is colliding with B at the moment. You can calculate a vector of A's movement and slide A back in time through that vector reversed. For example, if top left corner of the screen is (0,0), and A was moving at the speed of X=+10,Y=+10, you would move it back by whole or fraction of the step (depends on how complex you want to go with this), so by (-10,-10) or fraction thereof. You can use intersection rectangle to calculate precise values, and only move enough so the objects are barely touching.
Ideally, you would reflect the vector off the hit surface (use physics, i.e. hit angle = reflect angle) and before applying new speeds, move your ball in a way that it does not collide with paddle. To simplify, you can assume your hit surface is horizontal and is just a straight line, so your reflection formula is very simple.
This topic is well covered here (although using XNA, same principle applies):
Stuck in Wall after rectangle bounding box collision
So I need some help with my C# XNA top-down 2D "wave spawn" game. Basically, I have a player that has the functionality of shooting a laser at enemies that spawn in waves. The problem that I'm looking at fixing right now is my enemy collision code with a stationary non-rotated wall (rectangle)
I need to detect which side the enemy hits the rectangle on so he can properly get around the rectangle and to the player. (Example: if the enemy is blocked from the right side of the wall, move up the wall until he can get around the wall)
Here is the code I have to detect the angle between the enemy and the stationary wall when collided:
// I am blocked, find angle to find which side I'm blocked from
centerOfWall = wall.CenterOfWall;
Vector2 difference = centerOfWall - centerOfEnemy;
// Getting the angle of intersection between the two rectangles!
angle = Math.Atan2(difference.X, difference.Y);
// Converting angle to degrees!
degrees = angle * (180 / MathHelper.Pi);
I guess what I'm asking is, with this angle, can I find the side at which the enemy hits the wall? Like if the angle is less than 90 degrees but greater than 0 degrees I will be hitting from the Left or something like that.
If this doesn't work, can someone help me in finding another way that would work?
Thanks,
Johan
Im making a 2D game where the player controls a tank.
I can make the tank, and all, but whats really messing with my mind is how to make it rotate accordingly.
I want it to behave just like the Wii game, Tanks.
Fixed directions, and with no real front and back on the tank.
Driving up, then left should make it rotate to the left.
Driving up, then down should not make it rotate, just drive the other direction.
I red a tutorial a while back about some way to do that by dividing the degrees into 2 180 degree parts. But i have simply not been able to find that damn site again.
I hope you guys are able to understand what im trying to say.
Thanks in advance :)
I assume you're drawing your tank as a sprite? In that case there's an overload of the SpriteBatch.Draw method that allow you to specify the rotation angle around the origin.
SpriteBatch.Draw overload
Here's an example on how to use it from MSDN
The example above will keep rotating your sprite, so you will need to add some custom logic so it will only rotate it according to keyboard input. Here's a simple example on how to check for keyboard input. So add logic that checks if the right or left button has been pressed, and update the rotation angle if they have. If it's the up or down button that has been pressed you simply modify the position of your sprite.
I hope it makes sense, otherwise just let me know.
I think what you're looking for is simply the best way to minimize the rotation of the tank, modulo 180 degrees.
I would use the angle between the desired movement direction and the tank's current direction to start. Make sure this is the minimum angle, then compare that with the angle between the tank's current direction + 180 degrees. Something like:
// smallest angle between the current direction and the desired direction
minAngle1 = Math.Abs(Math.Min(tankAngle - desiredAngle, desiredAngle - tankAngle));
// smallest angle between the opposite direction and the desired direction
oppositeAngle = (tankAngle + 180) % 360;
minAngle2 = Math.Abs(Math.Min(oppositeAngle - desiredAngle, desiredAngle - oppositeAngle));
// get the smaller of two to rotate to
if (minAngle1 < minAngle2) {
// we know that we should rotate the current direction to the desired direction
} else {
// rotate the opposing direction to the desired direction
}
Note you'll need to play with your rotation signs to ensure you're rotating the right way. Also, I've assumed you know your rotation angles, if you have vectors you can simplify this a little bit by using the dot product between the two vectors instead of the angle for comparisons.
Is your problem with the direction of movement based on the angle they have rotated?
Vector2 moveDir = new Vector2(Math.Cos(rotation), Math.Sin(rotation));
position += (moveDir * speed);
Speed here would be a number for how fast you want to move in that direction. position is another Vector2 for the position of the sprite. As Tchami says you can draw it with the rotation using the SpriteBatch.Draw overload. Rotation for the the Cos and Sin methods should be in radians but I think Draw should be in degrees if I remember correctly. MathHelper.ToRadians(degrees) and MathHelper.ToDegrees(radians) should solve that.
There is lots of XNA tutorials and examples on the site http://creators.xna.com/en-US/education/catalog/