JeuWeb - Crée ton jeu par navigateur

Version complète : Algorithme d'ombre
Vous consultez actuellement la version basse qualité d'un document. Voir la version complète avec le bon formatage.
Pages : 1 2
Bonjour à tous,

Sous ce nom obscure ce cache une chose que tout bon "tape case" doit avoir: la possibilité de "noircir" les cases que le personnage ne voie pas, en gros celle qui sont derrière un décors.

J'arrive absolument pas a le faire, mais alors pas du tout, je ne sais pas par ou commencer.

Mes outils:

1 cartes ou chaque case est une cellule de tableau.
C'est une carte X/Y commencent en 0/0 et finissant en 23/16.
Le personnage ce déplace sur la carte, qui elle est fixe.

Quelques screens:

[Image: screen_6.jpg]
[Image: screen_2.jpg]

Comment gériez-vous cela ? Comment detecter si le personnage vois la case ou s'il y a un obstacle dans le champs de vision ?

Merci d'avance,

Phenix, perdu...
Salut,

Un algo tout bête, imaginé sur le pouce :

Code PHP :
$carte_ombre array_fill(023array_fill(016true));

// Donc ici on a $carte_ombre qui est un tableau contenant uniquement des true.
// On va passer la case où est le joueur à false : il peut toujours se voir lui-même.
$carte_ombre[$x_joueur][$y_joueur] = false;

// Ensuite le joueur a droit de se voir sur une certaine portée
$portee 3;

// On va donc déjà déterminer horizontalement et verticalement, ce qu'il voit
// Pour ça très simple : on va utiliser deux boucles for pour chaque direction.
// Le principe est : on part du joueur et on va dans la direction voulue.
// Si un obstacle bloque le joueur, il ne voit pas plus loin.
$bloque false;
for(
$i $x_joueur$i <= $x_joueur $portee$i++)
{
     if(
obstacle($i$y_joueur) || $bloque)
     {
          
$bloque true;
     } else {
          
$carte_ombre[$i][$y_joueur] = false;
     }
}
$bloque false;
for(
$i $x_joueur$i >= $x_joueur $portee$i--)
{
     if(
obstacle($i$y_joueur) || $bloque)
     {
          
$bloque true;
     } else {
          
$carte_ombre[$i][$y_joueur] = false;
     }
}
$bloque false;
for(
$i $y_joueur$i <= $y_joueur $portee$i++)
{
     if(
obstacle($x_joueur$i) || $bloque)
     {
          
$bloque true;
     } else {
          
$carte_ombre[$x_joueur][$i] = false;
     }
}
$bloque false;
for(
$i $y_joueur$i >= $y_joueur $portee$i--)
{
     if(
obstacle($x_joueur$i) || $bloque)
     {
          
$bloque true;
     } else {
          
$carte_ombre[$x_joueur][$i] = false;
     }


Voila pour les directions "simples". Maintenant, il va falloir complexifier un petit peu les choses pour les directions en diagonal. Là, ça dépends vraiment de comment tu veux gérer ton ombre. La manière la plus simple, pour moi, est de gérer ça en décalant le joueur, ce qui implique de coder le tout en fonction récursive :

Code PHP :
$carte_ombre array_fill(023array_fill(016true));

function 
decouvre_carte($carte_ombre$x_joueur$y_joueur$portee)
{
     
// On calcule comme expliqué précédement les directions "de base"
     
$bloque false;
     for(
$i $x_joueur$i <= $x_joueur $portee$i++)
     {
          if(
obstacle($i$y_joueur) || $bloque)
          {
               
$bloque true;
          } else {
               
$carte_ombre[$i][$y_joueur] = false;
          }
     }
     
$bloque false;
     for(
$i $x_joueur$i >= $x_joueur $portee$i--)
     {
          if(
obstacle($i$y_joueur) || $bloque)
          {
               
$bloque true;
          } else {
               
$carte_ombre[$i][$y_joueur] = false;
          }
     }
     
$bloque false;
     for(
$i $y_joueur$i <= $y_joueur $portee$i++)
     {
          if(
obstacle($x_joueur$i) || $bloque)
          {
               
$bloque true;
          } else {
               
$carte_ombre[$x_joueur][$i] = false;
          }
     }
     
$bloque false;
     for(
$i $y_joueur$i >= $y_joueur $portee$i--)
     {
          if(
obstacle($x_joueur$i) || $bloque)
          {
               
$bloque true;
          } else {
               
$carte_ombre[$x_joueur][$i] = false;
          }
     }
     
     
// On regarde pour chaque diagonale si on peut y voir
     
if($portee 1)
     {
          if(!
obstacle($x_joueur 1$y_joueur 1))
          {
                
$carte_ombre decouvre_carte($carte_ombre$x_joueur 1$y_joueur 1$portee 1);
          }
          if(!
obstacle($x_joueur 1$y_joueur 1))
          {
               
$carte_ombre decouvre_carte($carte_ombre$x_joueur 1$y_joueur 1$portee 1);
          }
          if(!
obstacle($x_joueur 1$y_joueur 1))
          {
               
$carte_ombre decouvre_carte($carte_ombre$x_joueur 1$y_joueur 1$portee 1);
          }
          if(!
obstacle($x_joueur 1$y_joueur 1))
          {
               
$carte_ombre decouvre_carte($carte_ombre$x_joueur 1$y_joueur 1$portee 1);
          }
     }

     return 
$carte_ombre;
}

$carte_ombre decouvre_carte($carte_ombre$x_joueur$y_joueur3); // Pour une portée de 3, bien sûr 

Et ensuite, il suffit de n'afficher le masque que sur les cases pour lesquelles $carte_ombre[$x][$y] est à true. Je suis pas sûr que ça marche, j'ai pas testé, mais l'idée me semble correcte.

Mes deux centimes du soir :-)
C'est pas mal fichu, mais une chose me gène un peu, a moins que j'ai mal vu, il va blocker la vue, seulement en ligne droite, pas en format "angle".

exemple:


P: joueur
A: arbre,
O: ombre,
C: case vide

COOOOOC
CCOOOCC
CCCACCC
CCCPCCC
CCCCCCC

Je sais pas si c'est suffisamment clair comme schéma...
L'idée reste pas mal en tout cas.
Hum... J'ai pas le courage de coder ce soir, mais je pense que tu peux arranger ça en utilisant, au lieu de true et false, des entiers.

Dans ce cas, l'idée serait la suivante : tu as un tableau avec que des 0. Si un objet passe, on interromps le cycle récursif (comme dans mon exemple), mais en plus on remplit les cases autour de l'objet avec des 1. Et dans les tests, on remplace :

if(obstacle($i, $y_joueur) || $bloque)

par

if(obstacle($i, $y_joueur) || $carte_ombre[$i][$y_joueur] == 1 || $bloque)

Si le test est faux, on passe la case à 2.

Et dans ce cas :

- Une case avec 0 est une case qui est hors de portée de la vue du joueur
- Une case avec 1 est une case qui est à portée du joueur, mais masquée par un obstacle
- Une case avec 2 est visible par le joueur

Ca permet de nuancer un peu et de faire varier la forme des ombres.

Je sais pas si je suis très clair...
Bonjour,

En gros, tu as ton tableau qui contient une carte et le deuxième avec des 1 ou 0 pour la visibilité 10

Est ce que vous masquez la carte à l'affichage ? Pour le masquage du contour, il suffit de balayer les éléments du tableau qui sont:
x-1,y
x+1,y
x,y+1
x,y-1
x+1,y+1
x-1,y-1
x-1,y+1
x+1,y-1

Ensuite, selon ta portée tu réalises ton cycle récurcif sur les cases autour 2:
Boucle 1:
on découvre à case + 1 en mettant un 1 dans ton tableau Visible[][]
Boucle 2:
On découvre à case + 2 en mettant un 1 dans ton tableau Visible[][]
(etc pour tes n cases visibles)

Après la question est: est ce que ton personnage ou la vision part du centre (dans ce cas là mon algo marche) ou bien est ce que ça part de n'importe où et dans ce cas là, tu devras faire:

on stocke les cases initiales autour du joueur à découvrir
Boucle 1:
on découvre à case + 1 en mettant un 1 dans ton tableau Visible[][]
on stocke dans un tableau secondaire les prochaines cases à découvrir
Boucle n:
On découvre les cases autour de la case du tableau si par exemple:
il n'y a pas de mur, le joueur peut voir la prochaine case
Il y a un mur, la case derriere le mur ne sera pas découverte,....

Ce principe est exactement celui du démineur 10

A bientôt !
Hum ...

On a tendance à se limiter à la notion de cases permissive à la vue et la case obstruante ... mais si sur tes cases tu as un grillage, ou de 2 piliers cote à cote ... La personne pourra théoriquement voir à travers le grillage ou entre les piliers.

Par ailleurs, un truc qui m'a toujours épaté, c'est que dans le cas d'un mur, on sache à priori constamment son épaisseur (le graphisme étant une simple ligne ...)

Je ne donne pas de solution technique, celle proposée au dessus me semblant tout à fait correcte, mais je me dis qu'il pourrait y avoir mieux à proposer à nos joueurs...

Kéké qui n'a pas de gestion des obstacles sur les vues de Magdales
Yop kéké,

Perso, à part ce genre de solution et donner à chaque objet une valeur de transparence 10 du genre:
grillage 1: transparence = 2 cases plus loin
grillage 2: transparence = 1 case

...
Pour info, pour le dev du moteur de jeux qui nous permettra de créer X types de jeux, nous n'avons pas encore de représentation graphique... y aura t-il une map... que du texte... perso, j'aime bien les reprensentations, mais après ma question est la suivante:

Là, c'est bien beau, on donne du code, mais comment réalisez vous l'affichage ? un cadrillage de gif bien moche ? du flash ? ...
Perso j'aime bien les cartes iso, alors moi j'afficherais une carte isométrique. X-ZoD avais fait des tutos ici (un exemple à la fin)

Sinon, tu as réussi à faire l'algo ? j'ai tenter pour le fun et j'obptient ce resultat :

[Image: capture9ej5.png]

P -> personnage
O -> obstacle
C -> case visible
A -> case cacher

et le code (pas optimiser du tout)
Code PHP :
<?php
//calcule l'angle en degres (sur 360°)
function angle($x,$y)
{
    
$module sqrt($x*$x $y*$y);
    
$angleCos acos($x $module);
    
$angleSin asin($y $module);

    if(
$angleSin 0)
        if(
$angleCos pi()/2)
            
$angleCos pi()*$angleCos;
        else
            
$angleCos pi()*$angleSin;

    return 
180*$angleCos/pi();
}

//array( ["x,y"] => type de terrain (pour la transparence par exemple (pas gerer ici))
$c_obstacle = array(
    
'5,6'=>3,
    
'3,2'=>3,
    
'5,3'=>3,
    
'8,8'=>3,
    
'8,9'=>3,
    
'13,14'=>3,
    
'20,5'=>3,
    
'18,10'=>3,
    
'16,15'=>3,
    
'12,14'=>3
);

$angle_obstacle = array();

$jx 13;
$jy 13;

//cherche les obstacles, la fourchette de l'angle et leur distance par rapport au joueur
foreach($c_obstacle as $coord=>$type){
    list(
$x,$y) = explode(","$coord);
    
$x -= $jx;
    
$y -= $jy;
    
/*definit l'anglez de chaque coin de la case
    (0.5 => l'obstacle prend toute la case 
    0.45=> l'obstacle prend 90% de la case)*/
    
$angle_coin = array(
        
angle($x+0.45$y+0.45),
        
angle($x+0.45$y-0.45),
        
angle($x-0.45$y-0.45),
        
angle($x-0.45$y+0.45)
    );


    
$angle_obstacle[] = array(
        
min($angle_coin),            //angle min
        
max($angle_coin),            //angle max
        
sqrt($x*$x $y*$y)        //distance
    
);
}

for(
$y=25;$y>=1;$y--){
    for(
$x=1;$x<=25;$x++){
        
$cacher false;

        
//regarde si la case est cacher par un obstacle
        
foreach($angle_obstacle as $values){
            
//zone d'ombre à porter (pas obligatoireent sur la case traiter)
            
if($values[2] < sqrt(pow($x-$jx2) + pow($y-$jy2))) {
                
$angle angle($x-$jx,$y-$jy);
                
//verifie si la zone d'ombre est bien sur la case en cours de traitement
                
if($values[0] <= $angle AND $angle <= $values[1]){
                    
$cacher true;
                    
//case cacher, pas la peine de continuer à chercher
                    
break;
                }
            }
        }

        if(isset(
$c_obstacle["$x,$y"]))
            echo 
'<span style="color:red">O </span>';
        elseif(
true === $cacher)
            echo 
'<span style="color:black">A </span>';
        elseif(
$jx == $x AND $jy == $y)
            echo 
'<span style="color:green">P </span>';
        else
            echo 
'<span style="color:gray">C </span>';
    }
    echo 
'<br />';
}

echo 
'<pre>';
print_r($angle_obstacle);
?>

bonne nuit
J'avoue n'avoir strictement rien comprit a ce code, je dois pas avoir le niveau en trigo 61

En tout cas, sa marche, je suis en train d'analyser et de modifier ce que je peux pour l'implanter dans la vallée des larmes.

Quand j'aurais fini (si je fini) je posterais la fonction, sa pourra servir a d'autre 16. Grand merci à toi.

(Vont faire une drôle de tête mes joueurs 60)

[edit]

Il doit y avoir un problème quelques part, parce qu'il arrive a me trouver des cases qui n'existe pas...

[Edit 2]: c'est en bidouillant qu'on reproduit les bug. Ton code semble foirer en largeur, en déplacent le personnage on a un joli bug:

Code PHP :
<?php
//calcule l'angle en degres (sur 360°)
function angle($x,$y)
{
    
$module sqrt($x*$x $y*$y);
    
$angleCos acos($x $module);
    
$angleSin asin($y $module);

    if(
$angleSin 0)
        if(
$angleCos pi()/2)
            
$angleCos pi()*$angleCos;
        else
            
$angleCos pi()*$angleSin;

    return 
180*$angleCos/pi();
}

//array( ["x,y"] => type de terrain (pour la transparence par exemple (pas gerer ici))
$c_obstacle = array(
    
'5,6'=>3,
    
'3,2'=>3,
    
'5,3'=>3,
    
'8,8'=>3,
    
'8,9'=>3,
    
'13,14'=>3,
    
'20,5'=>3,
    
'18,10'=>3,
    
'16,15'=>3,
    
'12,14'=>3
);

$angle_obstacle = array();

$jx 15;
$jy 15;

//cherche les obstacles, la fourchette de l'angle et leur distance par rapport au joueur
foreach($c_obstacle as $coord=>$type){
    list(
$x,$y) = explode(","$coord);
    
$x -= $jx;
    
$y -= $jy;
    
/*definit l'anglez de chaque coin de la case
    (0.5 => l'obstacle prend toute la case 
    0.45=> l'obstacle prend 90% de la case)*/
    
$angle_coin = array(
        
angle($x+0.45$y+0.45),
        
angle($x+0.45$y-0.45),
        
angle($x-0.45$y-0.45),
        
angle($x-0.45$y+0.45)
    );


    
$angle_obstacle[] = array(
        
min($angle_coin),            //angle min
        
max($angle_coin),            //angle max
        
sqrt($x*$x $y*$y)        //distance
    
);
}

for(
$y=25;$y>=1;$y--){
    for(
$x=1;$x<=25;$x++){
        
$cacher false;

        
//regarde si la case est cacher par un obstacle
        
foreach($angle_obstacle as $values){
            
//zone d'ombre à porter (pas obligatoireent sur la case traiter)
            
if($values[2] < sqrt(pow($x-$jx2) + pow($y-$jy2))) {
                
$angle angle($x-$jx,$y-$jy);
                
//verifie si la zone d'ombre est bien sur la case en cours de traitement
                
if($values[0] <= $angle AND $angle <= $values[1]){
                    
$cacher true;
                    
//case cacher, pas la peine de continuer à chercher
                    
break;
                }
            }
        }

        if(isset(
$c_obstacle["$x,$y"]))
            echo 
'<span style="color:red">O </span>';
        elseif(
true === $cacher)
            echo 
'<span style="color:black">A </span>';
        elseif(
$jx == $x AND $jy == $y)
            echo 
'<span style="color:green">P </span>';
        else
            echo 
'<span style="color:gray">C </span>';
    }
    echo 
'<br />';
}

echo 
'<pre>';
print_r($angle_obstacle);
?>

C'est dommage car sa semblais fonctionner correctement 12
Pages : 1 2
URLs de référence