movement on the surface

Developer discussion of experimental fixes, changes, and improvements.

Moderators: Nexuiz Moderators, Moderators

movement on the surface

Postby delta54 » Sun Feb 28, 2010 10:40 am

Hello not long ago began to study quakec, there were several issues to resolve please help.

why can not move forward:


Image


Code: Select all
#define MONSTES_ENABLED
#ifdef MONSTES_ENABLED

#define crab_anim_idle         0
#define crab_anim_walk         1
#define crab_anim_spawn        2
#define crab_anim_die          3
#define crab_anim_dead         4

#define CRAB_MIN                '-5 -5 0'
#define CRAB_MAX                '5 5 5'

#define CR_IDLE     10

#define CR_PATH     100
#define CR_HUNT     200

#define CR_ATTACK_FIND  10
#define CR_ATTACK_RUN   20
#define CR_ATTACK_STAND 30

#define CR_PATH2 10000

#define MONSTERFLAG_NORESPAWN_CR 2


void crab_spawn();

float crab_scoretarget(entity trg)                              // Оценка цели
{
    float  tmp;                                    // Определяем 32 разрядную переменную tmp
    vector ang1;                                 // Определяем вектор



    if (trg.takedamage == DAMAGE_AIM)                              // Если не цель, не трогать
    if not (trg.flags & FL_NOTARGET)                              // Если нет флага notarget
    if (trg.deadflag == DEAD_NO)                              // Если мертв, не трогать
//     if (trg.team != self.team)                                 // Если свой, не трогать
    if (trg.classname == "point")
    {
        if((self.origin_z - trg.origin_z) < 128)                        // Определяем расстояние по Z
        {
            ang1 = normalize(self.origin - trg.origin);                        // Определяем расстояние по Z
            tmp = vlen(ang1 - v_forward);            // Возвращает длину вектора (Расстояние - смотреть вперед)
            if(tmp > 1.5)                                 // НЕ ПОНЯТНО !!!
            {
                traceline(self.origin + '0 0 5',trg.origin + '0 0 1',MOVE_NORMAL,self);         // Функция: traceline
                if(trace_ent != trg)               // Получаем глобадбную переменную, если не равна trg возвращаем 0
                    return 0;

                return (cvar("g_monster_crab_targetrange") - vlen(self.origin - trg.origin)) * tmp;       // Цель враг
            }
            else if(self.enemy == trg)
                return (cvar("g_monster_crab_targetrange") - vlen(self.origin - trg.origin)) * tmp;      // Цель враг
        }
    }

    return 0;                                       // Цель не враг
}

void crab_corpse_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)  // остатки , если стрелять разлетаются
{
//     dprint("crab_corpse_damage\n");
    Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 160, self, attacker);

    self.health -= damage;                                    // Вычитаем урон

    if(self.health < 0)                                       // Если у тела переменная health<0 то переходим дальше
    {
        remove(self);                                       // Удалить тело после выстрела
    }
}

void crab_die(vector dir)                              // die
{
    entity dummy;                                 // Определяем лицо-пустышку

    dummy = spawn();                                 // Создаем точку входа пустышки
    setmodel(dummy,"models/monsters/crab.dpm");                        // Определяем модель пустышки
    setorigin(dummy, self.origin);                           // Указываем позицию по вектору self.origin
    dummy.velocity  = self.velocity;                           // Направление отскакивания тела
    dummy.movetype  = MOVETYPE_BOUNCE;                           // Тип движения (MOVETYPE_BOUNCE = отскакивают от стен)
    dummy.think     = SUB_Remove;                           // ? функция удаления
    dummy.nextthink = time + 3;                              // Вызывать каждые n число секунд
    dummy.health    = 50;                              // жизней у трупа, если ноль то куски
    dummy.takedamage = DAMAGE_YES;                           // Тип Damage (DAMAGE_YES) Гранаты не взрываются при прикосновении
    dummy.event_damage = crab_corpse_damage;                        // В случае повреждения вызываем функцию "crab_corpse_damage" !!!!!!!!!
    dummy.solid      = SOLID_CORPSE;                           // тип бокса тела
    setsize(dummy,self.mins,self.maxs);                           // Размер бокса тела setsize(entity, vector_min, vector_max);

    SUB_SetFade(dummy,time + 50,2);                           // Время жизни тела


    dummy.frame = crab_anim_die;                           // play die animation
   
    if(self.spawnflags & MONSTERFLAG_NORESPAWN_CR)               // Если спаун флаг стоит и MONSTERFLAG_NORESPAWN присутствует
    {
        self.think = SUB_Remove;                  // ? функция удаления или обновления
        self.nextthink = time;                     // обновлять по времени
        return;
    }

    setmodel(self,"");                        // Удаляем все
    self.solid          = SOLID_NOT;
    self.takedamage     = DAMAGE_NO;
    self.event_damage   = SUB_Null;
    self.enemy          = world;
    self.think          = crab_spawn;
    self.nextthink      = time + cvar("g_monster_crab_respawntime");      // Ждем конца времени респавна
    self.pain_finished  = self.nextthink;
}

void crab_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
{
    self.health -= damage;
    self.velocity = self.velocity + force;
    if(self.health <= 0)
    {
        crab_die(hitloc);
        return;
    }

    Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 160, self, attacker);

   if (damage > 50)
      Violence_GibSplash_At(hitloc, force * -0.1, 3, 1, self, attacker);
   if (damage > 100)
      Violence_GibSplash_At(hitloc, force * -0.2, 3, 1, self, attacker);
   
}

.vector bvec;
.float bvec_time;

void crab_move()                     // Движение
{
    vector real_angle;                     // Объявляем вектор
    float vz, tdiff, tspeed;                  // Объявляем переменные

    tdiff = time - self.zoomstate;               // Присваеваем значение
    tspeed = tdiff * cvar("g_monster_crab_turnspeed");         // Присваеваем значение g_monster_crab_turnspeed(скорость)
    vz = self.velocity_z;                  //

    if(self.bvec_time < time)                              // вращение
    {
        self.bvec_time = time + 0.2;
        self.bvec = steerlib_beamsteer(steerlib_attract2(self.moveto,0.5,500,0.95),512,32,34,64);
    }

    if(self.enemy)                                 // Если виден враг, то двигатьсяк к нему
        self.moveto = self.enemy.origin;                        // Координаты врага self.enemy.origin

    else
        self.moveto = self.origin + v_forward;                        // Двигаться вперед

    self.steerto = normalize(steerlib_attract2(self.moveto,500,500,0.95) + self.bvec);
   
    self.angles_x = safeangle(self.angles_x);
    self.angles_y = safeangle(self.angles_y);
    self.angles_z = safeangle(self.angles_z);
    dprint("x= ", ftos(self.angles_x), "\n");
    dprint("y= ", ftos(self.angles_y), "\n");
    dprint("z= ", ftos(self.angles_z), "\n");
    real_angle = vectoangles(self.steerto) - self.angles;
    dprint("real_angle= ", vtos(real_angle), "\n");
    self.angles_y += bound(-10, real_angle_y, 10);                     // Угол поворота 10

    if(vlen(self.origin - self.moveto) > 15)
    {
        movelib_move_simple(v_forward ,cvar("g_monster_crab_movespeed"),0.6);
        if(time > self.pain_finished)
            if(self.attack_finished_single < time)
                self.frame = crab_anim_walk;                     // Анимация crab_anim_runforward
    }
    else
    {
        movelib_beak_simple(cvar("g_monster_crab_stopspeed"));
        if(time > self.pain_finished)
            if(self.attack_finished_single < time)
                self.frame = crab_anim_idle;                        // Анимация crab_anim_idle
    }

    self.velocity_z = vz;
    self.steerto = self.origin;
}

float crab_verb_idle_roam(float eval)
{
    switch (eval)
    {
    case VCM_EVAL:

        if(self.enemy)
            return VS_CALL_NO;

        return verb.verb_static_value;

    case VCM_DO:

        self.moveto = v_forward * 128;
        self.steerto = v_forward; //steerlib_beamsteer(v_forward,512,32,34,64);

        return VS_CALL_YES_DOING;
    }

    return VS_CALL_YES_DONE;
}

float crab_verb_idle_stand(float eval)
{
    switch (eval)
    {
    case VCM_EVAL:

        if(self.enemy)
            return VS_CALL_NO;

        return verb.verb_static_value;

    case VCM_DO:

        self.moveto   = self.origin;
        self.frame    = crab_anim_idle;
        self.velocity = '0 0 0';

        return VS_CALL_YES_DOING;
    }

    return VS_CALL_YES_DONE;
}

float crab_verb_idle(float eval)                  // Ожидаем
{
    switch (eval)
    {
    case VCM_EVAL:                        // Случай

        if(self.enemy)                        // Если лицо-ВРАГ возвращаем VS_CALL_NO
            return VS_CALL_NO;

        return verb.verb_static_value;                  // Возвращаем verb.verb_static_value

    case VCM_DO:
        float t;

        t = cvar("g_monster_crab_idle_timer_max") -  cvar("g_monster_crab_idle_timer_min");
        t = cvar("g_monster_crab_idle_timer_min") + (random() * t);

        if(random() < 0.5)
   {
            verbstack_push(self.verbs_idle, crab_verb_idle_roam,  CR_IDLE + 1, t, self);   
   }
        else
   {
            verbstack_push(self.verbs_idle, crab_verb_idle_stand, CR_IDLE + 1, 0.1, self);
   }
        return VS_CALL_YES_DOING;
    }

    return VS_CALL_YES_DONE;
}

float crab_verb_attack_findtarget(float eval)
{
    switch (eval)
    {
    case VCM_EVAL:
        if(self.enemy)
            return VS_CALL_NO;

        return verb.verb_static_value;

    case VCM_DO:

        entity trg, best_trg;
        float trg_score, best_trg_score;

        trg = findradius(self.origin,cvar("g_monster_crab_targetrange"));
        while(trg)
        {
            trg_score = crab_scoretarget(trg);
            if(trg_score > best_trg_score)
            {
                best_trg = trg;
                best_trg_score = trg_score;
            }

            trg = trg.chain;
        }

        if(best_trg)
        {
            self.enemy = best_trg;
            dprint("Crab sees: ",best_trg.netname, " as target.\n");
        }

        return VS_CALL_YES_DOING;
    }

    return VS_CALL_YES_DONE;
}

void crab_runattack_damage()
{
    entity oldself;
    oldself = self;
    self = self.owner;

    if(vlen(self.origin - self.enemy.origin) > cvar("g_monster_crab_attack_run_hitrange"))
        return;

    if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.6)
        return;

    Damage(self.enemy, self, self, cvar("g_monster_crab_attack_run_damage"), DEATH_TURRET, self.enemy.origin, normalize(self.enemy.origin - self.origin)  * cvar("g_monster_crab_attack_run_force"));

    self = oldself;
    self.think = SUB_Remove;
    self.nextthink = time;
}

float crab_verb_attack_run(float eval)
{
    switch (eval)
    {
    case VCM_EVAL:
        if not (self.enemy)
            return VS_CALL_NO;

        if(self.attack_finished_single > time)
            return VS_CALL_NO;

        if(vlen(self.origin - self.enemy.origin) > cvar("g_monster_crab_attack_run_range"))
            return VS_CALL_NO;

        if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.6)
            return VS_CALL_NO;

        return verb.verb_static_value;

    case VCM_DO:
        entity pain;
        pain = spawn();
        pain.owner = self;
        pain.think = crab_runattack_damage;
        pain.nextthink = time + cvar("g_monster_crab_attack_run_delay");

        self.attack_finished_single = time + 0.7;
        self.frame = crab_anim_idle;

        return VS_CALL_YES_DOING;
    }

    return VS_CALL_YES_DONE;
}

void crab_standattack_damage()
{
    //entity oldself;
    //oldself = self;
    //self = self.owner;

    setorigin(self,self.owner.origin + v_forward * 32);
    RadiusDamage(self, self.owner, cvar("g_monster_crab_attack_stand_damage"),cvar("g_monster_crab_attack_stand_damage"),16,self, cvar("g_monster_crab_attack_stand_force"),DEATH_TURRET,world);
    //float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity ignore, float forceintensity, float deathtype, entity directhitentity)


    //self = oldself;
    self.think = SUB_Remove;
    self.nextthink = time;
}

float crab_verb_attack_stand(float eval)
{
    switch (eval)
    {
    case VCM_EVAL:
        if not (self.enemy)
            return VS_CALL_NO;

        if(self.attack_finished_single > time)
            return VS_CALL_NO;

        if(vlen(self.origin - self.enemy.origin) > cvar("g_monster_crab_attack_stand_range"))
            return VS_CALL_NO;

        if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.8)
            return VS_CALL_NO;

        return verb.verb_static_value;

    case VCM_DO:
        entity pain;
        pain = spawn();
        pain.owner = self;
        pain.think = crab_runattack_damage;
        pain.nextthink = time + cvar("g_monster_crab_attack_stand_delay");

        self.attack_finished_single = time + 0.7;
        self.frame = crab_anim_idle;
        dprint("frame:",ftos(self.frame),"\n");

        return VS_CALL_YES_DOING;
    }

    return VS_CALL_YES_DONE;
}

void crab_think()                  // Размышлегия оО
{   
    self.angles_x *= -1;               // Векторы
    makevectors(self.angles);
    self.angles_x *= -1;

    if (crab_scoretarget(self.enemy) == 0)         // Поиск врага по функции crab_scoretarget()
        self.enemy = world;               // не найден, продолжаем поиск

    verbstack_pop(self.verbs_attack);            // найден

    if not (self.enemy)                  // Если не враг, ожидание
        verbstack_pop(self.verbs_idle);

    crab_move();                  // Движение

    if(self.enemy)                  // Счетчик ?
        self.nextthink = time;
    else
        self.nextthink = time + 0.2;
}

void crab_spawn()                           // Spawn()
{
    setmodel(self,"models/monsters/crab.dpm");                  // Указываем модель

    self.solid          = SOLID_BBOX;                     // Тип бокса
    self.takedamage     = DAMAGE_AIM;                     // Тип Damage
    self.event_damage   = crab_damage;                     // В случае повреждения вызывается функция crab_damage()
    self.enemy          = world;                     // Что-то про врага
    self.frame          = crab_anim_spawn;                  // Проигрываем анимацию crab_anim_spawn
    self.think          = crab_think;                     // вызывается функция crab_think()
    self.nextthink      = time + 2.1;                     // Следующий вызов через time + 2.1
    self.pain_finished  = self.nextthink;                  // time when pain sound is finished
    self.movetype       = MOVETYPE_WALK;                  // Тип передвижения
    self.health         = cvar("g_monster_crab_health");            // Количество жизней
    self.velocity       = '0 0 0';                     // Направление вектора
    self.angles         = self.pos2;                     //
    self.moveto         = self.origin;                     //
    self.flags          = FL_MONSTER;                     // Определяем как монстра

    setorigin(self,self.pos1);                        // Позиция
    setsize(self,CRAB_MIN,CRAB_MAX);                     // Размер бокса
}


void spawnfunc_monster_crab()
{
    if not(cvar("g_monsters"))                        // Если нет переменной то все удаляем лицо
    {
        remove(self);
        return;
    }

    precache_model("models/monsters/crab.dpm");                  // Кешируем модель


    self.verbs_idle   = spawn();                     // прикрепляем ожидание
    self.verbs_attack = spawn();                     //  .... атаку

    self.verbs_idle.owner = self;                     // что то там с владельцем
    self.verbs_attack.owner = self;

    self.think      = crab_spawn;                     // Намеринья ) переходим на функцию crab_spawn()
    self.nextthink  = time + 2;                        // Ждем перед слдуюжим действием

    traceline(self.origin + '0 0 0', self.origin - '0 0 5', MOVE_WORLDONLY, self);   // Функция: traceline

    self.pos1 = trace_endpos;                        // ?
    self.pos2 = self.angles;                        // ?
    self.team = MAX_SHOT_DISTANCE -1;                     // ?

    verbstack_push(self.verbs_idle, crab_verb_idle, CR_IDLE,0 , self);         // Переходим на функцию crab_verb_idle

    verbstack_push(self.verbs_attack, crab_verb_attack_findtarget, CR_ATTACK_FIND,0 , self);
    verbstack_push(self.verbs_attack, crab_verb_attack_run, CR_ATTACK_RUN,0 , self);
    verbstack_push(self.verbs_attack, crab_verb_attack_stand, CR_ATTACK_STAND,0 , self);

}

#endif   // MONSTES_ENABLED





I can not solve the problem:

1. motion parallel to the surface
2. why slips
delta54
Newbie
 
Posts: 8
Joined: Sun Dec 13, 2009 6:58 pm
Location: Russia

Re: movement on the surface

Postby FruitieX » Sun Feb 28, 2010 2:23 pm

Hmm no idea... I don't have time to read through that code either, sorry. I'd suggest taking a look at the spiderbot code to see how tZork did it, there must be something similar in there.
Image
FruitieX
Keyboard killer
 
Posts: 588
Joined: Mon Nov 13, 2006 4:47 pm
Location: Finland

Re: movement on the surface

Postby delta54 » Sun Feb 28, 2010 3:26 pm

FruitieX wrote:Hmm no idea... I don't have time to read through that code either, sorry. I'd suggest taking a look at the spiderbot code to see how tZork did it, there must be something similar in there.

I looked spiderbot.qc, but did not find a solution.
delta54
Newbie
 
Posts: 8
Joined: Sun Dec 13, 2009 6:58 pm
Location: Russia

Re: movement on the surface

Postby tZork » Sun Feb 28, 2010 3:37 pm

That code looks like a old version of my experimental monster_zombie code. That code is just that, experimental. MOVETYPE_WALK does slide / slips, thats just the way that movetype works. you need to use some other movetype or apply more friction the the movement code to avoid it. Im guessing it wont move across up the slope because you simply dont give it enough velocity to overcome the gravity influence and/or the bbox collision. Id also advice you not to use verbstack unless you are going to maintain it yourself since it will be gone form nexuiz soon.
HOF:
<Diablo> the nex is a "game modification"
<Diablo> quake1 never had a weapon like that.
<Vordreller> there was no need for anything over 4GB untill Vista came along
<Samua>]Idea: Fix it? :D
<Samua>Lies, that only applies to other people.
tZork
tZite Admin
 
Posts: 1337
Joined: Tue Feb 28, 2006 6:16 pm
Location: Halfway to somwhere else

Re: movement on the surface

Postby delta54 » Sun Feb 28, 2010 4:28 pm

tZork wrote:That code looks like a old version of my experimental monster_zombie code. That code is just that, experimental. MOVETYPE_WALK does slide / slips, thats just the way that movetype works. you need to use some other movetype or apply more friction the the movement code to avoid it. Im guessing it wont move across up the slope because you simply dont give it enough velocity to overcome the gravity influence and/or the bbox collision. Id also advice you not to use verbstack unless you are going to maintain it yourself since it will be gone form nexuiz soon.

Yes your code, I have almost no experience in the qc please give an example of another movetype, and what do you recommend to use instead verbstack?
delta54
Newbie
 
Posts: 8
Joined: Sun Dec 13, 2009 6:58 pm
Location: Russia

Re: movement on the surface

Postby tZork » Sun Feb 28, 2010 4:55 pm

I recommend a finite state machine instead of verbstack's. What movetype to use and so on if something you need to figure out by yourself since only you know what you want to achieve. look around the game for something that moves the way you want it to and look how thats done. Also have a look in constants.qh line 23--35, theres the list of possible movetypes.
HOF:
<Diablo> the nex is a "game modification"
<Diablo> quake1 never had a weapon like that.
<Vordreller> there was no need for anything over 4GB untill Vista came along
<Samua>]Idea: Fix it? :D
<Samua>Lies, that only applies to other people.
tZork
tZite Admin
 
Posts: 1337
Joined: Tue Feb 28, 2006 6:16 pm
Location: Halfway to somwhere else

Re: movement on the surface

Postby delta54 » Sun Feb 28, 2010 5:01 pm

tZork wrote:I recommend a finite state machine instead of verbstack's. What movetype to use and so on if something you need to figure out by yourself since only you know what you want to achieve. look around the game for something that moves the way you want it to and look how thats done. Also have a look in constants.qh line 23--35, theres the list of possible movetypes.

thanks, I will examine
delta54
Newbie
 
Posts: 8
Joined: Sun Dec 13, 2009 6:58 pm
Location: Russia

Re: movement on the surface

Postby delta54 » Sun Feb 28, 2010 5:52 pm

self.gravity = 0.01; helped

how to know the angle of inclination of the surface normal under self.origin ?
delta54
Newbie
 
Posts: 8
Joined: Sun Dec 13, 2009 6:58 pm
Location: Russia


Return to Nexuiz - Development

Who is online

Users browsing this forum: No registered users and 1 guest