Something similar to either Rocket League or Kingdom Hearts, where the camera locks onto the target but it still keeps the player in the center of the screen. I've placed the camera as a child of the player, but after trying out various solutions from others I'm still unable to position the camera correctly.
public List<Transform> targets;
private void EnemyCam()
{
Vector3 centerPoint = GetCenterPoint();
transform.LookAt(centerPoint);
Vector3 newPos = centerPoint;
transform.position = Vector3.SmoothDamp(transform.position, newPos, ref
velocity, smoothTime);
}
private Vector3 GetCenterPoint()
{
if (targets.Count == 1)
return targets[0].position;
var bounds = new Bounds(targets[0].position, Vector3.zero);
for (int i = 0; i < targets.Count; ++i)
bounds.Encapsulate(targets[i].position);
return bounds.center;
}
If you are moving you camera by script, it shouldn't be child of the moving player at the same time. You are setting up some position from script, but at the same time, this position is modified also by parent object so final result is unpredictable.
Related
I make a 2d line renderer reflection on a specific object tag, it's working but only on the left side when on the right side the reflection is not showing, I don't have any idea why because when my script is on 3d it's working fine.
this is a script that I convert from 3D and I change it all to 2D.
public int reflections;
public float maxLength;
private LineRenderer lineRenderer;
public LayerMask layerMask;
private Ray2D ray;
private RaycastHit2D hit;
private void Awake()
{
lineRenderer = GetComponent<LineRenderer>();
}
private void Update()
{
ray = new Ray2D(transform.position, transform.up);
lineRenderer.positionCount = 1;
lineRenderer.SetPosition(0, transform.position);
float remainingLength = maxLength;
for (int i = 0; i < reflections; i++)
{
hit = Physics2D.Raycast(ray.origin, ray.direction, remainingLength, layerMask);
if (hit)
{
lineRenderer.positionCount += 1;
lineRenderer.SetPosition(lineRenderer.positionCount - 1, hit.point);
remainingLength -= Vector2.Distance(ray.origin, hit.point);
ray = new Ray2D(hit.point, Vector2.Reflect(ray.direction, hit.normal));
if (hit.collider.tag != "Reflect")
break;
}
else
{
lineRenderer.positionCount += 1;
lineRenderer.SetPosition(lineRenderer.positionCount - 1, ray.origin + ray.direction * remainingLength);
}
}
}
PREVIEW
When going to the right.
When going to left.
Sometimes it flickers too, I don't have any idea how this happens, I thought it was because order layer I have changed this but nothing happen.
In regard to the flickering, this is occuring due to a clipping issue with the collided object and the line itself.
Inside of the condition:
if (hit)
Adjust the code to be the following:
// Get the reflected vector of the raycast.
Vector2 updatedDirection = Vector2.Reflect(ray.direction, hit.normal);
// Create new Ray object & set origin to be 0.01f away from hitpoint so the line is not colliding with the gameobject collider.
ray = new Ray2D(hit.point + updatedDirection * 0.01f, updatedDirection);
You can find out more from these links:
https://answers.unity.com/questions/1602542/line-renderer-flickering-when-updated-in-runtime.html
https://answers.unity.com/questions/1690411/help-with-reflecting-in-2d.html?childToView=1690554#comment-1690554
As for the reason the line is not reflecting on the right wall, this is more than likely due to the gameObjects tag not being set to "Reflect". You are only creating a new reflected line when colliding with an object with that tag. Double check that the right walls gameObject has the tag "Reflect" set in the inspector.
In Unity 3D I'd like to create a crosshair for my top-down 2D-shooter that gradually moves to its target whenever the player has the same x-position as the target.
The problem is that I want a smooth animation when the crosshair moves to the target. I have included a small gif from another game that shows a crosshair I'd like to achieve. Have a look at it:
Crosshair video
I tried to do that with the following script but failed - the crosshair jumps forth and back when the enemies appear. It doesn't look so smooth like in the video I mentioned above.
The following script is attached to the player:
[SerializeField]
private GameObject crosshairGO;
[SerializeField]
private float speedCrosshair = 100.0f;
private Rigidbody2D crosshairRB;
private bool crosshairBegin = true;
void Start () {
crosshairRB = crosshairGO.GetComponent<Rigidbody2D>();
crosshairBegin = true;
}
void FixedUpdate() {
//Cast a ray straight up from the player
float _size = 12f;
Vector2 _direction = this.transform.up;
RaycastHit2D _hit = Physics2D.Raycast(this.transform.position, _direction, _size);
if (_hit.collider != null && _hit.collider.tag == "EnemyShipTag") {
// We touched something!
Debug.Log("we touched the enemy");
Vector2 _direction2 = (_hit.collider.gameObject.transform.position - crosshairGO.transform.position).normalized;
crosshairRB.velocity = new Vector2(this.transform.position.x, _direction2.y * speedCrosshair);
crosshairBegin = false;
} else {
// Nothing hit
Debug.Log("nothing hit");
crosshairRB.velocity = Vector2.zero;
Vector2 _pos2 = new Vector2(this.transform.position.x, 4.5f);
if (crosshairBegin) crosshairGO.transform.position = _pos2;
}
}
I think you need create a new variable call Speed translation
with
speed = distance from cross hair to enemy position / time (here is Time.fixedDeltaTime);
then multiply speed with velocity, the cross hair will move to enmey positsion in one frame.
but you can adjust speed by mitiply it with some float > 0 and < 1;
I'm trying to make a dotted line that shows where the balls going to land and reflect from there. I'm using unity's physics system.
I think something is wrong with circle cast and line renderer.
The balls are spawning thru wherever i click with my mouse. So i do not see any problem on BallCreate() function.
Here is the problem.
The Problem
As you can see in the picture, balls instantiated on transform.position and going thru hit.point. Somehow line-renderer and ball direction is not the same. There is always a little bit difference(Sometimes more).
The code is below:
I'm trying to fix this for a week, any help means so much.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public Transform BallPrefab = null;
bool ShootDirected = true;
Vector3 mousePos;
private LineRenderer linerender;
RaycastHit2D hitx;
private Vector3 dir;
private Vector3 origin;
void Start()
{
linerender = GetComponent<LineRenderer>();
}
void Update()
{
mousePos = new Vector3(Camera.main.ScreenToWorldPoint(Input.mousePosition).x, Camera.main.ScreenToWorldPoint(Input.mousePosition).y, 0);
//Direction according to mouse position.
dir = mousePos - transform.position;
origin = transform.position;
//First hit point 0.3307159f is the radius of the ball.
RaycastHit2D hit = Physics2D.CircleCast(origin, 0.3307159f, dir, 100f, 1 << 9 | 1<<10);
if (hit.collider != null)
{
//Stored reflected hit point.
Vector2 reflectDir = Vector2.Reflect(dir, hit.normal);
//Then start second ray from hit point thru reflected hit point.
RaycastHit2D SecondHit = Physics2D.CircleCast(hit.point, 0.3307159f, reflectDir, 100, 1 << 9 | 1<<10);
//Draw lines beetween origin, hit.point and secondhit point.
linerender.SetPosition(0, origin);
linerender.SetPosition(1, hit.point);
linerender.SetPosition(2, SecondHit.point);
}
//Create 50 balls when mouse clicked.
if (Input.GetMouseButtonUp(0))
{
ShootDirected = true;
StartCoroutine("BallCreate");
}
}
IEnumerator BallCreate()
{
Vector3 shootDirection = new Vector3(0,0,0);
//Create 50 balls
for (int i = 0; i < 50; i++)
{
Transform ball = Instantiate(BallPrefab, transform.position, Quaternion.identity) as Transform;
Rigidbody2D rb = ball.GetComponent<Rigidbody2D>();
if (ShootDirected)
{
//Set shootDirection to mouse position
shootDirection = Input.mousePosition;
shootDirection.z = 0.0f;
shootDirection = Camera.main.ScreenToWorldPoint(shootDirection);
//Get direction.
shootDirection = (shootDirection - transform.position);
ShootDirected = false;
}
//Apply force to each ball thru mouse direction.
rb.velocity = new Vector2(shootDirection.x, shootDirection.y);
rb.velocity = 7f * (rb.velocity.normalized);
yield return new WaitForSeconds(0.08f);
}
}
}
Found the problem with help of MelvMay on Unity Technologies.
Simply change
`RaycastHit2D SecondHit = Physics2D.CircleCast(hit.point, 0.3307159f, reflectDir, 100, 1 << 9 | 1<<10);`
to
RaycastHit2D SecondHit = Physics2D.CircleCast(hit.centroid, 0.3307159f, reflectDir, 100, 1 << 9 | 1<<10);
MelvMay's explanation;
If you look at the RaycastHit2D docs you'll see both a "point" property (which you're using) which is the actual position the shapes intersected. For a ray this is obvious as it has no size. For a shape such as a circle, this isn't the position the circle is when it intersects, it's the point on its exterior. For all the casts, you can use the "centroid" property for this. This returns the position of the shape when it is in contact. For a Line/Ray, both the "point" and "centroid" properties are identical but for (say) a circle, box, capsule or polygon, these will be different.
Problem
I have a spawn manager written in c# which spawns my game object, i use screen.width, to set the maximum screen with and -screen.width to set the minimum screen width for the spawning, but my game object spawns way off the screen.
I am using a portrait camera 2:3 instead of free aspect as my camera view, as i want my game to be in portrait mode
how do i make my game object spawn within the camera widths(max and min)?
my code
public class SpawnManager : MonoBehaviour {
public int maxBalloons = 100;
public GameObject balloon;
public float horizontalMin = -Screen.width;
public float horizontalMax = Screen.width;
public float verticalMin = -5.0f;
public float verticalMax = 1.0f;
private Vector2 originPosition;
void Start () {
originPosition = transform.position;
Spawn ();
}
void Spawn()
{
for (int i = 0; i < maxBalloons; i++)
{
Vector2 randomPosition = originPosition + new Vector2 (Random.Range(horizontalMin, horizontalMax), Random.Range (verticalMin, verticalMax));
Instantiate(balloon, randomPosition, Quaternion.identity);
originPosition = randomPosition;
}
}
}
Edit
I changed
Vector2 randomPosition = originPosition + new Vector2 (Random.Range(horizontalMin, horizontalMax), Random.Range (verticalMin, verticalMax));
To
Vector2 randomPosition =Camera.ScreenToWorldPoint (originPosition + new Vector2 (Random.Range(horizontalMin, horizontalMax), Random.Range (verticalMin, verticalMax)));
Still did not work as it should
A position on your screen with a X smaller than 0 will be always out of your screen. The bottom left corner of your screen is the origin of your the coordinate (x: 0, y: 0)
But here I think you mingled 2 kinds of positions. The position on your screen, is not the same position in the world space of your scene. It depends where the camera is rendering.
The position on the bottom left corner of your screen will not be x:0 y:0 in the world space.
To achieve what you are looking for you need to transform the position on the left and the right of your camera into worldspace positions.
Use Camera.ScreenToWorldPoint to achieve that : https://docs.unity3d.com/ScriptReference/Camera.ScreenToWorldPoint.html
I'm playing around with VR a bit, so far I can move a character around and such. However the position of the camera is changing. I want my camera to be in a fixed position and only be able to change up/down position and the normal rotation with the HMD.
void Start ()
{
startPos = transform.localPosition;
parentObj = transform.root;
}
void Update()
{
ResetVR();
}
void ResetVR()
{
if (parentObj != null)
{
startPos -= InputTracking.GetLocalPosition(VRNode.CenterEye);
transform.localRotation = Quaternion.Inverse(parentObj.localRotation);
}
}
With this my character rotates normally but the camera won't stay in a fixed position.
For example, if I rotate 90 degrees, the camera ends up left of the character. I want the camera stay in a fixed position.
You only want to up/down. This is the-same as rotating around x-axis only. Get the original position. Convert the Quaternion to angle then rotate with transform.localEulerAngles instead of transform.localRotation.Overwrite the other two axis(y,z) with originalPos variables before rotating. You may need to modify this to get it working properly.
Transform parentObj;
Vector3 startPos;
Vector3 originalPos;
void Start()
{
startPos = transform.localPosition;
originalPos = transform.localPosition;
parentObj = transform.root;
}
void Update()
{
ResetVR();
}
void ResetVR()
{
if (parentObj != null)
{
startPos -= InputTracking.GetLocalPosition(VRNode.CenterEye);
Quaternion tempRot = Quaternion.Inverse(parentObj.localRotation);
Vector3 newAngle = tempRot.eulerAngles;
transform.localEulerAngles = new Vector3(newAngle.x, originalPos.y, originalPos.z);
}
}
You might want to have a look at this rule.
See Unity's documentation about this.