/
Shed4Sprite.cs
236 lines (200 loc) · 6.65 KB
/
Shed4Sprite.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
[ExecuteInEditMode]
public class Shed4Sprite : HasIDColor
{
private bool needRestruct = true;
#if UNITY_EDITOR
void OnEnable()
{
SceneView.onSceneGUIDelegate += this.OnEditorUpdate;
needRestruct = true;
}
void OnDisable()
{
SceneView.onSceneGUIDelegate -= this.OnEditorUpdate;
}
void OnEditorUpdate(SceneView vw)
{
Start();
}
public bool zoomAroundPivot;
#endif
[SerializeField, Header("ドット絵の3Dサイズ")]
public Vector3Int size;
[SerializeField, Header("ドット絵の最手前座標")]
public Vector2Int pivot;
[SerializeField, Header("スプライトとpivot.xからsize自動計算")]
public bool autoSizeAdjust = true;
[SerializeField, Header("昼用スプライト")]
public Sprite sprite4Day;
[SerializeField, Header("夜用スプライト")]
public Sprite sprite4Night;
// ドット絵を保持するマテリアル
public Material material;
// マテリアルのメインテクスチャサイズ
private Vector2Int texSize;
// Spriteのテクスチャ領域
private RectInt spriteRect;
public RectInt SpriteRect
{
get { return spriteRect; }
}
public Vector2Int Size2D
{
get {
if (autoSizeAdjust) return spriteRect.size;
var w = size.x + size.z;
return new Vector2Int(w, size.y + w / 2);
}
}
private void Awake()
{
// なぜか Start/Awake の両方から Mesh初期化しないと、シーン再生時に表示されない
Start();
}
public static Texture2D textureFromSprite(Sprite sprite)
{
if (sprite.rect.width != sprite.texture.width)
{
Texture2D newText = new Texture2D((int)sprite.rect.width, (int)sprite.rect.height);
Color[] newColors = sprite.texture.GetPixels((int)sprite.textureRect.x,
(int)sprite.textureRect.y,
(int)sprite.textureRect.width,
(int)sprite.textureRect.height);
newText.SetPixels(newColors);
newText.Apply();
return newText;
}
else
return sprite.texture;
}
private void doAutoSizeAdjust()
{
spriteRect = GetSpriteRect();
texSize = GetTextureSize();
//Debug.LogFormat("Texture size:({0},{1})", texSize.x, texSize.y);
//Debug.LogFormat("Sprite rect:({0},{1})-({2},{3})", spriteRect.x, spriteRect.y, spriteRect.width, spriteRect.height);
pivot.y = 0;
pivot.x = Mathf.Clamp(pivot.x, 0, spriteRect.width);
size.z = pivot.x;
size.x = spriteRect.width - pivot.x;
size.y = spriteRect.height - spriteRect.width / 2;
}
void Start()
{
if (!needRestruct) return;
needRestruct = true;
if (autoSizeAdjust)
{
doAutoSizeAdjust();
}
Mesh mesh = InitializeCube();
var newMaterial = Instantiate(material);
newMaterial.SetTexture("_MainTex", sprite4Day.texture);
newMaterial.SetTexture("_DayTex", sprite4Day.texture);
newMaterial.SetTexture("_NightTex", sprite4Night.texture);
Vector4 vect = (Color)IDColor;
newMaterial.SetVector("_IDColor", vect);
GetComponent<MeshFilter>().sharedMesh = mesh;
GetComponent<MeshRenderer>().material = newMaterial;
}
#if UNITY_EDITOR
/// <summary>
/// インスペクターからメッシュを再設定する
/// </summary>
public void UpdateMesh() {
this.needRestruct = true;
this.Start();
}
/// <summary>
/// 設定されたテクスチャが3Dサイズで要求されるサイズに足りない
/// </summary>
public bool IsTextureHasNotEnoughSize
{
get
{
if (sprite4Day == null) return true;
return texSize.y < size.y + (size.x + size.z) / 2;
}
}
#endif
/// <summary>
/// テクスチャサイズを取得
/// </summary>
/// <returns></returns>
private Vector2Int GetTextureSize()
{
var tex = sprite4Day.texture;
return new Vector2Int(tex.width, tex.height);
}
/// <summary>
/// Spriteのテクスチャ範囲を取得
/// </summary>
/// <returns></returns>
private RectInt GetSpriteRect()
{
var rect = sprite4Day.textureRect;
return new RectInt((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
}
/// <summary>
/// pivotからの相対位置をUV座標に変換する
/// </summary>
/// <param name="offestX"></param>
/// <param name="offsetY"></param>
/// <returns></returns>
private Vector2 ToUV(float offestX, float offsetY)
{
var x = pivot.x + offestX + spriteRect.x;
var y = pivot.y + offsetY + spriteRect.y;
var pos = new Vector2( x / texSize.x, y / texSize.y);
//Debug.LogFormat("ToUV:({0},{1})",pos.x, pos.y);
return pos;
}
/// <summary>
/// メッシュを生成する
/// </summary>
/// <returns></returns>
private Mesh InitializeCube()
{
Mesh mesh = new Mesh();
/*
* 6
* 5< >3
* | 1 |
* 4<|>2
* 0
*/
var vertices = new Vector3[] {
new Vector3(0, 0, 0), // 0:pivot
new Vector3(0, size.y+1, 0), // 1:nearest top
new Vector3(0, 0, size.z), // 2:bottom right
new Vector3(0, size.y+1, size.z), // 3:top right
new Vector3(size.x, 0, 0), // 4:bottom left
new Vector3(size.x, size.y+1, 0), // 5:top left
new Vector3(size.x, size.y+1, size.z), // 6:most far top
};
var harfX = size.x * 0.5f;
var harfZ = size.z * 0.5f;
var uv = new Vector2[] {
ToUV(0, -0.5f), // 0:pivot
ToUV(0, size.y+0.5f), // 1:nearest top
ToUV(-size.z, harfZ-0.5f), // 4:bottom left
ToUV(-size.z, harfZ + size.y+0.5f), // 5:top left
ToUV(size.x, harfX-0.5f), // 2:bottom right
ToUV(size.x, harfX + size.y+0.5f), // 3:top right
ToUV(size.x - size.z, harfX + harfZ + size.y+0.5f), // 6:most far top
};
var triangles = new int[] {
0,3,1, 0,2,3, // Right Surface
5,4,0, 0,1,5, // Left Surface
1,3,5, 3,6,5, // Upper Surface
};
mesh.vertices = vertices;
mesh.uv = uv;
mesh.triangles = triangles;
return mesh;
}
}