Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Conception, modele object d'un jeu.

10 réponses
Avatar
Guillaume Bouchard
Bonjour à tous,

J'ai enfin décider de me lancer dans ma première grosse application en
Python.
Malheureusement j'ai encore du mal à penser en object et en modularité
lors de la conception (je viens du php dans lequel ces concepts sont
inconnus car inutile dans le cadre du dev web).

Mais voila, j'ai beau réflechir à l'implentation du jeu, je ne vois pas
trop comment faire.

J'esseye de coder un clone de Confrontation pour ceux qui conaissent, un
jeu de figurines fait par une boite française.

Le principe est plutôt simple, chaques tour est facilement identifiable
en phases distinctes.

Ce qui me pose de gros problèmes c'est les personnages.
Chaques personnages à des caracteristiques qui seront prisent en compte
lors de cesjets de dé. Jusque là tout vas bien.
Malheureusement, chaques personnages à des compétances. Ces compétances
allouent des capacitées speciales, quelques exemples:

- 2 fois plus de mouvement dans un tour
- ignorer les echecs lors d'un tir.
- faire son mouvement dans une autre phrase que la phase de mouvement
- tirer lors de la phrase de mouvement
- doubler la force lors du premier assaut.
- lors d'une blessure, calculer les points de vie perdues avec 3 dé
aulieu de deux.

J'ai donc envis de prendre tout cela en compte, mais imaginons ma classe
de résolution du tir:

gna gna gna
if personnage.tir.reussite():
# appliquer les dégats
gna gna gna

Ça c'est le fonctionement normal

imaginons la fonction reussite :

valeur = random.randrange(6)
if valeur == 0:
return false
else:
return true

Vous l'avez comprit, un 1(ici un 0) sur le jet de dé est un echec.
Or mon personnages possede la compétance tireur d'élite qui lui permet
d'éviter cet echec. Ce que je ferais c'est:

valeur = random.randrange(6)
if valeur == 0 and not competance.tireur_elite:
return false
else:
return true

Cela fonctionnera parfaitement.

Seulement je n'aime pas cette méthode. Le jour ou je devrais rajouter
d'autres compétances, il va faloir que j'aille modifier le corps du
programme, ce qui ne colle pas vraiment à ma philosophie de séparation
du code et de reutilisation.

Bref, j'aimerais savoir comment vous implanteriez ce systeme de compétances.

--
Guillaume.

10 réponses

Avatar
Didier FRAISSE
Bonjour à tous,

J'ai enfin décider de me lancer dans ma première grosse application en
Python.
Malheureusement j'ai encore du mal à penser en object et en modularité
lors de la conception (je viens du php dans lequel ces concepts sont
inconnus car inutile dans le cadre du dev web).

Mais voila, j'ai beau réflechir à l'implentation du jeu, je ne vois pas
trop comment faire.

J'esseye de coder un clone de Confrontation pour ceux qui conaissent, un
jeu de figurines fait par une boite française.

Le principe est plutôt simple, chaques tour est facilement identifiable
en phases distinctes.

Ce qui me pose de gros problèmes c'est les personnages.
Chaques personnages à des caracteristiques qui seront prisent en compte
lors de cesjets de dé. Jusque là tout vas bien.
Malheureusement, chaques personnages à des compétances. Ces compétances
allouent des capacitées speciales, quelques exemples:

- 2 fois plus de mouvement dans un tour
- ignorer les echecs lors d'un tir.
- faire son mouvement dans une autre phrase que la phase de mouvement
- tirer lors de la phrase de mouvement
- doubler la force lors du premier assaut.
- lors d'une blessure, calculer les points de vie perdues avec 3 dé
aulieu de deux.

J'ai donc envis de prendre tout cela en compte, mais imaginons ma classe
de résolution du tir:

gna gna gna
if personnage.tir.reussite():
# appliquer les dégats
gna gna gna

Ça c'est le fonctionement normal

imaginons la fonction reussite :

valeur = random.randrange(6)
if valeur == 0:
return false
else:
return true

Vous l'avez comprit, un 1(ici un 0) sur le jet de dé est un echec.
Or mon personnages possede la compétance tireur d'élite qui lui permet
d'éviter cet echec. Ce que je ferais c'est:

valeur = random.randrange(6)
if valeur == 0 and not competance.tireur_elite:
return false
else:
return true

Cela fonctionnera parfaitement.

Seulement je n'aime pas cette méthode. Le jour ou je devrais rajouter
d'autres compétances, il va faloir que j'aille modifier le corps du
programme, ce qui ne colle pas vraiment à ma philosophie de séparation
du code et de reutilisation.

Bref, j'aimerais savoir comment vous implanteriez ce systeme de
compétances.

Pour le peu que je connais à la programmation objet, il me semble que tu

résouds celà par héritage et en surchargeant ta fonction

class Soldat:
def reussite():
valeur = random.randrange(6)
if valeur == 0: return false
else: return true

class TireurElite(Soldat):
def reussite(): return true

Avatar
Guillaume Bouchard
Didier FRAISSE wrote:
Pour le peu que je connais à la programmation objet, il me semble que tu
résouds celà par héritage et en surchargeant ta fonction


Sauf que si un tireur d'elite est aussi tireur de precision et que sur 6
il augmente les dégats, je fait comment ?

Le probleme etant que ce n'est pas une classe de personnage (mage,
guerrier, tireur, avec ces parametres bien propres, un mage n'étant en
aucun cas un guerrier) c'est un personnages avec des compétances qui se
chevauchent les une les autres.

Un mage peut être "chanceux" et "mou". L'une des classe permet d'eviter
le coup de l'adversaire si celui-ci fait 1 ou 2 et l'autre fait que les
dégats sont augmentés sur 5 et 6 (aulieu de 6 normalement).

Bref, c'est encore tordu tout cela.

--
Guillaume.

Avatar
kaerbuhez
Didier FRAISSE wrote:

Pour le peu que je connais à la programmation objet, il me semble que
tu résouds celà par héritage et en surchargeant ta fonction



Sauf que si un tireur d'elite est aussi tireur de precision et que sur 6
il augmente les dégats, je fait comment ?

Le probleme etant que ce n'est pas une classe de personnage (mage,
guerrier, tireur, avec ces parametres bien propres, un mage n'étant en
aucun cas un guerrier) c'est un personnages avec des compétances qui se
chevauchent les une les autres.

Un mage peut être "chanceux" et "mou". L'une des classe permet d'eviter
le coup de l'adversaire si celui-ci fait 1 ou 2 et l'autre fait que les
dégats sont augmentés sur 5 et 6 (aulieu de 6 normalement).

Bref, c'est encore tordu tout cela.

Sur base de ce que tu dis, je suggére:

- une classe Competence (avec éventuellement une sous-classe par type de
compétence) qui encapsule tout ce qui concerne spécifiquement une
compétence.
- une classe Personnage délégant à autant d'instance de
(sous-?)Competence que nécessaire.

Si tu as du mal a définir les interfaces de tes classes (commence par
ça), je te suggére d'écrire la définition de tes classes en 3 lignes
maximum. Ca aide parfois.


Avatar
tiissa
La comme ca, j'essaierai peut-etre en utilisant des filtres.
Ainsi ma procedure de resolution de reussite de tir aurait un
comportement de base et ensuite passerait en revue toutes les
competences pour voir si elles modifient la reussite.

Ca pourrait donner quelque chose comme :

#### jeutest.py ####
import random

class Precision(object):
def modif_dmg(self, (jet, valeur)):
return (jet, valeur + 6)


class Elite(Precision):
def modif_tir(self, (jet, reussite)):
return (jet, True)


class ClasseBase(object):
def __init__(self, nom):
self.nom = nom
self.agilite = 2
self.force = 1

def base_tir(self, jet):
if ((jet+self.agilite) < 6) or (jet == 1):
return (jet, False)
else:
return (jet, True)

def base_dmg(self, jet):
return (jet, jet+self.force)


class Joueur(ClasseBase):
def __init__(self, nom):
super(Joueur, self).__init__(nom)
self.competences = []

def ajoute_competence(self, competence):
self.competences.append(competence)

def vise(self, jet):
tir = self.base_tir(jet)
for c in self.competences:
try:
tir = c.modif_tir(tir)
except AttributeError:
pass
return tir[1]

def degats(self, jet):
dmg = self.base_dmg(jet)
for c in self.competences:
try:
dmg = c.modif_dmg(dmg)
except AttributeError:
pass
return dmg[1]

def tire(self, de):
if self.vise(de.randint(1, 6)):
print "%s fait %d degats."
%(self.nom, self.degats(de.randint(1, 6)))
else:
print "%s rate."%self.nom

joe, bill = Joueur('Joe'), Joueur('Bill')
joe.ajoute_competence(Elite())
bill.ajoute_competence(Precision())

de = random.Random()

joe.tire(de)
bill.tire(de)
########

Ca donne :

python jeutest.py
Joe fait 9 degats.

Bill fait 8 degats.
python jeutest.py
Joe fait 8 degats.

Bill rate.




Ca suppose quand meme que l'ordre des competences n'est pas important
(mais il y a peut-etre moyen de s'arranger avec les heritages entre
competences en appelant le filtre de la competence mere avant le sien
par exemple).
Et evidemment il faudrait reflechir un peu plus aux classes.

Avatar
Guillaume Bouchard
wrote:
La comme ca, j'essaierai peut-etre en utilisant des filtres.
Ainsi ma procedure de resolution de reussite de tir aurait un
comportement de base et ensuite passerait en revue toutes les
competences pour voir si elles modifient la reussite.


Hum, interessant comme concept.

Ca pourrait donner quelque chose comme :


Merci pour le code.

Ca suppose quand meme que l'ordre des competences n'est pas important


Non, l'ordre n'est pas important, celle-ci sont juste cumulatif.

Merci, la solution commence à se dessiner dans ma tete.

--
Guillaume.

Avatar
bruno modulix
Guillaume Bouchard wrote:
Bonjour à tous,

(snip)

Malheureusement j'ai encore du mal à penser en object et en modularité
lors de la conception (je viens du php dans lequel ces concepts sont
inconnus


A peu près, en effet...

car inutile dans le cadre du dev web).


Pas du tout, bien au contraire.


(snip)>

Ce qui me pose de gros problèmes c'est les personnages.
Chaques personnages à des caracteristiques qui seront prisent en compte
lors de cesjets de dé. Jusque là tout vas bien.
Malheureusement, chaques personnages à des compétances. Ces compétances
allouent des capacitées speciales, quelques exemples:

- 2 fois plus de mouvement dans un tour
- ignorer les echecs lors d'un tir.
- faire son mouvement dans une autre phrase que la phase de mouvement
- tirer lors de la phrase de mouvement
- doubler la force lors du premier assaut.
- lors d'une blessure, calculer les points de vie perdues avec 3 dé
aulieu de deux.


Bref, pour chaque action, il y a une règle générale et des cas
particuliers dépendants des caractéristiques des personnages (au sens
large...) impliqués.


J'ai donc envis de prendre tout cela en compte, mais imaginons ma classe
de résolution du tir:

gna gna gna
if personnage.tir.reussite():
# appliquer les dégats
gna gna gna

Ça c'est le fonctionement normal

imaginons la fonction reussite :

valeur = random.randrange(6)
if valeur == 0:
return false
else:
return true


return bool(valeur)

Vous l'avez comprit, un 1(ici un 0) sur le jet de dé est un echec.
Or mon personnages possede la compétance tireur d'élite qui lui permet
d'éviter cet echec. Ce que je ferais c'est:

valeur = random.randrange(6)
if valeur == 0 and not competance.tireur_elite:
return false
else:
return true

Cela fonctionnera parfaitement.

Seulement je n'aime pas cette méthode.


Et tu a raison.

Le jour ou je devrais rajouter
d'autres compétances, il va faloir que j'aille modifier le corps du
programme, ce qui ne colle pas vraiment à ma philosophie de séparation
du code et de reutilisation.

Bref, j'aimerais savoir comment vous implanteriez ce systeme de
compétances.



Difficile de répondre comme ça, mais tu veux peut-être creuser les
points suivants:
- patterns Strategy et State
- multimethodes

HTH
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in ''.split('@')])"

Avatar
bruno modulix
Guillaume Bouchard wrote:
Didier FRAISSE wrote:

Pour le peu que je connais à la programmation objet, il me semble que
tu résouds celà par héritage et en surchargeant ta fonction



Sauf que si un tireur d'elite est aussi tireur de precision et que sur 6
il augmente les dégats, je fait comment ?


Avec un (des) decorateur(s) (au sens du pattern Decorator) sur la
méthode tir() ?


--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in ''.split('@')])"


Avatar
Guillaume Bouchard
bruno modulix wrote:
Avec un (des) decorateur(s) (au sens du pattern Decorator) sur la
méthode tir() ?


Je vais me renseigner la dessus. Je l'avais déjà croisé dans la doc,
mais rien compris sur le moment, je m'étais promi d'y revenir, cela va
faire une bonne occassion ;o)

--
Guillaume.

Avatar
Guillaume Bouchard
bruno modulix wrote:
Guillaume Bouchard wrote:
car inutile dans le cadre du dev web).


Pas du tout, bien au contraire.


C'est un long débat :)

Bref, pour chaque action, il y a une règle générale et des cas
particuliers dépendants des caractéristiques des personnages (au sens
large...) impliqués.


En effet.

valeur = random.randrange(6)
if valeur == 0:
return false
else:
return true



return bool(valeur)


Vexant de logique.

Seulement je n'aime pas cette méthode.
Et tu a raison.



Youpii, pour une fois.

Difficile de répondre comme ça, mais tu veux peut-être creuser les
points suivants:
- patterns Strategy et State
- multimethodes


Je relirais ce conseil à tête reposée car là j'avoue que je n'ai pas
tout compris.

Merci.

--
Guillaume.


Avatar
bruno modulix
Guillaume Bouchard wrote:
bruno modulix wrote:

Avec un (des) decorateur(s) (au sens du pattern Decorator) sur la
méthode tir() ?


Je vais me renseigner la dessus. Je l'avais déjà croisé dans la doc,
mais rien compris sur le moment, je m'étais promi d'y revenir, cela va
faire une bonne occassion ;o)


Je ne pensais pas [1] aux decorateurs Python 2.4.x, mais au design
pattern Decorateur.


[1] pas spécifiquement en tous cas, mais ça peut peut-être convenir
comme moyen d'implémenter la chose



--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in ''.split('@')])"