ピンを置き直したり、倒れたピンを取り除くピンセッターの動きをスクリプトで作ってみました。
ピンを置く機械の動きは、Youtubeでボーリングの動画を見ながら表に書いて整理しました。
表にすると思ったよりシンプルでした。閉じたバーが後ろに下がって倒れたピンを排除する動きは結局毎回入ります。あとは、表を見ながらif文の条件を作るだけなので簡単です。
普通の決定表で良かったです。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class GameScript3 : MonoBehaviour
{
public Text text;
public Text text2;
GameObject[] pins;
public float q = 0.01f;
Animator pinsetterAnimator;
public Animator barAnimator;
public GameObject pinsetter;
bool setpin = false;
// スコアを入れるリスト
List<int> playerPins;
List<int> npcPins;
public GameObject bowling_pin; // ピンのプレハブ
public GameObject leadingPin; // 新しく作るピンの先頭の位置を教える空のゲームオブジェクト
// Start is called before the first frame update
void Start()
{
text.text = "";
pinsetterAnimator = pinsetter.GetComponent<Animator>();
playerPins = new List<int>();
npcPins = new List<int>();
text2.text = "FRAME 1";
}
// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(KeyCode.R))
{
SceneManager.LoadScene("Bowling");
}
}
void CountStandingPins()
{
pins = GameObject.FindGameObjectsWithTag("Pin"); //「Pin」タグのついたオブジェクトを探して、全て配列pinsにいれる
setpin = true;
StartCoroutine("SetPin", pins);
}
IEnumerator SetPin()
{
barAnimator.SetTrigger("barTrig"); // バーが降りる
yield return new WaitForSeconds(2f);
// 立っているピンの数を数える
int n = 0;
foreach (GameObject pin in pins)
{
if (pin.transform.rotation.x * pin.transform.rotation.x < q && pin.transform.rotation.z * pin.transform.rotation.z < q)
{
n++;
}
}
text.text = n.ToString();
playerPins.Add(10 - n); // 倒れたピンの数をリストに追加
if(playerPins.Count % 2 == 1 && n == 0)
{
playerPins.Add(-1); // 1投目でストライクのときは2投目は無いので、配列にその分の -1 を入れて要素数を調整する。
}
if (playerPins.Count % 2 == 1 && playerPins[playerPins.Count - 1] < 10) // 1投目で、ストライク以外の時
{
pinsetterAnimator.SetTrigger("Pinsetter"); // 天井が降りる
foreach (GameObject pin in pins)
{
if (pin.transform.rotation.x * pin.transform.rotation.x < q && pin.transform.rotation.z * pin.transform.rotation.z < q)
{
pin.GetComponent<Rigidbody>().isKinematic = true; // 立っているピンの動きを止める。
}
}
yield return new WaitForSeconds(1.7f);
text.text = "";
foreach (GameObject pin in pins)
{
if (pin.transform.rotation.x * pin.transform.rotation.x < q && pin.transform.rotation.z * pin.transform.rotation.z < q)
{
pin.transform.parent = pinsetter.transform; // 立っているピンを天井の子オブジェクトにする。
}
}
pinsetterAnimator.SetTrigger("Pinsetter"); // 天井が上がる
}
else {
yield return new WaitForSeconds(1.7f);
text.text = "";
}
yield return new WaitForSeconds(1f);
barAnimator.SetTrigger("barTrig"); // バーがピンを排除
yield return new WaitForSeconds(0.6f);
if (playerPins.Count % 2 == 0 || playerPins[playerPins.Count - 1] == 10) // 2投目のときまたは、ストライクかスペアのとき
{
// 今あるピンを全て削除
foreach (GameObject pin in pins)
{
Destroy(pin);
}
SetNewPins(leadingPin.transform, 0.7f, 4);// 新しいピンを作る
foreach (GameObject pin in GameObject.FindGameObjectsWithTag("Pin"))
{
pin.GetComponent<Rigidbody>().isKinematic = true; // 物理で動かないようにする
pin.transform.parent = pinsetter.transform; // ピンを天井の子オブジェクトにする
}
}
//yield return new WaitForSeconds(1f);
pinsetterAnimator.SetTrigger("Pinsetter"); // 天井が降りる
yield return new WaitForSeconds(1.5f);
foreach (GameObject pin in GameObject.FindGameObjectsWithTag("Pin"))
{
if (pin.transform.rotation.x * pin.transform.rotation.x < q && pin.transform.rotation.z * pin.transform.rotation.z < q)
{
pin.transform.parent = null; // 立っているピンと天井の親子関係を解く
pin.GetComponent<Rigidbody>().isKinematic = false;
}
}
barAnimator.SetTrigger("barTrig"); // バーが上がる
pinsetterAnimator.SetTrigger("Pinsetter"); // 天井が上がる
yield return new WaitForSeconds(0.7f);
if (playerPins.Count % 2 == 0)
{
text2.text = "";
}
yield return new WaitForSeconds(0.4f);
//yield return new WaitForSeconds(1.1f);
setpin = false;
//yield return new WaitForSeconds(0.5f);
text2.text = "FRAME " + (playerPins.Count / 2 + 1);
}
private void OnTriggerEnter(Collider other)
{
if (other.tag == "Ball" && !setpin)
{
CountStandingPins();
}
}
/*
void GenerateNewPins()
{
Vector3[] newPinsPos = {
new Vector3(-42.29f, 1.318f, 0.0493f),new Vector3(-42.85f, 1.318f, 0.42f),new Vector3(-42.85f, 1.318f, -0.35f),
new Vector3(-43.34f, 1.318f, 0.79f),new Vector3(-43.34f, 1.318f, 0.02f),new Vector3(-43.34f, 1.318f, -0.769f),
new Vector3(-43.86f, 1.318f, 1.178f),new Vector3(-43.86f, 1.318f, 0.408f),new Vector3(-43.86f, 1.318f, -0.39f),
new Vector3(-43.86f, 1.318f, -1.16f),};
for(int p = 0; p < 10; p++)
{
Instantiate(bowling_pin, newPinsPos[p],Quaternion.Euler(0f, 0f, 0f));
}
}
*/
void SetNewPins(Transform t, float interval, int line_total)
{
int line = 0; // 行
int column = 1; // 列
for (int o = 0; o < line_total; o++)
{
for (int p = 0; p < column; p++)
{
Vector3 pos = t.position;
// 先頭のピンを基準に位置を変える
pos -= t.forward * (interval * line); // 置く列に合わせて後ろに下げる
pos += t.right * (interval * p - interval / 2 * line); // 左方向に動かす
Instantiate(bowling_pin, pos, Quaternion.Euler(0f, 0f, 0f));
}
line++;
column++;
}
}
}
2回投げるか、ストライクを取ると次のフレームへ進みます。
投げるごとに、残ったピンの数をリストに入れて、その要素数が奇数か偶数かで何投目かを判断しています。途中で順番が入れ替わらないように、ストライクの場合はさらに次の要素に-1を入れて要素数が偶数になるようにします。
yield return new WaitForSeconds()に入れた秒数だけ処理を待ちます。何度か試して値を決めます。
新しいピンを生成するときは、前の記事で作った関数を使っています。
空のゲームオブジェクトを置いて、新しくセットされる先頭のピンの位置を教えます。