So I'm making a little top down space shooter and everything works great so far. My issue is that when I change weapons I would like the secondary to do more damage than the primary (changeable with the number keys). It's been a real head scratcher and any help would be greatly appreciated. this is what I tried;
adding the weapons to individual layers. in the OnTriggerEnter2D function I make an if statement stating if the gameObject (bullet) is firing from layer 13, take away x amount of HP. Doesn't do anything though. below is my current code for the enemy.
using UnityEngine;
using System.Collections;
public class enemyDamage : MonoBehaviour {
public int health = 2;
void OnTriggerEnter2D(){
health--;
}
void Start () {
}
void Update () {
if (health <= 0){
Die();
}
}
void Die(){
Destroy (gameObject);
}
}
You can change your OnTriggerEnter2D function by adding Collider2D parameter to it. That way you can get access to the gameObject that triggered the function.
You didn't post the code that is instantiating the bullet. But if you set bullets name to different values you can decrease the health based on that.
void OnTriggerEnter2D(Collider2D other) {
if(other.gameObject.name == "missile"){
health -= 10;
}else if(other.gameObject.name == "bullet"){
health -= 1;
}
}
Or even better idea might be adding a script to the bullet, which knows the amount of damage the bullet is going to make.
void OnTriggerEnter2D(Collider2D other) {
health -= other.gameObject.GetComponent<BulletScript>().damage;
}
Related
Hello everyone. I have a character like the picture below, I want when playing the game, this character collides with another character, this character will be hidden (Exactly hide the entire skin shirt, okay? , but the character still moves normally) after about 10 seconds, it will show the skin again as shown below.
I'm stuck in the code. I tried to enable skinnedmeshrenderer , but it forces the sence to reload and it doesn't work very well. If you have any ideas, please let me know. Thank you!!!!
So for this you need to look up how to use colliders. You might want a simple box collider, or even a mesh collider. Then you need to tag the colliders (Go to Learn.Unity or the YouTube website to look for some guides if you don't know about these).
Then use private void OnCollisionEnter(Collision col){} and check col.tag to see if it's what you want and set the character GameObject to innactive* character.SetActive(false);
Then, set a float timer to 10 timer=10; and in Update run
if (timer > 0)
{
timer -= Time.deltaTime;
if (timer <= 0)
{
character.SetActive(true);
}
}
which will reactivate your character after 10 seconds.
* Note
If you don't want to turn the gameObject off, you can instead save the mesh in a variable then set it to null for 10 seconds before restoring it
Alternate solution:
Script used:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour
{
[SerializeField] SkinnedMeshRenderer skinnedMeshRenderer;
Mesh mesh;
float timer = 0;
// Start is called before the first frame update
void Start()
{
mesh = skinnedMeshRenderer.sharedMesh;
}
// Update is called once per frame
void Update()
{
if (timer > 0)
{
timer -= Time.deltaTime;
if (timer <= 0)
{
skinnedMeshRenderer.sharedMesh = mesh;
}
}
if (Input.GetMouseButtonDown(0))
{
skinnedMeshRenderer.sharedMesh = null;
timer = 10;
}
}
}
Model "Steve" thanks to Penny DeBylle
Here is the code in which I was talking about. I can't figure out why my collider isn't working:
using System.Collections.Generic;
using UnityEngine;
public class SphereCollider : MonoBehaviour
{
GameObject obj;
void Awake ()
{
obj = GameObject.FindGameObjectWithTag("Player");
}
// Update is called once per frame
void Update()
{
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.name == "Player")
{
obj.GetComponent<Health>().health -= 25;
}
}
}
}
Rather than using the code you have, make sure to change some code. This is what you should change: get rid of the obj variable and the awake function. Then instead of finding the object with that name, use tag. Also get rid of Update(){} and take the OnCollisionEnter(){} out of it.
A few more changes are shown in code:
void OnCollisionEnter(Collision collision){
var obj = collision.GameObject;
if (obj.Tag == “Player”){
obj.GetComponent<Health>().health -= 25;
}
}
This will work as long as: the script is called Health, the variable inside Health is called health, and it is set to a float, and the player’s tag is set to Player.
Not sure if the code pasted in the question is just copied over wrong, but OnCollisionEnter() is its own unique method and should not be nested in Update().
If the player will be colliding with this Sphere object often, it is good to cache a component rather than using GetComponent frequently. However I assume in your case this Sphere will be one of many obstacles, so calling the GetComponent in the collision is fine. The issue with your current code is the gameObject you are colliding with might not have the name exactly spelled as Player, which would make your collision check fail. Caching the object that has the tag of Player is a bit redundant when you can just check it inside of the collision check.
I will use your entire snippet of code so there is no confusion
using System.Collections.Generic;
using UnityEngine;
public class SphereCollider : MonoBehaviour
{
void OnCollisionEnter(Collision col)
{
// compare if the collider's gameObjects tag is equal to our target tag (Player)
if (col.gameObject.tag == "Player")
{
// get the component of Health on our gameObject that we collided with that has the tag of Player
obj.GetComponent<Health>().health -= 25;
}
}
}
I'm trying to add a healthbar which is affected by the choices made and link the two but am unable to do so. Any help would be appreciated.
I will recommend you that before you go any further with your game development process, you research a bit more about general OOP programming (no offense or anything, it will just make things waaay easier, trust me).
That being said, here's an example to steer you to the right direction:
You can create a script with a global variable called health and subtract it every time the player makes a decision that would "punish" them, here's an example of how that could work:
PlayerManager.cs (put this script on your player)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerManager : MonoBehaviour {
public float health = 100f;
private void Update() {
if (health < 0)
Die();
}
private void Die () {
//Fancy animations and text can be added on this method
Destroy(gameObject);
}
}
And on your dialogue script, once they choose a wrong answer, then you can just decrease health on the proper player manager instance, like this:
DialogueSystem.cs
public PlayerManager playerManager;
public float damage = 10f;
private void Start() {
//You can initialize other stuff here as well
//This line is assuming you have the dialogue system script attach to your player as well
playerManager = GetComponent<PlayerManager>();
}
private void Update () {
//This is obviously going to change depending on how your system is built
if (wrongChoice) {
playerManager.health -= damage;
wrongChoice = false;
}
}
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
I want to change the number of lives every time the player hits the water. I wrote this code so far:
public var dieSound:AudioClip;
static var lives = 3;
function Start () {
}
function Update () {
if(lives == 0)
{
Application.LoadLevel("menu");
}
}
public function OnGUI()
{
GUI.backgroundColor = Color.blue;
GUI.Button (Rect (10, 10, 100, 30), "Lives: " + lives);
}
function OnControllerColliderHit (hit : ControllerColliderHit)
{
if (hit.collider.tag == "Water")
{
// play dying sound
audio.PlayOneShot(dieSound);
// show mission fail UI
GameObject.Find("MissionTXT").guiText.enabled = true;
// wait until it's ended
yield WaitForSeconds(dieSound.length + 0.01);
transform.position = GameObject.FindWithTag("Respawn").transform.position;
if (transform.position == GameObject.FindWithTag("Respawn").transform.position)
{
GameObject.Find("MissionTXT").guiText.enabled = false;
lives = lives - 1;
}
}
}
The problem is that when the player hits the water, lives change from 3 to -120. I think that happens because the player is on the water for like 6-7 seconds. So character may hits the water 120 times until he goes back to the original position (Respawn position).
Can anyone help me with that please?
The first thing that comes to mind is as follows:
On your water GameObject, add a Collider component. I would think that a BoxCollider would fit in this scenario. Don't forget to mark the Is Trigger checkbox.
On your player GameObject, add both a RigidBody and a CharacterController (since it looks like you are using the CharacterController component). Make sure to check the RigidBody's Is Kinematic checkbox. Also, give your GameObject a meaningful tag like "Player".
Back to the water GameObject, add a new script that should look something like this:
public class Water : MonoBehaviour {
void OnTriggerEnter(Collider collider) {
if(collider.CompareTag("Player")) {
collider.SendMessage("Kill");
}
}
}
Back to the player GameObject, add a new script that should look something like this:
public class Player : MonoBehaviour {
public void Kill() {
//Perform all necessary steps to kill the player such as...
//Reduce the amount of lives by 1
//Play the death sound
//etc. etc. etc.
}
}
That's the "jist" of things, or this should at least get you started. Unity has some really good documentation and practically anything you need is there, you just have to know where to look. I'm not going to go in-depth of each thing I have mentioned above because as I've said, "Unity has some really good documentation." With that in mind, I highly recommend looking into each of the things I have mentioned. Hope this helps! =)