インゲームボイスチャットとインゲームビデオキャプチャー・・・「ゲームアプリをソーシャル化するAppSteroid」第7回 | GameBusiness.jp

インゲームボイスチャットとインゲームビデオキャプチャー・・・「ゲームアプリをソーシャル化するAppSteroid」第7回

ゲーム開発 ミドルウェア

インゲームボイスチャットとインゲームビデオキャプチャー・・・「ゲームアプリをソーシャル化するAppSteroid」第7回
  • インゲームボイスチャットとインゲームビデオキャプチャー・・・「ゲームアプリをソーシャル化するAppSteroid」第7回
  • インゲームボイスチャットとインゲームビデオキャプチャー・・・「ゲームアプリをソーシャル化するAppSteroid」第7回
  • インゲームボイスチャットとインゲームビデオキャプチャー・・・「ゲームアプリをソーシャル化するAppSteroid」第7回
  • インゲームボイスチャットとインゲームビデオキャプチャー・・・「ゲームアプリをソーシャル化するAppSteroid」第7回
  • インゲームボイスチャットとインゲームビデオキャプチャー・・・「ゲームアプリをソーシャル化するAppSteroid」第7回
  • インゲームボイスチャットとインゲームビデオキャプチャー・・・「ゲームアプリをソーシャル化するAppSteroid」第7回
  • インゲームボイスチャットとインゲームビデオキャプチャー・・・「ゲームアプリをソーシャル化するAppSteroid」第7回
  • インゲームボイスチャットとインゲームビデオキャプチャー・・・「ゲームアプリをソーシャル化するAppSteroid」第7回
今回は前回ご説明したチャットの流れでインゲームボイスチャットについて最初に解説し、さらにプレイの様子を動画として保存するためのインゲームビデオキャプチャー(現在iOSのみ対応)機能の実装方法をご紹介します。

インゲームボイスチャット



インゲームボイスチャットの前提条件はチャットの時と同様で、事前にメッセージの実績がありメッセージグループができていることが必要です。
(アプリ側ではプッシュ通知の設定を行っておく必要があります。)

このボイスチャットについてもUIは開発者側で用意する必要があります。
サンプルゲームに実装したものをご紹介します。画面遷移はチャットの時と共通です。

スタート画面のChatボタンの下にVoiceChatボタンを置きました。
このボタンのタップでグループリストを表示します。



ポップアップする形でチャットの時と同じグループ選択パネルが開きます。



グループを選択すると、相手側には呼び出されている旨の確認ダイアログが現れます。

(相手側の画面)


相手が「受信する」を選択すると、ボイスチャットが始まります。

ボイスチャット中の発信側と受信側の画面は以下のようになります。
(後からご説明しますが、ここでは受信する側の動作をAppSteroidの初期設定にしてあります)

●発信側画面



「通話中断」・・・マイクを一時的にミュートします。
「通話再開」・・・ミュートを解除し再開します。
「通話終了」・・・ボイスチャットを終了しパネルを閉じます。

これに対して受信する側は、AppSteroidのGUIに移動します。

●受信側画面



画面上部に通話中と表示されている青いバーがあります。
これをタップすると、通話画面に移動します。



この画面で終了ボタンをタップすることで受信側は通話を終えることができます。

ここまでが基本的な流れとなります。

Unity側の設定は以下のようになっています。



「VoiceChatCanvas」内が左のボイスチャットパネルのUIパーツです。「VoiceChatPanel」の中にボタン3つが並んでいます。「BindPanel」は背景を暗くするためのパネルですが、機能的には無くても大丈夫です。
「グループ」を選択すると、この「VoiceChatCanvas」のenabledがtrueになります。

ボイスチャットを制御する「VoiceChat.cs」を作成し、「Chat」オブジェクトにセットします。テキストチャットと一緒のスクリプトにしてしまっても良いのですが、説明を分かりやすするために別スクリプトにしました。

VoiceChat.cs

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
using Fresvii.AppSteroid;
using Fresvii.AppSteroid.Gui;
using Fresvii.AppSteroid.Services;

public class VoiceChat : MonoBehaviour {
// グループ内のメンバーを表示するキャンバス
[HideInInspector]
public Canvas groupCanvas;

// ボイスチャットキャンバスのコンポーネント
[HideInInspector]
public Canvas voiceChatCanvas;

// メッセージグループの配列
private IList groups = new List();

// メンバーの名前ボタン
public GameObject nameButton;

// ----------------- 変数終わり ----------------------

// グループメンバーパネルを表示・非表示
public void ShowGroup2() {
if(!groupCanvas.enabled) {
groupCanvas.enabled = true;
StartCoroutine("MakeGroupList2");
} else {
groupCanvas.enabled = false;

// COntentの子要素(=ボタン)を全削除
foreach(Transform n in GameObject.Find("Content").transform) {
GameObject.Destroy(n.gameObject);
}
}
}


// グループリストを表示するコルーチン
IEnumerator MakeGroupList2() {

yield return new WaitForSeconds(1.0f);

// グループボタンを作成、並べる
if(this.groups != null)
{
foreach(Fresvii.AppSteroid.Models.Group group in this.groups){

// ボタンPrefabを生成、contentパネルの子供にする
GameObject clone = Instantiate(nameButton) as GameObject;
clone.transform.SetParent(GameObject.Find("Content").transform);

// ボタンテキストを変更
clone.GetComponentInChildren().text = group.Name;

Button button = clone.GetComponent
button.onClick.AddListener (() => {
// グループリストを閉じる
ShowGroup2();
// ボイスチャットパネルを立ち上げる
ShowVoiceChat(group.Name, group);
});
}
}
}


// チャットパネルを表示・非表示
public void ShowVoiceChat(string title, Fresvii.AppSteroid.Models.Group group) {
if(!voiceChatCanvas.enabled) {
voiceChatCanvas.enabled = true;

// ボイスチャット開始
FASConference.StartConference(group.Id,
delegate(Fresvii.AppSteroid.Models.Error error)
{
if(error != null)
{
Debug.LogError(error);
}
},

delegate(Fresvii.AppSteroid.Models.Error error)
{
if(error != null)
{
Debug.LogError(error);
}
}
);
}
}


// 「通話中断」ボタンを押した時
public void MuteButton() {
FASConference.Mute();
}

// 「通話再開」ボタンを押した時
public void UnMuteButton() {
FASConference.Unmute();
}

// 「通話終了」ボタンを押した時
public void EndButton() {
FASConference.Leave();
voiceChatCanvas.enabled = false;
}




// Use this for initialization
IEnumerator Start () {
voiceChatCanvas = GameObject.Find("VoiceChatCanvas").GetComponent groupCanvas = GameObject.Find("GroupCanvas").GetComponent groupCanvas.enabled = false;


// 初期化処理完了まで待機
while (!FAS.Initialized)
{
yield return 1;
}

// グループリストを取得
FASGroup.GetGroupMessageGroupList(delegate(IList groups, Fresvii.AppSteroid.Models.Error error)Z
{
this.groups = groups;

foreach (Fresvii.AppSteroid.Models.Group group in this.groups)
{
string name = "";
foreach(Fresvii.AppSteroid.Models.Member member in group.MessageMembers)
{
name += member.Name + ", ";
}
group.Name = name;
}
});
}

// Update is called once per frame
void Update () {

}
}


グループリストを取得する部分はチャットの時とほぼ同じ流れです。
青文字部分がボイスチャットのための記述です。

・ボイスチャット発信のメソッド

ボイスチャット発信のメソッドの基本形です。

public static void StartConference(string groupId, Action startConferenceCallback, Action createConferenceCallback)


上記「VoiceChat.cs」ではその下に参加時のエラー処理「OnGroupConferenceJoinError」と通話中エラー発生時の処理「OnGroupConferenceError」が続いています。

「FASConference.Mute();」はマイクをミュート、「FASConference.Unmute();」はミュート解除、「FASConference.Leave();」はボイスチャット終了のメソッドです。

・着信時の動作設定

このソース中では記載していないのですが、着信した場合の動作を変更することができます。そのメソッドの基本形は以下になります。

public static void SetIncomingVoiceChatBehavior(IncomingVoiceChatBehavior incomingVoiceChatBehavior)


引数部分を変えることで動作が変わります。

FASConference.IncomingVoiceChatBehavior.ASK
→ 確認ダイアログを表示してユーザーの「承諾」によりボイスチャットが始まります。

FASConference.IncomingVoiceChatBehavior.AutoAccept
→ 自動的にカンファレンスへ接続する

FASConference.IncomingVoiceChatBehavior.DoNothing
→ 何もしない=開発者が定義できる

このメソッドを記載しない場合はAppSteroidのデフォルト「ASK」となります。
これでも良いのですが、これだとゲーム中に呼び出された場合、自動的に画面がAppSteroidのGUIに替わってしまうことでプレイを中断させられることとなります。
ゲーム中のボイスチャット使用を想定する場合は「DoNothing」を使って着信時の動作を個別に定義されることをお勧めします。
「VoiceChat.cs」を変更し、着信した場合にも画面移動せず、発信側と同様にボイスチャットパネルがポップアップするようにしてみます。ゲーム中なのでパネルが邪魔にならないようにしたい場合は、パネルの大きさやなどお好みで調整してください。

・着信時に「DoNothing」とした場合

using UnityEngine;
using UnityEngine.UI;

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

using Fresvii.AppSteroid;
using Fresvii.AppSteroid.Gui;
using Fresvii.AppSteroid.Services;

public class VoiceChat : MonoBehaviour {
// グループ内のメンバーを表示するキャンバス
[HideInInspector]
public Canvas groupCanvas;

// ボイスチャットキャンバスのコンポーネント
[HideInInspector]
public Canvas voiceChatCanvas;

// メッセージグループの配列
private IList groups = new List();

// メンバーの名前ボタン
public GameObject nameButton;

// ボイスチャット「着信」時のテキスト表示
Text VoiceChatTitle;

// ----------------- 変数終わり ----------------------

// グループメンバーパネルを表示・非表示
public void ShowGroup2() {
if(!groupCanvas.enabled) {
groupCanvas.enabled = true;
StartCoroutine("MakeGroupList2");
} else {
groupCanvas.enabled = false;

// COntentの子要素(=ボタン)を全削除
foreach(Transform n in GameObject.Find("Content").transform) {
GameObject.Destroy(n.gameObject);
}
}
}

// グループリストを表示するコルーチン
IEnumerator MakeGroupList2() {
yield return new WaitForSeconds(1.0f);
// グループボタンを作成、並べる
if(this.groups != null)
{
foreach(Fresvii.AppSteroid.Models.Group group in this.groups){

// ボタンPrefabを生成、contentパネルの子供にする
GameObject clone = Instantiate(nameButton) as GameObject;
clone.transform.SetParent(GameObject.Find("Content").transform);

// ボタンテキストを変更
clone.GetComponentInChildren().text = group.Name;

Button button = clone.GetComponent
button.onClick.AddListener (() => {
// グループリストを閉じる
ShowGroup2();
// ボイスチャットパネルを立ち上げる
ShowVoiceChat(group.Name, group);
});
}
}
}


// チャットパネルを表示・非表示
public void ShowVoiceChat(string title, Fresvii.AppSteroid.Models.Group group) {
if(!voiceChatCanvas.enabled) {

voiceChatCanvas.enabled = true;

// ボイスチャット開始
FASConference.StartConference(group.Id,
delegate(Fresvii.AppSteroid.Models.Error error)
{
if(error != null)
{
Debug.LogError(error);
}
},

delegate(Fresvii.AppSteroid.Models.Error error)
{
if(error != null)
{
Debug.LogError(error);
}
}
);
}
}

// 1. グループカンファレンス作成通知のイベントを登録
void OnEnable() {
FASEvent.OnGroupConferenceCreated += OnGroupConferenceCreated;
}

// 2. ボイスチャット依頼受信
void OnGroupConferenceCreated(Fresvii.AppSteroid.Models.GroupConference groupConference)
{
FASConference.JoinConference(groupConference, OnGroupConferenceJoinError);
FASConference.OnError += OnGroupConferenceError;

// ボイスチャットパネルを表示
voiceChatCanvas.enabled = true;

VoiceChatTitle.text = "ボイスチャット着信";

}


// 参加時のエラー処理
void OnGroupConferenceJoinError(Fresvii.AppSteroid.Models.Error error)
{
if (error != null)
{
Debug.LogError("GroupConferenceError : " + error.ToString());
}
}
// 通話中エラー発生時の処理
void OnGroupConferenceError(Fresvii.AppSteroid.Models.Error error)
{
Debug.LogError("GroupConferenceError : " + error.ToString());
}



// 「通話中断」ボタンを押した時
public void MuteButton() {
FASConference.Mute();
}

// 「通話再開」ボタンを押した時
public void UnMuteButton() {
FASConference.Unmute();
}

// 「通話終了」ボタンを押した時
public void EndButton() {
FASConference.Leave();
voiceChatCanvas.enabled = false;
}

// Use this for initialization
IEnumerator Start () {
voiceChatCanvas = GameObject.Find("VoiceChatCanvas").GetComponent groupCanvas = GameObject.Find("GroupCanvas").GetComponent groupCanvas.enabled = false;
VoiceChatTitle = GameObject.Find("VoicsChatText").GetComponent();

// 着信時の動作設定 = 何もしない FASConference.SetIncomingVoiceChatBehavior(FASConference.IncomingVoiceChatBehavior.DoNothing);

// 初期化処理完了まで待機
while (!FAS.Initialized)
{
yield return 1;
}

// グループリストを取得
FASGroup.GetGroupMessageGroupList(delegate(IList groups, Fresvii.AppSteroid.Models.Error error)
{
this.groups = groups;

foreach (Fresvii.AppSteroid.Models.Group group in this.groups)
{
string name = "";
foreach(Fresvii.AppSteroid.Models.Member member in group.MessageMembers)
{
name += member.Name + ", ";
}
group.Name = name;
}
});
}

// Update is called once per frame
void Update () {

}
}


赤字部分が変更した箇所です。

IEnumerator Start ()の中で

FASConference.SetIncomingVoiceChatBehavior(FASConference.IncomingVoiceChatBehavior.DoNothing);


を指定しています。これで着信時AppSteroid側では何もしない設定となります。

着信した場合の基本形は以下となります。

// 1. グループカンファレンス作成通知のイベントを登録
{
FASEvent.OnGroupConferenceCreated += OnGroupConferenceCreated;
}

// 2. 着信時 グループカンファレンス作成通知イベントが発火
void OnGroupConferenceCreated(GroupConference groupConference)
{
// グループカンファレンスにゲストとして参加
FASConference.JoinConference(groupConference, OnGroupConferenceJoinError);

// 通話中のエラーイベントの登録
FASConference.OnError += OnGroupConferenceError;
}


サンプルの中では、着信時にボイスチャットパネルが立ち上がり、ボイスチャット着信テキストが表示されるようにしました。



このソースやUIをいろいろと工夫することで、たとえばゲーム内のキャラクター同士で会話しているような演出に発展させることも可能でしょう。

ボイスチャットについての説明は以上です。
ここまでのUnityプロジェクトデータをGitHubにアップしました。
https://github.com/sinfonia2015/AdditionCrash

インゲームビデオキャプチャー



次はインゲームビデオキャプチャーについてご説明します。
ゲームを実際にプレイしているところを録画し、コミュニティに公開できる機能です。現在のところiOSのみの対応となります。
またUnity5を使用される場合、インゲームビデオキャプチャーが使えるのはWithout Voice Chat (Unity 5)版のみとなります。この点はいずれ改善する予定ですが、現時点ではご了承いただきますようお願いいたします。

最初に、この機能で使用するメソッドを紹介します。

Name 内容
FASPlayVideo.StartRecording ビデオ録画を開始する
FASPlayVideo.StopRecording ビデオ録画を終了する
FASPlayVideo.ShowLatestVideoSharingGUIWithUGUI 録画した最新ビデオをシェアするGUIを表示する。UGUIの上にダイアログを表示する。
FASPlayVideo.ShowLatestVideoSharingGUIWithLegacyGUI 録画した最新ビデオをシェアするGUIを表示する。LegacyGUIの上にダイアログを表示する。
FASPlayVideo.LatestVideoExists 録画したビデオが存在するか確認する
FASPlayVideo.SetMaxRecordingSecondsLength ビデオ録画を最大時間(秒)を設定する
FASPlayVideo.GetMaxRecordingSecondsLength ビデオ録画を最大時間(秒)を取得する
FASPlayVideo.IsRecording ビデオ録画の録画状態を取得する
FASPlayVideo.GetLatestRecordedVideoPath 録画した最新ビデオのパスを取得する


これらのメソッドを使用して、サンプルゲームにインゲームビデオキャプチャー機能を実装してみます。

プレイ画面の下の方に録画を開始するためのRecordボタンを作成します。録画がスタートした際にはこれをStopボタンに切り替えたいので、そのボタンも用意します。


(録画前)

(録画時)


UnityのHierarchyでは以下のようにしています。



2つのボタン用のCanvasの中に「StopBtn」と「RecordBtn」を置きます。
それぞれの中に、「Record」「Stop」というボタン文言のテキストが子供として入っています。

そして、この機能のためのスクリプト「Record.cs」を用意し、「GameController」オブジェクトに設置します。

・Recoed.cs

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using Fresvii.AppSteroid;
using Fresvii.AppSteroid.Models;

public class Record : MonoBehaviour {

// ボタンオブジェクト
public Button startRecBtn;
public Button stopRecBtn;

// 録画制限時間
public float limitTime = 10.0f;

// 録画制限時間の一時保管変数
float limitTimeTemp;

// 「RECORD」ボタンを押して録画
public void RecVideo() {
//Debug.Log("録画開始");
if (FASPlayVideo.StartRecording()) {
startRecBtn.gameObject.SetActive(false);
stopRecBtn.gameObject.SetActive(true);
}
}

// 録画ストップ
public void StopRec() {
FASPlayVideo.StopRecording();
startRecBtn.gameObject.SetActive(true);
stopRecBtn.gameObject.SetActive(false);
// Debug.Log("録画終了");
StartCoroutine("ShareMovie");
limitTimeTemp = limitTime;
}

// シェア画面を開くコルーチン
IEnumerator ShareMovie() {
while(!FASPlayVideo.LatestVideoExists())
yield return 1;
if (!FASPlayVideo.ShowLatestVideoSharingGUIWithUGUI(Application.loadedLevelName))
{
Fresvii.AppSteroid.Util.DialogManager.Instance.ShowSubmitDialog("Error : Recorded video does not exist", delegate(bool del) { });
}
}

void Start () {
limitTimeTemp = limitTime;
}

void Update () {
if(FASPlayVideo.IsRecording()) {
limitTimeTemp -= Time.deltaTime;

if(limitTimeTemp <= 0.0f) {
StopRec();
}
}
}
}


最初のところで、2つのボタンオブジェクトの変数を宣言していますので、Inspectorから「StopBtn」と「RecordBtn」を割り当てます。

また、「public void RecVideo()」をRecordボタンに、「public void StopRec()」ボタンをStopボタンのそれぞれクリック時のアクションに割り当てます。



今回は録画したままにならないよう、制限時間(limitTime)を設けています。
Update ()の中で、制限時間が過ぎると自動的にStopRec()が呼ばれるようになっています。

録画が終了したらShareMovie()コルーチンが呼ばれます。ここで録画をシェアする画面になります。

画面としては以下のような流れとなります。


(録画が完了した直後)

(「Share」ボタンを押した後)


My Videosボタンをタップするとマイページにアップされ、コミュニティ名ボタンをタップすると、そのままコミュニティ掲示板にアップされます。

(「My Videos」でマイページにアップした場合)



最後に、このUnityプロジェクトをビルドする際の注意点です。

このビデオ録画機能は現在、Open GL ES 3.0 の録画機能に対応しています。 Unity 4.6.2p2 以降をご利用の場合は、Player Setting -> Other Settings -> Graphics API を Open GL ES 3.0 に設定してください。

Unity5.1以降の場合は「Automatic Graphics API」のチェックを外してから選択してください。



ここまでのプロジェクトデータを以下にアップしました。
https://github.com/sinfonia2015/iOS_AdditionCrash

インゲームビデオキャプチャーの説明は以上です。
いかがでしたでしょうか。

次回はウェブコンソールについてご説明したいと思います。
《Fresvii》

関連ニュース

特集

人気ニュースランキングや特集をお届け…メルマガ会員はこちら