다음과 같이, Application.OpenURL을 이용해서

내 App을 사용하는 유저의 버그 리포트나 기타 문의사항 등을 메일로 받아보도록 할 수 있습니다.


mailto : 받는 메일 주소

subject : 보낼 메일의 제목

body : 보낼 메일의 내용



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
using UnityEngine;
 
public class EmailSender : MonoBehaviour
{
    public void OnClickEvent()
    {
        string mailto = "myapp.support@gmail.com";
        string subject = EscapeURL("버그 리포트 / 기타 문의사항");
        string body = EscapeURL
            (
             "이 곳에 내용을 작성해주세요.\n\n\n\n" +
             "________" +
             "Device Model : " + SystemInfo.deviceModel + "\n\n" +
             "Device OS : " + SystemInfo.operatingSystem + "\n\n" +
             "________"
            );
 
        Application.OpenURL("mailto:" + mailto + "?subject=" + subject + "&body=" + body);
    }
 
    private string EscapeURL(string url)
    {
        return WWW.EscapeURL(url).Replace("+""%20");
    }
 
}
 
cs



위의 OnClickEvent를 버튼에 달아서 사용하였습니다.

아래는 최근에 런칭한 로그(LOG) : 항해의 시작 이라는 게임 내 화면입니다.

이 프로젝트 런칭 준비하느라 통 블로그 활동을 못했네요 ... (핑계)





아래는, 위 사진의 '이메일 문의' 버튼을 눌렀을 때 나오는 화면입니다.

메일을 보내는 유저의 디바이스 모델과 OS도 알 수 있어서 도움이 되겠죠?






디바이스의 시스템 언어 정보를 가져오는 간단한 방법!

Application.systemLanguage



다국어 지원(Localization) 할 때 유용하게 사용하세요!


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
    public enum SystemLanguage
    {
        Afrikaans = 0,
        Arabic = 1,
        Basque = 2,
        Belarusian = 3,
        Bulgarian = 4,
        Catalan = 5,
        Chinese = 6,
        Czech = 7,
        Danish = 8,
        Dutch = 9,
        English = 10,
        Estonian = 11,
        Faroese = 12,
        Finnish = 13,
        French = 14,
        German = 15,
        Greek = 16,
        Hebrew = 17,
        Hungarian = 18,
        Hugarian = 18,
        Icelandic = 19,
        Indonesian = 20,
        Italian = 21,
        Japanese = 22,
        Korean = 23,
        Latvian = 24,
        Lithuanian = 25,
        Norwegian = 26,
        Polish = 27,
        Portuguese = 28,
        Romanian = 29,
        Russian = 30,
        SerboCroatian = 31,
        Slovak = 32,
        Slovenian = 33,
        Spanish = 34,
        Swedish = 35,
        Thai = 36,
        Turkish = 37,
        Ukrainian = 38,
        Vietnamese = 39,
        Unknown = 40,
    }
    
 
    // 예시
 
    SystemLanguage sl = Application.systemLanguage;
    
    switch (sl)
    {
        // to do ...
    }
    
    // 또는
        
    switch (sl.ToString())
    {
        // to do ...
    }
cs



ObjectPoolSample.unitypackage


모바일 프로젝트의 필수요소인 오브젝트 풀,

구글링하여 찾은 C# 소스를 기반으로 유니티에서 재사용 가능하도록 제작해보았습니다.

이를 활용한, 총에서 불렛을 발사하는 예제도 함께 첨부했습니다.


( ObjectPool<T>.cs, PoolableObject.cs, ObjectPoolManager.cs, Gun.cs, Bullet.cs )



풀링할 객체는 모두 PoolableObject 클래스를 상속받아서 사용하시면 됩니다.


ObjectPool<T>.cs의

 - objStack : 비활성화 된 object들을 담고있는 Stack (풀)

 - objList : 활성화 된 object들을 담고있는 List (참조용)


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
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
// ObjectPool<T>.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
 
public class ObjectPool<T> where T : PoolableObject
{
    private int allocateCount;
 
    public delegate T Initializer ();
    private Initializer initializer;
 
    private Stack<T> objStack;
    public List<T> objList;
 
    public ObjectPool ()
    {
        // default constructor
    }
 
 
    public ObjectPool (int ac, Initializer fn)
    {
        this.allocateCount = ac;
        this.initializer = fn;
        this.objStack = new Stack<T>();
        this.objList = new List<T>();
    }
 
    public void Allocate ()
    {
        for (int index = 0; index < this.allocateCount; ++index)
        {
            this.objStack.Push(this.initializer());
        }
    }
 
    public T PopObject ()
    {
        if (this.objStack.Count <= 0)
        {
            Allocate();
        }
 
        T obj = this.objStack.Pop();
        this.objList.Add(obj);
 
        obj.gameObject.SetActive(true);
 
        return obj;
    }
 
    public void PushObject (T obj)
    {
        obj.gameObject.SetActive(false);
 
        this.objList.Remove(obj);
        this.objStack.Push(obj);
    }
 
    public void Dispose ()
    {
        if (this.objStack == null || this.objList == null)
            return;
 
        this.objList.ForEach(obj => this.objStack.Push(obj));
 
        while (this.objStack.Count > 0)
        {
            GameObject.Destroy(this.objStack.Pop());
        }
 
        this.objList.Clear();
        this.objStack.Clear();
    }
    
 
 
// PoolableObject.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
 
public class PoolableObject : MonoBehaviour 
{
    protected ObjectPool<PoolableObject> pPool;
 
    public virtual void Create (ObjectPool<PoolableObject> pool)
    {
        pPool = pool;
 
        gameObject.SetActive(false);
    }
    
    public virtual void Dispose ()
    {
        pPool.PushObject(this);
    }
 
    public virtual void _OnEnableContents ()
    {
        // to do ...
    }
    
    public virtual void _OnDisableContents ()
    {
        // to do ...
    }
 
 
 
// ObjectPoolManager.cs
using UnityEngine;
using System.Collections;
 
public class ObjectPoolManager : MonoBehaviour 
{
    private static ObjectPoolManager singleton;
    public static ObjectPoolManager GetInstance () { return singleton; }
 
    public ObjectPool<PoolableObject> bulletPool = new ObjectPool<PoolableObject>();
    
    public Bullet bulletPrefab;
 
    void Awake ()
    {
        if (singleton != null && singleton != this)
        {
            Destroy(gameObject);
        }
        else 
        {
            singleton = this;
        }
    }
 
    void Start ()
    {
        bulletPool = new ObjectPool<PoolableObject>(5, () => 
        {
            Bullet bullet = Instantiate(bulletPrefab);
            bullet.Create(bulletPool);
            return bullet;
        });
        
        bulletPool.Allocate();
    }
 
    void OnDestroy ()
    {
        bulletPool.Dispose();
        singleton = null;
    }
 
 
 
// Gun.cs
using UnityEngine;
using System.Collections;
 
public class Gun : MonoBehaviour 
{
    [HideInInspector] public Transform tm;
    private Vector3 bulletSpawnPoint;
 
    void Awake ()
    {
        tm = gameObject.GetComponent<Transform>();
        bulletSpawnPoint = transform.FindChild("bulletSpawnPoint").transform.position;
    }
 
    void Update ()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Bullet bullet = ObjectPoolManager.GetInstance().bulletPool.PopObject() as Bullet;
            bullet.Fire(bulletSpawnPoint);
        }
    }
 
 
 
// Bullet.cs
using UnityEngine;
using System.Collections;
 
public class Bullet : PoolableObject
{
    [HideInInspector] public Transform tm;
    [HideInInspector] public Rigidbody2D rb2D;
 
    private float force;
 
    public override void Create (ObjectPool<PoolableObject> pool)
    {
        base.Create (pool);
    }
 
    public override void Dispose ()
    {
        base.Dispose ();
    }
 
    public override void _OnEnableContents ()
    {
        base._OnEnableContents ();
 
        rb2D.Sleep();
    }
 
    public override void _OnDisableContents ()
    {
        base._OnDisableContents ();
    }
 
    void Awake ()
    {
        tm = gameObject.GetComponent<Transform>();
        rb2D = gameObject.GetComponent<Rigidbody2D>();
 
        force = 800.0f;
    }
 
    void OnEnable ()
    {
        _OnEnableContents();
    }
 
    void OnDisable ()
    {
        _OnDisableContents();
    }
 
    void Update ()
    {
        if (tm.position.x > 10.0f)
        {
            Dispose();
        }
    }
 
    public void Fire (Vector3 spawnPoint)
    {
        tm.position = spawnPoint;
 
        rb2D.AddForce(Vector3.right * force);
    }
 
cs



1
2
3
4
5
6
7
8
9
    using UnityEngine;
 
    // return : -180 ~ 180 degree (for unity)
    public static float GetAngle (Vector3 vStart, Vector3 vEnd)
    {
        Vector3 v = vEnd - vStart;
 
        return Mathf.Atan2(v.y, v.x) * Mathf.Rad2Deg;
    }
cs



+ Recent posts