Drag&Dropのスクリプト修正
また、いつものサボり癖が発動してしまいました(;^_^A
記事にできる内容もなかったので、
更新ができないと言うかヤル気が無かったと言うか…
(;^o^) \(ToT )あんたほんとにそれでいいの
このままでは、ダメなので少し実験した事を記事にしてみます。
以前、ドラッグについて記事にしたのですが、
オブジェクトを掴んで動かすまでは、作る事ができました。
単純な移動の処理なら問題ないのですが、
ゲームでは、オブジェクトを指定の範囲に置いたり、
同じオブジェクトを合成したり、
オブジェクトをゴミ箱にポイしたり、
実際には、ドロップ時の処理が必要になります。
この辺りを試してみたので、まとめてみたいと思います。
まずは、マス目に合わせてドロップする事を記事にしてみます。
将棋やオセロなんかでは、必要になる処理です。
ジグソーパズルにも使えるかと思います。
まず、マス目のある盤面とドロップするオブジェクトが必要なので、
こんなものを用意してみました。

大砲のオブジェクトとマス目のフィールドを用意してみました。
大砲をドラッグしてフィールド上でドロップすると
ドロップの座標からマス目にハマるように処理を行います。
まずは、大砲をドラッグ操作できるようにスクリプトを組みます。
ドラッグ操作については、
【Unity】ドラッグでオブジェクトを動かしてみる
または、
【Unity】追いかけてくる敵を作ってみる
どちらかを参考にして頂ければいいかと思います。
続いて、オブジェクトの配置なんですが、

フィールドはマス目の背景と大砲を移動させた時の設置フィールドを用意します。

ドラッグする大砲は大砲Parentを用意して保管しておきます。
大砲を設置フィールドに出す際、
大砲Parentから設置フィールドに移行する必要があるので、
ドラッグ処理に修正を加えます。
DragScript
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DragScript : MonoBehaviour
{
public GameObject cannonParent; //大砲Parent
public GameObject SetField; //設置フィールド
private float constantZ; //ドラッグ時のZ座標
// Start is called before the first frame update
void Start()
{
constantZ = transform.z;
}
// Update is called once per frame
void Update()
{
}
//ドラッグ処理
private void OnMouseDrag()
{
//大砲Parentの子なら設置フィールドに移行する
if (transform.parent.gameObject == cannonParent)
transform.SetParent(SetField.transform, false);
//マウスポイントの取得と座標代入
Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
mousePos.z = constantZ;
transform.position = mousePos;
transform.SetSiblingIndex(99);
}
OnMouseDragメソッドの最初にParentの判断を入れて、
大砲Parentの子なら設置フィールドの子に変更します。
これで、設置フィールドの座標を基準にドロップする事ができます。
最後にSetSiblingIndexを入れましたが、
ドラッグ中の大砲が、置いてある大砲の下を通過すると
見た目がおかしくなるので、ドラッグ中は一番上に表示されるようにしています。
ドラッグ処理ができたので、ドロップの処理を考えて行きます。
ドラッグ中の大砲は、座標がマウスポイントに依存しています。
そのままドロップしてもマス目には関係ない位置に止まるので、
マス目の座標に修正する必要があります。
マス目の座標は、設置フィールドの座標そのものなので、
マス目をポジションと捉えます。

ドロップした大砲をポジション化すれば、対応したマス目にハメる事ができます。
ポジション化については、
【Unity】四捨五入を考える
を参考に処理していきます。
ただ、この記事の四捨五入は、正の数のみ対応してるので、
負の数の場合、処理できません。
コードも改良の余地があるので、そのへんを踏まえて
メソッドを考えてみます。
DragScript
//設置フィールドデータ
private const int pitch = 100; //フィールドのマス目のピッチ
//ドロップ時の座標を四捨五入(六捨五入)する
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;
}
少し説明します。
引数axisで渡ってきた座標をマス目のピッチで割ると
ポジションが出せます。
計算したポジション数は、端数が出るので、四捨五入して整数化します。
整数化した数値にピッチを掛けるとマス目の座標になります。
その座標を戻り値にして、大砲の座標に代入すればマス目に合うようになります。
正の数と負の数で処理を変えたのは、
ポジションが1.5の場合、centi = (dec - Mathf.FloorToInt(dec));を使っています。
これは、Mathf.FloorToInt(dec)で1.0が算出されます。
実際は、1.5-1.0=0.5の計算が行われる事になります。
では、ポジションが-1.5だった場合はどうなるかと言うと
-1.5-(-2)=0.5となります。
Mathf.FloorToInt(-1.5)だと切捨ての関数なので、-2になってしまいます。
なので、Mathf.CeilToInt(dec)で切り上げてやります。
centi = (dec - Mathf.CeilToInt(dec));
-1.5-(-1.0)=-0.5となります。
後は、正の数なら四捨五入、負の数なら六捨五入してやれば
マス目のポジションに揃える事ができます。
マス目の座標が計算できたので、ドロップ時に数値を代入していきます。
DragScript
private Vector3 pos; //大砲の座標
//ドロップ時の処理
private void OnMouseUp()
{
//マス目の座標に修正する
pos.x = Rounding(this.transform.localPosition.x);
pos.y = Rounding(this.transform.localPosition.y);
//座標代入
this.transform.localPosition = pos;
this.transform.SetSiblingIndex(0);
}
ドロップ時にtransformを代入してやれば、マス目の座標に移動してくれます。
早速PLAYしてみます。
マス目に上手くハマってくれます。
??

マス目の外にドロップされました。
設置フィールドの範囲を指定するのを忘れてました。
ロボアニメーションの時もやってしまいましたが、
範囲設定って重要ですね。
(゜゜;)\(--;)オイオイ
設置フィールドの範囲を指定して出来た完成版がこちら
DragScript
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DragScript : MonoBehaviour
{
public GameObject cannonParent; //大砲Parent
public GameObject SetField; //設置フィールド
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座標下限
// Start is called before the first frame update
void Start()
{
constantZ = transform.position.z;
}
// Update is called once per frame
void Update()
{
}
//ドラッグ時の処理
private void OnMouseDrag()
{
//大砲Parentの子なら設置フィールドに移行する
if (transform.parent.gameObject == cannonParent)
transform.SetParent(SetField.transform, false);
//マウスポイントの取得と座標代入
Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
mousePos.z = constantZ;
transform.position = mousePos;
transform.SetSiblingIndex(99);
}
//ドロップ時の処理
private void OnMouseUp()
{
//設置フィールド内のマス目座標に修正する
pos.x = Mathf.Clamp(Rounding(transform.localPosition.x), Xmin, Xmax);
pos.y = Mathf.Clamp(Rounding(transform.localPosition.y), Ymin, Ymax);
//座標代入
this.transform.localPosition = pos;
this.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;
}
}
×
この広告は90日以上新しい記事の投稿がないブログに表示されております。
この記事へのコメント