Gamestudio Links
Zorro Links
Newest Posts
Change chart colours
by 7th_zorro. 05/11/24 09:25
Data from CSV not parsed correctly
by dr_panther. 05/06/24 18:50
AUM Magazine
Latest Screens
The Bible Game
A psychological thriller game
SHADOW (2014)
DEAD TASTE
Who's Online Now
2 registered members (TipmyPip, AndrewAMD), 1,151 guests, and 4 spiders.
Key: Admin, Global Mod, Mod
Newest Members
Hanky27, firatv, wandaluciaia, Mega_Rod, EternallyCurious
19051 Registered Users
Previous Thread
Next Thread
Print Thread
Rate Thread
Multiplayer RPG Style "Enemy AI + Spawn Combo" #154317
09/15/07 09:48
09/15/07 09:48
Joined: Aug 2005
Posts: 390
Florida
O
oldschoolj Offline OP
Senior Member
oldschoolj  Offline OP
Senior Member
O

Joined: Aug 2005
Posts: 390
Florida
Hi folks,

Here is a very basic, watered down version of what I use to spawn enemies, and init their AI states. I'm not going to go into this code but I will say that in order to make this work properly you will have to add certain skills to your player. They are already defined and commented.

If you use this code the way it is:
Enemies will spawn up to five, and if you kill them they will die, fade out, and start repawning.
Enemies will move freely within the range specified that keeps them close enough to the spawn point.
Enemies have two attacks, a powerful one and a less powerful one. They will use either of them randomly, but the more powerful attack has less of a chance of happenning. Both attacks are on timers, and the enemies will wait before attacking.
Enemies will spot a player if within their scan range. They can only sense an enemy that is within a 180 radius of the front. They will turn toward the player, and wait to see if they get to close, if the player moves to far, they will begin moving around freely again. If the player comes within aggro range the enemy will go into attack mode, and begin chasing the player. Once within melee range the enemy begins atttacking. If the player moves the out of the spawn point range, and also out of aggro range, t he enemy will ignore the player and go back to within range of the spawn point.
This code is tested and works. If you neeed any help with it just give me a pm, also all of the variables, functions vectors, etc. are pretty much in template form, so just rename them.

Have fun...

Code:
#define 	MOVEMENT_SPEED 	skill1		//how an enemy can move
#define SCAN_RANGE skill2 //how far enemy can scan
#define COMBAT_MODE skill3 //in combat or out of combat **assign to player as well
#define IN_COMBAT 1
#define OUT_OF_COMBAT 2
#define STATUS skill4 //AI status
#define REST 3
#define SENSE 4
#define COMBAT 5
#define DEATH 20
#define ANIMATION_SPEED skill5 //animation speeds
#define PANNING skill6 //for rotating out of the way
#define ENEMY_SKILL01 skill7 //switching for skills
#define ENEMY_SKILL02 skill8 //switching for skills
#define ENEMY skill9 //the enemy **assign to player as well
#define LIFE skill10 //my hitpoints **assign to player as well
#define AGGRO_RANGE skill11 //the range at which the player can be attacked **player ONLY
#define ATTACKABLE skill12 //can be attacked **assign to player as well

// Prototypes
function enemy_spawn_point(); //spawns enemies
function enemy_init(); //initializes the enemies ai
function attach_to_ground(); //keeps enemies on the ground
function attack1_timer(); //countdown to enemy attack1
function attack2_timer(); //countdown to enemy attack2


//Entities
ENTITY* enemy; //enemy ent
ENTITY* spawn_point; //spawnpoint ent

//Variables
var max_enemies; //maximum enemies
var enemy_positioning [15] = {445,-10,740,775,350,740,930,-430,740,360,-250,740,-130,316,740}; // possible spawn points
var enemy_index = 0; //grabs numbers for spawn locations
var distance_to_ground; //used in keeping entities on the ground
var attack_decider; //chooses a random attack


//Vectors
VECTOR enemy_spawn_vector; //spawn location
vec_zero(enemy_spawn_vector);
VECTOR spawn_point_vector; //spawwn point location
vec_zero(spawn_point_vector);
VECTOR spawn_point_speed_vector; //used to stick the spawnpoint to the ground
vec_zero(spawn_point_speed_vector);
VECTOR temp_spawn_vector; //used to keep enemies within range of the spawnpoint
vec_zero(temp_spawn_vector);
VECTOR temp_enemy_vector; //used to seek out the player
vec_zero(temp_enemy_vector);
VECTOR enemy_ground_vector; //used to stick enemy to ground
vec_zero(enemy_ground_vector);


function enemy_spawn_point()
{
while (1)
{
while (max_enemies <= 5)
{
wait (-15);
enemy_index = 3 * integer(random(5));
enemy_spawn_vector.x = enemy_positioning[enemy_index + 0];
enemy_spawn_vector.y = enemy_positioning[enemy_index + 1];
enemy_spawn_vector.z = enemy_positioning[enemy_index + 2];
enemy = ent_create ("enemy_model.mdl", enemy_spawn_vector, enemy_init);
if (enemy_index > 4) enemy_index = 0;
max_enemies += 1;
wait (1);
}
wait (1);
}
}
action spawn_point01()
{
set (my, INVISIBLE);
while (1)
{
spawn_point = me;
spawn_point_speed_vector.z = 8 * time_step;
vec_set (spawn_point_vector.x, my.x);
spawn_point_vector.z -= 5000;
distance_to_ground = c_trace (my.x, spawn_point_vector.x, IGNORE_ME | USE_BOX | IGNORE_PASSABLE);
spawn_point_speed_vector.z = - (distance_to_ground - 17); // 17 = experimental value
spawn_point_speed_vector.z = maxv (-35 * time_step, spawn_point_speed_vector.z); // 35 = falling speed
c_move (my, spawn_point_speed_vector, nullvector, IGNORE_MODELS | GLIDE);
wait (1);
}
}

function enemy_init()
{
attach_to_ground(); // keep me on the ground
if(!my.SCAN_RANGE) my.SCAN_RANGE = 600; //Range that the enemy can detect others
if(!my.MOVEMENT_SPEED) my.MOVEMENT_SPEED = 8; //When walking or running
if(!my.COMBAT_MODE) my.COMBAT_MODE = OUT_OF_COMBAT; //Initial combat state
if(!my.ATTACKABLE) my.ATTACKABLE = 1; //Enemy is attackable
if(!my.LIFE) my.LIFE = 80;
my.STATUS = REST;
while(my.LIFE > 0) // still alive?
{
set (my, PASSABLE); //your preference
c_scan (my.x, my.pan, vector(180, 180, my.SCAN_RANGE), IGNORE_ME | IGNORE_PASSABLE | SCAN_ENTS | SCAN_LIMIT);
if (my.STATUS == REST)
{
if ((vec_dist (my.x, player.x) > player.AGGRO_RANGE * 1.5) && (vec_dist (my.x, player.x) < my.SCAN_RANGE * 1.5)) {my.STATUS = SENSE; my.ENEMY = 0;}
if (vec_dist (my.x, player.x) < player.AGGRO_RANGE * 1.5) {my.STATUS = COMBAT; my.ENEMY = 1;}
my.COMBAT_MODE = OUT_OF_COMBAT;
my.ANIMATION_SPEED += 6 * time_step;
if (vec_dist (my.x, spawn_point_vector.x) < 800)
{
ent_animate(my, "move", my.ANIMATION_SPEED, ANM_CYCLE); // play the "move" animation
c_move (my, vector(my.MOVEMENT_SPEED * time_step,0,0), nullvector, GLIDE | IGNORE_YOU | IGNORE_PASSABLE);
}
if (vec_dist (my.x, spawn_point_vector.x) > 800)
{
vec_set (temp_spawn_vector, spawn_point_vector.x);
vec_sub (temp_spawn_vector, my.x);
vec_to_angle (my.pan, temp_spawn_vector);
my.tilt = 0;
ent_animate(my, "move", my.ANIMATION_SPEED, ANM_CYCLE); // play the "move" animation
c_move (my, vector(my.MOVEMENT_SPEED * time_step,0,0), nullvector, GLIDE | IGNORE_YOU | IGNORE_PASSABLE);
}
if (c_scan (my.x,my.pan, vector (180,180,250), IGNORE_ME | IGNORE_PASSABLE | SCAN_ENTS | SCAN_LIMIT) > 0)
{
my.PANNING = 30 + random(120);
while (my.pan < my.PANNING)
{
my.pan += 50 * time_step;
wait (1);
}
}
}
if (my.STATUS == SENSE)
{
if (player == NULL) {my.STATUS = REST; my.ENEMY = 0;}
if (player.LIFE <= 0) {my.STATUS = REST; my.ENEMY = 0;}
if (player.ATTACKABLE == 0) {my.STATUS = REST; my.ENEMY = 0;}
if (vec_dist (my.x, player.x) > my.SCAN_RANGE * 1.5) {my.STATUS = REST; my.ENEMY = 0;}
if (vec_dist (my.x, player.x) < player.AGGRO_RANGE * 1.5) {my.STATUS = COMBAT; my.ENEMY = 0;}
my.COMBAT_MODE = OUT_OF_COMBAT;
my.ANIMATION_SPEED += 8 * time_step;
vec_set (temp_enemy_vector, player.x);
vec_sub (temp_enemy_vector, my.x);
vec_to_angle (my.pan, temp_enemy_vector);
my.tilt = 0;
ent_animate(my, "chase", my.ANIMATION_SPEED, ANM_CYCLE);
}
if (my.STATUS == COMBAT)
{
if (player == NULL) {my.STATUS = REST; my.ENEMY = 0;}
if (player.LIFE <= 0) {my.STATUS = REST; my.ENEMY = 0;}
if (player.ATTACKABLE == 0) {my.STATUS = REST; my.ENEMY = 0;}
if (vec_dist (my.x, player.x) > my.SCAN_RANGE * 1.5) {my.STATUS = REST; my.ENEMY = 0;}
if ((vec_dist (my.x, player.x) > player.AGGRO_RANGE * 1.5) && (vec_dist (my.x, player.x) < my.SCAN_RANGE * 1.5)) {my.STATUS = SENSE; my.ENEMY = 0;}
my.COMBAT_MODE = IN_COMBAT;
if (vec_dist (my.x, player.x) > 150)
{
my.ANIMATION_SPEED += 6 * time_step;
vec_set (temp_enemy_vector, player.x);
vec_sub (temp_enemy_vector, my.x);
vec_to_angle (my.pan, temp_enemy_vector);
my.tilt = 0;
ent_animate(my, "chase", my.ANIMATION_SPEED, ANM_CYCLE);
c_move (my, vector(my.MOVEMENT_SPEED * time_step, 0, 0), nullvector, GLIDE | IGNORE_YOU | IGNORE_PASSABLE);
}
if (vec_dist (my.x, player.x) <= 150)
{
vec_set (temp_enemy_vector, player.x);
vec_sub (temp_enemy_vector, my.x);
vec_to_angle (my.pan, temp_enemy_vector);
my.tilt = 0;
attack_decider = random(10);
if ((attack_decider > 9.2) && (my.ENEMY_SKILL02 == 0)) //the powerful attack
{
my.ENEMY_SKILL01 = 1;
my.ANIMATION_SPEED = 0;
while (my.ANIMATION_SPEED < 100)
{
ent_animate(my, "attack2", my.ANIMATION_SPEED, NULL);
my.ANIMATION_SPEED += 6 * time_step;
wait (1);
}
attack1_timer();
attack2_timer();
}
if ((attack_decider < 9.2) && (my.ENEMY_SKILL01 == 0)) //the basic attack
{
my.ENEMY_SKILL02 = 1;
my.ANIMATION_SPEED = 0;
while (my.ANIMATION_SPEED < 100)
{
ent_animate(my, "attack1", my.ANIMATION_SPEED, NULL);
my.ANIMATION_SPEED += 6 * time_step;
wait (1);
}
attack2_timer();
attack1_timer();
}
ent_animate(my, "attack_wait", my.ANIMATION_SPEED, ANM_CYCLE);
my.ANIMATION_SPEED += 6 * time_step;
}
}
wait (1);
}
player.COMBAT_MODE = OUT_OF_COMBAT;
player.ENEMY = 0;
my.ANIMATION_SPEED = 0;
while (my.ANIMATION_SPEED < 100)
{
ent_animate(my, "death", my.ANIMATION_SPEED, NULL);
my.ANIMATION_SPEED += 4 * time_step; // "death" animation speed
wait (1);
}
wait (-3);
set (my, TRANSLUCENT);
my.alpha = 100;
while (my.alpha > 0)
{
my.alpha -= 5 * time_step;
wait(1);
}
wait (1);
ent_remove (my);
}
function attach_to_ground()
{
// As long as I exists
while(my)
{
vec_set(enemy_ground_vector,vector(my.x,my.y,my.z + my.min_z));
vec_set(target,vector(my.x,my.y,my.z - 5000));

// Subtract the distance to the ground from my.z
my.z -= c_trace(enemy_ground_vector,target, IGNORE_ME | IGNORE_YOU | IGNORE_PASSABLE) -100;

// If we got too long down...
if(c_content(vector(my.x,my.y,my.z + my.min_z),0) == 3)
{
// Then move me a little upwards
my.z += 3 * time_step;
}
wait(1);
}
}

function attack1_timer() {my.ENEMY_SKILL01 = 1; wait (-3); my.ENEMY_SKILL01 = 0;}
function attack2_timer() {my.ENEMY_SKILL02 = 1; wait (-3); my.ENEMY_SKILL02 = 0;}



Thanks to several people who have posted code snippets, and also George and the magazine.
* one problem that I can see, sometimes when 3 or more enemies are aggro'd and then returned (out of range), the tend to get hung up near the spawn point and spin around radically for a few seconds. If anyone has a resolve for this, just post that would be great.
*enemies sometimes hop over each other as well...
*forgot to add: max_enemies = 0; //put his before the wait (1); after the while look in the enemy spawn function
Jesse

Last edited by oldschoolj; 09/15/07 10:22.

you can find me with my face in the keyboard, unshaven, listening to some nameless techno tragedy, and hashing through code over a cold cup a stale joe. __________________________________ yours truly
Re: Multiplayer RPG Style "Enemy AI + Spawn Combo" [Re: oldschoolj] #154318
09/15/07 11:19
09/15/07 11:19
Joined: Oct 2006
Posts: 91
G
Ghost Offline
Junior Member
Ghost  Offline
Junior Member
G

Joined: Oct 2006
Posts: 91
Fantastic contribution, no doubt very useful to many others.

Thank you very much for sharing.


Moderated by  HeelX, Lukas, rayp, Rei_Ayanami, Superku, Tobias, TWO, VeT 

Gamestudio download | chip programmers | Zorro platform | shop | Data Protection Policy

oP group Germany GmbH | Birkenstr. 25-27 | 63549 Ronneburg / Germany | info (at) opgroup.de

Powered by UBB.threads™ PHP Forum Software 7.7.1