登れない坂はただの壁だ
通勤時間は往復4時間半!驚きの遠距離通勤生活!
みたいな番組見て
「は???普通じゃね???」
って思ってしまった往復5時間半通学の六花(ろっか)です。こんばんは。
さて、最近はアクションゲームを作るべく、
壁ずりベクトルを作ってました。
入力は右のまま、
坂道の上では坂に沿って移動するようにする
っていうアレですね。
3D用なだけあって、2Dの外積はないんですよね。
3Dではベクトル、2Dではスカラーになる、憎きあいつです。
というわけで作りました。ベクトルクラス。
キャラの座標とかも、点じゃなくてベクトルで保持したほうが後々便利だしね。
class Vector{
public:
float x,y,z;
Vector(float x = 0.0f, float y = 0.0f, float z = 0.0f):x(x), y(y), z(z) {}
~Vector() {};
static const float GetDotVec(Vector v1, Vector v2); //2つのベクトルの内積を返す
static const float GetCrossVec2(Vector v1, Vector v2); //2つのベクトルの外積を返す(2次元)
static const Vector GetCrossVec3(Vector v1, Vector v2); //2つのベクトルの外積を返す(3次元)
static const float GetVecLen(Vector v); //ベクトルの長さを得る
static const Vector GetUnitVec(Vector v); //ベクトルを正規化
static const Vector VecScale(Vector v, float n); //ベクトルをn倍する
static const Vector GetUnitNormVec2Left(Vector v); //2次元ベクトルの単位法線ベクトルを得る v1×v2 ベクトルの左側の方
static const Vector GetUnitNormVec2Right(Vector v); //2次元ベクトルの単位法線ベクトルを得る v1×v2 ベクトルの右側の方
static const Vector GetUnitNormVec3(Vector v1, Vector v2); //3次元平面の単位法線ベクトルを得る v1,v2は平面上に存在するベクトル
//オペレータ定義
Vector& operator = (const Vector& v) { x = v.x; y = v.y; z = v.z; return *this; }
Vector& operator + (const Vector& v) { return Vector(x + v.x, y + v.y, z + v.z); }
Vector& operator - (const Vector& v) { return Vector(x - v.x, y - v.y, z - v.z); }
Vector& operator += (const Vector& v) { return Vector(x += v.x, y += v.y, z += v.z); }
Vector& operator -= (const Vector& v) { return Vector(x -= v.x, y -= v.y, z -= v.z); }
};
const float Vector::GetDotVec(Vector v1, Vector v2)
{ return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;}
const float Vector::GetCrossVec2(Vector v1, Vector v2)
{ return (v1.x*v2.y) - (v1.y*v2.x);}
const Vector Vector::GetCrossVec3(Vector v1, Vector v2){
Vector Result;
Result.x = v1.y*v2.z - v1.z*v2.y; Result.y = v1.z*v2.x - v1.x*v2.z; Result.z = v1.x*v2.y - v1.y*v2.x;
return Result;
}
const float Vector::GetVecLen(Vector v) { return std::pow(v.x*v.x + v.y*v.y + v.z*v.z, 0.5f);}
const Vector Vector::GetUnitVec(Vector v) {
float len = GetVecLen(v);
Vector Result = v; Result.x /= len; Result.y /= len; Result.z /= len;
return Result;
}
const Vector Vector::VecScale(Vector v, float n) {
Vector Result;
Result.x *= n; Result.y *= n; Result.z *= n;
return Result;
}
const Vector Vector::GetUnitNormVec2Left(Vector v) { //左回りに90度回転してるだけやで☆
Vector Result = v;
float tmpx = Result.x; Result.x = Result.y; Result.y = (-1)*tmpx;
Result = GetUnitVec(Result);
return Result;
}
const Vector Vector::GetUnitNormVec2Right(Vector v) { //こっちは右回りやで☆
Vector Result = v;
float tmpx = Result.x; Result.x = (-1)*Result.y; Result.y = tmpx;
Result = GetUnitVec(Result);
return Result;
}
const Vector Vector::GetUnitNormVec3(Vector v1, Vector v2) {
Vector Result = GetCrossVec3(v1, v2);
Result = GetUnitVec(Result);
return Result;
}
はてブロでソースコードを綺麗に公開してる人ってどうやってるの……
まあこれを使って、
進行ベクトル+坂の法線ベクトル
で壁ずりベクトルが出せる、と。
ただ、「坂に当たった」っていう判定が難しい……
外積を使うと簡単なんだけど、それでは「線分」じゃなくて「線」との判定なんだよね。
そうすると、坂の延長線上ならどこでもヒットしてしまう。
線分と点の当たり判定は内積でやるんだけど、
v1・v2=|v1||v2|cosθ=|v1||v2|
この条件では誤差で全くヒットしない。
今は誤差範囲を設定してなんとか動いたけど、
やっぱり入力方向によっては坂をすり抜ける……
まあピクセル単位でやってりゃそうなるわな、って感じですが。
なんかいい方法ないかなー。
まだ重力もつけてないので、
まだまだ改良の余地あり、ですかね。
ちなみに上に乗せたコード、
プログラミング始めて半年の学生が書いたコードということにご注意ください。
おかしなところあればコメントくださるとうれしいです!
まだクラス内関数の勉強も足りないなー
constとかstaticを関数につけた時の効果とかあいまいだし……
先は長いなぁ
話も長くなったので今日はこれにて。