Merge branch 'master' of https://git.etud.insa-toulouse.fr/nbillard/sokoban
This commit is contained in:
commit
109971f1d6
8 changed files with 246 additions and 48 deletions
65
index.html
65
index.html
|
@ -22,32 +22,63 @@
|
|||
<![endif]-->
|
||||
<nav>
|
||||
<h1>Sokoban</h1>
|
||||
<ol id="level-list">
|
||||
<ol id="level-list" class="not-in-win-animation">
|
||||
</ol>
|
||||
</nav>
|
||||
<main>
|
||||
<div class="controls">
|
||||
<div class="container">
|
||||
<aside class="left-sidebar">
|
||||
<table border="1">
|
||||
<thead>
|
||||
<th>Name</th>
|
||||
<th>Score</th>
|
||||
</thead>
|
||||
|
||||
<tbody id="scoreTable">
|
||||
<tr>
|
||||
<td>
|
||||
Axel
|
||||
</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Ronan
|
||||
</td>
|
||||
<td>2</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</aside>
|
||||
<main>
|
||||
<article class="not-in-win-animation">
|
||||
<canvas id="canvas" width="800" height="400"></canvas>
|
||||
<div id="tutorial-speech-bubble" class="text-bubble">
|
||||
<div class="dialog">
|
||||
<p id="tutorial-box" class="speech"></p>
|
||||
<div class="right-point">
|
||||
</div>
|
||||
<div class="right-point shifted">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
</main>
|
||||
<aside class="controls not-in-win-animation right-sidebar">
|
||||
<div id="timer">Time</div>
|
||||
<button id="pause-1">Pause</button>
|
||||
<button id="pause-2">Pause</button><br/>
|
||||
<label for="dificulty-slider">Difficulty</label><br/>
|
||||
<input type="range" min="0" max="100" value="50" id="difficulty-slider">
|
||||
<br/>
|
||||
</div>
|
||||
<div>
|
||||
<canvas id="canvas" width="800" height="400"></canvas>
|
||||
<div id="tutorial-speech-bubble" class="text-bubble">
|
||||
<div class="dialog">
|
||||
<div class="left-point">
|
||||
</div>
|
||||
<div class="left-point shifted">
|
||||
</div>
|
||||
<p id="tutorial-box" class="speech"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<p>Sokoban 2022</p>
|
||||
<p>Pour une meilleure expérience, veuillez utiliser ce jeu sur un ordinateur avec un écran horizontal.</p>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
<!-- <script type="module" src="./modules/ressources.mjs"></script> -->
|
||||
|
|
|
@ -2,6 +2,8 @@ import { levelsBlueprint } from '/modules/levels.mjs'
|
|||
import { generatePlayground } from '/modules/playground.mjs'
|
||||
import { Timer } from '/modules/timer.mjs'
|
||||
|
||||
const prionicSequence = [0, 2, 6, 12, 20, 30, 42];
|
||||
|
||||
export const selectLevel = (ctx, gameState, id) => {
|
||||
gameState.playground = generatePlayground(levelsBlueprint[id].structure, gameState.width, gameState.height);
|
||||
// TODO transfer expireFunction without a fail
|
||||
|
@ -18,15 +20,37 @@ export const fillLevelsSelection = (gameState, ctx) => {
|
|||
selectionButton.setAttribute("array-index", i);
|
||||
selectionButton.addEventListener("click", (click) => {
|
||||
selectLevel(ctx, gameState, click.srcElement.getAttribute("array-index"));
|
||||
// let blueprint = levelsBlueprint[
|
||||
// click.srcElement.getAttribute("array-index")
|
||||
// ];
|
||||
// gameState.playground = generatePlayground(blueprint.structure, gameState.width, gameState.height);
|
||||
// gameState.timer = new Timer(blueprint.time, gameState.timer.expireFunction);
|
||||
// gameState.playground.draw(ctx, gameState.width, gameState.height);
|
||||
});
|
||||
selectionButton.innerText = "Level" + i;
|
||||
selectionButton.innerText = "Level " + prionicSequence[i];
|
||||
listElement.appendChild(selectionButton);
|
||||
levelList.appendChild(listElement);
|
||||
}
|
||||
}
|
||||
|
||||
export class LevelManager {
|
||||
constructor(winFunction, StartingLevelId = 0) {
|
||||
self.CurrentLevelId = StartingLevelId;
|
||||
self.Completed = levelsBlueprint.map(() => { return false; });
|
||||
self.winFunction = winFunction;
|
||||
}
|
||||
|
||||
getFirstUncompleted() {
|
||||
for( let i = 0; i < self.Completed.size; i++ ) {
|
||||
if (!self.Completed[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
next(ctx, gameState) {
|
||||
self.Completed[self.CurrentLevelId] = true;
|
||||
let allLevelsFinished = self.Completed.reduce((a, b) => {
|
||||
return a && b;
|
||||
}, true);
|
||||
if (allLevelsFinished) {
|
||||
self.winFunction();
|
||||
}
|
||||
self.CurrentLevelId = getFirstUncompleted();
|
||||
selectLevel(ctx, gameState, self.CurrentLevelId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,57 @@ const level2Blueprint = {
|
|||
time: 23000,
|
||||
};
|
||||
|
||||
const level3Blueprint = {
|
||||
structure: [
|
||||
[Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall,],
|
||||
[Square.Wall, Square.Floor, Square.Floor, Square.Floor, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall,],
|
||||
[Square.Wall, Square.Floor, Square.Box, Square.Floor, Square.Destination, Square.Destination, Square.Destination, Square.Wall, Square.Wall, Square.Wall,],
|
||||
[Square.Wall, Square.Wall, Square.Destination, Square.Box, Square.Box, Square.Destination, Square.Floor, Square.Floor, Square.Wall, Square.Wall,],
|
||||
[Square.Wall, Square.Wall, Square.Destination, Square.Destination, Square.Floor, Square.Box, Square.Box, Square.Floor, Square.Wall, Square.Wall,],
|
||||
[Square.Wall, Square.Wall, Square.Destination, Square.Box, Square.Box, Square.Floor, Square.Box, Square.Floor, Square.Floor, Square.Floor],
|
||||
[Square.Wall, Square.Wall, Square.Player, Square.Destination, Square.Destination, Square.Box, Square.Box, Square.Floor, Square.Floor, Square.Wall,],
|
||||
[Square.Wall, Square.Wall, Square.Floor, Square.Floor, Square.Floor, Square.Floor, Square.Floor, Square.Wall, Square.Wall, Square.Wall,],
|
||||
[Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall,],
|
||||
],
|
||||
time: 8000,
|
||||
}
|
||||
|
||||
const level4Blueprint = {
|
||||
structure: [
|
||||
[Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall,],
|
||||
[Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Floor, Square.Floor, Square.Wall, Square.Wall, Square.Wall,],
|
||||
[Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Floor, Square.Box, Square.Wall, Square.Wall, Square.Wall,],
|
||||
[Square.Wall, Square.Wall, Square.Destination, Square.Floor, Square.Floor, Square.Floor, Square.Floor, Square.Floor, Square.Wall, Square.Wall, Square.Wall,],
|
||||
[Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Floor, Square.Floor, Square.Box, Square.Floor, Square.Floor, Square.Destination, Square.Wall,],
|
||||
[Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Box, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall,],
|
||||
[Square.Wall, Square.Floor, Square.Floor, Square.Wall, Square.Player, Square.Floor, Square.Box, Square.Floor, Square.Floor, Square.Destination, Square.Wall,],
|
||||
[Square.Wall, Square.Floor, Square.Floor, Square.Floor, Square.Floor, Square.Floor, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall,],
|
||||
[Square.Wall, Square.Destination, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall,],
|
||||
[Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall,],
|
||||
],
|
||||
time: 3000,
|
||||
}
|
||||
|
||||
const level5Blueprint = {
|
||||
structure: [
|
||||
[Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, ],
|
||||
[Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Floor, Square.Floor, Square.Floor, Square.Floor, Square.Floor, Square.Player, Square.Wall, Square.Wall, ],
|
||||
[Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Floor, Square.Box, Square.Wall, Square.Box, Square.Floor, Square.Wall, Square.Wall, Square.Wall, ],
|
||||
[Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Floor, Square.Box, Square.Floor, Square.Floor, Square.Box, Square.Wall, Square.Wall, Square.Wall, ],
|
||||
[Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Box, Square.Floor, Square.Box, Square.Floor, Square.Wall, Square.Wall, Square.Wall, ],
|
||||
[Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Floor, Square.Box, Square.Floor, Square.Wall, Square.Floor, Square.Wall, Square.Wall, Square.Wall, ],
|
||||
[Square.Wall, Square.Destination, Square.Destination, Square.Destination, Square.Destination, Square.Floor, Square.Floor, Square.Wall, Square.Wall, Square.Floor, Square.Box, Square.Floor, Square.Floor, Square.Box, Square.Floor, Square.Floor, Square.Wall, ],
|
||||
[Square.Wall, Square.Wall, Square.Destination, Square.Destination, Square.Destination, Square.Floor, Square.Floor, Square.Floor, Square.Floor, Square.Box, Square.Floor, Square.Floor, Square.Box, Square.Floor, Square.Floor, Square.Floor, Square.Wall, ],
|
||||
[Square.Wall, Square.Destination, Square.Destination, Square.Destination, Square.Floor, Square.Floor, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, ],
|
||||
[Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, Square.Wall, ],
|
||||
],
|
||||
time: 40000
|
||||
}
|
||||
|
||||
export const levelsBlueprint = [
|
||||
level1Blueprint,
|
||||
level2Blueprint,
|
||||
]
|
||||
level3Blueprint,
|
||||
level4Blueprint,
|
||||
level5Blueprint,
|
||||
];
|
||||
|
|
|
@ -2,8 +2,6 @@ export class Timer {
|
|||
readDifficulty(slider) {
|
||||
self.difficulty = 1.5 - slider.value * 0.01;
|
||||
self.time = self.originalTime * self.difficulty;
|
||||
console.log("difficulty: " + self.difficulty);
|
||||
console.log("time: " + self.time);
|
||||
}
|
||||
|
||||
constructor(time, expireFunction) {
|
||||
|
@ -48,8 +46,8 @@ export class Timer {
|
|||
if (self.timeRunning) {
|
||||
let timeStr = String(self.time).padStart(5, '0');
|
||||
self.timerElement.innerHTML = "Time : " + timeStr.slice(0, 3) + '.' + timeStr.slice(3);
|
||||
if (self.time == 0) {
|
||||
this.expireFunction();
|
||||
if (self.time <= 0) {
|
||||
self.expireFunction();
|
||||
clearInterval(self.intervalControler);
|
||||
self.timeRunning = false;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export class TutorialControler {
|
||||
static messages = [
|
||||
"V'là le Jérome avec son tracteur.\nFaut vit qu'il les mettes sous l'toit avant que ça pleuve.",
|
||||
"V'là le Jérome avec son tracteur.\nFaut vit qu'il les mettes sous l'toit avant que ça pleuve. (Appuye sur <Espace> pour continuer)",
|
||||
"Je m'suis dit : \"Faudrait que je d'mandes que tu lui y fasse\"",
|
||||
"Pi tant qu'à faire, c'pas dur. T'as qu'à appuyer sur les flèches",
|
||||
"Ben qu'est qu't'attends ? Vas y!",
|
||||
|
|
25
script.js
25
script.js
|
@ -1,7 +1,7 @@
|
|||
import { generatePlayground } from '/modules/playground.mjs'
|
||||
import { levelsBlueprint } from '/modules/levels.mjs'
|
||||
import { MoveDirection } from '/modules/enums.mjs'
|
||||
import { fillLevelsSelection, selectLevel } from '/modules/levelSelection.mjs'
|
||||
import { fillLevelsSelection, selectLevel, LevelManager } from '/modules/levelSelection.mjs'
|
||||
import { Timer } from '/modules/timer.mjs'
|
||||
import { TutorialControler } from '/modules/tutorialControler.mjs'
|
||||
import { Scoreboard } from '/modules/scoreboard.mjs'
|
||||
|
@ -26,6 +26,10 @@ let gameState = {
|
|||
alert("Les vaches mangent le foin");
|
||||
}),
|
||||
playable: false,
|
||||
levelManager: new LevelManager( () => {
|
||||
alert("Toutes les bottes sont rangées");
|
||||
gameState.timer.stop();
|
||||
} ),
|
||||
levelId: 0,
|
||||
};
|
||||
|
||||
|
@ -55,14 +59,21 @@ window.addEventListener("keydown", (event) => {
|
|||
}
|
||||
gameState.playground.draw(ctx, canvas.width, canvas.height);
|
||||
if (gameState.playground.isSolved()) {
|
||||
gameState.levelId++;
|
||||
selectLevel(ctx, gameState, gameState.levelId);
|
||||
gameState.levelManager.next(ctx, gameState);
|
||||
}
|
||||
} else {
|
||||
tutorial.next();
|
||||
if (tutorial.isFinished()) {
|
||||
gameState.playable = true;
|
||||
gameState.timer.start();
|
||||
switch (event.key) {
|
||||
case "ArrowRight":
|
||||
case " ":
|
||||
case "Enter":
|
||||
tutorial.next();
|
||||
if (tutorial.isFinished()) {
|
||||
gameState.playable = true;
|
||||
gameState.timer.start();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
99
style.css
99
style.css
|
@ -6,29 +6,107 @@
|
|||
|
||||
body {
|
||||
background-color: var(--main-background-color);
|
||||
color: --main-invert-color;
|
||||
color: --main-text-color;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 2rem 0 0 0;
|
||||
display: flex;
|
||||
min-height: 40vh;
|
||||
}
|
||||
|
||||
aside {
|
||||
margin: 0 auto;
|
||||
float: left;
|
||||
width: 20rem;
|
||||
justify-content: space-between;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
background-color: yellowgreen;
|
||||
padding: 0 20%;
|
||||
}
|
||||
|
||||
nav ol {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
nav ol li {
|
||||
margin: auto 1rem;
|
||||
}
|
||||
|
||||
nav ol li button {
|
||||
background-color: transparent;
|
||||
padding: 0.5rem;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
|
||||
footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
position:fixed;
|
||||
margin-top: auto;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
background-color: yellowgreen;
|
||||
}
|
||||
|
||||
footer p:last-child {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
|
||||
width:100%;
|
||||
}
|
||||
|
||||
thead {
|
||||
width:100%;
|
||||
background:#000;
|
||||
padding:(12px * 1.5) 0;
|
||||
color:wheat;
|
||||
}
|
||||
|
||||
tr {
|
||||
text-align: center;
|
||||
width:100%;
|
||||
padding:(12px * 1.5) 0;
|
||||
}
|
||||
|
||||
tr:nth-of-type(even) {
|
||||
background:lightgray;
|
||||
}
|
||||
|
||||
.text-bubble {
|
||||
/* transform: rotate(90deg); */
|
||||
position: relative;
|
||||
margin: auto;
|
||||
margin-left: 658px;
|
||||
margin-top: -385px;
|
||||
margin-left: 185px;
|
||||
margin-top: -395px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.dialog {
|
||||
height: 200px;
|
||||
width: 400px;
|
||||
height: 150px;
|
||||
width: 350px;
|
||||
background-color: var(--main-background-color);
|
||||
position: relative;
|
||||
border-radius: 10%;
|
||||
|
@ -37,7 +115,7 @@ main {
|
|||
border: 1px solid black;
|
||||
}
|
||||
|
||||
.left-point {
|
||||
.right-point {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 1rem solid transparent;
|
||||
|
@ -45,19 +123,18 @@ main {
|
|||
border-top: 5rem solid black;
|
||||
position: absolute;
|
||||
margin-top: 30%;
|
||||
margin-left: -10%;
|
||||
transform: rotate(60deg) ;
|
||||
margin-left: 100%;
|
||||
transform: rotate(-60deg) ;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.shifted {
|
||||
transform:rotate(60deg) translate(0px,-2px);
|
||||
transform:rotate(-60deg) translate(0px,-2px);
|
||||
border-top: 5rem solid white;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.speech {
|
||||
z-index: 3;
|
||||
margin: auto;
|
||||
|
|
7
todo.md
7
todo.md
|
@ -17,3 +17,10 @@
|
|||
|
||||
* Prompt for username after ending
|
||||
* Table with filled usernames
|
||||
|
||||
## Insectes
|
||||
|
||||
* Error when last level is successfully finished
|
||||
* Size of the canvas: tiles not squared with some levels
|
||||
* Timer does not stop on win
|
||||
* Le tracteur devient John Cena
|
||||
|
|
Loading…
Reference in a new issue