You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

225 lines
12 KiB
C#

using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Rendering;
namespace Class03.Editor
{
// 에디터에서 씬과 에셋을 만드는 도구입니다. 게임 실행에는 사용하지 않습니다.
public static class Class03SceneBuilder
{
private const string Root = "Assets/Class03";
[MenuItem("Class03/Create Scene")]
public static void CreateScene()
{
if (AssetDatabase.LoadAssetAtPath<SceneAsset>("Assets/Scenes/Class03.unity") != null)
throw new System.InvalidOperationException("Class03 scene already exists; refusing to overwrite it.");
if (!EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo()) return;
System.IO.Directory.CreateDirectory(Root + "/Materials");
System.IO.Directory.CreateDirectory(Root + "/Meshes");
System.IO.Directory.CreateDirectory(Root + "/Prefabs");
AssetDatabase.Refresh();
var scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
var floor = Material("Floor", new Color(0.065f, 0.12f, 0.20f), 0.15f, 0.25f);
var wall = Material("Walls", new Color(0.10f, 0.25f, 0.34f), 0.35f, 0.4f);
var cyan = Material("Cyan", new Color(0.12f, 0.85f, 0.94f), 0.25f, 0.6f);
var gold = Material("StarGold", new Color(1f, 0.67f, 0.08f), 0.55f, 0.65f);
var ballMat = Material("Ball", new Color(0.83f, 0.96f, 1f), 0.65f, 0.55f);
var grid = Material("Grid", new Color(0.12f, 0.22f, 0.31f), 0f, 0f);
var arena = new GameObject("Arena").transform;
Cube("Floor", new Vector3(0,-0.4f,0), new Vector3(20,0.8f,16), floor, arena);
Cube("Wall North", new Vector3(0,1,8), new Vector3(21,2,0.6f), wall, arena);
Cube("Wall South", new Vector3(0,1,-8), new Vector3(21,2,0.6f), wall, arena);
Cube("Wall East", new Vector3(10,1,0), new Vector3(0.6f,2,16), wall, arena);
Cube("Wall West", new Vector3(-10,1,0), new Vector3(0.6f,2,16), wall, arena);
Cube("North Light Strip", new Vector3(0,2.015f,8), new Vector3(20.6f,0.035f,0.12f), cyan, arena, false);
Cube("South Light Strip", new Vector3(0,2.015f,-8), new Vector3(20.6f,0.035f,0.12f), cyan, arena, false);
Cube("East Light Strip", new Vector3(10,2.015f,0), new Vector3(0.12f,0.035f,16), cyan, arena, false);
Cube("West Light Strip", new Vector3(-10,2.015f,0), new Vector3(0.12f,0.035f,16), cyan, arena, false);
var lines = new GameObject("Floor Grid").transform;
lines.SetParent(arena);
for (int x=-8;x<=8;x+=2) Cube("Grid X " + x,new Vector3(x,0.006f,0),new Vector3(0.018f,0.01f,15.4f),grid,lines,false);
for (int z=-6;z<=6;z+=2) Cube("Grid Z " + z,new Vector3(0,0.006f,z),new Vector3(19.4f,0.01f,0.018f),grid,lines,false);
var ball = GameObject.CreatePrimitive(PrimitiveType.Sphere);
ball.name = "Player Ball";
ball.transform.position = new Vector3(0,0.65f,-5.5f);
ball.transform.localScale = Vector3.one * 1.2f;
ball.GetComponent<Renderer>().sharedMaterial = ballMat;
var body = ball.AddComponent<Rigidbody>();
body.mass = 1f;
body.linearDamping = 1.25f;
body.angularDamping = 0.25f;
body.maxAngularVelocity = 20f;
body.interpolation = RigidbodyInterpolation.Interpolate;
body.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
ball.AddComponent<KeyboardMoveInput>();
ball.AddComponent<BallMotor>();
// 작은 표식이 공과 함께 회전하여 실제 구름을 알아보기 쉽게 합니다.
var marker = GameObject.CreatePrimitive(PrimitiveType.Sphere);
marker.name = "Rolling Marker";
Object.DestroyImmediate(marker.GetComponent<Collider>());
marker.transform.SetParent(ball.transform,false);
marker.transform.localPosition = new Vector3(0,0.44f,0);
marker.transform.localScale = new Vector3(0.3f,0.15f,0.3f);
marker.GetComponent<Renderer>().sharedMaterial = cyan;
var counter = new GameObject("Score Counter").AddComponent<ScoreCounter>();
Mesh mesh = StarMesh();
AssetDatabase.CreateAsset(mesh,Root + "/Meshes/Star.asset");
var star = new GameObject("Star");
var trigger = star.AddComponent<SphereCollider>();
trigger.radius = 0.7f;
trigger.isTrigger = true;
star.AddComponent<StarPickup>();
var visual = new GameObject("Visual");
visual.transform.SetParent(star.transform,false);
visual.AddComponent<MeshFilter>().sharedMesh = mesh;
visual.AddComponent<MeshRenderer>().sharedMaterial = gold;
visual.AddComponent<StarMotion>();
var prefab = PrefabUtility.SaveAsPrefabAsset(star,Root + "/Prefabs/Star.prefab");
Object.DestroyImmediate(star);
var stars = new GameObject("Stars").transform;
Vector3[] positions = {
new Vector3(-7,0.9f,-4.5f), new Vector3(-3.5f,0.9f,-1.5f),
new Vector3(-7,0.9f,3.5f), new Vector3(-2.5f,0.9f,5),
new Vector3(2.5f,0.9f,5), new Vector3(7,0.9f,3.5f),
new Vector3(3.5f,0.9f,-1.5f), new Vector3(7,0.9f,-4.5f)
};
for(int i=0;i<positions.Length;i++)
{
var instance=(GameObject)PrefabUtility.InstantiatePrefab(prefab);
instance.name="Star " + (i+1).ToString("00");
instance.transform.SetParent(stars);
instance.transform.position=positions[i];
instance.GetComponent<StarPickup>().Initialize(counter);
PrefabUtility.RecordPrefabInstancePropertyModifications(instance.GetComponent<StarPickup>());
var motion = new SerializedObject(instance.GetComponentInChildren<StarMotion>());
motion.FindProperty("phase").floatValue=i*0.65f;
motion.ApplyModifiedPropertiesWithoutUndo();
}
var camera = new GameObject("Main Camera").AddComponent<Camera>();
camera.tag="MainCamera";
camera.transform.position=new Vector3(0,22,-20);
camera.transform.LookAt(new Vector3(0,0,0));
camera.orthographic=true;
camera.orthographicSize=11f;
camera.clearFlags=CameraClearFlags.SolidColor;
camera.backgroundColor=new Color(0.018f,0.035f,0.065f);
camera.nearClipPlane=0.1f;
camera.farClipPlane=100f;
camera.gameObject.AddComponent<AudioListener>();
var light=new GameObject("Directional Light").AddComponent<Light>();
light.type=LightType.Directional;
light.intensity=1.5f;
light.shadows=LightShadows.Soft;
light.transform.rotation=Quaternion.Euler(45,-30,0);
RenderSettings.ambientMode=AmbientMode.Flat;
RenderSettings.ambientLight=new Color(0.48f,0.58f,0.72f);
CreateUI(counter);
EditorSceneManager.SaveScene(scene,"Assets/Scenes/Class03.unity");
AssetDatabase.SaveAssets();
Selection.activeGameObject=ball;
Debug.Log("Class03 created: ball, 8 stars, 4 walls and score UI.");
}
private static Material Material(string name,Color color,float metallic,float smoothness)
{
Shader shader=Shader.Find("Universal Render Pipeline/Lit");
if(shader==null) throw new System.InvalidOperationException("URP Lit shader missing.");
var material=new Material(shader){name=name};
material.SetColor("_BaseColor",color);
material.SetFloat("_Metallic",metallic);
material.SetFloat("_Smoothness",smoothness);
AssetDatabase.CreateAsset(material,Root + "/Materials/" + name + ".mat");
return material;
}
private static void Cube(string name,Vector3 position,Vector3 scale,Material material,Transform parent,bool solid=true)
{
var go=GameObject.CreatePrimitive(PrimitiveType.Cube);
go.name=name;
go.transform.SetParent(parent);
go.transform.position=position;
go.transform.localScale=scale;
go.GetComponent<Renderer>().sharedMaterial=material;
if(!solid) Object.DestroyImmediate(go.GetComponent<Collider>());
}
private static Mesh StarMesh()
{
var vertices=new Vector3[22];
vertices[0]=new Vector3(0,0,-0.16f);
vertices[11]=new Vector3(0,0,0.16f);
for(int i=0;i<10;i++)
{
float angle=(90+i*36)*Mathf.Deg2Rad;
float radius=i%2==0?0.65f:0.30f;
vertices[i+1]=new Vector3(Mathf.Cos(angle)*radius,Mathf.Sin(angle)*radius,-0.16f);
vertices[i+12]=new Vector3(Mathf.Cos(angle)*radius,Mathf.Sin(angle)*radius,0.16f);
}
var triangles=new System.Collections.Generic.List<int>();
for(int i=0;i<10;i++)
{
int a=i+1,b=(i+1)%10+1;
triangles.AddRange(new[]{0,b,a,11,a+11,b+11,a,b,b+11,a,b+11,a+11});
}
var mesh=new Mesh{name="Extruded Five Point Star",vertices=vertices,triangles=triangles.ToArray()};
mesh.RecalculateNormals();
mesh.RecalculateBounds();
return mesh;
}
private static void CreateUI(ScoreCounter counter)
{
var canvas=new GameObject("HUD",typeof(Canvas),typeof(CanvasScaler));
canvas.GetComponent<Canvas>().renderMode=RenderMode.ScreenSpaceOverlay;
var scaler=canvas.GetComponent<CanvasScaler>();
scaler.uiScaleMode=CanvasScaler.ScaleMode.ScaleWithScreenSize;
scaler.referenceResolution=new Vector2(1600,900);
scaler.matchWidthOrHeight=0.5f;
var panel=new GameObject("Score Panel",typeof(RectTransform),typeof(Image));
panel.transform.SetParent(canvas.transform,false);
var rect=panel.GetComponent<RectTransform>();
rect.anchorMin=rect.anchorMax=new Vector2(0,1);
rect.pivot=new Vector2(0,1);
rect.anchoredPosition=new Vector2(32,-32);
rect.sizeDelta=new Vector2(360,132);
panel.GetComponent<Image>().color=new Color(0.035f,0.07f,0.12f,0.96f);
TextLabel("Chapter",panel.transform,"CLASS 03 / STAR ROLL",new Vector2(22,-16),new Vector2(320,24),16,new Color(0.25f,0.85f,0.95f));
var score=TextLabel("Score",panel.transform,"STARS 00 / 08",new Vector2(20,-46),new Vector2(320,52),36,Color.white);
var status=TextLabel("Status",panel.transform,"ROLL. EXPLORE. COLLECT.",new Vector2(22,-103),new Vector2(320,22),15,new Color(1,0.75f,0.25f));
var help=TextLabel("Controls",canvas.transform,"W A S D / ARROW KEYS • COLLECT ALL 8 STARS",Vector2.zero,new Vector2(900,44),20,new Color(0.68f,0.80f,0.9f));
var helpRect=help.rectTransform;
helpRect.anchorMin=helpRect.anchorMax=new Vector2(0.5f,0);
helpRect.pivot=new Vector2(0.5f,0);
helpRect.anchoredPosition=new Vector2(0,22);
help.alignment=TextAnchor.MiddleCenter;
canvas.AddComponent<ScoreView>().Initialize(counter,score,status);
}
private static Text TextLabel(string name,Transform parent,string content,Vector2 position,Vector2 size,int fontSize,Color color)
{
var go=new GameObject(name,typeof(RectTransform),typeof(Text));
go.transform.SetParent(parent,false);
var text=go.GetComponent<Text>();
text.font=Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
text.text=content;
text.fontSize=fontSize;
text.color=color;
text.raycastTarget=false;
text.fontStyle=FontStyle.Bold;
text.alignment=TextAnchor.MiddleLeft;
var rect=text.rectTransform;
rect.anchorMin=rect.anchorMax=new Vector2(0,1);
rect.pivot=new Vector2(0,1);
rect.anchoredPosition=position;
rect.sizeDelta=size;
return text;
}
}
}