class Camera: def __init__(self, track, map): self._track_obj = track position = self._track_obj.getPosition() self._target = Verlet(position) self._pos = Verlet(position + (1,0,0)) self._map = map self._pos.setGravity(0) self._target.setGravity(0) self._pos.setDamping((0.3,0.3,0.99)) self._target.setDamping(0.3) self._up = N.array((0,0,1),dtype="f") self._look_at = position @profile def update(self,time): self._pos.update() self._target.update() look_at = self._track_obj.getPosition()+(0,0,0.6) cam_pos = look_at -self._track_obj.getFrontVector() * 2.0 + N.array((0,0,0.0)) self._pos.impulseTowards(cam_pos) self._target.impulseTowards(look_at) # see if the camera doesn't intersect geometry. If it does, push it up cam_pos =self._pos.getPosition() look_at = self._target._position dv = cam_pos - look_at dist = T.vector_norm(dv[0:2]) # distance across floor n = math.ceil(dist / 0.2) z0 = look_at[2] dray = dv / n m = self._map hit = False # ray-march #z_list = [] ray_pos = look_at + dray # advance once for i in xrange(1,int(n)+3): # start at i=1 to avoid division by zero z = m(ray_pos[0], ray_pos[1], False)+0.4 # is an offset so the camera can see #z_list.append(int(z*10)) if z > ray_pos[2]: slope = (z-z0) / float(i) #if slope > 0.1: # ray_pos -= dray # go back one step # break dray[2] = slope ray_pos[2] = z hit = True ray_pos += dray ray_pos -= dray*3 #print z_list #print "%s -> %s %s" % (self._pos.getPosition(), ray_pos, "HIT" if hit else "") if hit: self._pos.moveTo(ray_pos) def getMatrix(self): return lookAtMtx(self._pos._position, self._target._position, self._up)
class Player(Entity): def __init__(self, map, position): print "New player" Entity.__init__(self) self._lock = None self._phys = Verlet(position) self._phys.setDamping((0.02, 0.02, 0.0002)) self._phys.setGravity((0, 0, -0.00006)) self._on_floor = False self._speed = 0 self._map = map self._heading = 0 self.reset() r = self._radius = 0.1 self.setBounds(((-r, -r, -r), (r, r, r))) # entity stuff Entity.moveTo(self, position) # keep the entity updated self._scaling = T.scale_matrix(self._radius) self._last_pos = N.array((0, 0, 0), dtype="f") self._graphics = R.loadObject("sphere.obj", "diffuse") def getMissile(self, scene): if self._lock is not None: follow = self._lock[0] else: follow = None m_dir = 50 * (self._speed + 0.02) * self._front_vec * 1.5 + self._normal T.unit_vector(m_dir, out=m_dir) return Missile(scene, self._pos, m_dir, "projectile", follow) def reset(self, position=None): self._rotation = T.quaternion_about_axis(0, (1, 0, 0)) self.setHeading(0) if position is not None: self.moveTo(position) def checkLock(self, enemy): best_d = 100000 if self._lock is None else self._lock[1] if enemy._closing: return v = enemy._pos - self._pos d = N.dot(v, v) if d < 1000: # max enemy distance if self._lock is None or best_d > d: self._lock = (enemy, d, enemy._pos) def getLockPosition(self): try: return self._lock[2] # enemy position when locked except: return None # for physics simulation @profile def update(self, time): self._lock = None # ----- here be dragons ph = self._phys ph._impuse = ph._gravity ph.update() # test for collision with map z, normal = self._map(ph._position[0], ph._position[1]) h = (z + self._radius) - ph._position[2] T.unit_vector(normal, out=normal) self._on_floor = h > 0 if self._on_floor and ph._position[2] < ph._last_position[2]: # collision ph._impulse += h * normal * 0.00001 # * normal[2] ph._position[2] += h ph._last_position[2] += h new_pos = ph._position # ----- self._dir = new_pos - self._pos self._speed = T.vector_norm(self._dir) self._last_pos[:] = new_pos Entity.moveTo(self, new_pos) # updates self._pos too self._normal = normal self._axis = N.cross(self._dir, normal) self.roll(self._axis) def moveTo(self, pos): dp = pos - self._pos Entity.moveTo(pos) self._phys.displace(dp) def roll(self, axis): len = T.vector_norm(axis) * 5.0 rot = T.quaternion_about_axis(-len, axis) self._rotation = T.quaternion_multiply(rot, self._rotation) def getHeading(self): return self._heading def setHeading(self, new_angle): self._heading = new_angle self._front_vec = N.array((math.cos(new_angle), math.sin(new_angle), 0), dtype="f") def alterHeading(self, delta_angle): if delta_angle != 0: self.setHeading(self._heading + delta_angle) def advance(self, amount): if amount == 0: return r = N.cross(self._normal, self._front_vec) T.unit_vector(r, out=r) # vector facing front, parallel to the floor front = N.cross(r, self._normal) self._phys.impulse(front * amount) def getFrontVector(self): return self._front_vec def draw(self, scene): self._graphics.draw(scene, mmult(self._pos_m, T.quaternion_matrix(self._rotation), self._scaling)) def jump(self): if self._on_floor: self._phys._last_position = self._phys._position - self._normal * 0.1