please tell please
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.
You can try to learn this by following the course below.
thanks but i am trying to learn another programming language named LUA
for cryengine
this is my first game engine I have tried thanks and bye
love this engine