dealing with non-custom components in DOTS - c#

I want to start learning Unity DOTS with a simple 2D movement. I took the currently newest video to dive into it
https://www.youtube.com/watch?v=BNMrevfB6Q0
and know how to setup a custom component with a system. But for the movement I need the Rigidbody2D component now so I attached it to my gameobject.
My conversion script converts that GO to an entity
public class MovementBehaviour : MonoBehaviour, IConvertGameObjectToEntity
{
[SerializeField]
private float movementSpeed;
public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
{
dstManager.AddComponentData(entity, new MovementInputComponent());
dstManager.AddComponentData(entity, new MovementSpeedComponent { Value = movementSpeed });
// rigidbody gets converted automatically ... ?
}
}
And the system should handle a simple physics movement
public class MovementSystem : JobComponentSystem
{
[BurstCompile]
struct MovementJob : IJobForEach<MovementInputComponent, MovementSpeedComponent, Rigidbody2D>
{
public float fixedDeltaTime;
public void Execute(ref MovementInputComponent movementInput, ref MovementSpeedComponent movementSpeed, ref Rigidbody2D rigidbody)
{
// rb.MovePosition(rb.position + movementInput + movementSpeed * fixedDeltaTime);
}
}
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
MovementJob job = new MovementJob { fixedDeltaTime = Time.fixedDeltaTime };
return job.Schedule(this, inputDeps);
}
}
Unfortunately the MovementJob throws an error
The type 'Rigidbody2D' must be a non-nullable value type in order to
use it as parameter 'T2' in the generic type or method
'IJobForEach'
so does someone know how to deal with the Rigidbody component?

Related

Getting inspector tab of script when it is slid into an inspector field

Here is all the elements of my problem: i have a "ShotPattern" class that is supposed to define a bullet pattern that would be shot by a firearm.
A Shot Pattern in code:
[System.Serializable]
public class ShotPattern : MonoBehaviour
{
[Header("Projectile info")]
[SerializeField]
private GameObject projectile;
[SerializeField]
private AMovementPattern projectileMovementPattern;
[Header("Pattern shape info")]
[SerializeField]
private Vector2 startVector = Vector2.zero;
[SerializeField]
private Vector2 endVector = Vector2.zero;
[SerializeField]
private int projectileAmount = 1;
[SerializeField]
private float timeBetweenShots = 0;
[SerializeField]
private float speedIncrementBetweenShots = 0;
private void Start()
{
Shoot(transform.position);
}
public virtual void Shoot(Vector3 origin)
{
float angleDelta = (Vector2.SignedAngle(startVector,endVector)) / projectileAmount;
for (int i = 0 ; i < projectileAmount ; i++)
{
GameObject currentProjectile = Instantiate(projectile,origin,quaternion.identity);
StraightMovePattern currentMovePattern = currentProjectile.AddComponent<StraightMovePattern>();
currentMovePattern.direction = startVector.normalized;
}
}
}
A ShotPattern in inspector
I also have a few classes that define movement patterns for the resulting projectiles (move straight, in a sine wave, etc), these classes all inherit from the "AMovementPattern" Class.
The AMovementPattern abstract class in code:
[RequireComponent(typeof(Rigidbody2D))]
public abstract class AMovementPattern : MonoBehaviour
{
/**
* Direction of the movement pattern. (is down by default since we assume movement patterns are mostly used by enemies)
*/
[Header("General movement info")]
public Vector2 direction = Vector2.down;
/**
* Speed of the movement pattern.
*/
[SerializeField]
protected float speed = 1f;
protected Rigidbody2D rb;
protected virtual void Start()
{
rb = GetComponent<Rigidbody2D>();
}
protected virtual void FixedUpdate()
{
MovementUpdate();
}
/**
* Method to calculate the new position of the object based on the movement pattern and previous position.
*/
protected virtual void MovementUpdate()
{
throw new NotImplementedException();
}
}
A Movement pattern subclass in code:
public class StraightMovePattern : AMovementPattern
{
protected override void MovementUpdate()
{
rb.velocity = direction * speed;
}
}
A Movement pattern subclass in inspector
As you can tell from the ShotPattern inspector tab i want to be able to give a MovementPattern script to the ShotPattern editor for it to add to the projectiles it will produce on instanciation.
Unity won't let me just slide one of my MovePattern subclasses into the "AMovePattern" field, I am guessing it is because this field wants an instance of those classes with its parameters already set , is there a way to make it so that i could slide any of the MovePattern scripts in there and have the the corresponding inspector tab appear?
I know that i could make an empty GameObject that holds a movement pattern script, and initialize the values of that movement script in this GameObjects editor, but that kind of defeats the purpose of having it in inspector where i can edit the overall pattern on the fly to test out different compositions, so i'd like to avoid that.
I would suggest add those changes make MovementUpdate abstract like this so you will need to always implement this method.
protected abstract void MovementUpdate();
The second I would separate data and execution of pattern to two separate classes. Then I would redo the ShootPattern like this.
[Header("Projectile info")]
[SerializeField]
private Projectile projectile;
[SerializeField]
private AMovementPattern projectileMovementPattern;
public virtual void Shoot(Vector3 origin)
{
float angleDelta = (Vector2.SignedAngle(startVector,endVector)) / projectileAmount;
for (int i = 0 ; i < projectileAmount ; i++)
{
var currentProjectile = Instantiate(projectile,origin,quaternion.identity);
currentProjectile.Init(projectileMovementPattern, startVector.normalized);
}
}
And I suggest you to use ScriptableObject to hold such a data.
Remark from a Unity/C# guy
It has nothing to do with a abstract class.

get transform component via string to track player

im trying to grab the transform component via t.find and then via the transform component, grab the game object component, and then t.LookAt can work, and look at the player.
this is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class gunner : MonoBehaviour
{
//legacy statements: isShot
//these statements initialize all the main variables used in the project. most of these are for the "ai".
#region variables
[Header("gun stats")]
[Space(10)]
public float damage = 10f;
public float range = 100f;
[Space(10)]
[Header("Camera")]
[Space(10)]
public Camera cam;
[Space(10)]
[Header("AI Variables")]
[Space(10)]
public float shootlength;
public bool aiactive;
public float Speed;
public target self;
public Transform t;
public Rigidbody rb;
public string playername = "Player";
public GameObject PlayerObject;
public Transform PlayerTrans;
[Header("Decor")]
public ParticleSystem ps;
AudioSource audioData;
#endregion
#region gunmanager
private void Start()
{
GameObject PlayerObject = GameObject.Find(playername);
Transform PlayerTrans = PlayerObject.GetComponent<Transform>();
}
void Update()
{
if(aiactive && PlayerTrans != null)
{
Debug.Log("player trans found!");
}
if(aiactive && PlayerObject != null)
{
Debug.Log("player gameObject found!");
}
if(aiactive && PlayerTrans != null && PlayerObject != null)
{
Debug.Log("test passed!");
}
audioData = GetComponent<AudioSource>();
if (Input.GetButtonDown("Fire1") && !aiactive)
{
audioData.Play(0);
Shoot();
}
if(aiactive)
{
StartCoroutine(aiman());
}
}
public void Shoot()
{
ps.Play();
RaycastHit hit;
if(Physics.Raycast(cam.transform.position, cam.transform.forward, out hit, range))
{
Debug.Log("Hit:" + hit.transform.name);
target targ = hit.transform.GetComponent<target>();
if (targ != null)
{
if(!aiactive)
{
self.hp += 50;
}
targ.TakeDamage(damage);
}
}
}
public void aiActivity()
{
if(self.hp >= 0)
{
t.LookAt(PlayerTrans);
rb.AddRelativeForce(Vector3.forward * Speed * Time.deltaTime);
RaycastHit hitplayer;
if(Physics.Raycast(cam.transform.position, cam.transform.forward, out hitplayer, shootlength))
{
if(hitplayer.transform == PlayerObject)
{
Shoot();
}
}
}
else
{
rb.useGravity = true;
aiactive = false;
}
}
IEnumerator aiman()
{
yield return new WaitForSeconds(1f);
aiActivity();
}
#endregion
}
so no compiler errors, but it cannot find the player and float towards it, and therefore, I cannot get this to work.
Here are a few issues with the updated snippet, not sure if they will fix all of the errors you are getting.
You are re-using a variable name t. I would also refrain from naming any global variables very short random letters as it can get confusing. What is this a Transform of? If it is the transform of a player, possibly name it PlayerTransfom.
As I mentioned you are re-using a variable name which is not allowed especially with different types as well as re-initilization. It is fine to re-assign a variable such that it is updated, manipulating, changing, etc. the value, but re-declaring the value is not allowed in c# and I do not believe allowed in any other language (at least that I know of).
To be specific, the line target t = hit.transform.GetComponent<target>(); is delcaring t as the script component type target, but you have already declared a Transform named t above it as public Transform t;.
Another issue is you are attempting to assign a variable using a non-static method in a global setting. The line specifically is public Transform player = Transform.Find(playername);. You are not able to set the transform like this outside of a method as the Find method is not static. Change it to be.
public Transform player;
private void Start()
{
player = Transform.Find(playername);
}
The second error is because of the same reason, but due to this line public GameObject PlayerObject = player.GetComponent<GameObject>();. Again, GetComponent is a nonstatic method so can not be called in a global setting. The other issue is GameObject is not a component, it is a type. GameObjects have components so you can not get the component of itself as it does not exist. You are already using Transform.Find which finds a transform, I would recommend just finding the GameObject, storing that reference then get the Transform from the gameObject. You do not really need to store the transform as its own reference if you have the GameObject reference though.
public Transform player;
public GameObject PlayerObject;
private void Start()
{
PlayerObject = GameObject.Find(playername);
player = PlayerObject.transform;
}
The final error being outputted is specifying that you are using LookAt incorrectly. You need to pass in a type of Transform, but you are passing in a type of GameObject. Change it to...
t.LookAt(player);
Most of these issues are rather trivial and straightforward. I would follow along with a tutorial or read through the docs to get a better understanding of C#/Unity/Programming. Being a beginner is fine, but StackOverflow should not just be used as debugging help when the errors are right there. I do not know if the 4 recommendations I mentioned will fully fix your program as I did not run it. There could be more issues than what I had mentioned, but following the errors should tell you what is wrong and why it is wrong. It is printing the line number, file, and reason for why it is breaking.

Unity code cleaning: writing general shooting script implementing same methods from different bullet classes

I picked up unity and C# a month ago so I'm still a noobie.
So far I managed to build a simple space-based arcade shooter (i have my ship, i have a way to shoot bullets). What I'm trying to achieve is a way to keep the script that takes my keyboard input to shoot separate from the possible bullet types.
The way my bullet types are currently implemented is by having a gameobject for each with its own scripts for a) taking keyboard input and b) instancing a prefab with different properties to shoot. Currently i have 2 shooting modes, and a separate script lets me swap between them with the spacebar by enabling disabling the gameobjects. An example of the scripts I'm using for one bullet type:
Script for instantiating bullet. One method simply shoots every time a button is pressed, the other "charges" an array of bullets, accompanied in the second script by a "growing aura" signifing the power increase. These two methods have the same name across different bullet classes, but are implemented differently.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletA_Basic : MonoBehaviour
{
public GameObject bulletPrefab;
public GameObject aura;
public Transform firingPoint;
public Transform chargingPoint;
public float bulletForce = 20f;
public float altCooldown = 1f;
public float fireRate = 1f;
public float altFirePowerMultiplier = 1f;
private void Update()
{
}
public void Shoot()
{
GameObject bullet = Instantiate(bulletPrefab, firingPoint);
Rigidbody2D rb = bullet.GetComponent<Rigidbody2D>();
rb.AddForce(firingPoint.up * bulletForce, ForceMode2D.Impulse);
}
public void SpecialShoot(int n)
{
StartCoroutine(Special(n));
}
public IEnumerator Special(int n)
{
for (int i = 0; i < n; i++)
{
Shoot();
yield return new WaitForSeconds(0.1f);
}
}
}
Script for taking keyboard input
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Shooting_A : MonoBehaviour //This needs to be copied across all firing types
{
private BulletA_Basic bulletScript; //Change the class to make new projectile types with different firing modes
public Vector3 scaleChange;
private GameObject auraInstance;
private float timePassed = 0f;
private float timePassedMain = 0f;
public float timeToDetonation = 3f;
private void Start()
{
bulletScript = GetComponent<BulletA_Basic>();
}
// Update is called once per frame
void Update()
{
bool isFiring = Input.GetButtonDown("Main Cannon");
bool alternateFire = Input.GetButton("Main Cannon");
timePassedMain += Time.deltaTime;
if (isFiring && timePassedMain > bulletScript.fireRate)
{
bulletScript.Shoot();
timePassedMain = 0;
}
if (alternateFire)
{
timePassed += Time.deltaTime;
if (!auraInstance && timePassed >= bulletScript.altCooldown)
{
auraInstance = Instantiate(bulletScript.aura, bulletScript.chargingPoint);
}
if (alternateFire && auraInstance && timePassed < timeToDetonation)
{
Charge();
//Will need to add shader here
}
else if (timePassed >= timeToDetonation)
{
Destroy(auraInstance);
timePassed = 0;
}
}
else
{
if (auraInstance)
{
Destroy(auraInstance);
int powerAltFire = (int)(bulletScript.altFirePowerMultiplier * (Mathf.Pow(2 , timePassed))); //Equation returns a number of projectiles based on how long charge was held
bulletScript.SpecialShoot(powerAltFire);
}
timePassed = 0;
}
}
void Charge()
{
auraInstance.transform.localScale += scaleChange;
}
}
The key here is the bulletScript field.
Basically i'd like to make the second script general so that i don't have to implement it in a different way and copy-pasting it again and again for each type of bullet I'm going to make, and changing the bulletScript field type each time.
I tried doing it with interfaces but I'm not sure how to implement it in the general script since I need to access each field of the subclasses, which have each their own references (like bulletPrefab, or aura). In general i feel interfaces are not well integrated into unity but that might just be me.
I also tried with delegates, but i had similar problems. I simply changed the type of bulletScript to my delegate type (ShootingDelegate bulletScript), and wrote this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public delegate void ShootDelegate();
public delegate void SpecialShootDelegate(int n);
public class ShootingDelegate : MonoBehaviour
{
public ShootDelegate delShoot;
public SpecialShootDelegate delSpecialShoot;
private int weaponIndex;
public GameObject bulletPrefab;
public GameObject aura;
public Transform firingPoint;
public Transform chargingPoint;
public float bulletForce;
public float altCooldown;
public float fireRate;
public float altFirePowerMultiplier;
// Start is called before the first frame update
void Start()
{
WeaponSwap weapon = GetComponent<WeaponSwap>();
weaponIndex = weapon.weaponIndex;
switch (weaponIndex)
{
case 1:
BulletB_Fan bulletB = GetComponent<BulletB_Fan>();
delShoot = bulletB.Shoot;
delSpecialShoot = bulletB.SpecialShoot;
bulletPrefab = bulletB.bulletPrefab;
aura = bulletB.aura;
firingPoint = bulletB.firingPoint;
chargingPoint = bulletB.chargingPoint;
bulletForce = bulletB.bulletForce;
altCooldown = bulletB.altCooldown;
fireRate = bulletB.fireRate;
altFirePowerMultiplier = bulletB.altFirePowerMultiplier;
break;
case 0:
BulletA_Basic bullet = GetComponent<BulletA_Basic>();
delShoot = bullet.Shoot;
delSpecialShoot = bullet.SpecialShoot;
bulletPrefab = bullet.bulletPrefab;
aura = bullet.aura;
firingPoint = bullet.firingPoint;
chargingPoint = bullet.chargingPoint;
bulletForce = bullet.bulletForce;
altCooldown = bullet.altCooldown;
fireRate = bullet.fireRate;
altFirePowerMultiplier = bullet.altFirePowerMultiplier;
break;
}
}
// Update is called once per frame
void Update()
{
}
}
This is the error it throws:
ArgumentException: Value does not fall within the expected range.
ShootingDelegate.Start () (at Assets/Scripts/ShootingDelegate.cs:54)
which corresponds to this line
delShoot = bullet.Shoot;
I don't really care if a solution employs either interfaces or delegates, those were just things I tried. Any thoughts?
I created a sample just for you.
Here I am creating BulletType parent class for all bullet types. And atting some variable and method for all bullets.
public class BulletType : MonoBehaviour
{
// Protected is less stric than private, more stric than public
// Protected variables only accesible to this class and its child.
protected string name;
protected int bulletDamage;
protected int bulletSpeed;
protected virtual void Start()
{
}
// Virtual means you can override this method in child classes
protected virtual void Damage() { }
public virtual void PlaySound() { }
protected virtual void ShowEffect() { }
}
Now I will add child class and inherit from parent BulletType class. Everything write in comment lines.
// This class inherits from BulletType class.
public class FireBullet : BulletType
{
// If you want to completely ignore parent class variable to by adding new keyword.
new int bulletSpeed = 3;
protected override void Start()
{
// when overriding a method automatically adds this method.
// base means parent class. with base you can access parent methods.
base.Start();
// If you remove base method, parent method won't be called in this class.
// Here I accessed parent class variable and set its value.
// This doesn't effect parent or other child classes. That's the beauty.
name = "Fire Bullet";
}
void StopSound()
{
}
protected override void PlaySound()
{
// Sound played from parent.
base.PlaySound();
// You can add your own variable and methods in parent method.
StopSound();
}
}
// FireBullet inherited from BulletType, and LavaBullet inherited from FireBullet.
// You can do this as much as you want.
public class LavaBullet : FireBullet
{
protected override void PlaySound()
{
// Here base will be FireBullet
base.PlaySound();
}
}
public class IceBullet : BulletType
{
// Add as much as you thing.
}
And for using BulletType script in your player just add this line
public class Player
{
public BulletType currentBulletType;
// You can get child from main class.
FireBullet fireBullet = currentBulletType.GetComponent<FireBullet>();
// Now you can access and use child class methods.
fireBullet.PlaySound();
}
and when you want to change bullet type, just assign new bullettype. Because all bullet type inherit from this class. You can assign every bullet type.
I don't know if it's the answer but,
delShoot = bulletB.Shoot;
delShoot is a reference to a script.
bulletB.Shoot is a function.
I don't think you can make one equal to the other.
If I understand your question, you want to make one script for two type of bullets shoot. You can create a scipts Shoot.cs who is instantiate with a value (1 for the default fire 2 for the second fire) and other scrits defaultFire.cs / secondFire.cs with they own properties.
Like this you'll juste instantiate once your Bullet like this :
public void Start(){
case 1 : Shoot shoot = new Shoot(1)
case 2 : Shoot shoot = new Shoot(2)
}
Hope this help a little..

Unity - Movement Controller or movement function on every gameObject

So I'm trying to make a game with diferent unit types, each one with diferent movement speeds. I don't really know how to face this problem: At first I did a function on every unitType to define the speed but I don't think this is the most optimal way to do it. Now i was thinking about creating a MovementController class. This is what I did so far: First of all, I did a generic Unit Class -to keep it simple, I will just show the movement speed attribute- :
public class GenericUnit : MonoBehaviour
{
float movementSpeed;
public float mspeed
{
get { return movementSpeed; }
set { movementSpeed = value; }
}
}
after, I defined all atributes in a subClass depending of the unit type:
public class Archer : MonoBehaviour
{
GenericUnit archer;
void Start()
{
archer = new GenericUnit();
archer.mspeed = 3.0f;
}
}
This is the Movement controller I have right now:
public class Movement_Controller : MonoBehaviour
{
GenericUnit msUnit;
public float mspeed;
public bool movimentTrue;
void Start()
{
msunit = new GenericUnit();
mspeed = msUnit.mspeed;
movimentTrue = true;
}
void Update()
{
if (movimentTrue) {
Movement();
}
}
public void Movement(){
Vector3 moviment = new Vector3 (1.0f, 0.0f, 0.0f);
transform.position += Time.deltaTime * mspeed * moviment;
}
}
After all, this isn't working. Do you have any idea of whats the issue? I have been trying many other options that didn't make it. Do you think it's better to have this MovementController script or pasting the movement function on the Archer class? As you can see, im a novice on programming, so any suggestion would help a lot.
Thank you
What you are looking for is simple inheritence.
You describe the features you need in a base class and mark them (and the class) abstract. This enforces you to override it in all non abstract derived classed.
Base class:
public abstract class BaseUnit : MonoBehaviour
{
protected abstract float movementSpeed { get; } // force every deriving class to provide a movement speed
[SerializeField] private bool isMoving;
void Start()
{
isMoving = true;
}
void Update()
{
if (isMoving)
{
Movement();
}
}
public void Movement()
{
Vector3 direction = new Vector3(1.0f, 0.0f, 0.0f);
transform.position += Time.deltaTime * movementSpeed * direction;
}
}
Derived class Archer:
public class Archer : BaseUnit
{
protected override float movementSpeed => 3F;
}
Also note that you cannot create MonoBehaviours using the new keyword. You have to use AddComponent<T> to create or GetComponent<T> to retrieve them (see documentation).

In Unity, what type of method is Update()? And how to make my own?

How do gameobjects know that void Update means every frame and that OnCollisionEnter means when they collide. Can I make my own? Kind of like this
void OnPositionChange () {
//code goes here
}
And then any script that has that OnPositionChange will recognize it and do something with it when the position changes.
The BuiltIn SendMessage component:
http://docs.unity3d.com/ScriptReference/Component.SendMessage.html
And this might help you for something, I guess:
http://answers.unity3d.com/questions/676625/creating-my-own-custom-unity-messages.html
Here, the suggestion is to make a base class from which all objects that will need the method extends. In the example he used a damage source and damageable objects and example how they would interact:
In DamageSource.cs (the class you'd use to give damage to )
using UnityEngine;
using System.Collections;
public class DamageSource : MonoBehaviour {
protected float damageAmount = 10f;
//not 100% necessary, but handy for an example of how to
//handle damage based on the attacker (which is
//relevant for info sent in the OnTakeDamage() method
protected ElementType elementType = ElementType.Normal;
//we use a function for getting the damage this
//DamageSource can do because it lets us overwrite it.
//Eg, if the enemy is weakened, you can factor that
//in and return a lesser amount of damage.
public float GetDamageAmount() {
return damageAmount;
}
public ElementType GetElementType() {
return elementType;
}
}
//kinds of elements available for damage / resistance calculations
public enum ElementType {
Normal,
Fire,
Ice,
Lightning
}
In DamageableObject.cs (the base class from which all damageable objects inherit):
using UnityEngine;
using System.Collections;
public class DamageableObject : MonoBehaviour {
protected bool wasRecentlyHit;
protected float health;
protected float maxHealth;
public void Awake() {
health = maxHealth;
}
//Creating a virtual void method lets you choose whether
//or not you want to set it in a derived class.
//Here, we track the amount of damage and the source
//the damage came from. This can sometimes be handy for
//context-sensitive reactions to being damaged. Eg, play
//a particular sound in damaging the player, when
//successfully damaged by a particular attack.
//Note that this base implementation does nothing - you
//override it in an inheriting class, very similar to using Update() etc.
protected virtual void OnTakeDamage(float damageAmount, DamageSource damageSource) {}
//An example of how you'd check whether damage is incoming.
//You can alternatively just call
//someDamageableObject.TryDoDamage() from another script.
public void OnTriggerEnter(Collider other) {
DamageSource damageGiver = other.GetComponent<DamageSource>();
if (damageGiver) {
TryDoDamage(damageGiver.GetDamageAmount(),damageGiver.gameObject);
}
}
public void TryDoDamage(float damageAmount, GameObject damageGiver) {
//early out, this DamageableObject was damaged a very
//short time ago and shouldn't be damaged again so soon
if (wasRecentlyHit) return;
//optionally perform any damage calculations here based
//on the damageGiver, eg more damage from the player
//being weakened somehow, or less damage from type
//resistances... etc.
damageAmount = CalculateDamage(damageAmount,damageGiver);
//if after our damage calculations we still have an
//amount of damage greater than 0, we do the damage and
//send the OnTakeDamage() message.
if (damageAmount>0f) {
health -= damageAmount;
//optional handling of dying (uncomment this and the OnDeath() function to enable)
//if (health<0f) {
// OnDeath(damageAmount,damageGiver);
//}
//else {
OnTakeDamage(damageAmount,damageGiver);
//}
}
}
//Uncomment this and the (healtn<0f) if statement above
//if you want to handle dying as well as being damaged
//protected virtual void OnDeath(float damageAmount, DamageSource damageSource);
//Default implementation for calculating damage,
//given some amount of damage, and some source of damage.
//Override this in an inheriting class if you want to do
//different damage, eg based on the damage source (2x
//damage from fire attacks, 0.5x damage from ice
//attacks... etc) or based on the DamageableObject's
//current state (eg, player is weakened, so takes 1.5x damage)
protected float CalculateDamage(float damageAmount, DamageSource damageSource) {
return damageAmount;
}
}
In PlayerDamageReceiver.cs:
using UnityEngine;
using System.Collections;
public class PlayerDamageReceiver : DamageableObject {
//override the OnTakeDamage() method to make a
//different implementation of it for this class
protected override void OnTakeDamage(float damageAmount, DamageSource damageSource) {
Debug.Log("Ouch, the player was damaged!");
}
//Uncomment this to override the OnDeath() function
//in DamageableObject (if you've uncommented that, that is)
//protected override void OnDeath(float damageAmount, DamageSource damageSource) {
// Debug.Log("Uhoh... The player died. :(");
//}
//override the CalculateDamage() function to
//determine how damage applies to the player
protected override float CalculateDamage(float damageAmount, DamageSource damageSource) {
//Example: give the player a 2x weakness to fire damage, and immunity to ice damage
switch (damageSource.GetElementType()) {
case (ElementType.Fire):
damageAmount *= 2f;
break;
case (ElementType.Ice):
damageAmount = 0f;
break;
}
return damageAmount;
}
}
(I copied and paste the code from "nesis" user here, as asked by a fellow on comments)
Actually you can do that. Simply you can make your own Behavior class.
public class MyBehavior : MonoBehaviour {
Vector3 lastPosition = new Vector3();
void Update () {
Vector3 position = new Vector3();
if (position != lastPosition)
{
OnPositionChange();
lastPosition = position;
}
else
{
lastPosition = position;
}
}
public virtual void OnPositionChange(){}
}
Now you define your script which inherits MyBehavior instead of MonoBehavior directly.
public class test : MyBehavior {
public override void OnPositionChange()
{
Debug.Log("override");
}
}
This is the closest thing to what you asked I belive.
float startPositionX;
float startPositionY;
float startPositionZ;
float currentPositionX;
float currentPositionY;
float currentPositionZ;
void start(){
startPositionX = gameObject.transform.position.x ;
startPositionY = gameObject.transform.position.y ;
startPositionz = gameObject.transform.position.z ;
}
void update() {
currentPositionX = gameObject.transform.position.x ;
currentPositionY = gameObject.transform.position.y ;
currentPositionZ = gameObject.transform.position.z ;
OnPositionChange ();
}
void OnPositionChange () {
if(startPositionX == ! currentPositionX ||
startPositionY == ! currentPositionY ||
startPositionZ == ! currentPositionZ){
/*write your own code that you want to perform.*/ }
}
Update(), Start() and other method with special function like these, are overloads from MonoBehaviour class. You can see all of your scripts are derived from MonoBehaviour class.
What you need is using Events. You can create an event and delegate and on special situation raise them so all your scripts that are register in that event can call their own method for that event.

Categories

Resources