I started my game dev journey a few weeks ago and I am enjoying it, but sometimes it can get frustrating when things do not work.
I wrote a very basic code for particle system, if we press space then particle should play. The problem is that its not playing, when I hit play it doesn't work for some reason. When I click the particle in the scene then it works and it also works when I check on the play on awake
The Code:
[SerializeField] ParticleSystem engineBoostParticle;
[SerializeField] ParticleSystem sideEngineParticles;
void Start()
{
}
void Update()
{
ThrustingInput();
}
void ThrustingInput()
{
if (Input.GetKey(KeyCode.Space))
{
if (!engineBoostParticle.isPlaying)
{
engineBoostParticle.Play();
}
}
else
{
AS.Stop();
engineBoostParticle.Stop();
}
}
You want to check engineBoostParticle.isEmitting as well as isPlaying in your if statement.
It's possible that your system is playing, but not emitting (because the loop is over), so make sure the particle system loops properly as well.
Related
I Have a player which gets childed to a game object when it walks up to a trigger now I want the player's parent to become null again after space is pressed because I'm trying to make a rope system, and it's required for the player to be able to de-attach from the rope
This is the script that's supposed to attach/detach the player from the rope
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AttachToRope : MonoBehaviour
{
public GameObject objectToParentTo;
public GameObject objectWithSwingScript;
// Start is called before the first frame update
private void OnTriggerEnter(Collider collider)
{
if (collider.gameObject.tag == "Rope")
{
transform.parent = objectToParentTo.transform;
objectWithSwingScript.GetComponent<playerscript>().enabled = true;
GetComponent<PlayerController>().enabled = false;
GetComponent<CharacterController>().enabled = false;
GetComponent<Swinging>().enabled = false;
}
}
private void OnTriggerStay(Collider collider)
{
if (Input.GetButtonDown("Jump"))
{
transform.parent = null;
objectWithSwingScript.GetComponent<playerscript>().enabled = false;
GetComponent<PlayerController>().enabled = true;
GetComponent<CharacterController>().enabled = true;
GetComponent<Swinging>().enabled = true;
Debug.Log("Deattached");
}
}
}
What happens when the player enters the trigger is that the scripts that make the player move get disabled and then it gets chilled to the last section of the rope now in ontriggerstay i want it to check if space is pressed and re-enable all the scripts that are required for the player to move (which does not work) but since nothing in there works i tried to debug.log but even that does not work so if anyone knows how to fix this please help me
From the OnTriggerStay documentation: The function is on the physics timer so it won't necessarily run every frame.
Functions on the physics timer (e.g. FixedUpdate()) don't play nicely with Input.GetButtonDown because they don't run every frame. Instead, they run on a fixed timestep, 0.02 seconds by default.
The solution is to put calls to Input.GetButtonDown into Update(). For instance, in this example you could have a boolean member variable isJumpPushed and set it to true in Update() when the jump button is pushed and the player is attached, and then check that value in OnTriggerStay.
--
A note about debugging:
I tried to debug.log but even that does not work
If your Debug.Log isn't showing a log in the console, that still tells you something important. It tells you that code path isn't getting called. That's an important clue for you to figure out what's really going on. To further narrow down the problem, you could move the Debug.Log statement outside the if statement. This would show that it's Input.GetButtonDown that isn't returning true when you think it is.
I am using coroutines to manage cooldowns for powerups in my game. When the player collides with a powerup they will get the effect and a cooldown will start so they can't use it again for a certain amount of time.
I am using coroutines to manage these cooldowns - setting the gameObject to false, waiting for the cooldown, then setting the gameObject back to true.
My code:
IEnumerator RespawnTime ()
{
gameObject.SetActive(false);
Debug.Log("disabled");
yield return new WaitForSeconds(3f);
gameObject.SetActive(true);
Debug.Log("enabled");
}
private void OnCollisionEnter2D (Collision2D collision)
{
// Health stuff goes in here.
Debug.Log("Health regen!");
// Start cooldown
StartCoroutine(RespawnTime());
}
However, the gameObject is never activated again once disabled. I don't think the problem is with the yield as commenting out the SetActive statements results in both debug messages being displayed at the correct times.
Edit:
Sorry, I didn't clarify. I know coroutines don't run on disabled GameObjects. I made a PowerUpManager script and it didn't work. Code:
In the PowerUp script, in the OnCollisionEnter2D method
StartCoroutines(PowerUpManager.RespawnTime(gameObject))
In the PowerUpManager script
public static IEnumerator RespawnTime(GameObject powerUp)
{
powerUp.SetActive(false);
yield return new WaitForSeconds(3f);
powerUp.SetActive(true);
}
The moment you call
gameObject.SetActive(false);
this object does not receive the Update message anymore and thus also doesn't execute the Coroutine further.
Coroutines are also stopped when the MonoBehaviour is destroyed or when the GameObject it is attached to is disabled.
The reason your second attempt doesn't work is: You still are calling StartCoroutine on the same GameObject so the Coroutine of the PowerUpManager class is now executed on your GameObject => same effect.
If you really want to go with the PowerUpManager you would need a Singleton instance and call StartCoroutine on that instance like e.g.
In PowerUpManager have
public static PowerUpManager Instance;
private void Awake()
{
Instance = this;
}
then you can call from your script
PowerUpManager.Instance.StartCoroutine(PowerUpManager.RespawnTime(gameObject));
In your simple case where there is no smooth moving etc required but only a simple delay I would suggest rather using Invoke with your desired delay. This will also be executed on a disabled or inactive GameObject.
private void EnableAfterCooldown()
{
gameObject.SetActive(true);
Debug.Log("enabled");
}
private void OnCollisionEnter2D (Collision2D collision)
{
// Health stuff goes in here.
Debug.Log("Health regen!");
gameObject.SetActive(false);
Invoke("EnableAfterCooldown", 3f);
}
If you deactivate the game object, all its components get disabled as well, so the Coroutine stops being invoked.
What you can do, is to separate the Coroutine for the cool down and the script that checks the collision, in 2 separate scripts.
Let’s call the Cooldown.cs and Powerup.cs.
Then, have them cross referenced in each other.
In powerup.cs you have
private void OnCollisionEnter2D (Collision2D collision)
{
// Health stuff goes in here.
Debug.Log("Health regen!");
// Start cooldown
Cooldown cd = gameObject.GetComponent<cooldown>();
cd.CooldownCoroutine();
}
In Cooldown.cs:
IEnumerator RespawnTime ()
{
Powerup pu = gameObject.GetComponent<Powerup>()
pu.SetActive(false);
Debug.Log("disabled");
yield return new WaitForSeconds(3f);
pu.SetActive(true);
Debug.Log("enabled");
}
public void CooldownCoroutine()
{
// Health stuff goes in here.
Debug.Log("Health regen!");
// Start cooldown
StartCoroutine(RespawnTime());
}
This way you don’t disable the whole object, but only the script that checks for collisions.
Coroutines do not run on disabled game objects!
You should run this on another game object.
I'm making a function that it switches 2 scenes.
When the player enters the trigger, automatically unity switches the scene and in the "Scene view", the player is there, as I wanted. But in the game view, the player dissappears, I don't know why.
I tried to remove a script that it's function is teleport the player to a specific point of the new scene, and it worked.
But obviously I don't want that, because unity automatically teleports the player to a random point, how can I fix that?
Here are the scripts:
TeleportScript:
public class EnterScene : MonoBehaviour
{
public string transitionName; //Also 1-1
void Start()
{
if (transitionName == PlayerController.sharedInstance.areaTransitionName)
{
PlayerController.sharedInstance.transform.position = transform.position; //Moves the player to GameObject position
}
}
// Update is called once per frame
void Update()
{
}
}
https://pastebin.com/jdSPhR3s <-----SceneLoader
https://pastebin.com/KcwHVBfQ <----PlayerController
And a screenshot of my problem:
Problem
This question already has answers here:
Detect mouse clicked on GUI
(3 answers)
Closed 4 years ago.
Description
Hi Guys need your help I faced problems with mouse clicks which pass through UI panel in Unity, that is, I have created pause menu and when I click Resume button, the game gets unpaused and the player plays Attack animation which is undesirable.What I want is when I click Resume button, Attack animation should not be played. The same problem if I just click on panel not necessarily a button and the more I click on UI panel the more Attack animation is played after I exit pause menu. Moreover, I have searched for solutions to this issue and was suggeted to use event system and event triggers but since my knowledge of Unity is at beginner level I could not properly implement it. Please guys help and sorry for my English if it is not clear)) Here is the code that I use:
The code:
using UnityEngine;
using UnityEngine.EventSystems;
public class PauseMenu : MonoBehaviour {
public static bool IsPaused = false;
public GameObject pauseMenuUI;
public GameObject Player;
private bool state;
private void Update() {
//When Escape button is clicked, the game has to freeze and pause menu has to pop up
if (Input.GetKeyDown(KeyCode.Escape)) {
if (IsPaused) {
Resume();
}
else {
Pause();
}
}
}
//Code for Resume button
public void Resume() {
//I was suggested to use event system but no result Attack animation still plays once I exit pause menu
if (EventSystem.current.IsPointerOverGameObject()) {
Player.GetComponent<Animator>().ResetTrigger("Attack");
}
pauseMenuUI.SetActive(false);
Time.timeScale = 1f;
IsPaused = false;
}
//this method is responsible for freezing the game and showing UI panel
private void Pause() {
pauseMenuUI.SetActive(true);
Time.timeScale = 0f;
IsPaused = true;
}
//The code for Quit button
public void QuitGame() {
Application.Quit();
}
}
Im not sure if i understood your problem, but it sounds like somewhere in your code you start an attack when the player does a left click.
Now your problem is that this code is also executed when the player clicks on a UI element, for example in this case the Resume button?
You tried to fix this problem, by resetting the attack trigger of the animator, i think it would be a better solution to prevent the attack from starting instead of trying to reset it later.
EventSystem.current.IsPointerOverGameObject() returns true if the mouse is over an UI element.
So you can use it to modify your code where you start your attack:
... add this check in your code where you want to start the attack
if(EventSystem.current.IsPointerOverGameObject() == false)
{
// add your code to start your attack
}
...
Now your attack will only start if you are not over a UI element
I made a pretty basic 2D game to learn. I have 2 Scenes, and switching between them worked great. I used empty gameObjects as Start/Exit point of the Scene, so that the game would know to put player on point X after exiting through point X (for example exit outside house if I walk out the door).
Then I added a "Scene0", to use for persistent general scripts like GameManager, Sounds, Music, etc. With just one object called "Controller" that I DontDestroyOnLoad().
After adding this Scene and then just switching Scenes right away to my MainScene, all of a sudden the game starts acting really strange;
the first time I move from my MainScene (Scene1), to my secondary Scene (Scene2), it works fine, but then when I leave Scene2 to go back to Scene1, the player spawns in the middle of nowhere.
And this ONLY happens if I launch the game from my Persistent Scene.
I have no idea what is wrong, I don't add anything that interferes with my scene transitions, all I've added so far is playerHealth, for testing.
Scripts attached to my (persistent) Controller:
DDOL:
public class DDOL : MonoBehaviour {
// Use this for initialization
void Awake () {
DontDestroyOnLoad (gameObject);
}
}
GameManager:
public class GameManager : MonoBehaviour {
public static GameManager manager;
public int playerMaxHealth;
public int playerCurrentHealth;
void Awake(){
if (manager == null) {
manager = this;
} else if (manager != this) {
Destroy (gameObject);
}
}
// Use this for initialization
void Start () {
SceneManager.LoadScene("test_scene");
}
// Update is called once per frame
void Update () {
}
}
Scripts attached to my StartPoint:
PlayerStartPoint:
public class PlayerStartPoint : MonoBehaviour {
private PlayerController thePlayer;
private CameraController theCamera;
public Vector2 startDir;
public string pointName;
// Use this for initialization
void Start () {
thePlayer = FindObjectOfType<PlayerController> ();
if (thePlayer.startPoint == pointName) {
thePlayer.transform.position = transform.position;
thePlayer.lastMove = startDir;
theCamera = FindObjectOfType<CameraController> ();
theCamera.transform.position = new Vector3(transform.position.x, transform.position.y, theCamera.transform.position.z);
}
}
}
And finally ExitPoint:
LoadNewArea:
public class LoadNewArea : MonoBehaviour {
public string levelToLoad;
public string exitPoint;
private PlayerController thePlayer;
// Use this for initialization
void Start () {
thePlayer = FindObjectOfType<PlayerController> ();
}
void OnTriggerEnter2D(Collider2D other){
if (other.gameObject.name == "Player")
{
SceneManager.LoadScene(levelToLoad);
thePlayer.startPoint = exitPoint;
}
}
}
EDIT:
After moving all my DDOL gameObject to the Pre-Scene, it worked. So, I can assume the fault is inside Player or Cameras Start() functions since when they start in Scene1 they get called every time I enter the Scene (only DDOL).
I tried adjusting their Start()functions like follows:
Original camera:
void Start () {
Debug.Log("Starting camera");
if (!cameraExists) {
cameraExists = true;
DontDestroyOnLoad (gameObject);}
else{
Destroy (gameObject);
}
}
Changed Camera:
void Start () {
DontDestroyOnLoad (gameObject);
}
The exact same changes was made in Player.
Obviously this doesnt work because it creates a new Camera/Player every time I enter Scene1 (btw why does it not try to create them when I enter Scene2?, is it because they start in Scene1?). HOWEVER, the new player/camera do start at the correct position, and if I zoom out I can see the old player/camera at that same wrong position as before. So something weird happens when their Start() is called a second time it seems.
You've now mentioned that you had code something like this,
void Start () {
Debug.Log("Starting camera");
if (!cameraExists) {
cameraExists = true;
DontDestroyOnLoad (gameObject);}
else{
Destroy (gameObject);
}
}
Note that this is unfortunately just "utterly incorrect", heh :)
The issues you mention in the question (preload scenes etc) are just totally unrelated to the problem here.
In Unity if you have a character C that persists between scenes a, b, c as you load those scenes, you must kick-off C in it's own (perhaps otherwise empty) scene, you can not use "a" as a matter of convenience to kick off C.
The pattern is, in each of a, b, c just have a line of code like p = FindObjectOfType<Player>(); which runs when the scene loads, and position C as you wish.
Now, regarding your specific puzzle about the unusual behavior you are seeing.
I understand that you want to know why you are observing what you do.
It is a combination of confusion over the following issues: 1 - difference between Awake and Start, 2 - confusion over script execution order {but see below1} 3 - confusion about Destroy versus DestroyImmediate 4 - Not using Debug.Log enough, and not using gameObject.name in there (it's a common in Unity to be wildly confused about which object is talking in Debug.Log) 5 - where you mention you see the other object "off to the side", it's common to drastically confuse which one is which in such situations 6 - confusion between the computer programming concept of "instantiation" (ie, of a class or object) and "instantiating" (confusingly, it's the same word - utterly unrelated) game objects in nity.
If you fiddle around with all those issues, you'll discover an explanation for the behavior you're seeing!
But it doesn't amount to much; in Unity in the "C .. a b c" example you have to create C separately beforehand.
1 {aside, never fiddle with the script execution ordering system in Unity in an effort to solve problems; it's only there for R&D purposes; however it could in fact help you investigate the behavior at hand in this problem, if you are particularly keen to fully understand why you're seeing what you're apparently seeing}
Use the debugger. Have breakpoints at the relevant spots, like PlayerStartPoint.Start() and LoadNewArea.OnTriggerEnter2D() and check that they are executed
At the right time
The right number of times
With the expected values
This should make you see where things get out of hand.
If you use Visual Studio, install https://marketplace.visualstudio.com/items?itemName=SebastienLebreton.VisualStudio2015ToolsforUnity to be able to debug Unity from within Visual Studio.
If you are not using Visual Studio, you probably should.
Is player persistent between scenes (does he have DontDestroyOnLoad)? If no then this might be the reason - you can either try loading the scenes by using the additive mode or by instantiating the player on scene load in correct position.