movement on the surface

Developer discussion of experimental fixes, changes, and improvements.

Moderators: Nexuiz Moderators, Moderators

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
    User avatar
    delta54
    Newbie
     
    Posts: 8
    Joined: Sun Dec 13, 2009 6:58 pm
    Location: Russia

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
    User avatar
    FruitieX
    Keyboard killer
     
    Posts: 588
    Joined: Mon Nov 13, 2006 4:47 pm
    Location: Finland

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.
    User avatar
    delta54
    Newbie
     
    Posts: 8
    Joined: Sun Dec 13, 2009 6:58 pm
    Location: Russia

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.
    User avatar
    tZork
    tZite Admin
     
    Posts: 1337
    Joined: Tue Feb 28, 2006 6:16 pm
    Location: Halfway to somwhere else

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?
    User avatar
    delta54
    Newbie
     
    Posts: 8
    Joined: Sun Dec 13, 2009 6:58 pm
    Location: Russia

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.
    User avatar
    tZork
    tZite Admin
     
    Posts: 1337
    Joined: Tue Feb 28, 2006 6:16 pm
    Location: Halfway to somwhere else

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
    User avatar
    delta54
    Newbie
     
    Posts: 8
    Joined: Sun Dec 13, 2009 6:58 pm
    Location: Russia

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 ?
    User avatar
    delta54
    Newbie
     
    Posts: 8
    Joined: Sun Dec 13, 2009 6:58 pm
    Location: Russia



Return to Nexuiz - Development




Information
  • Who is online
  • Users browsing this forum: No registered users and 1 guest