Move and Rotate LineRenderer with Transform property - c#

You can rotate any visual Object in Unity with the Transform property. One exception is the LineRenderer. You can't move or rotate it with the transform property.
LineRenderer is moved with the SetPosition or SetPositions function so I managed to make it movable by the transform position property but I can't make make it rotate too.
Below is the code I am using to make it movable.
public Vector3 beginPos = new Vector3(-1.0f, -1.0f, 0);
public Vector3 endPos = new Vector3(1.0f, 1.0f, 0);
Vector3 beginPosOffset;
Vector3 endPosOffset;
LineRenderer diagLine;
void Start()
{
diagLine = gameObject.AddComponent<LineRenderer>();
diagLine.material = new Material(Shader.Find("Sprites/Default"));
diagLine.startColor = diagLine.endColor = Color.green;
diagLine.startWidth = diagLine.endWidth = 0.15f;
diagLine.SetPosition(0, beginPos);
diagLine.SetPosition(1, endPos);
//Get offset
beginPosOffset = transform.position - diagLine.GetPosition(0);
endPosOffset = transform.position - diagLine.GetPosition(1);
}
void Update()
{
//Calculate new postion with offset
Vector3 newBeginPos = transform.position + beginPosOffset;
Vector3 newEndPos = transform.position + endPosOffset;
//Apply new position with offset
diagLine.SetPosition(0, newBeginPos);
diagLine.SetPosition(1, newEndPos);
}
I tried to use the-same method I used to make it able to rotate but I am stuck in the first step of getting the offset because there is no way to access the rotation variable for LineRenderer but there is one for accessing the position GetPosition.
How can I get the LineRenderer rotation or how can I also make LineRenderer be rotated from the Transform property?
Below is an image that shows the behavior of LineRenderer with and without the script above. Position is now working with the script above enabled but rotation is not.

You can use the transform's localToWorldMatrix:
void Start()
{
diagLine = gameObject.AddComponent<LineRenderer>();
diagLine.material = new Material(Shader.Find("Sprites/Default"));
diagLine.startColor = diagLine.endColor = Color.green;
diagLine.startWidth = diagLine.endWidth = 0.15f;
diagLine.SetPosition(0, beginPos);
diagLine.SetPosition(1, endPos);
}
void Update()
{
//Calculate new postion
Vector3 newBeginPos = transform.localToWorldMatrix * new Vector4(beginPos.x, beginPos.y, beginPos.z, 1);
Vector3 newEndPos = transform.localToWorldMatrix * new Vector4(endPos.x, endPos.y, endPos.z, 1);
//Apply new position
diagLine.SetPosition(0, newBeginPos);
diagLine.SetPosition(1, newEndPos);
}

You can set useWorldSpace attribute of LineRenderer to false, Then LineRenderer can be controlled using its transform component.
https://answers.unity.com/questions/39391/line-renderer-position.html

Related

¿How to get the bottomLeft and the topRight bounds of an sprite in Unity?

First, i will explain myself...
I was trying to make an script for the camera to follow the player and keep itself inside the Map.
After a litle research i found out that you can use a property of tileMap called tileMap.localBounds.min to find the bottomLeft corner and tileMap.localBounds.max to find the topRight corner of a tilemap.
The problem with that is that my map is not a tileMap, it`s a sprite.
So i try the following...
public Transform target;
public GameObject theMap;
private Vector3 bottomLeftLimit;
private Vector3 topRightLimit;
// These values are for the camera
private float halfHeight;
private float halfWidth;
void start()
{
target = PlayerController.instance.transform;
halfHeight = Camera.main.orthographicSize;
halfWidth = halfHeight * Camera.main.aspect;
// We assign the corners of our map
// Maybe we`ll have to change the image for a tileMap to use: tileMap.localBounds
bottomLeftLimit = theMap.GetComponent<SpriteRenderer>().sprite.bounds.min + new Vector3(halfWidth, halfHeight, 0f);
topRightLimit = theMap.GetComponent<SpriteRenderer>().sprite.bounds.max + new Vector3(-halfWidth, -halfHeight, 0f);
// We send the bound limits to the PlayerController script to keep the player inside the map
PlayerController.instance.SetBounds(theMap.GetComponent<SpriteRenderer>().sprite.bounds.min, theMap.GetComponent<SpriteRenderer>().sprite.bounds.max);
}
void LateUpdate()
{
transform.position = new Vector3(target.position.x, target.position.y, transform.position.z);
// Keep the camera inside the bounds
transform.position = new Vector3(Mathf.Clamp(transform.position.x, bottomLeftLimit.x, topRightLimit.x), Mathf.Clamp(transform.position.y, bottomLeftLimit.y, topRightLimit.y), transform.position.z);
}
But it seems that the value of sprite.bounds.max and sprite.bounds.min are always 0 (the center), so it doesn`t work to set the bounds for the camera.
Anyone can help? I would aprecciate it a lot...
SpriteBoundsFinder.cs
using UnityEngine;
using UnityEngine.UI;
public class SpriteBoundsFinder : MonoBehaviour
{
public Image image;
private void Update()
{
var rectTransform = image.GetComponent<RectTransform>();
var sizeDelta = rectTransform.sizeDelta;
var position = image.transform.position;
var bottomLeft = position - new Vector3(sizeDelta.x / 2, sizeDelta.y / 2);
var topRight = position + new Vector3(sizeDelta.x / 2, sizeDelta.y / 2);
Debug.Log($"bottomLeft: {bottomLeft}, topRight: {topRight}");
}
}
You can use this to find the bottom left and top right corner of a sprite in world space. Assuming you're using an overlay canvas. If not, let me know.
The reason this works is because a sprite will always be stretched to have the same width and height as the RectTransform of its Image component's GameObject.

Shooting a projectile but goes in wrong direction - 2D game

I am trying to make a simple game where I am shooting a projectile when the user touches the screen, I first spawn 8 projectiles (sprites) and when the user touches the screen I would like the top projectile to fly in the touch direction. I was able to do this; However, every time I shoot, the projectile goes in the wrong direction, here is an image which will illustrate the issue.
Obviously the image is still here but the object will continue flying until it goes out of the screen and then gets destroyed.
Here is the code snippet that handles this
GameplayController.cs
if (Input.GetMouseButtonDown(0))
{
Vector3 position = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0);
position = Camera.main.ScreenToWorldPoint(position);
GameObject target;
target = new GameObject();
target.transform.position = position;
Arrow comp = currentArrows[0].GetComponent<Arrow>();
comp.setTarget(target.transform);
comp.GetComponent<Arrow>().arrowSpeed = 12;
comp.GetComponent<Arrow>().shoot = true;
currentArrows.RemoveAt(0);
Destroy(target);
}
I know I am getting the mouse input here and not the phone touch and that's fine for me, later I will convert it to the touch input.
Arrow.cs
public bool shoot = false;
public float arrowSpeed = 0.0f;
public Vector3 myDir;
public float speed = 30.0f;
private Transform target;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if(shoot)
{
transform.position += transform.right * arrowSpeed * Time.deltaTime;
}
}
public void setTarget(Transform targetTransform)
{
this.target = targetTransform;
Vector3 vectorToTarget = target.position - transform.position;
float angle = Mathf.Atan2(vectorToTarget.y, vectorToTarget.x) * Mathf.Rad2Deg;
Quaternion q = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = Quaternion.Slerp(transform.rotation, q, Time.deltaTime * speed);
}
private void OnBecameInvisible()
{
print("Disappeared");
Destroy(gameObject);
Gameplay.instance.isShooting = false;
}
Vector3 position = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0);
I think that your problem is that you're getting the screen coordinates by click, not the world coordinates, which is actually two different things. In order to direct your projectile correctly you need to convert your screen coordinates to world like it's done here.
The next thing is how you move the projectile:
transform.position += transform.right * arrowSpeed * Time.deltaTime;
You're moving the projectile to the right and then rotating it somehow. Maybe you should try to move it with Vector3.Lerp, which will be easier and rotate it with Transform.LookAt.

freezing the y position of the camera in unity3d

I am making a plat former game and I'm having a problem in the camera position of the game im imitating the camera movement of the 1st version of the super mario bros but every time I move my character the camera will go up until the character will disappear. How can I fix it?
public Transform playerPos;
public Transform rigthCamBoundary;
public Transform levelEnd;
Vector3 destination;
Vector3 velocity = Vector3.zero;
private void Start()
{
destination = Vector3.ClampMagnitude(levelEnd.position, 22.8f);
destination = new Vector3(destination.x, destination.y, 13.5f);
}
private void FixedUpdate()
{
if (Vector3.Distance(playerPos.position, rigthCamBoundary.position) < 13.7f)
transform.position = Vector3.SmoothDamp(transform.position, levelEnd.position, ref velocity, .14f, 8.5f);
}
To freeze the y-axis, get the y-axis value when the game runs. After using Vector3.SmoothDamp, change the y-axis to that variable you got before then apply it to your transform.
public Transform playerPos;
public Transform rigthCamBoundary;
public Transform levelEnd;
Vector3 destination;
Vector3 velocity = Vector3.zero;
float yPos;
private void Start()
{
destination = Vector3.ClampMagnitude(levelEnd.position, 22.8f);
destination = new Vector3(destination.x, destination.y, 13.5f);
//Get the default camera y pos
yPos = transform.position.y;
}
private void FixedUpdate()
{
if (Vector3.Distance(playerPos.position, rigthCamBoundary.position) < 13.7f)
{
Vector3 tempPos = Vector3.SmoothDamp(transform.position, levelEnd.position, ref velocity, .14f, 8.5f);
//Apply the default camera y pos
tempPos.y = yPos;
transform.position = tempPos;
}
}
Note that I don't know if this code is attached to the camera but this answer assumes it is. Otherwise the solution still remains the-same but you just have to change transform.position.y and transform.position to something else.

How to spawn object on mouse position?

When I click right click I want to create new sphere. And I don't know why this don't work. It creates a sphere, but definitely not on mouse position!
Vector2 mousePos;
public Transform mousePointer;
float mouseX, mouseY;
Vector3 spawnPoint;
void Start () {
}
void Update () {
if(Input.GetMouseButtonDown(1)){
mousePos = Input.mousePosition;
mouseX = Input.mousePosition.x;
mouseY = Input.mousePosition.y;
spawnPoint = new Vector3(mouseX, mouseY, 0);
Instantiate(mousePointer, spawnPoint, Quaternion.identity);
}
}
Try spawning the object relative to the camera.
For example, use spawnPoint = cameraPosition + new Vector3(mouseX, mouseY, 0); or something similar. Check out the related post: Create a cube relative to camera mouse position.
The object is being spawned in global coordinates.

How to use a mathematic equation to stop object going off screen?

[SOLVED]
I've been following the Learn To Code By Making Games course (Block Breaker Section) from Udemy and I have a flippin' annoying issue. My paddle doesn't clamp properly to the values I put in. I would have had no trouble with this but I decided that I want a small menu on the left side with a speed controller, sound controller and lives. This means I cant just say that I want the paddle to stop on the edge of the screen.
​Observed Behavior:
​The paddle does not constrain itself to the area I put in. As the screen size changes the paddle will either go off the screen or will be stopped somewhere like the middle of the screen.
​What I Want It To Do:
​I want the paddle to stop when it hits the edge of my menu on the left and to stop when it hits the screen on the right. I also want this to stay the same as my screen size changes. So basically I need a mathematic equation that can determine these points and it needs to be able to adjust based on the screen size.
Here is my code for the paddle:​
using UnityEngine;
using System.Collections;
public class Paddle : MonoBehaviour {
public Texture texture;
public void Update () {
Vector3 paddlePos = new Vector3 (0.5f, this.transform.position.y , 0f);
float mousePosInBlocks = Input.mousePosition.x;
paddlePos.x = Mathf.Clamp(mousePosInBlocks, //Left Vaule, //Right Value);
this.transform.position = paddlePos;
}
}
this happens because Input.mousePosition returns position of mouse on screen, not in world space. just convert mousePosition into world position, and then assign its value to mousePosInBlocks.
using UnityEngine;
using System.Collections;
public class Paddle : MonoBehaviour {
public Texture texture;
public void Update () {
Vector3 paddlePos = new Vector3 (0.5f, this.transform.position.y , 0f);
float mousePosInBlocks = Camera.main.ScreenToWorldPoint(Input.mousePosition).x;
paddlePos.x = Mathf.Clamp(mousePosInBlocks, leftValue, rightValue);
this.transform.position = paddlePos;
}
}
Edit: Sorry, not WorldToScreenPoint, ScreenToWorldPoint
Try just setting the paddlePos to the new vector you're creating (in world space):
public Texture texture; // if needed for something outside this code
private Vector3 paddlePos;
private float mousePosInBlocks;
private float xValue;
private float leftValue;
private float rightValue;
public void Update () {
mousePosInBlocks = Camera.main.ScreenToWorldPoint(Input.mousePosition).x;
//compute leftValue on this line
//compute rightValue on this line
xValue = Mathf.Clamp(mousePosInBlocks, leftValue, rightValue);
paddlePos = new Vector3 (xValue, transform.position.y , 0f);
transform.position = paddlePos;
}
EDIT Based on updated question title, the following should work:
public Texture texture; // if needed for something outside this code
private Vector3 playerPosOnScreen;
private float mousePosInBlocks;
public void Update () {
playerPosOnScreen = Camera.main.WorldToScreenPoint(transform.position);
if (playerPosOnScreen.x > Screen.Width) {
transform.position = Camera.main.ScreenToWorldPoint (new Vector3 (Screen.Width, transform.position.y, transform.position.z);
} else if (playerPosOnScreen.x < 0f) {
transform.position = Camera.main.ScreenToWorldPoint (new Vector3 (0f, transform.position.y, transform.position.z);
}
}
Try something like this: (pseudo code, untested, to give you an idea)
Please check the comment for each step.
public void Update () {
// left bound
Vector3 left = Camera.main.ViewPortToScreenPoint(new Vector3(0f, 0f, 0f));
// Menu width
left.x += fmyMenuWidth; // Width of menu
// Right bound
Vector3 right= Camera.main.ViewPortToScreenPoint(new Vector3(1f, 1f, 0f));
// Temporary position vector
Vector3 paddlePos = Vector3.zero;
// capture mouse x
float mouseX = Camera.main.ScreenToWorldPoint(Input.mousePosition).x;
// capture mouse y
float mouseY= Camera.main.ScreenToWorldPoint(Input.mousePosition).y;
// Combine and limit the position's X-value, should not go off screen menu's width---->screen's width
paddlePos.x = Mathf.Max(Mathf.Min(right.x, mouseX), left.x);
// Combine and limit the position's Y-value, should not go off screen 0---->screen's height
paddlePos.y = Mathf.Max(Mathf.Min(right.y, mouseY), left.y);
// Finally set the bounded position
this.transform.position = paddlePos;
}

Categories

Resources