libgdx api (java) に含まれている box2d を使用しています。
私は4方向(上下左右90°の斬撃)で剣の衝突(本体をセンサーとして使用)を検出するためのセンサーとして長方形のbox2d本体を使用しています。したがって、上方向にスラッシュするために、基本的に新しい長方形のbox2dボディを作成し、毎回その開始位置を設定します:
swordBodyDef.position.set(playerBody.getPosition().x, playerBody.getPosition().y + 4);
これだけで、プレイヤーは剣をまっすぐ上 (12 時) に構えることになります。しかし、12:10 に開始する必要があります (その後、力を加えて 11:50 に移動します)。剣の天使をプレイヤーの前で 12:10 に設定するには、次のコードを使用します。
swordBody.setTransform(playerBody.getPosition().x, playerBody.getPosition().y + 4 ), (float)Math.toRadians(-125));
ソードスラッシュ全体が機能しますが、敵を攻撃するたびにヒットが 2 としてカウントされます。12:00 (setPosition) に剣を作成すると、すでに物理シミュレーションに参加しており、ヒットとしてカウントされているように感じます。したがって、setTransform メソッドを使用して適切な天使 (12:10) に調整すると、2 回目のヒットになります。少なくとも、setTransform メソッドを使用してエンジェルを変更しない場合は機能します。剣の位置と天使を原子的に設定する方法があればうまくいくと思います。
ダブルヒットを防ぐ方法についてのアイデアは大歓迎です:)
編集: 回転ジョイントに関する box2d のマニュアルに次の記述があります。私がしていることとは正反対です。最初に RevoluteJoint を作成してから、swordBody の位置 (目的の天使) を設定します。どうやらそれが物理学の問題を引き起こしているようですが、剣体の最初の天使を適切に設定する方法はまだわかりません
EDIT2: iforce2dが推奨するように、問題を修正するために少し回避策を使用しました。この問題は次の world.step でのみ発生するため、私が行っているのは、swordBody を無効にすることです。
swordBody.setActive(false);
このゲームループで、次のゲームループで true に設定します。少し醜いですが、少なくとも機能します。
上方向のスラッシュの完全な box2d-code (12:10 から 11:50) :
//if the sword is active (slashing)
if(swordBody != null)
{
//destroy swordbody when it reaches a certain angel (11:50)
if(swordBody.getAngle() >= (float)Math.toRadians(50))
{
for (Body box : swordBody_List)
GameplayScreen.world.destroyBody(box);
swordBody_List.clear();
swordBody = null;
}
}
//construct a sword, set its position over the player's head, join it to the player's body, set the sword's angel to 12:10 and the
else if (playerInput.getMoveDirection() == Action.HIT)
{
//start state of hitting
hitUp = true;
//a short delay before the next hit starts
if (hitTestUpdateTimer < .50f)
{
hitTestUpdateTimer += Gdx.graphics.getDeltaTime();
}
else
{
//Player's sword (box2d collision detection)
BodyDef swordBodyDef = new BodyDef();
swordBodyDef.type = BodyDef.BodyType.DynamicBody;
swordBodyDef.position.set(playerBody.getPosition().x, playerBody.getPosition().y + 4);
swordBody = GameplayScreen.world.createBody(swordBodyDef);
swordBody.setUserData(this);
PolygonShape swordShape = new PolygonShape();
swordShape.setAsBox(.1f , 1.3f); //sword size
FixtureDef swordFixtureDef = new FixtureDef();
swordFixtureDef.shape = swordShape;
swordFixtureDef.density = 1f;
swordFixtureDef.isSensor = true;
swordBody.createFixture(swordFixtureDef);
swordShape.dispose();
swordBody_List.add(swordBody);
//Connection between sword & player
swordJointDef = new RevoluteJointDef();
swordJointDef.initialize(playerBody, swordBody, playerBody.getPosition().sub(new Vector2(0, -2)));
@SuppressWarnings("unused")
RevoluteJoint swordRevJointDef = (RevoluteJoint)GameplayScreen.world.createJoint(swordJointDef);
//set the angel of the sword to 12:10 when the hit starts
swordBody.setTransform(new Vector2(playerBody.getPosition().x, playerBody.getPosition().y + 4 ), (float)Math.toRadians(-125));
//rotate the sword (left-direction)
swordBody.applyTorque(1600f);
//Set update timer back to zero
hitTestUpdateTimer = 0;
hitUp = false; //state of hitting is finished
}
}