Argument exception when I try to set a variable with a custom set in unity - unity3d

I tried to use the Generate() function only if a variable has changed without having to check it every frame. I used the following tutorial to achieve this. but for some reason, whenever i try to set the variable, I get this error:
ArgumentException: GetComponent requires that the requested component 'List`1' derives from MonoBehaviour or Component or is an interface.
the script:
public GameObject CEMM;
private int ListLength;
public static int ListLengthProperty
{
get
{
return JLSV.instance.ListLength;
}
set
{
JLSV.instance.ListLength = value;
JLSV.instance.Generate();
}
}
private void Awake()
{
instance = this;
}
I tried to set the value like this: JLScrollView.ListLengthProperty = JLScrollView.instance.CEMM.GetComponent<List<JLClass>>().Count;

The generic type parameter that you use when calling GetComponent must be a class that derives from Component (or an interface type). List is a plain old class object, which is why you are getting the exception from this:
GetComponent<List<JLClass>>()
I'm not really sure what value you are trying to assign to the property. If you are trying to get the number of components of a certain type on the GameObject you can use GetComponents.
JLScrollView.ListLengthProperty = JLScrollView.instance.GetComponents<JLClass>().Length;

Related

Does formsflow support setting user task extension value as a variable?

Instead of hardcoding the value of formName in the task extension property of modeler, I need to place the formName value as a variable(e.g., ${formname}).
This is implemented in one of our listeners i.e; FormConnectorListener to get the extension property value in dynamic. Please refer https://github.com/AOT-Technologies/forms-flow-ai/blob/master/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/hooks/listeners/task/FormConnectorListener.java
You can add a java listener that should implement org.camunda.bpm.engine.delegate.JavaDelegate and can access the extension property with the general xml api.
public void execute(DelegateExecution execution) throws Exception {
CamundaProperties camundaProperties = execution.getBpmnModelElementInstance().getExtensionElements().getElementsQuery()
.filterByType(CamundaProperties.class).singleResult();
Collection<CamundaProperty> properties = camundaProperties.getCamundaProperties();
for (CamundaProperty property : properties) {
System.out.println(property.getCamundaValue());
}
}
In the above overriden method you can get the variable by using:
execution.getVariable(StringUtils.substringBetween(property.getCamundaValue(), "${", "}"));

Why i need to declare a variable that have the same name of class and script?

public class CanvasManager : MonoBehaviour
{
public static CanvasManager Instance; // = lobby
[SerializeField]
private LobbyFunction _lobbyFunction;
public LobbyFunction LobbyFunction
{
get { return _lobbyFunction; }
}
...
below is one of the reference
private void Start()
{
GameObject lobbyCanvasGO = CanvasManager.Instance.LobbyFunction.gameObject;
...
I am confused that is it necessary to have the same name of canvasmanager that it is declared , and why there is no error when I sayCanvasManager.Instance.LobbyFunction ,it made me confused since LobbyFunction is belonged to CanvasManager, not Instance.
Finally , sometimes ,
private LobbyFunction _lobbyFunction;
private LobbyFunction LobbyFunction
{
get { return _lobbyFunction; }
}
Sometimes,
private LobbyFunction _lobbyFunction;
public LobbyFunction LobbyFunction
{
get { return _lobbyFunction; }
}
Thanks for your patience reading this, and your help would be greatly appreciated, thanks!
Your class is named CanvasManager, but you cannot statically access it right away.
You created a static member variable in CanvasManager, which holds a reference to a CanvasManager. This is called the singleton pattern.
You can only access static members without a class instance. But in the case of singletons, you create a single instance of the class (usually assigned in Start() or in getInstance() (lazy) after checking if it exists) which you can then access statically through "Instance".
Now, Instance is a static variable holding a reference to a single instance of CanvasManager. So, you can then access non-static members and functions of CanvasManager, if you access "Instance".
Think about it like this:
CanvasManager local_instance = new CanvasManager();
local_instance.non_static_member = value; // this works
CanvasManager.static_member = value; // this works
CanvasManager.non_static_member = value; // won't work.
And now one step further, you access the instance via CanvasManager.Instance.*
CanvasManager.Instance.non_static_member = value; // works!
Explanation of static vs non-static:
normal variables:
Variables needs memory. So usually you create 5 instances of CanvasManager and each instance can have different values. Because each instance reserves memory for each Variable. But if you want to change one, you need to explicitly talk to that instance. You could manage them in a List or by having multiple variables in Code like manager1, manager2...
Think of it as books, where each copy can be modified (write notes into it)
static variables
If you create a static variable, the memory is reserved once for the Class. You can then directly get/set this static variable from anywhere in Code without the need of a Reference to an instance.
Think of it as an online blog, where changes are applied for everyone, being accessible from everywhere. The text exists once in the blog database.
Singletons:
If you only want a single CanvasManager and not 5, you could attach it to any GameObject and access it. But every other script needs a reference, like public CanvasManager my_manager which you need to assign in inspector. As an alterantive, you could use
GameObject.Find("CanvasManagerObject").getComponent<CanvasManager>()
in each script... If only there was a better way to access this CanvasManager from everywhere...
The singleton pattern allows you to get a reference to a single, nonstatic instance of the CanvasManager, while it doesn't even need a GameObject it can attach to.
Naming
You are talking about "it has to have the same name" - this is not true. You can name the instance whatever you like. CanvasManager.MyCustomlyNamedInstance would work too. But the MyCustomlyNamedInstance must be a static variable in the CanvasManager class, or any other class. You could have a GameManager that manages your instances, so GameManager.MyCanvasManagerInstance would work too.

Adding Coroutine functions to Transform

I'm creating a script in unity extending Transform
using UnityEngine;
using System.Collections;
using UnityEditor;
public static class TransformExtension
{
//lots of functions
public static IEnumerator tester(this Transform test)
{
Debug.Log("hello");
yield return null;
}
public static void tester2(this Transform test)
{
Debug.Log("hello2");
}
}
when I invoke
transform.tester();
transform.tester2();
only "hello2" is logged.
when I tried
StartCoroutine(transform.tester());
i got the following errors:
"error CS0103: The name 'tester' does not exist in the current context"
"Transform' does not contain a definition for 'StartCoroutine' and no accessible extension method 'StartCoroutine' accepting a first argument of type 'Transform' could be found (are you missing a using directive or an assembly reference?)
when I tried
transform.StartCoroutine(transform.tester());
I got:
"error CS1061: 'Transform' does not contain a definition for 'StartCoroutine' and no accessible extension method 'StartCoroutine' accepting a first argument of type 'Transform' could be found (are you missing a using directive or an assembly reference?)"
You can not call a Coroutine like a method you rather have to start it via StartCoroutine(). When you call it like a normal method it will simply be ignored (as you already noticed).
You can't use transform.StartCoroutine() since Transform is of type Component and does not inherit from MonoBehaviour.
But StartCoroutine() can only be used on a MonoBehaviour.
So assuming you are already calling it from within a MonoBehaviour due to the usage of transform instead simply do
StartCoroutine(transform.tester());
which works completely fine for me as long as called from within a MonoBehaviour or alternatively
anyGameObject.GetComponent<MonoBehaviour>().StartCoroutine(transform.tester());
That other MonoBehaviour which will be running the Coroutine doesn't even have to be on the same object but you have to be sure there is any other MonoBehaviour script attached to anyGameObject.
You can not start coroutines like function calls Add a function which starts coroutine. Also since derHugo pointed out you need Monobehavior to achieve this you can access MonoBehavior over your transform like this:
public static IEnumerator Tester()
{
Debug.Log("hello");
yield return null;
}
public static void StartTester(this Transform test)
{
test.GetComponent<MonoBehaviour>().StartCoroutine(Tester());
}
public static void tester2(this Transform test)
{
Debug.Log("hello2");
}
Then do this:
transform.startTester();

Serialization of a list of custom objects in unity

While trying to make a script for building assets, I ran into an issue with unity's serialization. I have a class in which I store some arbitrary information, which is then stored in an array in a MonoBehaviour on a prefab. I cannot for the life of me get the array to save however, as when I make the object into a prefab it loses the list's values. I have tried using [System.Serializable] and ScriptableObject, but both seem to pose their own new issues.
For instance, using ScriptableObject would mean having to save the data objects as assets, which would become way too much since these objects can get to hundreds in number.
Am I making a mistake in my understanding of unity's serialization? Is there a way to get this working without the ScriptableObject approach of saving every ArbitraryInfo object in an asset?
Data object:
[System.Serializable]
public class ArbitraryInfo{
public int intValue;
public Vector3 vectorValue;
}
OR
public class ArbitraryInfo : ScriptableObject {
public int intValue;
public Vector3 vectorValue;
void OnEnable() {
hideflags = HideFlags.HideAndDontSave;
}
}
Behaviour:
public class MyBuilder : MonoBehaviour {
public ArbitraryInfo[] infoArray;
}
Editor:
[CustomEditor(typeof(MyBuilder))]
public class MyBuilderEditor : Editor {
private SerializedProperty infoArrayProperty;
void OnLoad() {
infoArrayProperty = serializedObject.FindProperty("infoArray");
}
void OnInspectorGUI() {
serializedObject.Update();
for (var i = 0; i < infoArrayProperty.arraySize; i++) {
if (i > 0) EditorGUILayout.Space();
var info = infoArrayProperty.GetArrayElementAtIndex(i).objectReferenceValue as ArbitraryInfo;
EditorGUILayout.LabelField("Info " + i, EditorStyles.boldLabel);
info.intValue = EditorGUILayout.IntField(info.intValue);
info.vectorValue = EditorGUILayout.Vector3Field(info.vectorValue);
}
serializedObject.ApplyModifiedProperties();
}
}
EDIT 1, Thank you derHugo
I changed my code to incorporate the changes. Now there are errors for ArbitraryInfo not being a supported pptr value.
Secondly, ArbitraryInfo no longer being a ScriptableObject poses the question of how to initialize it. An empty object can be added to infoArrayProperty through infoArrayProperty.arraySize++, but this new empty object seems to be null in my case. This might be due to the pptr issue mentioned above.
EDIT 2
The issue I was having was caused by another piece of code where I tried to check if infoArrayProperty.objectReferenceValue == null. I changed this to another check that did the same thing and everything worked!
No, no ScriptableObject needed.
But note that GetArrayElementAtIndex(i) returns a SerializedProperty. You can not simply parse it to your target class.
so instead of
var info = infoArrayProperty.GetArrayElementAtIndex(i).objectReferenceValue as ArbitraryInfo;
and
info.intValue = EditorGUILayout.IntField(info.intValue);
info.vectorValue = EditorGUILayout.Vector3Field(info.vectorValue);
you have to get the info's SerializedPropertys by using FindPropertyRelative:
var info = infoArrayProperty.GetArrayElementAtIndex(i);
var intValue = info.FindPropertyRelative("intValue");
var vectorValue = info.FindPropertyRelative("vectorValue");
than you can/should use PropertyFields
EditorGUILayout.PropertyField(intValue);
EditorGUILayout.PropertyField(vectorValue);
allways try to avoid using direct setters and use those SerializedProperties instead! This provides you with Undo/Redo functionality and marking the changed Behaviour/Scene as unsaved automatically. Otherwise you would have to tak care of that manually (... don't ^^).

Check if spawn is empty

I have two spawn spots where a player will show up upon connection.
I need that, when one of the players connects on one of the spots, any other player will always spawn at the other spot.
Here's some visual in case it helps: https://goo.gl/Y0ohZC
Here is the code I'm using:
using UnityEngine;
using System.Collections;
public class SpawnSpot : MonoBehaviour {
public int teamId=0;
public GameObject[] Spots; //Drag the spots in here (In the editor)
bool[] OccupiedSpawnSpots;
//Using Photon Networking
void OnJoinedRoom()
{
//Request the recent OccupiedSpawnSpots List
PhotonView.RPC("RequestList", PhotonTargets.MasterClient, PhotonNetwork.player);
}
//In "RequestList" the MasterClient sends his List of the SpawnSpots
//by calling "ReceiveList"
[RPC]
void RequestList(PhotonPlayer player)
{
PhotonView.RPC("ReceiveList", PhotonTargets.All, player, OccupiedSpawnSpots);
}
[RPC]
void ReceiveList(PhotonPlayer Sender, bool[] ListOfMasterClient)
{
OccupiedSpawnSpots = ListOfMasterClient;
//Get the free one
if (OccupiedSpawnSpots[0] == false)
{
//Spawn player at 0
if (Sender == PhotonNetwork.player)
PhotonNetwork.Instantiate("PlayerController", Spots[0].transform.position);
OccupiedSpawnSpots[0] = true;
}
else
{
//Spawn player at 1
if (Sender == PhotonNetwork.player)
PhotonNetwork.Instantiate("PlayerController", Spots[1].transform.position);
OccupiedSpawnSpots[1] = true;
}
}
The errors given are:
Assets/Scripts/SpawnSpot.cs(14,28): error CS0120: An object reference
is required to access non-static member `PhotonView.RPC(string,
PhotonPlayer, params object[])'
Assets/Scripts/SpawnSpot.cs(22,28): error CS0120: An object reference
is required to access non-static member `PhotonView.RPC(string,
PhotonPlayer, params object[])'
Assets/Scripts/SpawnSpot.cs(36,47): error CS1501: No overload for
method Instantiate' takes3' arguments
Assets/Scripts/SpawnSpot.cs(43,47): error CS1501: No overload for
method Instantiate' takes3' arguments
Thanks in advance, IC
It appears that you are trying to call an instance function using a static reference. instead of doing PhotonView.RPC("RequestList", PhotonTargets.MasterClient, PhotonNetwork.player);
you need to create a reference to an PhatorView object, and then call the RPC function on it.
public PhotonView photonView;
void OnJoinedRoom()
{
if(photonView == null)
{
photonView = GetComponent<PhotonView>();
}
//Request the recent OccupiedSpawnSpots List
PhotonView.RPC("RequestList", PhotonTargets.MasterClient, PhotonNetwork.player);
}
you should have a PhotonView object on the same GameObject that this script is on, or assign a reference to a PhotonView in the editor.
That should fix your problems, but I think you should look into compiler errors and how to to fix them. In Unity3D if you double click the error in the console it will take you to the line that isn't compiling. It also tends to give you a pretty good hint as to why it isn't compiling.
your error was this
"Assets/Scripts/SpawnSpot.cs(14,28): error CS0120: An object reference is required to access non-static member `PhotonView.RPC(string, PhotonPlayer, params object[])'"
which means that you need an object in order to call this function.
The third and fourth errors are because you are calling Instantiate with only 2 arguments, but it takes at least 4. Include the rotation of the GameObject you're trying to instantiate, and a group number:
PhotonNetwork.Instantiate("PlayerController", Spots[0].transform.position, Quaternion.identity, 0);
Note that you may not want the identity quaternion, so you may need to change this. Also I'm not familiar with PhotonNetwork so 0 may not be an advisable group.