Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
  • Help Room /
avatar image
0
Question by Cheo · Nov 28, 2015 at 06:32 PM · c#animationstate-machineswitch scenesnext level

Use a string to call a class

Hi

I have several classes for each different level of the game. I'm using a state machine approach and when winning or losing a level, a intermediate state is loaded. I'd like to call previous level or next level class by a string, so I don't need to create a intermediate state for each level.

The name space is Code.States and the classes for each level are named PlayStateLevel1, PlayStateLevel2, etc.

This is my approach:

 public WinLoseState (StateManager managerRef)
 {
       .
       .
       string currentLevel = "PlayStateLevel" + CalculateLevelNumber ();
       Type type = Type.GetType(string.Format("Code.States.{0}", currentLevel));
       System.Object obj = System.Activator.CreateInstance(type);
 }

Then, the idea is to use the obj reference to restart level or go to next level:

 if (win)  
 {
      .
      .
      manager.SwitchState (new obj (manager));
 }

So, instead of using:

 manager.SwitchState (new PlayStateLevel2 (manager));

I want to use:

 manager.SwitchState (new obj (manager));

But it's giving me a long error:

MissingMethodException: Method not found: 'Default constructor not found...ctor() of Code.States.PlayStateLevel1'.

System.Activator.CreateInstance (System.Type type, Boolean nonPublic) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System/Activator.cs:368)

System.Activator.CreateInstance (System.Type type) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System/Activator.cs:254)

Code.States.WinLoseStateLevel1..ctor (.StateManager managerRef) (at Assets/Code/States/WinLoseStateLevel1.cs:22)

Code.States.PlayStateLevel1.StateUpdate () (at Assets/Code/States/PlayStateLevel1.cs:34) StateManager.Update () (at Assets/Code/Scripts/StateManager.cs:37)

I've tried several different combinations, but neither seems to work. I've followed some instructions, like here: http://forums.asp.net/t/1904441.aspx?Possible+Use+a+string+variable+to+call+a+class+in+C+

Any idea on how to approach this?

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
0

Answer by pekalicious · Nov 28, 2015 at 11:18 PM

There are several issues with your code. Reflection is kinda tricky, so I'll suggest you make some changes in your code for convenience.

First, you cannot call new on an object (a class that has instantiated). You can only do that with a class. Luckily, Activator.CreateInstance already does that for you (takes the type of a class and calls new and then returns the instantiated object).

However, your PlayStateLevel class has a constructor with a parameter. Now, there is a way to call it by passing your variable, but to make things easy, I suggest you have a constructor with no parameters and simply expose the manager variable so you can set it later.

Finally, you'll need to cast (explicitly tell C# what type the object is) so you can pass it to your method.

By the way, I assume that all PlayStateLevel class have a base class called PlayStateLevel. If not, I highly recommend you do.

Thus, you will end up with the following:

 public WinLoseState (StateManager managerRef)
 {
       .
       .
       string currentLevel = "PlayStateLevel" + CalculateLevelNumber ();
       Type type = Type.GetType(string.Format("Code.States.{0}", currentLevel));
       PlayStateLevel pLevel = (PlayStateLevel)System.Activator.CreateInstance(type);
       pLevel.manager = manager;
 }

and

 manager.SwitchState (pLevel);
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by Cheo · Nov 29, 2015 at 01:15 PM

Hi pekalicious

Thanks for your reply and suggestions. I still have the same system error as before. The lines triggering the error are these, both for my previous script and your script:

My line:

 System.Object obj = System.Activator.CreateInstance(type);

Your line:

 PlayStateLevel pLevel = (PlayStateLevel)System.Activator.CreateInstance(type);

I'm not using a PlayStateLevel base class as you mentioned. These are the classes involved so you can have a bigger picture of the design. I'm only including the relevant snippets for each class:

IStateBase class:

 namespace Code.Interfaces
 {
     public interface IStateBase
     {
     }
 }

StateManager class:

 using UnityEngine;
 using Code.States;
 using Code.Interfaces;
 
 public class StateManager : MonoBehaviour {
 
     private IStateBase activeState;
 
     public void SwitchState(IStateBase newState)
     {
         activeState = newState;
     }    
 }

PlayStateLevel1 class:

 using UnityEngine;
 using Code.Interfaces;
 
 namespace Code.States
 {
     public class PlayStateLevel1 : IStateBase
     {
         private StateManager manager;
 
         public PlayStateLevel1 (StateManager managerRef)
         {
             manager = managerRef;
             Application.LoadLevel("Level1");
         }
 
         public void StateUpdate()
         {
             if ( manager.statTracker.GetLifePoints() <= 0) {
                 manager.SwitchState (new WinLoseStateLevel1 (manager));
             }            
         }        
     }
 }

WinLoseStateLevel1 class:

 using UnityEngine;
 using Code.Interfaces;
 
 namespace Code.States
 {
     public class WinLoseStateLevel1 : IStateBase
     {
         private StateManager manager;
         
         public WinLoseStateLevel1 (StateManager managerRef)
         {
             manager = managerRef;
             
             /*** THIS IS THE CODE I ORIGINALLY ADDED BUT GIVES AN ERROR ***/
             Type type = Type.GetType(string.Format("Code.States.{0}", currentLevel));
             System.Object obj = System.Activator.CreateInstance(type)
             /**************************************************************/        
         }
         
         public void ShowIt()
         {                
             if (GUI.Button (new Rect (10, 10, 150, 100), stringNextLevel)) 
             {
                 manager.SwitchState (new PlayStateLevel2 (manager));
             }                
                 
             if (GUI.Button (new Rect (10, 110, 150, 100), stringPlayLevelAgain)) {
                 manager.SwitchState (new PlayStateLevel1 (manager));                    
             }            
         }
     }
 }

As you can see, the idea is to use a string for:

 manager.SwitchState(new STRING (manager));

Any suggestion?

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image pekalicious · Nov 29, 2015 at 04:38 PM 0
Share

So the problem is that your 'SwitchState', method expects an object of type IStateBase, which means that some way or another, you need to pass an object of that type.

Don't get me wrong, this is correct design. You should not change that method to expect an object of type 'object'. However, you still need to figure out how to get a IStateBase given a string.

The reason my code fails is because you don't have a PlayStateLevel base class. But since you only care about IStateBase, you can also do this:

 IStateBase pLevel = (IStateBase)System.Activator.CreateInstance(type);

And to be completely correct, since your constructor needs a manager, you will call this:

 IStateBase pLevel = (IStateBase)System.Activator.CreateInstance(type, manager);

Remember, this will ONLY work if the 'type' is a class that is a subtype of 'IStateBase' AND has a constructor that expects a 'State$$anonymous$$anager'.

avatar image Cheo · Dec 01, 2015 at 06:43 PM 0
Share

Hi, thanks for your reply and sorry for the late response, but I've spent the last days trying code lines you suggested but I was not able to make it work. I got a bunch of errors.

First error I encounter is: "

$$anonymous$$issing$$anonymous$$ethodException: $$anonymous$$ethod not found: 'Default constructor not found...ctor() of Code.States.PlayStateLevel1'

" So, to fix it, I create a default constructor for PlayStateLevel1.

When I fixed the first error, a second error occurs: "

NullReferenceException: Object reference not set to an instance of an object

" The error refers to the methods StateUpdate() and ShowIt() in PlayStateLevel1 class, which are referenced in the State$$anonymous$$anager class as follows:

 void Update () 
 {
     if (activeState != null)
     activeState.StateUpdate ();
 }
 
 void OnGUI()
 {
     if (activeState != null)
     activeState.ShowIt ();
 }

If I comment both methods StateUpdate() and ShowIt() in PlayStateLevel1 class in order to prevent the compiler from computing them, the running game gives no error, but when I click on the button to restart the level, the GUI disappears but nothing else happen, no restart, nothing.

A Debug.log of pLevel variable yields '

Code.States.PlayStateLevel1

'

Any new idea welcomed!!

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

49 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

how to smoothly transition between animations in the "Any State" state machine. 1 Answer

Free Look Camera Rig Changing Rotation 1 Answer

Starting an Animation from an Instantiated Object 0 Answers

How to make orb walking? 0 Answers

Click on object and play animation\sound C# script 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges