10
\$\begingroup\$

I am struggling with how to implement a melee weapon that can swing when a key is pressed.

I am imagining two different attacks (stab and swing)

I have tried creating two fixtures (character + weapon), two different bodies, two different bodies + revolute joint, but I can not code it to behave the way I imagine it to look like. myimagination

STAB:

So with the press of a button, a body/fixture (sensor) would come out for ~1 second and then disappear (alternatively, the body/fixture could always be on the hero and just rotate 90 degrees around the vertices when pressed, and then rotate back to normal)

SWING:

Same thing, but now the weapon will start from the top and swing downwards. Weapon will also be a sensor.

What I have tried:

I created two dynamic bodies.

The weapon has to follow the hero, so I used a revolute joint to hold them together. When a key is pressed, I set the angular velocity of the weapon to a number. However, the weapon will continue to spin after I let go of the key. I tried implementing an if check (if angle is greater than ___, set angular velocity to zero). However, that just means the weapon will stop spinning when I press the key a second time.

\$\endgroup\$
  • \$\begingroup\$ Since you have already made the rectangle shaped bodies/fixtures, you would just have to rotate the sword body 90 degrees to the right for the swing animation. Also you need to turn off the collisions of the sword body, when the animation is not occurring, and not draw it on screen. The stab animation is just a simpler version of swing, where the sword has a different starting angle. Isn't this right ? Seems pretty simple to me. Where did you stuck ? \$\endgroup\$ – dimitris93 Jun 4 '15 at 19:48
  • \$\begingroup\$ Is the problem the overlapping sword and hero? maybe a small square body could be the sword tip so it never overlaps. maybe edit for some more info \$\endgroup\$ – drumbumLOLcatz Jun 4 '15 at 20:48
  • \$\begingroup\$ @Shiro I included my attempts at the bottom. Right now I am stuck because I don't know how to start and stop the rotation in one key press. \$\endgroup\$ – quidproquo Jun 4 '15 at 22:34
  • \$\begingroup\$ Yea it feels like your actual question is how to rotate an object on key press \$\endgroup\$ – dimitris93 Jun 5 '15 at 6:06
1
\$\begingroup\$

Incidentally, I have done exactly what you are trying to do. The only catch is I was using Jbox2d so the code is in Java, but you should still be able to figure it out if you are using C++

You basically need to use joints/motors and all that fun stuff if you want to do swinging action. Here's a snippet of what my code looks like based on the key input:

    if (myinput.mouse0) {

        agents.get(0).rightForeJoint.enableMotor(true);
        agents.get(0).rightArmJoint.enableMotor(false);    

        if (Keyboard.isKeyDown(Keyboard.KEY_SPACE)){
            agents.get(0).rightForeJoint.enableMotor(false);
        }

        mouseY = Mouse.getY();
        mouseX = Mouse.getX();
        float temp = mouseY - prevPos[1];

        float temp2 = -mouseX + prevPos[0];

        temp2 *= modifier; temp2 *= 0.000026;
        temp  *= modifier; temp  *= 0.000030;

        agents.get(0).armR.applyAngularImpulse(-temp);
        agents.get(0).foreR.applyAngularImpulse(temp2); 

        prevPos[1] = mouseY;
        prevPos[0] = mouseX;

        if(temp2 < 0){
            temp2 *=-1;
        }
        if(temp < 0){
            temp *=-1;
        }
        fatigueDrain += temp2;
        fatigueDrain += temp;

    }

And then as far as actually building the arms and whatnot, the snippet looks like this.

    // RIGHTARM //
    this.rightArmDef = new RevoluteJointDef();
        this.rightArmDef.bodyA = this.torso ; this.rightArmDef.bodyB = this.armR;
        this.rightArmDef.collideConnected = false;

        torso_armL_pin = new Vec2(0.50f, +0.05f);
        local_armL_pin = new Vec2(0.14f, 0.14f);

        this.rightArmDef.localAnchorA.set(this.torso.getLocalCenter().add(torso_armL_pin));
        this.rightArmDef.localAnchorB.set(this.armR.getLocalCenter().add(local_armL_pin));

        this.rightArmDef.enableMotor = true;
        this.rightArmDef.motorSpeed = 0f;
        this.rightArmDef.maxMotorTorque =10f;

        this.rightArmDef.enableLimit = true;
        this.rightArmDef.lowerAngle = 1.2f;// * DEGTORAD;
        this.rightArmDef.upperAngle = 5;
    this.rightArmJoint = (RevoluteJoint)world.createJoint(this.rightArmDef);

I realize there is a lot going on here, but its probably easier if you just ask me what you need clarity on and I explain it. If you have never used any of these things though, you will probably need to do a fair bit of reading.

EDIT>>

Realize, Box2d has all of the collision detection and physics built clean into its libraries. Take it on faith when I say, it is easier to figure out their system than try and do things from scratch. If you want collision, you use fixtures bodydefs, if you want them to rotate or move, you use joints. It may seem a little more complicated at first, but in the end it saves you infinitely more time to use their methods.

In fact, I would suggest that you probably will never finish if you try and do things from scratch, assuming you are creating a physics game. Because computing things like friction, buoyancy and not to mention, /efficient/ collision detection, is going to take you a lifetime.

\$\endgroup\$
0
\$\begingroup\$

I have found some sort of a workaround this, but I am not sure if this is a good way to code.

When a key is pressed, I set the angular velocity to 10 and then at every update, I ask it to check

    if(weapon.getAngle() >= Math.PI / 2) {
        weapon.setAngularVelocity(-10);
    }
    if(weapon.getAngle() <= 0) {
        weapon.setAngularVelocity(0);
    }
\$\endgroup\$
  • \$\begingroup\$ Inside the if(weapon.getAngle() <= 0) you should also manually put it at the specific angle you want, otherwise its not gonna be precise and you need if-else statement instead of if-if. It comes down to basic java coding not really much to do with game specific problem. \$\endgroup\$ – dimitris93 Jun 5 '15 at 6:09
0
\$\begingroup\$

From what you are saying, it seems like you could also have to simply move the code that resets the angular velocity after a certain angle is reached. I suspect that this code is only used when the button is pressed, since you say pressing the button a second time makes the movement stop (and thus makes the testing code work).

If this is the case, you could move it to an 'else' statement after the code that tests if the key is pressed.

\$\endgroup\$
0
\$\begingroup\$

One thing that you could do is on command, run a method that would create a body relative to the position of the main body using body.getPosition.set(); set the filter bits to not collide, then set the linear velocity or apply force, whatever you want to move it forward after starting a timer to destroy after x amount of game loops

Or you could do the same thing but instead creating a distance joint combined with a prismatic joint only along the x axis to make a sudden shove out motion with collide connected to be false so that it doesn't collide with the main body this option would probably work better,

for a swing attack create a similar body rotated half of pi with only the tip of the sword connected to the main body with collide connected to equal false of course, then you could apply motor force on the joint an angular impulse on to the sword body destroying it after a set rotation of the body is achieved or a certain time has occurred,

if any extra assistance is needed, just comment below

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.