public static Vector3[] valid_arc_intersections(Arc arc, Vector3[] intersections, // TODO: research and development Quaternion orientation, optional <float> max_angle = new optional <float>()) { if (!max_angle.exists) { max_angle = arc.angle(); } Vector3[] results = new Vector3[0]; for (int intersection_index = 0; intersection_index < intersections.Length; ++intersection_index) { Vector3 intersection_point = intersections[intersection_index]; if (orientation != Quaternion.identity) { Quaternion arc_to_world = orientation; Quaternion world_to_arc = Quaternion.Inverse(arc_to_world); intersection_point = world_to_arc * intersection_point; } Vector3 arc_left = arc.position(-max_angle.data / 2); Vector3 arc_center = arc.position(0); Vector3 arc_right = arc.position(+max_angle.data / 2); Vector3 boundary_midpoint = (arc_left + arc_right) / 2; Plane arc_validator = new Plane(arc_center, boundary_midpoint); if (arc_validator.GetSide(intersection_point)) { Array.Resize(ref results, results.Length + 1); results[results.Length - 1] = intersections[intersection_index]; } } return(results); }
/// <summary> /// Mutator (Operating System level) - Writes (or overwrites!) the file at location "file" with the string "text_contents". /// </summary> /// <param name="file">The relative file path starting in the Unity directory (e.g. "Assets/important_file.txt"). Note: will be overwritten.</param> /// <param name="text_contents">The contents that will be placed in the file (overwrites file).</param> /// <param name="add_global_unique_identifier">Adds "_[0-9a-f]{32}" before file extension (last dot) in "file".</param> public static optional <TextAsset> write_file(string file, string text_contents, bool add_global_unique_identifier) { using (StreamWriter writer = new StreamWriter(file, false)) { string suffix = ""; writer.Write(text_contents); if (add_global_unique_identifier) { writer.Dispose(); UnityEditor.AssetDatabase.Refresh(); string global_unique_identifier = text_contents.GetHashCode().ToString("X"); Debug.Log("Creating " + global_unique_identifier); suffix = "_" + global_unique_identifier; optional <string> name = Miscellaneous.inner_text(file, "/", "."); if (name.exists) { UnityEditor.AssetDatabase.RenameAsset(file, name.data + suffix); // FIXME: INVESTIGATE: why does optional<string> + string work? (for safety reasons, it shouldn't) } else { Debug.Log("Critical Error"); } } UnityEditor.AssetDatabase.Refresh(); optional <string> resource = Miscellaneous.inner_text(file, "/Resources/", "."); if (resource.exists) { resource = resource.data + suffix; return(Resources.Load <TextAsset>(resource.data)); } return(new optional <TextAsset>()); } }
private void initialize_pole_light(optional <float> angle = new optional <float>()) { internal_light.type = LightType.Spot; internal_light.spotAngle = (range * 2) * Mathf.Rad2Deg; internal_cuculoris = create_pole_texture(internal_light.spotAngle); cuculoris.apply_to(ref internal_cuculoris, angle.exists ? angle.data : 2 * Mathf.PI); internal_light.cookie = internal_cuculoris; internal_transform.position = Vector3.zero; internal_transform.rotation = Quaternion.identity; }
/// <summary> /// Mutator - Gets the attached PlanetariaComponent if it exists; otherwise it adds and returns it. /// </summary> /// <typeparam name="Subtype">The type of the PlanetariaComponent to be fetched.</typeparam> /// <returns>The found or newly added PlanetariaComponent.</returns> public Subtype GetOrAddComponent <Subtype>() where Subtype : PlanetariaComponent { optional <Subtype> result = GetComponent <Subtype>(); if (!result.exists) { result = AddComponent <Subtype>(); } return(result.data); }
private static LevelCreatorEditor.CreateShape escape() { // Escape: close the shape so that it meets with the original point (using original point for slope) if (temporary_arc.exists) { temporary_arc.data.close_shape(); temporary_arc = new optional <ArcBuilder>(); } return(LevelCreatorEditor.draw_initialize); }
/// <summary> /// Mutator - Gets the attached Component if it exists; otherwise it adds and returns it. /// </summary> /// <typeparam name="Subtype">The type of the Component to be fetched.</typeparam> /// <param name="self">Calling object (explicit)</param> /// <returns>The found or newly added Component.</returns> public static Subtype GetOrAddComponent <Subtype>(Component self) where Subtype : Component { optional <Subtype> result = self.GetComponent <Subtype>(); if (!result.exists) { result = self.gameObject.AddComponent <Subtype>(); } return(result.data); }
public void move_position(float delta_length, optional <float> extrusion = new optional <float>()) // CONSIDER: combine move_position/set_position? { if (extrusion.exists) { last_extrusion = extrusion.data; initialize(); } float delta_angle = delta_length * (arc_angle / arc_length); set_position(angular_position + delta_angle); }
public static optional <Texture2D> fetch_image(string image_file) { optional <Texture2D> texture = new optional <Texture2D>(); if (File.Exists(image_file)) { byte[] raw_file_binary = File.ReadAllBytes(image_file); texture = new Texture2D(0, 0); texture.data.LoadImage(raw_file_binary); } return(texture); }
private void initialize_camera(optional <Camera> internal_camera, Rect screen, int draw_order) { if (internal_camera.exists) { Camera camera = internal_camera.data; camera.rect = screen; camera.depth = draw_order; camera.useOcclusionCulling = false; camera.nearClipPlane = near_clip_plane; camera.farClipPlane = far_clip_plane; camera.stereoSeparation = 0; camera.stereoConvergence = 0.01f; } }
/// <summary> /// Inspector - Draw an arc with lines only (basic) /// </summary> /// <param name="arc">The arc that will be rendered.</param> /// <param name="distance">The distance of the arc, negative or positive (overrides actual distance).</param> public static void draw_simple_arc(Arc arc, optional <float> distance = new optional <float>()) { float start_angle = -arc.half_angle; float angle = distance.exists ? distance.data : arc.angle(); int segments = 50; for (int segment = 1; segment <= segments; ++segment) { float end_angle = -arc.half_angle + segment / (float)segments * angle; Debug.DrawLine(arc.position(start_angle), arc.position(end_angle), Color.yellow, 5f); start_angle = end_angle; } }
public override bool Equals(System.Object other_object) // FIXME: { bool equal_type = other_object is optional <Type>; if (!equal_type) { return(false); } optional <Type> other = (optional <Type>)other_object; bool inequal_existance = (this.exists != other.exists); bool inequal_value = (this.exists && other.exists && !this.data.Equals(other.data)); bool inequal = inequal_existance || inequal_value; return(!inequal); }
private void OnTriggerStay(Collider collider) { optional <SphereCollider> sphere_collider = collider as SphereCollider; if (!sphere_collider.exists) { Debug.LogError("This should never happen"); return; } optional <PlanetariaCollider> other_collider = PlanetariaCache.collider_fetch(sphere_collider.data); if (!other_collider.exists) { Debug.LogError("This should never happen"); return; } Quaternion shift_from_self_to_other = other_collider.data.internal_transform.rotation; if (this.internal_transform.rotation != Quaternion.identity) // Only shift orientation when necessary { // TODO: verify the order of operations is correct (and logic itself) shift_from_self_to_other = Quaternion.Inverse(this.internal_transform.rotation) * shift_from_self_to_other; } if (other_collider.data.is_field) // field collision { if (this.shape.field_collision(other_collider.data.shape, shift_from_self_to_other)) { observer.potential_field_collision(other_collider.data); // TODO: augment field (like Unity triggers) works on both the sender and receiver. } } else // block collision { foreach (Arc intersection in this.shape.block_collision(other_collider.data.shape, shift_from_self_to_other)) { Vector3 position = planetaria_transform.position; if (other_collider.data.gameObject.internal_game_object.transform.rotation != Quaternion.identity) // Only shift orientation when necessary { position = Quaternion.Inverse(other_collider.data.gameObject.internal_game_object.transform.rotation) * position; } if (intersection.contains(position, planetaria_transform.scale / 2)) { observer.potential_block_collision(intersection, other_collider.data); // block collisions are handled in OnCollisionStay(): notification stage } } } }
public static optional <SphericalCirclePlanetarium> load(string file_name, float radius) { optional <Material> material = WorldPlanetarium.load_material(file_name); if (!material.exists) { return(new optional <SphericalCirclePlanetarium>()); } SphericalCirclePlanetarium result = new SphericalCirclePlanetarium(); result.material = material.data; result.texture = (Texture2D)WorldPlanetarium.load_texture(file_name); result.material.SetTexture("_MainTex", result.texture); result.radius_variable = radius; return(result); }
public static optional <OctahedronPlanetarium> load(string file_name) { optional <Material> material = WorldPlanetarium.load_material(file_name); if (!material.exists) { return(new optional <OctahedronPlanetarium>()); } Texture2D texture = (Texture2D)WorldPlanetarium.load_texture(file_name); OctahedronPlanetarium result = new OctahedronPlanetarium(texture.width); result.material = material.data; result.texture = texture; result.material.SetTexture("_MainTex", result.texture); return(result); }
public bool is_self_intersecting() { List <Arc> edges = generate_edges(); for (int left = 0; left < edges.Count; ++left) { for (int right = left + 1; right < edges.Count; ++right) { optional <Vector3> intersection = PlanetariaIntersection.arc_arc_intersection(edges[left], edges[right], 0); if (intersection.exists) { return(true); } } } return(false); }
public static optional <CubePlanetarium> load(string file_name) { optional <Material> material = WorldPlanetarium.load_material(file_name); if (!material.exists) { return(new optional <CubePlanetarium>()); } int size = material.data.GetTexture(directions[0]).width; CubePlanetarium result = new CubePlanetarium(size); result.material = material.data; for (int face = 0; face < directions.Length; ++face) { Texture2D texture = (Texture2D)material.data.GetTexture(directions[face]); result.textures[face] = texture; } return(result); }
/// <summary> /// Mutator - MouseDown finalizes equilateral shape. /// </summary> /// <returns>The next mode for the state machine.</returns> public static LevelCreatorEditor.CreateShape draw_equilateral(bool force_quit = false) { if (force_quit) { return(escape()); } builder.data.set_edge(LevelCreatorEditor.get_mouse_position()); // MouseUp: create first vertex of equilateral shape if (Event.current.type == EventType.MouseUp && Event.current.button == 0) { builder.data.close_shape(); builder = new optional <EquilateralBuilder>(); return(draw_center); } return(draw_equilateral); }
/// <summary> /// Mutator - Gets the designated object from the root of the scene if it exists; otherwise it creates and returns it. /// </summary> /// <param name="name">The name of the object (without double leading underscores i.e. "__").</param> /// <param name="hidden_internal">Whether the GameObject should be hidden unless debugging.</param> /// <returns>The found or newly added object from the root of the scene.</returns> public static GameObject GetOrAddObject(string name, bool hidden_internal = true) { if (hidden_internal) { name = "__" + name; } optional <GameObject> game_object = GameObject.Find("/" + name); if (!game_object.exists) { game_object = new GameObject(name); } #if UNITY_EDITOR if (hidden_internal && !EditorGlobal.self.show_inspector) { game_object.data.hideFlags = (HideFlags.HideInHierarchy | HideFlags.HideInInspector); } #endif return(game_object.data); }
public void potential_block_collision(Arc arc, PlanetariaCollider collider) { if (planetaria_rigidbody.exists) { if (current_collisions.Count == 0 || current_collisions[0].other != collider) { optional <BlockCollision> collision = BlockCollision.block_collision(this, arc, collider, planetaria_transformation, planetaria_rigidbody.data); if (collision.exists) { if (planetaria_rigidbody.exists) { if (planetaria_rigidbody.data.collide(collision.data, this)) { collision_candidates.Add(collision.data); } } } } } }
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>(); } }
private void initialize() { arc_angle = arc_visitor.arc.angle(); float floor_length = arc_visitor.arc.length(); // edge case float ceiling_length = arc_visitor.arc.length(2 * offset); // corner case arc_length = Mathf.Max(floor_length, ceiling_length); // use longer distance to make movement feel consistent left_angle_boundary = -arc_angle / 2; if (concave(arc_visitor[-1], offset)) // set left boundary { optional <Vector3> intersection = PlanetariaIntersection.arc_arc_intersection(arc_visitor[0], arc_visitor[-2], offset); left_angle_boundary = arc_visitor.arc.position_to_angle(intersection.data); } right_angle_boundary = +arc_angle / 2; if (concave(arc_visitor[+1], offset)) // set right boundary { optional <Vector3> intersection = PlanetariaIntersection.arc_arc_intersection(arc_visitor[0], arc_visitor[+2], offset); right_angle_boundary = arc_visitor.arc.position_to_angle(intersection.data); } }
/// <summary> /// Mutator - Gets the attached child by its name if it exists; otherwise it adds and returns it. /// </summary> /// <param name="self">Calling object - extension method (implicit).</param> /// <param name="name">The name of the object (without double leading underscores i.e. "__").</param> /// <param name="hidden_internal">Whether the GameObject should be hidden unless debugging.</param> /// <returns>The found or newly added child with given name.</returns> public static GameObject GetOrAddChild(this Component self, string name, bool hidden_internal = true) // TODO: should this return PlanetariaGameObject; this is an inadvertently exposed API, how should I fix this? Likely by making this a non-extension { if (hidden_internal) { name = "__" + name; } optional <Transform> child = self.transform.Find(name); if (!child.exists) { GameObject child_object = new GameObject(name); child_object.transform.parent = self.transform; child_object.transform.localPosition = Vector3.zero; // Ensure all children are on the same planetarium as their parent child = child_object.transform; child_object.layer = self.gameObject.layer; } #if UNITY_EDITOR if (hidden_internal && EditorGlobal.self.show_inspector) { child.data.hideFlags = (HideFlags.HideInHierarchy | HideFlags.HideInInspector); } #endif return(child.data.gameObject); }
/// <summary> /// Inspector/Constructor - Creates a copy of the shape then sets closed=true /// </summary> /// <returns>A closed shape mirroring all properties of original but with closed=true.</returns> public void close(optional <Vector3> slope = new optional <Vector3>(), AppendMode permanence = AppendMode.OverwriteWithPermanent) { if (permanence == AppendMode.OverwriteWithEphemeral || permanence == AppendMode.OverwriteWithPermanent) { serialized_arc_list.RemoveRange(serialized_arc_list.Count - ephemeral_arcs, ephemeral_arcs); ephemeral_arcs = 0; } // Add last edge! (if not already closed and Dot of last/first point is != 1) if (!closed()) { Arc first_arc = serialized_arc_list[0]; Arc last_arc = serialized_arc_list[serialized_arc_list.Count - 1]; if (!slope.exists) { slope = first_arc.begin(); } append(ArcFactory.curve(last_arc.end(), slope.data, first_arc.begin()), permanence); } initialize(); // TODO: if field, make this a convex_hull() // TODO: add convex property }
public static Vector3 snap(Vector3 position, bool v_pressed) { if (Event.current.control && Event.current.shift) // Edge snap on Control + Shift + click { optional <Vector3> edge_snap = closest_heuristic(ArcUtility.snap_to_edge, position); if (edge_snap.exists) { return(edge_snap.data); } } else if (EditorGlobal.self.v_pressed) // Vertex snap on V + click { optional <Vector3> vertex_snap = closest_heuristic(ArcUtility.snap_to_vertex, position); if (vertex_snap.exists) { return(vertex_snap.data); } } else if (Event.current.shift) // Grid snap on Shift + click { return(grid_snap(position)); } return(position); // return the input position (if all else fails). }
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); }
private void OnGUI() { if (GUILayout.Button("Image(s) to convert")) { from_file_name = EditorUtility.OpenFilePanel("PNG to convert", "Assets/Planetaria/ExampleProjects/DébrisNoirs/Art/Textures", "mat"); // TODO: multiple types from_file_name = from_file_name.Substring(0, from_file_name.Length - 4); // this is an editor tool, so the following is fine: int clip_index = from_file_name.IndexOf("Assets/"); from_file_name = from_file_name.Substring(clip_index); } if (GUILayout.Button("Generated PNG(s) filename")) { to_file_name = EditorUtility.SaveFilePanel("Generated PNG filename", "Assets/Planetaria/ExampleProjects/DébrisNoirs/Art/Textures", "output_file", "png"); // TODO: multiple types and use output in conversion // FIXME: HACK: trying to make deadlines to_file_name = to_file_name.Substring(0, to_file_name.Length - 4); // this is an editor tool, so the following is fine: int clip_index = to_file_name.IndexOf("Assets/"); to_file_name = to_file_name.Substring(clip_index); } GUILayout.BeginHorizontal(); from_shape = (Shape)EditorGUILayout.EnumPopup("Current shape format", from_shape); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); to_shape = (Shape)EditorGUILayout.EnumPopup("Target shape format", to_shape); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); resolution = EditorGUILayout.IntField("Pixel resolution", resolution); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); sample_rate = EditorGUILayout.IntField("Sample rate", sample_rate); GUILayout.EndHorizontal(); switch (from_shape) { case Shape.SphericalRectangle: GUILayout.BeginHorizontal(); canvas = EditorGUILayout.RectField("Spherical Rectangle", canvas); GUILayout.EndHorizontal(); break; case Shape.SphericalCircle: GUILayout.BeginHorizontal(); radius = EditorGUILayout.FloatField("Spherical Circle radius", radius); GUILayout.EndHorizontal(); break; } if (GUILayout.Button("Convert")) { WorldPlanetarium from; WorldPlanetarium to; switch (from_shape) { case Shape.Cube: optional <CubePlanetarium> cubemap = CubePlanetarium.load(from_file_name); Debug.Assert(cubemap.exists); from = cubemap.data; break; case Shape.Octahedron: optional <OctahedronPlanetarium> octahedron = OctahedronPlanetarium.load(from_file_name); Debug.Assert(octahedron.exists); from = octahedron.data; break; case Shape.SphericalRectangle: optional <SphericalRectanglePlanetarium> rectangle = SphericalRectanglePlanetarium.load(from_file_name, canvas); Debug.Assert(rectangle.exists); from = rectangle.data; break; case Shape.SphericalCircle: default: // FIXME: optional <SphericalCirclePlanetarium> circle = SphericalCirclePlanetarium.load(from_file_name, radius); Debug.Assert(circle.exists); from = circle.data; break; } switch (to_shape) { case Shape.Cube: to = new CubePlanetarium(resolution); to.convert(from); to.save(to_file_name); break; case Shape.Octahedron: to = new OctahedronPlanetarium(resolution); to.convert(from); to.save(to_file_name); break; } } }
private static LevelCreatorEditor.CreateShape escape() { builder.data.close_shape(); builder = new optional <EquilateralBuilder>(); return(LevelCreatorEditor.draw_initialize); }
public static optional <BlockCollision> block_collision(CollisionObserver observer, Arc arc, PlanetariaCollider collider, PlanetariaTransform transformation, PlanetariaRigidbody rigidbody) { optional <ArcVisitor> arc_visitor = collider.shape.arc_visitor(arc); if (!arc_visitor.exists) { Debug.LogError("This should never happen"); return(new optional <BlockCollision>()); } Quaternion block_to_world = collider.gameObject.internal_game_object.transform.rotation; Quaternion world_to_block = Quaternion.Inverse(block_to_world); Vector3 last_position = world_to_block * rigidbody.get_previous_position(); Vector3 current_position = world_to_block * rigidbody.get_position(); float extrusion = transformation.scale / 2; optional <Vector3> intersection_point = PlanetariaIntersection.arc_path_intersection(arc, last_position, current_position, extrusion); if (!intersection_point.exists) // theoretically only happens with moving objects for discrete collision checks { // these functions are general inverses of one another, but also serve to constrain/normalize the position to the arc path. float intersection_angle = arc.position_to_angle(current_position); if (Mathf.Abs(intersection_angle) <= arc.angle() / 2) // if the intersection is valid { intersection_point = arc.position(intersection_angle); // set the collision to the extruded collision point } } if (!intersection_point.exists) { Debug.LogError("Research why this happened."); return(new optional <BlockCollision>()); } BlockCollision result = new BlockCollision(); float angle = arc.position_to_angle(intersection_point.data); result.geometry_visitor = ShapeVisitor.geometry_visitor(arc_visitor.data, angle, extrusion, collider.gameObject.internal_game_object.transform); intersection_point.data = block_to_world * intersection_point.data; result.distance = Vector3.Angle(intersection_point.data, rigidbody.get_previous_position()) * Mathf.Deg2Rad; result.overshoot = Vector3.Angle(intersection_point.data, rigidbody.get_position()) * Mathf.Deg2Rad; result.observer = observer; result.self = observer.collider(); result.other = collider; PlanetariaPhysicMaterial self = result.self.material; PlanetariaPhysicMaterial other = result.other.material; result.elasticity = PlanetariaPhysics.blend( self.elasticity, self.elasticity_combine, other.elasticity, other.elasticity_combine); result.friction = PlanetariaPhysics.blend( self.friction, self.friction_combine, other.friction, other.friction_combine); result.magnetism = -(self.magnetism - other.magnetism * self.induced_magnetism_multiplier) * (other.magnetism - self.magnetism * other.induced_magnetism_multiplier); return(result); }
protected override void OnDestroy() { cleanup(); shutter = new optional <PlanetariaCameraShutter>(); // deregisters from blink_event }