[SOLVED] How to make enemy damage player

please tell :potable_water:please :pray: :pray: :pray: :pray: :pray:

Hello @MATURE !

In my example project below, the enemy can shoot a bullet on the player. This bullet acts as a trigger and has the bullet.js script. This script takes damage to the player. The player.js script does the last part.

https://playcanvas.com/project/870482/overview/basic-enemy-ai

cant player fire

// Basic enemy AI - version 1.1
var Enemy = pc.createScript('enemy');

Enemy.attributes.add('enemyTarget', {type: 'entity', title: 'Target Entity'});
Enemy.attributes.add('enemyHud', {type: 'entity', title: 'Hud Entity'});
Enemy.attributes.add('enemyBullet', {type: 'entity', title: 'Bullet Entity'});
Enemy.attributes.add('debugSensors', {type: 'boolean', default: false, title: 'Debug Sensors'});
Enemy.attributes.add('sensorLength', {type: 'number', default: 1, title: 'Sensor Length'});
Enemy.attributes.add('sensorHeight', {type: 'number', default: 1, title: 'Sensor Height'});
Enemy.attributes.add('rotationSpeed', {type: 'number', default: 1, title: 'Rotation Speed'});
Enemy.attributes.add('viewRange', {type: 'number', default: 20, title: 'View Range'});
Enemy.attributes.add('searchRange', {type: 'number', default: 10, title: 'Search Range'});
Enemy.attributes.add('searchSpeed', {type: 'number', default: 1, title: 'Search Speed'});
Enemy.attributes.add('chaseSpeed', {type: 'number', default: 2, title: 'Chase Speed'});
Enemy.attributes.add('chaseTime', {type: 'number', default: 5, title: 'Chase Time'});
Enemy.attributes.add('combatRange', {type: 'number', default: 5, title: 'Combat Range'});

// Set this to true when target can be heard
var enemyTargetIsAudible = false; 

// Initialize code called once per entity
Enemy.prototype.initialize = function() {
    this.enemy = this.entity;
    this.enemy.tags.add('AI');
    this.enemyState = 'Search';
    this.enemyAnimation = 'Idle';
    this.enemySearchTimer = 0;
    this.enemyChaseTimer = 0;
    this.enemyViewTimer = 0;
    this.enemyTargetDistance = 0; 
    this.enemyTargetPosition = new pc.Vec3();
    this.enemyDestination = new pc.Vec3();
    this.enemyDirection = new pc.Vec3(); 
    this.enemyRotation = new pc.Vec3(); 
    this.enemyOrigin = this.enemy.getPosition().clone();
    this.enemyCanSeeTarget = false; 
    this.enemyCanHearTarget = false;
    this.enemyIsAlive = true;
    this.enemyIsAttacking = false;
    this.enemyIsMoving = false;
};

// Update code called every frame
Enemy.prototype.update = function(dt) {
    this.updateView(dt);
    this.updateAudio(dt);
    this.updateState(dt);
    this.updateMovement(dt);
    this.updateAnimation(dt);
};

// This function controls the view of the enemy
Enemy.prototype.updateView = function (dt) {
    var visibleTarget = false;
    
    if (this.enemyTarget) {
        // Check distance to target
        this.enemyTargetDistance = this.enemy.getPosition().distance(this.enemyTarget.getPosition());

        // Check if target is in range
        if (this.enemyTargetDistance < this.viewRange) {
            var target = this.enemyTarget.getPosition();
            target.sub(this.enemy.getPosition()).normalize();
            var dot = target.dot(this.enemy.forward);
            
            // Check if target is in front
            if (dot > 0.5) {
                var start = new pc.Vec3(this.enemy.getPosition().x, this.enemy.getPosition().y + this.sensorHeight, this.enemy.getPosition().z);
                var end = this.enemyTarget.getPosition();
                var result = this.raycast(start, end, 2);

                // Check if target is in view
                if (result && result.entity === this.enemyTarget) {
                    visibleTarget = true;
                    this.enemyViewTimer += dt;
                    if (this.enemyViewTimer > 0.15) {
                        this.enemyCanSeeTarget = true;
                        this.enemyTargetPosition.copy(this.enemyTarget.getPosition());
                    }
                }
            } 
        }
    }

    if (!visibleTarget) {
        this.enemyViewTimer = 0;
        this.enemyCanSeeTarget = false;
    }
};

// This function check if target can be heard
Enemy.prototype.updateAudio = function () {
    this.enemyCanHearTarget = false;

    if (enemyTargetIsAudible) {
        if (this.enemyTargetDistance < this.combatRange) {
            this.enemyCanHearTarget = true;
            this.enemyTargetPosition.copy(this.enemyTarget.getPosition());
        }
    }
};

// This function controls the enemy state
Enemy.prototype.updateState = function (dt) {
    // If enemy is alive
    if (this.enemyState != 'Dead') {
        // If there is a target
        if (this.enemyTarget) {
            // If current state is search
            if (this.enemyState == 'Search') {
                if (this.enemyCanSeeTarget) {
                    if (this.enemyTargetDistance > this.combatRange*2) {
                        this.enemyState = 'Chase';
                    }
                    else if (this.enemyTargetDistance < this.combatRange) {
                        this.enemyState = 'Combat';
                    }
                    else if (this.enemyState != 'Combat') {
                        this.enemyState = 'Chase';
                    }
                }
                else if (this.enemyCanHearTarget) {
                    this.enemyState = 'Chase';
                }
            }
            // If current state is chase
            else if (this.enemyState == 'Chase') {
                if (this.enemyCanSeeTarget) {
                    if (this.enemyTargetDistance < this.combatRange) {
                        this.enemyChaseTimer = 0;
                        this.enemyState = 'Combat';
                    }
                } 
                else {
                    this.enemyChaseTimer += dt;
                    if (this.enemyChaseTimer < this.chaseTime) {
                        this.enemyTargetPosition.copy(this.enemyTarget.getPosition());
                    }
                    else if (this.enemyTargetDistance < this.combatRange || this.enemyChaseTimer > this.chaseTime*2) {
                        this.enemyChaseTimer = 0;
                        this.enemyState = 'Search';
                    }
                }
            }
            // If current state is combat
            else if (this.enemyState == 'Combat') {
                if (this.enemyCanSeeTarget) {
                    if (this.enemyTargetDistance > this.combatRange*2) {
                        this.enemyState = 'Chase';
                    }
                } 
                else {
                    this.enemyState = 'Chase';
                }
            }
            else {
                this.enemyState = 'Search';
            }
        }
    }

    // Exectue current state
    this[this.enemyState](dt);

    // Update enemy hud
    if (this.enemyHud) { 
        this.enemyHud.element.text = this.enemyState; 
    }
};

// Search state
Enemy.prototype.Search = function (dt) {
    this.enemySpeed = this.searchSpeed;
    this.enemySearchTimer -= dt;
    if (this.enemySearchTimer <= 0) {
        this.enemySearchTimer = Math.random() * this.chaseTime;
        this.getRandomDestination(this.enemyOrigin);
    }
};

// Chase state
Enemy.prototype.Chase = function (dt) {
    this.enemySpeed = this.chaseSpeed;
    this.setDestination(this.enemyTargetPosition);
};

// Combat state
Enemy.prototype.Combat = function (dt) {
    this.enemySpeed = 0;
    this.setDestination(this.enemyTargetPosition);
 
    if (!this.enemyIsAttacking && !this.enemyIsMoving) {
        this.Attack();
    }
};

// Dead state
// Set this.enemyIsAlive to false to apply this state
Enemy.prototype.Dead = function (dt) {
    this.enemySpeed = 0;
    this.setDestination(this.enemy.getPosition());
};

// Attack function
Enemy.prototype.Attack = function () {
    this.enemyIsAttacking = true;
    
    if (this.enemyBullet) {
        var bullet = this.enemyBullet.clone();
        this.app.root.addChild(bullet);
        bullet.setPosition(this.enemyBullet.getPosition());
        bullet.lookAt(this.enemyTarget.getPosition());
        bullet.enabled = true;
    }

    setTimeout(function(){
        this.enemyIsAttacking = false;
    }.bind(this), 1000);
};

// Set enemy destination based on the given position
Enemy.prototype.setDestination = function (position) {
    this.enemyDestination.copy(new pc.Vec3(position.x, this.enemy.getPosition().y, position.z));
};

// Get random destination around the given position
Enemy.prototype.getRandomDestination = function (position) {
    var positionX = pc.math.random(position.x - this.searchRange, position.x + this.searchRange);
    var positionZ = pc.math.random(position.z - this.searchRange, position.z + this.searchRange);
    this.enemyDestination.copy(new pc.Vec3(positionX, this.enemy.getPosition().y, positionZ));
};

// This function update the position and rotation
Enemy.prototype.updateMovement = function (dt) {
    this.enemyIsMoving = false;
    
    // Move enemy forward
    if (this.enemySpeed > 0 && this.enemy.getPosition().distance(this.enemyDestination) > this.sensorLength) {
        this.enemy.translateLocal(0, 0, -this.enemySpeed*dt);
        this.enemyIsMoving = true;
    }

    // Create raycasts
    var origin = this.enemy.getPosition();
    var start = new pc.Vec3(origin.x, origin.y + this.sensorHeight, origin.z);
    var startLeft = new pc.Vec3().copy(this.enemy.forward).scale(this.sensorLength/2).add(start);
    var endLeft = new pc.Vec3().copy(this.enemy.right).scale(-this.sensorLength).add(startLeft);
    var startRight = new pc.Vec3().copy(this.enemy.forward).scale(this.sensorLength/2).add(start);
    var endRight = new pc.Vec3().copy(this.enemy.right).scale(this.sensorLength).add(startRight);
    var startLeftFront = new pc.Vec3().copy(this.enemy.right).scale(-this.sensorLength/2.5).add(start);
    var endLeftFront = new pc.Vec3().copy(this.enemy.forward).scale(this.sensorLength).add(startLeftFront);
    var startRightFront = new pc.Vec3().copy(this.enemy.right).scale(this.sensorLength/2.5).add(start);
    var endRightFront = new pc.Vec3().copy(this.enemy.forward).scale(this.sensorLength).add(startRightFront);
    var endLeftBottom = new pc.Vec3(endLeft.x, endLeft.y -this.sensorLength*10, endLeft.z);
    var endRightBottom = new pc.Vec3(endRight.x, endRight.y -this.sensorLength*10, endRight.z);
    var endRightFrontBottom = new pc.Vec3(endRightFront.x, endRightFront.y -this.sensorLength*10, endRightFront.z);
    var endLeftFrontBottom = new pc.Vec3(endLeftFront.x, endLeftFront.y -this.sensorLength*10, endLeftFront.z);
    var endCenterBottom = new pc.Vec3(origin.x, origin.y -this.sensorLength*10, origin.z);

    // Raycast results
    var hitLeft = this.raycast(start, endLeft, 1);
    var hitRight = this.raycast(start, endRight, 1);
    var hitLeftFront = this.raycast(start, endLeftFront, 1);
    var hitRightFront = this.raycast(start, endRightFront, 1);
    var hitLeftBottom = this.raycast(endLeft, endLeftBottom, 1);
    var hitRightBottom = this.raycast(endRight, endRightBottom, 1);
    var hitLeftFrontBottom = this.raycast(endLeftFront, endLeftFrontBottom, 1);
    var hitRightFrontBottom = this.raycast(endRightFront, endRightFrontBottom, 1);
    var hitCenterBottom = this.raycast(start, endCenterBottom, 2);

    // Debug sensors
    if (this.debugSensors) {
        this.app.drawLine(start, endLeft, pc.Color.WHITE);
        this.app.drawLine(start, endRight, pc.Color.WHITE);
        this.app.drawLine(start, endLeftFront, pc.Color.WHITE);
        this.app.drawLine(start, endRightFront, pc.Color.WHITE);
        this.app.drawLine(endLeft, endLeftBottom, pc.Color.WHITE);
        this.app.drawLine(endRight, endRightBottom, pc.Color.WHITE);
        this.app.drawLine(endRightFront, endRightFrontBottom, pc.Color.WHITE);
        this.app.drawLine(endLeftFront, endLeftFrontBottom, pc.Color.WHITE);
        this.app.drawLine(start, endCenterBottom, pc.Color.WHITE);
    }

    // Keep enemy on ground
    if (hitCenterBottom) {
        this.entity.setPosition(this.enemy.getPosition().x, hitCenterBottom.point.y, this.enemy.getPosition().z);
    }

    // If this.enemyDirection.y less than 0 target is on the right and if more than 0 is target is on the left
    this.enemyDirection.cross(this.entity.forward, this.enemyRotation.copy(this.enemyDestination).sub(this.entity.getPosition()));

    // Reset rotation speed
    rotation = 0;

    // Avoid obstacles on the left
    if (hitLeftFront || !hitLeftFrontBottom) {
        rotation -= 1;
    } 
    // Rotate to target on the left
    else if (!hitLeft && hitLeftBottom) {
        if (this.enemyDirection.y > 1) {
            rotation += 1;
        }
        else if (this.enemyDirection.y > 0) {
            rotation += 0.1;
        }
    }  
   
    // Avoid obstacles on the right
    if (hitRightFront || !hitRightFrontBottom) {
        rotation += 1;
    } 
    // Rotate to target on the right
    else if (!hitRight && hitRightBottom) {
        if (this.enemyDirection.y < -1) {
            rotation -= 1;
        }
        else if (this.enemyDirection.y < 0) {
            rotation -= 0.1;
        }
    }

    // Avoid obstacles in front
    if (this.enemyIsMoving) {
        if ((hitLeftFront || !hitLeftFrontBottom) && (hitRightFront || !hitRightFrontBottom)) {
            if (!hitLeft && hitLeftBottom) {
                rotation += 100;
            }
            if (!hitRight && hitRightBottom) {
                rotation -= 100;
            }
            if (rotation === 0) {
                rotation = 100;
            }
        }
    }

    // Apply correct rotation speed
    this.enemy.rotate(0, rotation*this.rotationSpeed*100*dt, 0);
};

// Prepared function to apply your own animations
Enemy.prototype.updateAnimation = function (dt) {
    if (this.entity.anim && this.entity.anim.enabled) {
        if (this.enemyIsAlive) {
            if (this.enemyIsMoving) {
                if (this.enemySpeed > this.searchSpeed) {
                    this.enemyAnimation = 'Run';
                } 
                else {
                    this.enemyAnimation = 'Walk';
                }
            }
            else if (this.enemyIsAttacking) {
                this.enemyAnimation = 'Attack';
            } 
            else {
                this.enemyAnimation = 'Idle';
            }
        } 
        else {
            this.enemyAnimation = 'Dead';
        }

        if (this.entity.anim.baseLayer.activeState != this.enemyAnimation) {
            this.entity.anim.baseLayer.play(this.enemyAnimation);
        }
    }
};

// Sensor to detect entities with rigidbody only
Enemy.prototype.raycast = function (start, end, condition) {
    var distanceVec3 = new pc.Vec3();
    var closestDistanceSqr = Number.MAX_VALUE;
    var closestResult = null;
    var results = this.app.systems.rigidbody.raycastAll(start, end);

    for (var i = 0; i < results.length; ++i) {
        var result = results[i];

        if (result.entity.rigidbody) {
            if (condition === 1 || (condition === 2 && !result.entity.tags.has('AI'))) {
                distanceVec3.sub2(result.point, start);
                var distanceSqr = distanceVec3.lengthSq();
                if (distanceSqr < closestDistanceSqr) {
                    closestDistanceSqr = distanceSqr;
                    closestResult = result;
                }
            }
        }
    }

    return closestResult;
};

can you tell where is the script to fire

No, the player can’t shoot in this example.

On lines 209 to 213 above, a new bullet is created.

thanks but i will leave this engine

is not bad but i cant even write a code

Sad to hear. :cry:

You can try to learn this by following the course below.

https://developer.playcanvas.com/en/tutorials/crash-course/

1 Like

thanks but i am trying to learn another programming language named LUA
for cryengine :cold_sweat: :cold_sweat: :heartbeat: :heartbeat: :heartbeat: :heartbeat: :heartbeat:
this is my first game engine I have tried thanks and bye

1 Like

love this engine :heartbeat: :heartbeat: :heartbeat: :heartbeat: :heartbeat: :heartbeat: :heartbeat: :heartbeat: