Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 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 /
avatar image
1
Question by Mark Simpson · Nov 01, 2010 at 04:44 PM · editor-scriptingmenu-item

Programmatically playing a scene for a single frame

Update:

I gave up and changed tack; I now run our .cs files through the mono compiler as outlined in this post (thanks to Lucas for that). This allows us to use NUnit as with normal .NET development. The only difference is that we can't test classes that derive from MonoBehaviour, but that's something we can live with.

Original Post:

Context: I'm trying to create a "run tests" menu item which does the following:

  • Creates a new scene
  • Creates a new game object & test component
  • Run a single frame using the new scene (which will run the tests in the script's Start method via SharpUnit)
  • After the frame has completed, discard the generated scene and reload the user's original scene.

Here's a quick stab at the code:

public static class RunUnitTestsMenuItem { [MenuItem("Testing/Run Tests")] public static void RunUnitTests() { //string previousScene = EditorApplication.currentScene; EditorApplication.isPlaying = true; EditorApplication.NewScene(); var gameObject = new GameObject("UnitTestObject"); gameObject.AddComponent<Unity3D_TestRunner>();

     // If I leave the script as is, it will run the tests as expected, 
     // but the editor will be playing until the user clicks stop
     // plus it will require the user to manually discard the test 
     // scene and then reload their original scene ... too much friction.

     //EditorApplication.OpenScene(previousScene);
 }

}

If I attempt to reload the original scene after the test run (see commented out code), my script won't report any test results -- the script's Start method won't get called (verified via adding a Debug.Log line -- nothing is printed). If I remove the scene reloading code, the tests are run correctly and I get the result output in the console, but it means the user has to re-select their original scene and choose not to save the temporary test scene. I'm used to running tests via ReSharper & NUnit, so I'd like to minimise as much friction as possible.

Does anyone have any ideas about how to make the editor ensure that a single frame is completed in its entirety prior to reloading the original scene? I've tried setting EditorApplication.isPaused to true and then using EditorApplication.Step(), but that approach had the same problem.

Any help gratefully appreciated, cheers!

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 Tom 17 · May 25, 2011 at 09:10 AM

Full batch-mode-safe solution to be found here: Answer to Continuous Integration with Unity?

EDIT2: I'm afraid it is next to impossible to give a full solution to the problem. I do manage to get a signal when one frame was processed, but I can neither block on the main thread (in Update() or OnGUI() of the editor window script) nor can I access EditorApplication from a seperate thread.

EDIT: The following works OK, but I get three Update() runs reported befor the game is really stopped

On a sidenode, I use SharpUnit as testframework, it works with MonoBehaviour-derived classes.

This is the code for the signalling script using UnityEngine; using System.Collections; using System.Threading;

public class OneFrameSignaller : MonoBehaviour { public static volatile bool startGame = false; public static volatile bool stopGame = false;

 void Start()
 {
     StartCoroutine(SignalOneFrame());
 }

 IEnumerator SignalOneFrame()
 {
     yield return new WaitForEndOfFrame();
     stopGame = true;
 }

}


This is the code of the editor script I use for triggering the magic and doing the tests.

using UnityEditor; using UnityEngine;

public class InEditorTestsWindow : EditorWindow { [MenuItem("Tests/run tests")] public static void ShowWindow () { EditorWindow.GetWindow (typeof(InEditorTestsWindow)); }

 public void OnGUI ()
 {       
     if (GUILayout.Button ("play and step once"))
     {
         OneFrameSignaller.startGame = true;
     }
 }
 
 void Update()
 {
     if (OneFrameSignaller.startGame)
     {
         OneFrameSignaller.startGame = false;
         EditorApplication.NewScene();
         GameObject testObject        = GameObject.CreatePrimitive(PrimitiveType.Cube);
         UnityCSharpScript testScript = testObject.AddComponent<UnityCSharpScript>();
         OneFrameSignaller signaller  = testObject.AddComponent<OneFrameSignaller>();

         EditorApplication.isPlaying = true;
     }
     
     if (OneFrameSignaller.stopGame)
     {
         OneFrameSignaller.stopGame  = false;
         EditorApplication.isPaused  = true;
         // do tests/assertions here with the testScript
         EditorApplication.isPlaying = false;
         EditorApplication.isPaused  = false;                
     }
 }    

}

Original post:

This is barely an answer as I did not make it work, yet. However this might help to further the effort: I assume the key to allowing exactly n frames to run is to use WaitForEndOfFrame in a coroutine. This only works for MonoBehaviour-derived classes and not within an editor script. Thus what I do is to have one special script that I add to the scene. At the start it fires up a coroutine that does wait for the end of the frame. When this has happened the waiting thread that ran the editor script gets signalled about the end of the frame and it can thus stop the game. The problem is to get the signalling right. I tried to share an AutoResetEvent, but didn't get that to work (yet). I also tried to start a thread within the editor script, but I can't access EditorApplication from that thread. The research goes on.

Comment
Add comment · Show 1 · 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 Tom 17 · May 25, 2011 at 11:42 AM 0
Share

For some reason I don't get the formatting right for the first code snippet, sorry for that.

avatar image
0

Answer by Tom 17 · Jun 03, 2011 at 08:26 AM

I write this answer as an update because I can give you a quite short and simple solution now.

With all my experiementing on using the play mode in batch mode I made the following observation:

  • starting the play mode resets most variables, therefor you need to serialize the information you need to controll the test simulation and deserialize it after the play mode actuall startet

  • EditorApplication.update delegate is called after each frame during batch mode, you just need to set it after the play mode actually startet.

I have a test-governing script, which I add to each test scene, that does just that in its Start method.

The only drawback is that you can don't get a delegate invocation on the very first frame. I'll assume you write your games in a way that involves more than one frame, so maybe you can live with it.

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

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

1 Person is following this question.

avatar image

Related Questions

Can I make the name of a custom Menu Item context-sensitive, or show/hide it dynamically? 1 Answer

Browse button in unity editor script 0 Answers

Find public assigned values using editor script 1 Answer

How can I preserve static object/data between editor and play? 2 Answers

How to resize editor that is inside of a window? 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