Rooms.mover = new function(){ var base = this base.room = null base.noclip = false var cursor = base.cursor = new Rect (0,0,0,0) var wall_vec = new Rect (0,0,0,0) var intersect = new vec2(0,0) var origins = new Rect() origins.x = cursor.x origins.y = wall_vec.x base.init = function(){ base.bind() base.update(scene.camera) } base.bind = function(){ app.on("move", base.update) keys.on("backslash", function(e){ if ( ! (e.ctrlKey || e.metaKey) ) return base.noclip = ! base.noclip base.room = null app.movements.gravity( ! base.noclip ) }) } base.update = function(pos){ var radius = scene.camera.radius cam.y = pos.y // if we were in a room already.. if (base.room) { // check if we're still in the room if (base.room.rect.containsDisc(pos.x, pos.z, radius)) { cam.x = pos.x cam.z = pos.z return } var intersect = base.intersect(pos) if (intersect && ! base.noclip) { cam.x = intersect.a cam.z = intersect.b return } /* // check if we've breached one of the walls.. clamp position if so var collision = base.room.collidesDisc(cam, pos, radius) if (collision && ! base.noclip) { cam.x = (collision & LEFT_RIGHT) ? base.room.rect.x.clampDisc(pos.x, radius) : pos.x cam.z = (collision & FRONT_BACK) ? base.room.rect.y.clampDisc(pos.z, radius) : pos.z return } */ // in this case, we appear to have left the room.. // $(".face.active").removeClass("active") Walls.clearBodyColor() base.room = null } // collision test failed, so update position cam.x = pos.x cam.z = pos.z // determine what room we are in now var intersects = Rooms.filter(function(r){ return r.rect.contains(pos.x, pos.z) }) // did we actually enter a room? if (intersects.length) { base.room = intersects[0] if (! base.noclip) { Walls.setBodyColor() } app.tube("change-room", { room: base.room }) } } base.intersect = function(pos){ var closest_intersect, t, min_t = 1 cursor.x.a = cam.x cursor.x.b = cam.z cursor.y.a = pos.x cursor.y.b = pos.z var a = angle(cursor) cursor.y.a += scene.camera.radius * cos(a) cursor.y.b += scene.camera.radius * sin(a) Walls.list.forEach(function(wall, i){ var actually_intersects, intersecting_face if (wall.side & LEFT_RIGHT) { wall_vec.x.a = wall.edge wall_vec.x.b = wall.vec.a wall_vec.y.a = wall.edge wall_vec.y.b = wall.vec.b } else { wall_vec.x.a = wall.vec.a wall_vec.x.b = wall.edge wall_vec.y.a = wall.vec.b wall_vec.y.b = wall.edge } t = perp(origins, wall_vec) / ( perp(cursor, wall_vec) || 0.0000001 ) if ( min_t < t || t < 0 || 1 < t ) return intersect.a = cursor.x.a + ( cursor.y.a - cursor.x.a ) * t intersect.b = cursor.x.b + ( cursor.y.b - cursor.x.b ) * t if ( ! is_collinear( intersect, wall_vec ) ) return if (wall.side & LEFT_RIGHT) { intersecting_face = wall.surface.face_for_x(intersect.b) } else { intersecting_face = wall.surface.face_for_x(intersect.a) } actually_intersects = !! (intersecting_face && intersecting_face.y.a == 0) if (actually_intersects) { closest_intersect = intersect.clone() min_t = t } }) if (min_t < 1) { var a = angle(cursor) closest_intersect.a -= scene.camera.radius * cos(a) closest_intersect.b -= scene.camera.radius * sin(a) } return closest_intersect } function angle (va) { return atan2(va.y.b - va.x.b, va.y.a - va.x.a) } function dot (va, vb) { return (va.y.a - va.x.a) * (vb.y.a - vb.x.a) + (va.y.b - va.x.b) * (vb.y.b - vb.x.b) } function perp (va, vb) { return (va.y.a - va.x.a) * (vb.y.b - vb.x.b) - (va.y.b - va.x.b) * (vb.y.a - vb.x.a) } function is_collinear (p, vec) { var on_x, on_y var pa = round(p.a), pb = round(p.b) if (vec.x.a < vec.y.a) { on_x = vec.x.a <= pa && pa <= vec.y.a } else { on_x = vec.x.a >= pa && pa >= vec.y.a } if (vec.x.b < vec.y.b) { on_y = vec.x.b <= pb && pb <= vec.y.b } else { on_y = vec.x.b >= pb && pb >= vec.y.b } return !! (on_x && on_y) } }