seriruの技術屋ブログ

競技プログラミングやゲーム開発など技術に関することを発信します

UnityでUI.Sliderを使ってAudioSourceの音量を調整する

今回作るものです。

バージョン

  • Unity 2018.4.6f

AudioSource

AudioSourceはunityで音源を再生するためにゲームオブジェクトにアタッチするコンポーネントです。
Hierarchyタブから Audio -> Audio Source で選択し、Audio SourceにBGMクリップをアタッチすることで簡単に使用できます。

① HierarchyタブからAudioSouceを選ぶ。 f:id:ryo_seriru:20190828230805p:plain

② AudioClipをアタッチする。 f:id:ryo_seriru:20190828231236p:plain

UI

Unity上で使用できるUIが入ったコンポーネントです。AudioSourceと同様に選択するとCanvasとEventSystemと同時に作成されます。

① HierarchyタブからUIを選ぶ。 f:id:ryo_seriru:20190828232127p:plain

Canvas、EventSystemと一緒に選択したコンポーネントが追加されます。

f:id:ryo_seriru:20190828232155p:plain

SliderからAudioSourceの音量を調整する

AudioSourceの音量は AudioSource.volume の値を 0.0 ~ 1.0 に変化させることによって調整します。

また、Sliderの正規化した値は AudioSource.normalizedValue から取得できるので、この値を AudioSource.volume に代入することで変化させることができます。

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

public class ToggleBGM : MonoBehaviour {
  
  AudioSource m_AudioSource;

  public Slider m_Slider;

  private bool m_Play;
  public bool m_ToggleChange;
  void Start() {
    m_AudioSource = GetComponent<AudioSource>();
    m_Play = true;
  }

  void Update() {
    m_AudioSource.volume = m_Slider.GetComponent<Slider>().normalizedValue;
  }
}

UnityでUI.Sliderを使ってAudioSourceの音量を調整する

今回作るものです。

バージョン

  • Unity 2018.4.6f

AudioSource

AudioSourceはunityで音源を再生するためにゲームオブジェクトにアタッチするコンポーネントです。
Hierarchyタブから Audio -> Audio Source で選択し、Audio SourceにBGMクリップをアタッチすることで簡単に使用できます。

① HierarchyタブからAudioSouceを選ぶ。 f:id:ryo_seriru:20190828230805p:plain

② AudioClipをアタッチする。 f:id:ryo_seriru:20190828231236p:plain

UI

Unity上で使用できるUIが入ったコンポーネントです。AudioSourceと同様に選択するとCanvasとEventSystemと同時に作成されます。

① HierarchyタブからUIを選ぶ。 f:id:ryo_seriru:20190828232127p:plain

Canvas、EventSystemと一緒に選択したコンポーネントが追加されます。

f:id:ryo_seriru:20190828232155p:plain

SliderからAudioSourceの音量を調整する

AudioSourceの音量は AudioSource.volume の値を 0.0 ~ 1.0 に変化させることによって調整します。

また、Sliderの正規化した値は AudioSource.normalizedValue から取得できるので、この値を AudioSource.volume に代入することで変化させることができます。

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

public class ToggleBGM : MonoBehaviour {
  
  AudioSource m_AudioSource;

  public Slider m_Slider;

  private bool m_Play;
  public bool m_ToggleChange;
  void Start() {
    m_AudioSource = GetComponent<AudioSource>();
    m_Play = true;
  }

  void Update() {
    m_AudioSource.volume = m_Slider.GetComponent<Slider>().normalizedValue;
  }
}

コロプラハッカソン型インターン2019に参加してきました

8/21 ~ 8/23までコロプラのゲームハッカソンインターンシップに参加していました。 本記事はその反省会です。

インターン概要

be-ars.colopl.co.jp

3日間で3人1組でチームを組んで、unityを使用したカジュアルゲームを作るという内容です。自分がunityやゲームプログラム初心者ということで初日は非常に緊張していましたが、結果的にとても楽しく、多くの学びを得られるインターンになりました。

1日目

朝10時に恵比寿のコロプラ本社集合でした。15分前に会場に入るも、既に半分くらいの参加者が集まっていました。

最初に自分のチーム名と名札が渡されるのですが、この段階でチームメンバの2人がすでに集合していたので自己紹介。1人は北海道からやってきたということでかなり驚きました...

その後、運営の支持に従ってunityやsourcetree、gitlabのセットアップを行いながら作るゲームのアイディア出しを行います。

今回のハッカソンでは「青」というテーマに沿ったゲームがお題だったので3人でブレインストーミングの要領で、気軽に青から連想できるワードを言い合いました。また、チームメンバの1人が予めゲームのアイディアをもってきてくれていたのでそれも参考にした結果、時事ネタとテーマをかけ合わせようというアイディアが生まれます。

最終的に今話題の煽り運転(煽(青)り的な言葉遊び)がゲームのテーマになりました。自機は煽られる車で後ろから煽ってくる車を自機の動きで場外へ追い出すというゲームです。

結果的にできたゲームはこんな感じ。

アイディア決めは1時間くらいで終わり、早速開発に入っていきます。

初日は自分がGitLabのissueに最低限必要な実装を書き出し、できるところ手にかけるという感じで進めました。

初日非常に順調に進み、issueに書き出した実装はほとんどすべて終わったのでver1.0のビルドまで終了しました。ゲームの肝になる部分は完成したため明日以降はレベルデザインや追加要素、チュートリアルの製作をしようということでお開きになりました。

2日目

2日目は登場する車の種類の増加やオーディオ要素の追加、UIの実装が主でした。

しかし、自分はここらへんについての知識がほとんどなくほぼすべてチームメンバ頼りになってしまい非常に申し訳なかったです。

一部の実装やゲームを遊んだりしながら2日目終了。

3日目

各々が家でUIやチュートリアルの実装を行ってくれていたので、最終日はレベルデザインや細かいところの修正に時間を割くことができました。

自分は敵機の登場頻度のパラメータを変更したり、時間に依ってレベルを適切に変更できる関数を考えたりしてました。

最後にここまでの開発分をdevelopブランチにマージし、コンフリクトを解消、しっかり動いていることを確認してビルドを運営に提出して終了!

結果

最後に参加者と社員さんが務めるレビュアーさんがすべてのゲームを遊び、点数をつけて上位3チームが表彰されました。

結果、自分たちのチームは同率2位!!!

ほかのチームもクオリティが高いゲームばかりだったのでこの結果には少し驚きましたが、素直にうれしかったです。チームメンバに超感謝。

よかったところともっと改善できるところ

  • 今回の自分が作りたかったゲームがVtuberなどが良くプレイしているカジュアルな「バズゲー」(https://app-liv.jp/1425793208/ みたいなやつ)だったので、最後の懇親会でその意図が社員さんに伝わっていたのが確認できてよかった。

    • ただ、少しゲームとしての尖り方が弱かった。実装力に自信がなかったためこれ以上のアイディアを出すと詰むと思ってしまった点は反省。
  • 最初にゲームに最低限必要な要素をGitLabのissueに書き出して実装を促せた点はプロジェクトの進捗・モチベーションの管理に役立った(と感じた。)

    • 最初に大方の骨組みを決めて、小さなissueのような要素にまとめることで開発中のモチベーションを損なわず進めやすいことがわかったことは非常に大きいと思った。今後、自分の開発でも癖にしていきたい。
  • 物理や数学などゲームプログラミングに必要な素養が明らかに足りていなかった。実装で明らかに焦ってしまい、助けられる部分が多かった。

  • UIやアニメーション、オーディオの知識が全くなかった。反省点。

まとめ

自分に足りないところが浮かび上がったインターンだったので満足でした。また、社員さんとの懇親会もいろいろな方と話すことができたので自分を客観視することに役立ちました。本当にこの3日間ありがとうございました。

Unityお勉強2日目

2日目です。 現在以下の参考書をやり直しています。

www.sbcr.jp

以前、一通り読んでいたため今回は6章と7章を学習し直しました。 以下勉強したワードを(雑に)アウトプットしていきます。

シーン

シーンとはUnityにおけるゲーム場面のくくりのことです。プロジェクト内に .unity という拡張子で保存されており中身は YAML で記述されています。

%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
OcclusionCullingSettings:
  m_ObjectHideFlags: 0
  serializedVersion: 2
  m_OcclusionBakeSettings:
    smallestOccluder: 5
    smallestHole: 0.25

// ... // 

完成したシーンから他のシーンへの遷移には SceneManager.LoadScene("...Scene") というメソッドを使用します。 また、LoadScene メソッドからシーンを読み込むには BulidSetting でシーンを登録する必要があります。

f:id:ryo_seriru:20190807231854p:plain

Physics

Physics はUnityに標準で付属している物理エンジンです。これを使用することでゲームオブジェクトに対して物理挙動を比較的容易に実装することができます。

Rigidbodyコンポーネント

Rigidbody(剛体)コンポーネントは力の計算を担当します。 Rigidbodyではオブジェクトのtransferを変更するのではなく、Rigidbodyに力を加えることによって位置を移動させます。また、Rigidbodyだけでは別のオブジェクトと衝突したときに反応することができません。そのため、衝突判定のために Collider という専用のコンポーネントが存在します。

Colliderコンポーネント

Collider コンポーネントは衝突を行うためのコンポーネントです。Box ColliderCircle Collider などの様々なコンポーネントを組み合わせて衝突判定を与えたいオブジェクトにfitする形の判定を作ることが可能になります。

AddForceメソッド

Rigidbody コンポーネントを動かしたいときには、直接transferをいじらず AddForce などのメソッドを使ってオブジェクトに対して力を加えます。

// 例
GameObject rigid = GetComponent<Rigidbody>();
rigid.AddForce(transform.up * 10.0f);

当たり判定の検出

Physics を使った当たり判定には、CollisionTriggerという2つのモードがあります。Collision は衝突検知だけではなく跳ね返りなども計算します。一方で Trigger は当たったことのみを検知し知らせます。

Prefab

プレハブは同じオブジェクトを複製するために使用される仕組みです。ヒエラルキータブからプロジェクトウィンドウにプレハブにしたいオブジェクトを移動することで作ることができます。

Prefabのジェネレート

プレハブのスクリプトヒエラルキーに作った空のオブジェクトにアタッチすることで適用されます。 以下、プレハブのインスタンスを作るまでのスクリプト

public GameObject gamePrefab;

GameObject prefab = Instantiate(Prefab) as GameObject; // cast
//  その他処理

Unityお勉強1日目

夏に向けてUnityのお勉強が必要になったので1日ずつ勉強したことをまとめていきます。

UnityとCSharp

Unityのコーディングでは主にC#を使います。
公式の初心者向けの説明には

スクリプティングとは、ゲームオブジェクトにアタッチされているスクリプトコンポーネントのことで、ゲームオブジェクトがどのように動作するのか、そしてどのように相互作用するのかを指示します。

今や、Unity におけるスクリプティングとは純粋なプログラミングとは異なります。純粋なプログラミングを行った経験がある場合、例えば実行できるレベルのアプリを作成したことがある場合は、Unity ではアプリケーションを実行するためのコードを作成する必要がないことに気付くでしょう。Unity が代わりにやってくれるからです。その手間の分だけ、Unity スクリプトではゲームプレイの方へフォーカスするのです。

細かい部分はUnityが面倒を見てくれるので、開発者はゲームの動きにフォーカスすることが可能です。大きいプロダクトになるとわかりませんが、簡単なゲームならものすごいスピード感で開発できるんですね。

といっても自分はUnity全くのド素人でチュートリアルで少し触った程度なので簡単にC#を勉強してから実際にゲームを作っていきます。

今回は、AtCoderのA, B問題をC#で解きまくることによって文法を学習しました。コンパイラのバージョンは古いですが、やっぱり未知の言語の学習には非常に便利です。また、他の人の回答も無料で見ることができるので回答に迷ったときやライブラリの使い方がわからないときなど、こちらも非常に参考になります。

atcoder.jp

以下に特に気になった文法をまとめます。

LINQ

SQLのようにメソッドをチェーンさせて配列などを作ります。具体的には以下のようなメソッド群です。

var s = Console.ReadLine().Split(' ').Select(int.Parse).ToArray();

返り値は var で推論させるのが基本です。この場合コンソールからの標準入力を文字列として受け取り、それぞれの要素に対して int.Parse (int型にparse) を適応して配列として返します。 すなわち sint[] になります。

また、対象を決めて配列に対してソートを行う OrderBy や重複を取り除くDistinct など様々なLINQが存在します。

ここらへんを参考にしました。

qiita.com

Generic

C++でいうテンプレート、Javaでいうジェネリクスにあたり、型を抽象的に表現することによって汎用的なメソッドやクラスを作るための機能です。

コレクションのライブラリなどの様々な型が使われる可能性があるクラス群に使われます。

参考

ufcpp.net


非常に雑だけどできるだけ毎日続けます... 明日は実際にUnity触る!!

AtCoder Beginner Contest 134 D Preparing Boxes

表題通りです。

D Preparing Boxes

問題

atcoder.jp

問題概要

 N 個の数字が書かれた箱と数列  a が与えられる。 i の倍数の箱に入っているボールの数の合計の  mod 2 a_{i} と一致するようにしたい。ボールの入れ方を答えよ。

考察

後ろから条件を満たすようにボールを入れていく。

例えば、 N = 6, a = {1,0,0,0,1,1} とすると、 i = 4~6 の場合はその倍数が  N \leq 6 に存在しないので  a_{i} の通りボールを入れれば良い。

次に  i = 3 の場合、 3 の倍数は  6 しかない。 6 には  a_{6} = 1 よりボールが入っているので、箱3にはボールを入れる必要はない。

このように  i = 2 のときも  N \leq 6 の範囲で  2 の倍数の箱のボールの数を数えていき帳尻を合わせればよい。

計算量が非常に重要で一見  O(n^{2}) に感じるが、実際は  O(nlogn) になり十分高速である。(調和級数で調べると良いらしい)

この問題から得られる知見 前から箱のボールを決めようとすると後ろの状況が未知なので混乱するが、後ろから答えを決めることで1つが決まれば前の箱の状況は一意に求まる。

コード

#include <bits/stdc++.h>
using namespace std;

#define rep(i,n) for(long long i=0; i<n; i++)

int main() {
  int n;
  cin >> n;
  vector<int> a(n), b(n, 0);
  
  set<int> st;
  rep(i, n) cin >> a[i];

  for (int i = n; i > 0; --i) {
    int cnt = 0;
    for (int j = i + i; j <= n; j += i) {
      cnt += b[j - 1];
    }
    if (cnt % 2 != a[i-1]) {
      b[i-1] = 1;
      st.insert(i);
    }
  }

  cout << st.size() << endl;
    if (st.size()) {
      for (auto&& itr : st) {
      cout << itr << " ";
    }
  }
  

}

プログラミングバトル 予選・本戦 - BCU30 2019

本戦B問題解けず20位...めっちゃ悔しい

予選

A Bullet of Flame

atcoder.jp

考察

 Aを小さい方から和を取り、 P を超えたところまでの壁の枚数を出力する。

提出コード

#include <bits/stdc++.h>
using namespace std;

int main() {
  int n,p;
  cin >> n >> p;
  vector<int> a(n);
  for (int i = 0; i < n; ++i) {
    cin >> a[i];
  }
  
  int ans = 0;
  for (int i = 0; i < n; ++i) {
    if (a[i] <= p) {
      p -= a[i];
      ans += 1;
    } else {
      break;
    }
  }
  cout << ans << endl;
}

本戦

A Wolf Keyboard

atcoder.jp

考察

問題文に少し気圧されるが、多く使う文字ほど押す回数を減らせれば良い。 使う回数の少ない文字  N - K 個を2回、それ以外を1回押せばよい。

提出コード

#include <bits/stdc++.h>
using namespace std;

int main() {
  int n,k;
  cin >> n >> k;
  vector<int> a(n);
  for (int i = 0; i < n; ++i) cin >> a[i];
 
  sort(a.begin(), a.end());
  int ans = 0;
  for (int i = 0; i < n - k; ++i) {
    ans += a[i] * 2;
  }
 
  for (int i = n - k; i < n; ++i) {
    ans += a[i];
  }
 
  cout << ans << endl;
}

B Interval Addition

atcoder.jp

考察

全ての要素が  0 の配列 B中の連続する区間を自由に選び、その要素を  B_{i} \le B_{i+1}となるように変更し、与えられた配列  A と等しくなるまでに最小何回操作を行う必要があるかという問題。

区間の広さは自由に選べるが B_{i} \le B_{i+1}とする必要がある。 従って目的の配列  A の要素が  A_{i} \gt A_{i+1} となるまで  B を更新できる。

配列  A が最初から全てが  0 のときに注意。

提出コード

#include <bits/stdc++.h>
using namespace std;

int main() {
  int n;
  cin >> n;
  vector<int> a(n+1);
  bool isAllZero = true;
  for (int i = 0; i < n; ++i) {
    cin >> a[i];
    if (a[i]) isAllZero = false;
  }
  a[n] = numeric_limits<int>::max();

  int ans = 1;
  for (int i = 1; i <= n; ++i) {
    if (a[i] < a[i-1]) ans += 1;
  }

  if (!isAllZero) {
    if (a[n-1] == 0) ans -= 1;
    cout << ans << endl;
  } else {
    cout << 0 << endl;
  }
}

200, 300, 400って感じ