C# Unity 4.6编辑器,使用预定义数据创建脚本
我试图在Unity编辑器中创建一个易于使用的按钮,用于创建角色和项目 我会在这里提供一些额外的信息来帮助解释我的问题。 我的游戏结构是这样的; 游戏控制器>>角色脚本>>(玩家名称)脚本 角色对象上有角色脚本和以其命名的脚本 我希望能够在Unity编辑器中单击“创建新角色”,并执行以下操作; 1) 提示输入要使用的名称。 2) 根据用户键入的内容创建名为Name的空游戏对象。 3) 创建一个名为same的新C#脚本,并将其添加到对象中。 -我希望生成的脚本中有一些预先确定的“字符模板”代码。 4) 将新脚本附加到新的空游戏对象,并将“角色脚本”附加到该对象 提前谢谢 最后一个子问题。 通过角色脚本上的公共MonoBehavior从GameController访问PlayerNameScript是否更好 或者CharacterScript可以动态扩展PlayerNamedScript,sibling 我希望这是清楚的。再次感谢。试试这个 将字符creatoreditor.cs放入项目中名为编辑器的文件夹中 CharacterCreatorEditor.csC# Unity 4.6编辑器,使用预定义数据创建脚本,c#,unity3d,unity3d-editor,C#,Unity3d,Unity3d Editor,我试图在Unity编辑器中创建一个易于使用的按钮,用于创建角色和项目 我会在这里提供一些额外的信息来帮助解释我的问题。 我的游戏结构是这样的; 游戏控制器>>角色脚本>>(玩家名称)脚本 角色对象上有角色脚本和以其命名的脚本 我希望能够在Unity编辑器中单击“创建新角色”,并执行以下操作; 1) 提示输入要使用的名称。 2) 根据用户键入的内容创建名为Name的空游戏对象。 3) 创建一个名为same的新C#脚本,并将其添加到对象中。 -我希望生成的脚本中有一些预先确定的“字符模板”代码。 4
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.IO;
using System.Text.RegularExpressions;
public class CharacterCreatorEditor : EditorWindow {
#region Character Fields
//Add as many character specific fields / variables you want here.
//Remember to update the same thing in the "CharacterTemplate.txt"!
public string characterName = "John Doe";
public float characterHealth = 10;
public int characterCost = 1000;
public bool isBadGuy = false;
#endregion
private bool needToAttach = false; //A boolean that checks whether a newly created script has to be attached
private float waitForCompile = 1; //Counter for compile
GameObject tempCharacter; //A temporary GameObject that we assign the new chracter to.
//A Menu Item when clicked will bring up the Editor Window
[MenuItem ("AxS/Create New Character")]
public static void CreateNewChar () {
EditorWindow.GetWindow(typeof(CharacterCreatorEditor));
}
void OnGUI () {
GUILayout.Label("Here's a sample Editor Window. Put in more variables as you need below.");
GUILayout.Space(10);
//Note on adding more fields
//The code below is broken into groups, one group per variable
//While it's relatively long, it keeps the Editor Window clean
//Most of the code should be fairly obvious
GUILayout.BeginHorizontal();
GUILayout.Label("Character Name", new GUILayoutOption[0]);
characterName = EditorGUILayout.TextField(characterName, new GUILayoutOption[0]);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.BeginHorizontal();
GUILayout.Label("Character Health", new GUILayoutOption[0]);
characterHealth = EditorGUILayout.FloatField(characterHealth, new GUILayoutOption[0]);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.BeginHorizontal();
GUILayout.Label("Character Cost", new GUILayoutOption[0]);
characterCost = EditorGUILayout.IntField(characterCost, new GUILayoutOption[0]);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.BeginHorizontal();
GUILayout.Label(string.Format("Is {0} a Bad Guy?", new object[] { characterName }), new GUILayoutOption[0]);
isBadGuy = EditorGUILayout.Toggle(isBadGuy, new GUILayoutOption[0]);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUI.color = Color.green;
//If we click on the "Done!" button, let's create a new character
if(GUILayout.Button("Done!", new GUILayoutOption[0]))
CreateANewCharacter();
}
void Update () {
//We created a new script below (See the last few lines of CreateANewCharacter() )
if(needToAttach) {
//Some counter we just keep reducing, so we can give the
//EditorApplication.isCompiling to kick in
waitForCompile -= 0.01f;
//So a few frames later, we can assume that the Editor has enough
//time to "catch up" and EditorApplication.isCompiling will now be true
//so, we wait for the newly created script to compile
if(waitForCompile <= 0) {
//The newly created script is done compiling
if(!EditorApplication.isCompiling) {
//Lets add the script
//Here we add the script using the name as a string rather than
//it's type in Angled braces (As done below)
tempCharacter.AddComponent(characterName.Replace(" ", ""));
//Reset the control variables for attaching these scripts.
needToAttach = false;
waitForCompile = 1;
}
}
}
}
private void CreateANewCharacter () {
//Instantiate a new GameObject
tempCharacter = new GameObject();
//Name it the same as the Character Name
tempCharacter.name = characterName;
//Add the ChracterScript component. Note the use of angle braces over quotes
tempCharacter.AddComponent<CharacterScript>();
//Loading the template text file which has some code already in it.
//Note that the text file is stored in the path PROJECT_NAME/Assets/CharacterTemplate.txt
TextAsset templateTextFile = AssetDatabase.LoadAssetAtPath("Assets/CharacterTemplate.txt",
typeof(TextAsset)) as TextAsset;
string contents = "";
//If the text file is available, lets get the text in it
//And start replacing the place holder data in it with the
//options we created in the editor window
if(templateTextFile != null) {
contents = templateTextFile.text;
contents = contents.Replace("CHARACTERCLASS_NAME_HERE", characterName.Replace(" ", ""));
contents = contents.Replace("CHARACTER_NAME_HERE", characterName);
contents = contents.Replace("CHARACTER_HEALTH_HERE", characterHealth.ToString());
contents = contents.Replace("CHARACTER_COST_HERE", characterCost.ToString());
contents = contents.Replace("CHARACTER_BAD_GUY_HERE", isBadGuy.ToString().ToLower());
}
else {
Debug.LogError("Can't find the CharacterTemplate.txt file! Is it at the path YOUR_PROJECT/Assets/CharacterTemplate.txt?");
}
//Let's create a new Script named "CHARACTERNAME.cs"
using(StreamWriter sw = new StreamWriter(string.Format(Application.dataPath + "/{0}.cs",
new object[] { characterName.Replace(" ", "") }))) {
sw.Write(contents);
}
//Refresh the Asset Database
AssetDatabase.Refresh();
//Now we need to attach the newly created script
//We can use EditorApplication.isCompiling, but it doesn't seem to kick in
//after a few frames after creating the script. So, I've created a roundabout way
//to do so. Please see the Update function
needToAttach = true;
}
}
守则的解释 首先,编辑器脚本接受所有输入变量(应该非常清楚它们是什么) 单击“完成”按钮后,将发生以下情况
对于第二个问题,您需要做的是让所有PlayerNamed类扩展相同的基类。这样,您可以键入要在CharacterScript中公开的变量 例如,如果调用基类“NamedCharacterScripts” 在JohnDoe.cs中
public class JohnDoe : NamedCharacterScripts
public class JaneDoe : NamedCharacterScripts
public NamedCharacterScripts namedCharacterScript;
void Awake () {
//This will assign JohnDoe.cs for the GameObject named "John Doe" &
//JaneDoe.cs to the GameObject named "Jane Doe"
namedCharacterScript = GetComponent<NamedCharacterScripts>();
}
在JaneDoe.cs中
public class JohnDoe : NamedCharacterScripts
public class JaneDoe : NamedCharacterScripts
public NamedCharacterScripts namedCharacterScript;
void Awake () {
//This will assign JohnDoe.cs for the GameObject named "John Doe" &
//JaneDoe.cs to the GameObject named "Jane Doe"
namedCharacterScript = GetComponent<NamedCharacterScripts>();
}
在CharacterScript.cs中
public class JohnDoe : NamedCharacterScripts
public class JaneDoe : NamedCharacterScripts
public NamedCharacterScripts namedCharacterScript;
void Awake () {
//This will assign JohnDoe.cs for the GameObject named "John Doe" &
//JaneDoe.cs to the GameObject named "Jane Doe"
namedCharacterScript = GetComponent<NamedCharacterScripts>();
}
public NamedCharacterScripts namedCharacterScript;
无效唤醒(){
//这将为名为“John Doe”的游戏对象分配JohnDoe.cs&
//JaneDoe.cs到名为“Jane Doe”的游戏对象
namedCharacterScript=GetComponent();
}
希望这能回答你的问题。如果您有问题,只需留下评论我的脚本不像文卡特的回答那样可以制作,但出于教育目的,应该更容易理解
使用UnityEngine;
使用系统集合;
使用UnityEditor;
使用System.IO;
[执行编辑模式]
公共类角色工具:MonoBehavior
{
[序列化字段,隐藏索引]
私有字符串类名;
private bool waitForCompile=false;
私有void更新()
{
if(string.IsNullOrEmpty(className))
返回;
if(waitForCompile&&EditorApplication.isCompiling)
waitForCompile=false;
如果(!waitForCompile&&!EditorApplication.iscompile)
{
var gameObject=新游戏对象(类名);
Log(“正在尝试添加”+className);
var c=gameObject.AddComponent(类名);
className=null;
}
}
[上下文菜单(“创建字符”)]
私有void CreateCharacter()
{
string name=“Number”+Random.Range(01100).ToString();
字符串nameTemplate=“{0}字符”;
使用UnityEngine的字符串contentTemplate=@;
公共类{0}:单行为
{{
}}
";
var className=string.Format(nameTemplate,name);
var path=Application.dataPath+“/”+className+“.cs”;
var scriptFile=新StreamWriter(路径);
Write(string.Format(contentTemplate,className));
scriptFile.Close();
AssetDatabase.ImportAsset(路径,ImportAssetOptions.ForceSynchronousImport);
AssetDatabase.Refresh();
this.className=className;
this.waitForCompile=true;
}
}
用法:
可能会有帮助:有任何答案有用吗?这是一个很好的解决方案,我为简化而做的一个小改动是去掉waitForCompile变量:
private void Update(){if(EditorApplication.isCompiling){return;}if(needToAttach){//Do attach stuff here…needToAttach=false;}}
@Tim。我之所以添加它,是因为我注意到EditorApplication.isCompiling有时需要一段时间才能返回正确的值(在本例中为true)。这是一个丑陋的攻击,但它确保没有任何空引用充斥您的控制台。