I'm particularparticularly interested in the overall structure of my JS/JQuery - did I make good choices for the methods, is there enough separation of concerns etc. Are there any obvious conceptual errors?
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Robin Says</title>
<link rel="stylesheet" href="style.css">
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="script.js"></script>
</head>
<body>
<div id="wrapper">
<h1 id="title">Robin Says</h1>
<div id="control-area">
<p id="info">
Press start to play
</p>
<div id="score">Score: 0</div>
<button id="start-button">Start</button>
</div>
<div id="play-area">
<div id="pad1" class="pad"></div><!-- Could use data attributes -->
<div id="pad2" class="pad"></div>
<div id="pad3" class="pad"></div>
<div id="pad4" class="pad"></div>
</div>
</div>
</body>
</html>
JS/JQuery:
$( document ).ready( function() {
var Simon = {
// Game constants
cacheDom: function() {}, // to be implemented
flashSpeed: 400,
score : 0,
level: 1,
// Init whole game
init: function() {
this.bindControls();
},
newRound : function(){
this.unbindPads();
this.bindControls();
},
bindControls: function() {
// currently only start button needs event
$( '#start-button' ).on( 'click', this.playerRound.bind( this ) );
},
unbindControls: function() {
$( '#start-button' ).off( 'click' );
},
bindPads: function() {
$( '#play-area' ).on( 'click', '.pad', this.checkSequence.bind( this ) ); // pass object
},
unbindPads: function() {
$( '#play-area' ).off( 'click' );
},
playerRound: function() {
this.unbindControls();
$( '#info' ).text( 'Copy the sequence using mouse clicks' );
this.computerSequence = this.generateSequence( this.level );
this.remainingSequence = this.computerSequence.slice( 0 );
this.displaySequence( this.computerSequence );
this.bindPads();
},
// Generate random sequence for pads
generateSequence: function( length ) {
var seq = [];
for ( var i = 0; i < length; i++ ) {
seq.push( Math.floor( Math.random() * 4 ) + 1 ); // returns a random integer from 1 to 10]
}
return seq;
},
// Display sequence to player
displaySequence: function( seq ) {
var self = this;
if ( seq.length >= 1 ) {
var current_list_item = seq[ 0 ];
$( '#pad' + current_list_item ).css( 'opacity', '1' );
$( '#pad' + current_list_item ).animate( {
'opacity': '0.4'
}, self.flashSpeed, function() {
self.displaySequence( seq.slice( 1 ) );
} );
return;
}
},
checkSequence: function( e ) {
var boxNum = $( e.target ).attr( 'id' ).slice( -1 );
if ( boxNum != this.remainingSequence[ 0 ] ) {
this.playerLoses();
return; //?
}
this.remainingSequence = this.remainingSequence.slice( 1 );
if ( this.remainingSequence.length < 1 ) {
this.playerWins();
}
},
playerWins : function(){
$( '#info' ).text( 'You won. Press play to continue.' );
this.score += this.level;
$( '#score' ).text( 'Score: ' + this.score);
this.level += 1;
this.newRound();
},
playerLoses: function() {
$( '#info' ).text( 'You lost. Press play to play again.' );
this.level = 1;
this.score = 0;
$( '#score' ).text( 'Score: ' + this.score);
this.newRound();
}
};
Simon.init();
} );
// To do
// increae speed with level?
// Track highest score?
CSS:
* {
box-sizing: border-box;
}
body {
margin: 0;
background-color: grey;
font-family: "Lucida Console", Monaco, monospace;
}
#wrapper{
width: 600px;
height: 400px;
margin: auto;
position: relative;
}
#control-area{
width: 200px;
height: 400px;
background-color: black;
float: left;
}
#start-button{
display: block;
width: 100px;
margin: 20px auto;
background-color: white;
border: none;
border-radius: 30px;
padding: 5px;
top: 200px;
font-size: inherit;
font-family:inherit;
outline: none;
}
#info{
background-color: white;
width: 150px;
height: 90px;
padding: 5px;
margin: 20px auto;
border-radius: 5px;
}
#score{
background-color: white;
width: 100px;
padding: 5px;
margin: 20px auto;
border-radius: 5px;
}
#play-area{
width: 400px;
height: 400px;
float: right;
}
.pad{
width: 200px;
height: 200px;
float: left;
opacity: 0.4;
}
#pad1{
background: #66ff00;
}
#pad2{
background: red;
}
#pad3{
background: yellow;
}
#pad4{
background: blue;
}
$( document ).ready( function() {
var Simon = {
// Game constants
cacheDom: function() {}, // to be implemented
flashSpeed: 400,
score : 0,
level: 1,
// Init whole game
init: function() {
this.bindControls();
},
newRound : function(){
this.unbindPads();
this.bindControls();
},
bindControls: function() {
// currently only start button needs event
$( '#start-button' ).on( 'click', this.playerRound.bind( this ) );
},
unbindControls: function() {
$( '#start-button' ).off( 'click' );
},
bindPads: function() {
$( '#play-area' ).on( 'click', '.pad', this.checkSequence.bind( this ) ); // pass object
},
unbindPads: function() {
$( '#play-area' ).off( 'click' );
},
playerRound: function() {
this.unbindControls();
$( '#info' ).text( 'Copy the sequence using mouse clicks' );
this.computerSequence = this.generateSequence( this.level );
this.remainingSequence = this.computerSequence.slice( 0 );
this.displaySequence( this.computerSequence );
this.bindPads();
},
// Generate random sequence for pads
generateSequence: function( length ) {
var seq = [];
for ( var i = 0; i < length; i++ ) {
seq.push( Math.floor( Math.random() * 4 ) + 1 ); // returns a random integer from 1 to 10]
}
return seq;
},
// Display sequence to player
displaySequence: function( seq ) {
var self = this;
if ( seq.length >= 1 ) {
var current_list_item = seq[ 0 ];
$( '#pad' + current_list_item ).css( 'opacity', '1' );
$( '#pad' + current_list_item ).animate( {
'opacity': '0.4'
}, self.flashSpeed, function() {
self.displaySequence( seq.slice( 1 ) );
} );
return;
}
},
checkSequence: function( e ) {
var boxNum = $( e.target ).attr( 'id' ).slice( -1 );
if ( boxNum != this.remainingSequence[ 0 ] ) {
this.playerLoses();
return; //?
}
this.remainingSequence = this.remainingSequence.slice( 1 );
if ( this.remainingSequence.length < 1 ) {
this.playerWins();
}
},
playerWins : function(){
$( '#info' ).text( 'You won. Press play to continue.' );
this.score += this.level;
$( '#score' ).text( 'Score: ' + this.score);
this.level += 1;
this.newRound();
},
playerLoses: function() {
$( '#info' ).text( 'You lost. Press play to play again.' );
this.level = 1;
this.score = 0;
$( '#score' ).text( 'Score: ' + this.score);
this.newRound();
}
};
Simon.init();
} );
// To do
// increae speed with level?
// Track highest score?
* {
box-sizing: border-box;
}
body {
margin: 0;
background-color: grey;
font-family: "Lucida Console", Monaco, monospace;
}
#wrapper{
width: 600px;
height: 400px;
margin: auto;
position: relative;
}
#control-area{
width: 200px;
height: 400px;
background-color: black;
float: left;
}
#start-button{
display: block;
width: 100px;
margin: 20px auto;
background-color: white;
border: none;
border-radius: 30px;
padding: 5px;
top: 200px;
font-size: inherit;
font-family:inherit;
outline: none;
}
#info{
background-color: white;
width: 150px;
height: 90px;
padding: 5px;
margin: 20px auto;
border-radius: 5px;
}
#score{
background-color: white;
width: 100px;
padding: 5px;
margin: 20px auto;
border-radius: 5px;
}
#play-area{
width: 400px;
height: 400px;
float: right;
}
.pad{
width: 200px;
height: 200px;
float: left;
opacity: 0.4;
}
#pad1{
background: #66ff00;
}
#pad2{
background: red;
}
#pad3{
background: yellow;
}
#pad4{
background: blue;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Robin Says</title>
<link rel="stylesheet" href="style.css">
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="script.js"></script>
</head>
<body>
<div id="wrapper">
<h1 id="title">Robin Says</h1>
<div id="control-area">
<p id="info">
Press start to play
</p>
<div id="score">Score: 0</div>
<button id="start-button">Start</button>
</div>
<div id="play-area">
<div id="pad1" class="pad"></div><!-- Could use data attributes -->
<div id="pad2" class="pad"></div>
<div id="pad3" class="pad"></div>
<div id="pad4" class="pad"></div>
</div>
</div>
</body>
</html>