Hello guys, I have one base class that is a “ObjectBehavior” and one class that represents a sequence of this behaviors, my idea is that each boss have a specific sequence of actions, so I was planning to make something like this for example:
public var fireball : transform;
public var behaviorGroup : BehaviorGroup;
function Start()
{
behaviorGroup = new BehaviorGroup();
behaviorGroup.addBehavior( new fireBallSpin() );
behaviorGroup.addBehavior( new fireBallPursuit() );
....
}
function Update()
{
behaviorGroup.mainLoop(); // this part is to execute the behaviors or just change them
}
public class fireBallSpin extends ObjectBehavior
{
...
function mainLoop()
{
fireball.position.x += 10*Time.deltaTime; // the problem is here, it will give an error "fireball is an unknown variable" or something like
}
}
The problem is that I can’t access the extern variable from the inner class like I write there. I don’t want to pass an extra parameter because the number of element that I have to manipulate inside this class can change, so it can become hard to control. Any suggestion or better idea to make this? Thanks
Classes are independent of other classes. the only way to make a “static” variable work is to use the “static” tag. This, is not suggested in your case. You really want “modifiers”
OK, so you want an object to behave using certain modifiers added to it. You throw a new fireball, to do this, you want to add a BehaviourController to it, and then add “modifiers” to that. So each frame in the update, the BehaviourController will call MainLoop from each modifier. In order to do this, you need to also give that MainLoop a gameObject.
Sounds complicated.
So I suggest dropping the “modifiers” idea. Add the modifiers as Components to the game object as well as the BehaviourController. The BehaviourController will contain things like target or target position. The modifiers simply get the BehaviourController and ask it what the target is, or where it is supposed to go. In the case of FireballSpin, it wouldn’t care about the target, it would just make it spin.
When the game object is destroyed, so are it’s components and all is happy.
Hmmm this sounds complicated too, how the Components would access the “global variables”? Using a key-value array inside the behaviourController? Or duplicating the variable declaration?
Well, please look this code for a better example, it makes the boss walk until the edge of the screen and go back and also it makes the boss jump.
PS: In my project I am using the word “Life” instead of “Behaviour”, for each life the boss will have a different behaviour.
#pragma strict
private var bossScript : BossScript;
public var controller : GenericObjectController; // this is a simple script to move my enemies
function Start () {
bossScript = new BossScript();
if( controller == null )
{
Debug.LogError("This boss needs a generic object controller, destroying it.");
GameObject.Destroy( transform.gameObject );
}
bossScript.pushLifeObject( new WalkAndJump( 1, BossLife.BL_INFINITY, controller, transform ) );
bossScript.initialize();
}
function Update ()
{
bossScript.mainLoop();
}
public class WalkAndJump extends BossLife
{
private var bossTransform : Transform;
private var controller : GenericObjectController;
private var jumpTime : float = 2.0;
private var lastJumpTime : float = 0.0;
private var speedValue : float = -3.0;
public function WalkAndJump( life : int, time : int, cont : GenericObjectController, trans : Transform )
{
super( life, time );
controller = cont;
bossTransform = trans;
}
public function initialize() : int
{
setDamageCallBack( onDamage );
// Start walking to the left with gravity enabled
controller.setMaxAbsSpeedVector( Vector3( 10,40,0 ) );
controller.setGravityUse( true );
controller.setAccelerationUse( false );
controller.setSpeedVector( Vector3( speedValue, 0 ,0 ) );
}
public function mainLoop() : int
{
if( lastJumpTime + jumpTime < Time.time ) // Each 2 seconds the boss jump
{
controller.addExternSpeedVector( Vector3(0, 30, 0 ) );
lastJumpTime = Time.time;
}
// Don't let the boss go away from the scene
if( bossTransform.position.x < 2 speedValue < 0 || bossTransform.position.x > 18.7 speedValue > 0 )
{
speedValue = -1*speedValue;
controller.setSpeedVector( Vector3( speedValue, 0 ,0 ) );
}
return BossLife.BL_OK;
}
public function finalize() : int
{
/* nothing to do */
}
public function onDamage()
{
// A little jump to simulate pain
controller.addExternSpeedVector( Vector3(0, -10, 0 ) );
Debug.Log("ouch");
}
}
Hmm and what if I want to access a GameObject from the component that controls the boss’ behaviour? For example if I want to create a Pigeon object I could do something like this.
public var pigeonObj : GameObject = null; // in the GUI editor I just drop the object that I want here
function summonPigeon()
{
GameObject.Instantiate( pigeonObj, Vector3.zero, Quaternion.identity );
}
I don’t see how to access it from the BehaviourController without using a ID for a specific object. I think that I can’t use GetComponent for this one, maybe I could let on pigeon in some invisible place and use the Find function to get it but this does not look right
There are many ways in Unity to access objects. Most revolve around the GameObject class. GameObject.Find, FindWithTag, FindGameObjectsWithTag. Also GameObject.GetComponent, GetComponentInChildren, GetComponents, GetComponentsInChildren
The Transform offers the parent and root properties as well.
You can define game objects as you do in your example script. This can be done using existing objects or prefabs.
One slick trick that I use is to simply place a bullet at the end of a gun, deactivate it then instantiate it every time I need it, and place it with the rotation and position of the original. your gun always shoots straight and you never run into dumb problems.
I create a vehicle with X wheels, I never drag them in the inspector, I just use gameObject.GetComponentsInChildren() to get my base components I need, then issue orders from those.
Its all incredibly versatile. I really don’t see the need to re-create the whole thing.
Hmm but I think that this does not help when the prefab that you want to create does not exist on the Scene. Is there a way to create an object using its path in the Assets folder?
Also now thinking better how can I force some component to follow a model like a class that extends another? For example in that code that I pasted here, all behaviour objects have the functions “Initialize” “mainLoop” and “finalize”. The only way that I know to do this with Components is to use the SendMessage method requiring a receiver.
And sorry to be annoying, it is that I think that the way that I did works well but I want to discuss it to see if I can do something better
Well this post’s main question was how to access global variables from Components from an internal class. About the Behaviours I think that I’ll use classes to this, I can extend behaviours to create more complicated behaviours and etc. It’s working well now and it’s easy to code. Thanks for all the answers guys