Das G3-HUD steht im Spiel; die Abnahme (U3D) folgt. - U3B: alle Bereiche und Komponenten aus Godot übertragen (LuneHud, Lanes, Bossgrotte, nächste Welle, Kaufkarten, Armee, Held mit Items und Talenten, Angriffschampions, Team, Ereignisse, Minimap, Tooltip, Optionen, Partieende). Porträts aus den echten Modellen, einmal gerendert. - Offene G3-Punkte umgesetzt: „1 WELLE“ als Band am Porträtrand, Schadens- und Rüstungssymbole auf den Karten, Armeewert, Heldenporträts auf der Minimap. Befehlsplatz für die Ultimates der geplanten Helden reserviert (verborgen). - U3C: LuneGame verdrahtet Befehle (gleiche Schnittstelle wie die Bots), Bereit mit 1-s-Sperre nach dem Kampf, Tempo und Pause, Tasten wie in G3, Kamera-Ziele, Auswahl im Feld, Planungsvorschau und Aufstellungsflächen. Ersetzt die U2-Debug-Anzeige. Bot-Partien und Benchmark unverändert. - Szenen- und Bibliotheksbauer idempotent: Animator-Controller und Post-Processing-Profil werden an Ort und Stelle aktualisiert. Die Szene bekommt bei jedem Bau neue Objekt-IDs, der Inhalt ist gleich. - Prüfung (Port von verify_g3, Teile A–H): 699 Prüfungen ohne Fehler. EditMode 23/23, PlayMode 12/12, Fingerabdrücke der Bot-Partien unverändert (DCE95C96556F3A1A, 7B8E43AEFC0D60C5). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
65 lines
2.7 KiB
C#
65 lines
2.7 KiB
C#
using System.IO;
|
||
using UnityEngine;
|
||
|
||
namespace Luneraria.UI
|
||
{
|
||
/// <summary>
|
||
/// Screenshots of the scene with the HUD on top, also in batch mode: the camera renders into
|
||
/// one texture, the HUD panel into its own (premultiplied alpha), and both are composed on the
|
||
/// CPU. Used by the U3 tests and captures; the player can also capture the real screen.
|
||
/// </summary>
|
||
public static class LuneHudCapture
|
||
{
|
||
public static Texture2D Read(RenderTexture texture)
|
||
{
|
||
RenderTexture previous = RenderTexture.active;
|
||
RenderTexture.active = texture;
|
||
var image = new Texture2D(texture.width, texture.height, TextureFormat.RGBA32, false);
|
||
image.ReadPixels(new Rect(0, 0, texture.width, texture.height), 0, 0);
|
||
image.Apply();
|
||
RenderTexture.active = previous;
|
||
return image;
|
||
}
|
||
|
||
public static Texture2D RenderScene(Camera camera, int width, int height)
|
||
{
|
||
var target = new RenderTexture(width, height, 24, RenderTextureFormat.ARGB32) { antiAliasing = 4 };
|
||
RenderTexture previous = camera.targetTexture;
|
||
float aspect = camera.aspect;
|
||
camera.aspect = (float)width / height;
|
||
camera.targetTexture = target;
|
||
camera.Render();
|
||
camera.targetTexture = previous;
|
||
camera.aspect = aspect;
|
||
Texture2D image = Read(target);
|
||
target.Release();
|
||
Object.Destroy(target);
|
||
return image;
|
||
}
|
||
|
||
/// <summary>HUD (premultiplied alpha) over the scene: out = hud + scene · (1 − hud alpha).</summary>
|
||
public static Texture2D Compose(Texture2D scene, Texture2D hud)
|
||
{
|
||
Color32[] under = scene.GetPixels32();
|
||
Color32[] over = hud.GetPixels32();
|
||
var result = new Color32[under.Length];
|
||
for (int index = 0; index < under.Length; index++)
|
||
{
|
||
Color32 a = over[index];
|
||
Color32 b = under[index];
|
||
int keep = 255 - a.a;
|
||
result[index] = new Color32((byte)Mathf.Min(255, a.r + b.r * keep / 255), (byte)Mathf.Min(255, a.g + b.g * keep / 255), (byte)Mathf.Min(255, a.b + b.b * keep / 255), 255);
|
||
}
|
||
var image = new Texture2D(scene.width, scene.height, TextureFormat.RGBA32, false);
|
||
image.SetPixels32(result);
|
||
image.Apply();
|
||
return image;
|
||
}
|
||
|
||
public static void Save(Texture2D image, string file)
|
||
{
|
||
Directory.CreateDirectory(Path.GetDirectoryName(file));
|
||
File.WriteAllBytes(file, image.EncodeToPNG());
|
||
}
|
||
}
|
||
}
|