using UnityEngine; using UnityEngine.Rendering; public class Entity { private readonly int entityNum; private readonly VisualStyle visualStyle; private int skinNumber; private GameObject gameObject; private MeshFilter meshFilter; private MeshRenderer meshRenderer; private SkinnedMeshRenderer skinnedMeshRenderer; private Material material; private AliasModel aliasModel; private GameObject brushModel; private GameObject worldModel; public Entity(int entityNum, VisualStyle visualStyle) { this.entityNum = entityNum; this.visualStyle = visualStyle; CreateGameObject(); } private void CreateGameObject() { gameObject = new GameObject($"Entity_{entityNum}"); skinnedMeshRenderer = gameObject.AddComponent(); skinnedMeshRenderer.enabled = false; meshFilter = gameObject.AddComponent(); meshRenderer = gameObject.AddComponent(); meshRenderer.enabled = false; } public void Destroy() { Object.Destroy(gameObject); } public void ClearModel() { aliasModel = null; brushModel = null; worldModel = null; skinnedMeshRenderer.sharedMesh = null; if (skinnedMeshRenderer.material != null) { Object.Destroy(skinnedMeshRenderer.material); skinnedMeshRenderer.material = null; } skinnedMeshRenderer.enabled = false; meshFilter.sharedMesh = null; if (meshRenderer.material != null) { Object.Destroy(meshRenderer.material); meshRenderer.material = null; } meshRenderer.enabled = false; for (int child = 0; child < gameObject.transform.childCount; ++child) { Object.Destroy(gameObject.transform.GetChild(child).gameObject); } } public void SetAliasModel(AliasModel model) { ClearModel(); aliasModel = model; AssignMeshRenderer(); // Set a default pose based on the first animation frame UpdateAnimation(0); if (model.AutoAnimate) { // TODO: do something with syncbase value to push similar animations out of phase var animator = gameObject.AddComponent(); animator.aliasModel = model; } } public void SetBrushModel(GameObject brushModelGO) { ClearModel(); brushModel = brushModelGO; brushModel.transform.SetParent(gameObject.transform); } public void SetWorldModel(GameObject worldModelGO) { ClearModel(); worldModel = worldModelGO; worldModel.transform.SetParent(gameObject.transform); } public void UpdateAnimation(float frameNum) { if (aliasModel != null) { aliasModel.Animate(frameNum, out Mesh mesh, out float blendWeight); if (skinnedMeshRenderer.enabled) { skinnedMeshRenderer.sharedMesh = mesh; if (mesh != null && mesh.blendShapeCount > 0) skinnedMeshRenderer.SetBlendShapeWeight(0, blendWeight); } else if (meshRenderer.enabled) { meshFilter.sharedMesh = mesh; } } if (worldModel != null) { // TODO: update texture animation } } public void SetTransform(Vector3 position, Quaternion rotation) { gameObject.transform.position = position; gameObject.transform.rotation = rotation; } public void SetSkin(int skinNum) { skinNumber = skinNum; if (material == null) return; var skins = aliasModel.Textures.Skins; if (skinNumber >= 0 && skinNumber < skins.Count) { var skin = skins[skinNumber]; if (skin.Frames.Count > 0) visualStyle.SetAliasModelTextures(material, skin.Frames[0].MainTexture, skin.Frames[0].FullBrightTexture); } } private void AssignMeshRenderer() { if (aliasModel.IsAnimated) { visualStyle.SetupAliasModelRenderer(skinnedMeshRenderer); material = skinnedMeshRenderer.material; skinnedMeshRenderer.enabled = true; } else { visualStyle.SetupAliasModelRenderer(meshRenderer); material = meshRenderer.material; meshRenderer.enabled = true; } SetSkin(skinNumber); } }