I am trying to create a simple scriptable object for my shoot ability. I have that aspect working, but as I try to set my Transform to my player, it does not update the shoot position. I am very new to C#, and this script isnt complete. I still need to add the functionality to destroy the created objects. Any help would be greatly appreciated. I suspect I need to add an update function but im am not certain how to do this.
using UnityEngine.InputSystem;
using UnityEngine.AI;
using UnityEngine;
namespace EO.ARPGInput
{
[CreateAssetMenu]
public class Shoot : Ability
{
public Transform projectileSpawnPoint;
public GameObject projectilePrefab;
public float bulletSpeed = 10;
public float bulletLife = 3;
public override void Activate(GameObject parent)
{
var projectile = Instantiate(projectilePrefab, projectileSpawnPoint.position, projectileSpawnPoint.rotation);
projectile.GetComponent<Rigidbody>().velocity = projectileSpawnPoint.forward * bulletSpeed;
Destroy(projectile, bulletLife);
void OnCollisionEnter(Collision collision)
{
Destroy(projectile);
}
}
}
}
I'm still new to Unity and coding also, so take my advice with a load of salt :P.
It may be best to have a transform on your character (say just past the barrel of the player's gun) that you can put as the projectileSpawnPoint. In your code the projectileSpawnPoint is never set. Your first line of code in the "Activate" method should be something like:
public override void Activate(GameObject parent)
{
projectileSpawnPoint = playerGunBarrelTransform.transform.position;
var projectile = Instantiate(projectilePrefab, projectileSpawnPoint.position, projectileSpawnPoint.rotation);
projectile.GetComponent<Rigidbody>().velocity = projectileSpawnPoint.forward * bulletSpeed;
Destroy(projectile, bulletLife);
For destroying the projectile afterward you can keep it as you have it in OnCollision. howeer, with bullets in particular, since they tend to be instantiated A LOT and then destroyed afterward it would be best to use an object pooler for them to instantiate several of them on start and then disable and enable them as needed so you can resuse them instead of making new ones every time.
you have to create a new script that derives from Monobehaviour for your projectiles. attach that script to the projectile prefab and place the OnCollisionEnter method in that script. now your projectiles should get destroyed when touching another collider. make sure that there is a rigidbody component attached to the projectile.
When I try to get a variable from another script I get the error 'Component.GetComponent<T>()' is a method, which is not valid in the given context [Assembly-CSharp]csharp(CS0119)
The code that's throwing the error is here
GetComponent<EnemyAI>.Attack();
Any help or suggestions is greatly appreciated,
In fact, you can't get the component class just by writing the type in any code, and to do this you need to have an instance of the enemyAI gameObject as a reference. In this solution The easiest way to do this is to use GameObject.FindObjectOfType<>() like the code below:
public EnemyAI enemyAI; // define a variable for enemyAI
public void Start()
{
enemyAI = FindObjectOfType<EnemyAI>(); // it will find your enemyAI script gameObject
}
Once the game is begining, EnemyAI is stored in that variable, and you have access to the class properties. And you can easily run the methods.
private void OnNearEnemy()
{
enemyAI.Attack(); // call attack function
enemyAI.power += 10f; // add some power for example...
}
Now if you have another component like Rigidbody or Animator in EnemyAI, you can easily call and access it with GetComponent<>().
public void ForceEnemyToEscape()
{
var enemyAgent = enemyAI.GetComponent<NavMeshAgent>(); // get nav mesh
enemyAgent.destination = transform.position + transform.forward * 10f;
}
However, I suggest you learn object-oriented programming topics well. Because many calls can be made inside the enemy class. I hope it helped.
I'm working on a death script for my game in Unity. I made a 3d Box without textures underneath my level and made its Collider isTrigger = true. I now added a script to the box that reloads the current scene when the player enters the trigger. Its 2 lines of code and I don't know why but I get the error:
Assets\scripts\death.cs(20,32): error CS0103: The name 'currentScene' does not exist in the current context
The Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class death : MonoBehaviour
{
void Start()
{
Scene currentScene = SceneManager.GetActiveScene();
}
private void OnTriggerEnter(Collider other)
{
SceneManager.LoadScene(currentScene.buildIndex);
}
}
I know that the comments above already noticed your problem was the local variable and thanks to them, but this is just about to optimize your code and memory. you can just keep OnTriggerEnter only and delete Start.
private void OnTriggerEnter(Collider other)
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
there's no need to store the scene in a variable if we will not use in a further needs. it will be just a waste of memory (bad habit)
This is semi complicated of a question but I'll do my best to explain it:
I am making this mobile game in which you have to shoot four cubes. I'm trying to make it so when the cubes are shot by a bullet, they're destroyed and a UI text says 1/4, to 4/4 whenever a cube is shot. But it's being really weird and only counts to 1/4 even when all four cubes are shot and destroyed. I put these two scripts on the bullets (I made two separate scripts to see if that would do anything, it didn't)
And to give a better idea of what I'm talking about, here's a screenshot of the game itself.
I've been using Unity for about 6 days, so I apologize for anything I say that's noob-ish.
EDIT
So I combined the two scripts onto an empty gameobject and here's the new script:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class GameManagerScript : MonoBehaviour {
public GameObject cubes;
public Text countText;
public int cubeCount;
public Transform target;
// Use this for initialization
void Start () {
}
void OnTriggerEnter(Collider other)
{
cubes = other.gameObject;
}
// Update is called once per frame
void Update () {
cubes.transform.position = Vector3.MoveTowards(transform.position, target.position, 1f * Time.deltaTime);
if (cubes.gameObject.tag == "BULLET")
{
cubeCount = cubeCount + 1;
countText.text = cubeCount + "/4";
cubes.SetActive(false);
}
}
}
ANOTHER EDIT
I tried everything, so is there a way to detect when all the children in a parent on the Hierarchy are destroyed? Instead of counting up? This can give a better idea:
So I want to be able to detect when Cube, Cube1, Cube2, and Cube3 have all been destroyed.
The answer is pretty simple: Since every individual bullet has that script, each bullet has its own score.
For something like a score you want a single spot to store it, e.g. a script on an empty gameobject that serves as game controller. Just access that in the collision and increase the score (maybe have a look on singletons here).
You can combine those two scripts and actually it might be better to not have this on the bullet, but on the target because there are probably less of them which will save you some performance. (And it does more sense from a logical point of view.)
Edit:
I assume you create the bullets using Instantiate with a prefab. A prefab (= blueprint) is not actually in the game (only objects that are in the scene/hierarchy are in the game). Every use of Instantiate will create a new instance of that prefab with it's own version of components. A singleton is a thing that can only exist once, but also and that is why I mention it here, you can access it without something like Find. It is some sort of static. And an empty gameobject is just an object without visuals. You can easily create one in unity (rightclick > create empty). They are typically used as container and scriptholders.
Edit:
What you want is:
An empty gameobject with a script which holds the score.
A script that detects the collision using OnTriggerEnter and this script will either be on the bullets or on the targets.
Now, this is just a very quick example and can be optimized, but I hope this will give you an idea.
The script for the score, to be placed on an empty gameobject:
public class ScoreManager : MonoBehaviour
{
public Text scoreText; // the text object that displays the score, populate e.g. via inspector
private int score;
public void IncrementScore()
{
score++;
scoreText.text = score.ToString();
}
}
The collision script as bullet version:
public class Bullet : MonoBehaviour
{
private ScoreManager scoreManager;
private void Start()
{
scoreManager = GameObject.FindWithTag("GameManager").GetComponent<ScoreManager>(); // give the score manager empty gameobject that tag
}
private void OnTriggerEnter(Collider other)
{
if(other.CompareTag("Target") == true)
{
// update score
scoreManager.IncrementScore();
// handle target, in this example it's just destroyed
Destroy(other.gameObject);
}
}
}
I'm trying to use C# to disable and enable the MeshRender component in Unity3d however I am getting the following error,
error CS0120: An object reference is required to access non-static member `UnityEngine.GameObject.GetComponent(System.Type)'
The line of code I am using is below. I'm using this in the same function.
MeshRenderer showZone = GameObject.GetComponent<MeshRenderer>();
Also I'm posting here rather than Unity Answers as I get a far faster response here and it's always useful information regardless of the outcome.
You're having trouble with several problems. First, you are trying to use GetComponent<> on a class instead of an instance of an object. This leads directly to your second problem. After searching for a specific GameObject you're not using the result and you're trying to disable the renderer of the GameObject containing the script. Third, C# is case-sensitive, Renderer is a class while renderer is a reference to an instance of Renderer attached to the GameObject
This code snippet combines everything: find the GameObject and disable its renderer
GameObject go = GameObject.FindWithTag("zone1");
if (go != null) { // the result could be null if no matching GameObject is found
go.renderer.enabled = false;
}
You could use go.GetComponent<MeshRenderer>().enabled = false; instead of go.renderer. enabled = false; But by using renderer you don't need to know what kind of renderer is used by the GameObject. It could be a MeshRenderer or a SpriteRenderer for example, renderer always points to the renderer used by the GameObject, if there exists one.
My friend. Just try use lowercase gameObject instead of GameObject and renderer instead of Renderer
The main problem that you try access Static class variable, using the name of class instead of class instance.
Class names here are GameObject and Renderer
And instances are gameObject and renderer
MeshRenderer showZone = GetComponent<MeshRenderer>();
delete the 'GameObject.'
GameObject is a type. What you want is in an instance of a gameObject to call GetcComponent on. Thats what the error is about.
Which for note, this:
MeshRenderer showZone = GetComponent<MeshRenderer>();
is the exact same as this:
MeshRenderer showZone = this.GetComponent<MeshRenderer>();
You are calling GetComponent on the GameObject instance of which the script is attached to.
your code should look like this:
MeshRenderer showZone = GetComponent<MeshRenderer>();
Like others already wrote, you need to get an instantiated GameObject. You call the base class GameObject where only static functions can be called which do not need a GameObject in the SceneView.
gameObject IS AN instance.You get the instance of the GameObject the Monobehaviour is added to. Calling the function GetComponent without any object is the same as:
this
gameObject
GameObject IS NO instance.
Be careful at the first letter!
Look documentation:
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour {
void Example() {
renderer.enabled = false;
}
}
Link: http://docs.unity3d.com/ScriptReference/Renderer-enabled.html
Changing of programming languages upper-right.
2 ways you can solve the Problem either. You add the word static to the method that is calling your statement.
ex :
public static GetTheMesh(){}
I do not recommend on doing this cause. If you have other calls inside the method that needs to access Instance, this will cause you trouble.
Second way of fixing it is make a pointer or reference first before getting the component. Or use the GameObject.Find <= which is slow if.
showZone = GameObject.Find("TheGameObjectName").GetComponent<MeshRenderer>();
If you want to disable the renderer on this gameObject then use:
this.GetComponent<Renderer>().enabled = false;
If it's not this gameObject then use:
GameObject.FindGameObjectWithTag("your_tag").GetComponent<Renderer>().enabled = false;
Or you could give the object manually:
public GameObject go;
go.GetComponent<Renderer>().enabled = false;
https://docs.unity3d.com/ScriptReference/Renderer-enabled.html
you can use two types of peace of code for access MeshRenderer enable and disable
1> create GetMeshRenderer script (script name as you want) attached to empty game-object into the scene and assign Cube or sphere or any 3d object as u want to enable and disable.
************************************** Code ***************************
using UnityEngine;
using System.Collections;
public class GetMeshRenderer : MonoBehaviour
{
public MeshRenderer ShowZone;
void Start ()
{
}
// Update is called once per frame
void Update ()
{
if(Input.GetKey(KeyCode.Y))
{
ShowZone.enabled = true;
}
if(Input.GetKey(KeyCode.N))
{
ShowZone.enabled = false;
}
}
}
2>
attach below peace of code script to any 3d object like sphere ,cube
*************************** code ***************************
using UnityEngine;
using System.Collections;
public class GetMeshRenderer : MonoBehaviour
{
private MeshRenderer ShowZone;
// Use this for initialization
void Start ()
{
ShowZone = gameObject.GetComponent<MeshRenderer> ();
}
// Update is called once per frame
void Update ()
{
if(Input.GetKey(KeyCode.Y))
{
ShowZone.enabled = true;
}
if(Input.GetKey(KeyCode.N))
{
ShowZone.enabled = false;
}
}
}
Your problem is that you are using GameObject which is just a class that "describes" what it is. What you want, if this script is attached to the GameObject who's mesh renderer you want, is gameObject with a lowercase "g."
If you want to get the mesh renderer of another GameObject, you can find it by name with GameObject.Find("zone1"); (note the uppercase "G" in that one,) or you can give it a tag and find it with GameObject.FindGameObjectWithTag("zone1");
(You may or may not already know that but it doesn't hurt to provide the information.)
Edit:
Your other problem is that you must use renderer instead of Renderer because, like the GameObject "Renderer" with a capital "R" references a class, instead of a specific object.
the problem is GameObject is different from gameobject Gameobject is a class and gameobject is a instance of current gameobject or gameobject in which the script is attached
Replace the line
MeshRenderer showZone = GameObject.GetComponent<MeshRenderer>();
with
MeshRenderer showZone = gameobject.GetComponent<MeshRenderer>();
I think this will do,
Also note that in your Error statement ,it is saying that GameObject is a Class or a data type not an object
Do you see the gears? Yes? Click it and click remove component.
You can use the declaration:
other.gameobject.GetComponent< MeshRenderer>().Setactive (false);
One Line Reference...after the condition is fulfilled..
For more precise help regarding MeshRender, see the Unity Documentations..
I had same issue with my declaration and i just fixed it by changing "G" to "g" in gameObject and i declared it in Start so it is like...
MeshRenderer showZone = gameObject.GetComponent();