Forum

movement on the surface

Discuss programming in the QuakeC language.

Moderator: InsideQC Admins

movement on the surface

Postby delta54 » Sun Feb 28, 2010 1:15 pm

Hi not long ago began to study quakec, there were several issues to resolve please help.
engine: Darkplaces


why can not move forward:
http://www.youtube.com/watch?v=KfVBmsRJrK8


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
 
Posts: 3
Joined: Sun Feb 28, 2010 1:07 pm
Location: Russia

Postby Spike » Sun Feb 28, 2010 5:24 pm

MOVETYPE_WALK never becomes a no-op.
What I mean by that, is that gravity is always applied.
And because its on a slope, it'll rebound in a non-vertical direction.
Basically, it slides because its MOVETYPE_WALK.

MOVETYPE_WALK is basically MOVETYPE_TOSS on ice, with the ability to step. It slides. Constantly.

It stops on the slope because its not moving fast enough to overcome gravity.
See what happens if you set .gravity to 0.0001
Spike
 
Posts: 2892
Joined: Fri Nov 05, 2004 3:12 am
Location: UK

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

Spike wrote:MOVETYPE_WALK never becomes a no-op.
What I mean by that, is that gravity is always applied.
And because its on a slope, it'll rebound in a non-vertical direction.
Basically, it slides because its MOVETYPE_WALK.

MOVETYPE_WALK is basically MOVETYPE_TOSS on ice, with the ability to step. It slides. Constantly.

It stops on the slope because its not moving fast enough to overcome gravity.
See what happens if you set .gravity to 0.0001

Thanks, added self.gravity = 0.01; helped.
delta54
 
Posts: 3
Joined: Sun Feb 28, 2010 1:07 pm
Location: Russia

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

how to know the angle of inclination of the surface normal under self.origin ?
delta54
 
Posts: 3
Joined: Sun Feb 28, 2010 1:07 pm
Location: Russia

Postby Urre » Sun Feb 28, 2010 6:42 pm

tracebox(self.origin, self.mins, self.maxs, self.origin + '0 0 -1', FALSE, self);
if (trace_fraction < 1 && trace_plane_normal_z > 0.7) // we're on ground, and not on a slope too steep

And to answer the question, trace_plane_normal is set by traceline and tracebox, when it hits something.
I was once a Quake modder
User avatar
Urre
 
Posts: 1109
Joined: Fri Nov 05, 2004 2:36 am
Location: Moon


Return to QuakeC Programming

Who is online

Users browsing this forum: No registered users and 1 guest