JeuWeb - Crée ton jeu par navigateur
Ajouter des méthodes dynamiquement - 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 : Ajouter des méthodes dynamiquement (/showthread.php?tid=4789)

Pages : 1 2 3 4


Ajouter des méthodes dynamiquement - Roworll - 04-05-2010

Je travaille actuellement sur l'implémentation de capacités spéciales sur les unités (cf mon post sur les wargames tactique).
J'essaye de trouver une solution élégante pour implémenter des méthodes de manière dynamique tout en évitant de surcharger le code.
Celle que j'ai actuellement est d'ailleurs tout sauf élégante...

Voici mon problème.

Chaque unité peut avoir de 0 à n capacité spéciale.
Dans un environnement Objet, ces capacités sont des méthodes permettant de réaliser des actions spécifiques (support aérien, pose de mines, tir de couverture, camouflage, etc).

J'ai vite abandonné l'idée de faire des classes spécifiques héritées de la classe Unité en fonction des capacités spéciales tant la liste et les combinaisons sont grandes.
A coté de ça, je trouve idiot d'implémenter toutes les méthodes de capacités spéciales dans la classe de base alors que chaque unité ne pourra utiliser qu'une partie infime de celles-ci (et c'est sans compter la taille du fichier).

Donc, quelle solution envisageriez vous pour surmonter ce problème et garder un code clair ?

[Edit : changement du titre pour le rendre plus clair]


RE: Méthode dynamiques - barst - 04-05-2010

Tu devrais peut-être aller voir du côté du design pattern "Observer".

Les unités seraient le sujet et tes capacités les observateurs.

En cas d'attaque, ton sujet enverrait l'évènement "Attaque" aux observateurs qui se déclencheraient ou non en fonction de tes propres critères.

Symfony a posté une librairie implémentant ce pattern : http://components.symfony-project.org/event-dispatcher/


RE: Ajouter des méthodes dynamiquement - christouphe - 04-05-2010

pourquoi ne pas utiliser le pattern Strategy, de ce que tu décris, ça collerait parfaitement:

http://www.siteduzero.com/tutoriel-3-65563-les-limites-de-l-heritage-le-pattern-strategy.html

le lien de l'ancre:

http://www.siteduzero.com/tutoriel-3-65563-les-limites-de-l-heritage-le-pattern-strategy.html#ss_part_3


RE: Ajouter des méthodes dynamiquement - khiguard - 04-05-2010

Quel est ta méthode déjà utiliser?

Je ne sais pas si ca pourrait s'appliquer à toi, mais pour Alonya, je travaille avec un système de capacité dynamique, qui fonctionne en module, on peut ajouter sans modifier le code innitiale une infiniter de compétence (attaque, arme de siège, guérison, etc...).

J'ai déjà travailler sur un fichier de compétence qui faisait plusieurs milliers de ligne (à force de rajouter des compétences) et j'ai trouver que c'était très lourd pour le jeu et pas du tout pratique pour la maintenance.

Je travaille en ajax et avec une base de donnée:
- Il y a une table pour les actions: elle contient l'Id de l'action et l'url de celle ci. En fait j 'enregistre le chemin de la page php qui continent l'action (soigner.php par exemple)
- Il y a une deuxième table qui contient les conditions(quel unité? faut il un terrain spécial? faut il qu'il soit sur une ville? etc...)
- Le fichier de lancement des compétences pour le jeu, qui test toute les conditions pour l'unité et affiche seulement celle qu'il a droit de faire (il ne peut pas retirer une foret si l'unité ne se trouve pas sur une foret).
- Quand on lance il lance un test pour savoir si les conditions sont bien respectée et va chercher le lien dans la première table et le lance.

Ce système permet de rajouter très rapidement et facilement une compétence (un fichier de compétence + un ou deux entrée dans les tables et c'est fini). Et la maintenance est très facile.

Si ca correspond à ce que tu souhaite et si ca t'interresse, je peut développer.
@+


RE: Ajouter des méthodes dynamiquement - Argorate - 04-05-2010

J'ai une petit question pour toi khiguard: pourquoi tu stock tout ça en bdd? ça ne serait pas mieux dans un fichier de conf en php, puisque ce sont des données fixe qui ne seront éventuellement modifier que par toi...


RE: Ajouter des méthodes dynamiquement - Roworll - 04-05-2010

En fait, actuellement, j'utilise une classe de base dynamique.
Code PHP :
<?php 
class Dynamic {
function
__call($func, $args) {
$func = strtolower($func);
if(!isset(
$this -> funcs[$func])){
echo
'Action Impossible : "'.$func.'" pour '.$this->get_Name().'<br />';
return
false;
}
$assoc = $this -> funcs[$func];
if (
is_object($assoc))
return
call_user_func_array(array($assoc,$func), $args);
if (!isset(
$assoc)) $assoc = get_class($this);
$argarr = array();
$keys = array_keys($args);
foreach (
$keys as $id => $key)
$argarr[] = '$args[$keys['.$id.']]';
$argstr = implode($argarr, ",");
return eval(
"return $assoc::$func($argstr);");
}

function
import($arg1, $arg2=null) {
assert (is_object($arg1) || class_exists($arg1));
if (isset(
$arg2))
$this -> funcs[strtolower($arg2)] = $arg1;
else
foreach (
get_class_methods($arg1) as $method)
$this -> funcs[strtolower($method)] = $arg1;
}
}

J'ai trouvé la base de ce code sur un article parlant de méthodes dynamiques avec les objets en PHP. La class Dynamic permet donc d'importer les méthodes d'une autre classe (soit toutes les méthodes ou une méthode spécifique)

La classe Unité est une extension de cette classe de base. Elle contient une méthode Load_Specs, invoquée au chargement. Les méthodes "externes" sont importées en fonction du nom de la capacité spéciale.
Code PHP :
<?php 
Class troop extends Dynamic {
...
function
load_Specs($aSpecs){
foreach(
$aSpecs as $Spec){
// Inclusion du fichier externe correspondant à la méthode
require_once 'specs/'.$Spec.'.method.inc';
// Import de toutes les méthodes de la classe dans la classe Unité
$this->import($Spec.'_method');
}
}
}

Le code des méthodes dynamiques est donc encapsulé dans une classe.
Par exemple, pour la capacité spéciale "Charge"
Code PHP :
<?php 
Class charge_method {
public function
Charge($target){
echo
$this->get_name().' Charge '.$target->get_Name();
...
}
}

Au final, dans mon code PHP, je peux faire
Code PHP :
<?php 
$U1
=new Unit('Vikings');
$U2=new Unit('Cavalerie Normande');
$U2->Charge($U1);
$U1->Charge($U2);
Le résultat est
Cavalerie Normande charge Vikings
Action impossible "charge" pour Vikings

Le code présenté ici est un peu épuré car je gère en fait une collection de méthodes ajoutées ainsi que les exceptions (méthodes non disponibles pour les unités).

Au final, je peux donc ajouter des méthodes (capacités spéciales) sur mes classes (unités) à la volée. Personnellement, je trouve que ce n'est pas très propre, notamment à cause de l'Eval dans la classe dynamique. Voila pourquoi je me tourne vers la communauté.


RE: Ajouter des méthodes dynamiquement - khiguard - 04-05-2010

Citation :J'ai une petit question pour toi khiguard: pourquoi tu stock tout ça en bdd? ça ne serait pas mieux dans un fichier de conf en php, puisque ce sont des données fixe qui ne seront éventuellement modifier que par toi...
Le système des unités est beaucoup plus complexe que cela (gestion des capacités, des attributs, des évolutions possibles par l'expérience, etc... tout est dynamique), et j'ai besoin obligatoirement de faire des requêtes complexe, tout du moins du coté admin.

J'ai une interface admin qui me permet de tout modifier en 2,3 clic parce qu'actuellement, il y a beaucoup de changement (ajout d'unité, modification de paramètre, etc...) dont les fichier de config n'est pas pertinent. Mais a terme, j'aimerais que tout ce qui est fixe (mais pas uniquement que les unités) soit intégrer dans un fichier que mon interface créera automatiquement à la demande.

J'ai cela pour les variables javascript par exemple. Il va chercher les données dans la base, les met dans un fichier et l'intègre à la première connexion. Quand on survole un terrain (une plaine par exemple) il affiche sa nature sans aucune requête.
Mais pour le moment, pour autre chose, ca n'est pas intéressant pour moi.

Quand à utiliser des fichiers config que je doit changer manuellement,si tu voulais parler de cela, je ne le ferais jamais, c'est vraiment un calvaire pour la maintenance.

Citation :Au final, je peux donc ajouter des méthodes (capacités spéciales) sur mes classes (unités) à la volée. Personnellement, je trouve que ce n'est pas très propre, notamment à cause de l'Eval dans la classe dynamique. Voila pourquoi je me tourne vers la communauté.
Hum oui, c'est particulier pour des compétences. Par contre comment tu fait pour gérer les conditions d'utilisation d'une compétence avec ton système(si l'unité est sur une bonne case, ou doit être proche d'une autre, etc...)?
Enfin, a moins que toute les unités peuvent utiliser toute leurs compétences partout et tout le temps.
@+


RE: Ajouter des méthodes dynamiquement - Roworll - 04-05-2010

(04-05-2010, 11:48 AM)khiguard a écrit : Hum oui, c'est particulier pour des compétences. Par contre comment tu fait pour gérer les conditions d'utilisation d'une compétence avec ton système(si l'unité est sur une bonne case, ou doit être proche d'une autre, etc...)?
Enfin, a moins que toute les unités peuvent utiliser toute leurs compétences partout et tout le temps.

Les conditions d'utilisations font partie des méthodes incluses dans les classes importées. Par exemple, ma classe Charge contient actuellement deux méthodes
- Une pour lister les cibles possibles
- Une pour résoudre l'action
C'est extensible selon les besoins.

Lors de l'import, toutes les méthodes publiques de la classe Charge sont intégrées à la classe unité et peuvent donc être appelées.
Dans la classe Charge elle même, j'ai accès à toutes les méthodes et attributs publics de la classe Unité en utilisant $this.


RE: Ajouter des méthodes dynamiquement - jo_link_noir - 04-05-2010

(04-05-2010, 11:03 AM)Roworll a écrit : Au final, je peux donc ajouter des méthodes (capacités spéciales) sur mes classes (unités) à la volée. Personnellement, je trouve que ce n'est pas très propre, notamment à cause de l'Eval dans la classe dynamique. Voila pourquoi je me tourne vers la communauté.
Tu ne trouves pas ça propre juste à cause du eval ?

EDIT : Il y a une chose que ne comprend pas, si ça va dans l'eval ça fait un truc du genre
return charge_method::charge($args[$keys[0]]);
Mais comment on peut faire appelle à charge vu qu'elle n'est pas static ?


RE: Ajouter des méthodes dynamiquement - Ter Rowan - 04-05-2010

je suis pas forcément au point pour répondre mais voici mon idée après réflexion aujourd'hui
Code PHP :
<?php 
class troop
{
actions = array();

function
setAction($action, $strategy)
{
$this->actions[$action] = new $strategy;
}

function
launchAction($action, $params)
{
if (isset(
$this->actions[$action]))
return
$this->actions[$action]->launch($params);
else
throw new
Exception($action.' n est pas disponible !!!');
}
}

chacune de tes classes unités héritent de la class troop et tu génères (fichier de référence, directement dans la classe, en bdd, etc... ) la liste action / strategy à "setter" via setAction

après tu fonctionnes sur le pattern strategy (genre pour l'action "charger" il y a diverses stratégies : la stratégie pour les unités lourdes, pour les unités montées, etc...)
chacune de tes stratégies possède la méthode launch($params)

conclusion pour connaitre la liste des actions disponibles pour une unité :

Code PHP :
<?php 
foreach ($this->actions as $act => $idAct)
{
echo
'je peux '.$idAct.'<br/>';
}
pour lancer une action à la troupe :

Code PHP :
<?php 
$maTroupe
->launchAction('charger', array('target' => "l'autre là", 'how' => "en hurlant wouah Ter Rowan le roxxor");

alors la question, où ai je faux ? ^^