JeuWeb - Crée ton jeu par navigateur
Javascript comme traducteur ? - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : Javascript comme traducteur ? (/showthread.php?tid=5865)



Javascript comme traducteur ? - Ter Rowan - 18-12-2011

Coucou

J'ai eu une idée en réfléchissant à comment traiter les messages que le serveur enverrait au joueur
J'aimerais vous la soumettre, elle est peut être contre productive, mais j'aimerais avoir vos avis avant d'imaginer partir la dessus

Dans le cadre d'un jeu asynchrone, le joueur lance une action et attend une réponse

cette réponse est à mon sens de trois ordres :

1) un message explicatif :
Citation :Vous avez réussi à trouver un schrubuluck
Votre énergie a baissé de 15 points

2) la création de nouveaux objets (côté client)
ici il faut afficher le schrubuluck avec les ressources associées (image, et ses infos : quantité, position dans l'inventaire ou ailleurs, etc...)

3) la modification d'objets existants (côté client)
ici l'énergie du personnage qui doit baisser de 15 points

au final les données envoyées pour la suite du gameplay (a savoir 2 et 3) permette de déduire le message 1, à une exception près :

2) et 3) sont des données à destination du navigateur (des chiffres, des liens, etc...), et non du joueur (pas évident de se dire que t_f_2 = 45 veut dire que son énergie est passé de 60, ancienne à valeur, à 45 )


et donc je me suis dit pourquoi surcharger le serveur, la bande passante, et tout le toutim, a envoyer une information dupliquée, une fois pour le navigateur, une fois en langage "naturel" pour le joueur ?

d'où ma proposition:

à la première connexion du joueur, lors de sa création (on prend du temps à la création du compte au moins une minute donc ca devrait être transparent, sinon on communique au joueur comme quoi on charge des éléments pour son confort de jeu), on télécharge un fichier javascript spécialisé dans la traduction dans la langue du joueur des infos à destination du navigateur

genre j'envoie :
{"action":2,"object":[3,1,'schru.jpg'],"trait":{"t_f_2":45}}

et de fait le javascript sait que

action:2 = "vous avez réussi à trouver "
object[3,] = schrubuluck
object[1,] = quantité de 1
action:2+object[3,1] ==> "vous avez réussi à trouver un schrubuluck"

et trait t_f_2 donnera "énergie"
on compare 45 à l'ancienne valeur, et on en déduit qu'il faut afficher

"Votre énergie à baisser de 15 elle vaut désormais 45"

dans le même temps le système interprète l'affichage des différents éléments


de fait on réduit sensiblement la volumétrie des données transférées (en s'appuyant sur le cache navigateur pour le fichier javascript)

qu'en pensez vous ?


RE: javascript comme traducteur ? - Sephi-Chan - 18-12-2011

Je ne suis pas sûr de bien comprendre la problématique. Quand le serveur retourne le bilan d'une action au joueur, tu peux tout à faite te limiter au minimum de données nécessaires.


Par exemple, dans Conquest on Rails, j'ai plusieurs situations de ce type, à la différence près que dans mon cas, il ne s'agit pas de retour individuel : ce sont plutôt des messages envoyés à plusieurs joueurs. Quelques exemples :
  • Un joueur se joint à une partie, les autres participants sont notifiés. Cela se manifeste par un emplacement libre de la salle d'attente qui se remplit du nom d'un joueur.
  • La partie démarre, tous les joueurs sont notifiés. Cela se manifeste par un bouton "Rejoindre la partie" qui passe de grisé à allumé.
  • Au sein de la partie, un joueur en attaque un autre, les autres sont notifiés. Cela se manifeste par des textes "-2 unités", des changements de couleur du territoire, etc.

Pour l'implémentation, côté serveur j'envoie un petit objet JSON en push :


# Indique aux participants qu'un autre participant a rejoint la partie.
Juggernaut.publish("games/#{@participation.game_id}", {
eventType: "PLAYER_JOIN",
color: @participation.color,
gameId: @participation.game_id
})


# Envoie aux participants le résultat d'un combat.
Juggernaut.publish("games/#{@game.id}", {
eventType: "ATTACK_REPORT",
attacker: {
unitsLoss: @attack.attacker_losses,
territoryId: @attacker.territory_id,
color: @attacker.participation.color,
winner: @attacker == @attack.winner,
unitsCount: @attack.attackers_count,
remainingUnitsCount: @attack.remaining_attackers_count
},
target: {
unitsLoss: @attack.defender_losses,
territoryId: @target.territory_id,
color: @target.participation.color
}
})


Comme on peut voir, le volume de données est plutôt faible puisque ce sont presque essentiellement des nombres et de petites chaînes de caractères.


Côté client, je traite le message qui arrive (ici c'est du CoffeeScript, qui est compilé en bon vieux Javascript). Comme je le disais, dans mon cas c'est un push mais ça pourrait être un retour de requête Ajax) :


juggernaut.singleSubscribe channel, (data)->
handlers[data.eventType](data)

Ici, j'utilise un hash tout bête qui contient associe un type d'événement (PLAYER_JOIN, ATTACK_REPORT, etc.) à une fonction qui accepte un hash de données. Finalement, je ne fais que déléguer les données reçue à la bonne fonction (stockée dans handlers["PLAYER_JOIN"]).


handlers =
# Colorize the placeholder.
PLAYER_JOIN: (data)->
$participation = $(".participation[data-game=#{data.gameId}]")
$placeholder = $participation.find(".#{data.color}_placeholder")

$placeholder.addClass(data.color)
$placeholder.removeClass("nobody")


# Enable the button.
START: (data)->
$participation = $(".participation[data-game=#{data.gameId}]")
$button = $participation.find("a")

$button.text($button.data("enable-with"))
$button.removeClass("disabled")
$button.addClass("success")


# Display visual feedback for the attack.
ATTACK_REPORT: (data)->
attacker = data.attacker
target = data.target

$attackerBadge = $("#badge_territory_#{attacker.territoryId}")
$targetBadge = $("#badge_territory_#{target.territoryId}")

showFloatingLoss($attackerBadge, attacker.unitsLoss)
showFloatingLoss($targetBadge, target.unitsLoss)

if data.attacker.winner
removeUnitsFromBadge($attackerBadge, attacker.unitsCount)
changeBadgeOwnership($targetBadge, attacker.remainingUnitsCount, attacker.color)

else
removeUnitsFromBadge($attackerBadge, attacker.unitsLoss)
removeUnitsFromBadge($targetBadge, target.unitsLoss)


Comme tu peux le voir, je n'affiche pas de texte, mais le mécanisme resterai le même si je le faisais : j'utiliserais en plus un framework d'internationalisation en Javascript.

Est-ce que ça répond à ta question ou te donne des pistes ?


RE: javascript comme traducteur ? - Ter Rowan - 18-12-2011

(18-12-2011, 08:48 PM)Sephi-Chan a écrit : Comme tu peux le voir, je n'affiche pas de texte, mais le mécanisme resterai le même si je le faisais : j'utiliserais en plus un framework d'internationalisation en Javascript.

Est-ce que ça répond à ta question ou te donne des pistes ?

je crois :
mon sujet était de savoir si il était pertinent que ce soit javascript qui réalise le texte

en français : "vous trouvez la chose"
en anglais : "you find the thing" (choix du temps pas sûr :p)

tout ça avec la même donnée envoyée par le serveur

ce n'est donc ni php ni ruby ni ... qui traduisent mais javascript


est ce que ton framework d'internationalisation fonctionne ainsi (ie sans appel au serveur pour le choix des mots / phrases) ?







RE: javascript comme traducteur ? - Sephi-Chan - 18-12-2011

Les frameworks d'internationalisation associent une clé à un message (qui supporte l'interpolation).
Exemple avec jQuery i18n (disponible sur GitHub).


// On définit le dictionnaire, par exemple dans un fichier "translations.fr.js".
$.i18n.setDictionary({
player_joins_game: "%s rejoint la partie %d."
game_starts: "Que la partie commence !"
});


// Puis on l'utilise… Où on veut !
$.i18n._('player_joins_game', [ "Corwin", 42 ]);


// N'hésite pas à te faire un alias.
window.t = function(key, interpolations){
return $.i18n._(key, interpolations);
};

// Ça peut être plus sympa à utiliser.
t('player_joins_game', [ "Corwin", 42 ]);


Donc dans mon exemple, c'est bien moi qui définit le callback selon le type d'événement qui me vient du serveur : un callback quand un joueur rejoint la partie, un callback quand la partie démarre, un callback pour traiter le résultat d'une attaque, etc. A toi d'être malin quant aux données que renvoient les actions de ton serveur. Smile


RE: Javascript comme traducteur ? - Ter Rowan - 18-12-2011

je ne savais pas si c'était une bonne idée ou non
donc tant mieux si c est pas couillon ^^

merci pour la ressource

il faudra que je surcharge pour avoir des fonctionnalités du type récursif



$.i18n.setDictionary({
player_create: "%s crée %d %s."
object1: "balai"
});

t('player_create', [ "Corwin", object1, 3 ]);
t('player_create', [ "Corwin", object1, 1 ]);

qui donnerait
Citation : Corwin crée 3 balais.
Corwin crée 1 balai.




RE: Javascript comme traducteur ? - atra27 - 19-12-2011

y à pas moyen de créer un namespace qui renvoye un texte différent suivant que l'argument est 1, 2 ou 3, etc... ??
car la sinon tu doit utiliser object1 puis object2
le mieux serait:

t.('objects', [1])
Qui donnerai la string correspondant à l'objet 1[/code]


RE: Javascript comme traducteur ? - Sephi-Chan - 19-12-2011

Je ne sais pas. Le plus simple, c'est de toute façon de se faire des helpers. Des petites fonctions genre tObject(objectId), tSkill(skillId), etc.


RE: Javascript comme traducteur ? - atra27 - 19-12-2011

Dommage...
ça aurai pu être utile...


RE: Javascript comme traducteur ? - Viciousity - 19-12-2011

Ou utiliser une fonction du genre :

def pluralize(singular, plural, count)
"#{count} #{count ==1 ? singular : plural}"
end
# Que tu ulitises comme ceci:
pluralize('vache','vaches',3)