C# Camera Follow Player on X-axis - c#

I have a question like this. I want the camera to follow a player only on the x-axis. The simplest method is to make the MainCamera child for the target. This is a fairly easy method and makes the movement not with certain eruptions, or trembling, moving quite smoothly. The problem is that I would now like to make the MainCamera follow only on the x-axis. and I do not know how to do this condition.
Below you will see the code written by me, but this code does not work when the MainCamera is a child for the target.
/// <summary>
/// Follows to given target on specified axis
/// </summary>
public class FollowerCam : MonoBehaviour
{
public Transform target;
public bool followOnY = false;
public bool followOnX = false;
public bool constrainedOnX = false;
public bool constrainedOnY = false;
public float minY = 0f;
public float maxY = 0f;
public float minX = 0f;
public float maxX = 0f;
[ReadOnly]
public Vector3 offset;
private Vector3 originalPosition;
private void Start()
{
originalPosition = transform.position;
offset = transform.position - target.position;
}
private void Update()
{
if ((!followOnX && !followOnY) || target==null)
return;
transform.position = target.position + offset;
Vector3 normalizedPosition = transform.position;
if (followOnX)
{
if (constrainedOnX)
{
normalizedPosition.x = Mathf.Clamp(normalizedPosition.x, minX, maxX);
}
}
else
normalizedPosition.x = originalPosition.x;
if (followOnY)
{
if (constrainedOnY)
{
normalizedPosition.y = Mathf.Clamp(normalizedPosition.y, minY, maxY);
}
}
else
normalizedPosition.y = originalPosition.y;
normalizedPosition.z = originalPosition.z;
transform.position = normalizedPosition;
}
}
I can use this code by attaching it to the camera to follow a target, but the movement is very bad, especially when trying to make a target jump. I think this is a problem because the camera goes a little slower after the target. Help!!!

In this scenario I would suggest not having the camera as a child and just write a script to allow it to track. You can easily allow/disallow the y-movement this way and gives you a lot more freedom for camera movement down the road, should you need it.
public GameObject player; //assign player gameobject to variable in the inspector
public bool lockY = true;
private Vector3 offset;
private Vector3 tempVect;
void Start()
{
offset = transform.position - player.transform.position; //store initial camera offset.
}
void LateUpdate()
{
tempVect = player.transform.position + offset;
if (lockY) // toggle this to allow or disallow y-axis tracking
tempVect.y -= player.transform.position.y; // remove y component of player position
transform.position = tempVect;
}

Related

rb.AddForce() is launching my player in the opposite direction of the vector 2 value I assigned

Im making a game where you click and drag with the mouse then release to launch the player. But sometimes the player gets launched in the opposite direction of where it should go. I made a debug output to show you the different values. Here is the output
In that image for example you can see that the Vector2 of force * power is positive on the y axis, but the player launched downwards, and the same happens Viceversa. I think its also worth to note that this happens inconsistantly for some reason. Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Movement : MonoBehaviour
{
public GameObject player;
public float power = 10f;
public Rigidbody2D rb;
public float maxSpeed;
public Vector2 minPower;
public Vector2 maxPower;
TragectoryLine tl;
Camera cam;
public Vector2 force;
public Vector3 startPoint;
public Vector3 endPoint;
public Vector3 currentPoint;
public Vector3 startPointMouse;
public bool isPulling = false;
float distance;
private void Start()
{
cam = Camera.main;
tl = GetComponent<TragectoryLine>();
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
startPointMouse = cam.ScreenToWorldPoint(Input.mousePosition);
startPointMouse.z = 15;
}
if (Input.GetMouseButton(0))
{
startPoint = player.transform.position;
startPoint.z = 15;
isPulling = true;
Vector3 currentPoint = cam.ScreenToWorldPoint(Input.mousePosition);
currentPoint.z = 15;
tl.RenderLine(startPoint, currentPoint);
}
if (Input.GetMouseButtonUp(0))
{
endPoint = cam.ScreenToWorldPoint(Input.mousePosition);
endPoint.z = 15;
isPulling = false;
tl.EndLine();
distance = startPointMouse.magnitude - endPoint.magnitude;
if (distance < 0)
{
distance = -distance;
}
if (distance >= 1)
{
rb.AddForce(force * power, ForceMode2D.Impulse);
}
force = new Vector2(Mathf.Clamp(startPoint.x - endPoint.x, minPower.x, maxPower.x), Mathf.Clamp(startPoint.y - endPoint.y, minPower.y, maxPower.y));
Debug.Log("distance" + distance);
Debug.Log("start" + startPoint);
Debug.Log("end" + endPoint);
Debug.Log("force" +force);
Debug.Log("force * power" + force * power);
}
}
private void FixedUpdate()
{
rb.velocity = Vector3.ClampMagnitude(rb.velocity, maxSpeed);
}
}
Here I added the force using rb.AddForce(force * power, ForceMode2D.Impulse); when the force * power value was positive on the y axis. So why did it go to the opposite direction???
This was working perfectly fine before i tried implementing a feature where the player has to move the mouse a certain distance or else it wont launch. I have tried removing it but it doesnt seem to make a difference. I think I changed something in the code that ruined it but I cant figure out what! Please help!

Why the lerp function not working for the instantiated randomized Gameobjects?

The code helps in moving the game object in a continousy loop. I want the randomized generated cubes to follow the same pattern too. I didn't add the condition for stopping the generation of game objects when it completes one round. Currently, the generated game objects don't move.
The ultimate idea is to generate splash scene. I would like to know if the following way is gpu efficient too!
using UnityEngine;
using System.Collections.Generic;
public class IntegratedScrpt : MonoBehaviour
{
public List<GameObject> splashImagesGOList;
public float InvokeRate = 10f;
public GameObject cube01;
private int selection;
// Loop mode variables
private Vector3 startPosition;
private Vector3 endPosition;
private float distance = 54f;
private float distanceCovered;
private float currentDistance;
//for Vector Lerp
private float currentLerpTime = 0f;
private float lerpTime = 9f;
private float t;
void Start()
{
startPosition = splashImagesGOList[1].transform.position;
Debug.LogError("selection VALUE AT" + selection);
endPosition = Vector3.back * distance;
}
void Update()
{
InvokeRepeating("pickpoints", 1.0f, InvokeRate);
//loop mode
distanceCovered = Vector3.Distance(startPosition, endPosition);
currentDistance = distanceCovered * t;
currentLerpTime += Time.deltaTime;
if (currentLerpTime == lerpTime)
{
currentLerpTime = lerpTime;
}
if (currentLerpTime > lerpTime)
{
currentLerpTime = 0f;
}
t = currentLerpTime / lerpTime;
Move();
if (currentDistance == 64)
{
splashImagesGOList[selection].transform.position = startPosition;
Move();
}
Debug.LogError("SELECTION" + selection);
}
// method for making the gameobjects move
public void Move()
{
splashImagesGOList[selection].transform.position = Vector3.Lerp(startPosition, endPosition, t);
}
// code for instantiating the gameobjects
void pickpoints()
{
foreach (GameObject cube01 in splashImagesGOList)
{
int selection = UnityEngine.Random.Range(0, splashImagesGOList.Count);
// Instantiate(splashImagesGOList[selection], cube01.transform.position, cube01.transform.rotation);
Instantiate(splashImagesGOList[selection], startPosition, cube01.transform.rotation);
}
}
}
The reason the instantiated gameobjects aren't moving is because you're not assigning to any of their positions! splashImagesGOList[selection].transform.position is the position of one of the prefabs. In your current code, you instantiate the objects and then never interact with the instantiated objects.
You should have each object handle its own movement by separating out your movement logic into a different script and attaching the script to each of the prefabs in your list. You can use Mathf.Repeat to do the sort of looping your current code seems to mean to do.
Now, it's not clear what kind of pattern you are trying to achieve with the repeated simultaneous random instantiation but regardless of that, you probably don't mean to put InvokeRepeating in Update. Additionally, you should have some kind of end condition to cease the repeated PickPoints calls with CancelInvoke("PickPoints");. Creating an ever increasing number of objects is not gpu efficient ;)
Altogether, these changes might look like this:
public class SpashImageMover : MonoBehaviour
{
public Vector3 startPosition;
public Vector3 endPosition;
public float3 lerpTime;
private float t = 0; // in case code in Start is removed
void Start()
{
// remove these two lines if you don't want the objects synchronized
t = Mathf.Repeat(Time.time/lerpTime, 1f);
transform.position = Vector3.Lerp(startPosition, endPosition, t);
}
void Update()
{
t = Mathf.Repeat(t + Time.deltaTime / lerpTime, 1f);
transform.position = Vector3.Lerp(startPosition, endPosition, t);
}
}
public class IntegratedScrpt : MonoBehaviour
{
public List<GameObject> splashImagesGOList;
public float InvokeRate = 10f;
private int selection;
// Loop mode variables
private Vector3 startPosition;
private Vector3 endPosition;
//for Vector Lerp
private float lerpTime = 9f;
// end condition for PickPoints
private bool invokingPickPoints;
private float pickPointsTimeRemaining = 27f;
void Start()
{
startPosition = splashImagesGOList[1].transform.position;
Debug.LogError("selection VALUE AT" + selection);
endPosition = Vector3.back * distance;
InvokeRepeating("PickPoints", 1.0f, InvokeRate);
invokingPickPoints = true;
}
void Update()
{
if (invokingPickPoints)
{
pickPointsTimeRemaining -= Time.deltaTime;
if (pickPointsTimeRemaining <= 0 )
{
CancelInvoke("PickPoints");
invokingPickPoints = false;
}
}
}
// code for instantiating the gameobjects
void PickPoints()
{
foreach (GameObject cube01 in splashImagesGOList)
{
int selection = UnityEngine.Random.Range(0, splashImagesGOList.Count);
// Instantiate(splashImagesGOList[selection], cube01.transform.position, cube01.transform.rotation);
GameObject newGO = Instantiate(splashImagesGOList[selection], startPosition, cube01.transform.rotation);
SpashImageMover mover = newGO.GetComponent<SpashImageMover>();
mover.startPosition = startPosition;
mover.endPosition = endPosition;
mover.lerpTime = lerpTime;
}
}
}
As a sidenote, if you now find you don't like how you're instantiating the objects, that would be more appropriate for a different question with a very descriptive explanation of what you are trying to achieve. It's too broad of a question to try and address that here.

Return true if object is closer than a value. (Speherasting) in Unity

I have a script, for example, attached to a fire and I want to make damage to a player if he gets closer than a value to this fire.
public float fireDamageRange = 5;
public float fireDamage = 10;
private Vector3 origin;
private Vector3 direction;
void Update(){
origin = transform.position;
direction = transform.forward;
RaycastHit fireHit;
if (Physics.SphereCast(origin, fireDamageRange, direction, out fireHit) && fireHit.transform.gameObject.layer == LayerMask.NameToLayer("Player") && !makingDamage)
{
makingDamage = true;
MakeDamage(fireHit);
StartCoroutine(WaitToMakeDamage());
}
}
IEnumerator WaitToMakeDamage()
{
yield return new WaitForSecondsRealtime(0.2f);
makingDamage = false;
}
The script is attached to the fire.
This only returns true if the Player is actually fireDamageRange away of the origin, not if he gets closer. What am I doing wrong?
Just calculate the distance between the player and the fire and check if it's in range
The distance can be easily calculated using Vector3.Distance()
public float fireDamageRange = 5;
public float fireDamage = 10;
public GameObject player; // the player
private Vector3 origin;
private Vector3 direction;
void Update(){
float distance = Vector3.Distance(player.transform.position, transform.position);
if (distance <= fireDamageRange)
{
// handle damage to the player
}
}

In Unity3D, what is the best way to offset the viewport with multiple resolutions so the player is always to the left edge?

I'm working on my latest project, which is a action sidescroller, primarily 2D but using a perspective camera for 3D effect. I've gotten the basics working - design, etc, and now fixing the camera so that it follows correctly. However, I'd like to keep the player on the left side of the viewport - not actually modifying the player's position, but the camera following an offset. I have it partially worked out, but it broke the moment I started playing around with other alternative resolutions - say, from web standard, standalone, to mobile devices. This is what I want to do:
This is my code attempt thus far. The camera itself works perfectly for basic up/down right scrolling, but when the resolution changes the player can vanish:
public Transform TrackTarget;
public float dampTime = 0.15f;
public bool Ready = false;
private Vector3 velocity = Vector3.zero;
private Vector3 TargetOffset = Vector3.zero;
void Start()
{
TargetOffset = new Vector3(16,0,0);
Vector3 point = TrackTarget.position + TargetOffset;
Vector3 Destination = new Vector3(point.x, transform.position.y, transform.position.x);
transform.position = Destination;
}
void FixedUpdate () {
if (Ready) {
if (TrackTarget)
{
Vector3 point = TrackTarget.position + TargetOffset;
Vector3 Destination = new Vector3(point.x, transform.position.y, transform.position.x);
transform.position = Vector3.SmoothDamp(transform.position, Destination, ref velocity, dampTime);
}
}
}
void LateUpdate()
{
if (Ready) {
Vector3 CameraPosition = transform.position;
CameraPosition.z = -30.00f;
transform.position = CameraPosition;
}
}
This may be helpful.
public class CameraController : MonoBehaviour {
public Transform target;
public float distance = 5;
public float heigt = 1;
public float width = 6;
public float damping = 5;
void Start()
{
Vector3 unicornPos = camera.WorldToViewportPoint(target.position);
width = camera.ViewportToWorldPoint(new Vector3(1, 1, camera.nearClipPlane)).x/3;
}
void LateUpdate () {
Vector3 wantedPosition = target.TransformPoint (width, heigt, -distance);
transform.position = Vector3.Lerp (transform.position, wantedPosition, Time.deltaTime * damping);
}
}

Accelerate and decelerate to finger position

I have a 3D object on Unity and what I want is simply move this object as soon as the user presses the screen. The problem is that it needs to accelerate first and then, when it is reaching the pressed position, it starts decelerating until it totally stops on that point.
I need this to work in a way that if the user moves his finger, the object will recalculate if it needs to accelerate/decelerate based on his current condition.
I tried this example but, it only works for acceleration and it also seems a little confusing. So, I was thinking if someone else have a better and simple idea to solve this. Can physics help with this? If so, how?
My code is in C#.
Using unity rigidbody system and simple calculate. This is using mouse position, you can change it to touch.
public class MyDragMove : MonoBehaviour {
public float speedDelta = 1.0f;
public float decelerate = 1.0f;
private bool startDrag;
private Vector3 prePos;
void Update () {
this.rigidbody.drag = decelerate; //Rigidbody system can set drag also. You can use it and remove this line.
if (Input.GetKeyDown (KeyCode.Mouse0)) {
prePos = Input.mousePosition;
startDrag = true;
}
if(Input.GetKeyUp(KeyCode.Mouse0))
startDrag = false;
if(startDrag)
ForceCalculate();
}
void ForceCalculate()
{
Vector3 curPos = Input.mousePosition;
Vector3 dir = curPos - prePos;
float dist = dir.magnitude;
float v = dist / Time.deltaTime;
this.rigidbody.AddForce (dir.normalized * v * Time.deltaTime * speedDelta);
prePos = curPos;
}
}
or just use SmoothDamp toward last position.
public class MyDragMove : MonoBehaviour {
public float speedDelta = 1.0f;
public float maxSpeed = 5.0f;
public Vector3 v;
private Vector3 prePos;
void Update () {
if(Input.GetKey(KeyCode.Mouse0))
prePos = Input.mousePosition;
TowardTarget ();
}
void TowardTarget()
{
Vector3 targetPos = Camera.main.ScreenToWorldPoint (new Vector3(prePos.x, prePos.y, 10f)); //Assume your camera's z is -10 and cube's z is 0
transform.position = Vector3.SmoothDamp (transform.position, targetPos, ref v, speedDelta, maxSpeed);
}
}

Categories

Resources