private void synchronize_velocity_air_to_ground() { if (observer.exists) { horizontal_velocity = Vector3.Dot(velocity, Bearing.right(planetaria_transform.position, collision.geometry_visitor.normal())); vertical_velocity = Vector3.Dot(velocity, collision.geometry_visitor.normal()); } }
/// <summary> /// Inspector - Finds the point at "angle" extruded "extrusion" along "local_angle" direction. /// </summary> /// <param name="arc">The arc (used to determine positions and relative angles).</param> /// <param name="angle">The angle along the arc path. Range: [-arc.angle()/2, +arc.angle()/2]</param> /// <param name="local_angle">The secant angle relative to the arc at position("angle"). Range: [0, 2PI]</param> /// <param name="extrusion">The distance along "local_angle" to extrude.</param> /// <returns>The relative position after extruding the point at "angle" by "extrusion" along "local_angle".</returns> public static Vector3 relative_point(Arc arc, float angle, float local_angle, float extrusion) { Vector3 from = arc.position(angle); Vector3 local_direction = Bearing.bearing(arc.position(angle), arc.normal(angle), local_angle); Vector3 to = PlanetariaMath.spherical_linear_interpolation(from, local_direction, extrusion); return(to); }
private void synchronize_velocity_ground_to_air() { if (observer.exists) { Vector3 x = horizontal_velocity * Bearing.right(planetaria_transform.position, collision.geometry_visitor.normal()); Vector3 y = vertical_acceleration * Time.fixedDeltaTime * collision.geometry_visitor.normal(); velocity = x + y; } }
private void grounded_accelerate(float delta) { Vector3 normal = collision.geometry_visitor.normal(); Vector3 right = Bearing.right(collision.geometry_visitor.position(), normal); acceleration = get_acceleration(); horizontal_acceleration = Vector3.Dot(acceleration, right); vertical_acceleration = Vector3.Dot(acceleration, normal) - collision.magnetism; vertical_velocity += vertical_acceleration * Time.fixedDeltaTime; if (!collision.grounded(internal_velocity)) // TODO: check centripedal force { derail(0, vertical_acceleration * delta); // Force OnCollisionExit, "un-collision" (and accelerate for a frame) } }
/// <summary> /// Inspector - project a point onto the given equator axis (the direction a raindrop would fall along a globe). /// </summary> /// <param name="point">The point that shall be projected.</param> /// <param name="equator_axis">The axis of the equator line (onto which the point shall be projected).</param> /// <returns>A projected point along the equator axis.</returns> public static Vector3 project_onto_equator(Vector3 point, Vector3 equator_axis) { if (Vector3.Dot(point, equator_axis) < 0) // make sure you are repelling from the pole closer to the point (so the point moves towards the equator). { equator_axis *= -1; } Vector3 gradient = Bearing.repeller(point, equator_axis); // push the point away from the axis towards the equator float angle = Mathf.PI / 2 - Vector3.Angle(point, equator_axis) * Mathf.Deg2Rad; // find the angle to the equator Vector3 projected_point = spherical_linear_interpolation(point, gradient, angle); Debug.Assert(Vector3.Dot(projected_point, equator_axis) < Precision.threshold); return(projected_point); }
private static bool platform_collision(Arc arc, PlanetariaCollider collider, PlanetariaTransform transformation, PlanetariaRigidbody rigidbody, optional <Vector3> intersection_point) { Vector3 velocity = Bearing.attractor(rigidbody.get_previous_position(), rigidbody.get_position()); if (intersection_point.exists) { float arc_angle = arc.position_to_angle(intersection_point.data); Vector3 normal = arc.normal(arc_angle); bool upward_facing_normal = Vector3.Dot(normal, rigidbody.get_acceleration()) <= 0; bool moving_toward = Vector3.Dot(normal, velocity) <= 0; if (upward_facing_normal && moving_toward) { return(true); } } return(false); }
/// <summary> /// Inspector - Determine the type of corner connecting the left-hand-side and right-hand-side Arcs (concave/convex/straight). /// </summary> /// <param name="left">Arc that will connect to beginning.</param> /// <param name="right">Arc that will connect to end.</param> /// <returns> /// GeometryType.ConvexCorner if the corner arc is convex. /// GeometryType.ConcaveCorner if the corner arc is concave. /// GeometryType.StraightCorner if the corner arc is a straight angle. /// </returns> public static ArcType corner_type(Arc left, Arc right) { // Both cases Vector3 normal_for_left = left.end_normal(); // Straight angle check Vector3 normal_for_right = right.begin_normal(); // Convex/Concave check Vector3 rightward_for_right = Bearing.right(right.begin(), right.begin_normal()); if (Vector3.Dot(normal_for_left, normal_for_right) > 1 - Precision.tolerance) { return(ArcType.StraightCorner); } else { return(Vector3.Dot(normal_for_left, rightward_for_right) < Precision.tolerance ? ArcType.ConvexCorner : ArcType.ConcaveCorner); } }
public void derail(float x_velocity, float y_velocity) { if (observer.exists && observer.data.colliding()) { BlockCollision collision = observer.data.collisions()[0]; collision.geometry_visitor.move_position(0, transform.scale / 2 * (1 + 1e-3f)); // extrude the player so they do not accidentally re-collide (immediately) // FIXME: magic number, move to Precision.* x_velocity += horizontal_velocity; //y_velocity += vertical_velocity; planetaria_transform.position = collision.geometry_visitor.position(); Vector3 normal = collision.geometry_visitor.normal(); Vector3 right = Bearing.right(planetaria_transform.position, normal); velocity = right * x_velocity + normal * y_velocity; Debug.DrawRay(planetaria_transform.position, velocity, Color.yellow, 1f); acceleration = get_acceleration(); // TODO: accelerate vertically observer.data.clear_block_collision(); observer = new optional <CollisionObserver>(); } }
public bool collide(BlockCollision collision, CollisionObserver observer) { if (this.observer.exists) { this.observer.data.clear_block_collision(); } aerial_move(-collision.overshoot); // this only (truly) works with perpendicular vectors? this.observer = observer; this.collision = collision; horizontal_velocity = Vector3.Dot(velocity, Bearing.right(planetaria_transform.position, collision.geometry_visitor.normal())); vertical_velocity = Vector3.Dot(velocity, collision.geometry_visitor.normal()); if (vertical_velocity < 0) { vertical_velocity *= -collision.elasticity; } grounded_accelerate(0); return(this.observer.exists); }
/// <summary> /// Inspector (Cache Mutator) - Updates the cache so that spherical rectangle calculations avoid recomputing old values. /// </summary> /// <param name="canvas">A Rect (measuring radians) representing the start and stop angles relative to Quaternion.identity. X/Y Range: (-2PI, +2PI).</param> public static void cache_spherical_rectangle(Rect canvas) { if (cached_canvas != canvas) { Vector3 lower_left = intersection(canvas.xMin, canvas.yMin); Vector3 lower_center = intersection(canvas.center.x, canvas.yMin); Vector3 lower_right = intersection(canvas.xMax, canvas.yMin); Vector3 middle_left = intersection(canvas.xMin, canvas.center.y); Vector3 middle_center = intersection(canvas.center.x, canvas.center.y); Vector3 middle_right = intersection(canvas.xMax, canvas.center.y); Vector3 upper_left = intersection(canvas.xMin, canvas.yMax); Vector3 upper_center = intersection(canvas.center.x, canvas.yMax); Vector3 upper_right = intersection(canvas.xMax, canvas.yMax); Arc biangle_segment1 = ArcFactory.curve(upper_center, upper_right, -upper_center); Arc biangle_segment2 = ArcFactory.curve(lower_center, lower_right, -lower_center); cached_left_biangle_focus = PlanetariaIntersection.arc_arc_intersection(biangle_segment1, biangle_segment2, 0).data; cached_left_positive_partition = Bearing.attractor(cached_left_biangle_focus, middle_left); // used for a dot product to determine if the angle applied for UV is +/- if (Vector3.Dot(cached_left_positive_partition, middle_center) >= 0) { cached_left_start_angle = Vector3.Angle(cached_left_biangle_focus, middle_center) * Mathf.Deg2Rad; cached_left_end_angle = Vector3.Angle(cached_left_biangle_focus, middle_left) * Mathf.Deg2Rad; } else { cached_left_start_angle = Vector3.Angle(-cached_left_biangle_focus, middle_center) * Mathf.Deg2Rad + Mathf.PI; cached_left_end_angle = Vector3.Angle(-cached_left_biangle_focus, middle_left) * Mathf.Deg2Rad + Mathf.PI; } biangle_segment1 = ArcFactory.curve(upper_center, upper_left, -upper_center); biangle_segment2 = ArcFactory.curve(lower_center, lower_left, -lower_center); cached_right_biangle_focus = PlanetariaIntersection.arc_arc_intersection(biangle_segment1, biangle_segment2, 0).data; cached_right_positive_partition = Bearing.attractor(cached_right_biangle_focus, middle_right); // used for a dot product to determine if the angle applied for UV is +/- if (Vector3.Dot(cached_right_positive_partition, middle_center) >= 0) { cached_right_start_angle = Vector3.Angle(cached_right_biangle_focus, middle_center) * Mathf.Deg2Rad; cached_right_end_angle = Vector3.Angle(cached_right_biangle_focus, middle_right) * Mathf.Deg2Rad; } else { cached_right_start_angle = Vector3.Angle(-cached_right_biangle_focus, middle_center) * Mathf.Deg2Rad + Mathf.PI; cached_right_end_angle = Vector3.Angle(-cached_right_biangle_focus, middle_right) * Mathf.Deg2Rad + Mathf.PI; } biangle_segment1 = ArcFactory.curve(middle_left, upper_left, -middle_left); biangle_segment2 = ArcFactory.curve(middle_right, upper_right, -middle_right); cached_lower_biangle_focus = PlanetariaIntersection.arc_arc_intersection(biangle_segment1, biangle_segment2, 0).data; cached_lower_positive_partition = Bearing.attractor(cached_lower_biangle_focus, lower_center); // used for a dot product to determine if the angle applied for UV is +/- if (Vector3.Dot(cached_lower_positive_partition, middle_center) >= 0) { cached_lower_start_angle = Vector3.Angle(cached_lower_biangle_focus, middle_center) * Mathf.Deg2Rad; cached_lower_end_angle = Vector3.Angle(cached_lower_biangle_focus, lower_center) * Mathf.Deg2Rad; } else { cached_lower_start_angle = Vector3.Angle(-cached_lower_biangle_focus, middle_center) * Mathf.Deg2Rad + Mathf.PI; cached_lower_end_angle = Vector3.Angle(-cached_lower_biangle_focus, lower_center) * Mathf.Deg2Rad + Mathf.PI; } biangle_segment1 = ArcFactory.curve(middle_left, lower_left, -middle_left); biangle_segment2 = ArcFactory.curve(middle_right, lower_right, -middle_right); cached_upper_biangle_focus = PlanetariaIntersection.arc_arc_intersection(biangle_segment1, biangle_segment2, 0).data; cached_upper_positive_partition = Bearing.attractor(cached_upper_biangle_focus, upper_center); // used for a dot product to determine if the angle applied for UV is +/- if (Vector3.Dot(cached_upper_positive_partition, middle_center) >= 0) { cached_upper_start_angle = Vector3.Angle(cached_upper_biangle_focus, middle_center) * Mathf.Deg2Rad; cached_upper_end_angle = Vector3.Angle(cached_upper_biangle_focus, upper_center) * Mathf.Deg2Rad; } else { cached_upper_start_angle = Vector3.Angle(-cached_upper_biangle_focus, middle_center) * Mathf.Deg2Rad + Mathf.PI; cached_upper_end_angle = Vector3.Angle(-cached_upper_biangle_focus, upper_center) * Mathf.Deg2Rad + Mathf.PI; } cached_north_hemisphere = Bearing.attractor(middle_center, upper_center); cached_east_hemisphere = Bearing.attractor(middle_center, middle_right); cached_canvas = canvas; } }
public Vector3 get_acceleration() { return(Bearing.attractor(get_position(), gravity.normalized) * gravity.magnitude); }