//tips
//一部が透過するsubcamの描画修正
カメラの描画の前後関係は深度情報に基づいて行われる。
すでに手前にレンダリングされている場合はレンダリングしない、そうでなければレンダリングして深度情報も更新し、基本的には遠くにあるオブジェクトから順に描画される。
マテリアルの Render Queue の数字が小さいと先、大きいと後の描画順になる。
http://klabgames.creative.blog.jp.klab.com/archives/22266460.html
Subcameraをプレイヤーの子要素から外し、ステージ全体の描画に変更。
subcameraカメラ操作が不要になったので、操作ボタンの非表示化、操作ボタンに関係する表示スクリプトの変更、テキスト変更。
//playstage = PlayerPrefs.SetInt設置場所確認
Unityで動作確認していた際にplaystage = PlayerPrefs.SetInt設置場所がどこか分からなくなったので確認。
Stageselect画面のボタンに下記が実行されるように組み込まれており、ボタンを押して、押したボタンの番号を前回のplaystageとして記録していた。
public void PlayStage(int No)
{
PlayerPrefs.SetInt("playstage", No);
}
なので、unityのstageごとの動作確認を行い、stageselect画面に戻ってきても、そのstage情報は記録されないことになる。
//goalの位置移動
Goalの位置をゲーム進行中に移動させる。
このゲームの難易度に影響するものに視野の確保がある。そのためゴールも視野外に突如移動する可能性を示唆する。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TrickGoal : MonoBehaviour
{
[SerializeField] GameObject test;
[SerializeField] GameObject test1;
int count = 0;
void Update()
{
if (Input.anyKeyDown)
{
count++;
}
if (count == 0)
{
//ゲームオブジェクト表示→非表示
test.SetActive(true);
test1.SetActive(false);
}
if (count == 6)
{
//ゲームオブジェクト表示→非表示
test.SetActive(false);
test1.SetActive(true);
}
}
}
//goalとgameoverの時間差の解消
Goalのシーンへ移行する場合、Invoke("Goal", 0.0f);で、gameoverのシーンへ移行する場合、Invoke("Over", 1);とすると、被弾中に強引にgoalすることでgoalsceneへと移行することができる。
プレイヤーの移動を止めるためthis.Player.SetActive(false);をFadeover();発生タイミングで実行する。
以前まではカメラが子要素にあったため制御が難しかったが、既にカメラは両方とも子要素から外れているためthis.Player.SetActive(false);を組み込んでもゲーム進行に影響は出なくなった。
ただ、下記のエラー自体は発生している。
NullReferenceException: Object reference not set to an instance of an object
スクリプトを消してもエラーが出続けたがunityを再起動したら治った。
このエラーが気持ち悪いので、操作ボタンの方を押せなくする方法も考えた。
下記を追加して操作してみたところ若干のタイムラグがあるのとenemyごとにボタンを設定するのが面倒なので保留にした。
using UnityEngine.UI;
[SerializeField] Button Bleft;
[SerializeField] Button Bright;
[SerializeField] Button Bup;
[SerializeField] Button Bdown;
Bleft.interactable = false;
Bright.interactable = false;
Bup.interactable = false;
Bdown.interactable = false;
結局、一番簡単なInvoke("Goal", 1);にすることで処理をした。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class GoalController : MonoBehaviour
{
[SerializeField] GameObject Fade;
GameObject Player;
public int stageNo;
void Start()
{
this.Player = GameObject.Find("Player");
}
void Update()
{
Vector3 p1 = transform.position;
Vector3 p2 = this.Player.transform.position;
if (p1 == p2)
{
Fadeover();
if (Player != null)
{
Invoke("Goal", 1.0f);
}
}
}
void Goal()
{
if (PlayerPrefs.GetInt("CLEAR,0") < stageNo)
{
PlayerPrefs.SetInt("CLEAR", stageNo);
}
SceneManager.LoadScene("Goal");
}
void Fadeover()
{
Fade.SetActive(true);
}
}
//enemyの遠距離攻撃設定
遠距離の攻撃を行うenemyを作成する。
Instantiateを使用する必要もなかったので、enemyとbullet、bullet判定のオブジェクトを分けて作成した。
Enemyは動かす必要がなかったので、汎用性がある、当たり判定はあるが、その場から動かないスクリプトをアタッチ。
bulletは、このシーン用に、カウントごとに場所移動をするスクリプトをアタッチした。
Playerのy座標が-0.5であるため、bulletと当たり判定用の空オブジェクトであるbulletに分けて作成した。
Bullet2つのスクリプトは同じものをアタッチしてあるが、当たり判定用の初期位置はy=-0.5となっている。
これは座標一致で当たり判定とする設定のため。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class EnemyCBullet : MonoBehaviour
{
[SerializeField] GameObject Fade;
GameObject Player;
//Animator anim;
Vector3 MOVEX = new Vector3(1.0f, 0, 0);
Vector3 MOVEY = new Vector3(0, 1.0f, 0);
Vector3 MOVEZ = new Vector3(0, 0, 1.0f);
Vector3 target; // 入力受付時、移動後の位置を算出して保存
private int count = 0;
void Start()
{
target = transform.position;
this.Player = GameObject.Find("Player");
}
void Update()
{
if (Input.anyKeyDown)
{
count++;
if (count == 1)
{
target = transform.position + MOVEZ;
}
if (count == 2)
{
target = transform.position + MOVEZ;
}
if (count == 3)
{
target = transform.position + MOVEZ;
}
if (count == 4)
{
target = transform.position + MOVEZ;
}
if (count == 5)
{
target = transform.position + MOVEZ;
}
if (count == 6)
{
target = transform.position + MOVEZ;
}
if (count == 7)
{
target = transform.position - MOVEZ * 6;
count = 0;
}
}
Move();
Vector3 p1 = transform.position;
Vector3 p2 = this.Player.transform.position;
if (p1 == p2)
{
Fadeover();
if (Player != null)
{
Invoke("Over", 1);
}
}
}
void Move()
{
this.transform.position = target;
}
void Over()
{
SceneManager.LoadScene("GameOver");
}
void Fadeover()
{
Fade.SetActive(true);
}
}
Forで短縮しても良いが、カウントごとに修正を入れる変形版を別シーンで作成する可能性が高いため、現在は全て記載している。
//enemyの大規模攻撃への対応
Enemyの大規模攻撃は攻撃の発生をコントロールするスクリプトと攻撃発生時に衝突判定を与えるスクリプトの二つを利用する。
攻撃発生時に衝突反応を与えるスクリプトは、enemyがその場から動かないスクリプトをそのまま流用できる。エフェクトにこのスクリプトをアタッチした空オブジェクトを子要素として追加すれば良い。
発生をコントロールするスクリプトは下記とした。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemymany : MonoBehaviour
{
[SerializeField] GameObject fire1;
[SerializeField] GameObject fire2;
[SerializeField] GameObject fire3;
[SerializeField] GameObject fire4;
[SerializeField] GameObject fire5;
[SerializeField] GameObject fire6;
int count = 0;
void Update()
{
if (Input.anyKeyDown)
{
count++;
}
if (count == 0)
{
//ゲームオブジェクト表示→非表示
fire1.SetActive(true);
fire2.SetActive(true);
fire3.SetActive(true);
fire4.SetActive(true);
fire5.SetActive(true);
fire6.SetActive(true);
}
if (count == 3)
{
//ゲームオブジェクト表示→非表示
fire1.SetActive(false);
fire2.SetActive(false);
fire3.SetActive(false);
fire4.SetActive(false);
fire5.SetActive(false);
fire6.SetActive(false);
}
if (count == 6)
{
count = 0;
}
}
}