私はタイルベースのマリオクローンに取り組んでいます。
これは、ウォーキングや落下の際にすべて正常に機能します。しかし、プレイヤーが壁の近くにジャンプして空中を右に歩くと、プレイヤーは壁に引っかかってしまいます。プレーヤーがキーを離すと、プレーヤーのスプライトは再び落ちます。
セットアップはかなり簡単で、問題を見つけることができません。マップは、マップブロックを持つ2D配列として構築されます。ブロックは固体でもそうでなくてもかまいません。プレーヤーは固体オブジェクトを移動できません。
ゲームループでは:
- プレーヤーの位置が更新されます(重力、動きなど)。
- 衝突の地図を確認してください。Yで衝突が検出されると、プレーヤーの位置が更新され、ブロックの上または下(プレーヤーの方向に応じて)になり、その後、衝突ボックスが新しい位置で更新されます。次に、Xの同じプロセス。
- コリジョンボックスが新しい場所(空き場所)に更新されます。ボックスが調整され、プレイヤーの下にあるブロックが着地したかどうかを確認するのが少し高くなります。これは、プレイヤーの状態を、スプライトの飛行からアイドル状態に変更するためです。
また、XとYのチェックを入れ替えて、プレーヤーがX線上を移動するようにしました。その後、プレイヤーが移動すると、動きが非常に遅くなります。ボタンを押して離して移動すると、プレイヤーはより速く移動しますが、チャックの中にいます。とても奇抜です。
誰かがエラーを見たり、これのためのより良い衝突アルゴリズムを私に与えることができますか?
更新(コードを更新していません)
xとyのチェック方法を入れ替えて、isonland変数を実装しました。したがって、壁に向かって歩いたりジャンプしたりするときは、完璧に機能します。今だけ、プレイヤーがジャンプすると、マリオは着地したときに戻ってきます。これは、Xチェックメソッドが最初に実行され、マリオの位置を調整するためです。
どうすれば解決できますか?
マップクラス更新メソッド:
public void update(int timeElapsed) {
//update entities
for(Entity entity : _mapEntities) {
entity.update(timeElapsed);
}
//update objects
for(MapObject mapObt : _mapObjects) {
mapObt.update(timeElapsed);
}
//check for collisions
checkMapCollision();
}
エンティティ(抽象)更新メソッド:
public void update(int timeElapsed) {
_velocity = new Vector2d(0.0F, 0.0F);
//add gravity
_velocity.y = Map._GRAVITY_PER_SEC * timeElapsed;
}
マリオ(エンティティを拡張)更新メソッド:
@Override
public void update(int timeElapsed) {
super.update(timeElapsed);
if(_state == STATES.IDLE) {
} else if(_isMoving) {
_marioSmallWalk.update(timeElapsed);
}
if(_state == STATES.JUMPING) {
setVelocityY(getVelocity().y + _jumpSpeed);
_jumpSpeed += _JUMP_DECREASE * timeElapsed;
//falling?
if(getVelocity().y > 0) {
setState(STATES.FALLING);
}
}
if(_isMoving) {
double walkSpd = (_WALK_SPEED_SEC * timeElapsed);
if(getFacing() == FACING.LEFT) {
walkSpd = -walkSpd;
}
setVelocityX(getVelocity().x + walkSpd);
}
//falling?
if(getVelocity().y > (Map._GRAVITY_PER_SEC * timeElapsed) + 1.0F) {
setState(STATES.FALLING);
}
setPosition((int)(getX() + getVelocity().x), (int)(getY() + getVelocity().y));
}
MapクラスのCheckMapCollisionメソッド:
public void checkMapCollision() {
//enteties move so check it
for(Entity entity : _mapEntities) {
//get the corners
Rectangle bounds = entity.getBounds();
Block[] corners = getCornerBlocks(bounds);
Vector2d dir = entity.getDirection();
//moving down
if(dir.y > 0) {
if(corners[2].isSolid() || corners[3].isSolid()) {
Rectangle blkBounds = null;
if(corners[2].isSolid()) {
blkBounds = corners[2].getBounds();
} else {
blkBounds = corners[3].getBounds();
}
entity.setPositionY(blkBounds.y);
}
} else {
if(corners[0].isSolid() || corners[1].isSolid()) {
Rectangle blkBounds = null;
if(corners[0].isSolid()) {
blkBounds = corners[0].getBounds();
} else {
blkBounds = corners[1].getBounds();
}
entity.setPositionY(blkBounds.y + blkBounds.height + bounds.height);
}
}
bounds = entity.getBounds();
corners = getCornerBlocks(bounds);
//moving to the right
if(dir.x > 0) {
if(corners[1].isSolid() || corners[3].isSolid()) {
Rectangle blkBounds;
if(corners[1].isSolid()) {
blkBounds = corners[1].getBounds();
} else {
blkBounds = corners[3].getBounds();
}
entity.setPositionX(blkBounds.x - (bounds.width-entity.getCurrentSprite().getOffsetX())-1);
}
} else {
if(corners[0].isSolid() || corners[2].isSolid()) {
Rectangle blkBounds;
if(corners[0].isSolid()) {
blkBounds = corners[0].getBounds();
} else {
blkBounds = corners[2].getBounds();
}
entity.setPositionX(blkBounds.x + blkBounds.width + (bounds.width/2));
}
}
bounds = new Rectangle(bounds.x, bounds.y, bounds.width, bounds.height+1);
corners = getCornerBlocks(bounds);
//moving down
if(dir.y > 0) {
if(corners[2].isSolid() || corners[3].isSolid()) {
Rectangle blkBounds = null;
if(corners[2].isSolid()) {
blkBounds = corners[2].getBounds();
} else {
blkBounds = corners[3].getBounds();
}
entity.landed();
System.out.println("landed");
}
}
}
}
entity.setPositionX()
またはentity.setPositionY()
衝突チェックの後に呼び出されます。ジャンプせずに壁に向かって歩くと、プレイヤーは正しく押し戻されます。