I have the following script in UnityScript, which is called JavaScript in Unity Editor but is not quite the same especially for looping through objects.
public class UpgradeProfile extends MonoBehaviour {
public var brakeSpeed : float = 0;
public var jumpForce : float = 0;
public var maxJumps : int = 1;
};
How can I loop through all the properties of this class and, for example, log the values or sum them with the values of another member of the same class?
Note: UnityScript is not JavaScript or C# so answers relating to those languages do not answer this question.
This works for me to get the properites and values.
#pragma strict
public var test1 = 10;
public var test2 = 11;
function Start ()
{
for(var property in this.GetType().GetFields())
{
Debug.Log("Name: " + property.Name + " Value: " + property.GetValue(this));
}
}
And this prints out
Name: test1 Value: 10
Name: test2 Value: 11
And if you want to do this with another component, replace this with a component instead
Related
I'm trying to code a program with multiple classes such the one of the class reads the variables from a text file and the other classes use these variables for further processing.
The problem I'm facing is that I'm having trouble passing the variables from one class to another class, I did try "friend" class and also tried to use constructors but failed
to get the desired output.
The best I could do was
suppose I have class 1 and class 2, and I have a variable "A=10" declared and initialised in class 1, with the help of constructor I inherit it in class 2;
when I print it in class 1, it gives a correct output as 10 but when I print it in class 2 it gives an output as 293e30 (address location)
Please guide me on how to this.
Class1
{
public:
membfunc()
{
int A;
A = 10;
}
}
Class2
{
public:
membfunc2()
{
int B;
B = A + 10;
}
membfunc3()
{
int C, D;
C = A + 10;
D = B + C;
}
}
If i print variables, i expect to get
A = 10, B = 20, C = 20, D = 40
But what I get is
A = 10, B=(252e30) + 10
I think your problem was that you were defining local variables in your member functions, instead of creating member variables of a class object.
Here is some code based on your sample to demonstrate how member variables work:
class Class1
{
public:
int A;
void membfunc()
{
A=10;
}
};
class Class2
{
public:
int B;
int C;
int D;
void membfunc2(Class1& class1Object)
{
B = class1Object.A + 10;
}
void membfunc3(Class1& class1Object)
{
C = class1Object.A + 10;
D = B + C;
}
};
(Full code sample here: http://ideone.com/cwZ6DM.)
You can learn more about member variables (properties and fields) here: http://www.cplusplus.com/doc/tutorial/classes/.
In my game I programmatically create a bunch of buttons for a level select screen, and my intention was to have their onClick fire a function with a parameter that corresponds to level number.
Pseudocode:
public class UIManager extends MonoBehaviour {
public var button : Transform;
public function Start() {
for(var i : int = 0; i < 10; i++) {
var level : int = i + 1;
var b : Transform = Instantiate(button);
b.GetComponent(UI.Button).onClick.AddListener(function(){
StartGame(level);
});
}
}
public function StartGame(level : int) {
Debug.Log(level);
}
}
However, in this situation, when any of these buttons is pressed, the console shows number 10.
How can I achieve what I'm aiming for?
You should have a look at how anonymous functions in JavaScript capture outer variables.
You are creating 10 anonymous functions in your for-loop. All these functions refer to the local variable level. However, they do not yet create their own scope for this variable until they are first called. This means, there is not 10 level locals, but only one until the first function is actually called. Only then will the current value of level be evaluated. And this will be the value it was assigned last: 10.
To get around this you'll have to force creation of a new scope during every iteration of the loop:
public class UIManager extends MonoBehaviour
{
public var button : Transform;
public function Start()
{
for(var i : int = 0; i < 10; i++)
{
var level : int = i + 1;
var b : Transform = Instantiate(button);
b.GetComponent(UI.Button).onClick.AddListener
(
(function(newLocalLevel)
{
return function()
{
StartGame(newLocalLevel);
};
}) (level)
);
}
}
public function StartGame(level : int)
{
Debug.Log(level);
}
}
I changed your direct assigned of an anonymous handler function to a factory function call, which takes the current (!) value of level as a parameter. As it is immediately executed, the factory function creates its own scope, with an own local called newLocalLevel that carries the correct value of level.
The factory function now creates and returns your anonymous handler function, which, even though it not yet creates its own scope, refers to the local newLocalLevel of the enclosing factory function, which has one seperate scope for every iteration of the loop.
See also http://www.mennovanslooten.nl/blog/post/62.
I've got errors
Assets/TextPierwszy.js(22,28): BCE0019: 'id' is not a member of 'Object'.
Assets/TextPierwszy.js(24,38): BCE0019: 'id' is not a member of 'Object'.
when trying to compile that script in UnityScript.
#pragma strict
private var pole : UI.Text;
public var Started = false;
public var Ludnosc = new Array();
public class Human {
public var id : byte;
public var gender : byte; // 0=k 1=m
public var age : byte;
public var pregnant : byte;
function Breed(partner) {
// Tu będzie logika rozmnażania
}
public var parents : int[]; //Najpierw podajemy ID matki, potem ID ojca.
}
function Test1() {
if(!Started) {
Started = true;
Ludnosc.push(new Human());
Ludnosc[0].id = 1; //Line number 22
Debug.Log(Ludnosc.length);
Debug.Log(Ludnosc[0].id); //Line number 24
}
}
How can I tell compiler to track Ludnosc[0] as instance of Human instead of tracking it at plain Object?
Or is there problem in other place? Also tried
public var Ludnosc : Human = new Array();
but this don't work too. :(
This is because when you initialize Ludnosc using:
public var Ludnosc = new Array();
you're creating an array of Object elements. As a result, when you try to access Ludnosc[0].id, Ludnosc[0] is treated an an Object and hence does not have id available to it.
To address this, either initialize Ludnosc as a built-in array like so:
public var Ludnosc : Human[];
Ludnosc = new Human[1]; // When you're initializing it
Ludnosc[0] = new Human(); // When you're populating it
Or, if you really want to use a JavaScript array, you can cast the Object to a Human when you access the value in Test1(), modify the typecasted version, then place it back into the array (haven't tested this code):
function Test1() {
if(!Started) {
Started = true;
Ludnosc.push(new Human());
var tempHuman = Ludnosc[0] as Human;
tempHuman.id = 1;
Ludnosc[0] = tempHuman; // Overwriting with the updated Human
Debug.Log(Ludnosc.length);
Debug.Log(tempHuman.id);
}
}
Hope this helps! Let me know if you have any questions.
I've searched long for this one, but nobody seems to give a clear answer. I'm a beginner, and I want to import a variable from the main "F9" actions panel into a class file so it can read it (example: in main .fla file, I have a variable var myNumber:Number = 1; how would I import it into a class file so the program can read it?)
You can create a “Document Class”. In this class you can place your variable. Where will you use myNumber variable?
package {
import flash.display.MovieClip;
public class Main extends MovieClip {
public var myNumber:Number = 1;
public function Main()
{ }
}
}
You can "share" your variable when you create an instance of your class by passing it in the class constructor, or using any other public function.
Take this example :
MyClass.as :
package {
public class MyClass {
private var number:int;
public function MyClass(num:int = 0) {
// assign the value of the variable to a private one for a later use
this.number = num;
// use directly the value of the variable
trace('the number is passed in the constructor : ' + num);
}
public function set_number(num:int):void {
// assign the value of the variable to a private one for a later use
this.number = num;
}
public function use_number(num:int):void {
// use the value of the variable
trace(num + ' x ' + num + ' = ' + (num * num));
}
}
}
test.fla :
import MyClass;
var my_number:int = 1234;
var my_class:MyClass = new MyClass(my_number); // using the class constructor
my_class.set_number(my_number); // using a function to set a private var value
my_class.use_number(my_number); // using a function to do some operations
Hope that can help.
Is there a way of mimicking MonoBehaviour copy semantics in ScriptableObjects?
Say I have a MonoBehaviour like so:
public class DummyClassBehaviour : MonoBehaviour {
public DummyClass DummyClassTest; //ScriptableObject
public DummyClassBehaviour DummyBehaviourTest; //Another DummyClassBehaviour
}
And a ScriptableObject:
public class DummyClass : ScriptableObject {
public string Text = "";
}
When I duplicate(CTRL+D) a GameObject w/ DummyClassBehaviour attached, 'DummyBehaviourTest' copies as you would expect: If it references a MonoBehaviour in the GameObject I'm copying, the copy mechanism updates the reference to the same MonoBehaviour type in the new GameObject. If it references a MonoBehaviour in another GameObject, that reference remains unchanged.
The ScriptableObject, on the other hand, always references the original. So I end up with N GameObject's all sharing the same ScriptableObject (DummyClass) from the original GameObject. I'm using ScriptableObjects to allow serialization of non-Monobehaviour data classes.
As far as I can tell, and please someone correct me if I'm wrong, you cannot modify the serialization behavior of a ScriptableObject to match that of a MonoBehaviour. Namely that it should update references if a duplicate is made.
Instead I opted for a less than optimal solution, but it works. My class is assigned a unique identifier that gets serialized like everything else. I use this ID in DummyBehaviour.Awake() to create a lookup table that I can then use to reassign my DummyClass.
I'm not going to accept my own answer because I don't feel it answers my original question fully, but it's related:
[System.Serializable]
public class DummyClass {
// Unique id is assigned by DummyBehaviour and is unique to the game object
// that DummyBehaviour is attached to.
public int UniqueID = -1;
public string Text = "";
// Override GetHashCode so Dictionary lookups
public override int GetHashCode(){
int hash = 17;
hash = hash * 31 + UniqueID;
return hash;
}
// override equality function, allows dictionary to do comparisons.
public override bool Equals(object obj)
{
if (object.ReferenceEquals(obj, null))return false;
DummyClass item = obj as DummyClass;
return item.UniqueID == this.UniqueID;
}
// Allow checks of the form 'if(dummyClass)'
public static implicit operator bool(DummyClass a)
{
if (object.ReferenceEquals(a, null)) return false;
return (a.UniqueID==-1)?false:true;
}
public static bool operator ==(DummyClass a, DummyClass b)
{
if (object.ReferenceEquals(a, null))
{
return object.ReferenceEquals(b, null);
}
return a.Equals(b);
}
public static bool operator !=(DummyClass a, DummyClass b)
{
if (object.ReferenceEquals(a, null))
{
return object.ReferenceEquals(b, null);
}
return !a.Equals(b);
}
}
And my MonoBehaviour:
[ExecuteInEditMode]
public class DummyBehaviour : MonoBehaviour {
public List<DummyClass> DummyClasses = new List<DummyClass>();
// reassign references based on uniqueid.
void Awake(){
Dictionary<DummyClass,DummyClass> dmap = new Dictionary<DummyClass,DummyClass>();
// iterate over all dummyclasses, reassign references.
for(int i = 0; i < DummyClasses.Count; i++){
DummyClass2 d = DummyClasses[i];
if(dmap.ContainsKey(d)){
DummyClasses[i] = dmap[d];
} else {
dmap[d] = d;
}
}
DummyClasses[0].Text = "All items same";
}
// helper function, for inspector contextmenu, to add more classes from Editor
[ContextMenu ("AddDummy")]
void AddDummy(){
if(DummyClasses.Count==0)DummyClasses.Add(new DummyClass{UniqueID = 1});
else {
// Every item after 0 points to zero, serialization will remove refs during deep copy.
DummyClasses.Add(DummyClasses[0]);
}
UnityEditor.EditorUtility.SetDirty(this);
}
}