I want to draw some lines by dragging the mouse. I did that using this script .
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class DrawLine : MonoBehaviour
{
private LineRenderer line;
private bool isMousePressed;
private List<Vector3> pointsList;
private Vector3 mousePos;
// Structure for line points
struct myLine
{
public Vector3 StartPoint;
public Vector3 EndPoint;
};
// -----------------------------------
void Awake()
{
// Create line renderer component and set its property
line = gameObject.AddComponent<LineRenderer>();
line.material = new Material(Shader.Find("Particles/Additive"));
line.SetVertexCount(0);
line.SetWidth(0.1f,0.1f);
line.SetColors(Color.green, Color.green);
line.useWorldSpace = true;
isMousePressed = false;
pointsList = new List<Vector3>();
// renderer.material.SetTextureOffset(
}
// -----------------------------------
void Update ()
{
// If mouse button down, remove old line and set its color to green
if(Input.GetMouseButtonDown(0))
{
isMousePressed = true;
line.SetVertexCount(0);
//pointsList.RemoveRange(0,pointsList.Count);
line.SetColors(Color.green, Color.green);
}
else if(Input.GetMouseButtonUp(0))
{
isMousePressed = false;
}
// Drawing line when mouse is moving(presses)
if(isMousePressed)
{
mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
mousePos.z=0;
if (!pointsList.Contains (mousePos))
{
pointsList.Add (mousePos);
line.SetVertexCount (pointsList.Count);
line.SetPosition (pointsList.Count - 1, (Vector3)pointsList [pointsList.Count - 1]);
if(isLineCollide())
{
isMousePressed = false;
line.SetColors(Color.red, Color.red);
}
}
}
}
// -----------------------------------
// Following method checks is currentLine(line drawn by last two points) collided with line
// -----------------------------------
private bool isLineCollide()
{
// if (gameObject.tag == "default") {
if (pointsList.Count < 2)
return false;
int TotalLines = pointsList.Count - 1;
myLine[] lines = new myLine[TotalLines];
if (TotalLines > 1) {
for (int i = 0; i < TotalLines; i++) {
lines [i].StartPoint = (Vector3)pointsList [i];
lines [i].EndPoint = (Vector3)pointsList [i + 1];
}
}
for (int i = 0; i < TotalLines - 1; i++) {
myLine currentLine;
currentLine.StartPoint = (Vector3)pointsList [pointsList.Count - 2];
currentLine.EndPoint = (Vector3)pointsList [pointsList.Count - 1];
if (isLinesIntersect (lines [i], currentLine))
return true;
}
// }
return false;
}
// -----------------------------------
// Following method checks whether given two points are same or not
// -----------------------------------
private bool checkPoints (Vector3 pointA, Vector3 pointB)
{
return (pointA.x == pointB.x && pointA.y == pointB.y);
}
// -----------------------------------
// Following method checks whether given two line intersect or not
// -----------------------------------
private bool isLinesIntersect (myLine L1, myLine L2)
{
if (checkPoints (L1.StartPoint, L2.StartPoint) ||
checkPoints (L1.StartPoint, L2.EndPoint) ||
checkPoints (L1.EndPoint, L2.StartPoint) ||
checkPoints (L1.EndPoint, L2.EndPoint))
return false;
return((Mathf.Max (L1.StartPoint.x, L1.EndPoint.x) >= Mathf.Min (L2.StartPoint.x, L2.EndPoint.x)) &&
(Mathf.Max (L2.StartPoint.x, L2.EndPoint.x) >= Mathf.Min (L1.StartPoint.x, L1.EndPoint.x)) &&
(Mathf.Max (L1.StartPoint.y, L1.EndPoint.y) >= Mathf.Min (L2.StartPoint.y, L2.EndPoint.y)) &&
(Mathf.Max (L2.StartPoint.y, L2.EndPoint.y) >= Mathf.Min (L1.StartPoint.y, L1.EndPoint.y))
);
}
}
enter image description here
Now How to print something when my line collide with some gameobjects in the scene???
It means that when the line collide with my gameobject i want to say go to another scene.
You may use Raycast from LastPosition to CurrentPosition in Update method.
https://docs.unity3d.com/ScriptReference/Physics.Raycast.html
Example:
http://xenforo.unity3d.com/threads/general-purpose-method-for-better-collision-solving.64781/
Related
So I only want one line on screen at a time. I would like to destroy the current line when a ball collides or another line is drawn. Here is my code so far. It creates a line renderer with two points, adds a Box collider. I've tried making a loop and setting the vector points back to zero.
Every time I add a OnCollisonEnter2D I cannot get the Line to register that it hit a ball. In the Ball script I can get the Log to print Hit when the Ball hits the collider.
using System.Runtime.CompilerServices;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.UI;
public class Player1 : MonoBehaviour
{
private LineRenderer line; // Reference to LineRenderer
private Vector3 mousePos;
public Vector3 startPos; // Start position of line
public Vector3 endPos; // End position of line
void Update()
{
GetLine(); // On mouse down new line will be created
}
private void GetLine()
{
if (Input.GetMouseButtonDown(0))
{
if (line == null)
CreateLine();
SetFirstPos();
}
else if (Input.GetMouseButtonUp(0))
{
if (line)
{
SetSecondPos();
AddColliderToLine();
line = null;
}
}
else if (Input.GetMouseButton(0))
{
if (line)
{
mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
mousePos.z = 0;
line.SetPosition(1, mousePos);
}
}
}
// Following method creates line runtime using Line Renderer component
private void CreateLine()
{
line = new GameObject("Line").AddComponent<LineRenderer>();
line.positionCount = 2;
line.numCapVertices = 2;
line.startWidth = .25f;
line.endWidth = .25f;
line.startColor = Color.black;
line.endColor = Color.black;
line.useWorldSpace = true;
}
// Following method adds collider to created line
private void AddColliderToLine()
{
BoxCollider2D col = new GameObject("Collider").AddComponent<BoxCollider2D>();
col.transform.parent = line.transform; // Collider is added as child object of line
float lineLength = Vector3.Distance(startPos, endPos);// length of line
lineLength.ToString();
col.size = new Vector3(lineLength, 0.25f, 1f); // size of collider is set where X is length of
line, Y is width of line, Z will be set as per requirement
Vector3 midPoint = (startPos + endPos) / 2;
col.transform.position = midPoint; // setting position of collider object
// Following lines calculate the angle between startPos and endPos
float angle = (Mathf.Abs(startPos.y - endPos.y) / Mathf.Abs(startPos.x - endPos.x));
if ((startPos.y < endPos.y && startPos.x > endPos.x) || (endPos.y < startPos.y && endPos.x >
startPos.x))
{
angle *= -1;
}
angle = Mathf.Rad2Deg * Mathf.Atan(angle);
col.transform.Rotate(0, 0, angle);
}
//Sets the first position
private void SetFirstPos()
{
mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
mousePos.z = 0;
line.SetPosition(0, mousePos);
startPos = mousePos;
Debug.Log("Line");
}
//Sets the second position
private void SetSecondPos()
{
mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
mousePos.z = 0;
line.SetPosition(1, mousePos);
endPos = mousePos;
}
//Cannot get it to Log Hit. Line show up in the Hierarchy.
private void OnCollisionEnter2D(Collision2D collision)
{
if(collision.gameobject.name =="Line")
{
Debug.Log("Hit!");
}
}
}
If your OnCollisionEnter2D gets called why don't you use just use it?
private void OnCollisionEnter2D(Collision2D collision)
{
if(collision.gameObject.name =="Line")
{
Debug.Log("Hit!");
// destroy the hit line
GameObject.Destroy(collision.gameObject);
}
}
If you want the line to be destroyed once a new one gets created you have to store it and destroy it manually:
public class Player1 : MonoBehaviour
{
private GameObject lastLine;
[...]
private void GetLine()
{
if (Input.GetMouseButtonDown(0))
{
if(lastLine != null)
{
GameObject.Destroy(lastLine);
}
if (line == null)
CreateLine();
SetFirstPos();
}
else if (Input.GetMouseButtonUp(0))
{
if (line)
{
SetSecondPos();
AddColliderToLine();
lastLine = line.gameObject;
line = null;
}
}
[...]
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveCameraBehind : MonoBehaviour
{
public GameObject camera;
public List<GameObject> targets = new List<GameObject>();
public float cameraDistance = 10.0f;
public bool behindMultipleTargets = false;
public string cameraWarningMsgs = "";
public string targetsWarningMsgs = "";
// Use this for initialization
void Start()
{
if (camera == null)
{
var cam = GetComponent<Camera>();
if (cam != null)
{
cameraWarningMsgs = "Gettig camera component.";
camera = transform.gameObject;
}
else
{
cameraWarningMsgs = "Creating a new camera component.";
GameObject NewCam = Instantiate(new GameObject(), transform);
NewCam.name = "New Camera";
NewCam.AddComponent<Camera>();
camera = NewCam;
}
}
if(targets.Count == 0)
{
targetsWarningMsgs = "No targets found.";
}
}
void FixedUpdate()
{
if (targets.Count > 0)
{
MoveCameraToPosition();
}
}
public void MoveCameraToPosition()
{
if (targets.Count > 1 && behindMultipleTargets == true)
{
var center = CalculateCenter();
transform.position = new Vector3(center.x, center.y + 2, center.z + cameraDistance);
}
if (behindMultipleTargets == false)
{
Vector3 center = targets[0].transform.position - targets[0].transform.forward * cameraDistance;
transform.position = new Vector3(center.x, center.y + 2, center.z);
}
}
private Vector3 CalculateCenter()
{
Vector3 center = new Vector3();
var totalX = 0f;
var totalY = 0f;
foreach (var target in targets)
{
totalX += target.transform.position.x;
totalY += target.transform.position.y;
}
var centerX = totalX / targets.Count;
var centerY = totalY / targets.Count;
center = new Vector3(centerX, centerY);
return center;
}
}
The CalculateCenter function make the targets(objects) to change positions and vanish away far away. Even if there is only one single target.
What I want to do is if there is one object for example one 3d cube position the camera behind the cube. And if there are more cubes for example two or ten and the camera is somewhere else calculate the middle position behind the targets and position the camera in the middle behind them.
To show what I mean in this example the view(like a camera) is behind the two soldiers in the middle position between them from behind.
But what if there are 5 soldiers how can I find the middle position and then position the camera behind them like this example in the screenshot ?
This is my old script version was working fine but only for 1 or 2 targets. But if there are 5 targets(soldiers) how can I position the camera behind them in the middle ? Like in the screenshot example.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveCameraBehind : MonoBehaviour
{
public GameObject camera;
public List<GameObject> targets = new List<GameObject>();
public float cameraDistance = 10.0f;
public bool behindTwoTargets = false;
public string warningMsgs = "";
// Use this for initialization
void Start()
{
if (camera == null)
{
var cam = GetComponent<Camera>();
if (cam != null)
{
warningMsgs = "Gettig Camera omponent.";
camera = transform.gameObject;
}
else
{
warningMsgs = "Creating a new camera component.";
GameObject NewCam = Instantiate(new GameObject(), transform);
NewCam.name = "New Camera";
NewCam.AddComponent<Camera>();
camera = NewCam;
}
}
camera.transform.Rotate(0, 180, 0);
}
void FixedUpdate()
{
if (targets.Count > 0)
{
MoveCameraToPosition();
}
}
public void MoveCameraToPosition()
{
if (targets.Count == 2 && behindTwoTargets == true)
{
Vector3 center = ((targets[0].transform.position - targets[1].transform.position) / 2.0f) + targets[1].transform.position;
camera.transform.position = new Vector3(center.x, center.y + 2, center.z + cameraDistance);
}
if (behindTwoTargets == false)
{
Vector3 center = targets[0].transform.position - targets[0].transform.forward * cameraDistance;
camera.transform.position = new Vector3(center.x, center.y + 2, center.z);
}
}
}
This is my last version of my working code still using the CalculateCenter function :
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class CameraLook : MonoBehaviour
{
public GameObject camera;
public List<GameObject> targets = new List<GameObject>();
public float cameraDistance = 10.0f;
public float cameraHeight = 2f;
public float rotateTime = 2f;
public bool multipleTargets = false;
public bool changeRandomTarget = false;
public bool behindFront = false;
public bool targetsRandomRot = false;
public string cameraWarningMsgs = "";
public string targetsWarningMsgs = "";
private List<Vector3> vectors = new List<Vector3>();
//Random move rotation timer part
Quaternion qTo;
float speed = 3f;
float timer = 0.0f;
// Use this for initialization
void Start()
{
qTo = Quaternion.Euler(new Vector3(0.0f, Random.Range(-180.0f, 180.0f), 0.0f));
if (camera == null)
{
var cam = GetComponent<Camera>();
if (cam != null)
{
cameraWarningMsgs = "Gettig camera component.";
camera = transform.gameObject;
}
else
{
cameraWarningMsgs = "Creating a new camera component.";
GameObject NewCam = Instantiate(new GameObject(), transform);
NewCam.name = "New Camera";
NewCam.AddComponent<Camera>();
camera = NewCam;
}
}
if (targets.Count == 0)
{
targetsWarningMsgs = "No targets found.";
}
else
{
foreach(GameObject vector in targets)
{
vectors.Add(vector.transform.position);
}
}
}
void FixedUpdate()
{
if (targets.Count > 0)
{
MoveCameraToPosition();
if (targetsRandomRot == true)
{
RotateTargetsRandom();
}
}
}
public void MoveCameraToPosition()
{
Vector3 center = CalculateCenter();
camera.transform.position = center;
if (behindFront == false)
{
camera.transform.rotation = Quaternion.LookRotation(-center, Vector3.up);
}
else
{
camera.transform.rotation = Quaternion.LookRotation(center, Vector3.up);
}
}
private Vector3 CalculateCenter()
{
Vector3 center = new Vector3();
var x = targets[0].transform.position.x;
var y = targets[0].transform.position.y;
var z = targets[0].transform.position.z;
if (multipleTargets == true)
{
for (int i = 1; i < targets.Count; i++)
{
x += targets[i].transform.position.x;
y += targets[i].transform.position.y;
z += targets[i].transform.position.z;
}
}
else
{
x += targets[0].transform.position.x;
y += targets[0].transform.position.y;
z += targets[0].transform.position.z;
}
if(changeRandomTarget == true)
{
for (int i = 1; i < targets.Count; i++)
{
x += targets[i].transform.position.x;
y += targets[i].transform.position.y;
z += targets[i].transform.position.z;
}
}
x = x / targets.Count;
y = y / targets.Count;
z = z / targets.Count;
if (behindFront == false)
{
center = new Vector3(x, y + cameraHeight, z + cameraDistance);
}
else
{
center = new Vector3(x, y + cameraHeight, z - cameraDistance);
}
return center;
}
private void RotateTargetsRandom()
{
timer += Time.deltaTime;
if (timer > rotateTime)
{ // timer resets at 2, allowing .5 s to do the rotating
qTo = Quaternion.Euler(new Vector3(0.0f, Random.Range(-180.0f, 180.0f), 0.0f));
timer = 0.0f;
}
foreach (var target in targets)
{
target.transform.rotation = Quaternion.Slerp(target.transform.rotation, qTo, Time.deltaTime * speed);
}
}
}
And now I want to add and use the bool flag changeRandomTarget :
But not sure how to do it :
if(changeRandomTarget == true)
{
for (int i = 1; i < targets.Count; i++)
{
x += targets[i].transform.position.x;
y += targets[i].transform.position.y;
z += targets[i].transform.position.z;
}
}
I want that each X seconds it will pick a random center and change the camera position according to it. For example the first item in the targets List the last item and all the items so each X seconds the center will be once behind targets[0] or targets1 or targets[i]
Not sure how to do it with my code or with derHugo solution.
Surely you just find the average
so
if (mobcount > 1)
{
var x=mob[0].position.x;
var y=mob[0].position.y;
var z=mob[0].position.z;
for(int i=1; i<mobcount; i++)
{
x += mob[i].position.x;
y += mob[i].position.y;
z += mob[i].position.z;
}
x = x / mobcount;
y = y / mobcount;
z = z / mobcount;
}
therefore the camera should look at the position x,y,z.. and perhaps set the distance to be a fixed distance behind the nearest mob...
Actually you don't even need to do it component wise:
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
...
private static Vector3 Average(IReadOnlyCollection<Vector3> vectors)
{
if(vectors == null) return Vector3.zero;
switch (vectors.Count)
{
case 0:
return Vector3.zero;
case 1:
return vectors.First();
default:
var average = Vector3.zero;
foreach(var vector in vectors)
{
average += vector;
}
return average / vectors.Count;
}
}
Or directly using Linq aggregate
private static Vector3 Average(IReadOnlyCollection<Vector3> vectors)
{
if(vectors == null) return Vector3.zero;
switch (vectors.Count)
{
case 0:
return Vector3.zero;
case 1:
return vectors.First();
default:
var average = vectors.Aggregate(Vector3.zero, (current, vector) => current + vector);
return average / vectors.Count;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RotateObjects : MonoBehaviour
{
public GameObject[] objectsToRotate;
public Transform to;
public float speed = 0.1f;
public Vector3 spinDirection;
public bool useMouse = false;
public bool useQuaternion = false;
public bool nonstopSpin = false;
Ray ray;
RaycastHit hit;
RaycastHit[] hits;
GameObject[] myLines;
LineRenderer lr;
// Use this for initialization
void Start()
{
myLines = new GameObject[objectsToRotate.Length];
GenerateLinerenderer();
if (objectsToRotate.Length > 0)
{
if (useQuaternion == true)
{
for (int i = 0; i < objectsToRotate.Length; i++)
{
objectsToRotate[i].transform.rotation = Quaternion.Lerp(objectsToRotate[i].transform.rotation, to.rotation, Time.time * speed);
}
}
}
}
// Update is called once per frame
void Update()
{
if (objectsToRotate.Length > 0)
{
for (int i = 0; i < objectsToRotate.Length; i++)
{
/*ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
Debug.DrawLine(Input.mousePosition, hit.transform.position, Color.red);
if (hit.collider.name == objectsToRotate[i].name)
objectsToRotate[i].transform.Rotate(1, 1, 1);
}*/
hits = Physics.RaycastAll(Camera.main.ScreenPointToRay(Input.mousePosition), 100.0f);
for (int x = 0; x < hits.Length; x++)
{
RaycastHit hit = hits[x];
if (hit.collider.name == objectsToRotate[i].name)
{
objectsToRotate[i].transform.Rotate(1, 1, 1);
Debug.DrawLine(Input.mousePosition, hit.transform.position, Color.red);
SpawnLineGenerator(Input.mousePosition, hit.transform.position);
}
}
if (useMouse == true)
{
if (Input.GetMouseButton(0))
{
Rotate(i);
}
}
else
{
Rotate(i);
}
}
}
}
private void Rotate(int i)
{
if (useQuaternion == true)
{
objectsToRotate[i].transform.rotation = Quaternion.Lerp(objectsToRotate[i].transform.rotation, to.rotation, Time.time * speed);
}
if (nonstopSpin == true)
{
objectsToRotate[i].transform.Rotate(1, 1, 1);
}
}
void SpawnLineGenerator(Vector3 start, Vector3 end)
{
lr.SetPosition(0, start);
lr.SetPosition(1, end);
}
private void GenerateLinerenderer()
{
for (int i = 0; i < myLines.Length; i++)
{
myLines[i] = new GameObject();
myLines[i].name = "FrameLine";
myLines[i].AddComponent<LineRenderer>();
lr = myLines[i].GetComponent<LineRenderer>();
lr.material = new Material(Shader.Find("Particles/Alpha Blended Premultiply"));
lr.startColor = Color.green;
lr.useWorldSpace = false;
lr.endColor = Color.green;
lr.startWidth = 0.1f;//0.03f;
lr.endWidth = 0.1f;//0.03f;
lr.numCapVertices = 5;
}
}
}
For example if I hit with the ray in some objects at the same time it will draw multiple red lines from the mouse position to the hit objects using debug:
Debug.DrawLine(Input.mousePosition, hit.transform.position, Color.red);
Same result I want to do with the linerenderer. But it's drawing one green line even if I hit multiple objects.
Im using Unity and have asked this on there forums however have not had any replies. Ive found this example from a plugin where I am trying to use the kinect to rotate an object using my right hand to rotate it right and the left to rotate left. I have managed to get the object to do this apart from it stops at each side of the object, but cant work out what part of the code is doing this.
Thanks
using UnityEngine;
using System.Collections;
using System;
public class GestureListener : MonoBehaviour, KinectGestures.GestureListenerInterface
{
// GUI Text to display the gesture messages.
public GUIText GestureInfo;
private bool raiselefthand;
private bool raiserighthand;
public bool IsSwipeLeft()
{
if(raiserighthand)
{
raiserighthand = false;
return true;
}
return false;
}
public bool IsSwipeRight()
{
if(raiselefthand)
{
raiselefthand = false;
return true;
}
return false;
}
public void UserDetected(uint userId, int userIndex)
{
// detect these user specific gestures
KinectManager manager = KinectManager.Instance;
manager.DetectGesture(userId, KinectGestures.Gestures.RaiseLeftHand);
manager.DetectGesture(userId, KinectGestures.Gestures.RaiseRightHand);
if(GestureInfo != null)
{
GestureInfo.GetComponent<GUIText>().text = "Swipe left or right to change the slides.";
}
}
public void UserLost(uint userId, int userIndex)
{
if(GestureInfo != null)
{
GestureInfo.GetComponent<GUIText>().text = string.Empty;
}
}
public void GestureInProgress(uint userId, int userIndex, KinectGestures.Gestures gesture,
float progress, KinectWrapper.NuiSkeletonPositionIndex joint, Vector3 screenPos)
{
// don't do anything here
}
public bool GestureCompleted (uint userId, int userIndex, KinectGestures.Gestures gesture,
KinectWrapper.NuiSkeletonPositionIndex joint, Vector3 screenPos)
{
string sGestureText = gesture + " detected";
if(GestureInfo != null)
{
GestureInfo.GetComponent<GUIText>().text = sGestureText;
}
if(gesture == KinectGestures.Gestures.RaiseRightHand)
raiserighthand = true;
else if(gesture == KinectGestures.Gestures.RaiseLeftHand)
raiselefthand = true;
return true;
}
public bool GestureCancelled (uint userId, int userIndex, KinectGestures.Gestures gesture,
KinectWrapper.NuiSkeletonPositionIndex joint)
{
// don't do anything here, just reset the gesture state
return true;
}
}
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class PresentationScript : MonoBehaviour
{
public bool slideChangeWithGestures = true;
public bool slideChangeWithKeys = true;
public float spinSpeed = 5;
public bool autoChangeAlfterDelay = false;
public float slideChangeAfterDelay = 10;
public List<Texture> slideTextures;
public List<GameObject> horizontalSides;
// if the presentation cube is behind the user (true) or in front of the user (false)
public bool isBehindUser = false;
private int maxSides = 0;
private int maxTextures = 0;
private int side = 0;
private int tex = 0;
private bool isSpinning = false;
private float slideWaitUntil;
private Quaternion targetRotation;
private GestureListener gestureListener;
void Start()
{
// hide mouse cursor
Cursor.visible = false;
// calculate max slides and textures
maxSides = horizontalSides.Count;
maxTextures = slideTextures.Count;
// delay the first slide
slideWaitUntil = Time.realtimeSinceStartup + slideChangeAfterDelay;
targetRotation = transform.rotation;
isSpinning = false;
tex = 0;
side = 0;
if(horizontalSides[side] && horizontalSides[side].GetComponent<Renderer>())
{
horizontalSides[side].GetComponent<Renderer>().material.mainTexture = slideTextures[tex];
}
// get the gestures listener
gestureListener = Camera.main.GetComponent<GestureListener>();
}
void Update()
{
// dont run Update() if there is no user
KinectManager kinectManager = KinectManager.Instance;
if(autoChangeAlfterDelay && (!kinectManager || !kinectManager.IsInitialized() || !kinectManager.IsUserDetected()))
return;
if(!isSpinning)
{
if(slideChangeWithKeys)
{
if(Input.GetKeyDown(KeyCode.PageDown))
RotateToNext();
else if(Input.GetKeyDown(KeyCode.PageUp))
RotateToPrevious();
}
if(slideChangeWithGestures && gestureListener)
{
if(gestureListener.IsSwipeLeft())
RotateToNext();
else if(gestureListener.IsSwipeRight())
RotateToPrevious();
}
// check for automatic slide-change after a given delay time
if(autoChangeAlfterDelay && Time.realtimeSinceStartup >= slideWaitUntil)
{
RotateToNext();
}
}
else
{
// spin the presentation
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, spinSpeed * Time.deltaTime);
// check if transform reaches the target rotation. If yes - stop spinning
float deltaTargetX = Mathf.Abs(targetRotation.eulerAngles.x - transform.rotation.eulerAngles.x);
float deltaTargetY = Mathf.Abs(targetRotation.eulerAngles.y - transform.rotation.eulerAngles.y);
if(deltaTargetX < 1f && deltaTargetY < 1f)
{
// delay the slide
slideWaitUntil = Time.realtimeSinceStartup + slideChangeAfterDelay;
isSpinning = false;
}
}
}
private void RotateToNext()
{
// set the next texture slide
tex = (tex + 1) % maxTextures;
if(!isBehindUser)
{
side = (side + 1) % maxSides;
}
else
{
if(side <= 0)
side = maxSides - 1;
else
side -= 1;
}
if(horizontalSides[side] && horizontalSides[side].GetComponent<Renderer>())
{
horizontalSides[side].GetComponent<Renderer>().material.mainTexture = slideTextures[tex];
}
// rotate the presentation
float yawRotation = !isBehindUser ? 360f / maxSides : -360f / maxSides;
Vector3 rotateDegrees = new Vector3(0f, yawRotation, 0f);
targetRotation *= Quaternion.Euler(rotateDegrees);
isSpinning = true;
}
private void RotateToPrevious()
{
// set the previous texture slide
if(tex <= 0)
tex = maxTextures - 1;
else
tex -= 1;
if(!isBehindUser)
{
if(side <= 0)
side = maxSides - 1;
else
side -= 1;
}
else
{
side = (side + 1) % maxSides;
}
if(horizontalSides[side] && horizontalSides[side].GetComponent<Renderer>())
{
horizontalSides[side].GetComponent<Renderer>().material.mainTexture = slideTextures[tex];
}
// rotate the presentation
float yawRotation = !isBehindUser ? -360f / maxSides : 360f / maxSides;
Vector3 rotateDegrees = new Vector3(0f, yawRotation, 0f);
targetRotation *= Quaternion.Euler(rotateDegrees);
isSpinning = true;
}
}
I have managed to get the object to do this apart from it stops at each side of the object, but cant work out what part of the code is doing this.
I understand you ask for help finding which parts are involved in the rotation.
As such, I looked through the scripts and noticed 2 sections in the PresentationScript.
This part in the Update() method. Based on the code and the comments that are part of it.
// spin the presentation
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, spinSpeed * Time.deltaTime);
// check if transform reaches the target rotation. If yes - stop spinning
float deltaTargetX = Mathf.Abs(targetRotation.eulerAngles.x - transform.rotation.eulerAngles.x);
float deltaTargetY = Mathf.Abs(targetRotation.eulerAngles.y - transform.rotation.eulerAngles.y);
if(deltaTargetX < 1f && deltaTargetY < 1f)
{
// delay the slide
slideWaitUntil = Time.realtimeSinceStartup + slideChangeAfterDelay;
isSpinning = false;
}
This line in the Start() method is also involved.
targetRotation = transform.rotation;
A transform controls the position, scaling and as is relevant for this case, also the rotation of an object.
Does anyone how to make lines to be more guided in unity? Guided as in how you use a real life ruler where the drawn lines is not suppose to be straight and the direction of the line or the end point of the line is affected by how you place the ruler. Currently my code, im able to draw lines and collide with the ruler but the lines are more of a freehand drawing. So how do i make it like what i say earlier on.
Heres my code for the line properties script.
void Update()
{
this.GetComponent<Rigidbody> ().useGravity = false;
this.gameObject.GetComponent<Rigidbody> ().constraints =
RigidbodyConstraints.FreezeRotationX |
RigidbodyConstraints.FreezeRotationZ |
RigidbodyConstraints.FreezePositionY |
RigidbodyConstraints.FreezePositionZ;
}
public void OnCollisionStay(Collision col)
{
if (col.gameObject.tag == "Ruler")
{
if (LockPosX == false && LockPosY == false)
{
Debug.Log ("Collision with Ruler");
//line.SetPosition(1 , newPosititon);
//newPosititon.y = col.transform.position.y;
//newPosititon.z = 0;
LockPosY = true;
}
}
}
Heres my code for spawning the line/drawing the line:
void Update ()
{
if(Input.GetMouseButtonDown(0))
{
if (line == null)
{
createLine ();
mousePos = Camera.main.ScreenToWorldPoint (Input.mousePosition);
mousePos.z = 0;
line.SetPosition (0, mousePos);
startPos = mousePos;
}
}
else if(Input.GetMouseButtonUp(0) && line)
{
mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
mousePos.z = 0;
line.SetPosition(1,mousePos);
endPos = mousePos;
addColliderToLine ();
line = null;
currLines++;
}
else if(Input.GetMouseButton(0) && line)
{
mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
mousePos.z = 0;
line.SetPosition(1, mousePos);
}
}
public void createLine()
{
line = new GameObject("Line"+currLines).AddComponent<LineRenderer>();
line.material = material;
line.tag = "DrawnLines";
line.SetVertexCount(2);
line.SetWidth(0.15f,0.15f);
line.useWorldSpace = true;
}
private void addColliderToLine()
{
BoxCollider col = new GameObject("Collider").AddComponent<BoxCollider> ();
col.transform.parent = line.transform;
float lineLength = Vector3.Distance (startPos, endPos);
col.size = new Vector3 (lineLength, 1.0f, 5f);
Vector3 midPoint = (startPos + endPos)/2;
col.transform.position = midPoint;
float angle = (Mathf.Abs (startPos.y - endPos.y) / Mathf.Abs (startPos.x - endPos.x));
if((startPos.y<endPos.y && startPos.x>endPos.x) || (endPos.y<startPos.y && endPos.x>startPos.x))
{
angle*=-1;
}
angle = Mathf.Rad2Deg * Mathf.Atan (angle);
col.transform.Rotate (0, 0, angle);
col.gameObject.AddComponent<LineProperties> ();
col.gameObject.AddComponent<Rigidbody> ();
}
It sounds like what you want to do is snap the position of the user's mouse input to the line created by ruler. If this is the case, you could simply use a simple function to accomplish this before setting the line's position.
//This function returns a point which is a projection from a point to a line.
//The line is regarded infinite. If the line is finite, use ProjectPointOnLineSegment() instead.
public static Vector3 ProjectPointOnLine(Vector3 linePoint, Vector3 lineVec, Vector3 point)
{
//get vector from point on line to point in space
Vector3 linePointToPoint = point - linePoint;
float t = Vector3.Dot(linePointToPoint, lineVec);
return linePoint + lineVec * t;
}
For the first argument - linePoint - you would pass in some point along the ruler's edge. If the ruler gameObject's pivot is along this edge, you can just use the ruler's position. The second argument - lineVec - is the direction vector created by the ruler. Depending on how the ruler's gameObject is oriented, this could be as simple as ruler.transform.forward. Finally, for the third argument, you would pass in Input.mousePosition. If you do not want their input to be snapped to the ruler, but where they started, you would then pass in your Input.mousePosition to the first parameter as well. This will snap it to a line following the same direction as the ruler, but the line will start where their input started.
So your void Update() method becomes:
void Update ()
{
if(Input.GetMouseButtonDown(0))
{
if (line == null)
{
createLine ();
mousePos = Camera.main.ScreenToWorldPoint (ProjectPointOnLine(Input.mousePosition, ruler.transform.forward, Input.mousePosition));
mousePos.z = 0;
line.SetPosition (0, mousePos);
startPos = mousePos;
}
}
else if(Input.GetMouseButtonUp(0) && line)
{
mousePos = Camera.main.ScreenToWorldPoint(ProjectPointOnLine(Input.mousePosition, ruler.transform.forward, Input.mousePosition));
mousePos.z = 0;
line.SetPosition(1,mousePos);
endPos = mousePos;
addColliderToLine ();
line = null;
currLines++;
}
else if(Input.GetMouseButton(0) && line)
{
mousePos = Camera.main.ScreenToWorldPoint(ProjectPointOnLine(Input.mousePosition, ruler.transform.forward, Input.mousePosition));
mousePos.z = 0;
line.SetPosition(1, mousePos);
}
}
Edit
If you need a method to retrieve all of the lines with a specific tag - such as DrawnLines which you use in the createLines() method, you can do something like the following
private void UpdateLines()
{
GameObject[] drawnLineGameObjects = GameObject.FindGameObjectsWithTag("DrawnLines");
foreach (var lineObject in drawnLineGameObjects)
{
LineRenderer drawnLine = lineObject.GetComponent<LineRenderer>();
if (drawnLine != null)
{
// Do stuff to your Line Renderer Here
}
}
}