提交 77654452 编写于 作者: T Tim Petricola

Merge remote-tracking branch 'upstream/master' into best-score

Conflicts:
	index.html
	js/application.js
	js/html_actuator.js
...@@ -5,12 +5,15 @@ Made just for fun. [Play it here!](http://gabrielecirulli.github.io/2048/) ...@@ -5,12 +5,15 @@ Made just for fun. [Play it here!](http://gabrielecirulli.github.io/2048/)
[![Screenshot](http://pictures.gabrielecirulli.com/2048-20140309-234100.png)](http://pictures.gabrielecirulli.com/2048-20140309-234100.png) [![Screenshot](http://pictures.gabrielecirulli.com/2048-20140309-234100.png)](http://pictures.gabrielecirulli.com/2048-20140309-234100.png)
That screenshot is fake by, the way. I never reached 2048 :smile: That screenshot is fake, by the way. I never reached 2048 :smile:
## Contributing ## Contributing
Changes and improvements are more than welcome! Feel free to fork and open a pull request. Please make your changes in a specifically made branch and request to pull on `master`! If you can, please make sure the game fully works before sending the PR, as that will help speed up the process. Changes and improvements are more than welcome! Feel free to fork and open a pull request. Please make your changes in a specific branch and request to pull into `master`! If you can, please make sure the game fully works before sending the PR, as that will help speed up the process.
You can find the same information in the [contributing guide.](https://github.com/gabrielecirulli/2048/blob/master/CONTRIBUTING.md) You can find the same information in the [contributing guide.](https://github.com/gabrielecirulli/2048/blob/master/CONTRIBUTING.md)
## License ## License
2048 is licensed under the [MIT license.](https://github.com/gabrielecirulli/2048/blob/master/LICENSE.txt) 2048 is licensed under the [MIT license.](https://github.com/gabrielecirulli/2048/blob/master/LICENSE.txt)
## Donations
I made this in my spare time, and it's hosted on GitHub (which means I don't have any hosting costs), but if you enjoyed the game and feel like buying me coffee, you can donate at my BTC address: `1Ec6onfsQmoP9kkL3zkpB6c5sA4PVcXU2i`. Thank you very much!
...@@ -5,15 +5,7 @@ ...@@ -5,15 +5,7 @@
<title>2048</title> <title>2048</title>
<link href="style/main.css" rel="stylesheet" type="text/css"> <link href="style/main.css" rel="stylesheet" type="text/css">
<link rel="shortcut icon" href="favicon.ico">
<script src="js/hammer.min.js"></script>
<script src="js/keyboard_input_manager.js"></script>
<script src="js/html_actuator.js"></script>
<script src="js/grid.js"></script>
<script src="js/tile.js"></script>
<script src="js/local_score_manager.js"></script>
<script src="js/game_manager.js"></script>
<script src="js/application.js"></script>
<meta name="HandheldFriendly" content="True"> <meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320"> <meta name="MobileOptimized" content="320">
...@@ -75,8 +67,18 @@ ...@@ -75,8 +67,18 @@
</p> </p>
<hr> <hr>
<p> <p>
Created by <a href="http://gabrielecirulli.com" target="_blank">Gabriele Cirulli.</a> Based on <a href="https://itunes.apple.com/us/app/1024!/id823499224" target="_blank">1024 by Veewo Studio.</a> Created by <a href="http://gabrielecirulli.com" target="_blank">Gabriele Cirulli.</a> Based on <a href="https://itunes.apple.com/us/app/1024!/id823499224" target="_blank">1024 by Veewo Studio</a> and conceptually similar to <a href="http://asherv.com/threes/" target="_blank">Threes by Asher Vollmer.</a>
</p> </p>
</div> </div>
<script src="js/animframe_polyfill.js"></script>
<script src="js/hammer.min.js"></script>
<script src="js/keyboard_input_manager.js"></script>
<script src="js/html_actuator.js"></script>
<script src="js/grid.js"></script>
<script src="js/tile.js"></script>
<script src="js/local_score_manager.js"></script>
<script src="js/game_manager.js"></script>
<script src="js/application.js"></script>
</body> </body>
</html> </html>
(function() {
var lastTime = 0;
var vendors = ['webkit', 'moz'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame =
window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}
}());
document.addEventListener("DOMContentLoaded", function () { // Wait till the browser is ready to render the game (avoids glitches)
// Wait till the browser is ready to render the game (avoids glitches) window.requestAnimationFrame(function () {
window.requestAnimationFrame(function () { new GameManager(4, KeyboardInputManager, HTMLActuator, LocalScoreManager);
new GameManager(4, KeyboardInputManager, HTMLActuator, LocalScoreManager);
});
}); });
...@@ -31,11 +31,15 @@ KeyboardInputManager.prototype.listen = function () { ...@@ -31,11 +31,15 @@ KeyboardInputManager.prototype.listen = function () {
75: 0, // vim keybindings 75: 0, // vim keybindings
76: 1, 76: 1,
74: 2, 74: 2,
72: 3 72: 3,
87: 0, // W
68: 1, // D
83: 2, // S
65: 3 // A
}; };
document.addEventListener("keydown", function (event) { document.addEventListener("keydown", function (event) {
var modifiers = event.altKey && event.ctrlKey && event.metaKey && var modifiers = event.altKey || event.ctrlKey || event.metaKey ||
event.shiftKey; event.shiftKey;
var mapped = map[event.which]; var mapped = map[event.which];
......
...@@ -53,3 +53,10 @@ ...@@ -53,3 +53,10 @@
-webkit-animation-fill-mode: #{$str}; -webkit-animation-fill-mode: #{$str};
-moz-animation-fill-mode: #{$str}; -moz-animation-fill-mode: #{$str};
} }
// Media queries
@mixin smaller($width) {
@media screen and (max-width: $width) {
@content;
}
}
...@@ -140,6 +140,16 @@ hr { ...@@ -140,6 +140,16 @@ hr {
100% { 100% {
opacity: 1; } } opacity: 1; } }
.game-container .game-message a {
display: inline-block;
background: #8f7a66;
border-radius: 3px;
padding: 0 20px;
text-decoration: none;
color: #f9f6f2;
height: 40px;
line-height: 42px; }
.game-container { .game-container {
margin-top: 40px; margin-top: 40px;
position: relative; position: relative;
...@@ -179,14 +189,6 @@ hr { ...@@ -179,14 +189,6 @@ hr {
display: block; display: block;
margin-top: 59px; } margin-top: 59px; }
.game-container .game-message a { .game-container .game-message a {
display: inline-block;
background: #8f7a66;
border-radius: 3px;
padding: 0 20px;
text-decoration: none;
color: #f9f6f2;
height: 40px;
line-height: 42px;
margin-left: 9px; } margin-left: 9px; }
.game-container .game-message.game-won { .game-container .game-message.game-won {
background: rgba(237, 194, 46, 0.5); background: rgba(237, 194, 46, 0.5);
...@@ -222,20 +224,9 @@ hr { ...@@ -222,20 +224,9 @@ hr {
z-index: 2; } z-index: 2; }
.tile { .tile {
background: red;
width: 106.25px; width: 106.25px;
height: 106.25px; height: 106.25px;
border-radius: 3px; line-height: 116.25px; }
background: #eee4da;
text-align: center;
line-height: 116.25px;
font-size: 55px;
font-weight: bold;
z-index: 10;
-webkit-transition: 100ms ease-in-out;
-moz-transition: 100ms ease-in-out;
-webkit-transition-property: top, left;
-moz-transition-property: top, left; }
.tile.tile-position-1-1 { .tile.tile-position-1-1 {
position: absolute; position: absolute;
left: 0px; left: 0px;
...@@ -300,6 +291,18 @@ hr { ...@@ -300,6 +291,18 @@ hr {
position: absolute; position: absolute;
left: 364px; left: 364px;
top: 364px; } top: 364px; }
.tile {
border-radius: 3px;
background: #eee4da;
text-align: center;
font-weight: bold;
z-index: 10;
font-size: 55px;
-webkit-transition: 100ms ease-in-out;
-moz-transition: 100ms ease-in-out;
-webkit-transition-property: top, left;
-moz-transition-property: top, left; }
.tile.tile-2 { .tile.tile-2 {
background: #eee4da; background: #eee4da;
box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0), inset 0 0 0 1px rgba(255, 255, 255, 0); } box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0), inset 0 0 0 1px rgba(255, 255, 255, 0); }
...@@ -323,26 +326,41 @@ hr { ...@@ -323,26 +326,41 @@ hr {
background: #edcf72; background: #edcf72;
box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.2381), inset 0 0 0 1px rgba(255, 255, 255, 0.14286); box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.2381), inset 0 0 0 1px rgba(255, 255, 255, 0.14286);
font-size: 45px; } font-size: 45px; }
@media screen and (max-width: 480px) {
.tile.tile-128 {
font-size: 25px; } }
.tile.tile-256 { .tile.tile-256 {
color: #f9f6f2; color: #f9f6f2;
background: #edcc61; background: #edcc61;
box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.31746), inset 0 0 0 1px rgba(255, 255, 255, 0.19048); box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.31746), inset 0 0 0 1px rgba(255, 255, 255, 0.19048);
font-size: 45px; } font-size: 45px; }
@media screen and (max-width: 480px) {
.tile.tile-256 {
font-size: 25px; } }
.tile.tile-512 { .tile.tile-512 {
color: #f9f6f2; color: #f9f6f2;
background: #edc850; background: #edc850;
box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.39683), inset 0 0 0 1px rgba(255, 255, 255, 0.2381); box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.39683), inset 0 0 0 1px rgba(255, 255, 255, 0.2381);
font-size: 45px; } font-size: 45px; }
@media screen and (max-width: 480px) {
.tile.tile-512 {
font-size: 25px; } }
.tile.tile-1024 { .tile.tile-1024 {
color: #f9f6f2; color: #f9f6f2;
background: #edc53f; background: #edc53f;
box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.47619), inset 0 0 0 1px rgba(255, 255, 255, 0.28571); box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.47619), inset 0 0 0 1px rgba(255, 255, 255, 0.28571);
font-size: 35px; } font-size: 35px; }
@media screen and (max-width: 480px) {
.tile.tile-1024 {
font-size: 15px; } }
.tile.tile-2048 { .tile.tile-2048 {
color: #f9f6f2; color: #f9f6f2;
background: #edc22e; background: #edc22e;
box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.55556), inset 0 0 0 1px rgba(255, 255, 255, 0.33333); box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.55556), inset 0 0 0 1px rgba(255, 255, 255, 0.33333);
font-size: 35px; } font-size: 35px; }
@media screen and (max-width: 480px) {
.tile.tile-2048 {
font-size: 15px; } }
@-webkit-keyframes appear { @-webkit-keyframes appear {
0% { 0% {
...@@ -434,3 +452,180 @@ hr { ...@@ -434,3 +452,180 @@ hr {
.game-explanation { .game-explanation {
margin-top: 50px; } margin-top: 50px; }
@media screen and (max-width: 480px) {
html, body {
font-size: 15px; }
body {
margin: 20px 0;
padding: 0 20px; }
h1.title {
font-size: 50px; }
.container {
width: 280px;
margin: 0 auto; }
.score-container {
margin-top: 0; }
.heading {
margin-bottom: 10px; }
.game-container {
margin-top: 40px;
position: relative;
padding: 10px;
cursor: default;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
background: #bbada0;
border-radius: 6px;
width: 280px;
height: 280px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box; }
.game-container .game-message {
display: none;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: rgba(238, 228, 218, 0.5);
z-index: 100;
text-align: center;
-webkit-animation: fade-in 800ms ease 1200ms;
-moz-animation: fade-in 800ms ease 1200ms;
-webkit-animation-fill-mode: both;
-moz-animation-fill-mode: both; }
.game-container .game-message p {
font-size: 60px;
font-weight: bold;
height: 60px;
line-height: 60px;
margin-top: 222px; }
.game-container .game-message .lower {
display: block;
margin-top: 59px; }
.game-container .game-message a {
margin-left: 9px; }
.game-container .game-message.game-won {
background: rgba(237, 194, 46, 0.5);
color: #f9f6f2; }
.game-container .game-message.game-won, .game-container .game-message.game-over {
display: block; }
.grid-container {
position: absolute;
z-index: 1; }
.grid-row {
margin-bottom: 10px; }
.grid-row:last-child {
margin-bottom: 0; }
.grid-row:after {
content: "";
display: block;
clear: both; }
.grid-cell {
width: 57.5px;
height: 57.5px;
margin-right: 10px;
float: left;
border-radius: 3px;
background: rgba(238, 228, 218, 0.35); }
.grid-cell:last-child {
margin-right: 0; }
.tile-container {
position: absolute;
z-index: 2; }
.tile {
width: 57.5px;
height: 57.5px;
line-height: 67.5px; }
.tile.tile-position-1-1 {
position: absolute;
left: 0px;
top: 0px; }
.tile.tile-position-1-2 {
position: absolute;
left: 0px;
top: 68px; }
.tile.tile-position-1-3 {
position: absolute;
left: 0px;
top: 135px; }
.tile.tile-position-1-4 {
position: absolute;
left: 0px;
top: 203px; }
.tile.tile-position-2-1 {
position: absolute;
left: 68px;
top: 0px; }
.tile.tile-position-2-2 {
position: absolute;
left: 68px;
top: 68px; }
.tile.tile-position-2-3 {
position: absolute;
left: 68px;
top: 135px; }
.tile.tile-position-2-4 {
position: absolute;
left: 68px;
top: 203px; }
.tile.tile-position-3-1 {
position: absolute;
left: 135px;
top: 0px; }
.tile.tile-position-3-2 {
position: absolute;
left: 135px;
top: 68px; }
.tile.tile-position-3-3 {
position: absolute;
left: 135px;
top: 135px; }
.tile.tile-position-3-4 {
position: absolute;
left: 135px;
top: 203px; }
.tile.tile-position-4-1 {
position: absolute;
left: 203px;
top: 0px; }
.tile.tile-position-4-2 {
position: absolute;
left: 203px;
top: 68px; }
.tile.tile-position-4-3 {
position: absolute;
left: 203px;
top: 135px; }
.tile.tile-position-4-4 {
position: absolute;
left: 203px;
top: 203px; }
.game-container {
margin-top: 20px; }
.tile {
font-size: 35px; }
.game-message p {
font-size: 30px !important;
height: 30px !important;
line-height: 30px !important;
margin-top: 90px !important; }
.game-message .lower {
margin-top: 30px !important; } }
...@@ -153,145 +153,159 @@ hr { ...@@ -153,145 +153,159 @@ hr {
} }
} }
.game-container { // Styles for buttons
margin-top: 40px; @mixin button {
position: relative; display: inline-block;
padding: $grid-spacing; background: darken($game-container-background, 20%);
border-radius: 3px;
cursor: default; padding: 0 20px;
-webkit-touch-callout: none; text-decoration: none;
-webkit-user-select: none; color: $bright-text-color;
-moz-user-select: none; height: 40px;
line-height: 42px;
}
background: $game-container-background; // Game field mixin used to render CSS at different width
border-radius: $tile-border-radius * 2; @mixin game-field {
width: $field-width; .game-container {
height: $field-width; margin-top: 40px;
-webkit-box-sizing: border-box; position: relative;
-moz-box-sizing: border-box; padding: $grid-spacing;
box-sizing: border-box;
cursor: default;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
background: $game-container-background;
border-radius: $tile-border-radius * 2;
width: $field-width;
height: $field-width;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
.game-message {
display: none;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: rgba($tile-color, .5);
z-index: 100;
text-align: center;
p {
font-size: 60px;
font-weight: bold;
height: 60px;
line-height: 60px;
margin-top: 222px;
// height: $field-width;
// line-height: $field-width;
}
.game-message { .lower {
display: none; display: block;
margin-top: 59px;
}
position: absolute; a {
top: 0; @include button;
right: 0; margin-left: 9px;
bottom: 0; // margin-top: 59px;
left: 0; }
background: rgba($tile-color, .5);
z-index: 100;
text-align: center; @include animation(fade-in 800ms ease $transition-speed * 12);
@include animation-fill-mode(both);
p { &.game-won {
font-size: 60px; background: rgba($tile-gold-color, .5);
font-weight: bold; color: $bright-text-color;
height: 60px; }
line-height: 60px;
margin-top: 222px;
// height: $field-width;
// line-height: $field-width;
}
.lower { &.game-won, &.game-over {
display: block; display: block;
margin-top: 59px; }
} }
}
a { .grid-container {
display: inline-block; position: absolute;
background: darken($game-container-background, 20%); z-index: 1;
border-radius: 3px; }
padding: 0 20px;
text-decoration: none;
color: $bright-text-color;
height: 40px;
line-height: 42px;
margin-left: 9px;
// margin-top: 59px;
}
@include animation(fade-in 800ms ease $transition-speed * 12); .grid-row {
@include animation-fill-mode(both); margin-bottom: $grid-spacing;
&.game-won { &:last-child {
background: rgba($tile-gold-color, .5); margin-bottom: 0;
color: $bright-text-color;
} }
&.game-won, &.game-over { &:after {
content: "";
display: block; display: block;
clear: both;
} }
} }
}
.grid-container { .grid-cell {
position: absolute; width: $tile-size;
z-index: 1; height: $tile-size;
} margin-right: $grid-spacing;
float: left;
.grid-row { border-radius: $tile-border-radius;
margin-bottom: $grid-spacing;
&:last-child { background: rgba($tile-color, .35);
margin-bottom: 0;
}
&:after { &:last-child {
content: ""; margin-right: 0;
display: block; }
clear: both;
} }
}
.grid-cell {
width: $tile-size;
height: $tile-size;
margin-right: $grid-spacing;
float: left;
border-radius: $tile-border-radius; .tile-container {
position: absolute;
background: rgba($tile-color, .35); z-index: 2;
}
&:last-child { .tile {
margin-right: 0; width: $tile-size;
height: $tile-size;
line-height: $tile-size + 10px;
// Build position classes
@for $x from 1 through $grid-row-cells {
@for $y from 1 through $grid-row-cells {
&.tile-position-#{$x}-#{$y} {
position: absolute;
left: round(($tile-size + $grid-spacing) * ($x - 1));
top: round(($tile-size + $grid-spacing) * ($y - 1));
}
}
}
} }
} }
.tile-container { // End of game-field mixin
position: absolute; @include game-field;
z-index: 2;
}
.tile { .tile {
background: red;
width: $tile-size;
height: $tile-size;
border-radius: $tile-border-radius; border-radius: $tile-border-radius;
background: $tile-color; background: $tile-color;
text-align: center; text-align: center;
line-height: $tile-size + 10px;
font-size: 55px;
font-weight: bold; font-weight: bold;
z-index: 10; z-index: 10;
font-size: 55px;
@include transition($transition-speed ease-in-out); @include transition($transition-speed ease-in-out);
@include transition-property(top, left); @include transition-property(top, left);
// Build position classes
@for $x from 1 through $grid-row-cells {
@for $y from 1 through $grid-row-cells {
&.tile-position-#{$x}-#{$y} {
position: absolute;
left: round(($tile-size + $grid-spacing) * ($x - 1));
top: round(($tile-size + $grid-spacing) * ($y - 1));
}
}
}
$base: 2; $base: 2;
$exponent: 1; $exponent: 1;
$limit: 11; $limit: 11;
...@@ -345,8 +359,17 @@ hr { ...@@ -345,8 +359,17 @@ hr {
// Adjust font size for bigger numbers // Adjust font size for bigger numbers
@if $power >= 100 and $power < 1000 { @if $power >= 100 and $power < 1000 {
font-size: 45px; font-size: 45px;
// Media queries placed here to avoid carrying over the rest of the logic
@include smaller(480px) {
font-size: 25px;
}
} @else if $power >= 1000 { } @else if $power >= 1000 {
font-size: 35px; font-size: 35px;
@include smaller(480px) {
font-size: 15px;
}
} }
} }
...@@ -403,3 +426,63 @@ hr { ...@@ -403,3 +426,63 @@ hr {
.game-explanation { .game-explanation {
margin-top: 50px; margin-top: 50px;
} }
@include smaller(480px) {
// Redefine variables for smaller screens
$field-width: 280px;
$grid-spacing: 10px;
$grid-row-cells: 4;
$tile-size: ($field-width - $grid-spacing * ($grid-row-cells + 1)) / $grid-row-cells;
$tile-border-radius: 3px;
html, body {
font-size: 15px;
}
body {
margin: 20px 0;
padding: 0 20px;
}
h1.title {
font-size: 50px;
}
.container {
width: $field-width;
margin: 0 auto;
}
.score-container {
margin-top: 0;
}
.heading {
margin-bottom: 10px;
}
// Render the game field at the right width
@include game-field;
.game-container {
margin-top: 20px;
}
// Rest of the font-size adjustments in the tile class
.tile {
font-size: 35px;
}
.game-message {
p {
font-size: 30px !important;
height: 30px !important;
line-height: 30px !important;
margin-top: 90px !important;
}
.lower {
margin-top: 30px !important;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册