First Contact - Updated Input Manager

Also changed the game icon w/ mask
This commit is contained in:
Mytiaoga 2022-07-03 16:42:18 +08:00
parent abcf66ff5a
commit b1a491b50a
29 changed files with 7691 additions and 4540 deletions

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,9 @@ TrueTypeFontImporter:
includeFontData: 1
fontNames:
- FOT-Rodin Pro
fallbackFontReferences: []
fallbackFontReferences:
- {fileID: 12800000, guid: d9b391ecd583bd54fa458814fbcad7be, type: 3}
- {fileID: 12800000, guid: 6d457cf9900bba748b3250de2e990fa2, type: 3}
customCharacters:
fontRenderingMode: 0
ascentCalculationMode: 1

View file

@ -0,0 +1,105 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 6
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: FOT-Rodin Pro DB Entity
m_Shader: {fileID: 4800000, guid: 68e6db2ebdc24f95958faec2be5558d6, type: 3}
m_ShaderKeywords:
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _Cube:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _FaceTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 3307759631967023827, guid: 8597c35f18a008c428fc5870aec75766, type: 2}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OutlineTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Floats:
- _Ambient: 1
- _Bevel: 0.5
- _BevelClamp: 0
- _BevelOffset: 0
- _BevelRoundness: 0
- _BevelWidth: 0
- _BumpFace: 0
- _BumpOutline: 0
- _ColorMask: 15
- _CullMode: 0
- _Diffuse: 0.5
- _FaceDilate: 0.4
- _FaceUVSpeedX: 0
- _FaceUVSpeedY: 0
- _GlowInner: 0.659
- _GlowOffset: -1
- _GlowOuter: 1
- _GlowPower: 0.558
- _GradientScale: 10
- _LightAngle: 3.1416
- _MaskSoftnessX: 0
- _MaskSoftnessY: 0
- _OutlineSoftness: 0
- _OutlineUVSpeedX: 0
- _OutlineUVSpeedY: 0
- _OutlineWidth: 0.2
- _PerspectiveFilter: 0.875
- _Reflectivity: 10
- _ScaleRatioA: 0.9
- _ScaleRatioB: 0.37125
- _ScaleRatioC: 0.37125
- _ScaleX: 1
- _ScaleY: 1
- _ShaderFlags: 0
- _Sharpness: 0
- _SpecularPower: 2
- _Stencil: 0
- _StencilComp: 8
- _StencilOp: 0
- _StencilReadMask: 255
- _StencilWriteMask: 255
- _TextureHeight: 1024
- _TextureWidth: 1024
- _UnderlayDilate: 1
- _UnderlayOffsetX: 0
- _UnderlayOffsetY: 0
- _UnderlaySoftness: 0
- _VertexOffsetX: 0
- _VertexOffsetY: 0
- _WeightBold: 0.75
- _WeightNormal: 0
m_Colors:
- _ClipRect: {r: -32767, g: -32767, b: 32767, a: 32767}
- _EnvMatrixRotation: {r: 0, g: 0, b: 0, a: 0}
- _FaceColor: {r: 0, g: 0, b: 0, a: 1}
- _GlowColor: {r: 0, g: 1, b: 0, a: 0.5}
- _MaskCoord: {r: 0, g: 0, b: 32767, a: 32767}
- _OutlineColor: {r: 1, g: 1, b: 1, a: 1}
- _ReflectFaceColor: {r: 0, g: 0, b: 0, a: 1}
- _ReflectOutlineColor: {r: 0, g: 0, b: 0, a: 1}
- _SpecularColor: {r: 1, g: 1, b: 1, a: 1}
- _UnderlayColor: {r: 1, g: 0, b: 0, a: 0.78039217}
m_BuildTextureStacks: []

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 147c28f2f84477044b69d3cbf70ee556
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 426 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

View file

@ -0,0 +1,96 @@
fileFormatVersion: 2
guid: cef4312d99e58974a96782f10bca78f9
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load diff

View file

@ -1,113 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace HeavenStudio.Games.Scripts_FirstContact
{
public class AlienFirstContact : PlayerActionObject
{
public float createBeat;
FirstContact game;
Translator translator;
bool hasSpoke;
public float stateBeat;
public bool prefabHolder;
bool missed;
private void Awake()
{
game = FirstContact.instance;
translator = GameObject.Find("Games/firstContact/Translator").GetComponent<Translator>();
}
private void Start()
{
}
private void Update()
{
if (hasSpoke)
{
return;
}
stateBeat = Conductor.instance.GetPositionFromMargin(createBeat + game.beatInterval, 1f);
StateCheck(stateBeat);
if (PlayerInput.Pressed(true))
{
if (state.eligible())
{
if (!game.hasMissed)
{
Ace();
}
else
{
Eh();
}
}
else if (state.notPerfect() && game.translatorSpeakCount > 0)
{
Eh();
}
//else if (stateBeat > Minigame.LateTime() && game.translatorSpeakCount == 0)
//{
// //Debug.Log("OW");
// Miss();
//}
}
if (stateBeat > Minigame.LateTime())
{
if (!missed)
{
MissNoHit();
}
}
}
public void Ace()
{
translator.successTranslation(true);
game.isCorrect = true;
game.translatorSpeakCount++;
hasSpoke = true;
missed = false;
}
public void Miss()
{
translator.successTranslation(false);
game.isCorrect = false;
hasSpoke = true;
missed = false;
}
public void MissNoHit()
{
game.alienNoHit();
game.isCorrect = false;
missed = true;
game.hasMissed = true;
}
public void Eh()
{
translator.ehTranslation();
hasSpoke = true;
}
public override void OnAce()
{
Ace();
}
}
}

View file

@ -37,7 +37,7 @@ namespace HeavenStudio.Games.Loaders
namespace HeavenStudio.Games
{
using Scripts_FirstContact;
//using Scripts_FirstContact;
public class FirstContact : Minigame
{
@ -51,8 +51,8 @@ namespace HeavenStudio.Games
[Header("Components")]
[SerializeField] GameObject alien;
[SerializeField] Translator translator;
[SerializeField] GameObject alienSpeech;
[SerializeField] GameObject translator;
//[SerializeField] GameObject alienSpeech;
[SerializeField] GameObject dummyHolder;
[SerializeField] GameObject missionControl;
[SerializeField] GameObject liveBar;
@ -65,6 +65,7 @@ namespace HeavenStudio.Games
//public int version;
public float lookAtLength = 1f;
//public enum VersionOfContact
//{
// FirstContact,
@ -87,7 +88,19 @@ namespace HeavenStudio.Games
private void Awake()
{
instance = this;
translator.Init();
}
public void SetIntervalStart(float beat, float interval = 4f)
{
if (!intervalStarted)
{
//alienSpeakCount = 0;
//translatorSpeakCount = 0;
intervalStarted = true;
}
//intervalStartBeat = beat;
beatInterval = interval;
}
@ -102,6 +115,19 @@ namespace HeavenStudio.Games
{
lastReportedBeat = Mathf.Round(Conductor.instance.songPositionInBeats);
}
if(PlayerInput.Pressed() && !IsExpectingInputNow() && !noHitOnce && !isSpeaking)
{
Jukebox.PlayOneShotGame("firstContact/" + randomizerLines());
BeatAction.New(this.gameObject, new List<BeatAction.Action>()
{
new BeatAction.Action(.5f, delegate { translator.GetComponent<Animator>().Play("translator_speak", 0, 0);}),
});
}
if((PlayerInput.Pressed() && !IsExpectingInputNow() && isSpeaking))
{
hasMissed = true;
}
}
//public void versionOfFirstContact(int type)
@ -141,7 +167,7 @@ namespace HeavenStudio.Games
//}
//missionControl.SetActive(false);
Jukebox.PlayOneShotGame("firstContact/alien");
++alienSpeakCount;
var random = Random.Range(0, 2);
string textToPut = "";
if(random == 0)
@ -153,24 +179,26 @@ namespace HeavenStudio.Games
textToPut = "translator_lookAtAlien_nod";
}
ScheduleInput(beat, beatInterval, InputType.STANDARD_DOWN, alienTapping, alienOnMiss, AlienEmpty);
BeatAction.New(alien, new List<BeatAction.Action>()
{
new BeatAction.Action(beat, delegate { alien.GetComponent<Animator>().Play("alien_talk", 0, 0); }),
new BeatAction.Action(beat, delegate { translator.GetComponent<Animator>().Play(textToPut, 0, 0); }),
});
AlienFirstContact a = Instantiate(alienSpeech, dummyHolder.transform).GetComponent<AlienFirstContact>();
a.GetComponent<AlienFirstContact>().createBeat = beat;
alienSpeakCount++;
}
public void alienTurnOver(float beat)
{
//if (!intervalStarted)
//{
// SetIntervalStart(beat, beatInterval);
//}
if (!intervalStarted)
{
SetIntervalStart(beat, beatInterval);
}
if (intervalStarted)
{
SetIntervalStart(beat, beatInterval);
}
Jukebox.PlayOneShotGame("firstContact/turnover");
@ -184,21 +212,6 @@ namespace HeavenStudio.Games
isSpeaking = true;
}
public void SetIntervalStart(float beat, float interval = 4f)
{
if (!intervalStarted)
{
alienSpeakCount = 0;
translatorSpeakCount = 0;
intervalStarted = true;
}
//intervalStartBeat = beat;
beatInterval = interval;
}
public void alienSuccess(float beat)
{
//Make this codeblock smaller
@ -254,20 +267,6 @@ namespace HeavenStudio.Games
noHitOnce = false;
}
public void alienNoHit()
{
if (!noHitOnce)
{
Jukebox.PlayOneShotGame("firstContact/alienNoHit");
noHitOnce = true;
}
BeatAction.New(alien, new List<BeatAction.Action>()
{
new BeatAction.Action(.5f, delegate { alien.GetComponent<Animator>().Play("alien_noHit", 0, 0); }),
});
}
public void missionControlDisplay(float beat, bool stay)
{
missionControl.SetActive(true);
@ -306,6 +305,102 @@ namespace HeavenStudio.Games
translatorSpeakCount = 0;
isSpeaking = false;
}
public void alienTapping(PlayerActionEvent caller, float beat) //OnHit
{
if (!noHitOnce)
{
++translatorSpeakCount;
Jukebox.PlayOneShotGame("firstContact/" + randomizerLines());
isCorrect = true;
BeatAction.New(this.gameObject, new List<BeatAction.Action>()
{
new BeatAction.Action(.5f, delegate { translator.GetComponent<Animator>().Play("translator_speak", 0, 0);}),
});
}
else if (noHitOnce)
{
Jukebox.PlayOneShotGame("firstContact/slightlyFail");
BeatAction.New(this.gameObject, new List<BeatAction.Action>()
{
new BeatAction.Action(.5f, delegate { translator.GetComponent<Animator>().Play("translator_eh", 0, 0);}),
});
}
}
public void alienOnMiss(PlayerActionEvent caller) //OnMiss
{
if (!noHitOnce)
{
Jukebox.PlayOneShotGame("firstContact/alienNoHit");
noHitOnce = true;
}
BeatAction.New(alien, new List<BeatAction.Action>()
{
new BeatAction.Action(.5f, delegate { alien.GetComponent<Animator>().Play("alien_noHit", 0, 0); }),
});
}
public void AlienEmpty(PlayerActionEvent caller) //OnEmpty
{
//empty
}
public int randomizerLines()
{
return Random.Range(1, 11);
}
//public void alienSuccessTest(PlayerActionEvent caller, float beat)
//{
// string[] sfxStrings = { "", "" };
// string animString = "";
// float off = 0f;
// if (alienSpeakCount == translatorSpeakCount)
// {
// sfxStrings[0] = "firstContact/success_1";
// sfxStrings[1] = "firstContact/success_2";
// animString = "alien_success";
// off = .15f;
// }
// else if(alienSpeakCount != translatorSpeakCount)
// {
// sfxStrings[0] = "firstContact/failAlien_1";
// sfxStrings[1] = "firstContact/failAlien_2";
// animString = "alien_fail";
// off = .5f;
// }
// string[] sounds = new string[] { sfxStrings[0], sfxStrings[0] };
// var sound = new MultiSound.Sound[]
// {
// new MultiSound.Sound(sounds[0], beat),
// new MultiSound.Sound(sounds[1], beat + .5f, offset: off)
// };
// MultiSound.Play(sound);
// BeatAction.New(alien, new List<BeatAction.Action>()
// {
// new BeatAction.Action(beat, delegate { alien.GetComponent<Animator>().Play(animString, 0, 0); }),
// new BeatAction.Action(beat + .5f, delegate { alien.GetComponent<Animator>().Play(animString, 0, 0); })
// });
// BeatAction.New(translator.gameObject, new List<BeatAction.Action>()
// {
// new BeatAction.Action(beat, delegate { translator.GetComponent<Animator>().Play("translator_idle", 0, 0); }),
// });
// alienSpeakCount = 0;
// translatorSpeakCount = 0;
// isSpeaking = false;
// hasMissed = false;
// noHitOnce = false;
//}
}
}

View file

@ -1,70 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
using HeavenStudio.Util;
using Starpelly;
namespace HeavenStudio.Games.Scripts_FirstContact
{
public class Translator : PlayerActionObject
{
public Animator anim;
FirstContact game;
public void Init()
{
game = FirstContact.instance;
//anim = GetComponent<Animator>();
}
private void Update()
{
////IF YOU WANT TO PLAY NOTES ANYTIME W/O CONSTRAINTS
//if (PlayerInput.Pressed(true) && !game.isSpeaking)
//{
// successTranslation(true);
//}
}
public void successTranslation(bool ace)
{
if (ace)
{
//if(game.version == 1)
//{
// Jukebox.PlayOneShotGame("firstContact/citrusRemix/1_r");
//}
Jukebox.PlayOneShotGame("firstContact/" + randomizerLines());
}
else
{
Jukebox.PlayOneShotGame("firstContact/failContact");
}
BeatAction.New(this.gameObject, new List<BeatAction.Action>()
{
new BeatAction.Action(.5f, delegate { anim.Play("translator_speak", 0, 0);}),
});
}
public void ehTranslation()
{
Jukebox.PlayOneShotGame("firstContact/slightlyFail");
BeatAction.New(this.gameObject, new List<BeatAction.Action>()
{
new BeatAction.Action(.5f, delegate { anim.Play("translator_eh", 0, 0);}),
});
}
public int randomizerLines()
{
return Random.Range(1, 11);
}
}
}

View file

@ -23,6 +23,9 @@ namespace HeavenStudio.Editor
private bool clickedInTimeline = false;
private TMPro.TMP_Text sizeText;
private RectTransform text;
private float timelineLastX;
public static BoxSelection instance { get; private set; }
@ -40,10 +43,19 @@ namespace HeavenStudio.Editor
boxVisual.transform.GetChild(0).GetComponent<Image>().color = EditorTheme.theme.properties.BoxSelectionOutlineCol.Hex2RGB();
sizeText = boxVisual.transform.GetChild(1).GetComponent<TMPro.TMP_Text>();
text = boxVisual.transform.GetChild(1).GetComponent<RectTransform>();
}
private void Update()
{
float deltaTimelineX = timelineContent.transform.localPosition.x - timelineLastX;
Camera camera = Editor.instance.EditorCamera;
Vector3 scale = Editor.instance.MainCanvas.transform.localScale;
boxVisual.transform.localScale = new Vector2(0.01f/scale.x, 1f/scale.y);
text.transform.localScale = scale;
if (Selections.instance.eventsSelected.Count > 0 && Timeline.instance.InteractingWithEvents())
{
startPosition = Vector2.zero;
@ -60,10 +72,11 @@ namespace HeavenStudio.Editor
return;
}
if (boxVisual.rect.width * boxVisual.transform.localScale.x >= 0.5f)
sizeText.text = $"{string.Format("{0:0.000}", boxVisual.rect.width * boxVisual.transform.localScale.x)}";
float beatLen = boxVisual.rect.width * boxVisual.transform.localScale.x;
if (beatLen >= 0.5f)
sizeText.text = $"{string.Format("{0:0.000}", beatLen)}";
else
sizeText.text = string.Empty; // i'm lazy
sizeText.text = string.Empty;
// click
@ -78,9 +91,11 @@ namespace HeavenStudio.Editor
// dragging
if (Input.GetMouseButton(0) && clickedInTimeline)
{
startPosition.x += deltaTimelineX * scale.x;
endPosition = MousePosition();
DrawVisual();
DrawSelection();
SelectEvents(); //kek
DrawVisual();
}
// release click
@ -92,9 +107,7 @@ namespace HeavenStudio.Editor
DrawVisual();
}
// selecting = (selectionBox.size != Vector2.zero); -- doesn't work really
// for real time selection just move SelectEvents() to here, but that breaks some shit. might fix soon idk --pelly
timelineLastX = timelineContent.transform.localPosition.x;
}
private void DrawVisual()
@ -102,15 +115,12 @@ namespace HeavenStudio.Editor
Vector2 boxStart = startPosition;
Vector2 boxEnd = endPosition;
// boxEnd = new Vector2(Mathf.Clamp(boxEnd.x, -5.78f, Mathf.Infinity), boxEnd.y);
Vector2 boxCenter = (boxStart + boxEnd) / 2;
boxVisual.position = boxCenter;
Vector2 boxSize = new Vector2(Mathf.Abs(boxStart.x - boxEnd.x), Mathf.Abs(boxStart.y - boxEnd.y));
// boxVisual.sizeDelta = new Vector2(boxSize.x / boxVisual.localScale.x, boxSize.y / boxVisual.localScale.y);
boxVisual.sizeDelta = new Vector2(boxSize.x, boxSize.y);
boxVisual.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, boxSize.x);
boxVisual.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, boxSize.y);
}
private void DrawSelection()
@ -168,7 +178,7 @@ namespace HeavenStudio.Editor
{
var mousePos = Editor.instance.EditorCamera.ScreenToWorldPoint(Input.mousePosition);
// var mousePos = new Vector2();
// RectTransformUtility.ScreenPointToLocalPointInRectangle(timelineContent, Input.mousePosition, Camera.main, out mousePos);
// RectTransformUtility.ScreenPointToLocalPointInRectangle(timelineContent, Input.mousePosition, Editor.instance.EditorCamera, out mousePos);
return new Vector3(mousePos.x, mousePos.y, 0);
}

View file

@ -25,10 +25,10 @@ namespace HeavenStudio.Editor
{
private Initializer Initializer;
[SerializeField] private Canvas MainCanvas;
[SerializeField] public Canvas MainCanvas;
[SerializeField] public Camera EditorCamera;
[SerializeField] public GameObject EditorLetterbox;
// [SerializeField] public GameObject EditorLetterbox;
[SerializeField] public GameObject GameLetterbox;
[Header("Rect")]
@ -52,6 +52,7 @@ namespace HeavenStudio.Editor
[SerializeField] private Button EditorThemeBTN;
[SerializeField] private Button FullScreenBTN;
[SerializeField] private Button TempoFinderBTN;
[SerializeField] private Button SnapDiagBTN;
[Header("Tooltip")]
public TMP_Text tooltipText;
@ -105,27 +106,75 @@ namespace HeavenStudio.Editor
Tooltip.AddTooltip(EditorThemeBTN.gameObject, "Editor Theme");
Tooltip.AddTooltip(FullScreenBTN.gameObject, "Preview <color=#adadad>[Tab]</color>");
Tooltip.AddTooltip(TempoFinderBTN.gameObject, "Tempo Finder");
Tooltip.AddTooltip(SnapDiagBTN.gameObject, "Snap Settings");
UpdateEditorStatus(true);
}
public void LateUpdate()
{
if (Input.GetKeyDown(KeyCode.Tab))
#region Keyboard Shortcuts
if (!editingInputField)
{
if (!Editor.instance.editingInputField)
if (Input.GetKeyDown(KeyCode.Tab))
{
Fullscreen();
}
}
if (Input.GetKeyDown(KeyCode.Delete))
{
if (!Editor.instance.editingInputField)
if (Input.GetKeyDown(KeyCode.Delete))
{
List<TimelineEventObj> ev = new List<TimelineEventObj>();
for (int i = 0; i < Selections.instance.eventsSelected.Count; i++) ev.Add(Selections.instance.eventsSelected[i]);
CommandManager.instance.Execute(new Commands.Deletion(ev));
}
if (Input.GetKey(KeyCode.LeftControl))
{
if (Input.GetKeyDown(KeyCode.Z))
{
if (Input.GetKey(KeyCode.LeftShift))
CommandManager.instance.Redo();
else
CommandManager.instance.Undo();
}
else if (Input.GetKeyDown(KeyCode.Y))
{
CommandManager.instance.Redo();
}
if (Input.GetKey(KeyCode.LeftShift))
{
if (Input.GetKeyDown(KeyCode.D))
{
ToggleDebugCam();
}
}
}
if (Input.GetKey(KeyCode.LeftControl))
{
if (Input.GetKeyDown(KeyCode.N))
{
LoadRemix("");
}
else if (Input.GetKeyDown(KeyCode.O))
{
OpenRemix();
}
else if (Input.GetKey(KeyCode.LeftAlt))
{
if (Input.GetKeyDown(KeyCode.S))
{
SaveRemix(true);
}
}
else if (Input.GetKeyDown(KeyCode.S))
{
SaveRemix(false);
}
}
}
#endregion
if (CommandManager.instance.canUndo())
UndoBTN.transform.GetChild(0).GetComponent<Image>().color = "BD8CFF".Hex2RGB();
@ -137,29 +186,6 @@ namespace HeavenStudio.Editor
else
RedoBTN.transform.GetChild(0).GetComponent<Image>().color = Color.gray;
if (Input.GetKey(KeyCode.LeftControl))
{
if (Input.GetKeyDown(KeyCode.Z))
{
if (Input.GetKey(KeyCode.LeftShift))
CommandManager.instance.Redo();
else
CommandManager.instance.Undo();
}
else if (Input.GetKeyDown(KeyCode.Y))
{
CommandManager.instance.Redo();
}
if (Input.GetKey(KeyCode.LeftShift))
{
if (Input.GetKeyDown(KeyCode.D))
{
ToggleDebugCam();
}
}
}
if (Timeline.instance.timelineState.selected && Editor.instance.canSelect)
{
if (Input.GetMouseButtonUp(0))
@ -182,37 +208,6 @@ namespace HeavenStudio.Editor
}
}
}
if (Input.GetKey(KeyCode.LeftControl))
{
if (Input.GetKeyDown(KeyCode.N))
{
LoadRemix("");
}
else if (Input.GetKeyDown(KeyCode.O))
{
OpenRemix();
}
else if (Input.GetKey(KeyCode.LeftAlt))
{
if (Input.GetKeyDown(KeyCode.S))
{
SaveRemix(true);
}
}
else if (Input.GetKeyDown(KeyCode.S))
{
SaveRemix(false);
}
}
if (Application.isEditor)
{
if (Input.GetKeyDown(KeyCode.S))
{
// SaveRemix(false);
}
}
}
public static Sprite GameIcon(string name)
@ -441,7 +436,7 @@ namespace HeavenStudio.Editor
{
if (fullscreen == false)
{
EditorLetterbox.SetActive(false);
// EditorLetterbox.SetActive(false);
GameLetterbox.SetActive(true);
MainCanvas.enabled = false;
@ -453,7 +448,7 @@ namespace HeavenStudio.Editor
}
else
{
EditorLetterbox.SetActive(true);
// EditorLetterbox.SetActive(true);
GameLetterbox.SetActive(false);
MainCanvas.enabled = true;
@ -466,6 +461,7 @@ namespace HeavenStudio.Editor
GameCamera.instance.camera.rect = new Rect(0, 0, 1, 1);
GameManager.instance.CursorCam.rect = new Rect(0, 0, 1, 1);
GameManager.instance.OverlayCamera.rect = new Rect(0, 0, 1, 1);
EditorCamera.rect = new Rect(0, 0, 1, 1);
}
}

View file

@ -22,7 +22,7 @@ namespace HeavenStudio.Editor
public Beatmap.Entity entity;
private bool active;
public bool active;
private int childCountAtStart;

View file

@ -20,6 +20,8 @@ namespace HeavenStudio.Editor
public GameObject GameEventSelector;
public GameObject EventRef;
public GameObject CurrentSelected;
public RectTransform GameEventSelectorCanScroll;
private RectTransform GameEventSelectorRect;
private RectTransform eventsParent;
[Header("Properties")]
@ -29,9 +31,15 @@ namespace HeavenStudio.Editor
private int dragTimes;
public float posDif;
public int ignoreSelectCount;
private float selectorHeight;
private float eventSize;
private void Start()
{
GameEventSelectorRect = GameEventSelector.GetComponent<RectTransform>();
selectorHeight = GameEventSelectorRect.rect.height;
eventSize = EventRef.GetComponent<RectTransform>().rect.height;
eventsParent = EventRef.transform.parent.GetChild(2).GetComponent<RectTransform>();
SelectGame("Game Manager", 1);
@ -40,7 +48,7 @@ namespace HeavenStudio.Editor
private void Update()
{
if(!Conductor.instance.NotStopped())
if(!(EventParameterManager.instance.active || Conductor.instance.NotStopped()))
{
if (gameOpen)
{
@ -54,11 +62,14 @@ namespace HeavenStudio.Editor
}
}
if (Input.mouseScrollDelta.y != 0)
if (RectTransformUtility.RectangleContainsScreenPoint(GameEventSelectorCanScroll, Input.mousePosition, Editor.instance.EditorCamera) && Input.mouseScrollDelta.y != 0)
{
UpdateIndex(currentEventIndex - Mathf.RoundToInt(Input.mouseScrollDelta.y));
}
}
//moved here so this updates dynamically with window scale
UpdateScrollPosition();
}
#region Functions
@ -75,26 +86,32 @@ namespace HeavenStudio.Editor
else if (currentEventIndex > eventsParent.childCount - 1)
currentEventIndex = 0;
if (currentEventIndex > 2 && eventsParent.childCount >= 8)
{
if (eventsParent.childCount - 4 > currentEventIndex)
{
EventRef.transform.parent.DOLocalMoveY((EventRef.GetComponent<RectTransform>().sizeDelta.y) * (currentEventIndex - 2), 0.35f).SetEase(Ease.OutExpo);
}
else
{
EventRef.transform.parent.DOLocalMoveY((EventRef.GetComponent<RectTransform>().sizeDelta.y) * (eventsParent.childCount - 7), 0.35f).SetEase(Ease.OutExpo);
}
}
else
EventRef.transform.parent.DOLocalMoveY(0, 0.35f).SetEase(Ease.OutExpo);
CurrentSelected.transform.DOLocalMoveY(eventsParent.transform.GetChild(currentEventIndex).localPosition.y + eventsParent.transform.localPosition.y, 0.35f).SetEase(Ease.OutExpo);
if (updateCol)
SetColors(currentEventIndex);
}
private void UpdateScrollPosition()
{
selectorHeight = GameEventSelectorRect.rect.height;
eventSize = EventRef.GetComponent<RectTransform>().rect.height;
if (currentEventIndex * eventSize >= selectorHeight/2 && eventsParent.childCount * eventSize >= selectorHeight)
{
if (currentEventIndex * eventSize < eventsParent.childCount * eventSize - selectorHeight/2)
{
EventRef.transform.parent.DOLocalMoveY((currentEventIndex * eventSize) - selectorHeight/2, 0.35f).SetEase(Ease.OutExpo);
}
else
{
EventRef.transform.parent.DOLocalMoveY((eventsParent.childCount * eventSize) - selectorHeight + (eventSize*0.33f), 0.35f).SetEase(Ease.OutExpo);
}
}
else
EventRef.transform.parent.DOLocalMoveY(0, 0.35f).SetEase(Ease.OutExpo);
}
public void SelectGame(string gameName, int index)
{
if (SelectedGameIcon != null)

View file

@ -0,0 +1,28 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace HeavenStudio.Editor
{
public class SnapDialog : MonoBehaviour
{
[SerializeField] private GameObject snapSetter;
private void Awake()
{
}
public void SwitchSnapDialog()
{
if(snapSetter.activeSelf) {
snapSetter.SetActive(false);
} else {
snapSetter.SetActive(true);
}
}
private void Update()
{
}
}
}

View file

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 47ef82bd935047f42b39142f4a1b1d32
guid: f32d53b1d58c64e41b71bd7520435169
MonoImporter:
externalObjects: {}
serializedVersion: 2

View file

@ -0,0 +1,36 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using TMPro;
using Starpelly;
namespace HeavenStudio.Editor.Track
{
public class LayerLabel : MonoBehaviour
{
[SerializeField] private RectTransform rect;
// Update is called once per frame
void Update()
{
//convert timeline layer scale to screen space
Camera cam;
//"your program can't crash if you put everything in a try block"
try
{
cam = Editor.instance.EditorCamera;
float layerScaleDist = cam.WorldToScreenPoint(Timeline.instance.LayerCorners[1]).y - Camera.main.WorldToScreenPoint(Timeline.instance.LayerCorners[0]).y;
float modScale = Timeline.GetScaleModifier();
rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, layerScaleDist/4 * (1/modScale));
}
catch (System.NullReferenceException)
{
return;
}
}
}
}

View file

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 090e2309a1a03314d93714e9c1ed5a99
guid: b90b6b57a843c2245bfdae87a3e8fb21
MonoImporter:
externalObjects: {}
serializedVersion: 2

View file

@ -72,6 +72,7 @@ namespace HeavenStudio.Editor.Track
GameManager.instance.Beatmap.bpm += increase;
UpdateStartingBPMText();
UpdateStartingBPMFromText(); // In case the scrolled-to value is invalid.
}
}
}
@ -109,6 +110,8 @@ namespace HeavenStudio.Editor.Track
// In case the newBPM ended up differing from the inputted string.
UpdateStartingBPMText();
Timeline.instance.FitToSong();
}
public void UpdateOffsetFromText()
@ -160,6 +163,8 @@ namespace HeavenStudio.Editor.Track
}
tempoTimelineObjs.Add(tempoTimelineObj);
Timeline.instance.FitToSong();
}
}

View file

@ -46,6 +46,10 @@ namespace HeavenStudio.Editor.Track
tempoChange.tempo += newTempo;
//make sure tempo is positive
if (tempoChange.tempo < 1)
tempoChange.tempo = 1;
if (Input.GetMouseButtonDown(0))
{
Vector3 mousePos = Editor.instance.EditorCamera.ScreenToWorldPoint(Input.mousePosition);
@ -96,6 +100,7 @@ namespace HeavenStudio.Editor.Track
private void UpdateTempo()
{
tempoTXT.text = $"{tempoChange.tempo} BPM";
Timeline.instance.FitToSong();
}
}
}

View file

@ -68,6 +68,7 @@ namespace HeavenStudio.Editor.Track
[SerializeField] private RectTransform TimelineSongPosLineRef;
[SerializeField] private RectTransform TimelineEventObjRef;
[SerializeField] private RectTransform LayersRect;
public TempoTimeline TempoInfo;
public VolumeTimeline VolumeInfo;
private RectTransform TimelineSongPosLine;
@ -83,6 +84,8 @@ namespace HeavenStudio.Editor.Track
public Button MusicVolumeBTN;
public Slider PlaybackSpeed;
public Vector3[] LayerCorners = new Vector3[4];
public static Timeline instance { get; private set; }
public bool userIsEditingInputField
@ -256,9 +259,11 @@ namespace HeavenStudio.Editor.Track
SliderControl();
if (Input.GetKeyDown(KeyCode.Space))
#region Keyboard Shortcuts
if (!userIsEditingInputField)
{
if (!Editor.instance.editingInputField)
if (Input.GetKeyDown(KeyCode.Space))
{
if (Input.GetKey(KeyCode.LeftShift))
{
@ -269,20 +274,44 @@ namespace HeavenStudio.Editor.Track
PlayCheck(true);
}
}
}
if (Input.GetKeyDown(KeyCode.P))
{
if (!Editor.instance.editingInputField)
if (Input.GetKeyDown(KeyCode.P))
{
AutoPlayToggle();
}
}
if (Input.GetKeyDown(KeyCode.M))
{
if (!Editor.instance.editingInputField)
if (Input.GetKeyDown(KeyCode.M))
{
MetronomeToggle();
}
}
if (Input.GetKeyDown(KeyCode.Alpha1))
{
timelineState.SetState(true, false, false);
}
else if (Input.GetKeyDown(KeyCode.Alpha2))
{
timelineState.SetState(false, true, false);
}
else if (Input.GetKeyDown(KeyCode.Alpha3))
{
timelineState.SetState(false, false, true);
}
float moveSpeed = 750;
if (Input.GetKey(KeyCode.LeftShift)) moveSpeed *= 2;
if (Input.GetKey(KeyCode.LeftArrow) || Input.GetKey(KeyCode.A))
{
TimelineContent.transform.localPosition += new Vector3(moveSpeed * Time.deltaTime, 0);
}
else if (Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.D))
{
TimelineContent.transform.localPosition += new Vector3(-moveSpeed * Time.deltaTime, 0);
}
}
#endregion
if (Input.GetMouseButton(1) && !Conductor.instance.isPlaying && Editor.MouseInRectTransform(TimelineGridSelect))
{
@ -304,21 +333,6 @@ namespace HeavenStudio.Editor.Track
lastBeatPos = TimelineSlider.localPosition.x;
}
float moveSpeed = 750;
if (Input.GetKey(KeyCode.LeftShift)) moveSpeed *= 2;
if (!Editor.instance.editingInputField)
{
if (Input.GetKey(KeyCode.LeftArrow) || Input.GetKey(KeyCode.A))
{
TimelineContent.transform.localPosition += new Vector3(moveSpeed * Time.deltaTime, 0);
}
else if (Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.D))
{
TimelineContent.transform.localPosition += new Vector3(-moveSpeed * Time.deltaTime, 0);
}
}
if (Conductor.instance.isPlaying)
TimelineContent.transform.localPosition = new Vector3((-Conductor.instance.songPositionInBeats * 100) + 200, TimelineContent.transform.localPosition.y);
@ -326,18 +340,19 @@ namespace HeavenStudio.Editor.Track
CurrentTempo.text = $" = {Conductor.instance.songBpm}";
if (Input.GetKeyDown(KeyCode.Alpha1) && !userIsEditingInputField)
{
timelineState.SetState(true, false, false);
}
else if (Input.GetKeyDown(KeyCode.Alpha2) && !userIsEditingInputField)
{
timelineState.SetState(false, true, false);
}
else if (Input.GetKeyDown(KeyCode.Alpha3) && !userIsEditingInputField)
{
timelineState.SetState(false, false, true);
}
LayersRect.GetWorldCorners(LayerCorners);
}
public static float GetScaleModifier()
{
Camera cam = Editor.instance.EditorCamera;
return Mathf.Pow(cam.pixelWidth/1280f, 1f) * Mathf.Pow(cam.pixelHeight/720f, 0f);
}
public Vector2 LayerCornersToDist()
{
Vector3[] v = LayerCorners;
return new Vector2(Mathf.Abs(v[1].x - v[2].x), Mathf.Abs(v[3].y - v[1].y));
}
private void SliderControl()

View file

@ -26,7 +26,7 @@ namespace HeavenStudio.Editor.Track
[SerializeField] private RectTransform resizeGraphic;
[SerializeField] private RectTransform leftDrag;
[SerializeField] private RectTransform rightDrag;
private GameObject moveTemp;
// private GameObject moveTemp;
[Header("Properties")]
public Beatmap.Entity entity;
@ -61,8 +61,9 @@ namespace HeavenStudio.Editor.Track
lastMovePos = transform.localPosition;
moveTemp = new GameObject();
moveTemp.transform.SetParent(this.transform.parent);
// what the fuck????
// moveTemp = new GameObject();
// moveTemp.transform.SetParent(this.transform.parent);
bool visible = rectTransform.IsVisibleFrom(Editor.instance.EditorCamera);
for (int i = 0; i < this.transform.childCount; i++)
@ -105,7 +106,7 @@ namespace HeavenStudio.Editor.Track
#endregion
SetColor(GetTrack());
SetColor(entity.track);
if (selected)
{
@ -132,6 +133,20 @@ namespace HeavenStudio.Editor.Track
if (Conductor.instance.NotStopped())
{
Cancel();
if (moving)
moving = false;
if (selected)
{
selected = false;
selectedImage.gameObject.SetActive(false);
for (int i = 0; i < outline.childCount; i++)
outline.GetChild(i).GetComponent<Image>().color = new Color32(0, 0, 0, 51);
}
rectTransform.sizeDelta = new Vector2(rectTransform.sizeDelta.x, Timeline.instance.LayerHeight());
this.transform.localPosition = new Vector3(this.transform.localPosition.x, -entity.track * Timeline.instance.LayerHeight());
return;
}
@ -157,14 +172,11 @@ namespace HeavenStudio.Editor.Track
lastPos_ = transform.localPosition;
this.transform.position = new Vector3(mousePos.x - startPosX, mousePos.y - startPosY - 0.40f, 0);
this.transform.localPosition = new Vector3(Mathf.Clamp(Mathp.Round2Nearest(this.transform.localPosition.x, Timeline.SnapInterval()), 0, Mathf.Infinity), Timeline.instance.SnapToLayer(this.transform.localPosition.y));
// moveTemp.transform.position = new Vector3(mousePos.x - startPosX, mousePos.y - startPosY - 0.40f, 0);
// moveTemp.transform.localPosition = new Vector3(Mathf.Clamp(Mathp.Round2Nearest(moveTemp.transform.localPosition.x, 0.25f), 0, Mathf.Infinity), Timeline.instance.SnapToLayer(moveTemp.transform.localPosition.y));
this.transform.localPosition = new Vector3(Mathf.Max(Mathp.Round2Nearest(this.transform.localPosition.x, Timeline.SnapInterval()), 0), Timeline.instance.SnapToLayer(this.transform.localPosition.y));
if (lastPos != transform.localPosition)
{
OnMove();
// this.transform.DOLocalMove(new Vector3(Mathf.Clamp(Mathp.Round2Nearest(moveTemp.transform.localPosition.x, 0.25f), 0, Mathf.Infinity), Timeline.instance.SnapToLayer(moveTemp.transform.localPosition.y)), 0.15f).SetEase(Ease.OutExpo);
}
lastPos = transform.localPosition;
@ -215,6 +227,9 @@ namespace HeavenStudio.Editor.Track
{
Cursor.SetCursor(null, Vector2.zero, CursorMode.Auto);
}
rectTransform.sizeDelta = new Vector2(rectTransform.sizeDelta.x, Timeline.instance.LayerHeight());
this.transform.localPosition = new Vector3(this.transform.localPosition.x, -entity.track * Timeline.instance.LayerHeight());
}
#region ClickEvents

View file

@ -27,27 +27,33 @@ namespace HeavenStudio.Editor
private void Update()
{
Vector2 anchoredPosition = Input.mousePosition;
Vector3 anchoredPosition = Input.mousePosition;
Camera camera = Editor.instance.EditorCamera;
Vector3 canvasScale = Editor.instance.MainCanvas.transform.localScale;
Vector2 scale = new Vector2(canvasScale.x, canvasScale.y);
float toolTipScale = camera.pixelWidth / 1280f;
if (anchoredPosition.x + background.rect.width > canvasRect.rect.width)
if (anchoredPosition.x + background.rect.width * toolTipScale > camera.pixelWidth)
{
anchoredPosition.x = canvasRect.rect.width - background.rect.width;
anchoredPosition.x = camera.pixelWidth - background.rect.width * toolTipScale;
}
if (anchoredPosition.x < 0)
if (anchoredPosition.x < -camera.pixelWidth)
{
anchoredPosition.x = 0;
anchoredPosition.x = -camera.pixelWidth;
}
if (anchoredPosition.y + background.rect.height > canvasRect.rect.height)
if (anchoredPosition.y + background.rect.height * toolTipScale > camera.pixelHeight)
{
anchoredPosition.y = canvasRect.rect.height - background.rect.height;
anchoredPosition.y = camera.pixelHeight - background.rect.height * toolTipScale;
}
if (anchoredPosition.y < 0)
if (anchoredPosition.y < -camera.pixelHeight)
{
anchoredPosition.y = 0;
anchoredPosition.y = -camera.pixelHeight;
}
rectTransform.anchoredPosition = anchoredPosition;
anchoredPosition.z = camera.nearClipPlane;
anchoredPosition = camera.ScreenToWorldPoint(anchoredPosition);
rectTransform.anchoredPosition = anchoredPosition / scale;
}
public static void OnEnter(string tooltipText, string altTooltipText)

View file

@ -0,0 +1,94 @@
using UnityEngine;
using UnityEngine.EventSystems;
using static UnityEngine.EventSystems.ExecuteEvents;
namespace kamgam
{
/// <summary>
/// Bubbles events to the parent. Use this to overcome EventTriggers which stop scroll and drag events from bubbling.
///
/// If an EventTrigger component is attached and other code is listening for
/// onPointer events then these will NOT be triggered while dragging if DisableEventTriggerWhileDragging
/// is true.
/// </summary>
public class UiScrollRectEventBubbling : MonoBehaviour,
IBeginDragHandler,
IDragHandler,
IEndDragHandler,
IScrollHandler
{
[Tooltip("Should the scroll and drag events be forwarded (bubble up) to the parent?")]
public bool Bubble = true;
[Tooltip("Stop EventTriggers from executing events while dragging?")]
public bool DisableEventTriggerWhileDragging = true;
protected EventTrigger eventTrigger;
public EventTrigger EventTrigger
{
get
{
if (eventTrigger == null)
{
eventTrigger = this.GetComponent<EventTrigger>();
}
return eventTrigger;
}
}
protected bool dragging = false;
protected void HandleEventPropagation<T>(Transform goTransform, BaseEventData eventData, EventFunction<T> callbackFunction) where T : IEventSystemHandler
{
if (Bubble && goTransform.parent != null)
{
ExecuteEvents.ExecuteHierarchy(goTransform.parent.gameObject, eventData, callbackFunction);
}
}
public void OnScroll(PointerEventData eventData)
{
HandleEventPropagation(transform, eventData, ExecuteEvents.scrollHandler);
}
public void OnBeginDrag(PointerEventData eventData)
{
HandleEventPropagation(transform, eventData, ExecuteEvents.beginDragHandler);
dragging = true;
if (DisableEventTriggerWhileDragging && EventTrigger != null)
{
EventTrigger.enabled = false;
}
}
public void OnDrag(PointerEventData eventData)
{
HandleEventPropagation(transform, eventData, ExecuteEvents.dragHandler);
}
public void OnEndDrag(PointerEventData eventData)
{
HandleEventPropagation(transform, eventData, ExecuteEvents.endDragHandler);
dragging = false;
if (DisableEventTriggerWhileDragging && EventTrigger != null)
{
EventTrigger.enabled = true;
}
}
/// <summary>
/// If the object is disabled while being dragged then the EventTrigger would remain disabled.
/// </summary>
public void OnDisable()
{
if (DisableEventTriggerWhileDragging && dragging && EventTrigger != null)
{
dragging = false;
EventTrigger.enabled = true;
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c3ed2b8848b1a2c40819efeb60cbf9ec
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,9 +1,7 @@
## This project is still in development. There are NO public compiled releases (yet).
## This project is based on [Rhythm Heaven Mania](https://github.com/RhythmHeavenDevelopment/RhythmHeavenMania) by Starpelly
# Heaven Studio
(WIP) Fully playable, open source recreation of every rhythm heaven minigame with a built in level editor.
(WIP) A tool to create playable Rhythm Heaven custom remixes, with many customization options.
<p>
<a href="https://discord.gg/2kdZ8kFyEN">
@ -13,10 +11,13 @@
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
[Progress spreadsheet](https://docs.google.com/spreadsheets/d/1NXxIeL4nsdjChrxAZTPpk20QOKEdQWGbXIhT4TclB6k/edit?usp=sharing)
[Progress Spreadsheet](https://docs.google.com/spreadsheets/d/1NXxIeL4nsdjChrxAZTPpk20QOKEdQWGbXIhT4TclB6k/edit?usp=sharing)
![image](https://user-images.githubusercontent.com/40370440/155040498-07365bd4-a0eb-40ef-839e-2c5dcfc5141f.png)
![image](https://user-images.githubusercontent.com/40370440/154824159-07800021-9264-4293-92cf-d3f6e0155f5b.png)
[YouTube Channel](https://www.youtube.com/channel/UCAb3R-5qyXWOEj8B4vibhxQ)
[Bug Report Form](https://docs.google.com/forms/d/e/1FAIpQLSfu0p2ZjrfwwEvpLgJ4Hw-AAN3jh4QNSEk0U7mjDvwiIkoRAw/viewform?usp=pp_url)
![image](https://i.ibb.co/6sgDQtv/hsscreenshot.png)
## Prebuilt Binaries
@ -31,7 +32,7 @@ This project is still in development, so there are currently no release builds y
Heaven Studio is made in [Unity 2020.3.25f1](https://unity3d.com/unity/whats-new/2020.3.25),
and programmed with [Visual Studio Code](https://code.visualstudio.com/).
Video tutorial (from Rhythm Heaven Mania): https://www.youtube.com/watch?v=vONoZuP7qtg
Building tutorial: coming soon
## Other information
Rhythm Heaven is the intellectual property of Nintendo. This program is NOT endorsed nor sponsored in any way by Nintendo. All used properties of Nintendo (such as names, audio, graphics, etc.) in this software are not intended to maliciously infringe trademark rights. All other trademarks and assets are property of their respective owners. This is a community project and this is available for others to use according to the GPL-3.0 license, without charge.