TrailRenderer start point on click - unity3d

I followed Brackeys tutorial on how to create a Fruit Ninja Replica (youtube).
When creating the blade, though, the behaviour I got wasn't exactly the same.
Expected behaviour
Actual behaviour
The difference is that in the Actual behaviour, the trail starts where it stopped the last time it was shown. The code responsible for this is exactly the same as the video:
public class BladeController : MonoBehaviour
{
bool isCutting = false;
public GameObject bladeTrailPrefab;
GameObject currentBlade;
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0)) {
StartCutting();
} else if (Input.GetMouseButtonUp(0)) {
StopCutting();
}
if (isCutting) {
UpdateCut();
}
}
void UpdateCut()
{
GetComponent<Rigidbody2D>().position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
void StartCutting()
{
isCutting = true;
this.currentBlade = Instantiate(bladeTrailPrefab, transform);
}
void StopCutting()
{
isCutting = false;
Destroy(currentBlade, 1f);
}
}
After understanding the code, I thought the problem was that I instantiated the bladeTrail before actually moving the Blade to the new position, but tried moving the Instantiate method to UpdateCut after changing the position and only if this.currentBlade == null.
I've search a lot about this, and even found some other posts with the same problem but no answer.

It seams the Instantiate is using the last mouse position to instiantiate the prefab.
Maybe use:
Instantiate(bladeTrailPrefab, Camera.main.ScreenToWorldPoint(Input.mousePosition), Quaternion.identity)

I ran into this problem following the tutorial as well.
It's a few years later but for those of you who hit this page, I found a solution for me that while isn't fantastic, it's better than having the streaks shown in the post.
Before instantiating the trail vfx, make sure to wait until fixed update is called after you set the position of the parent transform.
I did this with a Coroutine like so:
private IEnumerator StartCutting()
{
// When we begin cutting, move the blade object to the input position
m_isCutting = true;
m_previousPosition = m_camera.ScreenToWorldPoint(Input.mousePosition);
m_rigidBody.position = m_previousPosition;
// Then for positions to be updated so that the vfx doesn't get confused
yield return m_waitForFixedUpdate; // new WaitForFixedUpdate(); <-- cache this
// Instantiate the trail at this new position
m_currentTrail = Instantiate(m_trailPrefab, m_rigidBody.transform);
m_collider.enabled = false;
}

Related

Unity | instantiate only works once

For some reason whenever I Instantiate, I can only instantiate once per build/run/game. I've tried to see if it was that I could only use different prefabs, but that isn't it. Please help, I've been trying to find an answer but no one seems to have the same problem. Thanks for reading this.
heres the project (assets and project settings) if you wanna mess around with it yourself
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CreatePipe : MonoBehaviour
{
public GameObject Pipe;
public bool yes = false;
// Start is called before the first frame update
void Start()
{
StartCoroutine("initializationn");
Debug.Log("started");
}
// Update is called once per frame
void Update()
{
// if (yes){
// inst();
// yes = false;
// }
}
public IEnumerator initializationn()
{
Debug.Log("started");
inst();
// yes = true;
yield return new WaitForSeconds(3);
inst();
// yes = true;
yield return new WaitForSeconds(3);
inst();
// yes = true;
yield return new WaitForSeconds(3);
// while (true){
// inst()
// yield return new WaitForSeconds(3);
// }
}
public void inst(){
Debug.Log("in");
var g = Instantiate(Pipe, new Vector3(7f, Random.Range(-6.5f,0f), 0f), Quaternion.identity);
g.SetActive(true);
g.name = "Pipe";
}
}
The reason only one pipe exist at at time is that the script "PipeStuff" you attached to the Prefab "Pipe", makes it a singleton. So every time you create a duplicate instance you are deleting that object since a "PipeStuff" already exist.
Suggestions:
Your script is absolutely fine there is no problem with it but perhaps you are destroying that gameObject which is intantiating those pipe prefabs thats why its not working as you intend it to, any ways check if it is so because there seems to be no other problem with your script and also you can do it in one more way by using invokeRepeating function too like:
InvokeRepeating( nameof(inst), 0, 3 );
it will call this function repeatadely after every 3 seconds and the first parameter which is 0, is used for delay at the start so if you want to Invoke that function after some seconds you can do so as well and when you are done you can destroy or disable that gameObject too, its just a basic way of doing so otherwise there are tons of ways to do so anyways...
Hope it helps... Happy Coding :)

Unity - Set player position after loading scene

I am Trying to set player position after loading a scene. The program runs ok sometimes, but sometimes it places the player in the wrong position.
This is a video showing this strange behaviour: https://youtu.be/MFl9P3taV0Y
This is the code:
public class IniciaHeroi : MonoBehaviour
{
public GameObject GM;
private int startPosition;
void Awake()
{
startPosition = GM.GetComponent<StartScene>().startPosition;
if(startPosition == 1)
{
transform.position = new Vector3(119,4.67f,36);
transform.GetComponent<HeroiMovimento>().rot = -30;
Debug.Log("StartPosition1: " + transform.position);
}
if(startPosition == 2)
{
transform.position = new Vector3(49,13.8f,167);
transform.GetComponent<HeroiMovimento>().rot = 100;
Debug.Log("StartPosition2: " + transform.position);
}
}
}
Debug log shows always the correct position but, as you can see in the video, something changes the position.
Can anyone point the correct way to do this?
The problem was the Character controller attached to my player. For some strange reason Character Controller do not change its own transform.position when i change player transform.position.
So the solution is to disable Character Controller before change player position and Enable it after the change.
Thanks!! Having the same issue, and took me so long to find this. Finally I was able to solve by using disabling the Controller and then enabling it:
example:
gameObject.GetComponent<CharacterController>().enabled = false;
gameObject.transform.position = new Vector3(-31, 1, -10);
gameObject.GetComponent<CharacterController>().enabled = true;

Pooled GameObject in Unity destroys itself after SetActive if Force is applied

When I retrieve an object from a list of created objects and reactivate it, it destroys itself, but only if I have force applied to start it moving. If I never apply force, everything works as intended and I can keep activating the object over and over.
I've tried putting a debug.log in the OnCollision and it isn't colliding with anything.
As said above, if I never initiate speed, the rest works fine.
When speed is applied, the first projectile works, the second destroys itself.
I've tried manually activating them instead of by code. Same result.
Exception: If I manually activate/deactivate objects myself through the inspector, they work if I only have 1 shot in the pool.
The one shot rule doesn't work if I do it through code. It breaks even if I only have one shot.
All the code worked when I wasn't using pooling.
Spawn code:
void CreateBullet(int GunID)
{
GameObject ShotFired = Guns[GunID].GetComponent<Weapon>().FireWeapon();
if (ShotFired == null)
{
ShotFired = Instantiate(Guns[GunID].GetComponent<Weapon>().Projectile,Guns[GunID].gameObject.transform);
Physics.IgnoreCollision(ShotFired.GetComponent<SphereCollider>(), Guns[GunID].GetComponentInParent<CapsuleCollider>());
Guns[GunID].GetComponent<Weapon>().AmmoPool.Add(ShotFired);
}
ShotFired.transform.position = Guns[GunID].transform.position;
ShotFired.transform.rotation = Guns[GunID].transform.rotation;
ShotFired.SetActive(true);
}
Projectile Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Mirror;
public class Projectile : NetworkBehaviour
{
public float Speed;
public float LifeTime;
public float DamagePower;
public GameObject ExplosionFX;
// Start is called before the first frame update
void Start()
{
GetComponent<Rigidbody>().AddRelativeForce(Vector3.up * Speed, ForceMode.VelocityChange);
StartCoroutine(DeactivateSelf(5.0f));
}
private void OnDestroy()
{
Debug.Log("WHY!");
}
IEnumerator DeactivateSelf(float Sec)
{
yield return new WaitForSeconds(Sec);
Explode();
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.GetComponentInChildren<Vehicle>())
{
collision.gameObject.GetComponentInChildren<Vehicle>().CmdTakeDamage(DamagePower);
}
Explode();
}
void Explode()
{
GameObject ExplosionEvent = Instantiate(ExplosionFX, this.transform.position, Quaternion.identity);
NetworkServer.Spawn(ExplosionEvent);
GetComponent<Rigidbody>().AddRelativeForce(Vector3.zero);
gameObject.SetActive(false);
}
}
Any thoughts welcome. Thanks in advance!
In case anyone else stumbles across this, here's what happened and why assigning a movement speed to the object was what caused the issue.
My projectiles had a 'trailrenderer' on them.
By default 'Autodestruct' is true.
Autodestruct does not destruct the trail, but the game object when the trail disappears. So if you disable anything that had a trail, and activated it through movement, when the object stops moving (say to reposition in an object pool) it will destroy the parent object.
If the object never moves, it never generates a trail, and never needs to be destroyed.
To fix, just uncheck autodestruct.
https://docs.unity3d.com/ScriptReference/TrailRenderer-autodestruct.html

How do I change GameObject properties in scripts Unity?

I'm trying to save/load my game. In the load method, everytime I change the properties of a GameObject, those changes are applied and then get reverted shortly after. Here is my code:
public void Load()
{
SceneManager.LoadScene(sceneID);
List<GameObject> rootObjects = new List<GameObject>();
Scene scene = SceneManager.GetActiveScene();
scene.GetRootGameObjects(rootObjects);
int ncube = 0, npick = 0;
for (int i = 0; i < rootObjects.Count; ++i)
{
GameObject obj = rootObjects[i];
if (obj.CompareTag("Player"))
{
obj.transform.position = player.position;
obj.transform.rotation = player.rotation;
obj.transform.localScale = player.localScale;
}
else if (obj.CompareTag("Cube"))
{
obj.transform.position = cube[ncube].position;
obj.transform.rotation = cube[ncube].rotation;
obj.transform.localScale = cube[ncube].localScale;
++ncube;
}
else if (obj.CompareTag("Pickup"))
obj.SetActive(pickup[npick++]);
else if (obj.CompareTag("Door"))
obj.SetActive(door);
else if (obj.CompareTag("GreenWall"))
obj.SetActive(greenWall);
}
}
Those changes are applied to the GameObject, however they get aborted right away. How can I resolve this?
The script contains these lines of code is not a component of the GameObject.
Edit 1: Complete code updated.
Problem is I think that
Scene scene = SceneManager.GetActiveScene();
scene.GetRootGameObjects(rootObjects);
gets the objects from the scene before the Scene is fully loaded so they are reset.
From the Docu
When using SceneManager.LoadScene, the loading does not happen immediately, it completes in the next frame. This semi-asynchronous behavior can cause frame stuttering and can be confusing because load does not complete immediately.
I guess you rather should use SceneManager.sceneLoaded and do your stuff there like
public void Load()
{
SceneManager.LoadScene(sceneID);
}
And maybe in an extra component within the scene:
void OnEnable()
{
SceneManager.sceneLoaded += OnSceneLoaded;
}
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
// your stuff here
}
void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
}
though we don't know/see where player, cube[ncube] etc come from ...
for transparting values between Scenes you should get into using ScriptableObjects
The problem might be that SceneManager.LoadScene completes in the next frame. See the documentation: https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager.LoadScene.html
It says:
When using SceneManager.LoadScene, the loading does not happen
immediately, it completes in the next frame. This semi-asynchronous
behavior can cause frame stuttering and can be confusing because load
does not complete immediately.
You change the values within the same frame, thus they are overwritten when loading the scene finishes. Cou could use an event to prevent that behaviour: https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager-sceneLoaded.html

Unity 2D - Why Rect.Contains does Not work in this example?

In a 2D space:
I have an sprite and a script component is assigned to it
I've this statement in the Start method:
"onScreenRect = rt.rect;"
It will Not detect mouseOver as it could be expected!
Now if this statement is moved to Update method, it will.
Please explain why.
public class EvtPub : MonoBehaviour
{
RectTransform rt;
Rect onScreenRect;
void Start()
{
rt = GetComponent<RectTransform>();
// having next statement here, the code will Not work!
onScreenRect = rt.rect;
}
void Update()
{
// having next statement here, the code Will work!
// onScreenRect = rt.rect;
onScreenRect.Set(onScreenRect.x + transform.position.x,
onScreenRect.y + transform.position.y, onScreenRect.width, onScreenRect.height);
if (onScreenRect.Contains(Input.mousePosition))
{
Debug.Log("Mouse over detected!");
}
}
}
well, Rect in Unity is a struct,it's a value type. which means the onScreenRect will be a value copy of the rt.Rect,not the reference. when you put the statement in Start(), the value will be copied only one time and will not be updated. :)sry about my poor English and hope helpful.