In Unity I have created cube and player. The player has LineRenderer component.The line hits the cube and stops. This is following code in player.
_lineRenderer.SetPosition(0,transform.position);
RaycastHit hit;
if (Physics.Raycast(transform.position, transform.forward, out hit))
{
if (hit.collider)
{
_lineRenderer.SetPosition(1,hit.point);
/* if(hit.collider){
Vector3 pos = Vector3.Reflect (hit.point - transform.position, hit.normal);
_lineRenderer.SetPosition(2,pos);
//lineRenderer.SetPosition(3, pos);
}*/
}
}
This works fine. But how can I reflect the line after hitting cube. As you can see in my code's comment I tried to reflect with Vector3.Reflect.But it did not work.If I run it shows me an error likeLineRenderer.SetPosition index out of bounds How can I reflect line like in this image
Per comments, your initial problem is not setting the correct number of points for the LineRenderer to use:
if (hit.collider)
{
_lineRenderer.positionCount = 3;
_lineRenderer.SetPosition(1,hit.point);
// etc
}
else
_lineRenderer.positionCount = 2; // No bounced ray
Also, Reflect returns a direction vector, but you're trying to use it as a position:
_lineRenderer.SetPosition(2,pos);
You need to apply the direction to an existing starting point. Do this:
_lineRenderer.SetPosition(2, hit.point + pos);
The error tells you that your LineRenderer does not provide enough space for setting a third point.
Unity's LineRenderer.SetPosition(...) does not manage the number of actually available points in a LineRenderer for you. You have to configure this manually before setting the points.
If you want a LineRenderer built from 3 points (player, reflection point, end of reflected ray) just use:
_lineRenderer.positionCount = 3; // tells the renderer it consists of 3 points
_lineRenderer.SetPosition(0, yourFirstPosition);
_lineRenderer.SetPosition(1, yourSecondPosition);
_lineRenderer.SetPosition(2, yourThirdPosition);
Related
I am creating a 2D platformer type game, and it has non flat terrain. How do I make it so that my character's legs always smoothly transition from a flat surface to a slope surface?
For reference you can check out [Alto's Adventure] (http://altosadventure.com/) (mobile). In that, the skateboard snaps to the curvy terrain.
Feel free to ask for more details.
To make such a possibility, you have to send a ray to the ground and then set the direction of up transform according to the Normal vector point of impact. The following code solves the basic problem.
public LayerMask groundLayer;
public float maxRayLength = 3;
public float offset = .5f; // set it to half of your character height
public void Update()
{
var ground = Physics2D.Raycast(transform.position, -transform.up, maxRayLength, groundLayer.value);
if (ground)
{
transform.up = ground.normal;
transform.position = new Vector3(ground.point.x, ground.point.y) + transform.up*offset;
}
}
In addition to the script, you must specify a suitable 2D collider as well as its layer. For layers, make sure that both the script inspector and the layer are set to the hypothetical ground layer.
Example Result:
This is a bonkers of an issue. Please bare with me and do ask for any additional detail if you require it!
I tried this tutorial from this youtube tutorial for creating an infinite parallax in unity that moves as the camera moves. Firstly, the camera is locked onto the player via a cinemachine which is the main camera.
Here is my unity editor screen:
Split up layers for showing the actual layers:
As you can see there are these three layers inside the Background Parallax layer, these layers are a single parallax scene with sprites replicated thrice and placed closely to one another. [Layer 1, 2 and 3 are the same collection of sprites duplicated in the scene]
Each child of the Layer 1, 2 and 3 in the hierarchy is just a sprite, for e.g.: A tree, or a bush or the ground beneath.
MainCamera Properties:
The camera is attached to the player moving around.
When the player moves forward, the layer is not being replicated when the layer is about to finish. Simply stated, it's not rolling over to give the infinite feel.
The Issue[The layers not 'arriving' in front of the player as he moves forward]:
Moreover, I tried to debug the game by going into the scene just to find that as soon as I hit the play button, all the three layers overlap with each other as opposed to how they are spread over. They just clog the camera as seen here:
I just want the parallax to be infinite as I move further on and not see a broken scene as seen above.
The Parallax code attached to childs(sprites) of each layer(Excluding Layer 1, 2, 3 as they are just empty objects used to tidy the hierarchy):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Parallax : MonoBehaviour
{
private float spriteLength, startpos;
public GameObject cam;
public float parallaxEffect;
// Start is called before the first frame update
void Start()
{
startpos = transform.position.x;
spriteLength = GetComponent<SpriteRenderer>().bounds.size.x;
}
// Update is called once per frame
void FixedUpdate()
{
float temp = (cam.transform.position.x * (1 - parallaxEffect));
float dist = (cam.transform.position.x * parallaxEffect);
transform.position = new Vector3(startpos + dist, transform.position.y, transform.position.z);
if (temp > startpos + spriteLength)
{
startpos += spriteLength;
}
else if (temp < startpos - spriteLength)
{
startpos -= spriteLength;
}
}
}
The above code just moves the sprite in the x direction(left and right) as the player moves.
I believe that the rolling of layers is not happening due to the camera being attached to the player. Just a hunch. Any help is highly appreciated!
I believe you have these reversed:
if (temp > startpos + spriteLength)
{
startpos += spriteLength;
}
else if (temp < startpos - spriteLength)
{
startpos -= spriteLength;
}
You have it where if the position is greater than a certain position, then it adds the length. This would mean it's always greater than that position and always adding. Same for the other side. What you need is:
if (temp > startpos + spriteLength)
{
startpos -= spriteLength;
}
else if (temp < startpos - spriteLength)
{
startpos += spriteLength;
}
So, I just discarded the entire way of doing this parallax, instead I found another way of doing the infinite parallax. This tutorial on youtube helps you create an infinite parallax from scratch.
After creating the parllax, if you face issues regarding lag or jitter with the parallax, you can try the following techniques to see if it runs smoothly:
Try alternating between FixedUpdate() and LateUpdate()
Try changing the Interpolation on the player(Interpolate or Extrapolate or None). Try combinations with the above step
Lastly, this worked for me: Try changing the pixel size of the sprites by clicking on the sprite and not the object. Mine was 100, but when I changed it to 64, it ran butter smooth
I'm trying to make whack a mole game using project tango.
When user start the game, the program will create holes at random point for the moles to come out. Right now, I already can make the hole and spawn the mole at random, though I have a problem with the created hole.
The hole sometimes spawn at an edge contour of table and stuff and make the hole partially floating in the air. Is there any way to check if the centerPlane is near an edge or not?
Here's the screenshot of the problem I meant. I want the "hole" not to spawn on area that doesn't fit with it's height and width. Currently, I'm using farandole release.
EDIT 1:
I'm trying to do as Hristo suggest. But it doesn't work, the FindClosestPoint always return -1, even when I use the center of the screen. Here's the script I used. And for some additional info, I'm using the unitySDK and unity 5.5.2f1
bool CheckTheCorner(Camera cam,Vector3 planeCenter){
Vector2 firstPointInScreen = WorldToScreenConverter(cam,new Vector3 (planeCenter.x,planeCenter.y,planeCenter.z-holeheight));
Vector2 secondPointInScreen = WorldToScreenConverter(cam,new Vector3 (planeCenter.x,planeCenter.y,planeCenter.z+holeheight));
Vector2 thirdPointInScreen = WorldToScreenConverter(cam,new Vector3 (planeCenter.x-holewidth,planeCenter.y,planeCenter.z));
Vector2 fourthPointInScreen = WorldToScreenConverter(cam,new Vector3 (planeCenter.x+holewidth,planeCenter.y,planeCenter.z));
DebugText.text = m_pointCloud.FindClosestPoint (cam, new Vector2(Screen.width / 2, Screen.height / 2), 1).ToString ();
Vector3 firstPoint = m_pointCloud.m_points[m_pointCloud.FindClosestPoint(cam, firstPointInScreen, 1)];
Vector3 secondPoint = m_pointCloud.m_points[m_pointCloud.FindClosestPoint(cam, secondPointInScreen, 1)];
Vector3 thirdPoint = m_pointCloud.m_points[m_pointCloud.FindClosestPoint(cam, thirdPointInScreen, 1)];
Vector3 fourthPoint = m_pointCloud.m_points[m_pointCloud.FindClosestPoint(cam, fourthPointInScreen, 1)];
return false;
}
Vector2 WorldToScreenConverter(Camera cam,Vector3 worldPos){
Vector3 screenPos = cam.WorldToScreenPoint (worldPos);
return new Vector2 (screenPos.x,screenPos.z);
}
Ah yes, don't mind the return false one for the moment, I just put it there to avoid error since I'm still figuring out the FindClosestPoint.
What you can do is take the 4 corners on your plane and decide if they are all laying on a surface in the real world, if not you can make the plane elsewhere.
That can happen with the use of FindClosestPoint() method in the TangoPointCloud.cs. What that method does is makes a Raycast from your camera trough a certain point on the screen landing in the real world environment. The method then returns the index of that point. The list to search with the indexes is called m_points
So lets split it in steps:
Make 4 Vectors using the `FindClosestPoint().
Check if all 4 vectors are on the same plane (simple math).
If step 2 is true -> Instantiate your GameObject on that plane.
To get one of the vectors your code should be something like this:
Vector3 firstPoint = m_pointCloud.m_points[m_pointCloud.FindClosestPoint(Camera.main, new Vector2(Screen.width / 2, Screen.height / 2), 1)];
In this example I'm using the center of the screen as my Vector2 parameter. However you don't want the center of the screen . Instead you want the position of one corner from your plane translated as a screen point.
Hope that solves your problem. Cheers.
I'm trying to convert a mouse event into a VR Raycast event.
I've Input.mousePosition.x & Input.mousePosition.y as the coordinate of a mouse click event. I want to apply the same event on a VR Raycast hit.
I've the following code
Ray ray = new Ray(CameraRay.transform.position, CameraRay.transform.forward);
RaycastHit hit;
if (GetComponent<Collider>().Raycast(ray, out hit, 100)) {
Debug.Log ("True");
Vector3 point = camera.WorldToScreenPoint(hit.point);
} else {
Debug.Log ("False");
}
From the Raycast hit point, how do I get the equivalent x-y coordinates of where the Ray hits the collider?
Update:
The following script is attached to a color picker object in my Unity setup for Google Cardboard. On hover on the color picker, I want to get the coordinates of where the Raycast hits the collider (so that I can get the color in that coordinate).
Question 1:
On the FixedUpdate, I've an if statement if (GetComponent<Collider>().Raycast(ray, out hit, 100)) and it's returning false. What am I missing here?
Question 2:
Am I correct to assume that if the hit.point is set, I could get the x,y,z coordinates of the point where the ray hits the collider to be point[0], point1 and point[2]?
I'm not a huge expert on VR in Unity, but you would usually use Camera.WorldToScreenPoint for these purposes. To use it on the main camera, use these lines:
Ray ray = new Ray(CameraRay.transform.position, CameraRay.transform.forward);
RaycastHit hit;
if (GetComponent<Collider>().Raycast(ray, out hit, 100)) {
Vector3 point = camera.WorldToScreenPoint(hit.point);
}
The z value gives you the distance from the camera, in case you were interested in that. The Unity documentation: https://docs.unity3d.com/ScriptReference/Camera.WorldToScreenPoint.html
EDIT:
Question 1:
RaycastHit hit;
if (Physics.Raycast(CameraRay.transform.position, Vector3.forward, out hit)) {
Debug.Log ("True");
Vector3 point = camera.WorldToScreenPoint(hit.point);
} else {
Debug.Log ("False");
}
Attempt using this code instead, from what I've read, Physics.Raycast() is almost always better to use than Collider.Raycast().
Question 2:
Vector3[] point = new Vector3[3] {hit.point.x, hit.point.y, hit.point.z};
This creates an array named point that has the three variables assigned, although the z coordinate can be discarded for use on a 2D color wheel.
I am having trouble keeping game objects inside of a contained space. When they reach the edge, there is some momentary push back but then they will go right through the wall.
I am using a Box Collider on the player, and a Mesh Collider for the level's wall. I am having issues with both a Player Character (a space ship) that the movement is controlled by the player. And with projectiles, which are fire and forget moving at a constant speed.
This is my movement code for my player. It is being run in the FixedUpdate() function.
//Movement
haxis = Input.GetAxis("Horizontal") * speed;
vaxis = Input.GetAxis("Vertical") * speed;
moveVector.x = haxis;
moveVector.z = vaxis;
if(moveVector.magnitude > 1)
{
moveVector.Normalize();
}
rigidbody.MovePosition(transform.position + moveVector * speed);
With the bullets, they are given a velocity and the engine calculates their moviements. They are using Box Collider and it is set as a Trigger so they don't have physics. But I use OnTriggerEnter to destroy them.
//Projectiles without physics collisiions
function OnTriggerEnter (other : Collider) {
Destroy(gameObject);
}
Some, but not all of the bullets will be destroyed when hitting the mesh collider wall. The player will sometimes hit it and stop, but can usually push through it. How can I make the collisions with the mesh collider work every time?
Collision with fast-moving objects is always a problem. A good way to ensure that you detect all collision is to use Raycasting instead of relying on the physics simulation. This works well for bullets or small objects, but will not produce good results for large objects.
http://unity3d.com/support/documentation/ScriptReference/Physics.Raycast.html
Pseudo-codeish (I don't have code-completion here and a poor memory):
void FixedUpdate()
{
Vector3 direction = new Vector3(transform.position - lastPosition);
Ray ray = new Ray(lastPosition, direction);
RaycastHit hit;
if (Physics.Raycast(ray, hit, direction.magnitude))
{
// Do something if hit
}
this.lastPosition = transform.position;
}
I have a pinball prototype that also gave me much trouble in the same areas. These are all the steps I've taken to almost (but not yet entirely) solve these problems:
For fast moving objects:
Set the rigidbody's Interpolate to 'Interpolate' (this does not affect the actual physics simulation, but updates the rendering of the object properly - use this only on important objects from a rendering point of view, like the player, or a pinball, but not for projectiles)
Set Collision Detection to Continuous Dynamic
Attach the script DontGoThroughThings (https://www.auto.tuwien.ac.at/wordpress/?p=260) to your object. This script cleverly uses the Raycasting solution I posted in my other answer to pull back offending objects to before the collision points.
In Edit -> Project Settings -> Physics:
Set Min Penetration for Penalty to a very low value. I've set mine to 0.001
Set Solver Iteration Count to a higher value. I've set mine to 50, but you can probably do ok with much less.
All that is going to have a penalty in performace, but that's unavoidable. The defaults values are soft on performance but are not really intented for proper simulation of small and fast-moving objects.
How about set the Collision Detection of rigidbody to Continuous or Continuous Dynamic?
http://unity3d.com/support/documentation/Components/class-Rigidbody.html
So I haven't been able to get the Mesh Colliders to work. I created a composite collider using simple box colliders and it worked exactly as expected.
Other tests with simple Mesh Colliders have come out the same.
It looks like the best answer is to build a composite collider out of simple box/sphere colliders.
For my specific case I wrote a Wizard that creates a Pipe shaped compound collider.
#script AddComponentMenu("Colliders/Pipe Collider");
class WizardCreatePipeCollider extends ScriptableWizard
{
public var outterRadius : float = 200;
public var innerRadius : float = 190;
public var sections : int = 12;
public var height : float = 20;
#MenuItem("GameObject/Colliders/Create Pipe Collider")
static function CreateWizard()
{
ScriptableWizard.DisplayWizard.<WizardCreatePipeCollider>("Create Pipe Collider");
}
public function OnWizardUpdate() {
helpString = "Creates a Pipe Collider";
}
public function OnWizardCreate() {
var theta : float = 360f / sections;
var width : float = outterRadius - innerRadius;
var sectionLength : float = 2 * outterRadius * Mathf.Sin((theta / 2) * Mathf.Deg2Rad);
var container : GameObject = new GameObject("Pipe Collider");
var section : GameObject;
var sectionCollider : GameObject;
var boxCollider : BoxCollider;
for(var i = 0; i < sections; i++)
{
section = new GameObject("Section " + (i + 1));
sectionCollider = new GameObject("SectionCollider " + (i + 1));
section.transform.parent = container.transform;
sectionCollider.transform.parent = section.transform;
section.transform.localPosition = Vector3.zero;
section.transform.localRotation.eulerAngles.y = i * theta;
boxCollider = sectionCollider.AddComponent.<BoxCollider>();
boxCollider.center = Vector3.zero;
boxCollider.size = new Vector3(width, height, sectionLength);
sectionCollider.transform.localPosition = new Vector3(innerRadius + (width / 2), 0, 0);
}
}
}
1.) Never use MESH COLLIDER. Use combination of box and capsule collider.
2.) Check constraints in RigidBody. If you tick Freeze Position X than it will pass through the object on the X axis. (Same for y axis).
Old Question but maybe it helps someone.
Go to Project settings > Time and Try dividing the fixed timestep and maximum allowed timestep by two or by four.
I had the problem that my player was able to squeeze through openings smaller than the players collider and that solved it. It also helps with stopping fast moving objects.
Edit ---> Project Settings ---> Time ... decrease "Fixed Timestep" value .. This will solve the problem but it can affect performance negatively.
Another solution is could be calculate the coordinates (for example, you have a ball and wall. Ball will hit to wall. So calculate coordinates of wall and set hitting process according these cordinates )
Try setting the models to environment and static. That fix my issue.