I wrote the following 2 scripts in Unity 3D , PhysicsObject and PlayerPlatformerController (following this tutorial). The PlayerPlatformerController script is attached to a game object.
PhysicsObject.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PhysicsObject : MonoBehaviour {
void Update () {
ComputeVelocity ();
}
protected virtual void ComputeVelocity() {
}
}
PlayerPlatformerController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerPlatformerController : PhysicsObject {
void Update () {
}
protected override void ComputeVelocity() {
}
}
The codes look simple, but the ComputeVelocity() in PlayerPlatformerController does not get called (proved by adding Debug.Log()). Why?
If I change to the following codes, the function works perfectly:
PhysicsObject.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PhysicsObject : MonoBehaviour {
void Update () {
//ComputeVelocity ();
}
/*protected virtual void ComputeVelocity() {
}*/
}
PlayerPlatformerController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerPlatformerController : PhysicsObject {
void Update() {
ComputeVelocity();
}
void ComputeVelocity() {
}
}
What did I miss?
It happened to me that I had two scripts:
Health.cs
HealthModified.cs -> This was overriding function of Health.cs
In my GameObject I was testing HealthModified (enabled) and I also had the Health.cs in the gameobject but disabled.
The code was using the Halth.cs compoenent also when it was disabled, I had to remove the component from the gameobject to get the HealthModified behaviour.
It may happen because you use Update method in child-class (PlayerPlatformerController). If it true, you will mark update as protected and virtual, and override it in child class. It may look like this:
public class PhysicsObject : MonoBehaviour
{
protected virtual void Update()
{
ComputeVelocity();
Debug.LogFormat("PhysicsObject Update");
}
protected virtual void ComputeVelocity()
{
Debug.LogFormat("PhysicsObject ComputeVelocity");
}
}
public class PlayerPlatformerController : PhysicsObject
{
protected override void Update()
{
base.Update();
Debug.LogFormat("PlayerPlatformerController Update");
}
protected override void ComputeVelocity()
{
base.ComputeVelocity();
Debug.LogFormat("PlayerPlatformerController ComputeVelocity");
}
}
I finally found out the problem. In the PlayerPlatformerController class, if I remove the Update() method, the override ComputeVelocity() will start working.
Thanks all for your efforts helping me.
When you have a class that inherits from another you need to be wary of accidentally overriding the parent's methods.
In this case, creating empty Start() and Update() methods will replace those from the parent. This is an easy mistake to make since new classes are normally created with those methods by default.
Removing the methods from the child class will ensure the parent is called instead. Or if you want to keep the child methods while also calling the parent's, you can use base.Start() (or whichever method you are overriding).
Related
i want to call coroutine in a non-monobehavior script but this approach is not working.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Attacking : BaseState
{
private MovementSM _sm;
public float movementSpeed;
public MonoBehaviour mono; //here i calling monobehaviour
public bool attackBool;
public Attacking(MovementSM stateMachine) : base("Attacking", stateMachine)
{
_sm = stateMachine;
}
public override void Enter()
{
base.Enter();
_sm.animator.SetTrigger("attack");
}
public override void UpdateLogic()
{
base.UpdateLogic();
mono.StartCoroutine(DelayFunction()); //calling couroutine
}
IEnumerator DelayFunction()
{
yield return new WaitForSeconds(2);
Debug.Log("Test!");
}
}
i tried to acces the monobehaviour using parser method. but it is not clear and didnt work. how to solve this problem. what is wrong in this code.
I tried the other method shown in stackoverflow but not working.
Inheritance and MonoBehaviour aren't friends. In C# you can't inherit from two base classes. There are good reasons for that, but we have to deal with the inconvenience from time to time.
Problem with your script is that the mono variable is null and therefore you will get an error on the StartCoroutine line. Typically you would resolve that by constructing the missing class like this:
public MonoBehaviour mono = new MonoBehaviour();
Only problem with that, there is no constructor for MonoBehaviour (at least not one that is accessible). Sadly I don't have a document to quote, so take it with a grain of salt.
There is a workaround, that basically involves running the Coroutine thru your MonoBehaviour derived base class. I'm assuming that your BaseState is derived from MonoBehaviour.
public override void UpdateLogic()
{
base.UpdateLogic();
base.StartCoroutine(DelayFunction());
}
I am making a VR game where I want to display the ammo next to the gun. I keep getting a error and dont know how to fix it. Please help
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ammoText : MonoBehaviour
{
public GameObject weapon;
Text ammoText;
void Awake()
{
ammoText = GetComponent<Text>();
}
// Update is called once per frame
void Update()
{
ammoText.text = weapon.GetComponent<Gun>().currentBullets.ToString();
}
}
After passing line public class ammoText : MonoBehaviour the compiler knows that ammoText is a class and this is used to evaluate the correctness of the code. Statement Text ammoText; generates a compilation error because class ammoText must not occur in such a statement. Also other occurrences of ammoText will generate errors.
It is recommended to start class names with capital letters so it may be enough to rename the class to AmmoText.
You can't name a variable the same as your class name. Change the text field name from ammoText to something else.
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ammoText : MonoBehaviour
{
public GameObject weapon;
Text renameThis;
void Awake()
{
renameThis = GetComponent<Text>();
}
// Update is called once per frame
void Update()
{
renameThis.text = weapon.GetComponent<Gun>().currentBullets.ToString();
}
}
I have had problems with the OnDrop method, it is that it is not called, I was reading and maybe it has something to do with a Raycaster component, but I'm not sure, I don't even have knowledge of it, if someone could explain this to me I would greatly appreciate it.
Here is my code in c # plus an image of my hierarchy in Unity2D:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class Drop : MonoBehaviour, IDropHandler
{
public void OnDrop(PointerEventData eventData)
{
if (eventData.pointerDrag != null)
{
Debug.Log("Aqui esta");
}
}
}
From already thank you very much.
OnDrop method is not called
To ensure the Method gets called you need to ensure that both the name and inherited class you use is correct.
As it seems you need to use override for each function and instead of IDropHandler and MonoBehaviour inherit from EventTrigger.
Example:
using UnityEngine;
using UnityEngine.EventSystems;
public class Drop : EventTrigger {
public override void OnDrop(PointerEventData eventData) {
// Check if the eventData is Null.
if (eventData.pointerDrag != null) {
Debug.Log("OnDrop called.");
}
}
}
EventTrigger
I have tried using
using UnityEngine;
using UnityEngine.SceneManagement;
public class LoadBScene : MonoBehaviour
{
void Start()
{
Debug.Log("LoadSceneB");
}
public void LoadB(string SceneB)
{
Debug.Log("sceneName to load: " + SceneB);
SceneManager.LoadScene(SceneB);
}
}
I have not been able to get the scene to change.
Anyone have any ideas?
Please and thank you!
Looks to me like the problem here is that you simply aren't calling the LoadB() method which means that SceneManager.LoadScene() is never reached. Inside the Start method just put
LoadB("InsertSceneNameHere")
I'm trying to extend a base class on my player object.
player has damage script that looks like this
using UnityEngine;
using System.Collections;
public class Damage : MonoBehaviour
{
public int health = 100;
public virtual void ReceiveDamage(int damageAmount)
{
Debug.Log ("Original");
}
}
And then the same player has another script like this :
using UnityEngine;
using System.Collections;
public class playerDamage : Damage
{
public override void ReceiveDamage(int damageAmount)
{
Debug.Log ("Extended");
}
}
But when I call the script from a 3rd scrip on another object like this:
var damageScript = collision.gameObject.GetComponent<Damage>();
if( damageScript)
{
damageScript.ReceiveDamage(damageAmount);
}
the only response to the log is "Original"
Shouldn't the child be called and "Extended" written to the log?
There are several ways to do this. The easiest one is to SendMessage.
collision.gameObject.SendMessage("ReceiveDamage", damageAmount);
Whatever implementation of ReceivedDamage that the collision GameObject has, that will be the one that is called. This is awesome because you don't need to specify the type yourself nor use GetComponent.
Important Extra Information
In any implementation that you choose the key step is to make sure that the right script is attached to the collision.gameObject. If you attach both scripts then you are playing with fire.
To avoid playing with fire please make Damage an abstract class.
public abstract class Damage : MonoBehaviour
{
public int health = 100;
public virtual void ReceiveDamage(int damageAmount)
{
Debug.Log ("Original");
}
}
Abstract will give you the same functionality you want, except that Unity3d won't let you attach Damage to the GameObjects, which is good to avoid mistakes. You will always have the option to have the original ReceiveDamage and the choice to override it on future classes that inherit from Damage, like this:
public class Example : Damage
{
// This one still has ReceiveDamage but it happens in the base class.
}
or
public class PlayerDamage : Damage
{
public override void ReceiveDamage(int damageAmount)
{
Debug.Log("Extended");
}
}
I think when you call this line:
var damageScript = collision.gameObject.GetComponent<Damage>();
It gets the component by name, which in this case would be the Damage script, not the playerDamage script.
In you script it should be:
var damageScript = collision.gameObject.GetComponent<playerDamage>();
if( damageScript)
{
damageScript.ReceiveDamage(damageAmount);
}