예제 #1
0
void TestApp::check_normalize_180(float input_angle, float output_angle)
{
	CL_Angle angle;
	angle.set_degrees(input_angle);
	angle.normalize_180();
	float f_angle = angle.to_degrees();
	if ( (f_angle < (output_angle - 0.001f)) || (f_angle > (output_angle + 0.001f) ) )
		fail();
}
예제 #2
0
파일: Car.cpp 프로젝트: genail/gear
CL_Angle CarImpl::vecToAngle(const CL_Vec2f &p_vec)
{
	const static CL_Vec2f ANGLE_ZERO(1.0f, 0.0f);
	CL_Angle angle = p_vec.angle(ANGLE_ZERO);

	if (p_vec.y < 0) {
		angle.set_radians(-angle.to_radians());
	}

	return angle;

}
예제 #3
0
void CL_Sprite::set_base_angle(CL_Angle angle)
{
	float degrees = angle.to_degrees();

	if (degrees >= 0.0f)
		degrees = fmod(degrees, 360.0f);
	else
		degrees = fmod(degrees, 360.0f) + 360.0f;

	impl->base_angle = CL_Angle(degrees, cl_degrees);
}
예제 #4
0
void CL_Sprite::rotate_yaw(CL_Angle angle)
{
	float degrees = angle.to_degrees();
	degrees+=impl->angle_yaw.to_degrees();

	if (degrees >= 0.0f)
		degrees = fmod(degrees, 360.0f);
	else
		degrees = fmod(degrees, 360.0f) + 360.0f;

	impl->angle_yaw = CL_Angle(degrees, cl_degrees);
}
std::vector<CL_Pointf> CL_BezierCurve_Impl::generate_curve_points(const CL_Angle &split_angle)
{
	std::vector<CL_Pointf> points;
/*
	for (float i = 0.0; i < 1.0; i += 0.01)
	{
		points.push_back(get_point_relative(i));
	}
	points.push_back(get_point_relative(1.0));
*/

	split_angle_rad = split_angle.to_radians(); 

	points.push_back( get_point_relative(0.0) );

	std::vector<CL_Pointf> sub_points = subdivide_bezier(0.0, 0.5);
	points.insert( points.end(), sub_points.begin(), sub_points.end() );

	sub_points = subdivide_bezier(0.5, 1.0);
	points.insert( points.end(), sub_points.begin(), sub_points.end() );

	return points;
}
예제 #6
0
void CL_Collada_Triangles_Impl::create_vertices_normal(CL_Vec3f *destination, int stride, const CL_String &semantic, const CL_Angle &smoothing_angle)
{
	CL_Collada_Input_Shared &input = get_input(semantic);

	CL_Collada_Source &source = input.get_source();
	if (source.is_null())
	{
		throw CL_Exception("unsupported situation. fixme");
	}

	std::vector<CL_Vec3f> &pos_array = source.get_vec3f_array();

	unsigned int primitive_offset = input.get_offset();
	std::vector<CL_Vec3f> face_normals;
	calculate_face_normals(face_normals, pos_array, primitive_offset);

	std::vector<int> face_offsets;
	std::vector<int> faces;

	generate_point_facelist(face_offsets, faces, pos_array.size(), primitive_offset);

	calculate_point_normals(face_offsets, faces, face_normals, destination, stride, smoothing_angle.to_radians(), primitive_offset );
}
예제 #7
0
CL_Mat3<Type> CL_Mat3<Type>::rotate(const CL_Angle &angle, Type x, Type y, Type z, bool normalize)
{
	if (normalize)
	{
		Type len2 = x*x+y*y+z*z;
		if (len2 != (Type)1)
		{	
			Type length = sqrt(len2);
			if (length > (Type) 0)
			{
				x /= length;
				y /= length;
				z /= length;
			}
			else
			{
				x = (Type) 0;
				y = (Type) 0;
				z = (Type) 0;
			}
		}
	}

	CL_Mat3<Type> rotate_matrix;
	Type c = cos(angle.to_radians());
	Type s = sin(angle.to_radians());
	rotate_matrix.matrix[0+0*3] = (Type) (x*x*(1.0f - c) + c);
	rotate_matrix.matrix[0+1*3] = (Type) (x*y*(1.0f - c) - z*s);
	rotate_matrix.matrix[0+2*3] = (Type) (x*z*(1.0f - c) + y*s);
	rotate_matrix.matrix[1+0*3] = (Type) (y*x*(1.0f - c) + z*s);
	rotate_matrix.matrix[1+1*3] = (Type) (y*y*(1.0f - c) + c);
	rotate_matrix.matrix[1+2*3] = (Type) (y*z*(1.0f - c) - x*s);
	rotate_matrix.matrix[2+0*3] = (Type) (x*z*(1.0f - c) - y*s);
	rotate_matrix.matrix[2+1*3] = (Type) (y*z*(1.0f - c) + x*s);
	rotate_matrix.matrix[2+2*3] = (Type) (z*z*(1.0f - c) + c);
	return rotate_matrix;
}
예제 #8
0
CL_Mat3<int> CL_Mat3<int>::rotate(const CL_Angle &angle, int x, int y, int z, bool normalize)
{
	if (normalize)
	{
		int len2 = x*x+y*y+z*z;
		if (len2 != (int)1)
		{	
			int length = sqrt( (float) len2);
			if (length > 0)
			{
				x /= length;
				y /= length;
				z /= length;
			}
			else
			{
				x = 0;
				y = 0;
				z = 0;
			}
		}
	}

	CL_Mat3<int> rotate_matrix;
	float c = cos(angle.to_radians());
	float s = sin(angle.to_radians());
	rotate_matrix.matrix[0+0*3] = (int) floor((x*x*(1.0f - c) + c)+0.5f);
	rotate_matrix.matrix[0+1*3] = (int) floor((x*y*(1.0f - c) - z*s)+0.5f);
	rotate_matrix.matrix[0+2*3] = (int) floor((x*z*(1.0f - c) + y*s)+0.5f);
	rotate_matrix.matrix[1+0*3] = (int) floor((y*x*(1.0f - c) + z*s)+0.5f);
	rotate_matrix.matrix[1+1*3] = (int) floor((y*y*(1.0f - c) + c)+0.5f);
	rotate_matrix.matrix[1+2*3] = (int) floor((y*z*(1.0f - c) - x*s)+0.5f);
	rotate_matrix.matrix[2+0*3] = (int) floor((x*z*(1.0f - c) - y*s)+0.5f);
	rotate_matrix.matrix[2+1*3] = (int) floor((y*z*(1.0f - c) + x*s)+0.5f);
	rotate_matrix.matrix[2+2*3] = (int) floor((z*z*(1.0f - c) + c)+0.5f);
	return rotate_matrix;
}
예제 #9
0
파일: Car.cpp 프로젝트: genail/gear
void CarImpl::alignRotation(CL_Angle &p_what, const CL_Angle &p_to, float p_stepRad)
{
	// works only on normalized values
	CL_Angle normWhat(p_what);
	CL_Angle normTo(p_to);

	Workarounds::clAngleNormalize(&normWhat);
	Workarounds::clAngleNormalize(&normTo);

	const CL_Angle diffAngle = normWhat - normTo;

	float diffRad = diffAngle.to_radians();

	// if difference is higher than 180, then rotate in shorten way
	if (diffRad > CL_PI) {
		diffRad -= CL_PI * 2;
	} else if (diffRad < -CL_PI) {
		diffRad += CL_PI * 2;
	}

	const float diffRadAbs = fabs(diffRad);

	if (diffRadAbs > 0.01f) {
		if (diffRadAbs > p_stepRad) {

			const CL_Angle stepAngle(p_stepRad, cl_radians);

			if (diffRad > 0.0f) {
				p_what -= stepAngle;
			} else {
				p_what += stepAngle;
			}
		} else {
			p_what = p_to;
		}
	}
}
예제 #10
0
void MotionBlurShaderImpl::setUniforms(CL_ProgramObject &p_program)
{
	p_program.set_uniform1i("radius", m_radius);
	p_program.set_uniform1f("angle", m_angle.to_radians());
}
예제 #11
0
파일: Car.cpp 프로젝트: genail/gear
namespace Race {

/* Car width in pixels */
const int CAR_WIDTH = 18;

/* Car height in pixels */
const int CAR_HEIGHT = 24;

class CarImpl
{
	public:

		/** Base object */
		const Car *const m_base;

		Player *m_ownerPlayer;

		/** This will help to keep 1/60 iteration speed */
		float m_timeReserveMs;

		/** Iteration counter */
		int32_t m_iterId;

		// current vehicle state

		/** Central position on map */
		CL_Pointf m_position;

		/** CW rotation from positive X axis */
		CL_Angle m_rotation;

		/** Current speed in map pixels per frame */
		float m_speed;

		/** Damage factor. 0.0 - 1.0 from new to damaged */
		float m_damage;

		/** If currently chocking */
		bool m_chocking;


		// input state

		CarInputState m_inputState;

		/** Locked state. If true then car shoudn't move. */
		bool m_inputLocked;


		// physics

		/** Car movement rotation */
		CL_Angle m_phyMoveRot;

		/** Car movement vector (created from movement rotation) */
		CL_Vec2f m_phyMoveVec;

		/** Speed delta (for isDrifting()) */
		float m_phySpeedDelta;

		/** Wheels turn. -1.0 is max left, 1.0 is max right */
		float m_phyWheelsTurn;

		/** Body outline for collision check */
		CL_CollisionOutline m_phyCollisionOutline;


		CarImpl(const Car *p_base, Player *p_ownerPlayer) :
			m_base(p_base),
			m_ownerPlayer(p_ownerPlayer),
			m_timeReserveMs(0),
			m_iterId(-1),
			m_position(300.0f, 300.0f),
			m_rotation(0, cl_degrees),
			m_speed(0.0f),
			m_damage(0.0f),
			m_chocking(false),
			m_inputState(),
			m_inputLocked(false),
			m_phySpeedDelta(0.0f),
			m_phyWheelsTurn(0.0f)
		{ init(); }


		void init();

		void update1_60();

		// helpers

		void alignRotation(CL_Angle &p_what, const CL_Angle &p_to, float p_stepRad);

		float limit(float p_value, float p_from, float p_to) const;

		/** Checks if car should choke at the moment */
		bool isChoking();

		CL_Angle vecToAngle(const CL_Vec2f &p_vec);
};

CL_String floatToHex(float p_num);

float hexToFloat(const CL_String &p_str);

Car::Car(Player *p_owner) :
		m_impl(new CarImpl(this, p_owner))
{
	// empty
}

void CarImpl::init()
{
	// build car contour for collision check
	CL_Contour contour;

	const int halfWidth = CAR_WIDTH / 2;
	const int halfHeight = CAR_HEIGHT / 2;
	contour.get_points().push_back(CL_Pointf(-halfWidth, halfHeight));
	contour.get_points().push_back(CL_Pointf(halfWidth, halfHeight));
	contour.get_points().push_back(CL_Pointf(halfWidth, -halfHeight));
	contour.get_points().push_back(CL_Pointf(-halfWidth, -halfHeight));

	m_phyCollisionOutline.get_contours().push_back(contour);

	m_phyCollisionOutline.set_inside_test(true);

	m_phyCollisionOutline.calculate_radius();
	m_phyCollisionOutline.calculate_smallest_enclosing_discs();
}

Car::~Car()
{
	// empty
}

void Car::update(unsigned p_timeElapsed)
{
	static const float breakPoint = 1000.0f / 60.0f;

	//cl_log_event("a", "%1", p_timeElapsed);
	m_impl->m_timeReserveMs += p_timeElapsed;

	bool first = true;

	do {
		if (!first) {
			cl_log_event("a", "double calculation");
		}

		m_impl->update1_60();
		m_impl->m_timeReserveMs -= breakPoint;
		first = false;
	} while (m_impl->m_timeReserveMs >= breakPoint);
}

void Car::updateToIteration(int32_t p_targetIterId)
{
	// allowed iteration delta
	static const int DELTA_LIMIT = 10000;


	// get the needed iterations count
	int count;

	if (p_targetIterId > m_impl->m_iterId) {
		count = p_targetIterId - m_impl->m_iterId;
	} else {
		count = std::numeric_limits<int32_t>::max() - m_impl->m_iterId;

		// protection against int32 overflow
		if (count > DELTA_LIMIT || p_targetIterId > DELTA_LIMIT) {
			throw CL_Exception(
					cl_format(
							"delta limit reached: %1 => %2",
							m_impl->m_iterId, p_targetIterId
					)
			);
		}

		count += p_targetIterId + 1;
	}

	// disallow too great iteration count
	if (count > DELTA_LIMIT) {
		throw CL_Exception("delta limit reached");
	}

	for (int i = 0; i < count; ++i) {
		m_impl->update1_60();
	}
}

void CarImpl::alignRotation(CL_Angle &p_what, const CL_Angle &p_to, float p_stepRad)
{
	// works only on normalized values
	CL_Angle normWhat(p_what);
	CL_Angle normTo(p_to);

	Workarounds::clAngleNormalize(&normWhat);
	Workarounds::clAngleNormalize(&normTo);

	const CL_Angle diffAngle = normWhat - normTo;

	float diffRad = diffAngle.to_radians();

	// if difference is higher than 180, then rotate in shorten way
	if (diffRad > CL_PI) {
		diffRad -= CL_PI * 2;
	} else if (diffRad < -CL_PI) {
		diffRad += CL_PI * 2;
	}

	const float diffRadAbs = fabs(diffRad);

	if (diffRadAbs > 0.01f) {
		if (diffRadAbs > p_stepRad) {

			const CL_Angle stepAngle(p_stepRad, cl_radians);

			if (diffRad > 0.0f) {
				p_what -= stepAngle;
			} else {
				p_what += stepAngle;
			}
		} else {
			p_what = p_to;
		}
	}
}

void CarImpl::update1_60() {
	
	static const float BRAKE_POWER = 0.1f;
	static const float ACCEL_POWER = 0.014f;
	static const float SPEED_LIMIT = 15.0f;
	static const float WHEEL_TURN_SPEED = 1.0f / 10.0f;
	static const float TURN_POWER  = (2 * CL_PI / 360.0f) * 2.5f;
	static const float MOV_ALIGN_POWER = TURN_POWER / 2.0f;
	static const float ROT_ALIGN_POWER = TURN_POWER * 0.7f;
	static const float AIR_RESITANCE = 0.003f; // per one speed unit
	static const float DRIFT_SPEED_REDUCTION_RATE = 0.1f;

	// speed limit under what physics angle reduction will be more aggressive
	static const float LOWER_SPEED_ANGLE_REDUCTION = 6.0f;
	// speed limit under what angle difference will be lower than normal
	static const float LOWER_SPEED_ROTATION_REDUCTION = 6.0f;
	// speed limit under what turn power will decrease
	static const float LOWER_SPEED_TURN_REDUCTION = 2.0f;


	// increase the iteration id
	// be aware of 32-bit integer limit
	if (m_iterId != std::numeric_limits<int32_t>::max()) {
		m_iterId++;
	} else {
		m_iterId = 0;
	}

	// don't do anything if car is locked
	if (m_inputLocked) {
		return;
	}
	
	const float prevSpeed = m_speed; // for m_phySpeedDelta

	// apply inputs to speed
	if (m_inputState.brake) {
		m_speed -= BRAKE_POWER;
	} else if (m_inputState.accel) {
		// only if not choking
		if (!isChoking()) {
			m_chocking = false;
			m_speed += (SPEED_LIMIT - m_speed) * ACCEL_POWER;
		} else {
			m_chocking = true;
		}
	}
	
	// rotate steering wheels
	const float diff = m_inputState.turn - m_phyWheelsTurn;

	if (fabs(diff) > WHEEL_TURN_SPEED) {
		m_phyWheelsTurn += diff > 0.0f ? WHEEL_TURN_SPEED : -WHEEL_TURN_SPEED;
	} else {
		m_phyWheelsTurn = m_inputState.turn;
	}

	const float absSpeed = fabs(m_speed);

	// calculate rotations
	if (m_phyWheelsTurn != 0.0f) {

		// rotate corpse and later physics movement
		CL_Angle turnAngle(TURN_POWER * m_phyWheelsTurn, cl_radians);

		if (absSpeed <= LOWER_SPEED_TURN_REDUCTION) {
			// reduce turn if car speed is too low
			turnAngle.set_radians(turnAngle.to_radians() * (absSpeed / LOWER_SPEED_TURN_REDUCTION));
		}

		if (m_speed > 0.0f) {
			m_rotation += turnAngle;
		} else {
			m_rotation -= turnAngle;
		}

		// rotate corpse and physics movement
		if (absSpeed > LOWER_SPEED_ROTATION_REDUCTION) {
			alignRotation(m_phyMoveRot, m_rotation, MOV_ALIGN_POWER);
		} else {
			alignRotation(m_phyMoveRot, m_rotation, MOV_ALIGN_POWER * ((LOWER_SPEED_ROTATION_REDUCTION + 1.0f) - absSpeed));
		}

	} else {

		// align corpse back to physics movement
		alignRotation(m_rotation, m_phyMoveRot, MOV_ALIGN_POWER);

		// makes car stop rotating if speed is too low
		if (absSpeed > LOWER_SPEED_ANGLE_REDUCTION) {
			alignRotation(m_phyMoveRot, m_rotation, ROT_ALIGN_POWER);
		} else {
			alignRotation(m_phyMoveRot, m_rotation, ROT_ALIGN_POWER * ((LOWER_SPEED_ANGLE_REDUCTION + 1.0f) - absSpeed));
		}

		// normalize rotations only when equal
		if (m_rotation == m_phyMoveRot) {
			Workarounds::clAngleNormalize(&m_rotation);
			Workarounds::clAngleNormalize(&m_phyMoveRot);
		}

	}

	Workarounds::clAngleNormalize(&m_phyMoveRot);
	Workarounds::clAngleNormalize(&m_rotation);


	// reduce speed
	const CL_Angle diffAngle = m_rotation - m_phyMoveRot;
	float diffDegAbs = fabs(diffAngle.to_degrees());

	if (diffDegAbs > 0.1f) {

		CL_Angle diffAngleNorm = diffAngle;
		Workarounds::clAngleNormalize180(&diffAngleNorm);

		// 0.0 when going straight, 1.0 when 90 deg, > 1.0 when more than 90 deg
		const float angleRate = fabs(1.0f - (fabs(diffAngleNorm.to_degrees()) - 90.0f) / 90.0f);
		const float speedReduction = -DRIFT_SPEED_REDUCTION_RATE * angleRate;

		if (absSpeed > speedReduction) {
			m_speed += m_speed > 0.0f ? speedReduction : -speedReduction;
		} else {
			m_speed = 0.0f;
		}
	}

	// car cannot travel too quickly
	m_speed -= m_speed * AIR_RESITANCE;

	// calculate next move vector
	const float m_rotationRad = m_phyMoveRot.to_radians();

	m_phyMoveVec.x = cos(m_rotationRad);
	m_phyMoveVec.y = sin(m_rotationRad);

	m_phyMoveVec.normalize();
	m_phyMoveVec *= m_speed;

	// apply movement (invert y)
	m_position.x += m_phyMoveVec.x;
	m_position.y += m_phyMoveVec.y;

	// set speed delta
	m_phySpeedDelta = m_speed - prevSpeed;


#if defined(CLIENT)
#if !defined(NDEBUG)
	// print debug information
	DebugLayer *dbgl = Gfx::Stage::getDebugLayer();

	dbgl->putMessage("speed", cl_format("%1", m_speed));
//	if (!m_level) {
//		const float resistance = m_level->getResistance(m_position.x, m_position.y);
//		dbgl->putMessage("resist", cl_format("%1", resistance));
//	}
#endif // NDEBUG
#endif // CLIENT
}

CL_CollisionOutline Car::getCollisionOutline() const
{
	CL_CollisionOutline outline(m_impl->m_phyCollisionOutline);

	// transform the outline
	CL_Angle angle(90, cl_degrees);
	angle += m_impl->m_rotation;

	outline.set_angle(angle);
	outline.set_translation(m_impl->m_position.x, m_impl->m_position.y);

	return outline;
}

void Car::applyCollision(const CL_LineSegment2f &p_seg)
{
	static const float DAMAGE_MULT = 0.2f;

	const float side = -p_seg.point_right_of_line(m_impl->m_position);

	const CL_Vec2f segVec = p_seg.q - p_seg.p;

	// need front normal (crash side)
	CL_Vec2f fnormal(segVec.y, -segVec.x); // right side normal
	fnormal.normalize();

	if (side < 0) {
		fnormal *= -1;
	}

	// move away
	m_impl->m_position += (fnormal * fabs(m_impl->m_speed));

	// calculate collision angle to estaminate speed reduction
	CL_Angle angleDiff(m_impl->m_phyMoveRot - m_impl->vecToAngle(fnormal));
	Workarounds::clAngleNormalize180(&angleDiff);

	const float colAngleDeg = fabs(angleDiff.to_degrees()) - 90.0f;
	const float reduction = fabs(1.0f - fabs(colAngleDeg - 90.0f) / 90.0f);

	// calculate and apply damage
	const float damage = m_impl->m_speed * reduction * DAMAGE_MULT;
	m_impl->m_damage =
			Math::Float::reduce(m_impl->m_damage + damage, 0.0f, 1.0f);

	cl_log_event(LOG_DEBUG, "damage: %1, total: %2", damage, m_impl->m_damage);

	// reduce speed
	m_impl->m_speed -= m_impl->m_speed * reduction;

	// bounce movement vector and angle away

	// get mirror point
	if (m_impl->m_phyMoveVec.length() > 0.01f) {
		m_impl->m_phyMoveVec.normalize();

		const float lengthProj = m_impl->m_phyMoveVec.length() * cos(segVec.angle(m_impl->m_phyMoveVec).to_radians());
		const CL_Vec2f mirrorPoint(segVec * (lengthProj / segVec.length()));

		// invert move vector by mirror point
		const CL_Vec2f mirrorVec = (m_impl->m_phyMoveVec - mirrorPoint) * -1;
		m_impl->m_phyMoveVec = mirrorPoint + mirrorVec;

		// update physics angle
		m_impl->m_phyMoveRot = m_impl->vecToAngle(m_impl->m_phyMoveVec);

	}

}

CL_String floatToHex(float p_num)
{
	G_ASSERT(sizeof(float) == sizeof(u_int32_t));

	u_int32_t num = *reinterpret_cast<u_int32_t*>(&p_num);
	return Math::Integer::toHex(num);
}

float hexToFloat(const CL_String &p_str)
{
	int result = Math::Integer::fromHex(p_str);
	return *reinterpret_cast<float*>(&result);
}

void Car::serialize(CL_NetGameEvent *p_event) const
{
	// save iteration counter
	p_event->add_argument(m_impl->m_iterId);

	// save inputs
	p_event->add_argument(CL_NetGameEventValue(m_impl->m_inputState.accel));
	p_event->add_argument(CL_NetGameEventValue(m_impl->m_inputState.brake));
	p_event->add_argument(floatToHex(m_impl->m_inputState.turn));
	p_event->add_argument(CL_NetGameEventValue(m_impl->m_inputLocked));

	// corpse state
	p_event->add_argument(floatToHex(m_impl->m_position.x));
	p_event->add_argument(floatToHex(m_impl->m_position.y));
	p_event->add_argument(floatToHex(m_impl->m_rotation.to_radians()));
	p_event->add_argument(floatToHex(m_impl->m_speed));

	// physics parameters
	p_event->add_argument(floatToHex(m_impl->m_phyMoveRot.to_radians()));
	p_event->add_argument(floatToHex(m_impl->m_phyMoveVec.x));
	p_event->add_argument(floatToHex(m_impl->m_phyMoveVec.y));
	p_event->add_argument(floatToHex(m_impl->m_phySpeedDelta));
	p_event->add_argument(floatToHex(m_impl->m_phyWheelsTurn));

	p_event->add_argument(floatToHex(m_impl->m_damage));
}

void Car::deserialize(const CL_NetGameEvent &p_event)
{
	static const unsigned ARGUMENT_COUNT = 15;

	if (p_event.get_argument_count() != ARGUMENT_COUNT) {
		// when serialize data is invalid don't do anything
		cl_log_event(
				LOG_DEBUG,
				"invalid serialize data count: %1",
				p_event.get_argument_count()
		);

		return;
	}

	int idx = 0;

	// load iteration counter
	m_impl->m_iterId = p_event.get_argument(idx++);

	// saved inputs
	m_impl->m_inputState.accel = p_event.get_argument(idx++);
	m_impl->m_inputState.brake = p_event.get_argument(idx++);
	m_impl->m_inputState.turn = hexToFloat(p_event.get_argument(idx++));
	m_impl->m_inputLocked = p_event.get_argument(idx++);

	// corpse state
	m_impl->m_position.x = hexToFloat(p_event.get_argument(idx++));
	m_impl->m_position.y = hexToFloat(p_event.get_argument(idx++));
	m_impl->m_rotation.set_radians(hexToFloat(p_event.get_argument(idx++)));
	m_impl->m_speed = hexToFloat(p_event.get_argument(idx++));

	// physics parameters
	m_impl->m_phyMoveRot.set_radians(hexToFloat(p_event.get_argument(idx++)));
	m_impl->m_phyMoveVec.x = hexToFloat(p_event.get_argument(idx++));
	m_impl->m_phyMoveVec.y = hexToFloat(p_event.get_argument(idx++));
	m_impl->m_phySpeedDelta = hexToFloat(p_event.get_argument(idx++));
	m_impl->m_phyWheelsTurn = hexToFloat(p_event.get_argument(idx++));

	m_impl->m_damage = hexToFloat(p_event.get_argument(idx++));
}

bool CarImpl::isChoking()
{
	if (m_damage < 1.0f) {
		return false;
	}

	// c is iter count. 60 per second
	const unsigned c = m_iterId;

	// lets assume that 64 iterations is one second
	// so then...

	if (1 << 8 & c && 1 << 5 & c) { // 0.5s every 4s
		return true;
	}

	if (1 << 7 & c && 1 << 4 & c) { // 0.25s every 2s
		return true;
	}

	if (1 << 6 & c && 1 << 3 & c) { // 0.1s every 1s
		return true;
	}

	return false;
}

bool Car::isChoking() const
{
	return m_impl->m_chocking;
}

bool Car::isDrifting() const {
	static const float DRIFT_LIMIT = 6.0f;
	static const float ACCEL_LIMIT = 0.05f;

	if (fabs((m_impl->m_rotation - m_impl->m_phyMoveRot).to_degrees()) >= DRIFT_LIMIT) {
		return true;
	}

	if (
			(m_impl->m_inputState.accel || m_impl->m_inputState.brake)
			&& fabs(m_impl->m_phySpeedDelta) >= ACCEL_LIMIT)
	{
		return true;
	}

	return false;
}

bool Car::isLocked() const
{
	return m_impl->m_inputLocked;
}

const CL_Pointf& Car::getPosition() const
{
	return m_impl->m_position;
}

float Car::getSpeed() const
{
	return m_impl->m_speed;
}

float Car::getSpeedKMS() const
{
//	// m_speed - pixels per iteration
//	// 4 - length of avarage car in meters
//	// 25 - length of avarage car in pixels
//	// 60 - one second
//	// 60 * 60 - one minute
//	// 60 * 60 * 60 - one hour
//	// / 1000 - to kmh
//	return m_speed * (4 / 25.0f) * 60 * 60 * 60 / 1000;

	const float m_f =  m_impl->m_speed / 15.0; // m / frame
	const float m_s = m_f * 60.0f; // m / s
	const float m_h = m_s * 3600.0; // m / h
	return m_h / 1000.0; // km / h
}

void Car::setAcceleration(bool p_value)
{
	m_impl->m_inputState.accel = p_value;
}

void Car::setBrake(bool p_value)
{
	m_impl->m_inputState.brake = p_value;
}

void Car::setTurn(float p_value)
{
	m_impl->m_inputState.turn = m_impl->limit(p_value, -1.0f, 1.0f);
}

void Car::setPosition(const CL_Pointf &p_position)
{
	m_impl->m_position = p_position;
}

void Car::setAngle(const CL_Angle &p_angle)
{
	m_impl->m_rotation = p_angle;
	m_impl->m_phyMoveRot = m_impl->m_rotation;
}

float CarImpl::limit(float p_value, float p_from, float p_to) const
{
	if (p_value < p_from) {
		return p_from;
	}

	if (p_value > p_to) {
		return p_to;
	}

	return p_value;
}

void Car::setLocked(bool p_locked)
{
	m_impl->m_inputLocked = p_locked;

	// stop the car
	if (p_locked) {
		m_impl->m_phyMoveVec.x = m_impl->m_phyMoveVec.y = 0.0f;
	}
}

CL_Angle CarImpl::vecToAngle(const CL_Vec2f &p_vec)
{
	const static CL_Vec2f ANGLE_ZERO(1.0f, 0.0f);
	CL_Angle angle = p_vec.angle(ANGLE_ZERO);

	if (p_vec.y < 0) {
		angle.set_radians(-angle.to_radians());
	}

	return angle;

}

void Car::setSpeed(float p_speed)
{
	m_impl->m_speed = p_speed;
}

void Car::setMovement(const CL_Vec2f &p_movement)
{
	m_impl->m_phyMoveVec = p_movement;
}

const CL_Angle &Car::getCorpseAngle() const
{
	return m_impl->m_rotation;
}

void Car::reset()
{
	m_impl->m_damage = 0.0f;
}

void Car::resetIterationCounter()
{
	m_impl->m_iterId = -1;
}

void Car::clone(const Car &p_car)
{
	m_impl->m_position = p_car.m_impl->m_position;
	m_impl->m_rotation = p_car.m_impl->m_rotation;
	m_impl->m_speed = p_car.m_impl->m_speed;
	m_impl->m_inputState.accel = p_car.m_impl->m_inputState.accel;
	m_impl->m_inputState.brake = p_car.m_impl->m_inputState.brake;
	m_impl->m_inputState.turn = p_car.m_impl->m_inputState.turn;
	m_impl->m_inputLocked = p_car.m_impl->m_inputLocked;
	m_impl->m_phyMoveRot = p_car.m_impl->m_phyMoveRot;
	m_impl->m_phyMoveVec = p_car.m_impl->m_phyMoveVec;
	m_impl->m_phySpeedDelta = p_car.m_impl->m_phySpeedDelta;
	m_impl->m_phyWheelsTurn = p_car.m_impl->m_phyWheelsTurn;
}

bool Car::operator==(const Car &p_other) const
{
	if (&p_other == this) {
		return true;
	}

	bool r = true;
	r &= m_impl->m_position == p_other.m_impl->m_position;
	r &= m_impl->m_rotation == p_other.m_impl->m_rotation;
	r &= m_impl->m_speed == p_other.m_impl->m_speed;
	r &= m_impl->m_inputState.accel == p_other.m_impl->m_inputState.accel;
	r &= m_impl->m_inputState.brake == p_other.m_impl->m_inputState.brake;
	r &= m_impl->m_inputState.turn == p_other.m_impl->m_inputState.turn;
	r &= m_impl->m_inputLocked == p_other.m_impl->m_inputLocked;
	r &= m_impl->m_phyMoveRot == p_other.m_impl->m_phyMoveRot;
	r &= m_impl->m_phyMoveVec == p_other.m_impl->m_phyMoveVec;
	r &= m_impl->m_phySpeedDelta == p_other.m_impl->m_phySpeedDelta;
	r &= m_impl->m_phyWheelsTurn == p_other.m_impl->m_phyWheelsTurn;

	return r;
}

bool Car::operator!=(const Car &p_other) const
{
	return !(*this == p_other);
}

float Car::getPhyWheelTurn() const
{
	return m_impl->m_phyWheelsTurn;
}

int32_t Car::getIterationId() const
{
	return m_impl->m_iterId;
}

const Player &Car::getOwnerPlayer() const
{
	return *m_impl->m_ownerPlayer;
}

const CarInputState &Car::getInputState() const
{
	return m_impl->m_inputState;
}

const CL_Angle &Car::getPhyAngle() const
{
	return m_impl->m_phyMoveRot;
}

const CL_Vec2f &Car::getPhyMoveVector() const
{
	return m_impl->m_phyMoveVec;
}

} // namespace
예제 #12
0
파일: Car.cpp 프로젝트: genail/gear
void CarImpl::update1_60() {
	
	static const float BRAKE_POWER = 0.1f;
	static const float ACCEL_POWER = 0.014f;
	static const float SPEED_LIMIT = 15.0f;
	static const float WHEEL_TURN_SPEED = 1.0f / 10.0f;
	static const float TURN_POWER  = (2 * CL_PI / 360.0f) * 2.5f;
	static const float MOV_ALIGN_POWER = TURN_POWER / 2.0f;
	static const float ROT_ALIGN_POWER = TURN_POWER * 0.7f;
	static const float AIR_RESITANCE = 0.003f; // per one speed unit
	static const float DRIFT_SPEED_REDUCTION_RATE = 0.1f;

	// speed limit under what physics angle reduction will be more aggressive
	static const float LOWER_SPEED_ANGLE_REDUCTION = 6.0f;
	// speed limit under what angle difference will be lower than normal
	static const float LOWER_SPEED_ROTATION_REDUCTION = 6.0f;
	// speed limit under what turn power will decrease
	static const float LOWER_SPEED_TURN_REDUCTION = 2.0f;


	// increase the iteration id
	// be aware of 32-bit integer limit
	if (m_iterId != std::numeric_limits<int32_t>::max()) {
		m_iterId++;
	} else {
		m_iterId = 0;
	}

	// don't do anything if car is locked
	if (m_inputLocked) {
		return;
	}
	
	const float prevSpeed = m_speed; // for m_phySpeedDelta

	// apply inputs to speed
	if (m_inputState.brake) {
		m_speed -= BRAKE_POWER;
	} else if (m_inputState.accel) {
		// only if not choking
		if (!isChoking()) {
			m_chocking = false;
			m_speed += (SPEED_LIMIT - m_speed) * ACCEL_POWER;
		} else {
			m_chocking = true;
		}
	}
	
	// rotate steering wheels
	const float diff = m_inputState.turn - m_phyWheelsTurn;

	if (fabs(diff) > WHEEL_TURN_SPEED) {
		m_phyWheelsTurn += diff > 0.0f ? WHEEL_TURN_SPEED : -WHEEL_TURN_SPEED;
	} else {
		m_phyWheelsTurn = m_inputState.turn;
	}

	const float absSpeed = fabs(m_speed);

	// calculate rotations
	if (m_phyWheelsTurn != 0.0f) {

		// rotate corpse and later physics movement
		CL_Angle turnAngle(TURN_POWER * m_phyWheelsTurn, cl_radians);

		if (absSpeed <= LOWER_SPEED_TURN_REDUCTION) {
			// reduce turn if car speed is too low
			turnAngle.set_radians(turnAngle.to_radians() * (absSpeed / LOWER_SPEED_TURN_REDUCTION));
		}

		if (m_speed > 0.0f) {
			m_rotation += turnAngle;
		} else {
			m_rotation -= turnAngle;
		}

		// rotate corpse and physics movement
		if (absSpeed > LOWER_SPEED_ROTATION_REDUCTION) {
			alignRotation(m_phyMoveRot, m_rotation, MOV_ALIGN_POWER);
		} else {
			alignRotation(m_phyMoveRot, m_rotation, MOV_ALIGN_POWER * ((LOWER_SPEED_ROTATION_REDUCTION + 1.0f) - absSpeed));
		}

	} else {

		// align corpse back to physics movement
		alignRotation(m_rotation, m_phyMoveRot, MOV_ALIGN_POWER);

		// makes car stop rotating if speed is too low
		if (absSpeed > LOWER_SPEED_ANGLE_REDUCTION) {
			alignRotation(m_phyMoveRot, m_rotation, ROT_ALIGN_POWER);
		} else {
			alignRotation(m_phyMoveRot, m_rotation, ROT_ALIGN_POWER * ((LOWER_SPEED_ANGLE_REDUCTION + 1.0f) - absSpeed));
		}

		// normalize rotations only when equal
		if (m_rotation == m_phyMoveRot) {
			Workarounds::clAngleNormalize(&m_rotation);
			Workarounds::clAngleNormalize(&m_phyMoveRot);
		}

	}

	Workarounds::clAngleNormalize(&m_phyMoveRot);
	Workarounds::clAngleNormalize(&m_rotation);


	// reduce speed
	const CL_Angle diffAngle = m_rotation - m_phyMoveRot;
	float diffDegAbs = fabs(diffAngle.to_degrees());

	if (diffDegAbs > 0.1f) {

		CL_Angle diffAngleNorm = diffAngle;
		Workarounds::clAngleNormalize180(&diffAngleNorm);

		// 0.0 when going straight, 1.0 when 90 deg, > 1.0 when more than 90 deg
		const float angleRate = fabs(1.0f - (fabs(diffAngleNorm.to_degrees()) - 90.0f) / 90.0f);
		const float speedReduction = -DRIFT_SPEED_REDUCTION_RATE * angleRate;

		if (absSpeed > speedReduction) {
			m_speed += m_speed > 0.0f ? speedReduction : -speedReduction;
		} else {
			m_speed = 0.0f;
		}
	}

	// car cannot travel too quickly
	m_speed -= m_speed * AIR_RESITANCE;

	// calculate next move vector
	const float m_rotationRad = m_phyMoveRot.to_radians();

	m_phyMoveVec.x = cos(m_rotationRad);
	m_phyMoveVec.y = sin(m_rotationRad);

	m_phyMoveVec.normalize();
	m_phyMoveVec *= m_speed;

	// apply movement (invert y)
	m_position.x += m_phyMoveVec.x;
	m_position.y += m_phyMoveVec.y;

	// set speed delta
	m_phySpeedDelta = m_speed - prevSpeed;


#if defined(CLIENT)
#if !defined(NDEBUG)
	// print debug information
	DebugLayer *dbgl = Gfx::Stage::getDebugLayer();

	dbgl->putMessage("speed", cl_format("%1", m_speed));
//	if (!m_level) {
//		const float resistance = m_level->getResistance(m_position.x, m_position.y);
//		dbgl->putMessage("resist", cl_format("%1", resistance));
//	}
#endif // NDEBUG
#endif // CLIENT
}