/**
 * The problem with this is that it doesn't really know if it's already performed turnaround,
 * and has no hysteresis, so it ends up wobbling its ass a lot, decelerating much more slowly
 * than it should be able to, and overshooting the target.
 *
 * Also for reasons I can't figure out, it only accelerates for about the first third of the trajectory,
 * instead of until halfway as it should.
 */
void SimpleShipMovementController::step(RocketShip& ship, point2 target) {
    // Angular tolerance within which directions are considered equivalent.
    const plane_angle direction_slop = ship.side_thruster_acceleration() * pow<2>(0.25*seconds);

    ship.stop_turning();
    ship.thrust_off();

    vec2<length> r = target - ship.position();
    unit_vec2 rhat(r);
    vec2<velocity> dr = ship.velocity();
    acceleration dv = ship.main_thruster_acceleration();

    // Not sure WTF these expressions mean physically, but it's the result of hours of screwing around and seems to produce nice results.
    unit_vec2 thrust_direction_towards(rhat*fudge_direction_ratio_ - dr.rejection(r)*((1-fudge_direction_ratio_)*second/meter));
    unit_vec2 thrust_direction_away(-rhat*fudge_direction_ratio_ - dr.rejection(r)*((1-fudge_direction_ratio_)*second/meter));


    time_interval time_to_target = r.magnitude() / dr.scalar_projection(r);
    time_interval time_to_stop = dr.scalar_projection(r) / dv;

    //plane_angle turnaround_delta_a = angle_difference(thrust_direction_away.angle(), ship.heading() + M_PI*radians);
    //time_interval maximum_turnaround_time = .75*seconds; // FIXME: pull this number from somewhere other than my ass
    //time_to_stop -= maximum_turnaround_time*(fabs(turnaround_delta_a) / (M_PI*radians)); // is this really linear wrt delta_a?
    /*
    if(fabs(turnaround_delta_a) > direction_slop) {
        time_to_stop -= maximum_turnaround_time*(fabs(turnaround_delta_a) / (M_PI*radians));
    }
    */

    unit_vec2 thrust_direction(0,0);
    if(time_to_target < 0*seconds || time_to_stop < time_to_target) {
        // Before turnaround - thrust towards the target.
        thrust_direction = thrust_direction_towards;
    } else {
        // After turnaround - thrust away from the target.
        thrust_direction = thrust_direction_away;
    }
    point_at(ship, thrust_direction);
    // Thrust if heading within tolerance
    if(fabs(angle_difference(thrust_direction.angle(), ship.heading())) < direction_slop) {
        ship.thrust_on();
    }
    // Finally,
    ship.update_forces();
}
Esempio n. 2
0
void bonesManipulation::SetMotion(CBoneInstance *bone, u8 axis, float target_yaw, float r_speed, u32 t)
{
	int index = -1;
	// найти бону bone в m_Bones
	for (u32 i=0; i<m_Bones.size(); ++i)  {
		if ((m_Bones[i].bone == bone) && (m_Bones[i].axis == axis)) {
			index = i;
			break;
		}
	}
	R_ASSERT(-1 != index);

	m_Bones[index].params.target_yaw	= target_yaw;
	m_Bones[index].params.r_speed		= r_speed;
	m_Bones[index].params.dist_yaw		= angle_difference(target_yaw,m_Bones[index].params.cur_yaw);
	if (t > freeze_time) freeze_time = t;

	bActive				= true;
	in_return_state		= false;
	time_started	= 0;
}
Esempio n. 3
0
void CControlRotationJump::stop_at_once()
{
	m_time = m_man->animation().motion_time(m_right_side ? m_data.anim_stop_rs : m_data.anim_stop_ls, m_object->Visual());	

	// set angular speed in exclusive force mode
	SControlDirectionData					*ctrl_data_dir = (SControlDirectionData*)m_man->data(this, ControlCom::eControlDir); 
	VERIFY									(ctrl_data_dir);	

	float target_yaw;
	if (m_data.flags.is(SControlRotationJumpData::eRotateOnce) && m_object->EnemyMan.get_enemy()) {
		// if rotate once so rotate to enemy
		Fvector					dir_to_enemy;
		dir_to_enemy.sub		(m_object->EnemyMan.get_enemy()->Position(), m_object->Position());
		dir_to_enemy.normalize	();
		target_yaw				= angle_normalize(-dir_to_enemy.getH());
	} else {
		target_yaw				= angle_normalize(-m_object->Direction().getH() + (m_right_side ? m_data.turn_angle : -m_data.turn_angle));
	}

	ctrl_data_dir->heading.target_angle		= target_yaw;

	float cur_yaw;
	m_man->direction().get_heading			(cur_yaw, target_yaw);
	ctrl_data_dir->heading.target_speed		= angle_difference(cur_yaw,target_yaw)/ m_time;
	ctrl_data_dir->linear_dependency		= false;
	VERIFY									(!fis_zero(ctrl_data_dir->heading.target_speed));

	m_stage									= eStop;	

	// start new animation
	SControlAnimationData		*ctrl_data = (SControlAnimationData*)m_man->data(this, ControlCom::eControlAnimation); 
	VERIFY						(ctrl_data);

	ctrl_data->global.motion	= m_right_side ? m_data.anim_stop_rs : m_data.anim_stop_ls;
	ctrl_data->global.actual	= false;
}
MotionID CStalkerAnimationManager::legs_move_animation		()
{
	m_no_move_actual			= false;

	stalker_movement_manager_smart_cover		&movement = object().movement();

	VERIFY						(
		(movement.body_state() == eBodyStateStand) ||
		(movement.mental_state() != eMentalStateFree)
	);

	if (eMentalStateDanger != movement.mental_state()) {
		m_target_speed			= movement.speed(eMovementDirectionForward);
		m_last_non_zero_speed	= m_target_speed;

		return					(
			m_data_storage->m_part_animations.A[
				body_state()
			].m_movement.A[
				movement.movement_type()
			].A[
				eMovementDirectionForward
			].A[
				1
			]
		);
	}

	float						yaw,pitch;
	object().sight().GetDirectionAngles(yaw,pitch);

	yaw							= angle_normalize_signed(-yaw);;
	legs_process_direction		(yaw);

	float						body_current = movement.body_orientation().current.yaw;
	bool						left = left_angle(yaw,body_current);
	float						test_angle_forward = right_forward_angle;
	float						test_angle_backward = left_forward_angle;
	if (left) {
		test_angle_forward		= left_forward_angle;
		test_angle_backward		= right_forward_angle;
	}
	test_angle_backward			= PI - test_angle_backward;

	EMovementDirection			speed_direction;
	float						difference = angle_difference(yaw,body_current);

	if (difference <= test_angle_forward)
		speed_direction			= eMovementDirectionForward;
	else {
		if (difference > test_angle_backward)
			speed_direction		= eMovementDirectionBackward;
		else {
			if (left)
				speed_direction	= eMovementDirectionLeft;
			else
				speed_direction	= eMovementDirectionRight;
		}
	}

	if (m_previous_speed_direction != speed_direction) {
		if (m_change_direction_time < Device.dwTimeGlobal)
			m_change_direction_time	= Device.dwTimeGlobal;

		if (!legs_switch_factor()) {
			m_previous_speed		= 0.f;
			m_target_speed			= 0.f;
		}

		m_previous_speed_direction	= speed_direction;
	}

	m_target_speed				= movement.speed(speed_direction);
	m_last_non_zero_speed		= m_target_speed;

	return						(
		m_data_storage->m_part_animations.A[
			body_state()
		].m_movement.A[
			movement.movement_type()
		].A[
			speed_direction
		].A[
			0
		]
	);
}
Esempio n. 5
0
double hexbright::difference_from_down() {
  int light_axis[3] = {0, -100, 0};
  return (angle_difference(dot_product(light_axis, down_vector), 100, 100));
}
Esempio n. 6
0
void CBaseMonster::HitEntity(const CEntity *pEntity, float fDamage, float impulse, Fvector &dir, ALife::EHitType hit_type, bool draw_hit_marks)
{
	if (!g_Alive()) return;
	if (!pEntity || pEntity->getDestroy()) return;

	if (!EnemyMan.get_enemy()) return;

	if (EnemyMan.get_enemy() == pEntity) {
		Fvector position_in_bone_space;
		position_in_bone_space.set(0.f,0.f,0.f);

		// перевод из локальных координат в мировые вектора направления импульса
		Fvector hit_dir;
		XFORM().transform_dir	(hit_dir,dir);
		hit_dir.normalize		();

		CEntity		*pEntityNC	= const_cast<CEntity*>(pEntity);
		VERIFY		(pEntityNC);
		
		NET_Packet	l_P;
		SHit		HS;
		HS.GenHeader(GE_HIT, pEntityNC->ID());													//		u_EventGen	(l_P,GE_HIT, pEntityNC->ID());
		HS.whoID			= (ID());															//		l_P.w_u16	(ID());
		HS.weaponID			= (ID());															//		l_P.w_u16	(ID());
		HS.dir				= (hit_dir);														//		l_P.w_dir	(hit_dir);
		HS.power			= (fDamage);														//		l_P.w_float	(fDamage);
		HS.boneID			= (smart_cast<IKinematics*>(pEntityNC->Visual())->LL_GetBoneRoot());//		l_P.w_s16	(smart_cast<IKinematics*>(pEntityNC->Visual())->LL_GetBoneRoot());
		HS.p_in_bone_space	= (position_in_bone_space);											//		l_P.w_vec3	(position_in_bone_space);
		HS.impulse			= (impulse);														//		l_P.w_float	(impulse);
		HS.hit_type			= hit_type;															//		l_P.w_u16	( u16(ALife::eHitTypeWound) );
		HS.Write_Packet(l_P);
		u_EventSend	(l_P);
		
		if (pEntityNC == Actor() && draw_hit_marks) {
			START_PROFILE("BaseMonster/Animation/HitEntity");

			SDrawStaticStruct* s = CurrentGameUI()->AddCustomStatic("monster_claws", false);
			
			float h1,p1;
			Device.vCameraDirection.getHP	(h1,p1);
			Fvector hd				= hit_dir;
			hd.mul					(-1);
			float d = -h1 + hd.getH	();
			s->wnd()->SetHeading	(d);
			Fvector2 wnd_pos = s->wnd()->GetWndPos();
			wnd_pos.y	+= 400.0f*_cos(d);
			wnd_pos.x	+= 500.0f*_sin(d);
			s->wnd()->SetWndPos(wnd_pos);

			STOP_PROFILE;

			//SetAttackEffector			();
			
			float time_to_lock		= fDamage * MAX_LOCK_TIME;
			clamp					(time_to_lock, 0.f, MAX_LOCK_TIME);
			Actor()->lock_accel_for	(int(time_to_lock * 1000));

			//////////////////////////////////////////////////////////////////////////
			//
			//////////////////////////////////////////////////////////////////////////
			
			CEffectorCam* ce = Actor()->Cameras().GetCamEffector((ECamEffectorType)effBigMonsterHit);
			if(!ce)
			{
				const shared_str&	eff_sect = pSettings->r_string(cNameSect(), "actor_hit_effect");	
				if(eff_sect.c_str())
				{
					int id						= -1;
					Fvector						cam_pos,cam_dir,cam_norm;
					Actor()->cam_Active()->Get	(cam_pos,cam_dir,cam_norm);
					cam_dir.normalize_safe		();
					dir.normalize_safe			();

					float ang_diff				= angle_difference	(cam_dir.getH(), dir.getH());
					Fvector						cp;
					cp.crossproduct				(cam_dir,dir);
					bool bUp					=(cp.y>0.0f);

					Fvector cross;
					cross.crossproduct			(cam_dir, dir);
					VERIFY						(ang_diff>=0.0f && ang_diff<=PI);

					float _s1 = PI_DIV_8;
					float _s2 = _s1+PI_DIV_4;
					float _s3 = _s2+PI_DIV_4;
					float _s4 = _s3+PI_DIV_4;

					if(ang_diff<=_s1){
						id = 2;
					}else {
						if(ang_diff>_s1 && ang_diff<=_s2){
							id = (bUp)?5:7;
						}else
							if(ang_diff>_s2 && ang_diff<=_s3){
								id = (bUp)?3:1;
							}else
								if(ang_diff>_s3 && ang_diff<=_s4){
									id = (bUp)?4:6;
								}else
									if(ang_diff>_s4){
										id = 0;
									}else{
										VERIFY(0);
									}
					}
					
					string64				sect_name;

					xr_sprintf					(sect_name,"%s_%d",eff_sect.c_str(), id);
					AddEffector				(Actor(), effBigMonsterHit, sect_name, fDamage);
				}
			}
			//////////////////////////////////////////////////////////////////////////
			

		}

		Morale.on_attack_success();
		
		m_time_last_attack_success	= Device.dwTimeGlobal;
	}
}
Esempio n. 7
0
void CActor::HitSignal(float perc, Fvector& vLocalDir, CObject* who, s16 element)
{
	if (g_Alive()) 
	{

		// stop-motion
		if (character_physics_support()->movement()->Environment()==CPHMovementControl::peOnGround || character_physics_support()->movement()->Environment()==CPHMovementControl::peAtWall)
		{
			Fvector zeroV;
			zeroV.set			(0,0,0);
			character_physics_support()->movement()->SetVelocity(zeroV);
		}
		
		// check damage bone
		Fvector D;
		XFORM().transform_dir(D,vLocalDir);

		float	yaw, pitch;
		D.getHP(yaw,pitch);
		CKinematicsAnimated *tpKinematics = smart_cast<CKinematicsAnimated*>(Visual());
		VERIFY(tpKinematics);
#pragma todo("Dima to Dima : forward-back bone impulse direction has been determined incorrectly!")
		MotionID motion_ID = m_anims->m_normal.m_damage[iFloor(tpKinematics->LL_GetBoneInstance(element).get_param(1) + (angle_difference(r_model_yaw + r_model_yaw_delta,yaw) <= PI_DIV_2 ? 0 : 1))];
		float power_factor = perc/100.f; clamp(power_factor,0.f,1.f);
		VERIFY(motion_ID.valid());
		tpKinematics->PlayFX(motion_ID,power_factor);
	}
}
Esempio n. 8
0
void CActor::HitMark	(float P, 
						 Fvector dir,			
						 CObject* who, 
						 s16 element, 
						 Fvector position_in_bone_space, 
						 float impulse,  
						 ALife::EHitType hit_type)
{
	// hit marker
	if ( (hit_type==ALife::eHitTypeFireWound||hit_type==ALife::eHitTypeWound_2) && g_Alive() && Local() && /*(this!=who) && */(Level().CurrentEntity()==this) )	
	{
		HUD().Hit(0, P, dir);

	{
		CEffectorCam* ce = Cameras().GetCamEffector((ECamEffectorType)effFireHit);
		if(!ce)
			{
			int id						= -1;
			Fvector						cam_pos,cam_dir,cam_norm;
			cam_Active()->Get			(cam_pos,cam_dir,cam_norm);
			cam_dir.normalize_safe		();
			dir.normalize_safe			();

			float ang_diff				= angle_difference	(cam_dir.getH(), dir.getH());
			Fvector						cp;
			cp.crossproduct				(cam_dir,dir);
			bool bUp					=(cp.y>0.0f);

			Fvector cross;
			cross.crossproduct			(cam_dir, dir);
			VERIFY						(ang_diff>=0.0f && ang_diff<=PI);

			float _s1 = PI_DIV_8;
			float _s2 = _s1+PI_DIV_4;
			float _s3 = _s2+PI_DIV_4;
			float _s4 = _s3+PI_DIV_4;

			if(ang_diff<=_s1){
				id = 2;
			}else
			if(ang_diff>_s1 && ang_diff<=_s2){
				id = (bUp)?5:7;
			}else
			if(ang_diff>_s2 && ang_diff<=_s3){
				id = (bUp)?3:1;
			}else
			if(ang_diff>_s3 && ang_diff<=_s4){
				id = (bUp)?4:6;
			}else
			if(ang_diff>_s4){
				id = 0;
			}else{
				VERIFY(0);
			}

			string64 sect_name;
			sprintf(sect_name,"effector_fire_hit_%d",id);
			AddEffector(this, effFireHit, sect_name, P/100.0f);
			}
		}
	}

}
Esempio n. 9
0
bool CControlJump::can_jump(CObject *target)
{
	const bool aggressive_jump = m_object->can_use_agressive_jump(target);

	if ( m_time_next_allowed != 0 )
	{
		// in aggressive mode we can jump after 1/3 of m_delay_after_jump
		if ( m_time_next_allowed - (int)aggressive_jump*(2*m_delay_after_jump/3) > Device.dwTimeGlobal) 
		{
			return false;
		}
	}

	Fvector source_position		= m_object->Position	();
	Fvector target_position;
	target->Center				(target_position);

	// проверка на dist
	float dist = source_position.distance_to(target_position);

	// in aggressive mode we can jump from distance >= 1
	const float test_min_distance = aggressive_jump ? _min(1.f, m_min_distance) : m_min_distance;
	if ( (dist < test_min_distance) || (dist > m_max_distance) ) return false;

	// получить вектор направлени¤ и его мир угол
	float		dir_yaw = Fvector().sub(target_position, source_position).getH();
	dir_yaw		= angle_normalize(-dir_yaw);

	// проверка на angle
	float yaw_current, yaw_target;
	m_object->control().direction().get_heading(yaw_current, yaw_target);

	if (angle_difference(yaw_current, dir_yaw) > m_max_angle) return false;
	
	// check if target on the same floor etc
	if (_abs(target_position.y-source_position.y) > m_max_height) return false;

	// проверка prepare
	if (!is_flag(SControlJumpData::ePrepareSkip) && !is_flag(SControlJumpData::eGlideOnPrepareFailed)) {
		if (!is_flag(SControlJumpData::ePrepareInMove)) {
			VERIFY(m_data.state_prepare.motion.valid());
		} else {
			VERIFY(m_data.state_prepare_in_move.motion.valid());
			VERIFY(m_data.state_prepare_in_move.velocity_mask != u32(-1));

			// try to trace distance according to prepare animation
			bool good_trace_res = false;

			// get animation time
			float time			= m_man->animation().motion_time(m_data.state_prepare_in_move.motion, m_object->Visual());
			// set acceleration and velocity
			SVelocityParam &vel	= m_object->move().get_velocity(m_data.state_prepare_in_move.velocity_mask);
			float dist = time * vel.velocity.linear;

			// check nodes in direction
			Fvector target_point;
			target_point.mad(m_object->Position(), m_object->Direction(), dist);

			if (m_man->path_builder().accessible(target_point)) {
				// нода в пр¤мой видимости?
				m_man->path_builder().restrictions().add_border(m_object->Position(), target_point);
				u32 node = ai().level_graph().check_position_in_direction(m_object->ai_location().level_vertex_id(),m_object->Position(),target_point);
				m_man->path_builder().restrictions().remove_border();
				
				if (ai().level_graph().valid_vertex_id(node) && m_man->path_builder().accessible(node)) 
					good_trace_res = true;
			}

			if (!good_trace_res) {
				// cannot prepare in move, so check if can prepare in stand state
				if (!m_data.state_prepare.motion.valid()) return false;
			}
		}
	}

	return true;
}
Esempio n. 10
0
void CControlRotationJump::build_line_second()
{
	if (!m_object->EnemyMan.get_enemy()) {
		m_man->notify				(ControlCom::eventRotationJumpEnd, 0);
		return;
	}
	
	// set acceleration and velocity
	m_target_velocity			= m_start_velocity;
	m_start_velocity			= 0;
	
	// get animation time
	m_time						= m_man->animation().motion_time(m_right_side ? m_data.anim_run_rs : m_data.anim_run_ls, m_object->Visual());

	// acceleration
	m_accel = (m_target_velocity - m_start_velocity) / m_time;

	// path distance
	m_dist = (m_target_velocity*m_target_velocity - m_start_velocity*m_start_velocity) / (2*m_accel);

	// set angular speed in exclusive force mode
	SControlDirectionData					*ctrl_data_dir = (SControlDirectionData*)m_man->data(this, ControlCom::eControlDir); 
	VERIFY									(ctrl_data_dir);	

	Fvector					dir_to_enemy;
	dir_to_enemy.sub		(m_object->EnemyMan.get_enemy()->Position(), m_object->Position());
	dir_to_enemy.normalize	();
	
	float target_yaw						= dir_to_enemy.getH();
	target_yaw								= angle_normalize(-target_yaw);
	ctrl_data_dir->heading.target_angle		= target_yaw;

	float cur_yaw;
	m_man->direction().get_heading			(cur_yaw, target_yaw);
	ctrl_data_dir->heading.target_speed		= angle_difference(cur_yaw,target_yaw)/ m_time;
	ctrl_data_dir->linear_dependency		= false;

	VERIFY									(!fis_zero(ctrl_data_dir->heading.target_speed));
	
	
	// Velocity mask
	u32 velocity_mask = MonsterMovement::eVelocityParameterStand | MonsterMovement::eVelocityParameterRunNormal;

	m_stage = eRun;

	Fvector target_position;
	target_position.mad(m_object->Position(), dir_to_enemy, m_dist);

	if (!m_man->build_path_line(this, target_position, u32(-1), velocity_mask)) {
		m_man->notify				(ControlCom::eventRotationJumpEnd, 0);
	} else { 
		// enable path
		SControlPathBuilderData		*ctrl_path = (SControlPathBuilderData*)m_man->data(this, ControlCom::eControlPath); 
		VERIFY						(ctrl_path);
		ctrl_path->enable			= true;

		m_man->lock					(this, ControlCom::eControlPath);

		SControlMovementData		*ctrl_move = (SControlMovementData*)m_man->data(this, ControlCom::eControlMovement); 
		VERIFY						(ctrl_move);
		ctrl_move->velocity_target	= m_target_velocity;
		ctrl_move->acc				= m_accel;

		// start new animation
		SControlAnimationData		*ctrl_data = (SControlAnimationData*)m_man->data(this, ControlCom::eControlAnimation); 
		VERIFY						(ctrl_data);

		ctrl_data->global.motion	= m_right_side ? m_data.anim_run_rs : m_data.anim_run_ls;
		ctrl_data->global.actual	= false;
	}
}
Esempio n. 11
0
void CHelicopter::MoveStep()
{
    Fvector dir, pathDir;
    float desired_H = m_movement.currPathH;
    float desired_P;
    if(m_movement.type != eMovNone) {

        float dist = m_movement.currP.distance_to(m_movement.desiredPoint);

        dir.sub(m_movement.desiredPoint,m_movement.currP);
        dir.normalize_safe();
        pathDir = dir;
        dir.getHP(desired_H, desired_P);
        float speed_ = _min(m_movement.GetSpeedInDestPoint(), GetMaxVelocity() );

        static float ang = pSettings->r_float	(cNameSect(),"magic_angle");
        if(m_movement.curLinearSpeed>GetMaxVelocity() || angle_difference(m_movement.currPathH,desired_H)>ang)
            m_movement.curLinearAcc = -m_movement.LinearAcc_bk;
        else
            m_movement.curLinearAcc = GetCurrAcc(	m_movement.curLinearSpeed,
                                                    speed_,
                                                    dist*0.95f,
                                                    m_movement.LinearAcc_fw,
                                                    -m_movement.LinearAcc_bk);


        angle_lerp	(m_movement.currPathH, desired_H, m_movement.GetAngSpeedHeading(m_movement.curLinearSpeed), STEP);
        angle_lerp	(m_movement.currPathP, desired_P, m_movement.GetAngSpeedPitch(m_movement.curLinearSpeed), STEP);

        dir.setHP(m_movement.currPathH, m_movement.currPathP);

        float vp = m_movement.curLinearSpeed*STEP+(m_movement.curLinearAcc*STEP*STEP)/2.0f;
        m_movement.currP.mad	(dir, vp);
        m_movement.curLinearSpeed += m_movement.curLinearAcc*STEP;
        static bool aaa = false;
        if(aaa)
            Log("1-m_movement.curLinearSpeed=",m_movement.curLinearSpeed);
        clamp(m_movement.curLinearSpeed,0.0f,1000.0f);
        if(aaa)
            Log("2-m_movement.curLinearSpeed=",m_movement.curLinearSpeed);
    } else { //go stopping
        if( !fis_zero(m_movement.curLinearSpeed) ) {
            m_movement.curLinearAcc = -m_movement.LinearAcc_bk;

            float vp = m_movement.curLinearSpeed*STEP+(m_movement.curLinearAcc*STEP*STEP)/2.0f;
            dir.setHP(m_movement.currPathH, m_movement.currPathP);
            dir.normalize_safe();
            m_movement.currP.mad	(dir, vp);
            m_movement.curLinearSpeed += m_movement.curLinearAcc*STEP;
            clamp(m_movement.curLinearSpeed,0.0f,1000.0f);
//			clamp(m_movement.curLinearSpeed,0.0f,m_movement.maxLinearSpeed);

        } else {
            m_movement.curLinearAcc		= 0.0f;
            m_movement.curLinearSpeed	= 0.0f;
        }

    };

    if(	m_body.b_looking_at_point) {
        Fvector desired_dir;
        desired_dir.sub(m_body.looking_point, m_movement.currP ).normalize_safe();

        float center_desired_H,tmp_P;
        desired_dir.getHP(center_desired_H, tmp_P);
        angle_lerp			(m_body.currBodyHPB.x, center_desired_H, m_movement.GetAngSpeedHeading(m_movement.curLinearSpeed), STEP);
    } else {
        angle_lerp			(m_body.currBodyHPB.x, m_movement.currPathH, m_movement.GetAngSpeedHeading(m_movement.curLinearSpeed), STEP);
    }


    float needBodyP = -m_body.model_pitch_k*m_movement.curLinearSpeed;
    if(m_movement.curLinearAcc < 0) needBodyP*=-1;
    angle_lerp	(m_body.currBodyHPB.y, needBodyP, m_body.model_angSpeedPitch, STEP);


    float sign;
    Fvector cp;
    cp.crossproduct (pathDir,dir);
    (cp.y>0.0)?sign=1.0f:sign=-1.0f;
    float ang_diff = angle_difference (m_movement.currPathH, desired_H);

    float needBodyB = -ang_diff*sign*m_body.model_bank_k*m_movement.curLinearSpeed;
    angle_lerp	(m_body.currBodyHPB.z, needBodyB, m_body.model_angSpeedBank, STEP);


    XFORM().setHPB(m_body.currBodyHPB.x,m_body.currBodyHPB.y,m_body.currBodyHPB.z);

    XFORM().translate_over(m_movement.currP);
}
Esempio n. 12
0
double move_contact_object(int object, double angle, double max_dist, bool solid_only)
{
    enigma::object_collisions* const inst1 = ((enigma::object_collisions*)enigma::instance_event_iterator->inst);
    if (inst1->sprite_index == -1 && (inst1->mask_index == -1)) {
        return -4;
    }

    const double x = inst1->x, y = inst1->y;

    if (collide_inst_inst(object, solid_only, true, x, y) != NULL) {
        return 0;
    }

    const double DMIN = 1, DMAX = 1000; // Arbitrary max for non-positive values, 1000 fits with other implementations.
    const double contact_distance = DMIN;
    double mid_dist = max_dist; // mid_dist is used for the subtraction part.
    if (max_dist <= 0) { // Use the arbitrary max for non-positive values.
        max_dist = DMAX;
    }
    mid_dist = max_dist;
    const double radang = (fmod(fmod(angle, 360) + 360, 360))*(M_PI/180.0);
    const double sin_angle = sin(radang), cos_angle = cos(radang);

    // Subtraction.

    const int quad = int(angle/90.0);

    const bbox_rect_t &box = inst1->$bbox_relative();
    const double x1 = inst1->x, y1 = inst1->y,
                 xscale1 = inst1->image_xscale, yscale1 = inst1->image_yscale,
                 ia1 = inst1->image_angle;
    int left1, top1, right1, bottom1;

    get_border(&left1, &right1, &top1, &bottom1, box.left, box.top, box.right, box.bottom, x1, y1, xscale1, yscale1, ia1);

    for (enigma::iterator it = enigma::fetch_inst_iter_by_int(object); it; ++it)
    {
        const enigma::object_collisions* inst2 = (enigma::object_collisions*)*it;
        if (inst2->sprite_index == -1 && (inst2->mask_index == -1))
            continue;
        if (inst2->id == inst1->id || (solid_only && !inst2->solid))
            continue;
        const bbox_rect_t &box2 = inst2->$bbox_relative();
        const double x2 = inst2->x, y2 = inst2->y,
                     xscale2 = inst2->image_xscale, yscale2 = inst2->image_yscale,
                     ia2 = inst2->image_angle;
        int left2, top2, right2, bottom2;

        get_border(&left2, &right2, &top2, &bottom2, box2.left, box2.top, box2.right, box2.bottom, x2, y2, xscale2, yscale2, ia2);

        if (right2 >= left1 && bottom2 >= top1 && left2 <= right1 && top2 <= bottom1)
        {
            mid_dist = DMIN;
            break;
        }

        switch (quad)
        {
            case 0:
                if ((left2 > right1 || top1 > bottom2) &&
                angle_difference(point_direction(right1, bottom1, left2, top2),angle) >= 0  &&
                angle_difference(point_direction(left1, top1, right2, bottom2),angle) <= 0)
                {
                    if (angle_difference(point_direction(right1, top1, left2, bottom2),angle) > 0)
                    {
                        mid_dist = min(mid_dist, (top1 - bottom2 - contact_distance)/sin_angle);
                    }
                    else
                    {
                        mid_dist = min(mid_dist, (left2 - right1 - contact_distance)/cos_angle);
                    }
                }
            break;
            case 1:
                if ((left1 > right2 || top1 > bottom2) &&
                angle_difference(point_direction(left1, bottom1, right2, top2),angle) <= 0  &&
                angle_difference(point_direction(right1, top1, left2, bottom2),angle) >= 0)
                {
                    if (angle_difference(point_direction(left1, top1, right2, bottom2),angle) > 0)
                    {
                        mid_dist = min(mid_dist, (right2 - left1 + contact_distance)/cos_angle);
                    }
                    else
                    {
                        mid_dist = min(mid_dist, (top1 - bottom2 - contact_distance)/sin_angle);
                    }
                }
            break;
            case 2:
                if ((left1 > right2 || top2 > bottom1) &&
                angle_difference(point_direction(right1, bottom1, left2, top2),angle) <= 0  &&
                angle_difference(point_direction(left1, top1, right2, bottom2),angle) >= 0)
                {
                    if (angle_difference(point_direction(left1, bottom1, right2, top2),angle) > 0)
                    {
                        mid_dist = min(mid_dist, (bottom1 - top2 + contact_distance)/sin_angle);
                    }
                    else
                    {
                        mid_dist = min(mid_dist, (right2 - left1 + contact_distance)/cos_angle);
                    }
                }
            break;
            case 3:
                if ((left2 > right1 || top2 > bottom1) &&
                angle_difference(point_direction(right1, top1, left2, bottom2),angle) <= 0  &&
                angle_difference(point_direction(left1, bottom1, right2, top2),angle) >= 0)
                {
                    if (angle_difference(point_direction(right1, bottom1, left2, top2),angle) > 0)
                    {
                        mid_dist = min(mid_dist, (left2 - right1 - contact_distance)/cos_angle);
                    }
                    else
                    {
                        mid_dist = min(mid_dist, (bottom1 - top2 + contact_distance)/sin_angle);
                    }
                }
            break;
        }
    }

    double current_dist = DMIN;
    {
        // Avoid moving to position which isn't free. mid_dist is not guaranteed to indicate a free position.
        double next_x = x + mid_dist*cos_angle;
        double next_y = y - mid_dist*sin_angle;
        if (collide_inst_inst(object, solid_only, true, next_x, next_y) == NULL) {
            inst1->x = next_x;
            inst1->y = next_y;
            current_dist = mid_dist;
        }
    }

    // Subtraction end.

    for (; current_dist <= max_dist; current_dist++)
    {
        const double next_x = x + current_dist*cos_angle;
        const double next_y = y - current_dist*sin_angle;
        if (collide_inst_inst(object, solid_only, true, next_x, next_y) != NULL) {
            current_dist--;
            break;
        }
        else {
            inst1->x = next_x;
            inst1->y = next_y;
        }
    }

    return current_dist;
}
Esempio n. 13
0
void CControlDirection::update_frame()
{
	pitch_correction			();	

	SRotationEventData			event_data;
	event_data.angle			= 0;

	bool heading_similar		= false;
	bool pitch_similar			= false;

	// difference
	float diff = angle_difference(m_pitch.current_angle, m_data.pitch.target_angle) * 4.0f;
	clamp(diff, PI_DIV_6, 5 * PI_DIV_6);

	m_data.pitch.target_speed = m_pitch.current_speed = diff;

	// поправка угловой скорости в соответствии с текущей и таргетовой линейной скоростями
	// heading speed correction
	if (!fis_zero(m_man->movement().velocity_current()) && !fis_zero(m_man->movement().velocity_target()) && m_data.linear_dependency)
		m_heading.current_speed	= m_data.heading.target_speed * m_man->movement().velocity_current() / (m_man->movement().velocity_target() + EPS_L);
	else 
		velocity_lerp			(m_heading.current_speed, m_data.heading.target_speed, m_heading.current_acc, m_object->client_update_fdelta());

	m_heading.current_angle		= angle_normalize(m_heading.current_angle);
	m_data.heading.target_angle	= angle_normalize(m_data.heading.target_angle);
	
	if (fsimilar(m_heading.current_angle, m_data.heading.target_angle)) heading_similar = true;
	angle_lerp(m_heading.current_angle, m_data.heading.target_angle, m_heading.current_speed, m_object->client_update_fdelta());
	if (!heading_similar && fsimilar(m_heading.current_angle, m_data.heading.target_angle)) {
		event_data.angle |= SRotationEventData::eHeading;
	}

	// update pitch
	velocity_lerp				(m_pitch.current_speed, m_data.pitch.target_speed, m_pitch.current_acc, m_object->client_update_fdelta());

	m_pitch.current_angle		= angle_normalize_signed	(m_pitch.current_angle);
	m_data.pitch.target_angle	= angle_normalize_signed	(m_data.pitch.target_angle);

	if (fsimilar(m_pitch.current_angle, m_data.pitch.target_angle)) pitch_similar = true;
	angle_lerp					(m_pitch.current_angle, m_data.pitch.target_angle, m_pitch.current_speed, m_object->client_update_fdelta());
	if (!pitch_similar && fsimilar(m_pitch.current_angle, m_data.pitch.target_angle)) {
		event_data.angle |= SRotationEventData::ePitch;
	}

	// set
	m_man->path_builder().m_body.speed			= m_heading.current_speed;
	m_man->path_builder().m_body.current.yaw	= m_heading.current_angle;
	m_man->path_builder().m_body.target.yaw		= m_heading.current_angle;
	m_man->path_builder().m_body.current.pitch	= m_pitch.current_angle;
	m_man->path_builder().m_body.target.pitch	= m_pitch.current_angle;

	// save object position
	Fvector P					= m_object->Position();
	// set angles
	if(!m_object->animation_movement_controlled())
		m_object->XFORM().setHPB	(-m_man->path_builder().m_body.current.yaw,-m_man->path_builder().m_body.current.pitch,0);
	// restore object position
	m_object->Position()		= P;

	
	// if there is an event
	if (event_data.angle)		m_man->notify(ControlCom::eventRotationEnd, &event_data);
}