アイテムと武器の変更

0 コメント


難しいところが出てきて、ちょっとやる気が減ってたというのもちょこっとあるけど、仕事が忙しかったのでなかなか進まなかった。

PowerUp          アイテムのActor、これを継承する
DoubleLaserPowerUp  武器強化のアイテム
DoubleLaserWeapon   弾2個分 同時に生成する武器

単純に弾を2個同時につくっているのにびっくりした。 さらなる弾強化の3つ同時も同様にやる。
貫通レーザーとかも、当たった時に消さずにそのまま残すだけでできそう。

この武器変更の仕組みはシューティングで使いまわせそう。


ここまでのプロジェクト(205K

アステロイド追加

0 コメント

アステロイドActorを追加。
新しい種類のActorの追加のやり方がわかる。これで、敵の種類が増えても大丈夫。
追加の際に、重ならないように出現場所をWorldクラスのFindSpawnPoint()であいてる場所を探す。
衝突判定後、AdjustVelocities()でActorの速度を調整する。
しかしこれが難しくてわからない。
円の衝突をモデル化すると、衝突時、ぶつかり合う円の中心同士を結んだベクトルがあり、衝突面は、このベクトルに直行したものになる。衝突面に対して、入射角度と反射角度は同じになるので、衝突面方向、中心同士を結んだ方向に速度の成分を分けて考える。というぐらいまでで、どうしてこういう計算になるんだろうか?

ここはとりあえずわからないので飛ばす。やっぱりわからんとこ出てきたなあ。

ここまでのプロジェクト(205KB

private static void AdjustVelocities(Actor actor1, Actor actor2) {
 if(actor1.Mass <= 0f || actor2.Mass <= 0f) {
  return;
 }
 Vector2 collisionNormal = Vector2.Normalize(actor2.Position - actor1.Position);
 Vector2 collisionTangent = new Vector2(-collisionNormal.Y, collisionNormal.X);

 float velocityNormal1 = Vector2.Dot(actor1.Velocity, collisionNormal);
 float velocityTangent1 = Vector2.Dot(actor1.Velocity, collisionNormal);
 float velocityNormal2 = Vector2.Dot(actor2.Velocity, collisionNormal);
 float velocityTangent2 = Vector2.Dot(actor2.Velocity, collisionTangent);

 float velocityNormal1New = ((velocityNormal1 * (actor1.Mass - actor2.Mass))
  + (2f * actor2.Mass * velocityNormal2)) / (actor1.Mass + actor2.Mass);
 float velocityNormal2New = ((velocityNormal2 * (actor2.Mass - actor1.Mass))
  + (2f * actor1.Mass * velocityNormal1)) / (actor1.Mass + actor2.Mass);
 actor1.Velocity = (velocityNormal1New * collisionNormal) +(velocityTangent1 * collisionTangent);
 actor2.Velocity = (velocityNormal2New * collisionNormal) +(velocityTangent2 * collisionTangent);
}

当たり判定 線分と円

0 コメント
Actorの持っている円形の領域と線分との当たり判定

学校で習ったベクトルがようやく役にたつとき!



基本的な考え方は、線分ABと点Cを中心とした円を考える。点C線分ABにおろした垂線が、円の中心との最短距離になる。こいつと円の半径を比較して、半径の方が小さかったら当たってない、大きかったらあたっていることになる。また、垂線との交点Hが線分ABの間にないときは、最短距離が、ACになったりBCになったりする。
こんな感じ




この場合はHCよりもACの方が短い。

問題はHCの長さを求める計算だけど、まず点Hの場所をベクトルを使って求める。
ベクトルAHはベクトルABをt倍したものとできるので、tを求めれば場所がわかる。




 という式の変形でtが求められる。
public static bool CircleLineCollide(Vector2 center, float radius,Vector2 lineStart, Vector2 lineEnd, ref CircleLineCollisionResult result) {

 Vector2 AC = center - lineStart;
 Vector2 AB = lineEnd - lineStart;
 float ab2 = AB.LengthSquared();
 if(ab2 <= 0f) {
  return false;
 }
 float acab = Vector2.Dot(AC, AB);
 float t = acab / ab2;

tが負の場合、または1以上の場合は線分ABからはみ出てるので調整する
if(t < 0.0f) {
  t = 0.0f;//点Hが点Aの場所になる
 } else if(t > 1.0f) {
  t = 1.0f;//点Hが点Bの場所になる
 } 

交点は当たり判定通知用の構造体、CircleLineCollisionResultにしまう。

円の半径と、距離を比較して結果を出す。

result.Point = lineStart + t * AB;
 result.Normal = center - result.Point;

 float h2 = result.Normal.LengthSquared();
 float r2 = radius * radius;
 if(h2 > r2) {
  result.Collision = false;
 } else {
  result.Normal.Normalize();
  result.Distance = (radius - (center - result.Point).Length());
  result.Collision = true;
 }

 return result.Collision;
} 
 
きれいに書いてみたかったのでTEXを使ってみた。環境をつくるのがめんどい。
図はGRAPESを使ってみました。使い方が独特だけど、簡単に図形がかけてよい感じ。

弾の発射 Actorの動的な追加

0 コメント


Projectile 射出体(弾)のActor
LaserProjectile 通常弾の実装
Weapon 武器を表す Shipが持っている
LaserWeapon 通常弾の実装

このへんがちょっとわかりにくい。
ProjectileはActorなのでGamePlayScreenが自機と同じようにUpdate()とかDraw()を呼び出してくれる。他のActorと当たった時の処理もここ。
WeaponはUpdate()やDraw()にかかわらない部分、弾の発射間隔のカウントとかをする。 同時発射数が決まってるとかだったらここでやるのだろうか?

だんだん要素が増えてきてしんどい。

ここまでのプロジェクト(190KB