返信遅くなってすみません。
坂以外のことをしていました。
今、坂ブロックは進行可能ブロックとしてみて、プレイヤーの足元の点からプレイヤーの移動量の点が坂ブロックに属していれば、坂判定を行うという形です。
どうやらこの方法だと、坂(上り)ブロックの上の方の次の坂ブロックとの隙間でプレイヤーが止まっちゃいます。
おそらく、プレイヤーの足元の点からプレイヤーの移動量分だけ伸ばした点が、
⊿ ⊿
ここの坂ブロックを調べずに→⊿□ ⊿□←ここの進行不可ブロックを調べてしまうためだと思います。
この問題で、色々悩んでいるのですが、移動後に現在の高さを調べて、めり込んでいたら補正で、可能なのでしょうか?
後、普通の進行不可ブロックはプレイヤーの進行方向にプレイヤーの半径+プレイヤーの移動量の先の配列の番号を調べて、進行不可なら移動しないという形です。
うまく説明できないので一応マップチップとのあたり判定の部分のソースコードを載せます。 見ずらい場合はすみません。
map.h(map.Get_MatrixPosの部分のみ)
コード:
// ブロックの左上の点を取る
Vector2 Map::Get_MatrixPos(Vector2 pos)
{
// もらった座標をブロックの大きさで割る
int x = (int)(pos._x / BLOCK_SIZE);
int y = (int)(pos._y / BLOCK_SIZE);
// 割った後の座標をブロックの大きさ分かけてあげることで、ブロックの左上の点を返す
return Vector2(x * BLOCK_SIZE,y * BLOCK_SIZE);
}
HitManager.cpp
コード:
// 次フレームの場所を返す
Vector2 HitManager::Get_Dist_Pos(Vector2 pos, Vector2 mov)
{
// いったん一時保存用のベクトルを作る
Vector2 tmp;
// 移動量分足した点を求める
tmp._x = pos._x + mov._x;
tmp._y = pos._y + mov._y;
return tmp;
}
// 次フレームの配列の値をとる
int HitManager::Get_Distance_Val(Vector2 pos, Vector2 mov, Map &map)
{
// いったん一時保存用のベクトルを作る
Vector2 tmp;
// 移動先の点を求める
tmp = Get_Dist_Pos(pos,Vector2(mov._x, mov._y));
int x1, y1; //マップ番号用
// マップ番号を求める
x1 = (int)( tmp._x / BLOCK_SIZE );
y1 = (int)( tmp._y / BLOCK_SIZE );
if( x1 < MAP_WIDTH && x1 > 0
&& y1 < MAP_HEIGHT && y1 > 0){ // 配列参照外を起こしてなかったら
// マップの値を返す
return map.MapData[y1][x1];
}
// 進行可能番号を返す
return 255;
}
// マップとのあたり判定(Y方向)
float HitManager::HIT_MAP_Y(Status &status, Map &map, int *data)
{
Vector2 pos = status._pos; // 測定のためのポジション設定(画像の真ん中)
float top = pos._y - status._radius + 1.0f; // 上下左右の座標設定(画像の上の点)
float bottom = pos._y + status._radius - 1.0f; // 上下左右の座標設定(画像の下の点)
float left = pos._x - status._radius + 16.0f; // 上下左右の座標設定(画像の左の点)
float right = pos._x + status._radius - 16.0f; // 上下左右の座標設定(画像の右の点)
//---- 上下左右判定
//--- 地面,天井
Vector2 posl, posr, center; // 左右真ん中
posl._x = left; // 左の点を入れる
posr._x = right; // 右の点を入れる
center._x = status._pos._x; // 真ん中の点を入れる
if( status._dir._y > 0.0f ){ // 移動量の向きが正の値だったら
//---- 地面
// 下のマップ番号を調べるために下の点を入れる
posl._y = bottom;
posr._y = bottom;
center._y = bottom;
}else{ // 移動量の向きが負の値だったら
//---- 天井
// 上のマップ番号を調べるために上の点を入れる
posl._y = top;
posr._y = top;
center._y = top;
}
int l,r,c; // 左右真ん中
// マップ番号を取得
l = Get_Distance_Val(posl,Vector2(0.0f,status._mov._y),map);
r = Get_Distance_Val(posr,Vector2(0.0f,status._mov._y),map);
c = Get_Distance_Val(center,Vector2(0.0f,status._mov._y),map);
//---- 今の状態を保存(別のことに使う)
data[0] = l; // プレイヤーの左下の配列の値を入れる
data[1] = r; // プレイヤーの右下の配列の値を入れる
data[2] = c; // プレイヤーの真下の配列の値を入れる
// 足元の点
t_pos = Vector2(status._pos._x, status._pos._y + status._radius - 1.0f);
// 足元の点のマップ番号を取得
int p = Get_Distance_Val(t_pos,Vector2(0.0f, 0.0f ), map);
if( p == 4 ){ // 斜め坂登りだったら
// 次フレームの進む点を求める
t_pos = Get_Dist_Pos(t_pos,Vector2(status._mov._x,0.0f));
// ブロックの左下の点を求める
begin_p = Vector2(map.Get_MatrixPos(t_pos)._x - 2.0f, map.Get_MatrixPos(t_pos)._y + 32.0f + 2.0f);
// ブロックの右上の点を求める
end_p = Vector2(map.Get_MatrixPos(t_pos)._x + 32.0f - 2.0f, map.Get_MatrixPos(t_pos)._y - 2.0f);
// 点と線とのあたり判定をする
return CheckHitLine(t_pos, begin_p, end_p); // めり込み量を返す
}
else if((( l == 19 || r == 19 || c == 19 )||( l == 0 || r == 0 || c == 0 ))
&& ( l != 4 && r != 4 && c != 4 )) // 調べたマップの値が19(ブロック番号)または0(地面番号)かつ全て4(坂)以外の時
{
return 0.0f; // めり込み量を返す
}
return -1.0f; // 当たってない
}
// マップとのあたり判定(X方向)
float HitManager::HIT_MAP_X(Status &status, Map &map)
{
Vector2 pos = status._pos; // 測定のためのポジション設定(画像の真ん中)
float top = pos._y - status._radius + 1.0f; // 上下左右の座標設定(画像の上の点)
float bottom = pos._y + status._radius - 1.0f; // 上下左右の座標設定(画像の下の点)
float left = pos._x - status._radius + 16.0f; // 上下左右の座標設定(画像の左の点)
float right = pos._x + status._radius - 16.0f; // 上下左右の座標設定(画像の右の点)
Vector2 post, posb, center; // 上下真ん中
post._y = top; // 上の点を入れる
posb._y = bottom; // 下の点を入れる
center._y = status._pos._y; // 真ん中の点を入れる
if( status._dir._x > 0.0f ){ // 移動量の向きが正の値だったら
//---- 右方向
// 右のマップ番号を調べるために右の点を入れる
post._x = right;
posb._x = right;
center._x = right;
}else if( status._dir._x < 0.0f ){ // 移動量の向きが負の値だったら
//---- 左方向
// 左のマップ番号を調べるために左の点を入れる
post._x = left;
posb._x = left;
center._x = left;
}
int t,b,c; // 上下真ん中
// マップの番号を取得
t = Get_Distance_Val(post,Vector2(status._mov._x,0.0f),map);
b = Get_Distance_Val(posb,Vector2(status._mov._x,0.0f),map);
c = Get_Distance_Val(center,Vector2(status._mov._x,0.0f),map);
// あたり判定
// 足元の点
t_pos = Vector2(status._pos._x, status._pos._y + status._radius - 5.0f);
//---- デバッグ用
s_pos = Get_Dist_Pos(t_pos,Vector2(0.0f,0.0f));
d_pos = map.Get_MatrixPos(t_pos);
// 足元の点のマップ番号を取得
int p = Get_Distance_Val(t_pos,Vector2(0.0f, 0.0f), map);
if( p == 4 ){ // 斜め坂登りだったら
// 次フレームの進む点を求める
t_pos = Get_Dist_Pos(t_pos,Vector2(status._mov._x,0.0f));
// ブロックの左下の点を求める
begin_p = Vector2(map.Get_MatrixPos(t_pos)._x - 2.0f, map.Get_MatrixPos(t_pos)._y + 32.0f + 2.0f);
// ブロックの右上の点を求める
end_p = Vector2(map.Get_MatrixPos(t_pos)._x + 32.0f - 2.0f, map.Get_MatrixPos(t_pos)._y - 2.0f);
// 足元の点が坂の開始地点と終了地点の間なら
if( t_pos._x >= begin_p._x && t_pos._x < end_p._x )
{
// 点と線とのあたり判定をする
return CheckHitLine(t_pos, begin_p, end_p); // めり込み量を返す
}
return -1.0f;
}
else if((t == 19 || b == 19 || c == 19) && (t != 4 && b != 4 && c != 4)) // 調べたマップの値が19(ブロック番号)かつ全て4(坂)以外の時
{
// めり込み量を返す
return 0.0f;
}
return -1.0f; // 当たってない
}
めり込み量によってその後の処理はこうなってます。
HitManager.cpp
コード:
int data[3]; // データ一時保管用
//--- 上下方向
if( HIT_MAP_Y(ninja, map, data) == 0.0f ){
ninja.hit_ground = true;
ninja.set_underval(data); // データを入れる
}else if( HIT_MAP_Y(ninja, map, data) > 0.0f ){
ninja.hit_ground = true;
float a = HIT_MAP_Y(ninja, map, data); // 値確認用
ninja._pos._y -= a;
ninja.set_underval(data); // データを入れる
}else{
ninja.hit_ground = false;
ninja.set_underval(data); // データを入れる
}
//---- 左右方向
if( HIT_MAP_X(ninja, map) == 0.0f){
ninja.hit_wall = true;
}else if( HIT_MAP_X(ninja, map) > 0.0f ){
float a = HIT_MAP_X(ninja, map); // 値確認用
ninja._pos._y -= a;
}else{
ninja.hit_wall = false;
}
d_nin = ninja._pos;
ninja.hit_wallやninja.hit_groundののちの処理は以下のようになっています
Ninja.cpp
コード:
if( hit_wall == true ){ // 壁と当たったら
_mov._x = 0; // 移動量を0に
SCROLL_SPEED_X = _mov._x; // スクロール量を入れる(後々変更予定)
}else{
SCROLL_SPEED_X = _mov._x; // スクロール量を入れる(後々変更予定)
_pos._x += _mov._x; // 移動
}
if( hit_ground == true ){ // 地面と接触していたら
_mov._y = 0; // 重力を0にする
status_mode = STATUS_RUN;
hit_ground = false; // 当たっているフラグをfalseにする
}else{
//----重力設定
_pos._y += _mov._y; // 重力
}
このあたり判定を「移動後に現在の高さを調べて、めり込んでいたら補正」に変更するにはどの辺が肝なのでしょうか?
学校の先生に相談したときは調べる方向を斜めにするということだったのですが、その方法をしてもダメだったので、改めて質問させていただきました。
ソースコードで足りない部分がありましたらお願いします。