예제 #1
0
void gun_shell::check_collision_voxel(ship& s, const vector3f& oldrelpos, const vector3f& newrelpos)
{
	// positions are relative to bbox of s.
	matrix4f obj2voxel = s.get_model().get_base_mesh_transformation().inverse();
	vector3f oldvoxpos = obj2voxel * oldrelpos, newvoxpos = obj2voxel * newrelpos;
	vector3f diffvoxpos = newvoxpos - oldvoxpos;
	// now iterate in 8 steps between oldvoxpos to newvoxpos,
	// transform both to voxel coordinates (0...N)
	// and determine voxel number by pos.
	// if coordinate is invalid, no hit, otherwise check voxel state (volume > 0.25 or similar)
	// if the voxel is filled.
	vector3f voxel_size_rcp = s.get_model().get_voxel_size().rcp();
	const vector3i& vres = s.get_model().get_voxel_resolution();
	vector3i vidxmax = vres - vector3i(1, 1, 1);
	vector3f voxel_pos_trans = vector3f(vres) * 0.5f;
	int lastvn = -1;
	log_debug("check collision voxel");
	for (unsigned k = 0; k <= 10; ++k) {
		float kf = k/10.0f;
		vector3f voxpos = oldvoxpos + diffvoxpos * kf;
		vector3i v = vector3i(voxpos.coeff_mul(voxel_size_rcp) + voxel_pos_trans);
		v = v.max(vector3i(0,0,0)).min(vidxmax);
		int vn = (v.z * vres.y + v.y)*vres.x + v.x;
		if (vn != lastvn) {
			lastvn = vn;
			log_debug("voxel hit k="<<k<<" voxpos="<<voxpos<<" v="<<v<<" vn="<<vn);
			const model::voxel* vox = s.get_model().get_voxel_by_pos(v);
			if (vox) {
				// we hit a part of the object!
				log_debug("..... Object hit! .....");
				// first compute exact real word position of impact
				vector3 impactpos = s.get_pos()
					+ s.get_orientation().rotate(s.get_model().
						get_base_mesh_transformation() * voxpos);
				// move gun shell pos to hit position to
				// let the explosion be at right position
				position = impactpos;
				log_debug("Hit object at real world pos " << impactpos);
				log_debug("that is relative: " << s.get_pos()-impactpos);
				// now damage the ship
				if (s.damage(impactpos, int(damage_amount))) { // fixme, crude
					gm.ship_sunk(&s);
				} else {
					s.ignite();
				}
#if 0
				//spawn some location marker object for testing
				//at exact impact position
				gm.spawn_particle(new marker_particle(impactpos));
#endif
				gm.add_event(new event_shell_explosion(get_pos()));
				kill(); // grenade is used and dead
				return; // no more checks
			}
		}
	}
}
예제 #2
0
void gun_shell::check_collision_precise(ship& s, const vector3& oldrelpos,
					const vector3& newrelpos)
{
	// transform positions to s' local bbox space
	quaternion qco = s.get_orientation().conj();
	vector3f oldrelbbox = vector3f(qco.rotate(oldrelpos));
	vector3f newrelbbox = vector3f(qco.rotate(newrelpos));
	// now the model::get_min/get_max values can be used to compute the axis aligned bbox
	float tmin = 0.0f, tmax = 1.0f;
	// clip the line oldrelbbox->newrelbbox with the bbox
	vector3f d = newrelbbox - oldrelbbox;
	const vector3f& b = oldrelbbox;
	vector3f bmin = s.get_model().get_min();
	vector3f bmax = s.get_model().get_max();

	if (fabs(d.x) > 1e-5) {
		float t0 = (bmin.x - b.x) / d.x;
		float t1 = (bmax.x - b.x) / d.x;
		float ta = std::min(t0, t1);
		float tb = std::max(t0, t1);
		tmax = std::min(tmax, tb);
		tmin = std::max(tmin, ta);
	}
	if (fabs(d.y) > 1e-5) {
		float t0 = (bmin.y - b.y) / d.y;
		float t1 = (bmax.y - b.y) / d.y;
		float ta = std::min(t0, t1);
		float tb = std::max(t0, t1);
		tmax = std::min(tmax, tb);
		tmin = std::max(tmin, ta);
	}
	if (fabs(d.z) > 1e-5) {
		float t0 = (bmin.z - b.z) / d.z;
		float t1 = (bmax.z - b.z) / d.z;
		float ta = std::min(t0, t1);
		float tb = std::max(t0, t1);
		tmax = std::min(tmax, tb);
		tmin = std::max(tmin, ta);
	}

	if (tmin <= tmax) {
		//log_debug("shell hit object?!");
		vector3f d = newrelbbox - oldrelbbox;
		check_collision_voxel(s, oldrelbbox + d * tmin, oldrelbbox + d * tmax);
		if (alive_stat == dead) return; // no more checks after hit
	}
}