第十六話 複数のコライダを持つ対象に対する範囲攻撃の実装 with Contains
ハウディーーーーーーーーーーー!!!!!!!!!!!!!
たぶんもうみんな知ってると思うんですけど、ぼくは今更Containsとかいうウルトラスーパー便利機能に感動したので書きます。
過去に作ったRTSに出てくる砲兵の範囲攻撃を実装する際にwhile文か何かをミスってEditorをフリーズさせたりさせなかったりした経験があるので個人的に爆発攻撃の実装はいやだな~って感じなんですけど、ゲームには必須ですよね。どうでもいいですね。
榴弾を作るぞ!
これを作りました。
爆発範囲内に被弾対象のコライダが1つでもあれば1回ダメージが入ります。また、爆発範囲内に被弾対象のコライダが2つ以上あってもダメージは1回しか入りません。
どうしよう
ロボットは複数のコライダを持つ複数の部品で構成されています。Physics.OverlapSphere等を使って爆発範囲内のコライダを取得すると思うんですけど、じゃあ取得した後にどうしよう。
今回はコライダのrootオブジェクトを取得して犠牲者リストにぶち込み、すべてのコライダの処理後に犠牲者リスト内のオブジェクトにダメージを与えるという処理をすることにしました。
コライダの処理
犠牲者リスト.Countが0以下のとき、1つめのコライダのroot.transform.gameObjectが犠牲者リストにAddされます。
2個め以降の処理はどうしよう…for文とかを使ってコライダのrootオブジェクトと犠牲者リスト内のオブジェクトで一致している物があるか調べるのかな?いやだな~と思っていたのですがContainsとかいう便利機能を発見!
ヤバい!お手軽!
Cointainsを使うとリスト内にお望みのブツが含まれているかどうかがすぐに判定できる…何も考えなくて良いんだ…。
詳しくはiPentec様の記事を見てくれ!!!!
List<T>の中に一致する要素があるか判定する (C#プログラミング)
これで簡単にリストの中にコライダのrootオブジェクトが含まれているかがわかります。含まれていなければこのrootオブジェクトをリストに新たに追加します。爆発範囲内に複数の機体が存在している際の処理が簡単に出来るね!
具体的に
Collider[] Colliders = Physics.OverlapSphere(transform.position, Size);
foreach(Collider coll in Colliders) {
if(coll.gameObject.tag == "Player" || coll.gameObject.tag == "Enemy"){
if(HitObjects.Count == 0) {
HitObjects.Add(coll.gameObject.transform.root.transform.gameObject);
} else {
if(HitObjects.Contains(coll.gameObject.transform.root.transform.gameObject)) {
Debug.Log("コライダのルートオブジェクトは既にこの爆風に被弾しています。");
} else {
HitObjects.Add(coll.gameObject.transform.root.transform.gameObject);
}
}
}
}
foreach(GameObject obj in HitObjects) {
AddDamage(obj);
}
的な事を書けばよろしいかとおもいます。
つまり
爆発物を作る際に「リストの中に同じものが入っているかどうか」を調べるハメになった場合、Containsを使うと何も考えずに済むよという話です。おわり。
第十五話 生存報告 & unity1weekに参加した話
おっすおっす!!!!
生存報告です。
unityroom様のunity1週間ゲームジャムに参加したので記事を書くことにしました。
何を作ったのか
バイト地獄 | 無料ゲーム投稿サイト unityroom - Unityのゲームをアップロードして公開しよう
お題が「10」だったのでクソゲーを10個作ろうと思いました。作りました。7日で10個作って合体させるのは普通につらかったので二度とやりません。ぼくの他にもゲーム10個作ってた方が何人か居らっしゃったのでUnityやってる奴どいつもこいつもイカれてんなと思いました。
前回と比べても時間に余裕がなく、心の余裕も失われていたので結果的にクソの山を築いてしまった感は否めません。今後はもう少しマトモな計画を立てたいですね。
以下ゲームの解説です。10個作ったら記事の面倒くささも10倍ですね。
ゲームシステムについて
10個のゲームがランダムな順番に登場します。intのリストとstringのリストを作って、intのリストにゲームの番号を入れstringのリストにシーンの名前を入れ、intのリストをランダムで並べ替えて順番に読み込んでいるだけです。簡単!!!!
登場モデルについて
これまでに作ったゲームに登場したモデルを使いまわしました。続けているとこういう所で良い事がありますね。いくつかのモデルは殺人水上機氏の手によるものです。いつもありがとうございます。
ランキングの実装
超簡単に実装できました!本当にありがとうございます!unityroom万歳!
10秒数えろ!
左クリックするまでの時間を数えて目標タイムとの差を計算してスコアにするだけ。作るのは死ぬほど簡単なのですが労働ちゃんを動かしたかったので無駄に時間がかかっています。
10回だけ押せ!
10回左クリックするまでの時間を記録するだけの簡単なものです。10回クリックした後0.5秒以内に11回目のクリックを行うと死ぬようになっています。
玉をあてろ!
何年経ってもマトモにブロック崩しを作れるようになりません。流石にヤバいと思うので今度ブロック崩しを作る練習をしようと思います。今回は手抜きなので玉が何かにぶつかると減速していきます。角度の計算をして力を失わないようにすべきなのですが何を思ったのか今回の玉は常に回転しているのでうわっこれ面倒くさと思ってやめました。というかものすごく適当に作ってあるのでバーが止まっていようが動いていようが玉をはね返した時の角度が変わっとらん気がします。要するにプレイヤーに出来る事は玉は受けるだけで、やってる事は↓のゲームと変わってないんですよね。しかも玉の発射角度はランダムで微妙に変わるの詰まるところ運ゲーと化しています。クソかな?
弾を防げ!
これ楽しいんだろうかと思って作ったゲームです。10個も作るんだから背に腹は代えられぬと思ってそのまま作りました。楽しいかどうか以前にクソ重くて不快な一作です。遠景やパーティクルを減らすべきでした。
組み立てろ!
WASD⏎を順番に押しまくる爽快な内容です。クソの山の中でも比較的良心的な内容になったと思います。部品をスクリプトで動かしているのでいろいろこんがらがって時間がかかってしまった。このメカが出るゲームを作ってるのでよろしくお願いします。
近づけ!
くるまのゲームを入れる予定だったんですけどモデル作ってる余裕なかったのでこんなん出ました。壁の反射を上手く使いながらドリフトするゲームです。マシンはちょっと浮遊しているの目標との距離は0.1以下にならないという地味なクソポイントがあります。
生きのびろ!
見下ろし型シューティングゲームを作ってみたかったので作った。まあまあ楽しいのでこれ一本でやればよかった。
拾え!
何故食品を拾っているのかは謎です。当初は食品から湯気のエフェクトをパーチクルをつかって出していたのですが重すぎたので止めました。かなり単純なゲームですが取得物の名前を浮き出させる等の実装に挑戦しており少し苦しんだ記憶があります。
飛べ!
トラパーで前が見えねえ!もうちょい簡潔なコースにすべきだったというか、そもそもこの内容のゲームをミニゲーム集に突っ込むべきだったのかという疑問が残るゲームです。
答えろ!
今更ながら文字入力をする要素を実装してみました。それだけ。
その他
開発中にマリオパーティかな?というお声を頂きましたが、どちらかというと本作はワイルドアニマルスポーツデイ(野生動物運動会)にインスパイアされています。
さいごに
以上!
第十四話 生存報告②
ハウディー!(生存報告)
被災地のいち早い復興と亡くなられた方のご冥福をお祈り申し上げます。
unityroom様の
Unity 1週間ゲームジャム | 無料ゲーム投稿サイト unityroom - Unityのゲームをアップロードして公開しよう
に出ました。
これです
アツクテシヌデチ | 無料ゲーム投稿サイト unityroom - Unityのゲームをアップロードして公開しよう
プレイ動画
開発に関する記事でも書こうかと思いましたが大した事はしていないのとマラッカ海峡とセイロン島の平定、さらにライン演習作戦への参加などで忙しいので多分書きません。需要があれば書くかもしれないので気になるところあったら聞いてね。
大したゲームではないのですが29時間くらい停電したのを徹夜でなんとかして納期ギリギリで上げたクソゲーなのであそんでほしい。
おわり
第十二話 弾が出たり散ったり & 弾痕の実装
ハウディーーーー!
アレがこうなりました。
なので、なんか書こうと思います。
弾が出る
大体何書いても弾出ると思うんで適当で良いと思います。今回は銃口が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);
}
これで動いた。もちろん問題もある。オブジェクトの端に着弾した場合弾痕がはみ出る。つらい。解決策が欲しい。
プロジェクターという技を使って弾痕を表示する方法もあるようなので試した方が良い。
以上!おわり!解散!
第十一話 何をしていたか
ハウディー!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
記事を書こうとは思っていたのですが作業をして満足してしまうので書いていませんでした。何をしていたかというと
これを作って
うごかして
これを作って
こうしました(モデル提供:アトリエ殺人水上機)
今後仕組みについての記事を書いたり書かなかったりするかもしれません。いずれにしても大したことはしていないのであしからず!!!!