【Unity】Unity1Week【ふる】に参加!【備忘録】
自分は5回目の参加です。今回は期間が2023年6月19日(月) 0時〜2023年6月25日(日) 20時でお題は【ふる】でした。
現在、作成中のゲームが完成予定を大幅に超過しており、参加を迷いましたが、連続参加を途切れさせたくないニキなのと、割とパッとゲームを思いついたので参加しました。
結果的に2時間遅刻はしましたが、投稿はできました。
途中まではStableDiffusionで素材を作ってたりしていたんですが、「時間かけられないなら持ってる素材でやれよ!」とリトル自分に説教されたので、持っている東方系の素材を活用、プログラムの大枠はChatGPTに書いてもらいました。
ゲームとしては大変単純で、増減を繰り返すバーが「フル」になったところでボタンを押すだけのゲームです。
本当はもっとUIやテキストに凝りたかったのですが、できませんでしたね…。
↓ここのチャンネルがUIの勉強に凄くなります。
今回の良かったところは「TrueShadow」という詰みアセットを活用できたところでしょうか。バンドルについてきたのですが、UIに自然な影を足せます。なくてもいいけど、あれば嬉しいアセットです。簡単に使えました。
↓配列内に値が含まれているか確認する方法
結局採用したのは単純なバーゲージでしたが、今後色々UIは凝っていきたいです。
↓ゲージ実装の際に参考にした記事
↓ライフ実装の際に参考にした記事
ただし記事とは違って、LifeGauge(パネル)→HeartGauge(画像)→heart(画像)という階層にしてあり、heartはGameManager中のにheartObjects配列として設定し、Lifeが2(初期値は3)になると、heartObjects[2]つまり3つあるうちの一番右のハートが非表示になるという仕組みになっています。
ボタンの連射ができないように、ボタンをクリックした後はボタンカバーを表示、一定期間後に非表示としています。interactable(ボタンの非活性化)を使用していないのは、ボタンにイラストを使用しているせいか、非活性化してもボタンの見た目が変わらず、いつ押せるようになったのかわからなかったためです。
今回のゲームはGameManagerにほぼ全ての処理を書いており、あとはSoundManager等いつも使用しているスクリプトを数個しているだけです。GameManagerは以下に全部載せます。コメントも整理しました。素人丸出しのコードですが、煮るなり焼くなり好きにしてください。ただし、EasySaveというアセットを使用しているので、持っていない人はPlayerPrefsに直してください。
using System;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class GameManager : MonoBehaviour
{
[Header("ゲージの増減速度")]public float gaugeSpeed; // ゲージの増減速度
[Header("ゲージの最大速度")]public float maxSpeed; // ゲージの最大速度
[Header("ゲージの加速")]public float acceleration; // ゲージの加速
[Header("ゲージの最大値")]public float gaugeMax = 100.0f; // ゲージの最大値
[Header("成功の閾値")]public float successThreshold = 95.0f; // 成功の閾値
[Header("大成功の閾値")]public float greatSuccessThreshold = 98.5f; // 大成功の閾値
[Header("成功時のスコア")]public int successScore = 100; // 成功時のスコア
[Header("大成功時のスコア")]public int greatSuccessScore = 300; // 大成功時のスコア
[Header("コンボボーナス")]public int comboBonus = 100; // コンボボーナス
[Header("スーパーコンボの閾値")]public int[] comboThresholds = { 10, 20, 30 }; // コンボの閾値
[Header("スーパーコンボ時のスコア")]public int[] comboScores = { 5000, 50000, 100000 }; // コンボ時のスコア
[Header("失敗効果音")] public AudioClip missSe;
[Header("成功効果音")] public AudioClip successSe;
[Header("大成功効果音")] public AudioClip greatSuccessSe;
[Header("スコアテキスト")] public TextMeshProUGUI scoreText;
[Header("ハイスコアテキスト")] public TextMeshProUGUI highScoreText;
[Header("コンボテキスト")] public TextMeshProUGUI comboText;
[Header("コンボテキスト(ゲームオブジェクト)")] public GameObject comboTextGameObject;
[Header("コンボボーナス(ゲームオブジェクト)")] public GameObject comboBonusGameObject;
[Header("バー画像")]public Image barImage;
[Header("霊夢画像")] public Image reimuImage;
[Header("魔理沙画像")] public Image marisaImage;
[Header("霊夢通常")]public Sprite reimuNormal;
[Header("霊夢成功")]public Sprite reimuSuccess;
[Header("霊夢失敗")]public Sprite reimuMiss;
[Header("魔理沙通常")]public Sprite marisaNormal;
[Header("魔理沙成功")]public Sprite marisaSuccess;
[Header("魔理沙失敗")]public Sprite marisaMiss;
[Header("ボタンカバー")] public GameObject buttonCover;
[Header("ハート")] public GameObject[] heartObjects;
[Header("ゲームオーバーパネル")] public GameObject gameOverPanel;
[Header("ポーズボタン")] public GameObject pauseButton;
[Header("大成功テキスト")] public GameObject greatText;
[Header("成功テキスト")] public GameObject successText;
[Header("失敗テキスト")] public GameObject missText;
[Header("BGM")] public AudioClip bgm;
private float startSpeed;//スタート時のスピード
private int currentCombo = 0;// 現在のコンボ数
private int highScore = 0;//ハイスコア
public int totalScore = 0; // 総スコア
private bool isIncreasing = true; // ゲージの増加フラグ
private bool isPressing;//ボタンが押されているか
private int life; //ライフ数
private void Start(){
Time.timeScale = 1;//タイムスケールを元に戻す
startSpeed = gaugeSpeed;
highScore = ES3.Load<int>("HIGHSCORE",0);//ハイスコアをロード
highScoreText.text = "HIGHSCORE:" + highScore;//ハイスコアテキスト更新
scoreText.text = "SCORE:" + 0;//スコアテキストを0に
buttonCover.SetActive(false);//ボタンカバーを消す
life = 3; //ライフを3にする
currentCombo = 0;//現在のコンボ数を0に
SoundManager.instance.PlayBgm(bgm);//BGM再生
}
private void Update(){
if(life <= 0)return;//ライフが0なら以下のUpdate内の処理を行わない
//増減フラグがオンなら
if (isIncreasing){
//ゲージを増やす
barImage.fillAmount += gaugeSpeed/gaugeMax * Time.deltaTime;
//ゲージが最大になると
if (barImage.fillAmount == 1.0f){
isIncreasing = false;//増減フラグをオフにする
}
}else{
//ゲージを減らす
barImage.fillAmount -= gaugeSpeed/gaugeMax * Time.deltaTime;
//ゲージが最低になると
if (barImage.fillAmount == 0.0f){
isIncreasing = true;//増減フラグをオンにする
}
}
//ボタンが押されたとき
if (isPressing){
//バーが大成功の閾値以上だと大成功
if (barImage.fillAmount*gaugeMax >= greatSuccessThreshold){
currentCombo++;//コンボ数プラス
//スコア計算
totalScore += greatSuccessScore + currentCombo * comboBonus;
//ゲージスピードが最大以下なら、ゲージスピードを加速する
if (gaugeSpeed < maxSpeed){
gaugeSpeed += acceleration;
}
//霊夢と魔理沙の画像を差し替える
reimuImage.sprite = reimuSuccess;
marisaImage.sprite = marisaSuccess;
//効果音
SoundManager.instance.PlaySe(greatSuccessSe);
//テキスト表示
greatText.SetActive(true);
//コンボ数が1より大きい場合は
if (currentCombo>1){
//コンボテキストを表示
comboTextGameObject.SetActive(true);
//コンボの内容をテキストを更新
comboText.text = currentCombo + "COMBO!";
//コンボ数が、スーパーコンボの配列内にあるかチェック
var result = Array.IndexOf(comboThresholds, currentCombo);
//Array.IndexOf(配列、探したい要素)で配列内に探したい要素がない場合は-1が返ってくる
if (result != -1) {//ー1ではない場合=スーパーコンボの配列内に現在のコンボ数があった場合
comboBonusGameObject.SetActive(true);//コンボボーナスオブジェクトを表示
//スーパーコンボの計算は後に行う
}
}
}
//バーが成功の閾値以上だと成功
else if (barImage.fillAmount*gaugeMax >= successThreshold){
totalScore += successScore;
if (gaugeSpeed < maxSpeed){
gaugeSpeed += acceleration;
}
reimuImage.sprite = reimuSuccess;
marisaImage.sprite = marisaSuccess;
SoundManager.instance.PlaySe(successSe);
successText.SetActive(true);
currentCombo = 0;//コンボ数はリセット
}
else{//バーが成功の閾値未満だと失敗
reimuImage.sprite = reimuMiss;
marisaImage.sprite = marisaMiss;
SoundManager.instance.PlaySe(missSe);
missText.SetActive(true);
life--;//ライフを減らす
currentCombo = 0;//コンボ数をリセット
heartObjects[life].SetActive(false);//ハートオブジェクトを減らす
//ライフが0になるとゲームオーバー
if (life==0){
GameOver();
}
}
//スーパーコンボの特別なスコア加算
for (int i = 0; i < comboThresholds.Length; i++){
//現在のコンボ数がスーパーコンボの閾値配列の中にあれば
if (currentCombo == comboThresholds[i]){
//現在のスコアにスーパーコンボボーナスが入る
totalScore += comboScores[i];
break;//一致したので、これ以上for文は回さない
}
}
scoreText.text = $"SCORE:{totalScore}";//スコアテキストを更新
isPressing = false;//ボタンが押されているフラグをオフにする
}
}
//ボタンがクリックされたとき
public void OnClick(){
if (!isPressing){//ボタンが押されているフラグがオンではないなら
isPressing = true;//ボタンが押されているフラグをオンにする
buttonCover.SetActive(true);//ボタンカバーを表示する
Invoke(nameof(OnClicked),1.0f);//1秒後にOnClickedメソッドを実行
}
}
private void OnClicked(){
//ボタンカバーとテキスト類を非表示にする
buttonCover.SetActive(false);
comboTextGameObject.SetActive(false);
comboBonusGameObject.SetActive(false);
successText.SetActive(false);
missText.SetActive(false);
greatText.SetActive(false);
//霊夢と魔理沙の画像を普通の表情に戻す
reimuImage.sprite = reimuNormal;
marisaImage.sprite = marisaNormal;
}
//ゲームオーバー時
private void GameOver(){
buttonCover.SetActive(true);//ボタンカバーを表示
//現在のスコアがハイスコアより高いなら
if (totalScore > highScore){
//現在のスコアをハイスコアとして記録
ES3.Save<int>("HIGHSCORE",totalScore);
}
//オンラインランキング呼び出し
naichilab.RankingLoader.Instance.SendScoreAndShowRanking (totalScore);
pauseButton.SetActive(false);//一時停止ボタンを非表示
gameOverPanel.SetActive(true);//ゲームオーバーパネルを表示
}
}
↓DOTweenPro持ってるのに、全然活用できてないから今回こそはやろうと思ったのに結局できんかった…
https://learning.unity3d.jp/5872/
↓このエディタ拡張もやりたい