Shooting code not working properly

I am having issues with my shooting code. It is not shooting properly, no matter how much I try to fix it. It just doesn’t shoot straight. I am new to playcanvas. issue with shoot function. code (firstPersonMovement.js)

var FirstPersonMovement = pc.createScript('firstPersonMovement');

FirstPersonMovement.attributes.add('camera', {
    type: 'entity',
    description: 'Optional, assign a camera entity, otherwise one is created'
});

FirstPersonMovement.attributes.add('power', {
    type: 'number',
    default: 2500,
    description: 'Adjusts the speed of player movement'
});

FirstPersonMovement.attributes.add('lookSpeed', {
    type: 'number',
    default: 0.25,
    description: 'Adjusts the sensitivity of looking'
});

FirstPersonMovement.attributes.add('bullet', { type: 'entity' });
FirstPersonMovement.attributes.add('gunfire', { type: 'entity' });
FirstPersonMovement.attributes.add('gunpower', { type: 'number', default: 1 });

FirstPersonMovement.prototype.initialize = function() {
    this.force = new pc.Vec3();
    this.eulers = new pc.Vec3();
    
    var app = this.app;
    if (app.ammo === undefined) {
        app.ammo = 100;  // Initialize ammo if not defined
    }
    if (app.health === undefined) {
        app.health = 100;  // Initialize health if not defined
    }
    
    app.mouse.on("mousemove", this._onMouseMove, this);
    app.mouse.on("mousedown", this._onMouseDown, this);

    this.on('destroy', function() {
        app.mouse.off("mousemove", this._onMouseMove, this);
        app.mouse.off("mousedown", this._onMouseDown, this);
    }, this);

    if (!this.entity.collision) {
        console.error("First Person Movement script needs to have a 'collision' component");
    }
    if (!this.entity.rigidbody || this.entity.rigidbody.type !== pc.BODYTYPE_DYNAMIC) {
        console.error("First Person Movement script needs to have a DYNAMIC 'rigidbody' component");
    }
    
    this.entity.collision.on('contact', this.onContact, this);
};

FirstPersonMovement.prototype._onMouseDown = function() {
    this.app.mouse.enablePointerLock();
    if (this.app.ammo > 0) {
        this.shoot();
    } else {
        if (this.entity.sound) {
            this.entity.sound.play('ammogone');
        }
    }
};

FirstPersonMovement.prototype.update = function(dt) {
    if (!this.camera) {
        this._createCamera();
    }
    
    if (this.app.health === 0 || this.app.enemyamount === 0) {
        var oldHierarchy = this.app.root.findByName('Root');
        this.loadScene(this.sceneId, function() {
            oldHierarchy.destroy();
        });
    }
    
    var force = this.force;
    var app = this.app;
    
    var forward = this.camera.forward;
    var right = this.camera.right;

    var x = 0, z = 0;
    if (app.keyboard.isPressed(pc.KEY_A)) {
        x -= right.x;
        z -= right.z;
    }
    if (app.keyboard.isPressed(pc.KEY_D)) {
        x += right.x;
        z += right.z;
    }
    if (app.keyboard.isPressed(pc.KEY_W)) {
        x += forward.x;
        z += forward.z;
    }
    if (app.keyboard.isPressed(pc.KEY_S)) {
        x -= forward.x;
        z -= forward.z;
    }
    
    if (x !== 0 || z !== 0) {
        force.set(x, 0, z).normalize().scale(this.power);
        this.entity.rigidbody.applyForce(force);
    }
    
    this.camera.setLocalEulerAngles(this.eulers.y, this.eulers.x, 0);

    if (app.keyboard.isPressed(pc.KEY_SPACE)) {
        if(this.grounded) {
            this.entity.rigidbody.applyImpulse(0, 0.5, 0);
        }
    }

    var pos = this.entity.getPosition();
    
    if(pos.y > 1.2) {
        this.grounded = false;
    }
    else {
        this.grounded = true;
    }

    // use direction from keypresses to apply a force to the character
    if (x !== 0 && z !== 0) {
        force.set(x, 0, z).normalize();
        force.scale(this.power);
        var speed = this.entity.rigidbody.linearVelocity.length();
        //viewer.anim_info.innerHTML = speed;
        if (speed < 10)
            this.entity.rigidbody.applyForce(force);
        //this.entity.rigidbody.applyImpulse(force);
        //this.entity.rigidbody.linearVelocity = force;
    }
};

FirstPersonMovement.prototype.shoot = function() {
    // Ensure the bullet entity exists
    if (!this.bullet) {
        console.error("Bullet entity not assigned or is null.");
        return;
    }

    if (this.app.ammo <= 0) {
        console.warn("No ammo left.");
        if (this.entity.sound) {
            this.entity.sound.play('ammogone'); // Play sound when out of ammo
            this.reload(); // Auto-reload when ammo is depleted
        }
        return;
    }

    // Clone the bullet for each shot
    var bullet = this.bullet.clone();
    var gunfire = this.gunfire ? this.gunfire.clone() : null;

    // Add the bullet and gunfire to the scene
    this.app.root.addChild(bullet);
    if (gunfire) this.app.root.addChild(gunfire);

    // Use the camera's forward direction to align the bullet with the crosshair
    var camera = this.camera; // Assuming you have the camera entity assigned
    if (!camera) {
        console.error("Camera entity not found.");
        return;
    }

    // Get the camera's world transform and forward direction
    var forward = new pc.Vec3();
    camera.getWorldTransform().transformVector(pc.Vec3.FORWARD, forward); // Get the world forward vector

    // Apply force in the precise forward direction of the camera
    this.force.copy(forward).scale(this.gunpower);

    // Set the bullet's position at the camera's position
    bullet.setPosition(camera.getPosition());
    if (gunfire) gunfire.setPosition(camera.getPosition());

    // Align bullet's rotation with the camera's rotation
    bullet.setRotation(camera.getRotation());

    // Reset bullet velocity and angular velocity to avoid carry-over effects
    bullet.rigidbody.linearVelocity = pc.Vec3.ZERO;
    bullet.rigidbody.angularVelocity = pc.Vec3.ZERO;

    bullet.enabled = true;
    if (gunfire) gunfire.enabled = true;

    // Apply the impulse to the bullet in the camera's forward direction
    bullet.rigidbody.applyImpulse(this.force);

    // Decrease ammo count
    this.app.ammo--;

    // Play gunshot sound
    if (this.entity.sound) {
        this.entity.sound.play('gunshot');
    }

    // Destroy gunfire after a short time
    if (gunfire) {
        setTimeout(function() {
            gunfire.destroy();
        }, 500);
    }

    // Destroy the bullet after 4 seconds
    setTimeout(function() {
        bullet.destroy();
    }, 4000);
};




FirstPersonMovement.prototype.onContact = function(result) {
    if (result.other.rigidbody && result.other.tags.has('bullet2')) {
        this.app.health--;
        console.log("YOU WERE HIT. Health: " + this.app.health);
    }
    
    if (result.other.rigidbody && result.other.tags.has('healthpack')) {
        this.app.health = Math.min(this.app.health + 20, 100);
        result.other.destroy();
        console.log("YOU WERE HEALED. Health: " + this.app.health);
    }
    
    if (result.other.rigidbody && result.other.tags.has('ammopack')) {
        this.app.ammo += 40;
        result.other.destroy();
        if (this.entity.sound) {
            this.entity.sound.play('ammoadd');
        }
        console.log("You got ammo. Ammo: " + this.app.ammo);
    }
};

FirstPersonMovement.prototype._onMouseMove = function(e) {
    if (pc.Mouse.isPointerLocked()) {
        this.eulers.x -= this.lookSpeed * e.dx;
        this.eulers.y -= this.lookSpeed * e.dy;
        this.eulers.y = pc.math.clamp(this.eulers.y, -90, 90);
    }
};

FirstPersonMovement.prototype._createCamera = function() {
    this.camera = new pc.Entity();
    this.camera.setName("First Person Camera");
    this.camera.addComponent("camera");
    this.entity.addChild(this.camera);
    this.camera.translateLocal(0, 0.5, 0);
};

please help. link to project: PlayCanvas 3D HTML5 Game Engine
thanks.

In my opinion you should have a separate script for the gun, but I suppose its fine to shove it into first person movement. You really need to give more information than “it doesnt shoot straight”, is the gun shooting in the same direction regardless of where the player is looking? Does it shoot off into a random direction? Is the bullet somehow misaligned from the center of the camera? I need more information.

I tried the project but all I got was “gun or camera entity not found”:

image

I also noticed your first person movement script isnt in the scripts folder for whatever reason.

I already made a gun script, so I actually can help you quite a bit. What I did is have an entity attached to the gun but disabled. Then it checks if the player has clicked and if there is more than 0 ammo. If both are true then enable the entity and play a sound. On the next frame the entity will be disabled automatically because the player hasnt clicked in the last frame. Just run some global variable checks to determine the ammo count.

ok i fixed the gun camera entity issue. PlayCanvas 3D HTML5 Game Engine
the issue is that its shooting in random directions. the first shot is kinda accurate, then its random.

Does it have to be an actual object launched? Because if you are willing to simply make it a single entity attached to the gun it would be far easier.

I could. Im really not sure how to make this work. I was trying to follow this tutorial, but its not great: https://www.youtube.com/watch?v=OnA0tvJ7JLQ&list=PLr-ymW5ydc3oG16kdfjnb5yLtRAXDz5Qn
I really don’t know. maybe hook me up to a tutorial?

Oh no I didnt use any tutorial I just figured out how to do it myself. I really dont like sending people to my project because they just end up stealing the code, or my entire game, but this is my game:

Ravioli Burglar Simulator by 18 Aliens (itch.io)

Go into the tutorial level and on a wall there is a gun (you cant miss it). Tell me if that type of mechanic would work for you.

The gun is actually pretty good. It just needs to be able to do damage, and the reload is a bit odd, but its better than what I’ve got.

Well its a revolver so it reloads one bullet at a time, the other guns reload the entire magazine. And it does do damage, just only to the cameras, and the balloon.

how would i do it?

The bullet is literally just a very long box with a collision that interacts with specified objects with rigidbodies. I dont really remember how all the scripts work at the moment, but I believe the entity is disabled every frame, then checks if the player has clicked the left mouse button. If they have the entity is enabled and plays a sound, Its really simple.

You also spelled laser wrong

that was on purpose

While Alucard’s solution works, a better solution would be putting out a raycast every shot to do the damage as raycasts are faster and will only damage the first thing, similar to how real bullets work.