I am new to installed Unity 5. I have some problem in the following code:
void OnTriggerEnter(Collider other) {
var air = other.collider.gameObject.GetComponent<DamageManager>();
if(air){
air.HP += HPFill;
}
}
Replace var air = other.collider.gameObject.GetComponent<DamageManager>() with var air = other.GetComponent<Collider>().gameObject.GetComponent<DamageManager>();
void OnTriggerEnter(Collider other)
{
var air = other.GetComponent<Collider>().gameObject.GetComponent<DamageManager>();
if (air)
{
air.HP += HPFill;
}
}
var air = other.GetComponent<DamageManager>();
The collider in your code is actually redundant since other is already the collider component. It is like asking the reference to reach itself. And no need either to use the gameObject reference since Collider is a Component and then contains a GetComponent method.
The new versions of Unity are removing all component reference but transform and gameObject as they are always there.
Related
So I am trying to make my first game using Unity and c#. I want my game to be a simple game of tag like I used to play when I was younger. I have tried using "OnCollisionEnter" and I was able to get that to change a counter that gave a bool a label. I realized that while this may work for tagging someone it does not help with other people tagging you. And tips on how I can make my code more like a "Tag Manager"?My current progress
you can have a Taggable.cs like this, not sure if this is even correct syntax, I don't care to actually write it out and test
class Taggable : MonoBehaviour {
bool it;
private void OnCollisionEnter(Collision collision) {
var other = collision.collider.GetComponent<Taggable>();
if(other != null) {
if(it) {
other.it = true;
it = false;
}else if(other.it) {
it = true;
other.it = false;
}
}
}
}
You could implement the logic such that your script checks to see if you are the tagger using Unity's tags property. Then, you could switch the tags of both the players, once you check if the collided object is a player.
Below is the code I suggest you use. I would personally use OnTriggerEnter to have more clearer logic between collider and player. Make sure to have a collider object and a Rigidbody on all players within the scene for the function to be called, and attach your script onto every player within the scene.
private void OnTriggerEnter (Collider col) {
// if you are the tagger
if (gameObject.tag == "Tagger") {
// and if the collided object is a regular player
if (col.tag == "Player") {
// the player is now a tagger
col.tag = "Tagger";
// depending on if you want to buildup taggers or switch them around,
// the below assignment would vary
gameObject.tag = "Player";
}
}
}
Alright, so I've been building a small thing in Unity 2D, and it works for the most part, however whenever I attempt to create a script to spawn a copy of the circle prefab, it just doesn't spawn without any error messages.
I've attempted to use Instantiate to spawn them at the button's location, yet no luck.
{
public GameObject circle;
public Transform circlespawn;
private bool touched = false;
void Update()
{
if(touched == true)
{
Instantiate(circle, circlespawn.position, circlespawn.rotation);
touched = false;
}
}
void OnMouseDown()
{
touched = true;
}
}
From BugFinder in the comments, he pointed out I simply needed a collider for the onmousedown to work correctly.
I'm making a game in Unity VR in which I punch numbers and get points.
The gloves are responsible for detecting collisions between the numbers that they hit. On my gloves I have a PunchScript component and the numbers each have a rigidBody and collider.
The problem is that no collisions seem to ever occur. I placed a Debug.LogError inside of the collision detection code to assert this.
I tried switching on/off kinematics on all objects and used different collision systems to no avail.
Here's my PunchScript component:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PunchScript : MonoBehaviour
{
public SteamVR_TrackedObject hand;
private Rigidbody rBody;
private bool visible = true;
// Start is called before the first frame update
void Start()
{
rBody = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
rBody.MovePosition(hand.transform.position);
rBody.MoveRotation(hand.transform.rotation);
// print(rBody.velocity.magnitude* 1000);
}
void OnCollisonEnter(Collision other)
{
Rigidbody otherR = other.gameObject.GetComponentInChildren<Rigidbody>();
if (other.gameObject.name == "frpnchbg") {
Debug.LogError("Hit!");
}
if (other == null)
return;
Vector3 avgPoint = Vector3.zero;
foreach (ContactPoint p in other.contacts) {
avgPoint += p.point;
}
avgPoint /= other.contacts.Length;
Vector3 dir = (avgPoint - transform.position).normalized;
otherR.AddForceAtPosition(dir *50f* rBody.velocity.magnitude, avgPoint);
}
}
Here's how the glove object looks in the Unity inspector.
It is very important to write the name of Unity callback methods correctly, otherwise Unity will not be able to detect them on the object (and as a result, can never execute them).
In your case, you have misspelled the OnCollisionEnter callback.
Instead of OnCollisonEnter it should be OnCollisionEnter.
Right now I have an obj file in Unity. I have a script that adds a Collider component, a Rigidbody component, and finally an OVRGrabbable component to the object. I need to add these components at runtime because eventually I will be producing procedural meshes in a script at runtime, and I need these procedural meshes to be grabbable.
My problem is that the OVRGrabbable script does not recognize the added collider as a grab point when the collider is added at runtime. I thought that it would be enough to add the collider before the OVRGrabbable in my script, but no dice. I tried attaching the collider in an Awake function and then the OVRGrabbable in the Start function, but that didn't work either. Additionally, I cannot add it in script because the grabPoints array is read-only. Here is my code:
public class AddVRComponents : MonoBehaviour {
void Start () {
public bool freeMoving = false;
public bool useGravity = false;
collide = gameObject.AddComponent<BoxCollider>();
Rigidbody rB = gameObject.AddComponent<Rigidbody>();
if (!freeMoving)
{
rB.drag = Mathf.Infinity;
rB.angularDrag = Mathf.Infinity;
}
if (!useGravity)
{
rB.useGravity = false;
}
OVRGrabbable grab = gameObject.AddComponent<OVRGrabbable>();
Collider[] newGrabPoints = new Collider[1];
newGrabPoints[0] = collide;
grab.enabled = true;
grab.grabPoints = newGrabPoints;
}
}
This obviously does not work because the final line produces the error that grab.grabPoints is read-only.
I know that it can be done because if I run my program and then in the editor manually drag my collider into the grab points field of the OVRGrabbable component, the object can be grabbed.
How can I get the OVRGrabbable script to recognize my collider?
Read-only properties are properties that can be assigned only through the script that contains them. This means that you can only change the value of grabPoints from inside the OVRGrabbable.cs script.
The best way to do this is by adding a custom function inside the OVRGrabbable.cs file so that you can access and set the read only variables.
I use this one so I can also set the snapPosition and snapOrientation fields as well as the grabPoints.
public void Initialize(bool snapPosition, bool snapOrientation, Collider[] grabPoints)
{
m_snapPosition = snapPosition;
m_snapOrientation = snapOrientation;
m_grabPoints = grabPoints;
}
You'll be good enough only adding and calling the following one:
public void Initialize(Collider[] grabPoints)
{
m_grabPoints = grabPoints;
}
I made this modification to OVRGrabbale.cs:
void Awake()
{
if (ReferenceEquals(m_grabPoints, null) || m_grabPoints.Length == 0)
{
// Get the collider from the grabbable
Collider collider = this.GetComponent<Collider>();
if (collider == null)
{
throw new ArgumentException("Grabbables cannot have zero grab points and no collider -- please add a grab point or collider.");
}
// Create a default grab point
m_grabPoints = new Collider[1] { collider };
}
}
I checked to see if m_grabPoints is null and it worked.
I'm facing audio problems in my project. There are three paddle game objects and one cube. Cube has Rigidbody2d or BoxCollider2d. And there is also a button script attach to cube which has button function when we click on button cube Kinematic becomes false and drop on the paddle. When it's collide with any paddle cube destroy and instantiate again with new prefab. When Cube is falling sound is play and cube is destroy. New cube is instantiate when again click on button then error came.
MissingReferenceException: The object of type AudioSource has been destroyed but you are still trying to access it. Your script should either check if it is null or you should not destroy the object.
Scripts on all paddles:
public class Paddle : MonoBehaviour
{
[SerializeField]
private AudioSource source;
[SerializeField]
private AudioClip hit;
[SerializeField]
private BoxCollider2D collide;
[SerializeField]
private GameObject Clone;
void Awake()
{
collide.isTrigger = true;
}
void OnTriggerEnter2D(Collider2D target)
{
source.PlayOneShot(hit);
Destroy(target.gameObject);
Instantiate(Clone, new Vector3(0f, 4.51f, 0f), Quaternion.identity);
}
}
Cube Script:
public class Cube : MonoBehaviour
{
[SerializeField]
private AudioSource source;
[SerializeField]
private Rigidbody2D body;
[SerializeField]
private AudioClip play;
private Button bt;
private float pos;
public bool check;
void Start()
{
bt = GameObject.FindGameObjectWithTag("Button").GetComponent<Button>();
bt.onClick.AddListener(Fire);
body.isKinematic = true;
}
void Update()
{
if (check)
{
return;
}
Vector3 temp = transform.position;
pos = Camera.main.ScreenToWorldPoint(Input.mousePosition).x;
temp.x = Mathf.Clamp(pos, -6.25f, 6.25f);
body.position = temp;
}
public void Fire()
{
GameObject.FindGameObjectWithTag("Player").GetComponent<Cube>().check = true;
GameObject.FindGameObjectWithTag("Player").GetComponent<Rigidbody2D>().isKinematic = false;
source.PlayOneShot(play);
}
}
Cube image:
Paddles image:
New Export package:
https://drive.google.com/file/d/0B1H5fdK2PJAnSXVPdmE5Z3J1SUU
Problem in Video:
https://drive.google.com/file/d/0B1H5fdK2PJAnYzRfVnlQT1FyTlE
Your linked package works fine, it does play the sound every time I launch and destroy a cube.
Nonetheless, you should remove the method on destroy. Unity does not throw any error nor warning when a non-persistent listener is null, kinda weird but this is how it is. You should remove it manually:
void OnDestroy(){
bt.onClick.RemoveListener (Fire);
}
But your package does not throw any error when I run it.
Though, I would rethink your approach, instead of the cube assigning its Fire method to the Button event, I would have a script on the button containing the Fire method as well as the AudoiSource and clip. Then on Start, the Cube would pass itself so that the button could access its Cube and Rigidbody2D component.
Best would be to pass a class that contains those are members:
public class CubeArgument{
public readonly Rigidbody2D rg = null;
public readonly Cube cube = null;
public CubeArgument(Rigidbody2D rg, Cube cube){
this.rg = rg;
this.cube = cube;
}
}
then here goes your Cube start method:
void Start () {
bt = GameObject.FindGameObjectWithTag ("Button");
bt.GetComponent<ButtonController> ().Init(new CubeArgument(body, this));
body.isKinematic = true;
}
The ButtonController reference could even be made static since there is only one for the whole level.
and then on the button you have a ButtonController:
public class ButtonController : MonoBehaviour{
Cube currentCube = null;
Rigodbody2D currentRig = null;
public void Init(CubeArgument ca){
currentRig = ca.rg;
currentCube = ca.cube;
}
public void Fire(){
if(currentCube != null){ currentCube.check = true; }
if(currentRig != null) { currentRig.isKinematic = false; }
}
}
Fire is passed as listener to the Button onClick and this is it.
your problem can be from many different places. my guesses:
1)problem with your build: rebuild your code or export all of your package to new project and retest.
2)your target framework: latest version of unity(i have 5.1) just support to .net 3,5 and unity 4.x supports 2,5 i think. so chek your target framework to not to use functions that is not functional in your version
3)settings of your platform that your editor is running on: it can be volume of your platform to many other settings, first option to know that is run your project on other machine (maybe its a unity bug that part of code is not good for your hardware or driver on platform)
Edit: OP was using version 5.1.1. This error does not repeat after Unity 5.2.
Tried your package and it is working fine!
No errors. Audio played when instantiated.
Are you still facing errors? Weird, dude. Sounds like something is not clean enough.
Maybe there is some issue with your build.
Few things you could try:
1- Try restarting your Unity. Maybe this will force Clean things.
2- Create a new project and import your own package to test it!
3- I'm using Unity 5.3.0f4 what Unity version are you using? Try an update.
If none of above works, there is something wicked going on with your AudioSource reference and I can't help you with my actual knowledge. But still we can try to do different approaches for that.
Instead of physically referenced it (Dragging and dropping), do it at the start of your script.
Desperate approach 1
On Cube.cs:
First remove [SerializeField] located above of private AudioSource source; and add the following line on the Start() method:
source = gameObject.GetComponent<AudioSource> ();
Practically the same, but now the script is referencing the own object Audio Source for you. Do the same approach with Paddle.cs. [remember to check the audio name when applying the approach for Paddle script. On paddle the audio name is PlayOneShot (hit) not PlayOneShot (play)].
If this still trigger some error. Let's try another approach.
Desperate approach 2
On Cube.cs:
Remove/Comment the following line on Fire() method:
source.PlayOneShot (play);
Add the following line to Fire() method:
gameObject.GetComponent<AudioSource> ().PlayOneShot (play);
This will get your actual AudioSource on the go. Do the same approach on Paddle.cs [remember to check the audio name when applying the approach for Paddle script. On paddle the audio name is PlayOneShot (hit) not PlayOneShot (play)].