Add formal enemies, remaining formal partners and synthesized UI SFX
- UI SFX v3: procedurally synthesized one-shots (Tools/synth_ui_sfx.py) wired to buttons, rewards, errors and red dots via UiSfx, gated by the SFX setting. - Five formal enemies (Hornlet, Dashlet, Shellhorn, HornCaptain, GreatHorn): Hunyuan 50k -> 2000-tri XPbr, DGXA TokenRig, Idle/Walk/Attack, nested per type in PrototypeArena; PrototypeBattle.Enemy gains presentation-only Moving/Strikes. - Formal partners for all ten pets in the arena and portraits, including new VineSprite, ThunderLeopard and TideWhale. - Pipeline fixes: reject local TokenRig fallback, drop loose mesh islands, configurable Unity run_script timeout, companion static stage. - Also includes concurrent work from another tool in this working tree (FlameLion, enemy combat FX, challenge mode, home explorer, server updates). - Resources registered in Doc/ResDesc_*.md; verified on isolated :18081. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
@@ -98,37 +99,45 @@ public static class BuildEnemyReview
|
||||
var view=SceneView.lastActiveSceneView;if(view!=null){view.LookAt(new Vector3(r.reviewOriginX,.35f,0),Quaternion.Euler(12,-12,0),3.6f);view.Repaint();}
|
||||
return "Built additive review "+r.reviewScene+"; other scenes preserved";
|
||||
}
|
||||
public static string Capture(string recipePath="Config/Art/EnemyCharacters/RockBall.json")
|
||||
public static async Task<string> Capture(string recipePath="Config/Art/EnemyCharacters/RockBall.json")
|
||||
{
|
||||
var r=Read(recipePath);var camera=GameObject.Find(Prefix(r)+"Camera").GetComponent<Camera>();
|
||||
var units=new[]{"Idle","Walk","Attack","Cycle"}.Select(n=>GameObject.Find(Prefix(r)+"_"+n)).ToArray();
|
||||
var cycles=units.Select(g=>g.GetComponent<CharacterReviewAnimCycle>()).ToArray();
|
||||
var labels=units.Select(g=>g.transform.Find("NameLabel").GetComponent<TextMesh>()).ToArray();
|
||||
var labelTexts=labels.Select(t=>t.text).ToArray();
|
||||
var animators=units.Select(g=>g.GetComponentInChildren<Animator>()).ToArray();
|
||||
var transforms=units.SelectMany(g=>g.GetComponentsInChildren<Transform>()).ToArray();
|
||||
var p=transforms.Select(t=>t.localPosition).ToArray();var q=transforms.Select(t=>t.localRotation).ToArray();var s=transforms.Select(t=>t.localScale).ToArray();
|
||||
var r=Read(recipePath);var sourceCamera=GameObject.Find(Prefix(r)+"Camera").GetComponent<Camera>();
|
||||
var names=new[]{"Static","Idle","Walk","Attack","Cycle"};
|
||||
var scene=EditorSceneManager.NewPreviewScene();
|
||||
var rt=new RenderTexture(1900,760,24);var tex=new Texture2D(1900,760,TextureFormat.RGB24,false);var active=RenderTexture.active;
|
||||
try
|
||||
{
|
||||
for(int i=0;i<units.Length;i++)
|
||||
// Fresh prefab instances have no review-cycle state or cached Animator
|
||||
// pose. The live review and its labels are never paused or modified.
|
||||
var container=new GameObject("IsolatedReviewCapture");SceneManager.MoveGameObjectToScene(container,scene);
|
||||
var camera=Object.Instantiate(sourceCamera,container.transform);camera.scene=scene;camera.enabled=false;
|
||||
foreach(var light in sourceCamera.transform.parent.GetComponentsInChildren<Light>())Object.Instantiate(light,container.transform);
|
||||
var floor=sourceCamera.transform.parent.Find("Ground_Y0");if(floor!=null)Object.Instantiate(floor,container.transform,false);
|
||||
for(int i=0;i<names.Length;i++)
|
||||
{
|
||||
cycles[i].enabled=false;animators[i].enabled=false;
|
||||
string name=i==0 ? "Idle" : i==1 ? "Walk" : "Attack";
|
||||
labels[i].text=i==3 ? "Auto cycle" : name+(i==2 ? " (impact)" : " (loop)");
|
||||
var source=GameObject.Find(Prefix(r)+"_"+names[i]);
|
||||
var asset=AssetDatabase.LoadAssetAtPath<GameObject>(i==0 ? r.staticPrefab : r.visualPrefab);
|
||||
var go=(GameObject)PrefabUtility.InstantiatePrefab(asset,scene);go.name="Capture_"+names[i];
|
||||
go.transform.position=source.transform.position;go.transform.rotation=source.transform.rotation;go.transform.localScale=source.transform.localScale;
|
||||
var label=Object.Instantiate(source.transform.Find("NameLabel"),go.transform,false).GetComponent<TextMesh>();
|
||||
label.text=i==0 ? "Static" : i==4 ? "Auto cycle" : names[i]+(i==3 ? " (impact)" : " (loop)");
|
||||
var marker=source.transform.Find("ForwardMinusZ");if(marker!=null)Object.Instantiate(marker,go.transform,false);
|
||||
foreach(var t in go.GetComponentsInChildren<Transform>(true))t.gameObject.layer=source.layer;
|
||||
if(i==0)continue;
|
||||
var animator=go.GetComponentInChildren<Animator>();animator.enabled=false;
|
||||
foreach(var skin in go.GetComponentsInChildren<SkinnedMeshRenderer>())skin.updateWhenOffscreen=true;
|
||||
string name=i==1 ? "Idle" : i==2 ? "Walk" : "Attack";
|
||||
var clip=AssetDatabase.LoadAssetAtPath<AnimationClip>(r.assetRoot+"/Clips/"+name+".anim");
|
||||
clip.SampleAnimation(animators[i].gameObject,clip.length*(i==0 ? .5f : i==1 ? .25f : r.attackImpact));
|
||||
clip.SampleAnimation(animator.gameObject,clip.length*(i==1 ? .5f : i==2 ? .25f : r.attackImpact));
|
||||
}
|
||||
await Task.Delay(100);
|
||||
camera.targetTexture=rt;camera.Render();RenderTexture.active=rt;tex.ReadPixels(new Rect(0,0,1900,760),0,0);tex.Apply();
|
||||
string path="Assets/Screenshots/"+(Companion(r) ? "companion_" : "enemy_")+r.id.ToLowerInvariant()+"_review.png";
|
||||
File.WriteAllBytes(Path.Combine(Application.dataPath,"../",path),tex.EncodeToPNG());return path;
|
||||
File.WriteAllBytes(Path.Combine(Application.dataPath,"../",path),tex.EncodeToPNG());AssetDatabase.Refresh();return path;
|
||||
}
|
||||
finally
|
||||
{
|
||||
RenderTexture.active=active;camera.targetTexture=null;rt.Release();Object.DestroyImmediate(rt);Object.DestroyImmediate(tex);
|
||||
for(int i=0;i<transforms.Length;i++){transforms[i].localPosition=p[i];transforms[i].localRotation=q[i];transforms[i].localScale=s[i];}
|
||||
for(int i=0;i<units.Length;i++){labels[i].text=labelTexts[i];animators[i].enabled=true;cycles[i].enabled=true;}
|
||||
AssetDatabase.Refresh();
|
||||
RenderTexture.active=active;rt.Release();Object.DestroyImmediate(rt);Object.DestroyImmediate(tex);EditorSceneManager.ClosePreviewScene(scene);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user