Dans Unity à la fois dans l'éditeur et au moment de l'exécution Je voulais accéder à diverses informations sur ADX2.
Cet article est probablement un peu plus difficile (manque d'explication).
S'il ne s'agit que du nom de la file d'attente, l'article précédent Introduction de scripts utiles tels que la copie vers Unity lors de la construction d'ADX2 Veuillez aussi.
Page de kan_kikuchi Qu'est-ce qu'un objet scriptable? [Unity] [Objet scriptable]
ADX2 Le middleware audio ADX2LE peut être utilisé gratuitement (des conditions s'appliquent)
ptyhon Ici
・ Les personnes qui veulent écrire du code qui génère ScriptableObject ・ Les personnes qui souhaitent utiliser la sortie xml d'ADX2 d'une manière ou d'une autre ・ Les personnes qui souhaitent analyser xml avec python et générer du code c #
Il y a des informations qui peuvent être obtenues par la fonction Acb au moment de l'exécution, et via la sortie du fichier cs au moment de la construction. Je voulais gérer uniquement les informations nécessaires en un seul endroit.
Je voulais extraire des informations qui pourraient être utilisées pour quelque chose.
("Quelque chose" ici peut être un outil interne.)
Après la construction avec ADX2 Lors de l'exécution à partir du menu sur Unity
Générez un fichier .assets qui ressemble à ceci. Il est fait autant que le nombre de feuilles de repères.
Si vous faites référence à ce ScriptableObject généré à partir de l'objet Unity, vous pouvez gérer les informations ACB d'ADX2 dans chaque situation. De plus, comme il est automatiquement mis à jour au moment de la construction (l'utilisation du menu est requise *), les erreurs de transmission d'informations peuvent être réduites.
("Chaque scène" fait ici référence au moment de l'exécution, de l'éditeur, de la construction, etc.)
En outre, des commentaires et autres "commentaires" peuvent être ajoutés à chaque file d'attente pour ceux qui ne touchent qu'avec Unity. Vous pouvez le voir dans l'extension de l'éditeur, il semble donc bon d'utiliser divers commentaires
Par exemple, "Données temporaires" ou "Date de mise à jour" (ADX2-> Commentaire unilatéral vers Unity, donc ce n'est pas bidirectionnel ...)
Utilisez python pour analyser xml. Sélectionnez les informations nécessaires avec python et Générez le code qui crée le ScriptableObject.
J'aimerais connaître le nom du contrôle AISAC, mais lorsque je fais référence à l'AISAC global, il n'est pas généré en XML, Comme convention de dénomination Nom @ nom du contrôle Adopté
--Vérifiez la sortie XML "acb_info"
Appel de python en post-processus (Les noms de fichiers sont légèrement différents ici, mais ils sont appelés de la même manière.)
Si vous ajoutez les informations nécessaires, il devrait être pratique d'utiliser les informations de XML dans Unity.
ADXAcbData.cs
using System;
using System.Collections.Generic;
using UnityEngine;
namespace MyDearest {
[CreateAssetMenu (menuName = "Sound/ADX Acb Data")]
public class ADXAcbData
: ScriptableObject
{
[Serializable]
public class CueData {
public string Name = "";
public List<string> BlockNames = new List<string> ();
public List<string> AisacNames = new List<string> ();
public string Comment = "";
public string UserData = "";
}
public string Name = "";
public List<CueData> Cues = new List<CueData> ();
private List<string> _cueNames = new List<string> ();
/// <summary>
///Renvoie une liste de noms de files d'attente
/// </summary>
/// <returns></returns>
public string[] CueNames () {
if (_cueNames.Count > 0) return _cueNames.ToArray ();
foreach (CueData cuedata in Cues) {
_cueNames.Add (cuedata.Name);
}
return _cueNames.ToArray ();
}
}
}
Puisqu'il sera plus long du nombre de données, une seule file d'attente est omise ici.
AcbDataCreators.cs
using UnityEngine;
using UnityEditor;
namespace MyDearest {
public static class AcbDataCreator {
[MenuItem ("Sound/CreateAcbData")]
private static void Create () {
{
ADXAcbData acb = ScriptableObject.CreateInstance<ADXAcbData> ();
acb.Name = "BGM";
{
ADXAcbData.CueData cueData = new ADXAcbData.CueData ();
cueData.Name = "Chronos";
acb.Cues.Add (cueData);
}
AssetDatabase.CreateAsset (acb, "Assets/MyDearest/Chronos/Data/Sound/BGM.asset");
}
}
}
}
J'aimerais pouvoir créer un ScriptableObject directement à partir de python, mais je ne connaissais pas un peu les informations YAML d'Unity, donc Je crée le code source du menu pour créer ScriptObject avec unité.
C'est un peu difficile à voir car le code est généré en même temps que l'analyse, mais je me demande s'il est facile de comprendre ce que vous faites.
Veuillez corriger le nom du chemin comme il convient.
adx2xml_to_str_cs.py
#print("Créer ScriptableObject à partir de la sortie xml ADX2 C#Générer du code")
import xml.etree.ElementTree as ET
import os
g_currentCueName = "" #Nom de la file d'attente
g_currentCueSheetName = "" #Nom de la feuille de file d'attente
def writeHeader(outstr):
outstr += "using UnityEngine;\n"
outstr += "using UnityEditor;\n"
outstr += "namespace MyDearest {\n"
outstr += " public static class AcbDataCreator {\n"
outstr += " [MenuItem (\"Window/MDSound/CreateAcbData\")]\n"
outstr += " private static void Create () {\n"
return outstr
def writeFooter(assetoutpath,outstr):
outstr += "\t\t\t\t\tacb.Cues.Add (cueData);\n"
outstr += "\t\t\t\t}\n"
outstr += "\t\t\t\tEditorUtility.SetDirty (acb);\n"
outstr += "\t\t\t}\n"
outstr += "\t\t}\n"
outstr += "\t}\n"
outstr += "}\n"
return outstr
def printOrcaName(nest,child,xmlpath,outpath,assetoutpath,outstr):
global g_currentCueName,g_currentCueSheetName
nestspacestr = ""
for i in range(nest):
nestspacestr +=" "
if(child.get("OrcaType") == "CriMw.CriAtomCraft.AcCore.AcOoCueSheet"):
print("Nom de la feuille de file d'attente" + child.get("OrcaName")) #Feuille de repère
if(g_currentCueSheetName != "" and g_currentCueSheetName != child.get("OrcaName")): #Seulement lorsque la feuille de repère change
outstr += "\t\t\t\t\tacb.Cues.Add (cueData);\n"
outstr += "\t\t\t\t}\n"
outstr += "\t\t\t\tEditorUtility.SetDirty (acb);\n"
outstr += "\t\t\t}\n"
g_currentCueSheetName = child.get("OrcaName")
g_currentCueName = ""
outstr += "\t\t\t{\n"
outstr += "\t\t\t\tADXAcbData acb = (ADXAcbData)AssetDatabase.LoadAssetAtPath (\"" + assetoutpath + g_currentCueSheetName + ".asset\", typeof (ADXAcbData));\n"
outstr += "\t\t\t\tif (acb == null) {\n"
outstr += "\t\t\t\t acb = ScriptableObject.CreateInstance<ADXAcbData> (); //Faire quand non\n"
outstr += "\t\t\t\t AssetDatabase.CreateAsset (acb, \"" + assetoutpath + g_currentCueSheetName + ".asset\");\n"
outstr += "\t\t\t\t acb = (ADXAcbData)AssetDatabase.LoadAssetAtPath (\"" + assetoutpath + g_currentCueSheetName + ".asset\", typeof (ADXAcbData));\n"
outstr += "\t\t\t\t}\n"
outstr += "\t\t\t\tacb.Cues.Clear ();\n"
outstr += "\t\t\t\tacb.Name = \"" + g_currentCueSheetName + "\";\n"
if(child.get("OrcaType") == "CriMw.CriAtomCraft.AcCore.AcOoCueFolder"):
print(nestspacestr + "Nom du dossier de la file d'attente" + child.get("OrcaName"))
if(child.get("OrcaType") == "CriMw.CriAtomCraft.AcCore.AcOoCueSynthCue"): #queue
print(nestspacestr + "Nom de la file d'attente" + child.get("OrcaName"))
if(g_currentCueName != "" and g_currentCueName != child.get("OrcaName")): #Fermer lorsque la file d'attente change
outstr += " acb.Cues.Add (cueData);\n"
outstr += " }\n"
g_currentCueName = child.get("OrcaName")
outstr += " {\n"
outstr += " ADXAcbData.CueData cueData = new ADXAcbData.CueData ();\n"
outstr += " cueData.Name = \"" + g_currentCueName + "\";\n"
if 'UserData' in child.attrib:
outstr += " cueData.UserData = @\"" + child.get("UserData") + "\";\n"
if 'Comment' in child.attrib:
outstr += " cueData.Comment = @\"" + child.get("Comment") + "\";\n"
if(child.get("OrcaType") == "CriMw.CriAtomCraft.AcCore.AcOoAisac"):
print(nestspacestr + "Nom du contrôle AISAC" + os.path.basename(child.get("AisacControl")))
outstr += " cueData.AisacNames.Add (\"" + os.path.basename(child.get("AisacControl")) + "\");\n"
if(child.get("OrcaType") == "CriMw.CriAtomCraft.AcCore.AcOoAisacLink"):
print(nestspacestr + "Nom du contrôle AISAC" + os.path.basename(child.get("LinkAisac")).split('@')[1]) # Distance@Avec une convention de dénomination comme Distance@Derrière le nom du contrôle((Parce que LinkAisac n'a pas AisacControl)
outstr += " cueData.AisacNames.Add (\"" + os.path.basename(child.get("LinkAisac")).split('@')[1] + "\");\n"
if(child.get("OrcaType") == "CriMw.CriAtomCraft.AcCore.AcOoBlock"):
print(nestspacestr + "Nom du bloc" + child.get("OrcaName"))
outstr += " cueData.BlockNames.Add (\"" + child.get("OrcaName") + "\");\n"
return outstr
#Générer du code de génération d'objets scriptable en analysant XML
def conv(xmlpaths,outpath,assetoutpath):
outstr = "";
outstr = writeHeader(outstr)
for xmlpath in xmlpaths:
tree = ET.parse(xmlpath)
root = tree.getroot()
for child in root:
for child1 in child:
for child2 in child1:
for child3 in child2:
outstr = printOrcaName(0,child3,xmlpath,outpath,assetoutpath,outstr)
for child4 in child3:
outstr = printOrcaName(1,child4,xmlpath,outpath,assetoutpath,outstr)
for child5 in child4:
outstr = printOrcaName(2,child5,xmlpath,outpath,assetoutpath,outstr)
for child6 in child5:
outstr = printOrcaName(3,child6,xmlpath,outpath,assetoutpath,outstr)
for child7 in child6:
outstr = printOrcaName(4,child7,xmlpath,outpath,assetoutpath,outstr)
outstr = writeFooter(assetoutpath,outstr)
print(outstr)
with open(outpath,"w",encoding="utf-8") as f:
f.write(outstr)
#Destination de sortie de construction (pas de sortie en couches)
adx2outputpath = "C:/MyDearest/CraftData/OculusAdxTest/PC/"
#Liste XML à analyser
cuesheetXmlNames = [adx2outputpath + "BGM_acb_info.xml",
adx2outputpath + "SE_acb_info.xml",
adx2outputpath + "VOICE_acb_info.xml"]
#Spécifiez l'emplacement de la conversion réelle et du fichier cs généré et l'emplacement des actifs générés par le fichier généré
conv(cuesheetXmlNames,
"C:/MyDearest/github/Chronos/Assets/MyDearest/Sound/Editor/AcbDataCreator.cs",
"Assets/MyDearest/Chronos/Data/Sound/")
Je suis désolé L'analyse récursive de xml est un code un peu décevant et désordonné, mais veuillez l'ajouter en fonction de la complexité des données.
Comme application Il est facile d'analyser le XML et de créer un fichier texte, donc Il peut également être utilisé à des fins de vérification, de gestion des versions et de coopération avec les outils ci.
Le code ici n'est pas pris en charge, mais par exemple
Je pense que je peux l'enlever. Cependant, si vous les supprimez tous aveuglément, ce sera énorme et difficile à gérer et les données seront gonflées. Je pense que c'est bien de ne pouvoir récupérer que les informations nécessaires.
Il peut être utilisé à l'avenir à des fins telles que le remplacement des données au moment de la construction ou la suppression des informations de débogage (bien que je ne l'ai pas encore essayé).
En outre, il peut être possible de télécharger des informations sur le cloud au moment de la construction, de rechercher des mises à jour à partir de là et de les générer automatiquement.
Recommended Posts