Пример #1
0
void CollideEntity::bounce(float ba)
{
	if (getState() == STATE_PUSH)
	{
		dsq->spawnParticleEffect("HitSurface", dsq->game->lastCollidePosition);
		//dsq->effectCollisionSmoke(position);
		sound("RockHit");
		// HACK: replace damage function
		//damage(pushDamage);
		setState(STATE_PUSHDELAY, 0.3);
	}

	switch (bounceType)
	{
	case BOUNCE_REAL:
	{
		if (!vel.isZero())
		{
			float len = vel.getLength2D();	
			Vector I = vel/len;
			Vector N = dsq->game->getWallNormal(dsq->game->lastCollidePosition);	

			if (!N.isZero())
			{
				//2*(-I dot N)*N + I 
				vel = 2*(-I.dot(N))*N + I;
				vel.setLength2D(len*ba);
			}
		}
	}
	break;
	case BOUNCE_SIMPLE:
	{
		if (!vel.isZero())
		{
			float len = vel.getLength2D();
			Vector mov = vel;
			mov.setLength2D(len*ba);
			if (mov.x > mov.y)
				mov.x = -mov.x;
			else
				mov.y = -mov.y;
			vel = mov;
			vel.z = 0;
		}
	}
	break;
	}
	//mov.setLength2D(-len * ba);


	onBounce();
}
Пример #2
0
void GRubberBallSwarm::advanceBall(double* pBallPos)
{
	// Get the ball
	double* pBallDir = pBallPos + m_dims;
	double* pBallBias = pBallDir + m_dims;
	GRubberBallStats* pBallStats = (GRubberBallStats*)(pBallBias + m_dims);

	// Advance
	GVec::addScaled(pBallPos, pBallStats->m_speed, pBallDir, m_dims);
	if(isInside(pBallPos))
	{
		// Accelerate
		pBallStats->m_speed *= m_acceleration;
		pBallStats->m_odometer += pBallStats->m_speed;
		return;
	}

	// Back up
	GVec::addScaled(pBallPos, -pBallStats->m_speed, pBallDir, m_dims);
	if(!isInside(pBallPos))
	{
		if(GVec::squaredMagnitude(pBallPos, m_dims) == 0)
			throw Ex("GRubberBallSwarm expects the origin to be inside");

		// The shell moved, and the ball is not longer inside, so it must die
		initBall(pBallPos, pBallStats->m_speed / 2);
		return;
	}

	// Move closer to the wall (using binary search)
	double d = pBallStats->m_speed;
	int i;
	for(i = 0; i < m_wallPrecisionIters; i++)
	{
		d *= 0.5;
		GVec::addScaled(pBallPos, d, pBallDir, m_dims);
		if(isInside(pBallPos))
			pBallStats->m_odometer += d;
		else
			GVec::addScaled(pBallPos, -d, pBallDir, m_dims);
	}

	// Approximate the wall's normal vector by sampling
	d *= 4;
	GVec::setAll(m_pNormal, 0.0, m_dims);
	int insideCount = 0;
	for(i = 0; i < m_wallPrecisionIters; i++)
	{
		m_pRand->spherical(m_pTemp, m_dims);
		GVec::addScaled(pBallPos, d, m_pTemp, m_dims);
		if(isInside(pBallPos))
		{
			GVec::add(m_pNormal, m_pTemp, m_dims);
			insideCount++;
		}
		else
			GVec::subtract(m_pNormal, m_pTemp, m_dims);
		GVec::addScaled(pBallPos, -d, m_pTemp, m_dims);
	}
	if(insideCount == 0)
	{
		// Somehow we got stuck in a bad spot, so let's just kill the ball
		initBall(pBallPos, 0.1);
		return;
	}

	// Update the ball's bias
	double sum = 0;
	for(i = 0; i < m_dims; i++)
	{
		m_pTemp[i] = 1.0 / std::max(1e-9, std::abs(m_pNormal[i]));
		sum += m_pTemp[i];
	}
	GVec::multiply(pBallBias, (1.0 - m_learningRate), m_dims);
	GVec::addScaled(pBallBias, m_learningRate * m_dims / sum, m_pTemp, m_dims);
	sum = 0;
	for(i = 0; i < m_dims; i++)
		sum += pBallBias[i];
	GVec::multiply(pBallBias, (double)m_dims / sum, m_dims);

	// Bounce in a biassed random direction
	onBounce(pBallPos);
	m_pRand->spherical(pBallDir, m_dims);
	for(i = 0; i < m_dims; i++)
		pBallDir[i] *= pBallBias[i];
	GVec::normalize(pBallDir, m_dims);
	if(GVec::dotProduct(pBallDir, m_pNormal, m_dims) < 0)
		GVec::multiply(pBallDir, -1, m_dims);
	pBallStats->m_speed *= m_deceleration;
}