I am a newbie coder and I'm trying to learn good coding habits. I'm making a Simon Says game challenge from Free Code Camp in Angular JS.
I have an array that keeps random integers between 1-4:
var simonSays = [];
This is how I'm currently animating and playing sounds. I've read that you're not to manipulate the DOM using Angular. But how would I handle it for my game?
var counter = 0, //for looping thru simon's array
innerTimeOutSecs = 1000, //time during each iteration
outerTimeOutSecs = 500, //time before next iteration
simonTurn = false; //if simon is playing, player cannot interrupt simon
function animateSimonSays() {
simonTurn = true;
$timeout(function() {
var simon = simonSays[counter];
//find the current pad and current audio to light up/play
var currentPad = document.getElementById("pad" + simon);
var currentAudio = document.getElementById("pad" + simon + "_audio");
angular.element(currentPad).addClass("lightUpPad");
currentAudio.play();
$timeout(function() {
currentAudio.pause(); //stop audio
currentAudio.currentTime = 0;
angular.element(currentPad).removeClass("lightUpPad"); //'turn off' pad
//get ready for the next simon
counter++;
if (counter < simonSays.length) { //recursion fail condition
animateSimonSays();
} else {
counter = 0;
simonTurn = false;
}
}, innerTimeOutSecs); //how long to stay 'lit'
}, outerTimeOutSecs); //how long before the next simon
}
It's dirty but it works for my app. All the examples I found online were jQuery so I couldn't really follow their methodology.
var app = angular.module('App', []);
app.controller('MainCtrl', ['$scope', '$timeout', function($scope, $timeout) {
var simonSays = [], //push what simon says
copy = [], // compare user answer to simon answer
counter = 0, //for looping thru simon's array
innerTimeOutSecs = 1000, //time during each iteration
outerTimeOutSecs = 500, //delay in resetting to original state of pad and call next pad
simonTurn = false, //if simon is playing, play cannot interrupt simon
currentResponse = true; //used to compare user answer to simon
$scope.count = 0; //number of rounds
$scope.isStrict = false; //is strict mode on/off
$scope.startGame = function() { //start button calls restart
restart();
}
function restart() { //initialize game by setting values in array to empty and start a new round
simonSays = [];
$scope.count = 0;
newRound();
}
function newRound() { //begin next round
if ($scope.count === 20) { //victory alert if player reaches 20 steps
alert("Congratulations. You win!");
restart();
return;
}
$scope.count++; //increase round by one
if ($scope.count % 5 === 0) {
innerTimeOutSecs -=100;
outerTimeOutSecs -=50;
}
simonSays.push(Math.floor(Math.random() * 4 + 1)); //add random step to the end
copy = simonSays.slice(0);
animateSimonSays();
}
function animateSimonSays() { //light works and sound
//TODO: speedup animations after every 5 'count'
simonTurn = true; //simon is playing, user cannot play function again by pressin start
$timeout(function() { //outertimeout
var simon = simonSays[counter]; //setting up iteration of array
var currentPad = document.getElementById("pad" + simon); //setting up light show for each
var currentAudio = document.getElementById("pad" + simon + "_audio"); //setup audio
angular.element(currentPad).addClass("lightUpPad"); //opacity change
currentAudio.play(); //audio starts
$timeout(function() { //inner timeout
currentAudio.pause(); //stop sound
currentAudio.currentTime = 0; //set audio back to start position
angular.element(currentPad).removeClass("lightUpPad"); //return to original opacity
counter++; //setting up next iteration in array
if (counter < simonSays.length) { //test for recursiveness
animateSimonSays(); //calling recursive function for next iteration
} else { //if counter reaches end..
counter = 0; //reset counter
simonTurn = false; //simon turn over
}
}, innerTimeOutSecs); //how long it stays lit
}, outerTimeOutSecs); //next pad
}
//three possible situations
//1.user click wrong pad --> call animate again (last round)
//2.user click right pad but seq not finish --> do nothing
//3.user pick right pad and end of seq --> new round
function checkResponse() {
if (!currentResponse) { // case 1
var buzzer = document.getElementById("buzzer");
buzzer.play();
if ($scope.isStrict) { //strict mode restarts game
$timeout(function() {
buzzer.pause();
buzzer.currentTime = 0;
restart();
}, 1000);
return;
}
$timeout(function() {
buzzer.pause();
buzzer.currentTime = 0;
copy = simonSays.slice(0);
animateSimonSays();
}, 1000);
} else if (currentResponse && copy.length === 0) { //case 3
$timeout(newRound, 1000);
}
}
$scope.registerClick = function(padId) {
if (simonTurn) return; //click does not register during simon turn
//var currentPad = document.getElementById("pad" + padId);
var currentAudio = document.getElementById("pad" + padId + "_audio");
currentAudio.play();
$timeout(function() {
currentAudio.pause();
currentAudio.currentTime = 0;
}, 500);
var desiredResponse = copy.shift(); //pop out first index of the array
var actualResponse = padId;
currentResponse = desiredResponse === actualResponse; //compare click and simon
checkResponse();
}
}]);
.wrapper {
position: relative;
width: 640px;
margin: 0 auto;
}
.back {
position: absolute;
top: 170px;
width: 640px;
height: 640px;
z-index: 0;
background-color: #000;
border-radius: 310px;
}
.pad {
width: 300px;
height: 300px;
float: left;
z-index: 1;
margin: 10px;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)";
filter: alpha(opacity=60);
opacity: 0.6;
cursor: pointer;
}
.pad:active {
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
filter: alpha(opacity=100);
opacity: 1;
}
.shape1 {
border-top-left-radius: 300px;
background-color: green;
}
.shape2 {
float: left;
border-top-right-radius: 300px;
background-color: red;
clear: right;
}
.shape3 {
float: left;
border-bottom-left-radius: 300px;
background-color: yellow;
clear: left;
}
.shape4 {
float: left;
border-bottom-right-radius: 300px;
background-color: blue;
}
.circle {
position: absolute;
top: 195px;
left: 195px;
width: 250px;
height: 250px;
background: #000;
border-radius: 125px;
z-index: 10;
}
.simon {
text-align: center;
color: white;
font-family: Impact;
font-size: 5em;
margin-top: 25px;
}
.startButton {
width: 25px;
height: 25px;
border-radius: 50%;
background: red;
margin-left: 25%;
margin-top: 10px;
}
.strictButton {
width: 25px;
height: 25px;
border-radius: 50%;
background: #ffff00;
margin-top: 8px;
margin-left: 10px;
}
.strictIndicator {
height: 7px;
width: 7px;
background-color: #32050C;
border-radius: 50%;
margin-left: 20px;
margin-top: -5px;
}
.strictIndicator-on {
background-color: #DC0D29;
}
.lightUpPad {
opacity: 1;
}
.count {
text-align: center;
width: 60px;
height: 50px;
background-color: #32050C;
border-radius: 10px;
margin-left: 15px;
color: #DC0D29;
font-size: 2.5em;
border: 2px solid #222;
}
.controllabel {
text-align: center;
text-transform: uppercase;
color: #fff;
}
.countlabel {
margin-left: 15px;
}
.buttonlabel {
margin-top: 13px;
}
.controls {
float: left;
margin-left: 13px;
}
.strictlabel {
margin-top: 13px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
<audio preload="auto" id="pad1_audio"><source src="https://s3.amazonaws.com/freecodecamp/simonSound1.mp3" type="audio/mp3"></audio>
<audio preload="auto" id="pad2_audio"><source src="https://s3.amazonaws.com/freecodecamp/simonSound2.mp3" type="audio/mp3"></audio>
<audio preload="auto" id="pad3_audio"><source src="https://s3.amazonaws.com/freecodecamp/simonSound3.mp3" type="audio/mp3"></audio>
<audio preload="auto" id="pad4_audio"><source src="https://s3.amazonaws.com/freecodecamp/simonSound4.mp3" type="audio/mp3"></audio>
<audio preload="auto" id="buzzer"><source src="http://soundbible.com/mp3/Basketball Buzzer-SoundBible.com-1863250611.mp3" type="audio/mp3"></audio>
<div ng-app="App" ng-controller="MainCtrl">
<div class="wrapper">
<div class="back">
<div id="pad1" class="pad shape1" ng-click="registerClick(1)">
</div>
<div id="pad2" class="pad shape2" ng-click="registerClick(2)">
</div>
<div id="pad3" class="pad shape3" ng-click="registerClick(3)">
</div>
<div id="pad4" class="pad shape4" ng-click="registerClick(4)">
</div>
<div class="circle">
<div class="simon">simon</div>
<div class="controls">
<div class="count">{{count}}</div>
<div class="controllabel countlabel">COUNT</div>
</div>
<div class="controls">
<button class="startButton" ng-click="startGame()"></button>
<div class="controllabel buttonlabel">START</div>
</div>
<div class="controls">
<div ng-class="isStrict ? 'strictIndicator-on' : ''" class="strictIndicator"></div>
<button class="strictButton" ng-click="isStrict = !isStrict"></button>
<div class="controllabel strictlabel">STRICT</div>
</div>
</div>
</div>
</div>
</div>