Crie um jogo de caça-níqueis em Vanilla JavaScript

O que estamos codificando

Aqui está a demonstração finalizada, para você ter uma ideia do que estamos criando:

<

div data-content-block-type=”Wysi” id=”iomw”>

Comece com a IU

Começaremos criando a interface. Este será um design minimalista com o saldo (quanto crédito há para jogar) e três rolos.

O contêiner geral vem primeiro, então adicione um

elemento em seu arquivo html.

<

div class=”rouge-syntax-highlight”>

1
  class="slot-machine">
2
 
3
 

Em um novo

adicione um

pelo título e por um

para exibir o saldo.

1
 class="header">
2
    

Classic Slots

3
     class="balance">Balance: $1000

4

Provavelmente a parte mais importante do jogo de caça-níqueis são os rolos. Os rolos são as posições verticais em um slot que gira quando o jogo começa. Adicione um

elemento para conter as bobinas.

<

div class=”rouge-syntax-highlight”>

1
  class="reels-container">
2
 
3
  />

O contêiner terá três rolos, cada rolo contendo três símbolos. Usaremos emojis para eles, então use o que quiser:

1
 class="reels-container">
2
     class="reel">
3
       class="symbol">🍒
4
       class="symbol">🔔
5
       class="symbol">🍋
6
    
7
     class="reel">
8
       class="symbol">🍒
9
       class="symbol">🔔
10
       class="symbol">🍋
11
    
12
     class="reel">
13
       class="symbol">🍒
14
       class="symbol">🔔
15
       class="symbol">🍋
16
    
17

Por último, precisaremos do botão para iniciar o jogo e de uma mensagem de BOA SORTE exibida com um

marcação.

1
 class="controls">
2
     class="spin_btn">SPIN
3
     class="message">Good Luck!

4

Estilizando o jogo de caça-níqueis

Com a estrutura completa, vamos estilizá-la. Para o título estiloso precisaremos de uma fonte personalizada do Google Fonts, além de outra para as mensagens.

caça-níqueis clássicoscaça-níqueis clássicoscaça-níqueis clássicos
Por que isso me lembra Quentin Tarantino?

No seu arquivo CSS, adicione isto no topo.

1
import url("https://fonts.googleapis.com/css2?family=DM+Mono:ital,wght@0,300;0,400;0,500;1,300;1,400;1,500&display=swap");
2
@import url('https://fonts.googleapis.com/css2?family=Ultra&display=swap');

Em seguida, use flex para alinhar tudo ao centro, horizontal e verticalmente. Além disso, adicione a fonte universal e uma cor de fundo.

1
body {
2
    background: #121212;
3
    display: flex;
4
    justify-content: center;
5
    align-items: center;
6
    height: 100vh;
7
    font-family: "DM Mono", monospace;
8
}

Adicione esses estilos adicionais para garantir que o conteúdo do cabeçalho tenha o estilo adequado e todo o conteúdo esteja alinhado.

1
.slot-machine {
2
    text-align: center;
3
  }
4
  .header {
5
    margin-bottom: 20px;
6
    padding: 10px;
7
  }
8
  .header h1 {
9
    font-family: "Ultra", serif;
10
    font-size: 6em;
11
    line-height: .9;
12
    margin: 0;
13
    color: #ebb701;
14
    max-width: 10ch;
15
  }
16
  .header p {
17
    font-size: 1.2em;
18
    margin-top: 10px;
19
    color: white;
20
  }

Até agora temos isto:

O próximo passo é adicionar estilos aos rolos para formar três colunas:

1
.reels-container {
2
    display: flex;
3
    justify-content: center;
4
    align-items: center;
5
    height: 60%;
6
  }
7
  .reel {
8
    display: block;
9
    width: 130px;
10
    height: 210px;
11
    background-color: #3a3a3a;
12
    border-radius: 15px;
13
    overflow: hidden;
14
    margin: 0 10px;
15
    box-shadow: 0px 14px 15px -5px rgba(0,0,0,0.3) inset,
16
      1px -14px 15px -5px rgba(0,0,0,0.3) inset;
17
    border: 2px solid rgba(255,255,255,0.2);
18
    position: relative;
19
  }

Nos estilos acima, adicionamos display:flex no contêiner de bobinas que garante que as bobinas estejam alinhadas por colunas. Além disso, para centralizar as bobinas, usamos justify-content: center; e align-items: center;.

Para cada bobina, temos largura e altura personalizadas e algumas outras propriedades, como box-shadow, background-color, e border-radius para torná-lo mais atraente.

Também adicionamos alguns margin para garantir que as bobinas estejam espaçadas no contêiner.

Os símbolos terão os seguintes estilos.

1
.symbol {
2
    font-size: 3em;
3
    height: 1.5em;
4
    opacity: 0.6;
5
  }

Por último, adicione estes estilos para o botão SPIN e o elemento que contém a mensagem BOA SORTE.

1
.controls .btn {
2
  margin: 3em 0 1em 0;
3
  }
4
.controls .message {
5
  font-size: 1.5em;
6
  color: #ebb701;
7
  }

Obtenha os elementos com o DOM

Obtenha todos os elementos DOM que precisarão de manipulação. No topo do seu arquivo JS, adicione este código.

1
const reels = document.querySelectorAll(".reel");
2
const spinButton = document.querySelector(".spin_btn");
3
const messageDisplay = document.querySelector(".message");
4
const reelSound = document.getElementById("reelSound");
5
const winSound = document.getElementById("winSound");

A probabilidade de ganhar ao jogar numa slot machine pode ser muito baixa. Para aumentar as chances de ganhar, vamos criar uma série de estados de rolo parecidos com este:

1
deixar reelStates = [
2
  ["🍒", "🍒", "🍒", "🍋", "🍋", "🍉"],
3
  ["🍒", "🍋", "🍋", "🍉", "🍒", "7️⃣"],
4
  ["🍒", "7️⃣", "🍋", "🍒", "🍓", "🍋"]
5
];

No array, você pode ver que alguns símbolos aparecem mais que outros, isso é intencional para aumentar a probabilidade de vitória. Cada vez que um jogador quiser jogar este jogo, terá um saldo inicial de $ 1000 e sempre que girar a slot machine será deduzido do seu saldo um valor de $ 10.

Defina essas variáveis ​​iniciais.

1
let spinning = false;
2
let balance = 1000;
3
let betAmount = 10;

Também adicionamos uma variável spinning que controlará se o jogo está girando ou não. O valor inicial será definido como falso (ou seja, não girando).

Para atualizar o saldo restante, crie uma função chamada updateBalanceDisplay() e adicione o código abaixo. Esta função será chamada após cada giro.

1
function updateBalanceDisplay() {
2
  const balanceDisplay = document.querySelector(".balance");
3
  balanceDisplay.textContent = `Balance: $${balance}`;
4
}

Para fazer uma aposta ou girar o jogo, primeiro precisamos verificar se o saldo é adequado, ou seja, o saldo deve ser maior que o valor da aposta. Se o saldo for superior ao valor da aposta, o jogador terá a oportunidade de continuar jogando. Caso contrário, exibiremos a mensagem “Saldo insuficiente para fazer uma aposta!”.

Crie uma função chamada placeBet() e adicione este código:

1
function placeBet() {
2
  if (balance >= betAmount) {
3
    balance -= betAmount;
4
    updateBalanceDisplay();
5
   
6
  } else {
7
    alert("Not enough balance to place a bet!");
8
  }
9
}

Anexe um ouvinte de evento ao botão giratório, para que quando o usuário clicar no botão, ele acione o placeBet() função. O placeBet() A função atualizará o equilíbrio e gerenciará a lógica de rotação e vitória.

Por enquanto, o placeBet() atualiza apenas o saldo, atualizaremos o resto da lógica mais tarde.

Gire as bobinas

A característica mais importante da slot machine é a capacidade de girar os rolos. Atualmente, temos três colunas com cada coluna contendo 3 símbolos. A lógica de rotação envolverá a injeção de novos símbolos em cada rolo, quando a rotação começar. Uma vitória será determinada combinando três símbolos na mesma linha.

Para determinar o ciclo de rotação, ou seja, quantas vezes a bobina girará antes de parar, usaremos esta fórmula.

1
const spinCount = 10 + Math.floor(Math.random() * 5);

Crie uma nova função chamada spinReel e adicione a fórmula no topo da função. Esta função levará o reel e index como parâmetros.

1
function spinReel(reel, index) {
2
  const spinCount = 10 + Math.floor(Math.random() * 5);
3
  
4
  }

Para determinar o ponto de partida, partimos de 0. Este valor aumentará em 1 até o valor de spinCount é alcançado. Inicialize o valor inicial usando currentSpin e defina-o como 0. Este valor aumentará a cada giro até chegarmos ao valor de spinCount.

1
function spinReel(reel, index) {
2
  const spinCount = 10 + Math.floor(Math.random() * 5);
3
  let currentSpin = 0;
4
}

Para garantir que os rolos girem em intervalos diferentes, usaremos o setInterval() função, que executa uma função especificada repetidamente após um determinado intervalo de tempo.

Para obter um efeito giratório, obteremos cada array de realStates (uma matriz dimensional) e troque as posições dos elementos. Ao mesmo tempo, os elementos serão adicionados ao DOM, criando assim uma ilusão giratória.

Crie uma função chamada spinReeladicione o spinCount variável, inicializar currentSpin para 0 e crie um intervalo que será executado a cada 50 milissegundos.

1
function spinReel(reel, index) {
2
  const spinCount = 10 + Math.floor(Math.random() * 5);
3
  let currentSpin = 0;
4
  console.log(spinCount);
5
  const interval = setInterval(() => {}, 50 + index * 50);
6
}

Cada matriz no reelStates array contém 6 símbolos. Para criar a ilusão de girar, pegaremos o último item do array e o moveremos para o início (ou seja, giraremos o último elemento para a frente).

Após alterar a ordem dos símbolos na matriz, eles serão adicionados ao DOM para efetuar a rotação. Essa mudança repentina na posição dos símbolos criará o efeito visual de rotação.

Atualize o código dentro do setInterval() funcionar conforme mostrado abaixo.

1
  const interval = setInterval(() => {
2
    console.log(reelStates[index]);
3
    reelStates[0].unshift(reelStates[0].pop());
4
    reel.innerHTML = "";
5
    reelStates[index].forEach((symbol) => {
6
      const symbolDiv = document.createElement("div");
7
      symbolDiv.classList.add("symbol");
8
      symbolDiv.textContent = symbol;
9
      reel.appendChild(symbolDiv);
10
    });
11
    currentSpin++;
12
   
13
  }, 50 + index * 50);
14
}

Vamos detalhar o código acima: Por exemplo, para índice =0:

  • reelstates[index].pop() remove o último elemento do primeiro array ( [“🍒”, “🍒”, “🍒”, “🔔”, “🍋”, “🍉”] ) e o retorna. O último elemento neste caso é “🍉. Agora reelStates[index] tem apenas 5 itens.
  • reelStates[index].unshift() adiciona o elemento retornado (“🍉) de volta ao array no início do array. Este processo de remoção e adição de elementos ao array ocorrerá a cada 50 milissegundos mais um valor escalonado adicional com base no índice do rolo.
  • Após a atualização de cada array, também atualizamos o DOM para simular o efeito giratório. Em seguida, incrementamos o valor do giro criando um giro infinito.

Em algum momento, precisamos parar a rotação para que aconteça uma vitória ou uma derrota. Para fazer isso, verificaremos se o valor do giro atual é maior ou igual à contagem de giros e, em caso afirmativo, limparemos o intervalo. Limpar o intervalo significa que os rolos irão parar de girar.

Atualize o código da seguinte maneira:

1
function spinReel(reel, index) {
2
  const spinCount = 10 + Math.floor(Math.random() * 5);
3
  let currentSpin = 0;
4
  console.log(spinCount);
5
  const interval = setInterval(() => {
6
    reelStates[index].unshift(reelStates[index].pop());
7
    reel.innerHTML = "";
8
    reelStates[index].forEach((symbol) => {
9
      const symbolDiv = document.createElement("div");
10
      symbolDiv.classList.add("symbol");
11
      symbolDiv.textContent = symbol;
12
      reel.appendChild(symbolDiv);
13
    });
14
    currentSpin++;
15
    if (currentSpin >= spinCount) {
16
      clearInterval(interval);
17
      if (index === reels.length - 1) {
18
        spinning = false;
19
        
20
        
21
      }
22
    }
23
  }, 50 + index * 50);
24
}

O spinReel() a função funcionará apenas para uma bobina. Em vez de invocar a função três vezes, crie uma função chamada spinReels que irá girar todos os rolos.

1
function spinReels() {
2
    if (spinning) return;
3
    spinning = true;
4
    reelSound.play();
5
    messageDisplay.textContent = "Spinning.........";
6
    reels.forEach((reel, index) => {
7
      spinReel(reel, index);
8
    });
9
  }

Nesta função, primeiro verificamos se as bobinas já estão girando com a variável spinning. Se os rolos estiverem girando, nenhuma ação adicional ocorrerá e a função retornará no ponto. Se os rolos estiverem girando, definimos a variável de giro como verdadeira, exibimos uma mensagem e giramos todos os rolos enquanto o reelSound o som está tocando, dando um indicador de que as bobinas estão girando.

No placeBet() função, chame o spinReels() função para que quando o botão for clicado, os rolos comecem a girar.

1
function placeBet() {
2
    if (balance >= betAmount) {
3
      balance -= betAmount;
4
      updateBalanceDisplay();
5
      spinReels();
6
    } else {
7
      alert("Not enough balance to place a bet!");
8
    }
9
  }

Verifique se há uma vitória

Numa slot machine, o jogo é considerado uma vitória se um jogador acertar os símbolos consecutivos. Vamos implementar essa lógica. Depois que os rolos pararem, obteremos os símbolos exibidos atualmente para as 2 primeiras linhas e, em seguida, verificaremos se há um par correspondente no tabuleiro. Se for encontrada uma correspondência, atualizaremos o saldo e reproduziremos o som vencedor.

No entanto, se não ocorrer nenhum símbolo correspondente em uma linha, exibiremos uma mensagem incentivando o usuário a tentar novamente.

1
function checkWin() {
2
  const [reel1, reel2, reel3] = reelStates.map((reel) => reel[0]);
3
  const [reel4, reel5, reel6] = reelStates.map((reel) => reel[1]);
4

5
  if (
6
    (reel1 === reel2 && reel2 === reel3) ||
7
    (reel4 === reel5 && reel5 === reel6)
8
  ) {
9
    const payout = betAmount * 5;
10
    balance += payout;
11
    console.log("win");
12
    winSound.play();
13
    messageDisplay.textContent = " ";
14
  } else {
15
    messageDisplay.textContent = "Try Again";
16
  }
17
  updateBalanceDisplay();
18
}

Atualize o spinReel() funcionar de modo que o checkWin() a função é chamada depois que os rolos param de girar.

1
function spinReel(reel, index) {
2
//......

3
if (currentSpin >= spinCount) {
4
      clearInterval(interval);
5
      if (index === reels.length - 1) {
6
        spinning = false;
7
        reelSound.pause();
8
        reelSound.currentTime = 0;
9
        checkWin();
10
      }
11
    }
12
    //........

13
 }

E terminamos! Aqui está o que construímos:

Próximas etapas

Para tornar o aplicativo de caça-níqueis ainda melhor, considere adicionar um rastreador de pontuação para acompanhar a pontuação mais alta. Você também pode adicionar animações para uma experiência do usuário mais envolvente. Aproveitar!

Deixe uma resposta