Пример #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
			}
		}
	}
}