Need to fix this Homing missile animation

at the moment it doesnt feel right.
DEMO video:

code:

import {
    StandardMaterial, Color3, SphereParticleEmitter, ParticleSystem,
    Texture, Vector3, Quaternion,
    Animation, CreateCapsuleVertexData, ActionManager, ExecuteCodeAction, CircleEase, Matrix
} from "@babylonjs/core";
import Game from "../Game";
import GameObject from "./GameObject";

export default class HomingMissile extends GameObject {
    explosionParticleSystem: ParticleSystem;
    private _collisionTriggered: boolean;
    private _timer: number;

    constructor(pos: Vector3, game: Game, explosionTime: number) {
        super("homingMissile", game);

        // Create a mesh
        const vertexData = CreateCapsuleVertexData({ radius: 0.1, capSubdivisions: 1, height: 1.2, tessellation: 4, topCapSubdivisions: 8 });
        vertexData.applyToMesh(this, true);

        // Set plane material
        const mat = new StandardMaterial("planeMaterial", this.getScene());
        mat.diffuseColor = Color3.Red();
        this.material = mat;
        Game.shadowGenerator.addShadowCaster(this);

        // Create an explosion particle system
        this.explosionParticleSystem = this.createExplosionParticleSystem();

        this.position = pos;
        this.rotationQuaternion = Quaternion.RotationYawPitchRoll(0, Math.PI / 2, 0);
        this.hommingMissile(game.player!);

        // Set a timer for the plane to explode
        this._collisionTriggered = false;

        // Set a timer for the plane to explode
        this._timer = setTimeout(() => {
            this.explode();
        }, explosionTime);

        // Detect collision with the player
        this.actionManager = new ActionManager(this.getScene());
        this.actionManager.registerAction(
            new ExecuteCodeAction(
                {
                    trigger: ActionManager.OnIntersectionEnterTrigger,
                    parameter: game.player,
                },
                () => {
                    console.log('its a hit!');

                    this._collisionTriggered = true;
                    window.clearTimeout(this._timer);
                    this.explode();
                }
            )
        );
    }

    explode() {
        if (!this._collisionTriggered) {
            clearTimeout(this._timer);
        }
        // Trigger the explosion particle system
        this.isVisible = false;
        this.explosionParticleSystem.start();

        // Dispose the plane after the explosion
        setTimeout(() => {
            this.explosionParticleSystem.dispose();
            this.dispose();
        }, this.explosionParticleSystem.maxLifeTime * 1000);
    }

    private createExplosionParticleSystem(): ParticleSystem {
        ...
    }

    hommingMissile(player: GameObject) {
        const playerPosition = player.position.clone();

        // Move the pivot point to the base of the cylinder
        const pivotMatrix = Matrix.Translation(0, -1, 0);
        this.setPivotMatrix(pivotMatrix);

        // Create a quaternion representing a 90-degree pitch rotation
        const pitch = Math.PI / 2; // 90 degrees in radians
        const yaw = Math.PI / 2; // 90 degrees in radians
        const roll = 0;
        const rotationQuaternion = Quaternion.RotationYawPitchRoll(yaw, pitch, roll);


        // Assign the quaternion to the cylinder's rotationQuaternion property
        this.rotationQuaternion = rotationQuaternion;

        // Define animation for position
        const positionAnimation = new Animation("positionAnimation", "position", 100, Animation.ANIMATIONTYPE_VECTOR3, Animation.ANIMATIONLOOPMODE_CONSTANT);
        const [a, b, c] = this.getMissilePath(playerPosition)
        this.lookAt(b);
        // Define position keyframes
        const positionKeys = [
            { frame: 0, value: a },
            { frame: 25, value: b.add(new Vector3(1, -3, 0)) },
            { frame: 50, value: b },
            { frame: 75, value: b.add(new Vector3(-1, -3, 0)) },
            { frame: 100, value: c },
        ];

        // Assign keyframes to position animation
        positionAnimation.setKeys(positionKeys);

        // Define easing function for curved path
        const easingFunction = new CircleEase();
        positionAnimation.setEasingFunction(easingFunction);

        // Define animation for rotation
        const rotationAnimation = new Animation("rotationAnimation", "rotationQuaternion", 100, Animation.ANIMATIONTYPE_QUATERNION, Animation.ANIMATIONLOOPMODE_CONSTANT);

        // Define rotation keyframes
        const rotationKeys = [
            { frame: 0, value: rotationQuaternion },
            { frame: 25, value: Quaternion.RotationYawPitchRoll(yaw, pitch + Math.PI / 2, roll) },
            { frame: 50, value: Quaternion.RotationYawPitchRoll(yaw, pitch + Math.PI, roll) },
            { frame: 75, value: Quaternion.RotationYawPitchRoll(yaw, pitch + 1.5 * Math.PI, roll) },
            { frame: 100, value: Quaternion.RotationYawPitchRoll(yaw, pitch + 2 * Math.PI, roll) },
        ];

        // Assign keyframes to rotation animation
        rotationAnimation.setKeys(rotationKeys);

        this.getScene().beginDirectAnimation(this, [positionAnimation, rotationAnimation], 0, 100, false);
    }

    getMissilePath(destination: Vector3) {
        const initialPosition = this.position.clone(); // starting position

        // Calculate median position between initial and final positions
        const medianPosition = Vector3.Lerp(initialPosition, destination, 0.5);
        return [initialPosition, medianPosition, destination]
    }

}

I have no faen clue how to do it just exactly, but looking at your video I had a good laugh :joy: so I guess you already achieved something :grin:

Jokes apart, if I had to do it (luckily I don’t :wink:) I would likely look on the side of physics. Basically I would create a force around the target that attracts the homing missile. The missile would shoot in the direction of where it is aimed at following some ballistic curve (with a velocity, direction, etc…) and when entering this force, it would be attracted to the target. My guess only.

Probably @Cedric or @Evgeni_Popov will be able to give you more of an expert advise on this, will you?
Meanwhile, have a great day :sunglasses:

1 Like

Hey thanks for reply. I have another version in Havok physics it uncontrollable.

So started with without Physics version. Lets me also add animations. Since the only objective to not direct hit player, but try hit the last player position, but with really good animation.

Are you able to setup a simple repro with only the relevant code in the Playground? It would be easier for everyone to help.

I tried moving to playground, its difficult to get HavokPlugin running at playground.

here is it
https://playground.babylonjs.com/#3JUAIC#4

1 Like

how did you fix Havok missing plugin ? Thanks, now I update the rest of the code <3/
oh was it the sequence of initialization ?

1 Like

it’s just sequence problem
you using aggregate Bodies in Class Player before create HavokPlugin and scene’s turn on physics

1 Like

here it is, please have a look →

shot key is ‘space’;

but i can’t do physics based on real ballistics
so. then this is a chase using animation.
https://playground.babylonjs.com/#3JUAIC#11

2 Likes

wow this is much better. I will have a look for diff. I can still use it.
I’m working on Physics based alternative Missile, will share here soon. Thanks

Call me boring but I don’t think I’d use a physics engine for controlling a missile.
It’s simple Euler integration. Difficult part is to align missile along velocity and I think it can be done with Matrix LookAt. Explosion is a matter of computing distance between missile and target.
It’s a matter of a few lines of code, really.

EDIT: Here is a quick PG:

Note: this can be adapted to use with a physics engine too.

1 Like

thanks this is amazing. I actually moved away from Physics cause it was difficult for me to manipulate it. thanks again.