//seg1,2(当たり判定)が線分、outT1,2が線分の内分比、outPosが交点(出力用)
bool CCollision::ColSegments(Segment &seg1, Segment &seg2, float* outT1, float* outT2, Vector2* outPos) {
Vector2 v = seg2.s - seg1.s;
float Crs_v1_v2 = Vector2Cross(&seg1.v, &seg2.v);
if (Crs_v1_v2 == 0.0F) {
return false;
}
float Crs_v_v1 = Vector2Cross(&v, &seg1.v);
float Crs_v_v2 = Vector2Cross(&v, &seg2.v);
float t1 = Crs_v_v2 / Crs_v1_v2;
float t2 = Crs_v_v1 / Crs_v1_v2;
if (outT1)
*outT1 = Crs_v_v2 / Crs_v1_v2;
if (outT2)
*outT2 = Crs_v_v1 / Crs_v1_v2;
const float eps = 0.00001f;
if (t1 + eps < 0 || t1 - eps > 1 || t2 + eps < 0 || t2 - eps > 1) {
// 交差していない
return false;
}
//出力用。
if (outPos)
*outPos = seg1.s + seg1.v * t1;
return true;
}
現在考えている線分を使った坂道のアルゴリズムは、
①坂道のブロックがあるかどうかを確認
②坂道の線分を設定
③プレイヤーの線分を設定
④プレイヤーの線分と坂道の線分が交差していたら座標を返す
⑤さきほど返した座標にめり込み防止処理をしたのがプレイヤーの座標。
アルゴリズムは間違っているのかもしれません…。
何かアルゴリズムの改善案や、アルゴリズムの問題点などを上げてくれないのでしょうか?
当たり判定関係のプログラムは以下のとおりです。
ヘッダーファイル
//坂道の当たり判定
POINT CheckSlope(int x, int y,Segment& Slope,int layernum,int slopecond,int addy = 0);
//坂道のブロックとしての当たり判定。
POINT CheckSlopeBlock(int x, int y,int layernum,int addy=0);
//ブロックの左上の点を取る。(坂道用)
Vector2 GetMatrixPos(float myx, float myy);
//seg1,2が線分、outT1,2が線分の内分比、outPosが交点(出力用)
bool ColSegments(Segment &seg1, Segment &seg2, float* outT1 = 0, float* outT2 = 0, Vector2* outPos = 0);
//横の衝突判定
void GetXPosition(float* myx, float* myy, float* addx, float* addy);
//縦の衝突判定
void GetYPosition(float* myx, float* myy, float* addx, float* addy, int* jcount, bool* gflag);
Vector2 CCollision::GetMatrixPos(float myx, float myy) {
DWORD cwidth = Game->MapData().GetChipWidth();
DWORD cheight = Game->MapData().GetChipHeight();
int x = (int)(myx / cwidth);
int y = (int)(myy / cheight);
return Vector2((float)x * cwidth, (float)y * cheight);
}
//省略。
POINT CCollision::CheckSlopeBlock(int x, int y, int layernum, int addy) {
POINT pt[] = {
{ x + mPt[0].x, y + mPt[0].y },//左上
{ x + mPt[1].x, y + mPt[1].y },//上真ん中
{ x + mPt[2].x, y + mPt[2].y },//右上
{ x + mPt[3].x, y + mPt[3].y },//左真ん中
{ x + mPt[4].x, y + mPt[4].y },//右真ん中
{ x + mPt[5].x, y + mPt[5].y },//左下
{ x + mPt[6].x, y + mPt[6].y },//下真ん中
{ x + mPt[7].x, y + mPt[7].y },//右下
};
POINT res = { x,y };
DWORD cwidth = Game->MapData().GetChipWidth();
DWORD cheight = Game->MapData().GetChipHeight();
for(int i = 0; i < 8; i++){
int index = Game->MapData().GetValue(layernum , pt[i].x / cwidth, pt[i].y / cheight);
int src_x = (index % Game->GetBitCount()) * cwidth;
int src_y = (index / Game->GetBitCount()) * cheight;
//坂道の当たり判定がない時は床の当たり判定を行う。
if (src_x == 0 && src_y == 0) {
res.x = pt[i].x / cwidth; // 壁の座標を代入
res.y = pt[i].y / cheight;
return res; // 壁の座標を返す
}
}
res.x = -1;
res.y = -1;
return res;
}
POINT CCollision::CheckSlope(int x, int y, Segment& Slope, int layernum,int slopecond,int addy) {
//当たり判定。
POINT pt[] = {
{ x + mPt[0].x, y + mPt[0].y },//左上
{ x + mPt[1].x, y + mPt[1].y },//上真ん中
{ x + mPt[2].x, y + mPt[2].y },//右上
{ x + mPt[3].x, y + mPt[3].y },//左真ん中
{ x + mPt[4].x, y + mPt[4].y },//右真ん中
{ x + mPt[5].x, y + mPt[5].y },//左下
{ x + mPt[6].x, y + mPt[6].y },//下真ん中
{ x + mPt[7].x, y + mPt[7].y },//右下
};
DWORD cwidth = Game->MapData().GetChipWidth();
DWORD cheight = Game->MapData().GetChipHeight();
Segment Player;
switch (slopecond) {
//1は下の下り坂。
case 1:
Player.s = { (float)pt[2].x,(float)pt[2].y };
Player.v = { (float)pt[5].x,(float)pt[5].y };
break;
//2は上の上り坂。
case 2:
Player.s = { (float)pt[7].x,(float)pt[7].y };
Player.v = { (float)pt[0].x,(float)pt[0].y };
break;
//3は上の上り坂。
case 3:
Player.s = { (float)pt[5].x,(float)pt[5].y };
Player.v = { (float)pt[2].x,(float)pt[2].y };
break;
//0は下の上り坂。(0以外は想定していないのだ。)
default:
Player.s = { (float)pt[0].x,(float)pt[0].y };
Player.v = { (float)pt[7].x,(float)pt[7].y };
break;
}
POINT res;
//デバッグ用。
float T1;
float T2;
Vector2 Vres;
if (Slope.s.x >= Player.v.x && Player.v.x < Slope.v.x || Slope.s.x <= Player.v.x && Player.v.x > Slope.v.x) {
if (ColSegments(Slope,Player,&T1,&T2,&Vres)) {
res.x = (int)Vres.x;
res.y = (int)Vres.y;
}
}
//ここまで来たら衝突していないということ。
res.x = -1;
res.y = -1;
return res;
}
void CCollision::GetXPosition(float* myx, float* myy, float* addx, float* addy) {
float newx;
float tempx = *myx;
float tempaddx = *addx;
newx = tempx + tempaddx;
POINT block = CheckMap((int)newx, (int)*myy);
//X座標が衝突していなかったら。
if (block.x == -1) {
*myx = newx;
}
//X座標が坂道のレイヤーにいたら。
else if(block.x == -2){
int Layer = GetChipLayerNum((int)newx, (int)*myy);
Segment Slope;
//スロープの条件分離。
int SlopeCond;
switch (Layer) {
case 2:
Slope.s = GetMatrixPos(newx, *myy - 16.0f);
Slope.v = GetMatrixPos(newx + 16.0f, *myy);
SlopeCond = 0;
break;
}
POINT slopeblock = CheckSlopeBlock((int)newx, (int)*myy, Layer);
POINT slope = CheckSlope((int)newx, (int)*myy, Slope, Layer,SlopeCond);
//-2を返したら、ブロックとして扱う。
if (slope.x == -1) {
*myx = newx;
}
else if (slope.x == -2) {
//ブロックとしての当たり判定。
if (tempaddx > 0) {
*myx = (float)((slopeblock.x - 1) * 16 + 8 + OffsetR - 0.1f);
}
else {
*myx = (float)((slopeblock.x + 1) * 16 + 8 + OffsetL + 0.1f);
}
*addx = 0;
}
else {
//めり込み防止をする。
}
}
//ブロックの当たり判定。
else {
if (tempaddx > 0) {
*myx = (float)((block.x - 1) * 16 + 8 + OffsetR - 0.1f);
}
else {
*myx = (float)((block.x + 1) * 16 + 8 + OffsetL + 0.1f);
}
*addx = 0;//当たっているので移動させない。
}
}
void CCollision::GetYPosition(float* myx, float* myy, float* addx, float* addy, int* jcount, bool* gflag) {
float tempaddx = *addx;
float newy = *myy + *addy;
POINT block = CheckMap((int)*myx, (int)newy, *addy);
//Y座標が衝突していなかったら。
if (block.y == -1) {
*myy = newy;
*gflag = false;
}
//Y座標が坂道のレイヤーにいたら。
else if(block.y == -2){
*addy = 0;
int Layer = GetChipLayerNum((int)*myx, (int)newy);
Segment Slope;
//スロープの条件分離。
int SlopeCond;
switch (Layer) {
case 2:
Slope.s = GetMatrixPos(*myx, newy - 16.0f);
Slope.v = GetMatrixPos(*myx + 16.0f, newy);
SlopeCond = 0;
break;
}
POINT slopeblock = CheckSlopeBlock((int)*myx, (int)newy, Layer);
POINT slope = CheckSlope((int)*myx, (int)newy, Slope, SlopeCond, Layer);
//-2を返したら、ブロックとして扱う。
if (slope.y == -1) {
*gflag = true;
}
else if (slope.y == -2) {
//ブロックとしての当たり判定。
}
else {
*addy = slope.y;
}
}
//ブロックの当たり判定。
else {
if (*addy < 0) {
*myy = (float)((block.y + 1) * 16 + 8 + OffsetU + 0.1f);
}
else {
*myy = (float)((block.y - 1) * 16 + 8 + OffsetD - 0.1f);
*jcount = 0;
*gflag = true;
}
*addy = 0;
}
}