■最初に…
こんにちは、Twitter(@hayadebi)で個人開発の活動をしている"ハヤデビ"と申します。
(まだまだ未熟な開発者です)
この記事では、個人開発でQRコード・Webカメラを使用した際に少し困ったことや、実際に使っているスクリプト・参考にしたサイトなどについての小話をしていきます。
また、完成後に公開する際、公開先ごとの必須事項・注意点(DLsiteやFreem等)も書きまとめてみます。
QRコードを使用して実際に作ったゲーム▼
1.困った事
おもに困った事としては、
・PC"ゲーム開発"に適した参考サイトが少なかったこと
・QRコードを扱った作品で生じる、公開先ごとの必須事項と修正作業
です。
私が開発しながら調べた感じだと、
難しく技術的に書かれてるものは多くあっても、大半は初心者のゲーム開発だと扱いづらい印象でした。
なので以降からは、そういった事を解決できるように話していきます。
(自分でなるべく考えて書きたいから私は使わないけど、そういうこだわりが無い人はぶっちゃけChatGPTに頼れば良いと思う)
2.参考サイト・使用スクリプト
QRコードを扱うゲーム開発の際、初心者でも分かりやすくとても参考になったサイトは以下のものです▼(この記事の前提知識)
2.Webカメラを利用してQRコードを読み込むWindowsアプリを作る
3.[Zxing] UnityでQRコードを読み取りしてみる
どんな開発でもそうですが、ひとつを参考にするだけだと解決は難しいと思います。
なので私の場合は、上記をそれぞれ照らし合わせ、嚙み合うように自分流で書いてます。
(※下記の中には、開発作品専用の汎用ではない変数もあるため、コピペだけでは実装できません。
コピペだけで解決したい場合は、上記参考サイトから)
実際に使用しているスクリプト達▼
①QRコードのマネージャー的な役割
-
using System.Collections;
-
using System.Collections.Generic;
-
using UnityEngine;
-
using ZXing;
-
using ZXing.QrCode;
-
public class QRCodeHelper
-
{
-
//参考サイト3.にて
-
}
②QRコードから読み取ってファイル操作
-
using System.Collections;
-
using System.Collections.Generic;
-
using UnityEngine;
-
using UnityEngine.UI;
-
using System;
-
using System.Linq;
-
using System.IO;
-
using UnityEngine.SceneManagement;
-
public class qr_imgread : MonoBehaviour
-
{
-
string _result = null;
-
public WebCamTexture _webCam;//カメラ
-
public RawImage raw;//カメラに映った様子を表示するためのRawImage
-
private bool check_trg = false;
-
private string global_temp1;
-
private string global_temp2;
-
public Image btimg;
-
public Text bttxt;
-
private bool is_start = false;
-
public Text qrtxt;
-
private bool not_lost = false;
-
public FileManager fmanager;
-
private bool not_stageqrtrg = false;
-
public void ClickQR()
-
{
-
StartCoroutine(nameof(QRStart));
-
}
-
public IEnumerator QRStart()//カメラ起動
-
{
-
yield return Application.RequestUserAuthorization(UserAuthorization.WebCam);
-
-
btimg.enabled = false;
-
bttxt.enabled = false;
-
GManager.instance.setmenu = 1;
-
if (Application.HasUserAuthorization(UserAuthorization.WebCam) == false)
-
{
-
Debug.LogFormat("no camera.");
-
yield break;
-
}
-
Debug.LogFormat("camera ok.");
-
WebCamDevice[] devices = WebCamTexture.devices;
-
if (devices == null || devices.Length == 0)
-
yield break;
-
_webCam = new WebCamTexture(devices[0].name, Screen.width, Screen.height, 12);
-
raw.texture = _webCam;
-
_webCam.Play();//このカメラ起動と似たような感じでStop()で止めれる
-
is_start = true;
-
}
-
void Update()
-
{
-
if (is_start && !check_trg && _webCam != null)
-
{
-
_result = QRCodeHelper.Read(_webCam);//QRかどうか判断するための
-
if (_result != null && QRCodeHelper.Read(_webCam) != null && _result != "error" && !check_trg)//QRだった場合に条件を通させる、エラーの時は通らない
-
{
-
print(_result);
-
string tmp = _result;
-
System.IO.StringReader rs = new System.IO.StringReader(tmp);
-
string line = null;
-
int check_line = 0;
-
bool stage_qrtrg = false;
-
while ((line = rs.ReadLine()) != null)//本作では1行読み込んでステージデータかどうか判別してる
-
{
-
if (check_line == 0 && line == "stage")
-
stage_qrtrg = true;
-
else if (check_line == 0 && line != "stage" && !not_stageqrtrg)
-
{
-
not_stageqrtrg = true;
-
GManager.instance.setrg = 1;
-
if (GManager.instance.isEnglish == 0)
-
qrtxt.text = "<color=red>ステージ専用の</color>QRコードを読み込んでね!";
-
else
-
qrtxt.text = "Read the QR code for the <color=red>stage</color>!";
-
}
-
check_line += 1;
-
}
-
if (stage_qrtrg)//ステージデータなら
-
{
-
check_trg = true;
-
// 書き込み
-
string path = Application.persistentDataPath + "/stage00.txt";
-
bool isAppend = false; // 上書き or 追記
-
using (var fs = new StreamWriter(path, isAppend, System.Text.Encoding.GetEncoding("UTF-8")))
-
{
-
fs.Write(tmp);
-
}
-
GManager.instance.setrg = 6;
-
Instantiate(GManager.instance.all_ui[0], transform.position, transform.rotation);
-
_webCam.Stop();
-
_webCam = null;
-
Invoke("SceneChange", 1);//書き込み後ステージシーンへ飛ぶ
-
}
-
}
-
}
-
}
-
void SceneChange()
-
{
-
GManager.instance.setmenu = 0;
-
GManager.instance.walktrg = true;
-
GManager.instance.storymode = false;
-
GManager.instance.debug_trg = false;
-
GManager.instance.over = false;
-
GManager.instance.goal_num = 0;
-
SceneManager.LoadScene("loadstage");
-
}
-
private void Start()
-
{
-
if (SceneManager.GetActiveScene().name == "qrstage")
-
{
-
StartCoroutine(nameof(QRStart));
-
}
-
}
-
}
③QR画像作成後に共有ツイート
-
using UnityEngine;
-
using ZXing;
-
using ZXing.QrCode;
-
using System.IO;
-
using System;
-
using System.Collections;
-
using System.Text;
-
using UnityEngine.Networking;
-
using UnityEngine.Events;
-
//前提知識:参考サイト5
-
public class qr_create : MonoBehaviour
-
{
-
public static qr_create instance = null;
-
//public string content = "";
-
public string[] tags;
-
[Multiline]
-
public string qr_content = "";
-
[Multiline]
-
public string tweets = "";
-
-
private void Start()
-
{
-
//if(content != "")
-
//{
-
// StartCoroutine(nameof(CreaterQR));
-
//}
-
}
-
public void outputread()//呼び出すことでQRコードを作成し、ツイートする
-
{
-
string path = Application.persistentDataPath + "/stage00.txt";
-
using (var fs = new StreamReader(path, System.Text.Encoding.GetEncoding("UTF-8")))
-
{
-
string tmp = fs.ReadToEnd();
-
qr_content = tmp;
-
}
-
StartCoroutine("CreaterQR");
-
}
-
public IEnumerator CreaterQR()
-
{
-
// 保存するQRコードの画像ファイル名
-
var path = Application.dataPath + "/QRCode.png";
-
// QR コードの画像の幅と高さ
-
var width = 256;
-
var height = 256;
-
var writer = new BarcodeWriter
-
{
-
Format = BarcodeFormat.QR_CODE,
-
Options = new QrCodeEncodingOptions
-
{
-
Width = width,
-
Height = height
-
}
-
};
-
var format = TextureFormat.ARGB32;
-
var texture = new Texture2D(width, height, format, false);
-
var colors = writer.Write(qr_content);
-
texture.SetPixels32(colors);
-
texture.Apply();
-
var bytes = texture.EncodeToPNG();
-
var imageBase64 = Convert.ToBase64String(bytes);
-
// Form Dataの作成
-
var formData = new WWWForm();
-
formData.AddField("image", imageBase64);
-
//imgurのリクエスト作成
-
var request = UnityWebRequest.Post("https://api.imgur.com/3/image", formData);
-
request.SetRequestHeader("AUTHORIZATION", "Client-ID " + "dd103802824b5f9");
-
// リクエスト実行
-
yield return request.SendWebRequest();
-
var response = JsonUtility.FromJson<Response>(request.downloadHandler.text);
-
string tempurl = response.data.link;
-
tempurl = tempurl.Remove(tempurl.Length - 4, 4);
-
tweets += tempurl + "%0a";
-
StartCoroutine(TweetWithScreenShot.TweetManager.TweetWithScreenShot(tweets));//参考サイト5のを呼び出してツイート
-
}
-
// アップロードAPIのレスポンスデータ(必要分のみ定義)
-
[Serializable]
-
private struct Response
-
{
-
[Serializable]
-
public struct Data
-
{
-
// アップロードされた画像URL
-
public string link;
-
}
-
public Data data;
-
public bool success;
-
public int status;
-
}
-
}
①の重要部分は先人方の参考サイトに頼るとして…
以下は試行錯誤の際に困った箇所のみを抜粋します。
まずは②のQRコード読み取りについて見ていきましょう。
・13行目のpublic RawImage raw;には、あらかじめシーン内で作成していたRawImageをいれてください。
これでカメラに映った様子を、UIとして見えるようにできます。
(初見困り度Lv.1)
・46行目の_webCam.Play()でカメラが完全に起動します。
Play()と似たような感じで、Stop()でカメラを止めれます。
カメラの停止は目的のQRコードを読み込んだら、またはシーン移動前に絶対行いましょう。
Webカメラがつきっぱなしの状態だと、あまりよろしくないからですね。
(初見困り度Lv.2)
(ちなみに、②ではQRコード読み取り後にステージデータの準備をしています)
次は、③のQRコードの画像作成について見ていきます。
QR部分は良いのですが、imgurやツイート部分に関しては参考サイト5が前提知識となります。
・public IEnumerator CreaterQR()でQRコード画像の作成と、imgurを利用して画像をツイートするようにしてます。
本来の参考サイト5ではゲーム画面をツイートするという趣旨のようですが、私の場合はステージデータのQRコードを共有するためにツイートさせるので…
作成したQRコード画像をBase64で変換し(60行目辺り)、imgurに対応させて共有ツイートするようにしています。
(初見困り度Lv.3)
困った部分を簡単に説明すると以上です。
基本的には参考サイトや自分が思うように書けば良いと思います。
ただ、上記に自分が記したことは実際に試行錯誤して初めて分かった事、苦戦したことなので、
皆さんも苦戦しないように気を付けましょう…(私はエラー地獄でした)
使いこなせれるようになれば、以下のようにバーコードバトラーやモンスターファームみたいな感覚でキャラクターも作れちゃいます▼
魔法陣(QRコード)から異世界の魔物を召喚してみた。
— ゆっくりハヤデビ@学生ゲーム開発者 (@hayadebi) March 15, 2023
死んだ魔物のQRコードは"二度と"読み込めないようにしてるから、強いQRコードを入手しても油断はダメよ。#Unity #ゲーム制作 #indiegame #クイックライク pic.twitter.com/Ob7jMIJKYr
3.公開先ごとの必須事項・注意点
以下は各公開先での必須項目一覧です▼
公開先のサイト名 |
カメラ/サイトでの説明 |
カメラ/同梱READMEでの説明 |
通信/サイトでの説明 |
通信/同梱READMEでの説明 |
ゲーム内で確認画面表示 |
Freem | 必須 | 必須 | 必須 | 必須 | 必須 |
DLsite | 必須 | 任意 | 必須 | 任意 | 任意 |
Itch.io | 任意 | 任意 | 任意 | 任意 | 任意 |
BOOTH | 任意 | 任意 | 任意 | 任意 | 任意 |
Freemは厳しく審査している感じで、ダメな場合は公開を見送られます。
DLsiteは比較的寛容で、ダメな場合は確認メールを送ってくれます。
その時に迅速な対処をすれば審査を通してくれました。
その他itch.ioとBOOTHは基本任意ですが、
ユーザーを安心させたいならちゃんと対処した方が良いでしょう。
4.終わりに
少し面倒だけど、扱えるようになればゲーム開発の幅が広がりそうですよね。
私の開発では、今後も作品によっては使っていくかもしれません。
皆さんもこれを機に使ってみませんか?
…以上を持ちまして、今回の小話を終わらせていただきます。
何かまた開発の小話ができそうになったら、新しいのを出すかもしれません。
ここまで見てくれてありがとうございました💦
お互いに個人開発を楽しみ頑張りましょう…
「itch.ioからWebGL直リンク等を取得する話」次回の小話▶