I'll keep this brief and a bit short, but I currently have a particle system that seems to not be rendering even though my collision works.
I have trouble understanding other peoples work so I have not been able to find a solution I can understand.
Here is my code:
public float speed;
public Rigidbody rb;
public int health;
private float knockback;
private float knockup;
public ParticleSystem Eparticle; //*** variable for particle system ***
// Use this for initialization
void Start()
{
rb = GetComponent <Rigidbody>();
knockback = 100f;
knockup = 250f;
}
void OnCollisionEnter(Collision col)
{
if (col.gameObject.name == "enemy")
{
health = health - 20;
rb.AddRelativeForce(Vector3.back * knockback);
rb.AddRelativeForce(Vector3.up * knockup);
Destroy(col.gameObject);
Instantiate(Eparticle);
}
if (col.gameObject.name == "endgoal")
{
SceneManager.LoadScene("level 1");
}
}
What am I doing wrong with my instantiate(Eparticle) line?
Could someone please talk me through a solution?
Thank You :)
You should invoke the Instantiate method at the position where you want the particle prefab to appear.
You could do something like this...
Instantiate(Eparticle,transform.position,transform.rotation);
Actually, you can also create (instantiate) a GameObject at runtime as follows...
GameObject obj= Instantiate(Eparticle,transform.position,transfrom.rotation) as GameObject;
This way, you have some sort of 'control' over the instantiated gameobject.
For instance, you can destroy the object after using it by calling the Destroy() method.
E.g.:
Destroy(obj,2f);//Destroys the created object after 2 seconds.
Of course, this is not a good way to go about it if you are going to be instantiating and destroying a lot of objects. You should read about Object Pooling for this purpose.
Related
So I'm trying to make a little pushback effect in my tests arena, I've got a sphere collider and here is my script:
// PushBack Class Script
if (Input.GetKeyDown(KeyCode.Q))
{
explosion_ball.transform.position = transform.position;
StartCoroutine(WaitAndPrint());
}
IEnumerator WaitAndPrint()
{
float i = 0;
while (i < 1)
{
i += 0.01f;
explosion_ball.radius = curve.Evaluate(i) * 10;
yield return new WaitForSeconds(0.01f);
}
}
//__________//
Sphere collider is set and stuff, but it doesn't push things back like I thought it would.
Thanks!
Edit:
explosion_ball is a sphere collider, I'm changing it with the point on the animation curve and * it by 10
EDIT:Unity Rigid bodies go to sleep so[Also Change interpolation to continuous if collider changes size too quickly]
A.check if obstacle rigid bodies are Sleeping with onTriggerEnter and Wake Up
void OnTriggerEnter(collider){ if(rb.IsSleeping()){rb.WakeUp();}
or
B.Attach this forceWakeUp Script to all Objects you want to be obstacles.
using UnityEngine;
public class forceWakeUp : MonoBehaviour
{
private Rigidbody rb;
void Start()
{
rb = gameObject.GetComponent<Rigidbody>();
}
void Update()
{
if(rb.IsSleeping()){rb.WakeUp();}
}
}
Forcibly Keeping Many objects awake Will impact performance.So ,your decision.
You need to scale up the collider on the object by radius and all the objects it is supposed to wobble need to have Rigid body component attached to them
2.if you ARE doing above things and its not adding any force you could just add a force on all the overlapping objects using the "OnCollisionEnterTrigger" and AddForceMethod radially away from the Sphere
Obstacle.position - Sphere.position is the vector Radially away from Sphere I think.
You don't need coroutines for this I think.
While searching through the Unity scripting API, found a method in there called
Rigidbody.AddExplosionForce(explosionForce, explosionPosition, explosionRadius, upwardsModifier, mode)
In order to get the rigid bodies that are to be affected by the explosion I would need to get them using Physics.OverlapSphere(position, radius) this gets all of the objects within the radius variable, then get the component.
Combining these two would also look like:
Collider[] colliders = Physics.OverlapSphere(transform.position, radius);
foreach (Collider hit in colliders)
{
if (hit.transform.tag == "Interactable")
{
if (hit.gameObject != hitgameObject)
{
Rigidbody rb = hit.GetComponent<Rigidbody>();
if (rb != null)
rb.AddExplosionForce(power, transform.position, radius, upForce, ForceMode.Impulse);
}
}
}
If there is any explaining that you would like me to do about my variables mentioned I will reply :)
Thanks for the help guys.
I don't know your curve and what values that evaluation produces, but you can check your code visually with Window/Analysis/Physics Debugger, or write a gizmo:
private void OnDrawGizmos()
{
Gizmos.color = new(1.0f, 0.0f, 0.0f, 0.5f);
Gizmos.DrawSphere(explosion_ball.transform.position, explosion_ball.radius);
}
Or simply just use https://docs.unity3d.com/ScriptReference/Rigidbody.AddExplosionForce.html
I have a script for that Instantiates 2 game object but when something happens to one of them it also happens to the another one even when the conditions are not met for it. How can I make the script act separately for every Game Object?
GO script:
private Transform target;
public float speed = 2f;
private Animator anim;
public float H2Damage = 5f;
private healthBar Hp;
void Start()
{
target = GameObject.FindGameObjectWithTag("enemy").GetComponent<Transform>();
anim = gameObject.GetComponent<Animator>();
Hp = GameObject.FindGameObjectWithTag("enemy").GetComponentInChildren<healthBar>();
}
void Update()
{
target = GameObject.FindGameObjectWithTag("enemy").GetComponent<Transform>();
if (Hp.Died == true)
{
Hp.Died = false;
anim.SetBool("Hero2Attack", false);
anim.SetBool("Hero2Move", true);
}
if (!target || this.anim.GetCurrentAnimatorStateInfo(0).IsName("Hero2ATTACK"))
return;
transform.position = Vector2.MoveTowards(transform.position, target.position, speed * Time.deltaTime);
anim.SetBool("Hero2Move", true);
}
private void OnTriggerEnter2D(Collider2D col)
{
if (col.gameObject.CompareTag("enemy"))
{
anim.SetBool("Hero2Attack", true);
healthBar hp = col.transform.GetComponent<healthBar>();
hp.GiveDamage(H2Damage);
}
}
I believe they act the same way because they are getting the same GetComponentWithTag(), so they will Get the same objects. You also instantiate the animator, which is the exact same one, so they will do the same things. --> If it was as simple as changing the position by 1 meter per second, they would have different behavior (ie. be at different positions) But.... If you instantiate it, the current position is also instantiated, so you are going to have to get the current postion and set it to what you want, so both of these moving boxes aren't at the exact same position. You will have to do something similar here, you are going to want to either (create different scripts for the objects, or set the script values to different things)
TL;DR: You are copying the exact same script with the exact same components, so they will act similarly.
Fix: The only way to fix this is by setting their values after you instantiate them using GetComponent<>()or changing the script you assign them. (or any components for that matter)
Let me know if you have any problems or questions in the comments! :)
I've followed a C# in Unity tutorial to create a simple Space Invaders game. I'm now trying to understand the different functions being used.
There is this class called PlayerController. It also defines a shot gameobject, a field which is then supplied with a bullet prefab:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
private Transform player;
public float speed;
public float maxBound, minBound;
public GameObject shot;
public Transform shotSpawn;
public float fireRate;
private float nextFire;
// Start is called before the first frame update
void Start()
{
player = GetComponent<Transform> ();
}
// Update is called once per frame
void FixedUpdate()
{
float h = Input.GetAxis ("Horizontal");
if (player.position.x < minBound && h < 0)
h = 0;
else if (player.position.x > maxBound && h > 0)
h = 0;
player.position += Vector3.right * h * speed;
}
void Update()
{
if (Input.GetButton("Fire1") && Time.time > nextFire)
{
nextFire = Time.time + fireRate;
Instantiate(shot, shotSpawn.position, shotSpawn.rotation);
}
}
}
The bullet gameobject used the class BulletController:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletController : MonoBehaviour
{
private Transform bullet;
public float speed;
// Start is called before the first frame update
void Start()
{
bullet = GetComponent<Transform>();
}
void FixedUpdate()
{
bullet.position += Vector3.up * speed;
if (bullet.position.y >= 10)
Destroy(gameObject);
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Enemy")
{
Destroy(other.gameObject);
Destroy(gameObject);
PlayerScore.playerScore++;
}
else if (other.tag == "Base")
Destroy(gameObject);
}
}
From what I understand, a Transform object has values for position, rotation and scale.
So first, what does declaring x = GetComponent; do?
Second, where does "shotSpawn" takes its values from? From the object to which the code is applied to?
Third, the bullet gets instantiated exactly at the center of the square serving as the player ship's body, but I want it start higher at the y axis so it starts at the end of the cannon shape. It also seems to graphically intersect with the ship's body, so I wanted to move it slightly into the z axis. So how can you write that? I tried adding to the value of shotSpawn.position but it keeps declaring errors.
Thanks in advance.
A GetComponent means basically just grabbing a component of an object. Take a simple example: The Main Camera has a lot of components:
1.1. A Transform component. This component is used, as you understood, to define the position, rotation and scaling of an object
1.2. A Camera component. This has plenty of fields
1.3. A Flare Layer component.
etc.
These components can be grabbed via script. The reason developers use this is for their properties. For example, by saying Transform playerTransformComp = player.GetComponent<Transform>();, you will be able to write playerTransformComp.position. position is a property of objects of type Transform.
I don't think that the GetComponent you saw in the tutorial are useful because every game object has a transform component anyway, so if they declared the player as public GameObject player;, then used player.transform.position instead, it would have been way easier. In fact, I don't think it even makes sense to declare something as Transform, and then grabbing the Transform component. As #BugFinder said in your previous post, the tutorial is pretty bad overall.
shotSpawn takes its values from... itself! It is a public object, so I'm assuming you dragged & dropped the shotSpawn object from the scene into the script's fields. This means that the shotSpawn object from the script is the object you dragged & dropped on the script's fields. You can use all of its features and the dragged & dropped object will be affected. Thus, you can use shotSpawn.position and shotSpawn.rotation. I might be repeating myself here for a little bit, but please notice that shotSpawn is a Transform object, therefore you can use a typical Transform object's properties.
The documentation on Transform.position (as well as the one on Transform.rotation say you have to use Vector3 objects to add or substract values to them.
One would do shotSpawn.position + new Vector3(10f, 5f, 10f).
Naturally, you can also do
value = new Vector3(10f, 5f, 10f);
and then Instantiate(shot, shotSpawn.position + value, shotSpawn.rotation);
Also, please (for the future), try to ask one question per post, otherwise people will ignore your question or even flag it and it will be deleted. I was once like you, so I wouldn't do that, but please take this into consideration when making further posts.
There is a problem with my bullet firing logic.
The first time everything works fine, but when I shoot the bullet after respawning it doesn't move. It only works for the first shot.
The bullet is a prefab.
Here is my code:
public Rigidbody2D bulletrb;
private float dirX=1;
public float speed=.001f;
public Transform playerPos;
private Vector3 bulletPos;
public GameObject bulletObj;
void Update () {
bulletPos.x = playerPos.transform.position.x + 2;
bulletPos.y = playerPos.transform.position.y + 1;
if (Input.GetKeyDown("1"))
{
bulletrb.velocity = new Vector2(dirX * speed, bulletrb.velocity.y);
Debug.Log("Shoot!");
}
}
private void OnTriggerEnter2D(Collider2D target)
{
if(target.gameObject.tag=="Zombie")
{
Destroy(bulletObj);
Debug.Log("Hited!");
Instantiate(bulletObj,bulletPos,Quaternion.identity,playerPos);
}
}
When you call Destroy, you are losing your active bullet GameObject, but when you call Instantiate, it is not actually assigned back to your bulletObj reference.
The quick and simple fix is:
bulletObj = Instantiate(bulletObj, bulletPos, Quaternion.identity, playerPos);
There are probably more improvements that could be made, but this is the gist of the issue.
One recommendation I would make is using bulletObj.SetActive(false) and bulletObj.SetActive(true) instead of Destroy and Instantiate
Hi i am currently working on a turret shooting script. My bullet shoots boet does not go in the enemy's direction. something is wrong or missing and i cant figure out what. I have looked up alot of solutions but cant find recent ones or good ones.
EDIT:
my enemy's are instantiated so there is multiple of them. would that be part of the problem? if not do i need to provide more details? im kina new to the site so pls forgive me if i do stuff wrong.
public GameObject Enemy;
public GameObject Bullet;
public float bulletForce = 100f;
private Vector3 direction;
// Use this for initialization
void Start ()
{
ShootFunctionRepeat();
}
// Update is called once per frame
void Update ()
{
direction = Enemy.transform.position - this.transform.position;
}
void ShootFunctionRepeat()
{
InvokeRepeating("ShootFunction", 0.0f, 1.0f);
}
void ShootFunction(GameObject Bullet)
{
GameObject temp = Instantiate(Bullet, this.transform.position + direction.normalized, Quaternion.identity);
temp.GetComponent<Rigidbody>().AddForce(direction.normalized * bulletForce);
}
Your code won't work. You need to remove the GameObject Bullet paramter from ShootFunction() because the paramter hides this.Bullet. And also Unity3D will print warning message Trying to Invoke method: Shoot.ShootFunction couldn't be called.: you cannot use InvokeRepeating with method parameters.
Now it works:
I used a bullet prefab assigned to public GameObject Bullet. And public GameObject Enemy was also assigned a Cube GameObject from the inspector.
Full project.
But you still need to think about how to recycle and finally destroy the bullets: In your code, you just Instantiate the bullets, but when will they be destroyed?
It's not easy to know what exactly you are trying to do.
But this will at least fix most issues.
You must always normalize your vectors before they can be used as a
direction. A direction is a vector with a magnitude of 1. If you
simply subtract one location from another you don't get a
normalized vector.
I am not sure if your ShootFunction is
allowed to have a parameter. I don't think so. Access you member
(Bullet) directly.
I also removed an offset in your instantiation location. You might need to add it back in. But I believe it is not necessary.
Sample
public GameObject Enemy;
public GameObject Bullet;
public float bulletForce = 100f;
private Vector3 direction;
// Use this for initialization
void Start ()
{
ShootFunctionRepeat();
}
// Update is called once per frame
void Update ()
{
direction = (Enemy.transform.position - this.transform.position).normalized;
}
void ShootFunctionRepeat()
{
InvokeRepeating("ShootFunction", 0.0f, 1.0f);
}
void ShootFunction()
{
GameObject temp = Instantiate(Bullet, this.transform.position, Quaternion.identity);
temp.GetComponent<Rigidbody>().AddForce(direction.normalized * bulletForce);
}