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.
Related
I have a laser turret in Unity3D, which I'd like to turn towards the enemies. The turret consists of a "leg" and a "head" (selected on the picture 1). The head can pan and tilt around a spherical joint.
I do the following:
Vector3 targetDir = collision.gameObject.transform.position - turretHead.transform.position;
float step = turnSpeed * Time.deltaTime;
Vector3 newDir = Vector3.RotateTowards(turretHead.transform.forward, targetDir, step, 0.0f);
turretHead.transform.rotation = Quaternion.LookRotation(newDir);
The problem is that since the pivot of the head is not aligned with the laser beam, the turret turns into the almost right direction, but it shoots above the target. (It would hit perfectly, if the laser would come out of the red axis of the pivot.)
Is there a builtin method or some trick to achieve the correct functionality other then doing the calculation myself?
Okay, here's the quick and easy way to do this. It's probably "better" to do it with proper trig, but this should give you the result you want pretty quick:
If you don't already have a transform aligned with the barrel, then create an empty GameObject and line it up (make sure it's a child of the turret so they move together). Add a reference to your script for it's transform.
Then, in your first line, calculate from the new Barrel transform instead of the turretHead transform. Leave everything else the same. This way it calculates from the turret barrel, but moves the turret head.
Now, this approach isn't perfect. If the pivot center is too offset from the barrel transform, then it would be less accurate over large moves, or when aiming at something close by, because the expected position when aiming would be different than the initial position due to the rotation pivot being elsewhere. But this can be solved with iteration, as the calculation would become more accurate the closer it is to it's desired goal.
I am trying to make a spin wheel that is divided into 6 sections. Each section is marked with a gameObject that is centered in that section. After the player spins the wheel, it will rotate until its starts stopping and then the wheel moves and stops in the center based on the section that was selected (Randomly). I used the following code to rotate the wheel towards the 0 on X axis. this code works fine and the wheel rotates fine, but only if the selected section was on the positive X axis.
float rotateFloat = (((randomReward + 1) * 60) - 30) - transform.rotation.z;
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, rotateFloat));
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, f_difX * Time.deltaTime);
I did some digging and found that Quaternion.RotateTowards()finds the closest way towards the target and rotates using that direction (This caused a problem with the direction of rotation).
Example (Follow image): The player swipes and randomReward (Number 5 on spin wheel) and the wheel starts rotating. When the wheel slows down, it starts moving towards the center. Then it will stop spinning along the direction of the swipe and will rotate towards the other side (Because the distance to the center is closer from the left side).
How can I set it to follow the same direction of the swipe regardless of which is closer to the center. And maybe if there is a better way to do this, please enlighten me. Thanks.
I think the easiest way to rotate a GameObject is by using:
float Speed = 1f;
void Update()
{
// Rotate the object around its local X axis at 1 degree per second
transform.Rotate(Vector3.right * Time.deltaTime * Speed);
}
You can read more about his here
It can happen sometimes the center of the GameObject it´s not placed in the center of the mesh or sprite. If you can´t modify this for any reason, what you can do is place this model/sprite as a child of an Empty GameObject and then attach the rotation script to the Empty GameObject.
While i understand that you don't want people to rotate the disk to the reward they want. Why do you use a random reward and go through the trouble of lining the rotation to the reward?
You should be able to say catch a 'swipe time', then do some math to it (say so it turns at least once if the screen touch time is very short) and then add a random range to it, that is within the circumference of the disk. Then when the disk is done spinning do a ray cast at the top location to determine the reward? (could also link the spinning time to the swipe-time, so that the reward is offered in somewhat the same time interval).
//this comment would have been made as a comment if i would have had the rights to do so, as i think this response may help the question asker, it is provided as an answer instead. i do hope this doesn't piss any one off to much :(
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
I want to allow a boat in my 3D simulation of a ship to rotate and be moved on all axes. However, the way that I have the boat's movement programmed makes this impossible.
The way it moves:
this.transform.Translate(Vector3.left * Time.smoothDeltaTime * speed);
The way it turns:
this.transform.Rotate(Vector3.forward * Time.smoothDeltaTime * (int)horizontal)
The shape of the boat also makes it impossible to simply move it on a solid base, since it does have the triangular shape (for underwater collisions).
So what I want to do is allow the boat to be affected by gravity, but still float on the water. Then, when the boat hits something, it needs to be able to "roll" and then eventually return to its normal position.
So, is there any way to make an object slowly return to its normal rotation(z rotation of 0) after it hit something, and not be affected by gravity once it reaches a certain elevation. (Y value of 34.75)
The boat has a Rigidbody and a Mesh Collider
I'm not sure if the player would be able to move when he gets hit, but you could save the current values to local variables (for example: Transform transformOnHit). After you complete the roll, you can use your own provided code to translate and rotate back to the original transform.
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/