 | Escrevendo o Código de Disparo
O código para disparar a arma é dividido em algumas funções diferentes:
senseFire — Verifica o botão para ver se foi pressionado.
fireShot — Dispara o tiro quando um pressionamento de botão é detectado.
oscillationWrite — Usado para tratar da oscilação real do disparo.
selfDestruct — Para tratar da auto-destruição quando uma arma tiver feito muitos disparos.
A Função senseFire
Para sentir e tratar corretamente de um pressionamento de botão, é necessário verificar diversas coisas: o estado do pino, a variável que revela se esse pressionamento de botão já foi tratado, se o jogador ainda está vivo e o número de disparos feitos pelo jogador.
Se o jogador ainda estiver vivo e o número de disparos for maior do que seis, é necessário verificar se esse tiro é o que quebra a arma e elimina o jogador.
Nesse caso, vamos supor que o número máximo absoluto de disparos que uma arma possa fazer seja 20. Escolha um número aleatório entre um e 20 e, se esse número for menor ou igual ao número de disparos, a arma é auto-destruída. (Você irá colocar a auto-destruição real em uma função que será escrita posteriormente.) A função senseFire tem a aparência da Listagem 7.
Listagem 7. Função senseFire
void senseFire() {
trigger = digitalRead(triggerPin);
if (trigger == LOW && fired == false) {
Serial.println("Button Pressed");
fired = true;
myShots++;
if (myHits <= maxHits && myShots > maxShots && random(1,20)
<= myShots) {
Serial.println("SELF DESTRUCT");
selfDestruct();
} else if (myHits <= maxHits) {
Serial.print("Firing Shot : ");
Serial.println(myShots);
fireShot(myCode, myLevel);
}
} else if (trigger == HIGH) {
if (fired == true) {
Serial.println("Button Released");
}
// reconfigure a variável acionada
fired = false;
Serial.println("Button Released");
}
}
|
Um problema um tanto quanto mais complicado é onde essa função é chamada. Você não pode simplesmente emiti-la na função loop como está escrita ou ela somente perceberá um pressionamento de botão toda vez que um disparo recebido for reconhecido. Você poderia emitir a função no loop while na função senseIR , mas isso serve para obscurecer as coisas um pouco. Vamos alterar esse loop
while para uma instrução if
e retornar da função se você não estiver recebendo um sinal. Você também precisa fazer uma leve modificação na leitura de
pulseIn , incluindo um valor de tempo limite (caso contrário, pulseIn aguardará um segundo inteiro entre as leituras).
Listagem 8. Modificando a Leitura de pulseIn
...
if (pulseIn(sensorPin, LOW, 500) < startBit) {
digitalWrite(blinkPin, LOW);
ret[0] = -1;
return;
}
...
|
Você pode incluir a chamada da função senseFire na função loop .
Listagem 9. Chamada da Função senseFire para a Função loop
void loop() {
senseFire();
senseIR();
if (ret[0] != -1) {
...
|
Disparar e sentir são funções separadas. Se uma arma for atingida exatamente na mesma hora em que a arma estiver sendo disparada, o tiro não será registrado.
Devido à maneira como o exemplo reproduz sons, isso deve ser verdadeiro enquanto o som estiver sendo reproduzido.
Há maneiras como isso pode ser melhorado posteriormente, se você se sentir ambicioso, mas por hora, não se preocupe muito com isso. Se a arma de todos funcionar da mesma forma e for construía da mesma forma, o campo de jogo está essencialmente nivelado.
A Função fireShot
Quando um pressionamento de botão for detectado e você souber que a arma não foi auto-destruída, você pode disparara o tiro em si.
Lembre-se, um tipo consiste em duas informações (Quem e O que) colocadas entre um bit inicial e um bit final.
No caso de um jogador, Quem é o código do jogador e O que é o nível do jogador.
Esses valores são mantidos nas variáveis myCode e myLevel e são passados na função senseFire .
A função fireShot segue esta sequência:
- Ative o LED de feedback
- Codifique Quem em binário
- Codifique O QUE em binário
- Envie o bit inicial
- Envie o binário
- Envie o bit final
- Reproduza um sinal
- Desative o LED de feedback
Para iniciar, você irá declarar a função, inicializar uma array para conter os dados codificados e ativar o LED de feedback, conforme mostrado abaixo.
Listagem 10. Declarando a Função fireShot e Inicializando uma array
void fireShot(int player, int level) {
int encoded[8];
digitalWrite(blinkPin, HIGH);
|
Preencha primeiro a array de dados codificada com as informações do jogador e, em seguida, com as informações de nível.
Listagem 11. Preencher a array
for (int i=0; i<4; i++) {
encoded[i] = player>>i & B1; //codifique os dados como '1' ou '0'
}
for (int i=4; i<8; i++) {
encoded[i] = level>>i & B1;
}
|
Envie o bit inicial, como na Listagem 12, usando a função oscillationWrite que você escreverá em um momento. Após enviar cada bit, você precisa enviar o que é chamado de um
separador (essencialmente um flash) e pausar por pouco tempo.
Listagem 12. Enviando o Bit Inicial
oscillationWrite(senderPin, startBit);
digitalWrite(senderPin, HIGH);
delayMicroseconds(waitTime);
|
Agora que você enviou o bit inicial e pausou, irá percorrer a array codificada para trás, enviar cada bit através da mesma função
oscillationWrite
e incluir um separador e uma pausa no final de cada bit.
Listagem 13. Incluindo um Separador e uma Pausa no Final de Cada Bit
for (int i=7; i>=0; i--) {
if (encoded[i] == 0) {
oscillationWrite(senderPin, zero);
} else {
oscillationWrite(senderPin, one);
}
digitalWrite(senderPin, HIGH);
delayMicroseconds(waitTime);
}
|
Envie o bit final, reproduza um sinal para indicar o disparo e desative o LED de feedback.
Listagem 14. Enviando o Bit Final
oscillationWrite(senderPin, endBit);
playTone(100, 5);
digitalWrite(blinkPin, LOW);
}
|
O sinal reproduzido aqui é extremamente simples. Abstrair todo o sinal sendo reproduzido para um conjunto separado de funções, para que elas pudessem ser descarregadas para a área de troca mais facilmente, seria uma excelente melhora.
Alguns funções desta série, incluindo fireShot , mas principalmente
oscillationWrite, foram baseadas em ou retiradas de código escrito por Paul Malmsten e postado nos fóruns do Arduino (consulte Recursos). Disponibilizar esse código para o público em geral facilitou a conclusão desta série.
A Função oscillationWrite
A função oscillationWrite , na Listagem 15, trata da transmissão do sinal na frequência desejada: 38 kHz. Você irá ativar o pino do emissor por 13 microssegundos, em seguida, desativará por 13 microssegundos (isso cria um ciclo) por um período de tempo determinado pelo o que você deseja enviar (um zero ou um um, um bit inicial ou um bit final).
Listagem 15. Função oscillationWrite
void oscillationWrite(int pin, int time) {
for(int i = 0; i <= time/26; i++) {
digitalWrite(pin, HIGH);
delayMicroseconds(13);
digitalWrite(pin, LOW);
delayMicroseconds(13);
}
}
|
Se você tiver optado por usar uma frequência diferente para seus sensores e armas, é necessário reescrever esta seção de código conforme necessário.
A Função selfDestruct
A função selfDestruct é mostrada na Listagem 16. Quando uma arma tiver disparo muitos tiros, o jogador é eliminado.
Faça isso configurando os acertos do jogador para maxHits+1 e reproduzindo um som interessante.
Listagem 16. Função selfDestruct
void selfDestruct() {
myHits = maxHits+1;
playTone(1000, 250);
playTone(750, 250);
playTone(500, 250);
playTone(250, 250);
}
|
Nesse ponto, você está pronto para testar o disparo de sua arma. Respire fundo e prepare-se para pressionar alguns botões.
|  |