O Esfinge Gamification está disponível no Maven Central
O Esfinge Gamification é um framework baseado em metadados aplicável aos sistemas que necessitam de uma lógica gamification, independentemente do seu domínio. O principal objetivo do framework é dissociar as preocupações de gamification da aplicação, permitindo que os desenvolvedores se concentrem na lógica da aplicação, acrescentando apenas informação sobre como a gamification deve trabalhar em cada funcionalidade invocada. O framework intercepta estas invocações e executa a lógica gamification apropriada, este também fornece pontos de extensão que permitem a introdução de comportamentos gamification específicos da aplicação.
O Esfinge Gamification define vários tipos de conquistas e diferentes implementações para armazenar informações gamification sobre os usuários. Para registrar como a gamification deve ser manuseada na aplicação, o framework usa anotações que devem ser adicionadas aos métodos de negócio nas classes de aplicação. O framework proposto pode ser facilmente integrado em qualquer aplicação Java, sendo responsável por registrar as conquistas do usuário sem depender de qualquer informação relacionada com o domínio específico da aplicação. Ele fornece também uma API que pode ser acessada diretamente pelo aplicativo para recuperar e mostrar informações relacionadas com as conquistas do usuário, tais como sua pontuação ou sua posição no ranking.
Instanciando o framework
Game
. O framework
fornece algumas implementações que armazenam essas informações
em arquivos, em memória e em um banco de dados; no entanto, o
aplicativo pode criar sua própria implementação para ele. Este
exemplo é configurado chamando o método setGame()
no GameInvoker.
//configure game
Game g = new GameMemoryStorage();
GameInvoker.getInstance().setGame(g);
//current user
UserStorage.setUserID("spider");
Outra configuração importante apresentada no código anterior é o usuário atual.
O método setUserID()
na classe UserStorage
deve ser chamado
para configurar o usuário e para ser usado pelo framework na thread atual.
Assim, todos os métodos invocados na thread atual que desencadeiam a lógica
gamification usarão este usuário como uma referência. O parâmetro deve ser qualquer
identificação do usuário, este será utilizado para fins de armazenamento e de recuperação dos
dados.
Por exemplo, para criar uma instância do framework em uma aplicação web, um filtro web
deve ser criado para configurar o usuário atual em cada solicitação recebida.
O próximo passo é adicionar as anotações gamification
adequadas sobre as interfaces dos aplicativos. Os métodos escolhidos para serem anotados devem
representar a ação no domínio do aplicativo que deve acionar a lógica gamification.
O código a seguir ilustra o uso da anotação
@PointsToUser
.
Com base na configuração, quando uma implementação do método answerQuestion()
é
invocado,
o framework gamification deve adicionar 10 pontos de resposta para o usuário atual.
É importante ressaltar que existem outras anotações fornecidos pela
estrutura,
e também um ponto de extensão que permite a criação de anotações
personalizadas.
public interface Questionnaire {
@PointsToUser(name = "ANSWER", quantity = 10)
public void answerQuestion(String answer);
}
createProxy()
da classe GameProxy
deve ser invocado. Ele recebe uma
instância da implementação e retorna um proxy dinâmico que implementa todas
as suas interfaces. O código a seguir apresenta um exemplo de como isso deve ser feito. É aconselhável
encapsular essa lógica de criação de uma classe factory.Questionnaire q = (Questionnaire) GameProxy.createProxy(new
QuestionnaireImpl());
Para finalizar, o aplicativo pode usar a API do framework para acessar diretamente os dados
gamification.
Esta API está disponível através da implementação do classe Game
, que pode ser
recuperada usando o comando GameInvoker.getInstance().getGame()
. Quando o
aplicativo precisar de informações gamification, esta deve ser a única lógica de negócios
que
tem acesso direto ao framework.
Estrutura interna
Sobre como implementar os modelos
Tipos de conquistas
O framework usa um sistema de recompensa no qual o usuário pode receber um certo tipo de
conquista
quando uma tarefa é executada ou realizada no aplicativo. Conforme ilustrado na figura
abaixo, no Esfinge Gamification, quatro tipos de conquistas podem ser
encontradas:
Ponto, Classificação, Recompensa e Troféu. A interface Achievement
também pode ser estendida para incluir outros tipos de recompensas.
O tipo Ponto representa um affordance que contém uma medida de número discreto, tais como pontos ou moedas, que podem ser utilizados para alcançar outras conquistas, ou para usar dentro do próprio sistema. O mesmo sistema pode ter diferentes tipos de Ponto. O tipo Ranking representa um nível de usuário escalar (semelhante a uma hierarquia militar), e é descrito por dois atributos, um nome e um nível. Ele pode ser usado para explicar a melhoria de alguma tarefa do usuário ou representar o seu status. Por exemplo, quando uma tarefa é concluída com êxito um certo número de vezes, o usuário pode subir um nível naquela habilidade. Isso incentiva o usuário a explorar as tarefas a serem realizadas e também melhorar o trabalho realizado.
A conquista de Recompensa representa algo que o usuário ganha e pode gastar. As suas características são um nome e uma variável booleana que indica se a Recompensa já foi usada. O usuário mantém esta Recompensa até que ele decida usá-la para algum propósito. Por exemplo, se a Recompensa é um cupom de desconto, ele estará disponível até que o usuário o utilize. O tipo Troféu, que é semelhante ao de distintivos, como no mundo real, descreve um prêmio recebido apenas uma vez. O usuário pode receber um Troféu para a realização de uma tarefa, mas ele não vai ganhar de novo se ele repetir a mesma tarefa.
Novos tipos de realizações podem ser adicionados ao implementar a interface
Achievement
.
Esta interface possui métodos para definir o que deve ser feito quando uma nova
conquista
desse tipo é adicionado para um usuário. A seguir estão os métodos definidos por esta
interface:
public String getName()
: retorna o nome de identificação da
conquista.public void addAchievement(Object user, Achievement achievement)
:
usado para
atribuir um usuário a uma conquista, tando no caso de inserção como no
caso de upgrade.public void removeAchievement(Object user, Achievement achievement)
:
usado para
remover uma conquista de um determinado usuário. Dependendo do tipo de
conquista,
a operação pode ser efetuada uma supressão ou de atualização.Gerenciamento de conquistas
Além da interface Achievement
e suas implementações, o framework define um
componente cuja função é armazenar as conquistas. A classe abstrata
Game
encapsula a mecânica gamification de armazenamento. Ele define métodos
abstratos que devem ser implementados a fim de dar as ações apropriadas para atribuir
ou remover conquistas do usuário. Atualmente, quatro subclasses de jogo estão
disponíveis: GameMemoryStorage
, que mantém dados armazenados apenas na
memória; GameFileStorage
, que armazena os resultados em um arquivo de
propriedades; GameDatabaseStorage
, que salva os affordances em
um banco de dados SQL; e GameMongoStorage
, que salva os dados em um banco
de dados não relacional.
Os métodos relativos à armazenagem de conquistas são:
public abstract void insertAchievement (Object user, Achievement achievement)
:
define o que deve ser feito para atribuir uma nova conquista para um
usuário.public abstract void deleteAchievement (Object user, Achievement achievement)
:
define o que deve ser feito para eliminar uma conquista de um usuário.
public abstract void updateAchievement (Object user, Achievement achievement)
:
define o que deve ser feito para mudar uma conquista que o usuário
possui.public abstract Achievement getAchievement (Object user, String achievementName)
:
define a forma de recuperar dados de conquista de um usuário.public abstract Map <String, Achievement> getAchievements (Object user)
:
configura como recuperar todas as conquistas de um usuário.public abstract Map <String, Achievement> getAllAchievements(Class achievementType)
:
configura como recuperar todas as conquistas de um tipo.As subclasses concretas do jogo devem gerenciar as conquistas sem o uso de seus tipos concretos. Isto é importante para permitir a extensão dos tipos de conquista.
As implementações da classe Game
podem fornecer métodos mais específicos para
consultar as informações gamification. Por exemplo, pode haver métodos para
recuperar as classificações ou para localizar a posição do usuário. Em
versões futuras esses recursos devem ser padronizados na API do framework.
Metadados gamification
Além da criação e armazenamento de conquistas, as operações que adicionam ou removem as conquistas podem ser configuradas através de anotações para serem acionadas com base na invocação de métodos de interface do aplicativo. A lista de anotações fornecidos pelo framework Esfinge Gamification para a configuração das conquistas é descrita abaixo.
Anotações | Descrição geral |
@PointsToUser, @RankingsToUser, |
Estas anotações permitem o incremento de uma implementação de conquistas para o usuário atual. |
@RemoveRankings, @RemovePoints,
|
Estas anotações permitem a eliminação de uma implementação de conquistas de um determinado usuário. |
@PointToParam |
Esta anotação permite o incremento de Pontos para outro usuário, ou seja, a ação do usuário logado no sistema gera pontos para outro usuário. |
@AllowPointGreaterThan, @AllowPointLessOrEqualsThan,
|
Estas anotações verificam se os pontos respeitam as restrições de maior ou menor igual a uma determinada quantidade de pontos definida na anotação para que a autorização seja permitida ou não. |
@AllowTrophy, @DenyTrophy
|
Estas anotações verificam o acesso de usuários a recursos protegidos com a restrição de troféu, isto é, quando algum usuário possuir o troféu conseguirá ou não acessar o recurso. |
@AllowReward, @DenyReward
|
Estas anotações verificam o acesso de usuários a recursos protegidos com a restrição de recompensa, isto é, quando algum usuário possuir o recompensa conseguirá ou não acessar o recurso. |
@AllowRanking, @AllowLevel, @AllowRankingAndLevel, @AllowRankingOrLevel,
|
As anotações de ranking possuem a mesma lógica das anteriores, porém, visando os recursos do ranking, permitindo e não permitindo o acesso a recursos com as restrições de ranking e level. |
É importante ressaltar que a anotação
@PointsToParam
pode fazer uso da anotação @Named
para
rotular o parâmetro que contém o ID do usuário que deve
receber os pontos.
Abaixo, exemplifica-se como estas anotações
devem ser configuradas em uma interface do aplicativo.
public interface ITestAnnotations {
@PointsToUser(name = "GOLD", quantity = 1000)
public void doSomething();
@RewardsToUser(Name = "lunch", used = false)
public void doSomethingRemarcable();
@RemovePoints(name = "GOLD", quantity = 500)
public void doBadThing();
@RemoveReward(Name = "lunch", used = true)
public void useReward();
@PointsToParam (name = "SILVER", quantity = 100, param = "owner")
public void niceComment(String comment, @Named("owner") String owner);
@PointsToParam (name = "SILVER", quantity = 300, param = "comment"
prop ="user.login")
public void niceComment(@Named("comment") Comment c); }
param
. O atributo da anotação
param
refere-se ao nome de atributo, marcado pela anotação
@Named
,
que contém o ID de usuário. O atributo prop
pode ser utilizado
para configurar o estabelecimento de parâmetros que contém a informação. Pontos de extensão
O framework Esfinge Gamification tem dois pontos de extensão internos: um
que configura a persistência e outro que permite a adição de novos tipos de
conquistas.
A persistência pode ser estendida para ser compatível com o que é usado na
aplicação. Este ponto de extensão pode ser ampliado através da criação de
uma nova subclasse da classe abstrata Game
e configurado na classe
GameInvoker
.
Para criar novos tipos de conquistas, o primeiro passo é criar uma nova
implementação da interface Achievement
, que define as regras para a
adição e remoção de tais conquistas. O mecanismo de persistência deve
também estar pronto para lidar com essas conquistas e devem ser criadas
anotações para desencadear ações para a sua gestão.
Alguns detalhes para esses pontos de extensão foram apresentadas nas seções
anteriores.
@PointsToUser
para ilustrar como esta
extensão funciona. Todas as anotações gamification
devem possuir uma anotação @GamificationProcessor
que configura a classe do processador relacionado.@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @GamificationProcessor(PointsToUserProcessor.class) public @interface PointsToUser { int quantity(); String name(); }
A classe configurada na anotação deve implementar a
interface AchievementProcessor
. Essa interface define o método
receiveAnnotation()
,
que é responsável por interpretar a anotação, recuperando
informações de seus atributos específicos. O método process()
é
responsável por executar a ação na lógica gamification relacionada com a
anotação. Nesta classe específica que dá pontos para o
usuário atual.
public class PointsToUserProcessor implements AchievementProcessor { private int quantity; private String name; @Override public void receiveAnnotation(Annotation an) { PointsToUser ptu = (PointsToUser) an; quantity = ptu.quantity(); name = ptu.name(); } @Override public void process(Game game, Object encapsulated, Method method, Object[] args) { Object currentUser = UserStorage.getUserID(); Point p = new Point(quantity, name); game.addAchievement(currentUser, p); } }
É importante destacar que este mecanismo pode ser usado para adicionar lógica específica do aplicativo diferente para o framework. Por exemplo, uma anotação pode configurar pontos para o usuário atual, a alguém relacionado com a ação do usuário, e até mesmo para grupo ou uma equipe em que o usuário participa. No entanto, usando esta abordagem, as ações relacionadas com o gamification são dissociados das classes de aplicação, estando relacionadas apenas por seus metadados.
Apoio