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
Related
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);
I'm trying to figure out simple custom 2D physics for platformer. At the moment I'm using ray casts to figure out collision between the player and map. However using ray cast has some problems. For example, if the player is falling (has somewhat high downwards velocity) its unable to pick up holes in the wall because it moves past them due to going too far down to be detected as empty space.
One solution is to move to tile based system instead of using ray casts but I would preferably not to do so.
So I'm wondering is there some kinda solution to figure out empty holes in wall, even small edge ones without huge performance impact.
High quality drawn illustration, assume leftwards velocity:
Physics2D.BoxCast is how I would tackle this. It does what you expect, instead of a ray it calculates as if a full box was traversing the distance.
Usage is very similar to raycasting. Example:
public Collider2D mainCollider;
public Vector2 velocity;
void Update() {
Vector2 origin = new Vector2(transform.position.x, transform.position.y);
Vector2 size = mainCollider.bounds.size;
Vector2 direction = velocity * Time.deltaTime;
float maxDist = velocity.magnitude;
var hit = Physics2D.BoxCast(origin, size, 0, direction, maxDepth);
if (hit == null) {
transform.position += direction;
} else {
transform.position += direction.normalized * hit.distance;
}
}
If boxes are not your taste, there's also a Physics2D.CapsuleCast and Physics2D.CircleCast.
I am making a third person mobile game with the help of joysticks. I have it set up where joystick.vertical moves the character forward or backwards depending on where he is looking and joystick.horizontal turns the character. Since the camera is parented to the character the camera always stays behind the character.
Swiping across the screen rotates the camera around the player with a touch panel using Camera.main.transform.RotateAround() function and the transform.LookAt() ensures I am looking at my character always.
My issue: I would like when the swipe is let go the camera to return to its original position behind the character but in a smooth motion or at a set speed moving around the player.
My Solution 1: To make an empty gameObject parented to the character and place it in the position where I want the camera to revert back to and call this position when the mouse is let go.
float spanCamera = -Joystick.Horizontal;
Camera.main.transform.LookAt(rb.transform.position);
if (spanCamera != 0)
Camera.main.transform.RotateAround(rb.position, Vector3.up, spanCamera * Time.fixedDeltaTime * spanSpeed);
else if (Input.touchCount <= 1)
{
float var6 = var5 * Time.deltaTime;
Camera.main.transform.position = camPos.transform.position;
Camera.main.transform.LookAt(camLookAt.transform.position);
}
This piece of code moves the camera back to the start position immediately without smoothing.
Solution 2: use a Vector3.MoveTowards() instead
// Camera.main.transform.position = camPos.transform.position;
Camera.main.transform.position = Vector3.MoveTowards(Camera.main.transform.position, camPos.transform.position, var6);
This code allows me to smoothly move to the start position in a straight line. I want it to go around the player.
So I tried a different method where I assign a float value 1 if the camera turns right and check if the rotate button is let go and if the value is 1 within an if block.
public float axisDir;
...
else if (spanCamera == 0 && axisDir == 1)
{
Camera.main.transform.RotateAround(rb.position, Vector3.up, -1 * Time.fixedDeltaTime * spanSpeed);
}
But this results in an infinite spin because I do not know how to check if the desired position has been reached.
I hope someone can help. This is quite a long post. :(
You could have an dummy gameObject as a child of the player, and the camera as a child of the dummy.
That way, the camera is looking at the centre of the gameObject: where the player is. The camera would also rotate with the player, so it would always be behind the player.
Now, you know that when Mathf.Approximately(dummy.transform.localEulerAngles.y, 0.0f), the camera is behind the player. [1][2]
Knowing that, you can check when the player stopped swiping and start slowly rotating it back.
// If the player let go and camera is not behind the player
if (!playerIsSwiping && !Mathf.Approximately(dummy.transform.localEulerAngles.y, 0.0f))
{
// Slowly rotate until the camera is behind the player
dummy.transform.RotateAround(Vector3.zero, Vector3.up, rotationSpeed * Time.deltaTime);
}
try this buddy :
// Maximum turn rate in degrees per second.
public float turningRate = 30f;
// Rotation we should blend towards.
private Quaternion _targetRotation = Quaternion.identity;
// Call this when you want to turn the object smoothly.
public void SetBlendedEulerAngles(Vector3 angles)
{
_targetRotation = Quaternion.Euler(angles);
}
private void Update()
{
// Turn towards our target rotation.
transform.rotation = Quaternion.RotateTowards(transform.rotation, _targetRotation, turningRate * Time.deltaTime);
}
i found it here
from my own experience using LERP works quite well, you lookin for a smooth transition, or between two points, known as interpolation, in this case linear interpolation.
I am working on a small mini-game that requires the rotation of a cube 90 degrees in the appropriate direction based on the direction you swipe. So you could swipe up and it would rotate up 90 degrees, and them immediately after, swipe left, and it would swipe 90 degrees to the left from your current rotation (so it would stay rotated up 90 degrees as well). I feel like this should be really simple, but it's giving me a ton of trouble.
I would like to use Lerp/Slerp so that the rotation looks nice, though it isn't entirely necessary. The way I currently have it implemented, each time I call my "SlerpRotateLeft()" function for example, it only rotates to the exact same exact rotation relative to the world each time (instead of the current rotation + 90 degrees in the correct direction).
I have been reading up on Quaternions and Euler angles all day, but I'm still not entirely sure what my problem is.
I am currently using states to determine when the object is currently rotating and in what direction, though I feel like I may be overcomplicating it. Any possible solution to this problem (where you can swipe in a particular direction, in any order, in succession, to rotate a cube 90 degrees in that particular direction). Previously, I attempted to use coroutines, but those didn't have the desired effect either (and I was unable to reset them).
Here is my class. It works and you can test it by dropping the script into any cube object in-editor, but it doesn't work as intended. You will see what my problem is by testing it (I recommend placing an image on the cube's front face to track which one it is). I'm not sure if I explained my problem properly, so please let me know if any more information is needed.
****UPDATE: I have accepted #Draco18s's answer as correct, because their solution worked. However, I did not completely understand the solution, or how to store the value. I found an answer to a similar question that also used Transform.Rotate, and stored the value, which helped clear the solution up. The key seemed to be storing it in a GameObject instead of in a Quaternion like I originally thought. I thought I should provide this code in case anyone stumbles upon this and is equally confused, though you may not need the swipe detection:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotater : MonoBehaviour
{
private GameObject endRotation;
//SWIPE VARIABLES
public Vector2 touchStart = new Vector2(0, 0);
public Vector2 touchEnd = new Vector2(0, 0);
public Vector2 currentSwipe = new Vector2(0, 0);
public Vector2 currentSwipeNormal = new Vector2(0, 0);
// Use this for initialization
void Start()
{
endRotation = new GameObject();
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
touchStart = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
//Debug.Log("Touched at: " + touchStart);
}
if (Input.GetMouseButtonUp(0))
{
touchEnd = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
//Get Swipe Vector information
currentSwipe = new Vector2(touchEnd.x - touchStart.x, touchEnd.y - touchStart.y);
//Normalize Swipe Vector
currentSwipeNormal = currentSwipe;
currentSwipeNormal.Normalize();
//Swipe up
if (currentSwipeNormal.y > 0 && currentSwipeNormal.x > -0.5 && currentSwipeNormal.x < 0.5)
{
endRotation.transform.Rotate(-Vector3.left, 90, Space.World);
}
//Swipe down
if (currentSwipeNormal.y < 0 && currentSwipeNormal.x > -0.5 && currentSwipeNormal.x < 0.5)
{
endRotation.transform.Rotate(Vector3.left, 90, Space.World);
}
//Swipe left
if (currentSwipeNormal.x < 0 && currentSwipeNormal.y > -0.5 && currentSwipeNormal.y < 0.5)
{
endRotation.transform.Rotate(Vector3.up, 90, Space.World);
}
//Swipe right
if (currentSwipeNormal.x > 0 && currentSwipeNormal.y > -0.5 && currentSwipeNormal.y < 0.5)
{
endRotation.transform.Rotate(-Vector3.up, 90, Space.World);
}
}
LerpRotate();
}
void LerpRotate()
{
transform.rotation = Quaternion.Lerp(transform.rotation, endRotation.transform.rotation, Time.deltaTime * 10);
}
}
Use Transform.RotateAround
You're encountering an issue where you take the current Euler angles and try and add/subtract 90, which does not necessarily correlate to the desired position, due to the rotated nature of the rotated reference frame.
But using RotateAround, you can pass in the global Up, Left, and Forward vectors, which is what you're trying to do.
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.