-
Notifications
You must be signed in to change notification settings - Fork 6
/
GrassyCompass.cs
140 lines (117 loc) · 5.24 KB
/
GrassyCompass.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
using System;
using UnityEngine;
namespace GrassyKnight
{
// Attach to the hero to give them a grassy compass friend
class GrassyCompass : MonoBehaviour {
// The target location in world space that the compass will point to
public Vector2? Target = null;
// Maximum distance between game object and compass
public float Radius = 1.5f;
// A hotkey that will toggle the compass visible/invisible
public KeyCode? ToggleHotkey = null;
// Whether the compass is toggled on or off
public bool ToggledOn { get; private set; } = true;
// Will be used to automatically update Target every frame if non-null
public GrassDB AllGrass = null;
// The actual compass object
private GameObject _compassGameObject = null;
public void Start() {
try {
_Start();
} catch (System.Exception e) {
GrassyKnight.Instance.LogException(
"Error in GrassyCompass.Start()", e);
}
}
private void _Start() {
_compassGameObject = new GameObject(
"Grassy Compass", typeof(SpriteRenderer));
// We'll destroy it when we're destroyed... so hopefully this keeps
// anything else from destroying it until that happens.
UnityEngine.Object.DontDestroyOnLoad(_compassGameObject);
// Create a 1x1 green sprite. Maybe one day we can have a fancy
// arrow sprite 😳
Texture2D texture = new Texture2D(1, 1);
texture.SetPixel(0, 0, Color.green);
texture.Apply();
Sprite sprite = Sprite.Create(
texture,
new Rect(0, 0, 1, 1),
// This makes the pivot point the center of sprite
new Vector2(0.5f, 0.5f),
// And this makes the sprite 1 world unit by 1 world unit. The
// default value makes it 1/100 world unit by 1/100...
1);
SpriteRenderer renderer =
_compassGameObject.GetComponent<SpriteRenderer>();
renderer.sprite = sprite;
// Keep us above everything on the default layer
renderer.sortingOrder = 32767;
renderer.enabled = false;
// Size the sprite to be X of a game unit (though it'll be
// affected by scaling of the knight).
_compassGameObject.transform.parent = gameObject.transform;
_compassGameObject.transform.localScale =
new Vector3(1, 1, 0) * 0.1f;
}
public void Destroy() {
try {
UnityEngine.Object.Destroy(_compassGameObject);
} catch (System.Exception e) {
GrassyKnight.Instance.LogException(
"Error in GrassyCompass.Destroy()", e);
}
}
// Called every frame, best be quick
public void Update() {
try {
_Update();
} catch (System.Exception e) {
GrassyKnight.Instance.LogException(
"Error in GrassyCompass.Update()", e);
}
}
private void _Update() {
if (ToggleHotkey != null &&
Input.GetKeyDown(ToggleHotkey.Value)) {
ToggledOn = !ToggledOn;
string prettyValue = ToggledOn ? "on" : "off";
GrassyKnight.Instance.LogDebug(
$"Toggling Grassy compass. It is now {prettyValue}.");
}
// It seems to be fine with doing it every frame, so we'll do that
if (ToggledOn && AllGrass != null) {
// Can't use the game object's .scene.name because the hero
// (the main object we want to attach this to) and any other
// object set to not get destroyed on load have a garbage
// scene name.
string sceneName = GameManager.instance?.sceneName;
if (sceneName != null) {
GrassKey? nearestGrass = AllGrass.GetNearestUncutGrass(
gameObject.transform.position,
sceneName);
Vector2? newTarget = nearestGrass?.Position;
// Very handy debug message in all sorts of situations
if (newTarget != Target) {
GrassyKnight.Instance.LogDebug(
$"Nearest uncut grass is now '{nearestGrass}'");
}
Target = newTarget;
}
}
if (Target != null) {
// Position of target relative to game object. This'll account
// for rotation, scale, and world position of game object
// properly
Vector3 targetLocalPosition =
gameObject.transform.InverseTransformPoint(Target.Value);
_compassGameObject.transform.localPosition =
Vector3.ClampMagnitude(targetLocalPosition, Radius);
}
// Hide/show the compass appropriately
_compassGameObject.GetComponent<SpriteRenderer>().enabled =
ToggledOn && Target != null;
}
}
}