スクリプト一部修正
大砲を合成する所まで出来たわけなんですが、
コライダーが複数接触しているとバグる可能性があると言う事で、
修正が必要になってきました。
コライダーの大きさを調整してみたり、
オフセットを弄ってみたり…
なかなか思うようにいかないものですね~(~ヘ~;)ウーン
そもそも、ドラッグ中は合成しないと言う条件が
厳しかったりします。
OnCollisionで合成処理をすると何かに接触しただけで合成されるので、
コライダーを使わずに重なりを判別する方法…
余計に複雑になりますね~(T^T) ヒック
いろいろと考えてる内に、
ドラッグ中にOnCollisionが働かなければ良いのでは!?
と言う考えに至りまして、処理方法を変える事に…
まず、ドラッグ中にOnCollisionが働かないようにするには、
コライダーが無ければいいので、非アクティブにしてしまえ!
と言う考え方でっす。(^.^) オホホホ
DragScript
private BoxCollider2D boxcoll; //コラインダー取得変数
void Start()
{
boxcoll = this.GetComponent<BoxCollider2D>();
}
//ドラッグ時の処理
private void OnMouseDrag()
{
//ドラッグしたらコライダーを非アクティブにする
boxcoll.enabled = false;
}
//ドロップ時の処理
private void OnMouseUp()
{
//ドロップしたらコライダーをアクティブにする
boxcoll.enabled = true;
}
これでドラッグ中はコライダーが隠れるので、衝突判定は起こりません。
ドロップした際に再度、コライダーをアクティブにすれば、
衝突判定を利用できるので、問題ないかと思います。
さて、こうなるとOnCollisionも通常の衝突判定が使えるので、
OnCollision内でプレハブの生成が出来るようになるのですが…
問題点があります。
Collisionは、衝突した二つの大砲から呼び出されるので、
プレハブが二つ生成される事になります。
同じ物が二つ生成されるので、呼び出されると同時に合成が発生して、
プレハブが無くなるまで合成され続けます。
以前どこかで似た現象が起きたような…(- .-)ヾ ポリポリ
なので、合成処理も作り直す必要がでてきました。
OnCollisionで衝突を判断して、その信号を受け取るスクリプトを用意すれば、
プレハブ生成も一度で済みます。
新しくスクリプトを組んで、プレハブの管理と生成をさせてみます。
Reproduction
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Reproduction : MonoBehaviour
{
//各種プレハブ
public GameObject[] WCannon;
public GameObject[] Bcannon;
public GameObject[] RCannon;
public GameObject[] YCannon;
public GameObject[] GCannon;
//呼び出しカウント変数
private int i = 0;
//各大砲の生成メソッド
public void RepCannonn(Vector3 pos,int Lv,string color)
{
i++;
GameObject cannon=null;
//呼び出しカウントが2回目なら生成する
if (i == 2)
{
//色別の大砲判定
if (color == "White") cannon = (GameObject)Instantiate(WCannon[Lv]);
if (color == "Blue") cannon = (GameObject)Instantiate(Bcannon[Lv]);
if (color == "Red") cannon = (GameObject)Instantiate(RCannon[Lv]);
if (color == "Yellow") cannon = (GameObject)Instantiate(YCannon[Lv]);
if (color == "Green") cannon = (GameObject)Instantiate(GCannon[Lv]);
//ペアレント・生成座標・表示レイヤーの指定
cannon.transform.SetParent(this.gameObject.transform, false);
cannon.transform.localPosition = pos;
cannon.transform.SetSiblingIndex(0);
//呼び出しカウントリセット
i = 0;
}
}
}
少し説明すると
大砲のOnCollisionからアクセスするので、大砲の情報が必要になります。
生成座標、大砲レベル、色の情報がないと判別できないので、
メソッドの引数に設定しました。
OnCollisionは二つあるので、カウントして2回目の時だけ生成します。
この辺りは、1回目の呼び出しで生成してもかまわないです。
このスクリプトを設置フィールドにアタッチします。

アタッチが出来たらプレハブ変数に各プレハブをアタッチします。
この時に

要素0を空けて、要素1から順にプレハブをアタッチします。
プレハブの準備ができたので、OnCollisionからアクセスできるように
DragScriptを修正します。
DragScript
private Reproduction rep; //プレハブ複製スクリプト
public int level; //大砲のレベルを設定
public string color; //大砲の色を設定
void Start()
{
if (SetField == null) SetField = transform.parent.gameObject;
rep = SetField.GetComponent<Reproduction>();
if (boxcoll.enabled == false) boxcoll.enabled = true;
}
//何かのRigidbodyに接触したら
private void OnCollisionEnter2D(Collision2D collision)
{
//接触したRigidbodyが同じタグなら
if (collision.gameObject.tag == this.tag)
{
rep.RepCannonn(pos, level, color);
Destroy(this.gameObject);
}
}
Reproductionスクリプトを取得する際、設置フィールドが取得できてないと
エラーが出るので、必ず設置フィールド取得後にGetComponentして下さい。
if (boxcoll.enabled == false) boxcoll.enabled = true;を追加してますが、
後ほど説明します。
RepCannonnメソッドに送る情報が必要になるので、
level、colorの変数を追加して、インスペクターから設定しておきます。

プレハブにも同様にレベルと色を設定します。
ここまで来れば合成ができるようになったのですが、
新しい問題点が…
Cellから大砲をドラッグした際、複製が作成されなくなります。
何故かと言うと、大砲をドラッグした際、コライダーを非アクティブ化するので、
複製された大砲は、コライダーがOFFになったまま複製されます。
コライダーがOFFだと、CellのOnTriggerが働かず複製されない状況になります。
そこで
if (boxcoll.enabled == false) boxcoll.enabled = true;
です。
複製が出来た時にコライダーをONにする為に追加しました。
これで合成ができるようになったので、テストしてみます。
再生できない場合、ダウンロードは🎥こちら
Lv1の中間でドロップしても移動先で合成が行われているので、
問題ないかと思います。
スクリプトがややこしくなってきたので、ドロップ時の位置決めや移動処理も
カプセル化して、整理してみます。
DragScript
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DragScript : MonoBehaviour
{
public GameObject cannonParent; //大砲Parent
public GameObject SetField; //設置フィールド
private Reproduction rep; //プレハブ複製スクリプト
private BoxCollider2D boxcoll; //コライダー取得変数
public int level; //大砲のレベルを設定
public string color; //大砲の色を設定
private float constantZ; //ドラッグ時のZ座標
private Vector3 pos; //大砲の座標
//設置フィールドデータ
private const int pitch = 100; //フィールドのマス目のピッチ
private const int Xmax = 300; //フィールドのX座標上限
private const int Xmin = -300; //フィールドのX座標下限
private const int Ymax = 200; //フィールドのY座標上限
private const int Ymin = -200; //フィールドのY座標下限
void Start()
{
if (SetField == null)
SetField = transform.parent.gameObject;
constantZ = transform.position.z;
rep = SetField.GetComponent<Reproduction>();
boxcoll = GetComponent<BoxCollider2D>();
if (boxcoll.enabled == false)
boxcoll.enabled = true;
}
//ドラッグ時の処理
private void OnMouseDrag()
{
//大砲Parentの子なら設置フィールドに移行する
if (transform.parent.gameObject == cannonParent)
transform.SetParent(SetField.transform, false);
//ドラッグしたらコライダーを非アクティブにする
boxcoll.enabled = false;
//マウスポイントの取得と座標代入
Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
mousePos.z = constantZ;
transform.position = mousePos;
transform.SetSiblingIndex(99);
}
//ドロップ時の処理
private void OnMouseUp()
{
Positioning();
PositionMatch();
//ドロップしたらコライダーをアクティブにする
boxcoll.enabled = true;
}
//設置フィールド内のマス目座標に修正する
private void Positioning()
{
pos.x = Mathf.Clamp(Rounding(transform.localPosition.x), Xmin, Xmax);
pos.y = Mathf.Clamp(Rounding(transform.localPosition.y), Ymin, Ymax);
}
//マス目に合わせて移動させる
private void PositionMatch()
{
transform.localPosition = pos;
transform.SetSiblingIndex(0);
}
//ドロップ時の座標を四捨五入(六捨五入)する
private int Rounding(float axis)
{
float dec = axis / pitch;
float centi = 0;
int conf = 0;
//座標が正の数値なら四捨五入
if (axis >= 0)
{
centi = (dec - Mathf.FloorToInt(dec));
if (centi >= 0.5) conf = Mathf.CeilToInt(dec) * pitch;
if (centi < 0.5) conf = Mathf.FloorToInt(dec) * pitch;
}
//座標が負の数値なら六捨五入
else
{
centi = (dec - Mathf.CeilToInt(dec));
if (centi >= -0.5) conf = Mathf.CeilToInt(dec) * pitch;
if (centi < -0.5) conf = Mathf.FloorToInt(dec) * pitch;
}
return conf;
}
//何かのRigidbodyに接触したら
private void OnCollisionEnter2D(Collision2D collision)
{
//接触したRigidbodyが同じタグなら
if (collision.gameObject.tag == this.tag)
{
rep.RepCannonn(pos, level, color);
Destroy(this.gameObject);
}
}
}
この記事へのコメント