Ajouter une coulée de lave

pour Victor (Rosny-sous-bois)

En faisant peser sur ton joueur une menace continue venant d'un bord de l'écran, tu vas pouvoir ajouter de la tension à ton jeu. En variant la direction de la coulée de lave, il est aussi possible de condamner puis de rendre accessible certains passages de ton niveau.

Déclarer un symbole

Nous allons maintenant déclarer un nouveau type d'objet que tu vas pouvoir placer dans ton jeu. Cet objet va nous permettre de déterminer la direction de la coulée de lave. Dans cet exemple nous avons choisi le caractère +. Dans le script level.js, trouve la variable LEVEL_CONFIG et ajoutes-y le code ci-dessous, comme suit.

// défini ce à quoi correspond chaque symbole dans le niveau
const LEVEL_CONFIG = {
  
  // taille en pixel de chaque case
  width: 64,
  height: 64,

  // sol
  "=": () => [
    sprite("grass"), 
    area(), 
    solid(), 
    origin("bot")
  ],
  
// direction de la lave "+": () => [ area(), "camerapoint", ],
} ;

Placer les points de direction

Tu vas maintenant pouvoir choisir la direction de ta coulée de lave, mais pour cela il va d'abord te falloir comprendre comment ceux-ci fonctionnent.

  • le premier point doit se trouver sur la même ligne ou colonne que ton joueur
  • la position du point par rapport au joueur va déterminer le sens de la coulée
  • si le joueur dépasse ce point, la coulée se dirige vers le point suivant
  • le point suivant doit se trouver sur la même ligne ou colonne que le point précédent
  • la position du point par rapport au point précédent va déterminer le sens de la coulée
  • et ainsi de suite, jusqu'à ce qu'il n'y ait plus de point
Toujours dans le script level.js, trouve le tableau LEVELS et places des caractères + là où tu le souhaites.

// plan du niveau
const LEVELS = [
  
  [
    "                         +    " ,
    " @                            " ,
    " =                            " ,
    "     =                        " ,
    "         =                    " ,
    "             =    =           " ,
    "                     =        " ,
    "                              " ,
    "                        =     " ,
    "                              " ,
    "                          =   " ,
    "                              " ,
    "                             =" ,
    "                              " ,
    "                           =  " ,
    "                              " ,
    "                        =     " ,
    "      =              =        " ,
    " #       =        =      +    " ,
    "===          =                " ,
  ],
  
];

Tes points sont placés mais la coulée de lave n'est pas encore là.

Créer un nouveau composant

Pour que ta coulée de lave apparaisse, il va nous falloir créer un nouveau composant. Rends-toi dans le script component.js et ajoutes-y cette fonction.

function lava( speed = 160 , followB = false , looping = false ) { const w = 240 ; // marge entre le joueur et la lave const ha = 0.4 ; // amplitude de l'effet de chaleur const hs = 0.6 ; // vitesse de l'effet const hr = 10 ; // décalage entre les vagues de chaleur const rd = 6 ; // nombre de vagues const ra = 2 ; // amplitue de la rotation des vagues const rr = 10 ; // décalage de la rotation des vagues let currentCameraTarget = 0 ; let cameraTargets = [] ; let cameraDirections = [] ; let heatbox = [] ; let start = false ; const hitbox = add( [ pos(0,0) , rect(0,0) , color(255,100,80) , area(), origin("center"), "danger", ] ) ; return { add(){ onKeyPress(() => { start = true ; }) }, load(){ let cp = get("camerapoint"); let pt = get("playerstart"); let st = new Vec2(0,0); every( "start" , ( s ) => { st = s.pos ; }); this.pos = st ; every( "camerapoint" , ( ) => { let sd ; let sdn ; let b = false ; for(let i = 0 ; i < cp.length ; i++){ let p = cp[i].pos ; let d = this.distance( p , st ); if( ( !sd || d<sd ) && ( p.x == st.x || p.y == st.y ) ) { sd = d ; sdn = i ; b = true } } for(let i = 0 ; i < rd ; i++){ let lyr = ["foreground","background"]; heatbox[i] = add( [ pos(0,0) , rect(0,0) , color(255,100,80) , area(), opacity(0.2), rotate( wave( -ra , ra , i * rr ) ) , origin("center"), layer(lyr[ i % lyr.length ]) ] ) ; } if (b){ let np = cp[sdn].pos ; let dx = np.x - st.x ; let dy = np.y - st.y ; let dir ; if( Math.abs(dx) > Math.abs(dy) ){ if(dx<0) dir = new Vec2(-1, 0); else dir = new Vec2( 1, 0); } else { if(dy<0) dir = new Vec2( 0 , -1 ); else dir = new Vec2( 0 , 1 ); } cameraTargets.push( new Vec2( np.x + dir.x , np.y + dir.y ) ) ; cameraDirections.push( dir ) ; st = np ; cp.splice( sdn , 1 ) ; } }); }, update() { if ( currentCameraTarget < cameraTargets.length ) { let p = get("player")[0].pos ; let d = cameraDirections[currentCameraTarget] ; let t = cameraTargets[currentCameraTarget] ; let x = this.pos.x ; let y = this.pos.y ; if (start){ if (d.x == 0) this.pos.x = p.x ; else this.pos.x += d.x * speed * dt() ; if (d.y == 0) this.pos.y = p.y ; else this.pos.y += d.y * speed * dt() ; if (followB){ if( d.x == 1 && x < p.x ) this.pos.x = p.x ; if( d.x == -1 && x > p.x ) this.pos.x = p.x ; if( d.y == 1 && y < p.y ) this.pos.y = p.y ; if( d.y == -1 && y > p.y ) this.pos.y = p.y ; } if ( d.x < 0 && x <= t.x - w ) currentCameraTarget ++ ; if ( d.x > 0 && x >= t.x + w ) currentCameraTarget ++ ; if ( d.y < 0 && y <= t.y - w ) currentCameraTarget ++ ; if ( d.y > 0 && y >= t.y + w ) currentCameraTarget ++ ; if ( d.x < 0 && p.x <= t.x ) currentCameraTarget ++ ; if ( d.x > 0 && p.x >= t.x ) currentCameraTarget ++ ; if ( d.y < 0 && p.y <= t.y ) currentCameraTarget ++ ; if ( d.y > 0 && p.y >= t.y ) currentCameraTarget ++ ; } hitbox.height = height() * 2 ; hitbox.width = width() * 2 ; hitbox.pos.x = x - ( width() + w ) * d.x ; hitbox.pos.y = y - ( height() + w ) * d.y ; for(let i = 0 ; i < heatbox.length ; i++){ let amp = (1 / heatbox.length * i + 1 ); let t = time() * hs + i * hr ; heatbox[i].height = hitbox.height ; heatbox[i].width = hitbox.width ; heatbox[i].pos.x = hitbox.pos.x + wave(amp,amp+w,t) * d.x * ha ; heatbox[i].pos.y = hitbox.pos.y + wave(amp,amp+w,t) * d.y * ha ; } } else if (looping) currentCameraTarget = 0 ; }, distance( e , t ){ const dx = Math.pow( e.x - t.x , 2 ) ; const dy = Math.pow( e.y - t.y , 2 ) ; return Math.sqrt( dx + dy ) ; }, } }

Ajouter le nouveau composant

Nous devons maintenant créer un nouvel objet dans ta scène puis y ajouter ce nouveau composant. Dans le script game.js, à l'intérieur de la scène game, après la variable level crée l'objet lavaflow.

// ajoute le niveau
const level = addLevel( LEVELS[ CURRENT_LEVEL ] , LEVEL_CONFIG ) ;

// définition de la lave const lavaflow = add( [ lava( 160 , false , false ) , ] ) ;

Facultatif : Déplacer la caméra

Si tu le souhaites, il est aussi possible de déplacer la caméra du joueur, afin d'accentuer le sentiment d'urgence produit par la lave. Cela peut aussi permettre d'afficher davantage le reste du parcours.

Toujours dans le script game.js, à l'intérieur de la scène game, retrouve l'objet lavaflow et modifie cette ligne.

// définition de la lave
const lavaflow = add( [

  lava( 160 , false , false ) ,

  lava( 160 , true  , false ) ,

] ) ;

Enfin, dans le script game.js, à l'intérieur de la scène game, trouve la fonction l'objet onUpdate et modifie cette ligne.

// est lu à chaque frame
onUpdate( () => {
    
  // mouvement de la caméra

  camPos( player.pos   ) ;

  camPos( lavaflow.pos ) ;
    
} ) ;