void Update() { // Make sure the events have loaded if (!Controller.obj.levelEventController.hasLoaded) { return; } // Update frame and states if (ObjData.CurrentAnimation != null && !Settings.LoadFromMemory) { ObjData.UpdateFrame(); } UpdateTimer += Time.deltaTime; // Only update 60 frames per second, as that's the framerate for the game if (!(UpdateTimer > 1.0f / 60.0f)) { return; } UpdateTimer = 0.0f; // Update object ObjData.OnUpdate(); defaultRenderer.enabled = true; bool frameUpdated = false; bool collisionUpdated = false; if (ShowCollision != CurrentShowCollision) { CurrentShowCollision = ShowCollision; collisionUpdated = true; } if (ObjData.ShouldUpdateAnimation()) { CurrentFrame = -1; CurrentShowCollision = ShowCollision; frameUpdated = true; // Clear old arrays ClearSprites(animSpriteRenderers); ClearSprites(animCollisionRenderers); // If animation is null, show gizmo instead if (ObjData.CurrentAnimation != null) { // Reset the current frame ObjData.ResetFrame(); // Get the amount of sprite layers per frame var spritesLength = ObjData.CurrentAnimation.Frames.Max(f => f.SpriteLayers.Length); // Get the amount of collision layers per frame var collisionLength = ObjData.CurrentAnimation.Frames.Max(f => f.CollisionLayers?.Length ?? 0); // Create arrays animSpriteRenderers = new SpriteRenderer[spritesLength]; animCollisionRenderers = new SpriteRenderer[collisionLength]; bool is3D = ObjData is Unity_Object_3D && LevelEditorData.Level.IsometricData != null; // Populate sprites for (int i = 0; i < spritesLength; i++) { // Instantiate prefab SpriteRenderer newRenderer = Instantiate(prefabSpritepart, transform).GetComponent <SpriteRenderer>(); newRenderer.sortingOrder = is3D ? 0 : (Layer + i); newRenderer.sortingLayerName = ObjData.MapLayer == 2 ? "Object Sprites Back" : "Object Sprites"; if (is3D) { newRenderer.gameObject.layer = LayerMask.NameToLayer("3D Object"); } newRenderer.transform.localPosition = new Vector3(0, 0, is3D ? 0 : (spritesLength - i)); newRenderer.transform.localRotation = Quaternion.identity; newRenderer.transform.localScale = Vector3.one * ObjData.Scale; // Add to list animSpriteRenderers[i] = newRenderer; } // Populate collision boxes for (int i = 0; i < collisionLength; i++) { // Instantiate prefab var newRenderer = Instantiate(prefabBox, transform).GetComponent <SpriteRenderer>(); newRenderer.sortingOrder = is3D ? 0 : (Layer + spritesLength + i); if (is3D) { newRenderer.gameObject.layer = LayerMask.NameToLayer("3D Object"); } newRenderer.transform.localRotation = Quaternion.identity; // Add to list animCollisionRenderers[i] = newRenderer; } } } // Get the current animation var anim = ObjData.CurrentAnimation; // bool defaultRendererEnabled = ShowGizmo; if (defaultRenderer.gameObject.activeSelf != defaultRendererEnabled) { defaultRenderer.gameObject.SetActive(defaultRendererEnabled); } UpdatePosition(); // Don't move link cube if it's part of a link if (ObjData.EditorLinkGroup != 0) { linkCube.position = linkCubeLockPosition; } else { linkCubeLockPosition = linkCube.position; } var isVisible = IsVisible; // Update sprite parts in the animation if (anim != null) { // Get properties var frame = ObjData.AnimationFrame; if (CurrentFrame != frame) { frameUpdated = true; CurrentFrame = frame; } var sprites = ObjData.Sprites; var pivot = ObjData.Pivot; var mirroredX = ObjData.FlipHorizontally; var mirroredY = ObjData.FlipVertically; if (CurrentMirrorX != mirroredX || CurrentMirrorY != mirroredY) { frameUpdated = true; CurrentMirrorX = mirroredX; CurrentMirrorY = mirroredY; } if (frame >= anim.Frames.Length) { throw new Exception($"Invalid frame index {frame} with length {anim.Frames.Length} for obj {Index}. {ObjData.PrimaryName}-{ObjData.SecondaryName}"); } // Update sprites for (int i = 0; i < anim.Frames[frame].SpriteLayers.Length; i++) { var layer = anim.Frames[frame].SpriteLayers[i]; // Get the sprite index var spriteIndex = layer.ImageIndex; // Change it if the event is multi-colored (Rayman 1 only) if (ObjData is Unity_Object_R1 objr1 && objr1.EventData.Type.IsMultiColored()) { spriteIndex += ((sprites.Count / 6) * objr1.EventData.HitPoints); } if (animSpriteRenderers.Length <= i) { continue; } if (frameUpdated) { // Set the sprite, skipping sprites which are out of bounds if (spriteIndex >= sprites.Count && (LevelEditorData.CurrentSettings.EngineVersion != EngineVersion.R2_PS1 || spriteIndex < 0xFFF)) { print($"Sprite index too high: {ObjData.PrimaryName}|{ObjData.SecondaryName}: {spriteIndex} >= {sprites.Count}"); } animSpriteRenderers[i].sprite = spriteIndex >= sprites.Count ? null : sprites[spriteIndex]; var layerMirroredX = layer.IsFlippedHorizontally; var layerMirroredY = layer.IsFlippedVertically; // Indicate if the sprites should be flipped animSpriteRenderers[i].flipX = (layerMirroredX ^ mirroredX); animSpriteRenderers[i].flipY = (layerMirroredY ^ mirroredY); // Get the dimensions var w = animSpriteRenderers[i].sprite == null ? 0 : animSpriteRenderers[i].sprite.textureRect.width; var h = animSpriteRenderers[i].sprite == null ? 0 : animSpriteRenderers[i].sprite.textureRect.height; var xx = layer.XPosition + (layerMirroredX ? w : 0); var yy = -(layer.YPosition + (layerMirroredY ? h : 0)); // scale Vector2 pos = new Vector2( ((xx - pivot.x) * (mirroredX ? -1f : 1f) * ObjData.Scale + pivot.x) / (float)LevelEditorData.Level.PixelsPerUnit, ((yy - pivot.y) * (mirroredY ? -1f : 1f) * ObjData.Scale + pivot.y) / (float)LevelEditorData.Level.PixelsPerUnit); animSpriteRenderers[i].transform.localPosition = new Vector3(pos.x, pos.y, animSpriteRenderers[i].transform.localPosition.z); animSpriteRenderers[i].transform.localScale = Vector3.one * ObjData.Scale; animSpriteRenderers[i].transform.localRotation = Quaternion.Euler(0, 0, 0); // First transform based on layer properties if ((layer.Rotation.HasValue && layer.Rotation.Value != 0) || (layer.Scale.HasValue && layer.Scale.Value != Vector2.one)) { Vector3 transformOrigin = new Vector3( (((layer.TransformOriginX - pivot.x) * (mirroredX ? -1f : 1f) * ObjData.Scale + pivot.x) / (float)LevelEditorData.Level.PixelsPerUnit), ((-layer.TransformOriginY - pivot.y) * (mirroredY ? -1f : 1f) * ObjData.Scale + pivot.y) / (float)LevelEditorData.Level.PixelsPerUnit, animSpriteRenderers[i].transform.localPosition.z); // Scale first if (layer.Scale.HasValue && layer.Scale.Value != Vector2.one) { Vector3 scaleValue = new Vector3(layer.Scale.Value.x, layer.Scale.Value.y, 1f); animSpriteRenderers[i].transform.localScale = Vector3.Scale(Vector3.one * ObjData.Scale, scaleValue); Vector3 scaledPos = Vector3.Scale(animSpriteRenderers[i].transform.localPosition - transformOrigin, scaleValue); animSpriteRenderers[i].transform.localPosition = transformOrigin + scaledPos; } // Then rotate if (layer.Rotation.HasValue && layer.Rotation.Value != 0) { /*Quaternion rotation = Quaternion.Euler(0, 0, layer.Rotation * 180f);*/ //Vector3 rotationOrigin = Vector3.zero; animSpriteRenderers[i].transform.RotateAround(transform.TransformPoint(transformOrigin), new Vector3(0, 0, 1), layer.Rotation.Value * ((mirroredX ^ mirroredY) ? -1f : 1f)); /* Vector2 relativePos = pos - rotationOrigin; * Vector2 rotatedPos = rotation * relativePos; * prefabRenderers[i].transform.localRotation = rotation; * prefabRenderers[i].transform.localPosition = new Vector3(relativePos.x + rotatedPos.x, relativePos.y + rotatedPos.y, prefabRenderers[i].transform.localPosition.z);*/ } } // Then transform based on object properties if ((ObjData.Rotation.HasValue && ObjData.Rotation.Value != 0)) { Vector3 transformOrigin = new Vector3( pivot.x / (float)LevelEditorData.Level.PixelsPerUnit, pivot.y / (float)LevelEditorData.Level.PixelsPerUnit, animSpriteRenderers[i].transform.localPosition.z); // Then rotate if (ObjData.Rotation.HasValue && ObjData.Rotation.Value != 0) { animSpriteRenderers[i].transform.RotateAround(transform.TransformPoint(transformOrigin), new Vector3(0, 0, 1), ObjData.Rotation.Value * ((mirroredX ^ mirroredY) ? -1f : 1f)); } } } // Get visibility animSpriteRenderers[i].enabled = isVisible; animSpriteRenderers[i].color = ObjData.IsDisabled ? new Color(1, 1, 1, 0.5f) : Color.white; } if (frameUpdated) { // Remove unused sprites for (int i = anim.Frames[frame].SpriteLayers.Length; i < animSpriteRenderers.Length; i++) { animSpriteRenderers[i].sprite = null; animSpriteRenderers[i].enabled = false; } // Remove unused collision layers for (int i = anim.Frames[frame].CollisionLayers.Length; i < animCollisionRenderers.Length; i++) { animCollisionRenderers[i].sprite = null; animCollisionRenderers[i].enabled = false; } } if (frameUpdated || collisionUpdated) { // Update collision for (int i = 0; i < anim.Frames[frame].CollisionLayers.Length; i++) { SetCollisionBox(anim.Frames[frame].CollisionLayers[i], animCollisionRenderers[i], pivot); animCollisionRenderers[i].enabled = CurrentShowCollision; } } } if (ShowGizmo) { UpdateGizmoPosition(ObjData.ObjCollision, ObjData.Pivot); } if (CurrentShowCollision && (frameUpdated || collisionUpdated)) { // Update object collision var objCol = ObjData.ObjCollision; // Update new if ((objCollisionRenderers == null && objCol != null && objCol.Length > 0) || objCol?.Length != objCollisionRenderers?.Length) { // Clear old object collision array ClearSprites(objCollisionRenderers); if (objCol != null && objCol.Length > 0) { if (CurrentShowCollision) { objCollisionRenderers = new SpriteRenderer[objCol.Length]; bool is3D = ObjData is Unity_Object_3D && LevelEditorData.Level.IsometricData != null; // Instantiate prefabs for (int i = 0; i < objCol.Length; i++) { objCollisionRenderers[i] = Instantiate(prefabBox, transform).GetComponent <SpriteRenderer>(); objCollisionRenderers[i].sortingOrder = is3D ? 0 : Layer; objCollisionRenderers[i].transform.localPosition = new Vector3(0, 0, is3D ? 0.1f : (objCol.Length - i)); objCollisionRenderers[i].transform.localRotation = Quaternion.identity; objCollisionRenderers[i].transform.localScale = Vector3.one * ObjData.Scale; } } } else { objCollisionRenderers = null; } } // Update object collision boxes if (objCollisionRenderers != null) { for (var i = 0; i < objCollisionRenderers.Length; i++) { SetCollisionBox(objCol[i], objCollisionRenderers[i], ObjData.Pivot); objCollisionRenderers[i].enabled = CurrentShowCollision; } } } else if (!CurrentShowCollision) { if (objCollisionRenderers != null) { for (var i = 0; i < objCollisionRenderers.Length; i++) { objCollisionRenderers[i].enabled = false; } } } if (frameUpdated) { // Update the follow sprite line (Rayman 1 only) if (ObjData is Unity_Object_R1 r1 && anim != null) { var animLayer = anim.Frames[r1.AnimationFrame].SpriteLayers.ElementAtOrDefault(r1.EventData.FollowSprite); var imgDescr = r1.ObjManager.DES.ElementAtOrDefault(r1.DESIndex)?.Data?.ImageDescriptors.ElementAtOrDefault(animLayer?.ImageIndex ?? -1); followSpriteLine.localPosition = new Vector2( ((animLayer?.XPosition ?? 0) + (imgDescr?.HitBoxOffsetX ?? 0)) / (float)LevelEditorData.Level.PixelsPerUnit, -((animLayer?.YPosition ?? 0) + (imgDescr?.HitBoxOffsetY ?? 0)) / (float)LevelEditorData.Level.PixelsPerUnit - (r1.EventData.OffsetHY / (float)LevelEditorData.Level.PixelsPerUnit)); var w = (animSpriteRenderers.ElementAtOrDefault(r1.EventData.FollowSprite)?.sprite == null) ? 0 : imgDescr?.HitBoxWidth ?? 0; followSpriteLine.localScale = new Vector2(w, 1f); } } // Update the collider size for when selecting the events if (frameUpdated || collisionUpdated) { if (anim != null || objCollisionRenderers?.Any() == true) { var sprites = anim != null ? animSpriteRenderers : objCollisionRenderers; // Set box collider size to be the combination of all parts float leftX = 0, bottomY = 0, rightX = 0, topY = 0; float w = 1f; float h = 1f; float centerX = 0f; float centerY = 0f; bool first = true; bool hasSprites = false; foreach (SpriteRenderer part in sprites) { if (part.sprite == null) { continue; } hasSprites = true; Bounds b = part.bounds; if (boxCollider3D != null) { b = part.sprite?.bounds ?? b; var scl = part.transform.localScale; if (part.flipX) { scl.x = scl.x * -1; } if (part.flipY) { scl.y = scl.y * -1; } b = new Bounds((part.transform.localPosition + Vector3.Scale(b.center, scl)) * LevelEditorData.Level.PixelsPerUnit, Vector3.Scale(b.size, scl) * LevelEditorData.Level.PixelsPerUnit); } else { b = new Bounds(transform.InverseTransformPoint(b.center) * LevelEditorData.Level.PixelsPerUnit, transform.InverseTransformVector(b.size) * LevelEditorData.Level.PixelsPerUnit); } if (b.min.x < leftX || first) { leftX = b.min.x; } if (b.min.y < bottomY || first) { bottomY = b.min.y; } if (b.max.x > rightX || first) { rightX = b.max.x; } if (b.max.y > topY || first) { topY = b.max.y; } if (first) { first = false; } } if (hasSprites) { w = (rightX - leftX) / LevelEditorData.Level.PixelsPerUnit; h = (topY - bottomY) / LevelEditorData.Level.PixelsPerUnit; centerX = leftX / LevelEditorData.Level.PixelsPerUnit + w / 2f; centerY = topY / LevelEditorData.Level.PixelsPerUnit - h / 2f; w = Mathf.Abs(w); h = Mathf.Abs(h); if (boxCollider != null) { boxCollider.size = new Vector2(w, h); boxCollider.offset = new Vector2(centerX, centerY); } else if (boxCollider3D != null) { boxCollider3D.size = new Vector3(w, h, 0.1f); boxCollider3D.center = new Vector2(centerX, centerY); } } } else { SetGizmoBoxCollider(); } } if (ShowGizmo && anim == null && !CurrentShowCollision) { SetGizmoBoxCollider(); } // Update offset points if (anim != null) { var pivot = ObjData.Pivot; offsetCrossBX.localPosition = new Vector2(pivot.x / LevelEditorData.Level.PixelsPerUnit, (pivot.y / LevelEditorData.Level.PixelsPerUnit)); if (ObjData is Unity_Object_R1 r1bj) { int hy = -(r1bj.EventData.OffsetHY); if (r1bj.EventData.GetFollowEnabled(LevelEditorData.CurrentSettings)) { hy -= anim.Frames[r1bj.EventData.RuntimeCurrentAnimFrame].SpriteLayers.ElementAtOrDefault(r1bj.EventData.FollowSprite)?.YPosition ?? 0; } offsetCrossHY.localPosition = new Vector2(pivot.x / LevelEditorData.Level.PixelsPerUnit, hy / (float)LevelEditorData.Level.PixelsPerUnit); } else if (ObjData is Unity_Object_R2 r2bj) { var hy = -(r2bj.EventData.CollisionData?.OffsetHY ?? 0); offsetCrossHY.localPosition = new Vector2(pivot.x / LevelEditorData.Level.PixelsPerUnit, hy / (float)LevelEditorData.Level.PixelsPerUnit); } } if (PrevObjType != ObjData.Type) { PrevObjType = ObjData.Type; InitGizmo(); } bool enableBoxCollider = EnableBoxCollider; if (boxCollider != null) { // Update visibility boxCollider.enabled = enableBoxCollider; // Set new midpoint midpoint = new Vector3(transform.position.x + boxCollider.offset.x, transform.position.y + boxCollider.offset.y, 0); } else if (boxCollider3D != null) { // Update visibility boxCollider3D.enabled = enableBoxCollider; // Set new midpoint midpoint = transform.TransformPoint(boxCollider3D.center); } // Set link line to cube lineRend.SetPosition(0, midpoint); lineRend.SetPosition(1, linkCube.position); // Update link colors if (ObjData.EditorLinkGroup == 0) { lineRend.startColor = Controller.obj.levelEventController.linkColorDeactive; lineRend.endColor = Controller.obj.levelEventController.linkColorDeactive; linkCube.GetComponent <SpriteRenderer>().color = Controller.obj.levelEventController.linkColorDeactive; } else { lineRend.startColor = Controller.obj.levelEventController.linkColorActive; lineRend.endColor = Controller.obj.levelEventController.linkColorActive; linkCube.GetComponent <SpriteRenderer>().color = Controller.obj.levelEventController.linkColorActive; } // Set link visibility var showLinks = // Make sure the obj is visible isVisible && // Make sure links are set to show Settings.ShowLinks && // Only show active links on web !(Settings.HideUnusedLinks && ObjData.EditorLinkGroup == 0) && // Only show if available ObjData.CanBeLinkedToGroup; lineRend.enabled = showLinks; void SetGameObjectActive(GameObject gao, bool active) { if (gao.activeSelf != active) { gao.SetActive(active); } } SetGameObjectActive(linkCube.gameObject, showLinks); // Change the offsets visibility bool showOffsets = ShowOffsets; SetGameObjectActive(offsetOrigin.gameObject, showOffsets); SetGameObjectActive(offsetCrossBX.gameObject, showOffsets && offsetCrossBX.transform.position != Vector3.zero); SetGameObjectActive(offsetCrossHY.gameObject, showOffsets && (ObjData is Unity_Object_R1 || ObjData is Unity_Object_R2) && offsetCrossHY.transform.position != Vector3.zero); var engineVersion = LevelEditorData.CurrentSettings.EngineVersion; followSpriteLine.gameObject.SetActive( ShowCollision && ObjData is Unity_Object_R1 r1o && r1o.EventData.GetFollowEnabled(LevelEditorData.CurrentSettings) && !(engineVersion == EngineVersion.R1_PS1_JP || engineVersion == EngineVersion.R1_PS1_JPDemoVol3 || engineVersion == EngineVersion.R1_PS1_JPDemoVol6 || engineVersion == EngineVersion.R1_Saturn)); // Update one-way link lines if (oneWayLinkLines != null) { for (var i = 0; i < oneWayLinkLines.Length; i++) { oneWayLinkLines[i].enabled = (enableBoxCollider && Settings.ShowLinks && ObjData.CanBeLinked && connectedOneWayLinkLines[i]) || ForceShowOneWayLinks; } } HasInitialized = true; }
void Update() { // Make sure the events have loaded if (!Controller.obj.levelEventController.hasLoaded) { return; } // Update frame and states if (ObjData.CurrentAnimation != null && !Settings.LoadFromMemory) { ObjData.UpdateFrame(); } UpdateTimer += Time.deltaTime; // Only update 60 frames per second, as that's the framerate for the game if (!(UpdateTimer > 1.0f / 60.0f)) { return; } UpdateTimer = 0.0f; defautRenderer.enabled = true; bool frameUpdated = false; bool collisionUpdated = false; if (ShowCollision != CurrentShowCollision) { CurrentShowCollision = ShowCollision; collisionUpdated = true; } if (ObjData.ShouldUpdateAnimation()) { CurrentFrame = -1; CurrentShowCollision = ShowCollision; frameUpdated = true; // If animation is null, use default renderer ("E") if (ObjData.CurrentAnimation == null) { ClearSprites(prefabRenderers); ClearSprites(prefabRenderersCollision); } else { // Reset the current frame ObjData.ResetFrame(); // Get the amount of sprite layers per frame var spritesLength = ObjData.CurrentAnimation.Frames.Max(f => f.SpriteLayers.Length); // Get the amount of collision layers per frame var collisionLength = ObjData.CurrentAnimation.Frames.Max(f => f.CollisionLayers?.Length ?? 0); // Clear old arrays ClearSprites(prefabRenderers); ClearSprites(prefabRenderersCollision); // Create arrays prefabRenderers = new SpriteRenderer[spritesLength]; prefabRenderersCollision = new SpriteRenderer[collisionLength]; // Populate sprites for (int i = 0; i < spritesLength; i++) { // Instantiate prefab SpriteRenderer newRenderer = Instantiate(prefabSpritepart, transform).GetComponent <SpriteRenderer>(); newRenderer.sortingOrder = Layer + i; newRenderer.transform.localPosition = new Vector3(0, 0, spritesLength - i); newRenderer.transform.localRotation = Quaternion.identity; newRenderer.transform.localScale = Vector3.one * ObjData.Scale; // Add to list prefabRenderers[i] = newRenderer; } // Populate collision boxes for (int i = 0; i < collisionLength; i++) { // Instantiate prefab var newRenderer = Instantiate(prefabBox, transform).GetComponent <SpriteRenderer>(); newRenderer.sortingOrder = Layer + spritesLength + i; newRenderer.transform.localRotation = Quaternion.identity; // Add to list prefabRenderersCollision[i] = newRenderer; } } } // Get the current animation var anim = ObjData.CurrentAnimation; defautRenderer.enabled = ShowDefaultRenderer; UpdatePosition(); // Don't move link cube if it's part of a link if (ObjData.EditorLinkGroup != 0) { linkCube.position = linkCubeLockPosition; } else { linkCubeLockPosition = linkCube.position; } var isVisible = IsVisible; // Update sprite parts in the animation if (anim != null) { // Get properties var frame = ObjData.AnimationFrame; if (CurrentFrame != frame) { frameUpdated = true; CurrentFrame = frame; } var sprites = ObjData.Sprites; var pivot = ObjData.Pivot; var mirroredX = ObjData.FlipHorizontally; var mirroredY = ObjData.FlipVertically; if (frame >= anim.Frames.Length) { throw new Exception($"Invalid frame index {frame} with length {anim.Frames.Length} for obj {Index}. {ObjData.PrimaryName}-{ObjData.SecondaryName}"); } // Update sprites for (int i = 0; i < anim.Frames[frame].SpriteLayers.Length; i++) { var layer = anim.Frames[frame].SpriteLayers[i]; // Get the sprite index var spriteIndex = layer.ImageIndex; // Change it if the event is multi-colored (Rayman 1 only) if (ObjData is Unity_Object_R1 objr1 && objr1.EventData.Type.IsMultiColored()) { spriteIndex += ((sprites.Count / 6) * objr1.EventData.HitPoints); } if (prefabRenderers.Length <= i) { continue; } if (frameUpdated) { // Set the sprite, skipping sprites which are out of bounds if (spriteIndex >= sprites.Count && (LevelEditorData.CurrentSettings.EngineVersion != EngineVersion.R2_PS1 || spriteIndex < 0xFFF)) { print("Sprite index too high: " + ObjData.Name + ": " + spriteIndex + " >= " + sprites.Count); } prefabRenderers[i].sprite = spriteIndex >= sprites.Count ? null : sprites[spriteIndex]; var layerMirroredX = layer.IsFlippedHorizontally; var layerMirroredY = layer.IsFlippedVertically; // Indicate if the sprites should be flipped prefabRenderers[i].flipX = (layerMirroredX ^ mirroredX); prefabRenderers[i].flipY = (layerMirroredY ^ mirroredY); // Get the dimensions var w = prefabRenderers[i].sprite == null ? 0 : prefabRenderers[i].sprite.texture.width; var h = prefabRenderers[i].sprite == null ? 0 : prefabRenderers[i].sprite.texture.height; var xx = layer.XPosition + (layerMirroredX ? w : 0); var yy = -(layer.YPosition + (layerMirroredY ? h : 0)); // scale Vector2 pos = new Vector2( ((xx - pivot.x) * (mirroredX ? -1f : 1f) * ObjData.Scale + pivot.x) / (float)LevelEditorData.Level.PixelsPerUnit, ((yy - pivot.y) * (mirroredY ? -1f : 1f) * ObjData.Scale + pivot.y) / (float)LevelEditorData.Level.PixelsPerUnit); prefabRenderers[i].transform.localPosition = new Vector3(pos.x, pos.y, prefabRenderers[i].transform.localPosition.z); prefabRenderers[i].transform.localScale = Vector3.one * ObjData.Scale; prefabRenderers[i].transform.localRotation = Quaternion.Euler(0, 0, 0); if ((layer.Rotation.HasValue && layer.Rotation.Value != 0) || (layer.Scale.HasValue && layer.Scale.Value != Vector2.one)) { Vector3 transformOrigin = new Vector3( (((layer.TransformOriginX - pivot.x) * (mirroredX ? -1f : 1f) * ObjData.Scale + pivot.x) / (float)LevelEditorData.Level.PixelsPerUnit), ((-layer.TransformOriginY - pivot.y) * (mirroredY ? -1f : 1f) * ObjData.Scale + pivot.y) / (float)LevelEditorData.Level.PixelsPerUnit, prefabRenderers[i].transform.localPosition.z); // Scale first if (layer.Scale.HasValue && layer.Scale.Value != Vector2.one) { Vector3 scaleValue = new Vector3(layer.Scale.Value.x, layer.Scale.Value.y, 1f); prefabRenderers[i].transform.localScale = Vector3.Scale(Vector3.one * ObjData.Scale, scaleValue); Vector3 scaledPos = Vector3.Scale(prefabRenderers[i].transform.localPosition - transformOrigin, scaleValue); prefabRenderers[i].transform.localPosition = transformOrigin + scaledPos; } // Then rotate if (layer.Rotation.HasValue && layer.Rotation.Value != 0) { /*Quaternion rotation = Quaternion.Euler(0, 0, layer.Rotation * 180f);*/ //Vector3 rotationOrigin = Vector3.zero; prefabRenderers[i].transform.RotateAround(transform.TransformPoint(transformOrigin), new Vector3(0, 0, 1), layer.Rotation.Value * ((mirroredX ^ mirroredY) ? -1f : 1f)); /* Vector2 relativePos = pos - rotationOrigin; * Vector2 rotatedPos = rotation * relativePos; * prefabRenderers[i].transform.localRotation = rotation; * prefabRenderers[i].transform.localPosition = new Vector3(relativePos.x + rotatedPos.x, relativePos.y + rotatedPos.y, prefabRenderers[i].transform.localPosition.z);*/ } } } // Get visibility prefabRenderers[i].enabled = isVisible; prefabRenderers[i].color = ObjData.IsDisabled ? new Color(1, 1, 1, 0.5f) : Color.white; } if (frameUpdated) { // Remove unused sprites for (int i = anim.Frames[frame].SpriteLayers.Length; i < prefabRenderers.Length; i++) { prefabRenderers[i].sprite = null; prefabRenderers[i].enabled = false; } // Remove unused collision layers for (int i = anim.Frames[frame].CollisionLayers.Length; i < prefabRenderersCollision.Length; i++) { prefabRenderersCollision[i].sprite = null; prefabRenderersCollision[i].enabled = false; } } if (frameUpdated || collisionUpdated) { // Update collision for (int i = 0; i < anim.Frames[frame].CollisionLayers.Length; i++) { SetCollisionBox(anim.Frames[frame].CollisionLayers[i], prefabRenderersCollision[i], pivot); prefabRenderersCollision[i].enabled = CurrentShowCollision; } } } if (frameUpdated || collisionUpdated) { var col = ObjData.ObjCollision; // Update object collision if (CurrentShowCollision && ((prefabRendersObjCollision == null && col != null && col.Length > 0) || col.Length != prefabRendersObjCollision?.Length)) { // Clear old sprites ClearSprites(prefabRendersObjCollision); if (col != null && col.Length > 0) { prefabRendersObjCollision = new SpriteRenderer[col.Length]; // Instantiate prefabs for (int i = 0; i < col.Length; i++) { prefabRendersObjCollision[i] = Instantiate(prefabBox, transform).GetComponent <SpriteRenderer>(); prefabRendersObjCollision[i].sortingOrder = Layer; prefabRendersObjCollision[i].transform.localPosition = new Vector3(0, 0, col.Length - i); prefabRendersObjCollision[i].transform.localRotation = Quaternion.identity; prefabRendersObjCollision[i].transform.localScale = Vector3.one * ObjData.Scale; } } else { prefabRendersObjCollision = null; } } if (prefabRendersObjCollision != null) { for (var i = 0; i < prefabRendersObjCollision.Length; i++) { SetCollisionBox(col[i], prefabRendersObjCollision[i], ObjData.Pivot); prefabRendersObjCollision[i].enabled = CurrentShowCollision; } } } if (frameUpdated) { // Update the follow sprite line (Rayman 1 only) if (ObjData is Unity_Object_R1 r1 && anim != null) { var animLayer = anim.Frames[r1.AnimationFrame].SpriteLayers.ElementAtOrDefault(r1.EventData.FollowSprite); var imgDescr = r1.ObjManager.DES.ElementAtOrDefault(r1.DESIndex)?.Data?.ImageDescriptors.ElementAtOrDefault(animLayer?.ImageIndex ?? -1); followSpriteLine.localPosition = new Vector2( ((animLayer?.XPosition ?? 0) + (imgDescr?.HitBoxOffsetX ?? 0)) / (float)LevelEditorData.Level.PixelsPerUnit, -((animLayer?.YPosition ?? 0) + (imgDescr?.HitBoxOffsetY ?? 0)) / (float)LevelEditorData.Level.PixelsPerUnit - (r1.EventData.OffsetHY / (float)LevelEditorData.Level.PixelsPerUnit)); var w = (prefabRenderers.ElementAtOrDefault(r1.EventData.FollowSprite)?.sprite == null) ? 0 : imgDescr?.HitBoxWidth ?? 0; followSpriteLine.localScale = new Vector2(w, 1f); } } // Update the collider size for when selecting the events if (frameUpdated || collisionUpdated) { if (anim != null || prefabRendersObjCollision?.Any() == true) { var sprites = anim != null ? prefabRenderers : prefabRendersObjCollision; // Set box collider size to be the combination of all parts float leftX = 0, bottomY = 0, rightX = 0, topY = 0; bool first = true; foreach (SpriteRenderer part in sprites) { if (part.sprite == null) { continue; } Bounds b = part.bounds; b = new Bounds(transform.InverseTransformPoint(b.center) * LevelEditorData.Level.PixelsPerUnit, transform.InverseTransformVector(b.size) * LevelEditorData.Level.PixelsPerUnit); if (b.min.x < leftX || first) { leftX = b.min.x; } if (b.min.y < bottomY || first) { bottomY = b.min.y; } if (b.max.x > rightX || first) { rightX = b.max.x; } if (b.max.y > topY || first) { topY = b.max.y; } if (first) { first = false; } } if (!first) { var w = (rightX - leftX) / LevelEditorData.Level.PixelsPerUnit; var h = (topY - bottomY) / LevelEditorData.Level.PixelsPerUnit; boxCollider.size = new Vector2(w, h); boxCollider.offset = new Vector2(leftX / LevelEditorData.Level.PixelsPerUnit + w / 2f, (topY / LevelEditorData.Level.PixelsPerUnit - h / 2f)); } } else { boxCollider.size = new Vector2(1, 1); boxCollider.offset = new Vector2(); } } // Update offset points if (anim != null) { var pivot = ObjData.Pivot; offsetCrossBX.localPosition = new Vector2(pivot.x / LevelEditorData.Level.PixelsPerUnit, (pivot.y / LevelEditorData.Level.PixelsPerUnit)); if (ObjData is Unity_Object_R1 r1bj) { int hy = -(r1bj.EventData.OffsetHY); if (r1bj.EventData.GetFollowEnabled(LevelEditorData.CurrentSettings)) { hy -= anim.Frames[r1bj.EventData.RuntimeCurrentAnimFrame].SpriteLayers.ElementAtOrDefault(r1bj.EventData.FollowSprite)?.YPosition ?? 0; } offsetCrossHY.localPosition = new Vector2(pivot.x / LevelEditorData.Level.PixelsPerUnit, hy / (float)LevelEditorData.Level.PixelsPerUnit); } else if (ObjData is Unity_Object_R2 r2bj) { var hy = -(r2bj.EventData.CollisionData?.OffsetHY ?? 0); offsetCrossHY.localPosition = new Vector2(pivot.x / LevelEditorData.Level.PixelsPerUnit, hy / (float)LevelEditorData.Level.PixelsPerUnit); } } // Update visibility boxCollider.enabled = EnableBoxCollider; // Set new midpoint midpoint = new Vector3(transform.position.x + boxCollider.offset.x, transform.position.y + boxCollider.offset.y, 0); // Set link line to cube lineRend.SetPosition(0, midpoint); lineRend.SetPosition(1, linkCube.position); // Update link colors if (ObjData.EditorLinkGroup == 0) { lineRend.startColor = Controller.obj.levelEventController.linkColorDeactive; lineRend.endColor = Controller.obj.levelEventController.linkColorDeactive; linkCube.GetComponent <SpriteRenderer>().color = Controller.obj.levelEventController.linkColorDeactive; } else { lineRend.startColor = Controller.obj.levelEventController.linkColorActive; lineRend.endColor = Controller.obj.levelEventController.linkColorActive; linkCube.GetComponent <SpriteRenderer>().color = Controller.obj.levelEventController.linkColorActive; } // Set link visibility var showLinks = // Make sure the obj is visible isVisible && // Make sure links are set to show Settings.ShowLinks && // Only show active links on web !(FileSystem.mode == FileSystem.Mode.Web && ObjData.EditorLinkGroup == 0) && // Only show if available ObjData.CanBeLinkedToGroup; lineRend.enabled = showLinks; linkCube.gameObject.SetActive(showLinks); // Change the offsets visibility offsetOrigin.gameObject.SetActive(ShowOffsets); offsetCrossBX.gameObject.SetActive(ShowOffsets && offsetCrossBX.transform.position != Vector3.zero); offsetCrossHY.gameObject.SetActive(ShowOffsets && (ObjData is Unity_Object_R1 || ObjData is Unity_Object_R2) && offsetCrossHY.transform.position != Vector3.zero); var engineVersion = LevelEditorData.CurrentSettings.EngineVersion; followSpriteLine.gameObject.SetActive( ShowCollision && ObjData is Unity_Object_R1 r1o && r1o.EventData.GetFollowEnabled(LevelEditorData.CurrentSettings) && !(engineVersion == EngineVersion.R1_PS1_JP || engineVersion == EngineVersion.R1_PS1_JPDemoVol3 || engineVersion == EngineVersion.R1_PS1_JPDemoVol6 || engineVersion == EngineVersion.R1_Saturn)); // Update one-way link lines if (oneWayLinkLines != null) { foreach (var lr in oneWayLinkLines) { lr.enabled = EnableBoxCollider && Settings.ShowLinks && ObjData.CanBeLinked; } } HasInitialized = true; }