Ok so here's my issue, I have a script that allows me to lock on to and orbit an enemy target. The problem is if my character is moving when pressing the lock on button the character will continue moving in whatever direction it was going before the button was pressed regardless of any more button presses save for the opposite direction.
This doesn't happen when I'm stationary, if my character stands still and I press the lock on button everything works fine. It's only when I'm moving.
I'm not sure if this is enough information, or what else someone might need to better understand but here is my script:
if (GetComponent<DetectedEnemies>().locked)//checks bool to see if lockOn button was pressed
{
mainCam.SetActive(false);//turns off main cam
lockCam.SetActive(true);//turns on lockOn cam
movesetting.tarObject = GetComponent<DetectedEnemies>().Closest;//target object will be the closest enemy to player
this.transform.LookAt(movesetting.tarObject.transform.position);//player will look at the target object at all times
if (currXRot.x > maxXRot.x)//if the current x rot of this object exceeds the maxXRot it can go...
currXRot.x = maxXRot.x;//it gets reset
transform.Translate(Vector3.right * movesetting.speed * Time.deltaTime * turnInput);//orbits around the target object
transform.Translate(Vector3.forward * movesetting.speed * Time.deltaTime * forwardInput);//in control of moving towards and away from target
}
Any and all help is greatly appreaciated, thank you in advance. If you need more info or if something isn't clear please let me know.
Try creating a second speed variable which you use for the orbiting speed. Then if the player is locked set the first speed variable to 0 and when the player isn't locked set the orbiting speed variable to 0. Something like this: (I use 5 as an example)
if(GetComponent.<DetectedEnemies>().locked) {
speed = 5;
orbitSpeed = 5;
} else {
speed = 5;
orbitSpeed = 0;
}
Related
I'm new in Unity. I am trying to make a 2D game similar to Pong. However, I want to increase more speed to Ball over time to make it harder. I set the gravity scale of the Ball to zero so that it doesn't fall down.
I added a force and bouncy Physics element to the ball. So it bounces back from walls and it goes to different directions.
Here is a screenshot of Game I'm working on:
MY QUESTION IS:
How can I add more force to the ball regardless of which direction it
bounces back?
<Note: I tried putting it inside FixedUpdate () method but the ball goes crazy because of constantly executing same function every frame. I was thinking of adding more force to the ball over time by using InvokeRepeating ( ) method later on to set time interval. If there is better idea of using other techniques, giving me a little advice will help me a lot>
Thank you !
I would recommend using a Coroutine or an InvokeRepeating. I would also recommend changing your code a bit.
rbBall.AddForce(rbBall.transform.right * ballForce)
The above snippet will add the ballForce in the direction the rbBall is moving.
Now for the two example snippets.
Coroutine
private float timeBeforeAddForce = 5f;
private void Start()
{
StartCoroutine(GradualAddForceToBall());
}
private IEnumerator GradualAddForceToBall()
{
// wait for 5 seconds
yield return new WaitForSeconds(timeBeforeAddForce);
// add the speed
rbBall.AddForce(rbBall.transform.right * ballForce)
// call the coroutine again
StartCoroutine(GradualAddForceToBall());
}
InvokeRepeating
private void Start()
{
InvokeRepeating("GradualAddForceToBall", 0.0f, timeBeforeAddForce);
}
private void GradualAddForceToBall()
{
rbBall.AddForce(rbBall.transform.right * ballForce)
}
If you want to change the current time of how long the speed is applied, I would go with the Coroutine as you can gradually decrease the timeBeforeAddingForce every time it enters the Coroutine.
I found the answer. You can force an object to be a specific speed while keeping its same movement direction - normalize the velocity (which sets the value to have a mangitude of 1) and then multiply it by your desired speed:
Here is the code:
public float currentSpeed = 5f;
void FixedUpdate()
{
//This will let you adjust the speed of ball using normalization
rbBall.velocity = rbBall.velocity.normalized * currentSpeed;
}
Adjust the currentSpeed variable to change it's speed.
""
I need the Player to follow the moving Target and stop exactly when it reaches the Target.
The Player has to reach the Target almost instantaneously in every frame, so i need a high speed way to do it.
I couldn't use Transform.translate because there's a lot of physics implementations in my game and using Transform.translate or movetowards made the physics buggy.
Is there any physics based way to follow the target? velocity, AddForce, anything? For a 2D game.
Any leads would be greatly appreciated! Thank You!
If you have a Rigidbody2D you want to follow another object, the Rigidbody2D.MovePosition is the proper way to move it.
Do the following:
1.Disable gravity by setting the "Gravity Scale" to 0.
2.Change the BodyType to Kinematic.
3.You can now move the Rigidbody object to follow another GameObject with the Rigidbody2D.MovePosition function. See code below. This should be done in the FixedUpdate function and with Time.fixedDeltaTime instead of Time.deltatime.
Finally, if you still get jerky movement, change Interpolate option from None to Interpolate or Extrapolate. I would also suggest reducing the speed variable below.
//Object to follow
public Transform target;
//Rigidbody to move
public Rigidbody2D rb2d;
public float speed = 7.0f;
//Distance to start moving
public float minDistance = 0.09f;
void FixedUpdate()
{
//Find direction
Vector3 dir = (target.transform.position - rb2d.transform.position).normalized;
//Check if we need to follow object then do so
if (Vector3.Distance(target.transform.position, rb2d.transform.position) > minDistance)
{
rb2d.MovePosition(rb2d.transform.position + dir * speed * Time.fixedDeltaTime);
}
}
Changing the velocity directly is always a bad practice and should be avoided. Instead always work with AddForce.
I would calculate the distance between the target and the body and add a force based on that distance.
var dif = target.transform.pos - body.transform.pos;
bodyRigid.AddForce(dif * multiplier * Time.deltatime);
The only problem that comes with that solution might be the fact that the body 'shakes' around the target once its to close.
You could avoid this by checking if the body is close to target and then freezing it.
var dif = target.transform.pos - body.transform.pos;
if(dif.magnitude > 1) {
bodyRigid.AddForce(dif * multiplier * Time.deltatime);
} else {
bodyRigid.velocity = Vector2.zero;
}
Although I said that setting the velocity directly is a bad habit, using it to just freeze the body should be fine. I have no idea whether that might break your other physics that you use in your game, duo the fact that that just strait up freezes your object.
You can also change the distance (1 in the if statement) that it needs in order to freeze, just play around with it a bit and find a value that fits the game
I am seeing a camera stutter when using smooth follow to lerp after my player with my camera in my multiplayer browser game. The player position is received from the server, the player lerps to that position, and my goal is for the camera to smoothly follow the player with its own, extra smoothing.
You can find my game at http://orn.io to see the current state, without smooth follow camera lerping, which is better but causes choppy movement and creates a headache. The current code for camera follow is:
void LateUpdate ()
{
if (Target == null) {
return;
}
currentScale = Mathf.Lerp(currentScale, -GameManager.TotalMass, Mathf.Clamp01 (Time.deltaTime * heightDamping));
Vector3 h = currentScale * 2f * Target.up;
Vector3 f = currentScale * 3f * Target.forward;
// tried lerping to this value but it causes choppy stutters
Vector3 wantedPosition = new Vector3(Target.position.x, Target.position.y, currentScale * 2) + h + f;
myTransform.position = wantedPosition;
myTransform.LookAt (Target, -Vector3.forward); // world up
}
and I have tried for days to tinker with the values, use fixed timestamps, put the camera movement in FixedUpdate/Update, use MoveTowards, and other changes, but am still experiencing issues.
Part of my problem that that the player position changes mid lerp, which causes a stutter since the target position changes in the middle of the lerp. This causes the camera to jump/sutter due to the target position of the lerp being changed in the middle of the lerp, and shakes due to the LookAt.
I would appreciate it if anyone could suggest a way to improve the camera following code as it stands now.
Is there any particular reason you need to use the Mathf.Lerp function?
Unity has a function, Vector3.SmoothDamp that is specifically designed for movement lerping:
void FixedUpdate() {
// Code for your desired position
transform.position = Vector3.SmoothDamp(transform.position, wantedPosition, ref moveVelocity, dampTime);
}
The above will smoothly follow the player by giving the SmoothDamp method control of the velocity variable. This is assuming that you supply it with a ref to store the current velocity and the damp time.
You can also adjust the damp time to change how smooth your transition is. This function will also automatically account for player movement mid-lerp.
To clarify, quoting from the documentation, dampTime in the above is:
Approximately the time it will take to reach the target. A smaller value will reach the target faster.
Also consider using Quaternion.slerp to smoothly rotate between the two rotations.
So I have tried several ways to fix a Mega-man 2 camera without actually figuring out a good way of doing it. So I would love if someone could give me some tips for I could solve this issue.
The problem: As I have written I want a Mega-man 2 camera (2D). The thing from it that I have not been able to solve is how to move it in Y like they do in Mega-man 2. What happens is that the camera does not move at all in Y, unless you go outside "camera bounds" and then it "freezes" the player and moves the camera down, see this video: https://youtu.be/NP697v8WtkU?t=5m2s (Hopefully it starts where the camera does this, otherwise go to 5:02).
But I can't get this to work in any good ways for me. What I have tried so far is, I have triggers at the top and bottom of the camera and when the player hit's one of them I start a coroutine where the camera should Lerp, however, it moves too much, so if I need to move it twice in the Y it would be all messed up. (My code is at the bottom but as I said, I need some help how I can fix it)
So please, if anyone have any idea how I can solve this, please let me know. I've been trying for several days without getting it to work perfectly.
public void ChangeY()
{
StartCoroutine(MoveCameraDown());
}
IEnumerator MoveCameraDown()
{
Vector3 CurrentCameraPos = Camera.main.transform.position;
Vector3 NewCameraPos = new Vector3(Camera.main.transform.position.x, Camera.main.transform.position.y - 5.6f, Camera.main.transform.position.z);
for (float t = 0.0f; t < 1; t += Time.deltaTime / 1.5f /* TIME IT SHOULD TAKE TO MOVE THE CAMERA DOWN */)
{
Camera.main.transform.position = Vector3.Lerp(CurrentCameraPos, NewCameraPos, t);
yield return null;
}
}
And as I have already written, I call the ChangeY() when I hit one of the triggers. This is just my testing case if you are wondering why some numbers are hardcoded and all that. But as I said, I have not been able to fix this so if anyone can help me I would really appreciate it.
It is actually easy to do. You asked for some tips and I will give you one.
Assuming you have already built your 2D world just like in the video you posted. There are many ways to solve this problem but I show you the way I consider to be the easiest. I have 5 steps for you to follow.
You need a value you can use each time to move down. Based on your code, you used -5.6f each time. The go down value should never be the same each time when the player touches the bottom trigger. It should be generated during run time.
This will be addressed in step 3.
1) If the player triggers the camera bottom trigger, first thing you should do is to stop the player, by disabling gravity then setting the rigidbody velocity and torque to zero.
For example inside your OnTriggerEnter function attched to the camera:
void OnTriggerEnter(Collider other) {
Rigidbody rgbd;
rgbd= other.gameObject.GetComponent<Rigidbody> ();
rgbd.useGravity = false;
rgbd.velocity = Vector3.zero;
rgbd.angularVelocity = Vector3.zero;
}
2) Immediately throw Ray cast downward(-y) using Physics.Raycast.
The origin position of the raycast should be the position of the player. For example,
GameObject gameOBjectHitFromRaycast;//Store Game Object detected from the raycast
RaycastHit hit;
if (Physics.Raycast(player.transform.position, Vector3.down, out hit)){
gameOBjectHitFromRaycast = hit.collider.gameObject;
}
The information of the object below the player will be stored in RaycastHit.
Use RaycastHit to get the information about the object that the player is about to land on.
3) After getting the information of that object the player is about to land on, get the y-axis position of that object then get the y-axis position of the player. Add them together then divide the result by 2. That is your new y position. The new position you need to move the camera to. For example,
Vector3 cameraNewPos = new Vector3(player.transform.position.x,(gameOBjectHitFromRaycast.transform.position.y+
camera.transform.position.y)/2,player.transform.position.z);
Basically, what we did here is to find the middle of the player's current position and the the landing position so that we can position the camera right in the middle of it. That should be do it but you can also subtract another number from the y-xis if that is not enough.
4) Use a coroutine function to move the camera smoothly to the new y axis position. Inside the corutine function, there should be public bool variable that will be used to determine if this function is done running(if camera is done moving).
Replace this function with the current camera move function you have
bool cameraMoving = false; //This variable can be used to determine when the camera is done moving
private IEnumerator MoveCameraDown (Vector3 toLocationPos, float timeToFinish)
{
float runTime = 0; //Dont change
float timer = 0; //Dont change
float tempDeltaTime;
cameraMoving = true;
//Will keep looping until camera is done moving
while (timer<timeToFinish) {
//Translate camera
Camera.main.transform.position = Vector3.Lerp (Camera.main.transform.position, toLocationPos, runTime);
tempDeltaTime = Time.deltaTime; //Get delta time once to be used multiple times to improve performance
runTime += tempDeltaTime / timeToFinish;
timer += tempDeltaTime; //Increement To exit loop
yield return null;
}
//Camera is done moving
cameraMoving = false;
}
Finally, to move the camera, you can just start the coroutine and pass in the new position calcluation in step 3 and also how much time you want it to take to do the moving. For example, we can pass in the cameraNewPos from step 3 and 2 for seconds it will take to move the camera.
StartCoroutine (MoveCameraDown (cameraNewPos , 2f));
5) When the camera is done moving, enable rigidbody gravity of the player with
Rigidbody rgbd;
rgbd= player.GetComponent<Rigidbody> ();
rgbd.useGravity = true;
I have a game that effectively has two paddles in it, and I've got it working set up so that either the players or an AI can control either paddle. However, I'm trying to figure out how to get my AI to actually smoothly run after the ball and catch it, instead of simply brute-forcing it with a basic "Direction of Ball" = Opposite direction AI moves.
In order to do so, I'm trying to write some code that will allow the AI to predict where it will land, when the ball is in it's court or going to be. It's not going that well. This is a diagram of what I want to achieve:
So, I've been studying Unity3D and came up with this:
Vector3 BallMinder = BallPosition.gameObject.rigidbody.velocity;
float BallX = BallMinder.x;
float BallY = BallMinder.y * Time.deltaTime;
float GroundHitPointX = (BallY + BallX);
Vector3 BallImpactPoint = new Vector3 (GroundHitPointX, 0, 0);
Debug.Log (BallImpactPoint);
Debug.DrawRay (BallImpactPoint, Vector3.up, Color.green);
However, I feel like I've oversimplified it or forgotten something. My calculations are way off, and the ray isn't showing up where it should, if it does at all. What have I gotten wrong?
All you need is the Kinematics equations.
These equations perfectly describe a projectile in motion. Therefore, you can use them to predict where and with what components the ball will land.
Here is a graph to help you understand.
This is going to be simplified by assuming that gravity is downward, and the floor is at Y=0. It could be expanded using vector math for arbitrary floorlines and gravity directions, but for your purposes you should be fine using the two aforementioned assumptions. I'm also assuming for this explanation that BallPosition is a Transform object, but the math would be the same if it weren't. I'm also assuming no air friction on the ball, which would make the math a fair bit more complicated.
Essentially, you need to calculate the time until the ball hits the ground and then extrapolate the ball's X-position at that time.
The classic formula dictating the motion of an accelerating object is d = vt + at^2 / 2, where v is the current velocity, a is the acceleration, and t is the amount of time that has passed. To figure out the time of impact, we simply solve for t.
To figure out when the ball will hit the ground you'll want to set d = BallPosition.position.y * -1, a = Physics.gravity.y, and v = BallPosition.rigidbody.velocity.y. This will give us the number of seconds until impact.
Since gravity is assumed to be entirely downward and no other forces are acting on the ball, we can know that the X-position of the ball at impact time is BallPosition.position.x + BallPosition.rigidbody.velocity.x * impactTime. This would be the X-position your computer player should move towards.
...The formula should work any time the gravity is entirely downward, even if the ball is on the upward portion of its trajectory or moving away from your computer player. You'll probably want to come up with some strategy for what the computer should do while waiting for the human to hit the ball and set the ball's new trajectory, since you probably don't want the computer to try to run towards the human's side of the net. Depending on how your players are able to hit the ball, you might be able to predict the new velocity the ball would have after the human hits it, and then feed that data to this formula.
essentialy you apply gravity to the ball at every step to make it seem natural something like this:
ball is at your position ready to be trown
ball.x = 20;
ball.y = 10;
xVelocity = 0;
yVelocity = 0;
gravity = 0.1;
you trow the ball
When you trow the ball you set xVelocity to a constant lets say 1 and yVelocity to 5. So:
xVelocity = 1;
yVelocity = 5;
ball.x+=xVelocity;
ball.y+=yVelocity; //to start the ball moving
Now in the gameloop you calculate the ball position like this:
tick
{
if(ball.y > 10) //if the ball is off the ground (i asume 10 is ground)
{
ball.x+=xVelocity;
ball.y+=yVelocity;
yVelocity-=gravity;
}
}
with this the ball should fly in a perfect arc now to calculate the landing zone you can simply do the same thing again with dummy numbers
while(dummyBall.y > 10)
{
dummyBall.x+=xVelocity;
dummyBall.y+=yVelocity;
yVelocity-=gravity;
}
landingPosX = dummyBall.x;
You will probably need to tweak the numbers but if i remember everything correctly it should work something like this. Hope it make sense