using UnityEditor; using UnityEngine; using UnityEngine.UI; using UnityEngine.SceneManagement; using UnityEditor.SceneManagement; using UnityEngine.EventSystems; using TMPro; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; public class SceneSetupTool { // [MenuItem("Battlefield/Setup Initial Scenes")] public static void SetupScenes() { if (!AssetDatabase.IsValidFolder("Assets/Scenes")) AssetDatabase.CreateFolder("Assets", "Scenes"); BuildLoginScene(); BuildLobbyScene(); BuildSampleScene(); SetupBuildSettings(); ConfigureImagesAsSprites(); BuildShipPrefabs(); BuildBulletPrefab(); CreateSkillPrefabs(); CreateHazardPrefabs(); CreateJuicePrefabs(); Debug.Log("=== สร้างฉากทั้งหมดเรียบร้อย! ==="); EditorSceneManager.OpenScene("Assets/Scenes/LoginScene.unity"); } // [MenuItem("Battlefield/Configure Images as Sprites")] public static void ConfigureImagesAsSprites() { string[] guids = AssetDatabase.FindAssets("t:Texture2D", new[] { "Assets/Resources/Images" }); foreach (string guid in guids) { string path = AssetDatabase.GUIDToAssetPath(guid); TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter; if (importer != null) { importer.textureType = TextureImporterType.Sprite; importer.spriteImportMode = SpriteImportMode.Single; importer.spritePivot = new Vector2(0.5f, 0.5f); // บังคับให้จุดหมุนอยู่ตรงกลางเสมอ var settings = new TextureImporterSettings(); importer.ReadTextureSettings(settings); settings.spriteAlignment = (int)SpriteAlignment.Center; importer.SetTextureSettings(settings); importer.SaveAndReimport(); } } Debug.Log("=== อัปเดตตั้งค่ารูปภาพทั้งหมดเป็น Sprite เรียบร้อย! ==="); } // [MenuItem("Battlefield/Build Ship Prefabs")] public static void BuildShipPrefabs() { if (!AssetDatabase.IsValidFolder("Assets/Resources/ShipPrefabs")) { if (!AssetDatabase.IsValidFolder("Assets/Resources")) AssetDatabase.CreateFolder("Assets", "Resources"); AssetDatabase.CreateFolder("Assets/Resources", "ShipPrefabs"); } CreateShipPrefab("Ship1", "Images/ship1", 0.4f); // Nebula Ghost - เล็กสุด CreateShipPrefab("Ship2", "Images/ship2", 0.65f); // Comet Crusher - ใหญ่สุด CreateShipPrefab("Ship3", "Images/ship3", 0.5f); // Stellar Striker - กลาง Debug.Log("=== สร้าง Ship Prefabs สำหรับ Gameplay เรียบร้อย! ==="); } private static void CreateShipPrefab(string prefabName, string spritePath, float shipScale = 0.5f) { string path = $"Assets/Resources/ShipPrefabs/{prefabName}.prefab"; GameObject go = new GameObject(prefabName); // Sprite SpriteRenderer sr = go.AddComponent(); Sprite sp = Resources.Load(spritePath); if (sp != null) sr.sprite = sp; // Scale ตามประเภทยาน (PHASE 1) go.transform.localScale = new Vector3(shipScale, shipScale, 1f); // Physics & Collision var rb = go.AddComponent(); rb.gravityScale = 0; rb.isKinematic = true; // PlayerController handles movement directly go.AddComponent(); // Networking go.AddComponent(); var ptv = go.AddComponent(); ptv.m_SynchronizePosition = true; ptv.m_SynchronizeRotation = false; ptv.m_SynchronizeScale = false; go.AddComponent(); // Ensure PhotonView observes the TransformView go.GetComponent().ObservedComponents = new System.Collections.Generic.List { ptv }; // Ensure PhotonView observes the PlayerController go.GetComponent().ObservedComponents.Add(go.GetComponent()); // FirePoint Setup (ปรับตาม Scale) GameObject fpObj = new GameObject("FirePoint"); fpObj.transform.SetParent(go.transform); fpObj.transform.localPosition = new Vector3(0, 1.2f / shipScale * 0.5f, 0); go.GetComponent().firePoint = fpObj.transform; // Shield Visual (ปรับตาม Scale) GameObject shieldObj = new GameObject("ShieldVisual"); shieldObj.transform.SetParent(go.transform); shieldObj.transform.localPosition = Vector3.zero; var shieldSr = shieldObj.AddComponent(); shieldSr.sprite = UnityEditor.AssetDatabase.GetBuiltinExtraResource("UI/Skin/Knob.psd"); shieldSr.color = new Color(0.2f, 0.8f, 1f, 0.4f); float shieldScale = 3f / shipScale * 0.5f; shieldObj.transform.localScale = new Vector3(shieldScale, shieldScale, 1f); shieldObj.SetActive(false); go.GetComponent().shieldVisual = shieldObj; PrefabUtility.SaveAsPrefabAsset(go, path); Object.DestroyImmediate(go); } // [MenuItem("Battlefield/Build Bullet Prefab")] public static void BuildBulletPrefab() { if (!AssetDatabase.IsValidFolder("Assets/Resources")) AssetDatabase.CreateFolder("Assets", "Resources"); string texPath = "Assets/Resources/Images/laser_bullet.png"; if (!System.IO.File.Exists(texPath)) { Texture2D tex = new Texture2D(4, 16); for (int y = 0; y < 16; y++) for (int x = 0; x < 4; x++) tex.SetPixel(x, y, new Color(0.4f, 0.8f, 1f, (x == 0 || x == 3) ? 0.5f : 1f)); tex.Apply(); System.IO.File.WriteAllBytes(texPath, tex.EncodeToPNG()); AssetDatabase.Refresh(); TextureImporter importer = AssetImporter.GetAtPath(texPath) as TextureImporter; if (importer != null) { importer.textureType = TextureImporterType.Sprite; importer.spritePixelsPerUnit = 16; importer.SaveAndReimport(); } } string path = "Assets/Resources/BulletPrefab.prefab"; GameObject go = new GameObject("BulletPrefab"); // Visual var sr = go.AddComponent(); Sprite laserSprite = AssetDatabase.LoadAssetAtPath(texPath); if (laserSprite != null) sr.sprite = laserSprite; else sr.sprite = UnityEditor.AssetDatabase.GetBuiltinExtraResource("UI/Skin/Knob.psd"); // Trail Renderer for visual flair var tr = go.AddComponent(); tr.time = 0.15f; tr.startWidth = 0.1f; tr.endWidth = 0f; tr.material = new Material(Shader.Find("Sprites/Default")); Gradient gradient = new Gradient(); gradient.SetKeys(new GradientColorKey[] { new GradientColorKey(new Color(0.4f, 0.8f, 1f), 0.0f), new GradientColorKey(Color.white, 1.0f) }, new GradientAlphaKey[] { new GradientAlphaKey(1.0f, 0.0f), new GradientAlphaKey(0.0f, 1.0f) }); tr.colorGradient = gradient; // Physics var rb = go.AddComponent(); rb.gravityScale = 0; rb.collisionDetectionMode = CollisionDetectionMode2D.Continuous; // ป้องกันทะลุ var col = go.AddComponent(); col.size = new Vector2(0.2f, 0.8f); col.isTrigger = true; // Networking go.AddComponent(); var ptv = go.AddComponent(); ptv.m_SynchronizePosition = true; ptv.m_SynchronizeRotation = true; ptv.m_SynchronizeScale = false; go.GetComponent().ObservedComponents = new System.Collections.Generic.List { ptv }; // Controller var bc = go.AddComponent(); bc.speed = 15f; bc.lifeTime = 2f; PrefabUtility.SaveAsPrefabAsset(go, path); Object.DestroyImmediate(go); Debug.Log("=== สร้าง Bullet Prefab สำหรับ Gameplay เรียบร้อย! ==="); } private static void CreateSkillPrefabs() { string[] skills = { "Skill_StunWave", "Skill_NovaBlast", "Skill_SeekerMissile" }; foreach (string skillName in skills) { string path = "Assets/Resources/" + skillName + ".prefab"; GameObject go = new GameObject(skillName); var sr = go.AddComponent(); sr.sprite = Resources.Load("Images/icon_" + skillName.Split('_')[1].Replace("Wave", "stun").Replace("Blast", "nova").Replace("Missile", "seeker").ToLower()); if (sr.sprite == null) sr.sprite = Resources.Load("Images/icon_stun"); sr.color = new Color(1, 1, 1, 0.8f); var rb = go.AddComponent(); rb.gravityScale = 0; rb.collisionDetectionMode = CollisionDetectionMode2D.Continuous; var col = go.AddComponent(); col.isTrigger = true; go.AddComponent(); var ptv = go.AddComponent(); ptv.m_SynchronizePosition = true; ptv.m_SynchronizeRotation = true; go.GetComponent().ObservedComponents = new System.Collections.Generic.List { ptv }; var sc = go.AddComponent(); if (skillName == "Skill_StunWave") { sc.behavior = SkillController.SkillBehavior.StunWave; sc.speed = 15f; sc.lifeTime = 2f; sr.sprite = UnityEditor.AssetDatabase.GetBuiltinExtraResource("UI/Skin/UISprite.psd"); sr.color = new Color(0.4f, 1f, 1f, 0.8f); // Cyan wave go.transform.localScale = new Vector3(3f, 0.5f, 1f); // กว้างๆ แบนๆ เหมือนคลื่น col.radius = 1f; } else if (skillName == "Skill_NovaBlast") { sc.behavior = SkillController.SkillBehavior.NovaBlast; sc.speed = 0f; sc.lifeTime = 0.5f; sr.sprite = UnityEditor.AssetDatabase.GetBuiltinExtraResource("UI/Skin/Knob.psd"); sr.color = new Color(1f, 0.5f, 0.2f, 0.5f); // Orange Nova go.transform.localScale = new Vector3(5f, 5f, 1f); // ระเบิดวงกว้างมาก col.radius = 1.2f; // Add ParticleSystem for explosive effect ParticleSystem ps = go.AddComponent(); var main = ps.main; main.duration = 0.5f; main.startLifetime = 0.5f; main.startSpeed = 10f; main.startSize = 0.5f; main.startColor = new Color(1f, 0.5f, 0.2f, 1f); main.loop = false; var emission = ps.emission; emission.rateOverTime = 0; emission.SetBursts(new ParticleSystem.Burst[] { new ParticleSystem.Burst(0f, 30) }); var shape = ps.shape; shape.shapeType = ParticleSystemShapeType.Sphere; shape.radius = 0.5f; var renderer = ps.GetComponent(); renderer.material = new Material(Shader.Find("Sprites/Default")); } else if (skillName == "Skill_SeekerMissile") { sc.behavior = SkillController.SkillBehavior.SeekerMissile; sc.speed = 12f; sc.lifeTime = 4f; go.transform.localScale = new Vector3(1f, 1f, 1f); col.radius = 0.4f; // Trail Renderer for smoke var tr = go.AddComponent(); tr.time = 0.5f; tr.startWidth = 0.3f; tr.endWidth = 0.1f; tr.material = new Material(Shader.Find("Sprites/Default")); Gradient gradient = new Gradient(); gradient.SetKeys(new GradientColorKey[] { new GradientColorKey(Color.gray, 0.0f), new GradientColorKey(Color.darkGray, 1.0f) }, new GradientAlphaKey[] { new GradientAlphaKey(0.8f, 0.0f), new GradientAlphaKey(0.0f, 1.0f) }); tr.colorGradient = gradient; } PrefabUtility.SaveAsPrefabAsset(go, path); Object.DestroyImmediate(go); } Debug.Log("=== สร้าง Skill Prefabs เรียบร้อย! ==="); } private static void CreateHazardPrefabs() { string[] hazards = { "Hazard_Lightning", "Hazard_SlowZone", "Hazard_Meteor", "Hazard_MoltenAsteroid", "Hazard_EnergyCore" }; foreach (string h in hazards) { string path = "Assets/Resources/" + h + ".prefab"; GameObject go = new GameObject(h); // Warning Area (Red Blink) GameObject warnObj = new GameObject("WarningArea"); warnObj.transform.SetParent(go.transform); warnObj.transform.localPosition = Vector3.zero; var warnSr = warnObj.AddComponent(); warnSr.sprite = UnityEditor.AssetDatabase.GetBuiltinExtraResource("UI/Skin/Knob.psd"); warnSr.color = new Color(1f, 0f, 0f, 0.3f); // Effect Visual GameObject effObj = new GameObject("EffectVisual"); effObj.transform.SetParent(go.transform); effObj.transform.localPosition = Vector3.zero; var effSr = effObj.AddComponent(); effSr.sprite = UnityEditor.AssetDatabase.GetBuiltinExtraResource("UI/Skin/Knob.psd"); // Collider var col = go.AddComponent(); col.isTrigger = true; col.enabled = false; // Enabled only during effect phase // Scale and Color based on type var hc = go.AddComponent(); if (h == "Hazard_Lightning") { hc.type = HazardController.HazardType.Lightning; effSr.color = new Color(0.8f, 1f, 1f, 0.9f); // Bright white/cyan lightning flash go.transform.localScale = new Vector3(3f, 3f, 1f); // PHASE 5: ใหญ่ขึ้น col.radius = 0.5f; } else if (h == "Hazard_SlowZone") { hc.type = HazardController.HazardType.SlowZone; effSr.color = new Color(0.2f, 0.2f, 0.8f, 0.5f); // Purple slow pool go.transform.localScale = new Vector3(5f, 5f, 1f); // PHASE 5: ใหญ่ขึ้น col.radius = 0.5f; } else if (h == "Hazard_Meteor") { hc.type = HazardController.HazardType.Meteor; effSr.color = new Color(1f, 0.5f, 0f, 0.9f); // Orange meteor explosion go.transform.localScale = new Vector3(3f, 3f, 1f); col.radius = 0.5f; } else if (h == "Hazard_MoltenAsteroid") { hc.type = HazardController.HazardType.MoltenAsteroid; effSr.color = new Color(1f, 0.3f, 0f, 1f); // Lava Red go.transform.localScale = new Vector3(2f, 2f, 1f); col.radius = 0.5f; } else if (h == "Hazard_EnergyCore") { hc.type = HazardController.HazardType.EnergyCore; effSr.color = new Color(0f, 1f, 1f, 0.5f); // Cyan transparent core go.transform.localScale = new Vector3(6f, 6f, 1f); // Large buff zone col.radius = 0.5f; } hc.warningArea = warnSr; hc.effectVisual = effSr; hc.hitCollider = col; // Networking go.AddComponent(); var ptv = go.AddComponent(); ptv.m_SynchronizePosition = true; ptv.m_SynchronizeRotation = false; go.GetComponent().ObservedComponents = new System.Collections.Generic.List { ptv }; PrefabUtility.SaveAsPrefabAsset(go, path); Object.DestroyImmediate(go); } // Create Black Pillar separately string pillarPath = "Assets/Resources/Hazard_BlackPillar.prefab"; GameObject pillarObj = new GameObject("Hazard_BlackPillar"); var pSr = pillarObj.AddComponent(); pSr.sprite = UnityEditor.AssetDatabase.GetBuiltinExtraResource("UI/Skin/Knob.psd"); pSr.color = new Color(0.1f, 0.1f, 0.1f, 1f); // Black pillar pillarObj.transform.localScale = new Vector3(2f, 2f, 1f); var pCol = pillarObj.AddComponent(); pCol.isTrigger = false; // Solid! var prb = pillarObj.AddComponent(); prb.isKinematic = true; // Static body pillarObj.AddComponent(); var pPtv = pillarObj.AddComponent(); pPtv.m_SynchronizePosition = true; pillarObj.GetComponent().ObservedComponents = new System.Collections.Generic.List { pPtv }; PrefabUtility.SaveAsPrefabAsset(pillarObj, pillarPath); Object.DestroyImmediate(pillarObj); } private static void CreateJuicePrefabs() { // 1. Floating Text string textPath = "Assets/Resources/FloatingText.prefab"; GameObject textObj = new GameObject("FloatingText"); var tmp = textObj.AddComponent(); tmp.fontSize = 6; tmp.alignment = TextAlignmentOptions.Center; tmp.color = Color.red; tmp.fontStyle = FontStyles.Bold; textObj.AddComponent(); PrefabUtility.SaveAsPrefabAsset(textObj, textPath); Object.DestroyImmediate(textObj); // 2. Death Explosion string deathPath = "Assets/Resources/DeathExplosion.prefab"; GameObject deathObj = new GameObject("DeathExplosion"); var ps = deathObj.AddComponent(); var main = ps.main; main.duration = 1.5f; main.startLifetime = 1f; main.startSpeed = 8f; main.startSize = 1.5f; main.startColor = new Color(1f, 0.4f, 0f, 1f); // Orange Explosion main.loop = false; var emission = ps.emission; emission.rateOverTime = 0; emission.SetBursts(new ParticleSystem.Burst[] { new ParticleSystem.Burst(0f, 50) }); var shape = ps.shape; shape.shapeType = ParticleSystemShapeType.Sphere; shape.radius = 1f; var renderer = deathObj.GetComponent(); renderer.material = new Material(Shader.Find("Sprites/Default")); deathObj.AddComponent().lifetime = 2f; PrefabUtility.SaveAsPrefabAsset(deathObj, deathPath); Object.DestroyImmediate(deathObj); } // ============================ // LOGIN SCENE // ============================ private static void BuildLoginScene() { Scene scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); CreateCamera(new Color(0.02f, 0.02f, 0.08f)); GameObject firebaseObj = new GameObject("FirebaseManager"); firebaseObj.AddComponent(); GameObject audioManagerObj = new GameObject("AudioManager"); audioManagerObj.AddComponent(); GameObject loginManagerObj = new GameObject("LoginManager"); LoginManager loginManager = loginManagerObj.AddComponent(); GameObject canvasObj = CreateCanvas(); CreateEventSystem(); // พื้นหลัง CreateBackground(canvasObj.transform, "Images/LoginBG_HQ"); // ชื่อเกม CreateTMPText("TitleLine1", "BATTLEFIELD", canvasObj.transform, new Vector2(0, 320), 60, new Color(0.4f, 0.75f, 1f), FontStyles.Bold); CreateTMPText("TitleLine2", "OF THE STARS", canvasObj.transform, new Vector2(0, 250), 50, new Color(0.9f, 0.7f, 0.3f), FontStyles.Bold); CreateTMPText("SubTitle", "ONLINE ARENA", canvasObj.transform, new Vector2(0, 200), 22, new Color(0.7f, 0.8f, 0.9f), FontStyles.Normal); // สถานะ var statusObj = CreateTMPText("StatusText", "System Initializing...", canvasObj.transform, new Vector2(0, -50), 20, new Color(0.7f, 0.9f, 1f), FontStyles.Normal); // ปุ่ม Login Google (สีฟ้า) var btnGoogle = CreateTMPButton("Btn_LoginGoogle", "Login Google", canvasObj.transform, new Vector2(0, -130), new Vector2(380, 65), new Color(0.35f, 0.55f, 0.85f), Color.white, 26); // ปุ่ม Guest (สีเทา) var btnGuest = CreateTMPButton("Btn_LoginGuest", "Guest", canvasObj.transform, new Vector2(0, -215), new Vector2(380, 65), new Color(0.45f, 0.45f, 0.5f), Color.white, 26); // Error var errorObj = CreateTMPText("ErrorText", "", canvasObj.transform, new Vector2(0, -300), 18, new Color(1f, 0.3f, 0.3f), FontStyles.Normal); errorObj.SetActive(false); // Version CreateTMPText("VersionText", "v0.1 Alpha", canvasObj.transform, new Vector2(0, -490), 14, new Color(0.4f, 0.4f, 0.5f), FontStyles.Normal); // ผูก UI loginManager.statusText = statusObj.GetComponent(); loginManager.errorText = errorObj.GetComponent(); loginManager.googleButton = btnGoogle.GetComponent