FC2ブログ
06 «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.» 08

ハルシオンシステムの気ままBlog

株式会社ハルシオンシステムのメンバーが送る、UnityやらJavaやらの技術的話題から、自社開発のアプリの宣伝とかとかのブログです。ほんと気ままにいきたいと思います。更新日は毎週 月 木でっす!

 

【ハルシオンブログ】Unity+Playfab Playfabサーバに置いた絵のファイルをアプリ起動時に持ってくるよぅ(ファイル管理の使い方一例) 

こんにちは。坂内っす。

蒸し暑い日が続きますね。さすが梅雨って感じです。
まぁ一日中クーラーの効いた部屋にいるので、あんまり関係ないですが。

さて、Unity使いで最近Playfabが流行ってきてるみたいですね。
うちも1年前から使ってます。
色々とかゆくても手が届かないところも多いPlayfabですが使える機能の一つとして、「ファイル管理」という機能があります。

画像ファイルやサウンドファイルなどをここにアップロードし、アプリから落として使うといったことに使える機能です。

まずはPlayfabに画像ファイルをアップロードします。



コンテンツ>ファイル管理>ファイルをアップロードからアップロードができます。

ちなみに今回はテスト用にポケガ2のロゴを置いてみました。



説明にも書いてますが、CDNを使用するため、お金がかかるのでカード等の登録が必要になります。

※PlayFab にファイルをアップロードして保存し、グローバル CDN 経由でゲーム クライアントにダウンロードします。CDN の使用コストは、課金期間中にダウンロードされたギガバイトの合計数に基づいて計算され、1 GB あたり 0.10 米ドルのレートで計算されます。CDN へのアップロードと保存は無料で提供されます。

とのことです。

ちなみにファイルのダウンロードはPlayfabにアプリ側でログインしないといけない感じです。

【Blog20200713.cs】

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Blog20200713 : MonoBehaviour
{
public Image img;

IEnumerator Start()
{
yield return StartCoroutine(PlayfabManager.instance.ConnectPlayfab());
yield return new WaitWhile(() => !PlayfabManager.instance.isLogin && !PlayfabManager.instance.isError);

StartCoroutine(PlayfabManager.instance.GetImageFromPlayfab(img, "image01.png"));
}

}



画面を開くとログインをし、SpriteをPlayfabから持ってきて表示するだけのもの。

【PlayfabManager.cs】

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using PlayFab;
using PlayFab.ClientModels;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;


public class PlayfabManager : MonoBehaviour {
public static PlayfabManager instance;
private void Awake() {
if (instance == null) {
instance = this;
DontDestroyOnLoad(gameObject);
} else {
Destroy(gameObject);
}
}

public bool isLogin;
public bool isError;

string downloadPath;
Sprite contentSprite;

public IEnumerator ConnectPlayfab() {
if (string.IsNullOrEmpty(PlayFabSettings.TitleId)) {
PlayFabSettings.TitleId = "TestGame"; // Please change this value to your own titleId from PlayFab Game Manager
}

bool isWait = true;

var request = new LoginWithCustomIDRequest { CustomId = SystemInfo.deviceUniqueIdentifier, CreateAccount = true };
PlayFabClientAPI.LoginWithCustomID(request, OnSuccess, OnError);

while (isWait) {
yield return null;
}

void OnSuccess(LoginResult result) {
isLogin = true;
isWait = false;
}
void OnError(PlayFabError error) {
isLogin = true;
isWait = false;
}
}

///
/// Playfabから画像を取得
///

///
///
///
public IEnumerator GetImageFromPlayfab(Image img, string fileName) {
contentSprite = null;
yield return StartCoroutine(GetContentURL(fileName));
yield return StartCoroutine(PlayFabContentLoad(fileName));
if (contentSprite != null) {
img.sprite = contentSprite;
}
}

///
/// 素材ダウンロード用URL取得
///

public IEnumerator GetContentURL(string playfabPath) {
bool isWait = true;
GetContentDownloadUrlRequest request = new GetContentDownloadUrlRequest() {
Key = playfabPath,
ThruCDN = true,
};
PlayFabClientAPI.GetContentDownloadUrl(request, OnSuccess, OnError);

while (isWait) {
yield return null;
}

void OnSuccess(GetContentDownloadUrlResult result) {
Debug.Log("GetContentURL:OnSuccess");

downloadPath = result.URL;
isWait = false;
}

void OnError(PlayFabError error) {
Debug.Log(error.GenerateErrorReport());
isWait = false;
}
}

///
/// Playfabからファイルを取得
///

///
///
private IEnumerator PlayFabContentLoad(string fileName) {
string localFilePath = Application.persistentDataPath + "/" + fileName;
var getTextureRequest = UnityWebRequestTexture.GetTexture(downloadPath, false);
yield return getTextureRequest.SendWebRequest();

while (!getTextureRequest.isDone) {
yield return getTextureRequest;
}

if (getTextureRequest.isNetworkError) {
Debug.Log("Error:" + getTextureRequest.error);
} else {
File.WriteAllBytes(localFilePath, getTextureRequest.downloadHandler.data);
byte[] bytes = getTextureRequest.downloadHandler.data;
Texture2D texture = new Texture2D(1, 1);

if (texture.LoadImage(bytes)) {
contentSprite = Sprite.Create(texture, new Rect(0.0f, 0.0f, texture.width, texture.height),Vector2.zero);
} else {
contentSprite = null;
}

}
}
}


ちょっと長いですが、Playfabへのログインとデータを取得するところが書かれています。
PlayFabContentLoadメソッドの以下の行でローカルに保存していますが、毎回とってくるならこの行入らない感じですね。

File.WriteAllBytes(localFilePath, getTextureRequest.downloadHandler.data);

本当は、ローカルに保存し、ファイルがローカルに存在する場合はPlayfabから持ってこないで、ローカルのやつを使用ってやるのがいいかと思います。

CDNはお金かかるので、無駄に使わないのがいいですね!

実際に実行するとこんな感じ。



アプリ起動時にSpriteキャッシュとかに入れといて、実際に使うときにはそこから持ってくる感じにしないと、ロードに時間かかるから気持ち悪いですね。

ってことで、こんな感じでPlayfabに置いたファイルをもってこれます!

では今日はこんなところで。

あでゅ~ノシ

Category: 開発日記(Unity)

tb 0 : cm 0   

【ハルシオンブログ】Awakeより先にメソッドを呼び出したいとき 

お疲れさまです。
大坂です。

Awakeより先にメソッド呼べたらなーと思ったことは・・・たまにあるでしょうか?
そんなときは「RuntimeInitializeOnLoadMethod」アトリビュートを使用しましょう。
そのまま使うとAwakeよりあとになってしまうので引数に「RuntimeInitializeLoadType.BeforeSceneLoad」をつけます。

では一応コードです。

void Awake() {
Debug.Log("Awake");
}

void Start() {
Debug.Log("Start");
}

[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
static void Test_1() {
Debug.Log("RuntimeInitializeLoadType.BeforeSceneLoad");
}

[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
static void Test_2() {
Debug.Log("RuntimeInitializeLoadType.AfterSceneLoad");
}

結果。


ちゃんとAwake前に呼ばれていますね!
おまけで、引数「RuntimeInitializeLoadType.AfterSceneLoad」も書いてみてます。
こちらはAwakeよりあとになっていますね。

ということで、Awake前に処理を呼び出す方法の紹介でした。
ではまたノシ

Category: 開発日記(Unity)

tb 0 : cm 0   

【ハルシオンブログ】Unity(C#)でDictionaryの紹介。Listばっかり使ってたけどこいつも悪くはねえなぁ 

こんにちは!坂内っす。

雨すごいらしいっすね・・・・九州は川も氾濫危険水位に達しているようで・・・・
皆さんお気をつけてくださいませ。

UnityというかC#でDictionaryって使ってます?

ListとかArrayとか配列とかと同じ感じで使えるやつです。
連想配列って言われるらしいです。

使うには、usingが必要になります。


using System.Collections.Generic;


Listとかとの違いは、添え字の代わりに任意のデータ型を使います。

・Listとか

List<int> intAry = new List<Int>();
intAry.Add(1);
intAry.Add(3);
intAry.Add(5);
intAry.Add(7);

Debug.Log(intAry[2]);


結果は「5」が取れますよね。
この時intAry[2] という感じに、"3番目"に入っている値という感じで、添え字を使うと思います。

これがDictionaryだとこんな感じになります。

・Dictionaryの場合

Dictionary<string, int> dic = new Dictionary<string, int>();
dic.Add("no1", 1);
dic.Add("no2", 3);
dic.Add("no3", 5);
dic.Add("no4", 7);

Debug.Log(dic["no2"]);


これも結果は「3」が取れます。

こんな感じで、文字列など(key)でvalueをとる感じになります。

また、keyは同じものを入れることができません。


Dictionary<string, int> dic = new Dictionary<string, int>();
dic.Add("no1", 1);
dic.Add("no2", 3);
dic.Add("no2", 5);


こういうことができないということです。

ちなみに初期化時に値を入れる場合はこんな感じでできます。


Dictionary<string, int> dic = new Dictionary<string, int>()
{
{"no1", 1},
{"no2", 3},
{"no3", 5}
}


valueの更新はこんな感じ。


Dictionary<string, int> dic = new Dictionary<string, int>()
{
{"no1", 1},
{"no2", 3},
{"no3", 5}
}

dic["no2"] = 100;


特定のkeyがあるかどうかは、こんな感じで判定できます。


Dictionary<string, int> dic = new Dictionary<string, int>()
{
{"no1", 1},
{"no2", 3},
{"no3", 5}
}

if(dic.ContainsKey("no2")){
Debug.Log("no2があるので更新");
dic["no2"] = 50;
} else {
Debug.Log("no2がないので追加");
dic,Add("no2", 50);
}


また、全体をなめる感じの場合は、foreachでいけますね。


Dictionary<string, int> dic = new Dictionary<string, int>()
{
{"no1", 1},
{"no2", 3},
{"no3", 5}
}

foreach(Dictionary<string, int> data in dic){
Debug.Log(data.key + ":" + data.value);
}


こんな感じで、全部をとることができます。
Dictionaryでは順不動のようで、上記のように全部をなめる時に順番が変わる可能性があるらしいです。

登録した順番に何かの処理をする必要がある場合は、DictionaryではなくList等を使わないといけません。

という感じで、Dictionaryの紹介でした。

では、あでゅ~ノシ

Category: 開発日記(Unity)

tb 0 : cm 0   

【ハルシオンブログ】Toggleで値を変えたときにonValueChangedで処理したくないとき 

こんにちは。
大坂です。

Toggleの値が変わったらonValueChangedでなにか処理をしたいときがよくありますね。
が、しかし処理タイミングによっては処理をしたくないときもあります。。
そんなときは「SetIsOnWithoutNotify」を使うとonValueChangedの処理が呼び出されなくなります。

public class Test : MonoBehaviour
{
public Toggle toggle;

void Start()
{
toggle.onValueChanged.AddListener(a => Debug.Log("Test"));

// onValueChangedが呼び出される
toggle.isOn = false;
// onValueChangedが呼び出されない
toggle.SetIsOnWithoutNotify(true);
}
}



「toggle.isOn」で変更している一回分のログしか出ていませんね。
という感じで、「SetIsOnWithoutNotify」を使用すればonValueChangedが呼び出されません。

他にもSliderやDropdownなら「SetValueWithoutNotify」を使用すればonValueChangedが呼び出されなくなります。
なにかの参考にしてくださいませ。

ではではノシ

Category: 開発日記(Unity)

tb 0 : cm 0   

【ハルシオンブログ】Unityのパッケージマネージャーにローカル通知のやつがあったので試してみたよ(Android) 

こんにちは。坂内っす。

そういえばUnity+スマホでのローカル通知って、今簡単にできるんです?
試しにやってみました。
あ、iOS版は色々めんどそうなので、Android版のみ行っています。

①パッケージマネージャーで、「Mobile Notifications」をインストール


②Project SettingにMobileNotificationの項目が増えているので、アイコンタイプとアイコンを指定


③ローカル通知用クラスの作成
【LocalNotification.cs】

using Unity.Notifications.Android;

public static class LocalNotification {

private static string ChannelId = "ch_0";

///
/// 通知チャンネルの登録
///

public static void Initialize() {
AndroidNotificationChannel channel = new AndroidNotificationChannel{
Id = ChannelId,
Name = "Channel Name",
Importance = Importance.High,
Description = "Description"
};
AndroidNotificationCenter.RegisterNotificationChannel(channel);
}

///
/// ローカル通知を登録
///

/// タイトル
/// 本文
/// 何秒後に通知をするか
public static void ReserveNotification(string title, string body, int afterSec) {

// 通知チャンネルを登録
Initialize();

// 通知を送信する
AndroidNotification notification = new AndroidNotification {
Title = title,
Text = body,
// アイコンをそれぞれセット
SmallIcon = "icon_0",
LargeIcon = "icon_1",
// 今から何秒後に通知をするか?
FireTime = System.DateTime.Now.AddSeconds(afterSec)
};
AndroidNotificationCenter.SendNotification(notification, ChannelId);
}
}


で、呼ぶところはこんな感じ。

【Blog2020629.cs】

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Blog20200629 : MonoBehaviour
{
void Start()
{
LocalNotification.ReserveNotification("ポケガからのお知らせ", "冒険がおわったよ。きてみてさわって。", 30);
}
}



こんな感じ。

これで起動すると、ちゃんとローカル通知が来るよ!



あっ!!



アイコン(小)がでてない!?


で、確認すると・・・・



小さい方のプレビューが出てませんね。
もとのアイコンのファイルが1024x1024で大きいからだめなのかな?

こんなのが書いてますね。


Only icons added to this list or manually added to the `res/drawable` folder can be used by notifications.
Small icons can only be composed simply of white pixels on a transparent backdrop and must be at least 48x48 pixels.
Large icons can contain any colors but must be not smaller than 192x192 pixels.


小さいアイコンは48x48で、透過背景に白だけで書いてね。

なるほど。

そんな感じで小さいアイコンできるらしいっす。



48x48でこんなの作ってみた。



なったw

こんな感じで、簡単にローカル通知が導入できるようになりましたね!

問題はIOSだけど・・・・・それはまた・・・・今度‥書くかもしれないし、書かないかもしれない!

では、あでゅ~ノシ

Category: 開発日記(Unity)

tb 0 : cm 0