I'm trying to get my player to light torches in a scene, but not quite sure how to do this.
I have a torch prefab that has a particle system. Each time the player's torch collides into an unlit torch, I would like that torch to start burning.
I have been trying to follow the docs but have not been able to understand (https://docs.unity3d.com/ScriptReference/ParticleSystem.html, https://docs.unity3d.com/ScriptReference/ParticleSystem.Play.html).
Also have this question posted here: https://answers.unity.com/questions/1491419/having-player-light-torches-using-particle-system.html
My current code is below. I have each torch object tagged as torch, and my player tagged as Player. All particle systems, except the player's torch, have 'Play on Awake' off and prewarm on.
Any advice or tips?
Thanks!
/*
* Attach this script to all the torches. It will be used to start the fire
using OnCollision?/OnTrigger? See which is better
* Start with the particle effect/light being off, get all the components
* Turn the torches on when the player's torch collides with them
* 1.) Must make sure each torch object has a collider
* */
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class StartFire : MonoBehaviour
{
public GameObject torch;
public ParticleSystem fireParticleSystem;
bool lightOn;
void Start()
{
lightOn = false; //Start with the light off
fireParticleSystem = GetComponent<ParticleSystem>(); //get Particle System
torch = GetComponent<GameObject>(); //get Torch
}
/*
* if player's torch hits this torch (that is not lit)
* Turn on the fire
* Set the light being on to true
* */
private void OnCollisionEnter(Collision collision)
{
if(this.gameObject.tag==("torch") && collision.gameObject.tag==("Player") && lightOn==false)
{
fireParticleSystem.Play(); //start the particle system
lightOn = true;
}
}
}
1.Create your ParticleSystem and change the tag of its GameObject to "torch".
2.Attach BoxCollider to the SphereCollider to that GameObject with the ParticleSystem.
3.Mark the IsTrigger of the collider created from #2 to be true because it doen't make sense to collide with a touch. It seems like you just want to detect when the player is touching it.
4.The touch script should attached to the player instead of the touch. Use OnTriggerEnter to handle the detection and detect when player touches the touch-light then use GetComponent to get the ParticleSystem and play it. Stop the particle in OnTriggerExit.
If you actually want player to collide and be stopped by the touch then ignore #2 and also use OnCollisionEnter and OnCollisionExit instead of OnTriggerEnter and OnTriggerExit.
Attach to the Player:
public class ParticlePlayer : MonoBehaviour
{
void OnTriggerEnter(Collider other)
{
//Make sure player is touching a touch
if (other.CompareTag("torch"))
{
//Get ParticleSystem from the Gameobject the player collided with
ParticleSystem ps = other.GetComponent<ParticleSystem>();
//Play Particle
ps.Play();
}
}
void OnTriggerExit(Collider other)
{
//Make sure player is touching a touch
if (other.CompareTag("torch"))
{
//Get ParticleSystem from the Gameobject the player collided with
ParticleSystem ps = other.GetComponent<ParticleSystem>();
//Stop Particle
ps.Stop();
}
}
}
I've used the following code in some of my projects:
private ParticleSystem _particleSystem;
private ParticleSystem.EmissionModule _emissionModule;
private void Awake()
{
_particleSystem = GetComponent<ParticleSystem>();
_emissionModule = _particleSystem.emission;
_emissionModule.enabled = false;
}
private void OnCollisionEnter(Collision collision)
{
_emissionModule.enabled = true;
_particleSystem.Play();
}
I believe you're missing the emission module.
Related
I am trying to make a projectile that spawns and when it hits the player he gets destroyed. I have to mention that the projectile would be spawned with the "Instantiate" command making it a "cloned gameobject". In the script I wrote that if the projectile would hit another gameobject with the tag "player" the gameobject it hits would get destroyed but after running the code and the projectile hit the player he didn't get destroyed. I checked and the tag does say "player". I threw in a debug command into the code and managed to find out that the tag doesn't get detected. The script for the projectile spawner and the projectile itself are separate so I'm going to only show the projectile script since it is the problematic script. I have to mention that the script doesn't generate any errors and that the simulation runs fine except for the things I have mentioned above.
public class Bulletboi : MonoBehaviour
{
public float speed;
private Transform player;
private Vector2 target;
public GameObject Elven;
void Start()
{
player = GameObject.FindGameObjectWithTag("player").transform;
target = new Vector2(player.position.x, player.position.y);
}
void Update()
{
transform.position = Vector2.MoveTowards(transform.position, target, speed * Time.deltaTime);
if(transform.position.x == target.x && transform.position.y == target.y)
{
DestroyProjectile();
}
}
void OnEnterTrigger2D(Collision2D other)
{
if (other.gameObject.tag.Equals("player"))
{
Debug.Log("bbbb");
DestroyProjectile();
Destroy(other.gameObject);
}
}
void DestroyProjectile()
{
Destroy(gameObject);
}
}
Never mind I decided to change the script a little bit and I put it on the player and made it detect the tag of the projectile and now it works.
I am using a Player rigid body object and there are walls around the Player. These walls are restricting the Player to go through. The Player gets collided with these walls and then falls. The Player uses teleport function to jump from one area to next. Is there a way to make the Player jump to a position just outside the collision area after the Player is collided with these walls?
That is, Player A gets collided with the wall and does not jump to last position, but the position before the collision happened?
public GameObject Player;
public Vector3 PlayerPos;
public bool RecordPos = true;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if(RecordPos == true)
{
PlayerPos = Player.transform.position;
}
}
public void OnTriggerEnter(Collider col)
{
if(col.gameObject.name == "Cube(3)" )
{
RecordPos = false;
Player.transform.position = PlayerPos;
}
}
In this script, the Player moves to last position it teleported from.
The "last" position before colliding is 1 frame before the collision. If you capture this position, the character will probably just fall on the obstacle again. Imagine you have a platform ___...___ and an obstacle. The easiest solution is to have 1 trigger at the left side of the obstacles and 1 trigger at the right side. If the player hasn't overcome the obstacle yet, he will be teleported to a chosen destination by you (before the obstacle) and if he's already overcome the obstacle, he will be teleported at the right side. __S_..._S__ (S stands for save/checkpoint trigger)
You need the following script on the gameobject with the Trigger collider. You also need to create a child object to the gameobject with the trigger:
private void OnTriggerEnter2D(Collider2D collision)
{
SaveManager.Instance.LastCheckpointOnHit = transform.GetChild(0).position;
}
And I suppose you have some sort of a singleton for data persistance. Now you can move the child gameobject whereever you want to teleport the player. And BTW I named the property LastCheckpointOnHit, because I was thinking of Holow Knight where if you get hit by spikes it instantly teleports you.
Then you just move the player: Player.transform.position = SaveManager.Instance.LastCheckpointOnHit;
In general when dealing with Rigidbody you shouldn't apply positions through the Transform component but rather through the Rigidbody.
I could imagine something like if you collide with a wall you get pushed away from the wall a bit in the direction where you came from like e.g.
[SerializeField] private float someDistanceThreshold = 0.01f;
[SerializeField] private Rigidbody _rigidbody;
private void Start()
{
if(!_rigidbody) _rigidbody = Player.GetComponent<Rigidbody>();
}
private void FixedUpdate()
{
PlayerPos = _rigidbody.position;
}
public void OnTriggerEnter(Collider col)
{
// instead of the name I would rather use a tag later to cover all obstacles
if(col.gameObject.name == "Cube(3)")
{
_rigidbody.position -= (_rigidbody.position - PlayerPos).normalized * someDistanceThreshold;
// For stopping the player here
_rigidbody.velocity = Vector3.zero;
}
}
In my platform game I have just added some checkpoints, so that if the player dies doesn't necessarily spawn at the beginning of the track.
ghfdghdggfhfg
using UnityEngine;
public class CheckPoints : MonoBehaviour
{
[SerializeField] private Grounded game;
void Update()
{
transform.Rotate(0, 0, 5);
}
private void OnTriggerEnter() {
game.updatedCheckPointPosition = transform.position;
Destroy(this);
}
}
What I unsuccessfully tried to do is to set the public float variable of the Grounded script to the current position of the CheckPoint itself, which should be destroyed after doing that.
Any information or help on how to do this is really appreciated.
From Destroy
The object obj will be destroyed now or if a time is specified t seconds from now.
If obj is a Component it will remove the component from the GameObject and destroy it. [But keep the rest of the GameObject intact!]
If obj is a GameObject it will destroy the GameObject, all its components and all transform children of the GameObject.
this refers to the according component instance. What you want is rather
Destroy(gameObject);
OnTriggerEnter requires a parameter of type Collider in order to work
private void OnTriggerEnter(Collider other)
{
game.updatedCheckPointPosition = transform.position;
Destroy(this);
}
Note however that this way round the player has to be a trigger while the checkpoint a non-trigger! I would actually rather do it the other way round and make the chackpoint a trigger and rather let the player object check for OnTriggerEnter.
i am bloody beginner with Unity and i am currently working on a 2D Brawler. The movement works perfectly but my colliders don't do what they should... I want to detect if two GameObjects Collide (Spear and Player2) and if the collide Player2s healthPoints should decrease by Spears AttackDamage.
The names of the GameObjects are also their tags. The Spears Prefab has following configuration: SpriteRendered(Material Sprites-Default), BoxCollider2D(Material None Physics Material 2D, IsTrigger(not activated), UsedByEffector(also not activated) Rigidbody2D(Kinematic, None Material, Simulated(Activated), KinematicContacts(activated), Standard configs for the rest))
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpearCtr : MonoBehaviour {
public Vector2 speed;
public float delay;
Rigidbody2D rb;
void Start ()
{
rb = GetComponent<Rigidbody2D>();
rb.velocity = speed;
Destroy(gameObject, delay);
}
void Update ()
{
rb.velocity = speed;
}
}
The Players Configurations
The Spears Configurations
This was the code i have tried before
OnCollision2D(Collision2D target);
{
if (target.gameObject.tag == "Spear")
{
hp = -1;
if (hp <= 0)
{
alive = false;
}
}
}
I hope someone can tell me how to get this working
Thanks for all the answers
(BTW sorry for my bad english I am austrian)
enter image description here
enter image description here
Reasons why OnCollisionEnter() does not work:
Collison:
1.Rigidbody or Rigidbody2D is not attached.
At-least, one of the two GameObjects must have Rigidbody attached to it if it is a 3D GameObject. Rigidbody2D should be attached if it is a 2D GameObject/2D Collider.
2.Incorrect Spelling
You failed to spell it right. Its spelling is also case sensitive.
The correct Spellings:
For 3D MeshRenderer/Collider:
OnCollisionEnter
OnCollisionStay
OnCollisionExit
For 2D SpriteRenderer/Collider2D:
OnCollisionEnter2D
OnCollisionStay2D
OnCollisionExit2D
3.Collider has IsTrigger checked. Uncheck this for the OnCollisionXXX functions to be called.
4.The script is not attached to any of the Colliding GameObjects. Attach the script to the GameObject.
5.You provided the wrong parameter to the callback functions.
For 3D MeshRenderer/Collider:
The parameter is Collision not Collider.
It is:
void OnCollisionEnter(Collision collision) {}
not
void OnCollisionEnter(Collider collision) {}
For 2D SpriteRenderer/Collider2D:
6.Both Rigidbody that collides has a isKinematic enabled. The callback function will not be called in this case.
This is the complete collison table:
I'm trying to build a pool game where the pot has a collider. Now on collision with a ball, I expect that particular ball that collided to disable.
The code below is what I've tried but it only allows me to set the ball manually. How do I automat and detect the right ball directly?
using UnityEngine;
using System.Collections;
public class pot: MonoBehaviour
{ //allows me to set collider
public SphereCollider ball;
void OnTriggerEnter(Collider other) {
Debug.Log("Ball potted");
ball = GetComponent<SphereCollider>();
ball.enabled = !ball.enabled;
}
}
Is
other.enabled = false;
what you are looking for?
It looks like your code is getting the sphere collider of the pot itself. Isn't "other" the ball in this case?
You can disable the "other" object (assuming it is the ball) with "other.gameObject.SetActive(false)" -- that's if you want the whole ball to disappear. If you just want it's collider to stop working then use "other.enabled = false".
public SphereCollider sphereCollider;
void Update()
{
if (Input.GetKeyDown(KeyCode.Q)) //or however you want to call it.
{
sphereCollider = gameObject.GetComponent<SphereCollider>();
sphereCollider.enabled = false;
}
}