Libgdx Melee Attack Collision Detection
Asked Answered
D

2

2

I have a 3D scene with 3D model instances; and I want to do collision detection. I'm currently following this tutorial (http://blog.xoppa.com/using-the-libgdx-3d-physics-bullet-wrapper-part1/). However, what I want is a bit more complicated.

There's a character (a knight.g3db model that's part of the sample code from Libgdx basic 3d model class), and it can attack with a sword. I also have another model instance that I want to "attack" with the sword.

Checking if the two objects for collision isn't the problem since that can easily be detected from the Bullet library. What I would like is possibly the following, but I'm not sure how to implement:

  • Have the sword as the collision object, or
  • Implement checking if only the front part of the "box" of the knight is colliding with the other object, or
  • Create a separate invisible virtual box in front of the knight character and use that as basis if there's a collision.

Are there any references that you know that can do this (if the above proposed solutions are even possible)? Or if there's a better solution, please let me know.

What I'm trying to avoid: knight attacking while the other object is behind and still getting hit.

Thanks in advance.

Disparagement answered 6/1, 2015 at 0:53 Comment(0)
M
1

If you just want to avoid enemies in your back being hit you could check if you are facing them. I'll take it you have a direction Vector for movement, check the difference in rotation of that Vector vs the vector calculated based on your position and the enemy.

Something like this (Disclaimer: out of my head, not sure if this work and just to give you an idea):

float yourAngle = direction.angle();
float enemyAngle = new Vector2(enemyPos.x - playerPos.X, enemyPos.y - playerPos.y).angle();

if (yourAngle - enemyAngle < 30 && yourAngle - enemyAngle > -30) //enemy within a 60 degree cone in front of you.

This might not be the ideal solution but it sure is a cheap solution and it might work very well.

Mixon answered 9/1, 2015 at 2:19 Comment(6)
Thanks for that, the solution seems straight forward. I was looking for something like .angle(). How will it work with Vector3 or ModelInstances, though? Since I'm working with 3D space.Disparagement
Unless, I guess it's possible to just get the x and z (since I'm using Y-up) coordinates of the Vector3?Disparagement
You could just create a V2 from your V3.x and V3.z. but it should be possible with V3 as well, maybe yaw/roll? But my 3D experience is limited.Mixon
Cool. Thanks, I think this is what I'm looking for. Accepted the answer (though I haven't implemented yet) :)Disparagement
if (PlayerForward.cpy().rot(player.transform).hasSameDirection(EnemyForward.cpy().rot(enemy.transform)) { ... } where PlayerForward and EnemyForward is the direction vector to indicate which side is (the unrotated) front, e.g. Vector3.Z or new Vector3(0,0,-1);. Note that i used cpy() for the sake of the example, you should re-use a temporary vector instead.Churning
Thanks, @Xoppa. That's a handy method that I saw, but that would have to mean the ModelInstances have to be facing each other, though, right?Disparagement
D
0

These are what I used to check if the enemy object is within the 'field of view' of the hero (Working code):

/**
 *
 * @param localAngle - the current yaw of the Player
 * @param angleTarget - the angle between the player and the target receipent of the attack -- use RotationHelper.angle() method
 * @param offset - the difference in localAngle(hero) and angleTarget(enemy)
 * @return
 */
public static float angleDifference(float localAngle, float angleTarget, int offset) {
    float newLocalAngle = (convert180to360(localAngle) + offset) % 360;
    AppLog.log("ANGLE_DIFFERENCE2", "localAngle(yaw, degrees, with offset): " + newLocalAngle + ", angleTarget: " + angleTarget);

    float result = 180 - Math.abs(Math.abs(newLocalAngle - angleTarget) - 180);
    AppLog.log("ANGLE_DIFFERENCE2", "result : " + result);
    AppLog.log("ANGLE_DIFFERENCE2", "==================================");
    return result;
}

public static float angle(Vector3 vectorA, Vector3 vectorB) {
    return new Vector2(vectorB.x - vectorA.x, (-vectorB.z) - (-vectorA.z)).angle();
}


public static float convert180to360(float originalAngle) {
    float newAngle = 0;
    if(originalAngle < 0) {
        newAngle = (originalAngle + 180) + 180;
    } else {
        newAngle = originalAngle;
    }

    return newAngle;
}

Thanks to @Menno Gouw for the idea on getting the angle from Vector3.

And the code below is how I used these helper methods:

                float angleTarget = RotationHelper.angle(hero.transform.getTranslation(hero.tmpVector), enemy.transform.getTranslation(enemy.tmpVector));
                    float angleDifference = RotationHelper.angleDifference(hero.transform.getRotation(playerObject.tmpRotation).nor().getYaw(), angleTarget, CHARACTER_TO_WORLD_ROTATION_OFFSET);
                    AppLog.log("ANGLE_DIFFERENCE2", " angle from point hero to enemy): " + angleTarget);

                    if(angleDifference < VIEW_ANGLE_THRESHOLD) { //use 'angleDifference < VIEW_ANGLE_THRESHOLD'

                        enemy.hurt(hero.stats.damage);
                        AppLog.log("HERO_STATE", "Enemy monkey hit!");
                    }

                    if(enemy.stats.hp <= 0) {
                        AppLog.log("ENEMY_STATE", "Dead monkey");
                        //TODO: Remove monkey from game 
                        enemy.die();
                        instances.removeValue(gameObject, true);
                    }

Hope this helps you if you're encountering the same issue. Feel free to make changes if there are improvements or issues with this.

Disparagement answered 18/1, 2015 at 15:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.