第十二話 弾が出たり散ったり & 弾痕の実装
ハウディーーーー!
アレがこうなりました。
なので、なんか書こうと思います。
弾が出る
大体何書いても弾出ると思うんで適当で良いと思います。今回は銃口が1つだったり2つだったりに対応できるようにしてあるけどそれくらい。以下は左手から弾出すやつ。プレイヤーキャラに装着するスクリプトの中に書く。
public float leftArmFireRate = 0.1f;//発射間隔
private float leftArmTime = 65535f;//左手用のTime
public GameObject leftArmBullet;//出す弾
public Transform leftArmBulletSpawnPos1, leftArmBulletSpawnPos2;//弾出る位置
void LeftArmFire() {//左手から弾出る
if(Input.GetMouseButton(0)) {//左クリック中に
if(leftArmTime >= leftArmFireRate) {//TimeがFireRate以上になったら(TimeはUpdate関数内で増えているよ!)
Instantiate(leftArmBullet,leftArmBulletSpawnPos1.transform.position, leftArmBulletSpawnPos1.transform.rotation);//弾が出る
if(leftArmBulletSpawnPos2 != null) Instantiate(leftArmBullet, leftArmBulletSpawnPos2.transform.position, leftArmBulletSpawnPos2.transform.rotation);//銃口2が無ではない時、弾が出る
leftArmTime = 0;//Timeをリセット
}
}
}
こっちは弾に装着するスクリプト。Start関数でRigidbodyにAddForceすれば生まれた瞬間に飛んでく。Speedはお好みで。
public float Speed = 65535f;//弾速
void Start() {
gameObject.GetComponent<Rigidbody>().AddForce(transform.forward * Speed, ForceMode.VelocityChange);//力加える
}
こんな感じに書くとこれだけで弾が出て前に飛んでいく。やったね!
弾が散る
必要だよなあと思ってだいぶ適当に作った。
その1
適当に思いついて作った奴。Scatterの大きさに応じてタテ方向とヨコ方向に力を加えて飛ばす。細かい事を気にしないならこれでもそれっぽく見えるけど…・
public float Scatter = 10f;//飛び散り力
void Start() {
float scatterX = Random.Range(-Scatter, Scatter);//ヨコ方向の飛び散り力をランダムに決定
float scatterY = Random.Range(-Scatter, Scatter); //タテ方向の飛び散り力をランダムに決定
gameObject.GetComponent<Rigidbody>().AddForce(transform.right * scatterX, ForceMode.Impulse);
gameObject.GetComponent<Rigidbody>().AddForce(transform.up * scatterY, ForceMode.Impulse);
gameObject.GetComponent<Rigidbody>().AddForce(transform.forward * Speed, ForceMode.VelocityChange);
}
結果がこれ。四角い!!!!
その2
三角関数を使う。ぼくは数学無理マンなのでググって作った。
public float Scatter = 10f;//飛び散り力
void Start() {
float r = Random.Range(-Scatter, Scatter);
float theta = Random.Range(0, 360);
float scatterX = r * Mathf.Cos(theta);
float scatterY = r * Mathf.Sin(theta); gameObject.GetComponent<Rigidbody>().AddForce(transform.right * scatterX, ForceMode.Impulse);
gameObject.GetComponent<Rigidbody>().AddForce(transform.up * scatterY, ForceMode.Impulse);
gameObject.GetComponent<Rigidbody>().AddForce(transform.forward * Speed, ForceMode.VelocityChange);
}
結果がこれ。丸くなった。
プログラム見りゃ分かる通り、「初弾は真っ直ぐ飛ぶ」だとか「えらく飛び散る奴が出る確率」だとかは実装してない。ゲーム作っていく内に必要そうなら加えるかもしれない。
弾痕を出す&くっつける
こちらの記事を参考にして作りました。
弾痕はこれ。Spriteです。
弾痕オブジェクトを当たった物体の子にする事でくっ付けてる。
親と子のスケールの問題があったけど弾痕の元のスケールと親オブジェクトのスケールを使って割り算したら何とかなった。
public GameObject Dankon;//弾痕オブジェクト
public LayerMask mask;//弾痕を表示したくない物体をマスク
public Vector3 defaultScale;//弾痕の元のスケール
void Start() {
defaultScale = Dankon.transform.localScale;//弾痕の元のスケールを取得
}
private void OnCollisionEnter(Collision collision) {
RaycastHit hit;
Ray ray = new Ray(transform.position - transform.forward * 1, transform.forward);
if(Physics.Raycast(ray, out hit, 10f, mask)) {
if(collision.gameObject == hit.transform.gameObject) {
Vector3 BulletHolePos = hit.point + hit.normal * 0.01f;
Quaternion BulletHoleRot = Quaternion.FromToRotation(-Dankon.transform.forward, hit.normal);
GameObject BulletHole = Instantiate(Dankon, BulletHolePos, BulletHoleRot, collision.transform) as GameObject;
float x, y, z;//弾痕の親と弾痕の元のスケールを使って割り算
x = defaultScale.x / BulletHole.transform.parent.transform.localScale.x;
y = defaultScale.y / BulletHole.transform.parent.transform.localScale.y;
z = defaultScale.z / BulletHole.transform.parent.transform.localScale.z; if(collision.gameObject.tag == "Jimen") {//テスト段階では地面が平たい板なので地面に着弾した場合弾痕の高さに地面の奥行を使う(????)
y = z;
}
BulletHole.transform.localScale = new Vector3(x, y, z);
Debug.Log(collision.gameObject.name + " / 弾痕出現!");
Destroy(BulletHole, 1000f);
} else {
Debug.Log(collision.gameObject.name + " / 弾痕出現せず!");
}
}
Destroy(gameObject);
}
これで動いた。もちろん問題もある。オブジェクトの端に着弾した場合弾痕がはみ出る。つらい。解決策が欲しい。
プロジェクターという技を使って弾痕を表示する方法もあるようなので試した方が良い。
以上!おわり!解散!