Разделять код на миллион монобехов != ооп. Единственный способ достичь правильного ооп в юнити - отделять всю логику от движка, а монобехи использовать как вьюшку, чтобы отображать всякое. Но реализуемый для тебя способ - использовать интерфейсы, под каждый паблик метод отдельный интерфейс, взаимодействовать через эти интерфейсы, учиться нормально прокидывать зависимости: всегда должна быть какая-то точка входа, где будут инициализироваться компоненты и передаваться все зависимости.
Virtual методы = плохо, класс в идеале должен быть либо abstract либо sealed.
Protected поля = public поля = нарушение инкапсуляции/иммутабельности.
PlayerHealth, PlayerEnergy, Health - это все одно и то же с разными реализациями, есть интерфейс IHealth все под него и просто этот интерфейс реализуешь.
AudioPlayer вообще какой-то ужас. Во-первых, почему GameObject takeDamageSourseObject и т.д Почему GameObject, если ты потом получаешь у него компонент AudioSource, ты можешь конкретные компоненты в инспекторе передавать, т.е. не GameObject, a AudioSource и GetComponent потом делать не нужно будет. Во-вторых, из всего этого можно было сделать один компонент, в котором будет один метод Play, который будет принимать AudioSource и проигрывать его. Либо напрямую пропихивать AudioSource и воспроизводить звук.
Нет какого-то единого кодстайла, где-то есть нижнее подчеркивание, где-то нет, где-то есть _cs где-то нет, для чего эта _cs я так и не понял. Где-то сериализуемое приватное поле, где-то тупо паблик.
Про солид вообще смысла говорить нет. Интерфейсов пара штук на весь проект. Зависимости нормально не прокидываются, всё через поля.
Это так, навскидку. Думаю, если зайти в папку bot, то можно будет диссертацию написать по содержимому этой папки.