Об использовании mixins в игровом движке CoffeeScript - PullRequest
3 голосов
/ 29 января 2012

Я работаю над игровым движком CoffeeScript для Html5 canvas.Мне пришла в голову «крутая» идея использовать миксины после того, как я проверил очень аккуратную реализацию CoffeeScript .Я подумал, что это может быть очень крутой идеей - сократить различные иерархии объектов, которые обычно предоставляют игровые объекты, путем разработки набора компонентов на основе миксинов, каждый из которых обладает очень специфической функциональностью.Затем, при разработке реальной игры, можно создавать уникальные игровые объекты на лету, в основном начиная с одного компонента и смешивая его с кучей других компонентов.Это уменьшает иерархии и допускает частые изменения.

Затем я подумал о возможных коллизиях, которые могут возникнуть, например, наличие нескольких компонентов, определяющих метод с одинаковой сигнатурой.Теперь я не так взволнован, как раньше.

Что мне делать?Это хороший способ?Мне все еще нравится это, особенно из-за базового механизма прототипов JS, который позволяет так легко комбинировать вещи на лету.

1 Ответ

10 голосов
/ 29 января 2012

Вы говорите о компонентной системе .Есть пара написана на JS;самый популярный - Crafty , который большой, но стоит посмотреть.Недавно я написал один на CoffeeScript (просто для забавы; вероятно, никогда не выпустит его).

Несколько замечаний о столкновениях:

Итак, во-первых, проблема может быть хуже, чем вы думаете: столкновения будутпроизойдет, если два метода имеют одинаковое имя ;JS не различает сигнатуры функций.Это также может быть не так уж плохо: почему бы вам просто не создать соглашение о пространстве имен, где каждое поведение (смысловой метод) названо в честь компонента, к которому он принадлежит, например, burnable_burn?

Чтобы сделать шагХотя миксины - не единственный способ построить это - поведение (то есть то, что может сделать компонент) вовсе не обязательно должно быть методом.Мотивирующий вопрос, который я задаю: как вы запускаете поведение?Например, вы могли бы сделать:

if entity.hasComponent "burnable" #hasComponent provided by your framework
  entity.burn()

Но мне это не кажется правильным;он создает странную связь между тем, что происходит в вашей игре, и тем, какие компоненты у вас есть, и неудобно проверять, реализуют ли ваши сущности соответствующий компонент.Вместо этого я хотел бы, чтобы поведение было слушателями на событиях :

entity.send("applySeriousHeat") #triggers whatever behaviors are there

И затем ваш компонент делал все, что ему нужно.Поэтому, когда вы добавляете компонент к объекту, он регистрирует слушателей событий.Может быть, это выглядит (просто набросок):

register: (entity) -> #called when you add a component to an entity
  entity.listen "applySeriousHeat", -> #thing I do when this event is sent to me
    #do burnination here

Чтобы довести эту мысль до дома, если вы делаете это, вас не волнуют коллизии, потому что у вашего поведения нет имен.На самом деле, вы хотите "столкновения";вы хотите иметь возможность иметь более одного компонента, отвечающего на одно и то же событие.Может быть, он горит и тает одновременно?

На практике я использовал обе установки вместе.Я сделал entity.addComponent микс в функциях компонента, так как иногда удобно просто вызывать поведение как метод.Но в основном компоненты объявляют прослушиватели, которые вызывают эти методы, что помогло отделить и уменьшило неловкость использования имен с областями, поскольку в большинстве случаев я не вызываю их напрямую.

...