Hi guys . I recently started using unity for a school project . I have moved from xna and ogre so i am kinda lost as to how to develop a framework for a character .
Is there a “good practice” that i need to follow while creating a class for a character ? I mean how should i approach this ? Do i put all the behaviour for the character in a single script ? It would be great if i could get some pseudo code or something .
Check out the 3rd Person Platform Tutorial. There is a fully functioning character in there, which should give you a good idea of at least one way to set one up.
If you wanted different character classes, then you’d probably either create separate scripts for each class (which would end up reusing a lot of code), or put in if statements for each class in a single script. (if classType == 0) for example. If you stored class type as an integer, you could have it so that 0 is a hunter, 1 is a warrior, etc…
All you’d need is to do class-specific stuff based on the if statement.
Thanks , I will look up the tutorial .
I am sorry if i wasnt very clear but i wasnt talking about character classes from an rpg point of view . I want to know how i would define a class which stores a character info . I mean like health , equipment etc . I can use normal variables to store these but i was confused about behaviors . Say i want to write a behaviour for what my character does when i left click on the ground, or when i left click on an object that can be picked up .
The scripting languages in Unity are all Object Oriented, so you should be able to handle this pretty easily. I’d recommend C# as you can then use Interfaces which can be pretty handy for implementing different behaviors in different classes. If you’ve been doing some work in XNA already you may be familiar with these.
I’d start off with a base class with health, strength, etc. then work out which behaviors all the classes have, and split them up if they have different implementations for each class. For example you might have a mage class and a warrior class, each can attack but both attack in different ways. You could have an IAttack interface, which has an attack function that you implement differently for each class, then it’s just a matter of calling that attack function in all different player classes which simplifies your main game logic.
Here’s the MSDN reference on interfaces. Should be a good starting point for you.
For the behaviors you describe above, like clicking on the ground, or clicking on an object, it’s best to do a raycast test against the object. This will return information about the object you clicked on, and you can make it as simple as placing tags on different types of objects, and having defined behaviors for each tag, or you could put in an IClickable interface, that has a Clicked() function that you call, which you would implement differently for each type of clickable object.
Theres many different ways you could approach the problem, if you need some more info on the language options let me know, I can go into some more detail about it, but don’t write a different script for each type or try and jam it all into one script, theres a reason object oriented languages have inheritance, it’s to avoid having to do those kinds of things.
Thanks a lot . I decided to use C# as you suggested . Atleast its fimiliar to what I am used to but I am still not comfortable with OOP in scripts . I have no idea how to access class variables of another game component . For example , I have an Agent class which reperesents the player . The agent is going to be controlled using the mouse . I do a raycast on left click and get the transform which was hit . Now I want to know if this object that i hit was terrain or an object or an enemy agent . I am not able to figure out how to do this .
This is how my Agent script looks like .
using UnityEngine;
using System.Collections;
class agentClass
{
public string objectType;
public int health ;
public string offensiveWeapon;
public string defensiveWeapon;
}
public class Agent: MonoBehaviour {
agentClass agent;
// Use this for initialization
void Start () {
agent = new agentClass();
agent.objectType = "agent";
agent.health = 100;
agent.offensiveWeapon = "fist";
agent.defensiveWeapon = "koolaid";
}
// Update is called once per frame
void Update () {
float x = Input.GetAxis("Horizontal")*5*Time.deltaTime;
float z = Input.GetAxis("Vertical")*5*Time.deltaTime;
transform.Translate(x,0,z);
if (Input.GetButtonDown("Fire1"))
{
Ray theRay = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast (theRay, out hit, 100))
{
Debug.Log("HIT:"+hit.transform.name);
}
}
Debug.Log("Health:"+agent.health);
}
void OnMouseDown()
{
// Put in code that sends message to the Level Manager that the Agent is selected .
}
void OnCollisionEnter(Collision collider1)
{
agent.health = agent.health - 1;
}
}
The easiest way would be to use tags, which you can assign in the editor. Here is a link to the documentation on tags.
You could also create a simple script that every object has like this.
class Clickable : MonoBehaviour
{
void Clicked()
{
// Do your click code here
}
}
Then in all the objects that can be clicked should respond to your raycast like so.
if (Input.GetButtonDown("Fire1"))
{
Ray theRay = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast (theRay, out hit, 100))
{
Debug.Log("HIT:"+hit.transform.name);
Clickable cl = hit.transform.GetComponent(typeof(Clickable)) as Clickable;
if(cl != null)
{
// GetComponent returns null if there is no script of type Clickable
cl.Clicked();
}
}
}
Now this will work but you require a different implementation for each different object, which means you will probably have a giant switch statement handling all possible click types in one script. We need an easier way to handle that, which is where Interfaces come in. Rather than have a clickable class, you could define an interface.
interface IClickable
{
void Clicked();
}
And then have more specialised types for each object
class Crate : Monobehaviour, IClickable
{
void IClickable.Clicked()
{
// Place specific crate click behaviour here.
}
}
Now when you go to use GetComponent, you should be able to grab the IClickable type
IClickable cl = hit.transform.GetComponent(typeof(IClickable)) as IClickable;
if(cl != null)
{
// GetComponent returns null if there is no script of type IClickable
cl.Clicked();
}
This gives you an easy way to implement many different types of clicks in much neater code, not having to write giant switch statements, and not having to test for many types of scripts that could be on each object.
I haven’t tested this, so if theres something major in the Interface code I’ve overlooked I apologise, anyone else feel free to correct me.
Good luck with it :).
Thanks a lot Murcho . I used tags and now i see how i should proceed . I will try to use interfaces to implement my object behaviours . My next doubt ( i am sorry i have lots of them as i am just starting up ) is about the oop framework . As i understand any behaviour script in unity needs to be derived from MonoBehaviour . So can i have classes which do not derive from MonoBehaviour ? Like can I have script which has an Agent class where i store all the variables and methods and another script which has a class which has MonoBehaviour as a base class and implements all the Agent behaviours . I understand that Unity compiles Scripts according to its location . So I am guessing the Agent class should be in the Standard assets folder and i can have Behaviour scripts which refers to the Agent class outside of the standard assets folder .
You can have classes that don’t derive from MonoBehaviour. There’s no special place you need to put them to make them compile correctly - just put them anywhere convenient. Sometimes it is useful to declare classes in the same script where the MonoBehaviour is declared:-
[System.Serializable]
public class CharacterData {
...
}
public class Player : MonoBehaviour {
public CharacterData data;
...
}
The reason for the System.Serializable attribute is that is makes the public variables of CharacterData visible in the Unity editor - they won’t be otherwise.