浏览代码

Refonte du code pour préciser les objectifs de chaque classe et séparer leurs tâches

les classes game et tube servent à décrire et modifier les données du modèle du jeu
la classe drawer s'occupe d'afficher le jeu dans la page web via les méthodes fournies par la librairie p5js
la classe controller s'occupe de la logique interne aux régles du jeu
la classe main sert à déclarer le controller ainsi que les méthodes appelées par la librairie p5js
master
Figg 10 个月前
父节点
当前提交
e7ea88f832
共有 8 个文件被更改,包括 243 次插入178 次删除
  1. 8
    7
      index.html
  2. 120
    38
      js/controller.js
  3. 25
    29
      js/drawer.js
  4. 0
    102
      js/game.js
  5. 0
    0
      js/lib/p5.min.js
  6. 16
    0
      js/main.js
  7. 67
    0
      js/model/game.js
  8. 7
    2
      js/model/tube.js

+ 8
- 7
index.html 查看文件

@@ -4,13 +4,14 @@
4 4
 <head>
5 5
 	<meta charset="utf-8">
6 6
 	<meta name="viewport" content="width=device-width, initial-scale=1.0">
7
-	<title>p5.js example</title>
7
+	<title>Le jeu des tubes là</title>
8 8
 	<link href="./css/style.css" rel="stylesheet">
9
-	<script src="./js/p5.min.js"></script>
10
-	<script src="./js/tube.js"></script>
11
-	<script src="./js/game.js"></script>
9
+	<script src="./js/lib/p5.min.js"></script>
10
+	<script src="./js/model/tube.js"></script>
11
+	<script src="./js/model/game.js"></script>
12 12
 	<script src="./js/drawer.js"></script>
13 13
 	<script src="./js/controller.js"></script>
14
+	<script src="./js/main.js"></script>
14 15
 </head>
15 16
 
16 17
 <body>
@@ -28,10 +29,10 @@
28 29
 			<input type="number" size="5" id="padding" value="10">
29 30
 		</menuitem>
30 31
 		<menuitem>
31
-			<label>Tube Size</label>
32
-			<input type="number" size="5" id="tbSize" value="50">
32
+			<label>Tube Scale</label>
33
+			<input type="number" size="5" id="scale" value="50">
33 34
 		</menuitem>
34
-		<button type="button" onclick="newGame()">New game</button>
35
+		<button type="button" onclick="controller.initializeGame()">New game</button>
35 36
 	</menu>
36 37
 	<main oncontextmenu="return false;">
37 38
 	</main>

+ 120
- 38
js/controller.js 查看文件

@@ -1,50 +1,132 @@
1
-function setup()
1
+class Controller
2 2
 {
3
-	newGame();
4
-}
3
+	#game;
4
+	#drawer;
5
+	#colorsBank = ['black','silver','gray','maroon','red','purple','fuchsia','green','lime','olive','yellow','navy','blue','teal','aqua'];
6
+	
7
+	constructor()
8
+	{
9
+		this.initializeGame();
10
+	}
11
+	
12
+	initializeGame() {
13
+		let params = this.gatherMenuValues();
14
+		
15
+		this.game = new Game(params.TUBESNUMBERS, params.TUBESLEVELS);
16
+		this.drawer = new Drawer(params.PADDING, params.SCALE);
17
+		
18
+		this.drawer.computeGameParams(params.TUBESNUMBERS, params.TUBESLEVELS);
19
+		
20
+		this.initializeColorTubes(params.TUBESLEVELS - 1);
21
+		
22
+		this.needUpdate = true;
23
+	}
5 24
 
6
-function newGame() {
7
-	let params = gatherMenuValues();
25
+	gatherMenuValues()
26
+	{
27
+		let inputTubesNumbers = parseInt(document.getElementById("tbNumber").value);
28
+		let inputTubesLevels = parseInt(document.getElementById("tbLevel").value);
29
+		let inputScale = parseInt(document.getElementById("scale").value);
30
+		let inputPadding = parseInt(document.getElementById("padding").value);
31
+		
32
+		return {
33
+			TUBESNUMBERS: inputTubesNumbers,
34
+			TUBESLEVELS: inputTubesLevels,
35
+			SCALE: inputScale,
36
+			PADDING: inputPadding
37
+		};
38
+	}
8 39
 	
9
-	this.game = new Game(params.TUBESNUMBERS, params.TUBESLEVELS);
10
-	this.drawer = new Drawer(params.PADDING);
40
+	initializeColorTubes(LayersPerTube)
41
+	{
42
+		let nbTubes = this.game.tubesNumber() - 1;
43
+		let allColors = [];
44
+		
45
+		for (let i = 0; i < nbTubes; i++)
46
+		{
47
+			let coloridx = i % this.#colorsBank.length;
48
+			for (let times = 0; times < LayersPerTube; times++)
49
+			{
50
+				allColors.push(this.#colorsBank[coloridx]);
51
+			}
52
+		}
53
+		
54
+		for (let index = allColors.length - 1; index >= 0; index--) {
55
+			let randomIndex = Math.floor(Math.random() * (index + 1));
56
+			let tubeIndex = Math.floor(index / LayersPerTube);
57
+			
58
+			this.game.tubeAt(tubeIndex).addColorLayer(allColors[randomIndex]);
59
+			
60
+			allColors[randomIndex] = allColors[index];
61
+		}
62
+	}
11 63
 	
12
-	this.drawer.setTubesParams(params.TUBESNUMBERS, params.TUBESLEVELS, params.TUBESIZE);
64
+	clickTube(tubeIndex)
65
+	{
66
+		let _clickedTube = this.game.tubeAt(tubeIndex);
67
+		if (_clickedTube == null) return;
68
+		
69
+		if (_clickedTube == this.game.selectedTube())
70
+			this.game.unselectTube();
71
+		else if (this.canPourInto(this.game.selectedTube(), _clickedTube))
72
+		{
73
+			this.pourColorInto(this.game.selectedTube(), _clickedTube);
74
+			this.game.unselectTube();
75
+		}
76
+		else if (!_clickedTube.isEmpty())
77
+			this.game.selectTubeAt(tubeIndex);
78
+	}
13 79
 	
14
-	this.needUpdate = true;
15
-}
16
-
17
-function mousePressed(e) 
18
-{
19
-	let tubeId = this.drawer.getTubeIdAt(mouseX, mouseY);
80
+	canPourInto(sourceTube, targetTube)
81
+	{
82
+		return sourceTube != null && targetTube != null
83
+			&& sourceTube != targetTube
84
+			&& (targetTube.isEmpty() || sourceTube.peekTopColor() == targetTube.peekTopColor())
85
+			&& !targetTube.isFull();
86
+	}
20 87
 	
21
-	if (tubeId != -1)
88
+	pourColorInto(sourceTube, targetTube)
22 89
 	{
23
-		this.game.selectTube(tubeId);
90
+		while (this.canPourInto(sourceTube, targetTube))
91
+		{
92
+			targetTube.addColorLayer(sourceTube.removeColorLayer());
93
+		}
94
+		
95
+		this.checkTubeCompletion(sourceTube);
96
+		this.checkTubeCompletion(targetTube);
24 97
 	}
25 98
 	
26
-	this.needUpdate = true;
27
-}
28
-
29
-function gatherMenuValues()
30
-{
31
-	let inputTubesNumbers = parseInt(document.getElementById("tbNumber").value);
32
-	let inputTubesLevels = parseInt(document.getElementById("tbLevel").value);
33
-	let inputTubeSize = parseInt(document.getElementById("tbSize").value);
34
-	let inputPadding = parseInt(document.getElementById("padding").value);
35
-	
36
-	return {
37
-		TUBESNUMBERS: inputTubesNumbers,
38
-		TUBESLEVELS: inputTubesLevels,
39
-		TUBESIZE: inputTubeSize,
40
-		PADDING: inputPadding
41
-	};
42
-}
43
-function draw()
44
-{
45
-	if (!this.needUpdate) return;
99
+	checkTubeCompletion(tube)
100
+	{
101
+		if (tube.isComplete())
102
+		{
103
+			this.game.removeTube(tube);
104
+			this.checkGameCompletion();
105
+		}
106
+	}
46 107
 	
47
-	this.drawer.draw(this.game);
108
+	checkGameCompletion()
109
+	{
110
+		if (this.game.tubesNumber() == 1 && this.game.tubeAt(0).isEmpty())
111
+		{
112
+			this.game.clean();
113
+		}
114
+	}
115
+
116
+	mousePressed(e) 
117
+	{
118
+		let clickedTubeId = this.drawer.getTubeIdAt(mouseX, mouseY);
119
+		this.clickTube(clickedTubeId);
120
+		
121
+		this.needUpdate = true;
122
+	}
48 123
 	
49
-	this.needUpdate = false;
124
+	runLoop()
125
+	{
126
+		if (!this.needUpdate) return;
127
+		
128
+		this.drawer.draw(this.game);
129
+		
130
+		this.needUpdate = false;
131
+	}
50 132
 }

+ 25
- 29
js/drawer.js 查看文件

@@ -1,64 +1,60 @@
1 1
 class Drawer
2 2
 {
3
-	#canvasWidth
4
-	#canvasHeight
3
+	#canvas;
5 4
 	
6
-	constructor(_padding)
5
+	constructor(_padding, _scale)
7 6
 	{
8 7
 		this.padding = _padding;
8
+		this.scale = _scale;
9 9
 		
10
-		createCanvas(0, 0);
10
+		this.#canvas = createCanvas(0, 0);
11 11
 	}
12 12
 	
13
-	setTubesParams(_tubesNumbers, _tubeLevels, _tubeSize)
13
+	computeGameParams(_tubesNumbers, _tubeLevels)
14 14
 	{
15
-		this.tubesNumbers = _tubesNumbers;
16
-		this.tubeLevels = _tubeLevels;
17
-		this.tubeSize = _tubeSize;
15
+		let canvasWidth = _tubesNumbers * (this.scale + this.padding) + this.padding;
16
+		let canvasHeight = 2 * this.padding + (_tubeLevels+1) * this.scale;
18 17
 		
19
-		this.#canvasWidth = this.tubesNumbers * (this.tubeSize + this.padding) + this.padding;
20
-		this.#canvasHeight = 2 * this.padding + (this.tubeLevels+1) * this.tubeSize;
21
-		
22
-		resizeCanvas(this.#canvasWidth, this.#canvasHeight);
18
+		resizeCanvas(canvasWidth, canvasHeight);
23 19
 	}
24 20
 	
25 21
 	draw(game)
26 22
 	{
27
-		let tubes = game.tubes;
28
-		let selectedTube = game.selectedTube;
29
-		
30
-		background('white');
23
+		background('orange');
31 24
 		
32
-		this.drawTubes(this.padding, this.padding+this.tubeSize, tubes, selectedTube);
25
+		this.drawTubes(this.padding, this.padding+this.scale, game);
33 26
 	}
34 27
 
35
-	drawTubes(x, y, tubes, selectedTube)
28
+	drawTubes(x, y, game)
36 29
 	{
37 30
 		let tubeX = x;
38 31
 		let tubeY = y;
39 32
 		let selectionOffset = 0;
40 33
 		
41
-		tubes.forEach(tube => {
42
-			selectionOffset = (tube == selectedTube ? this.tubeSize : 0);
34
+		for (let i = 0; i < game.tubesNumber(); i++)
35
+		{
36
+			let tube = game.tubeAt(i);
37
+			selectionOffset = (tube == game.selectedTube() ? this.scale : 0);
43 38
 			
44 39
 			this.drawTube(tubeX, tubeY - selectionOffset, tube);
45
-			tubeX += this.padding + this.tubeSize;
46
-		});
40
+			tubeX += this.padding + this.scale;
41
+		}
47 42
 	}
48 43
 
49 44
 	drawTube(x, y, tube)
50 45
 	{
46
+		let tubeLevels = tube.height();
51 47
 		
52
-		y += (this.tubeLevels-1) * this.tubeSize;
48
+		y += (tubeLevels-1) * this.scale;
53 49
 		
54
-		for(let i = 0; i < this.tubeLevels; i++)
50
+		for(let i = 0; i < tubeLevels; i++)
55 51
 		{
56 52
 			color = tube.getColorAtLevel(i);
57 53
 			color == null ? noFill() : fill(color);
58 54
 			
59 55
 			if (i >= 0)
60 56
 			{
61
-				rect(x, y - i * this.tubeSize, this.tubeSize);
57
+				rect(x, y - i * this.scale, this.scale);
62 58
 			}
63 59
 		}
64 60
 	}
@@ -67,15 +63,15 @@ class Drawer
67 63
 	{
68 64
 		if (!this.isInboundsCanvas(x,y)) return -1;
69 65
 		
70
-		let idWithPadding = (x - this.padding) / (this.tubeSize + this.padding);
71
-		return idWithPadding % 1 > 1 - (this.padding / (this.tubeSize + this.padding)) ? -1 : int(idWithPadding);
66
+		let idWithPadding = (x - this.padding) / (this.scale + this.padding);
67
+		return idWithPadding % 1 > 1 - (this.padding / (this.scale + this.padding)) ? -1 : int(idWithPadding);
72 68
 	}
73 69
 	
74 70
 	isInboundsCanvas(x, y)
75 71
 	{
76 72
 		return x >= this.padding
77 73
 			&& y >= this.padding
78
-			&& x < this.#canvasWidth - this.padding
79
-			&& y < this.#canvasHeight - this.padding;
74
+			&& x < this.#canvas.width - this.padding
75
+			&& y < this.#canvas.height - this.padding;
80 76
 	}
81 77
 }

+ 0
- 102
js/game.js 查看文件

@@ -1,102 +0,0 @@
1
-class Game {
2
-	#colorsBank = ['black','silver','gray','maroon','red','purple','fuchsia','green','lime','olive','yellow','navy','blue','teal','aqua'];
3
-	
4
-	constructor(nbTubes, tubeLevel)
5
-	{
6
-		this.tubes = [];
7
-		this.selectedTube = null;
8
-		
9
-		for (let i = 0; i < nbTubes; i++)
10
-		{
11
-			this.tubes.push(new Tube(tubeLevel));
12
-		}
13
-		
14
-		this.initializeColorTubes(tubeLevel);
15
-	}
16
-	
17
-	/*	The goal is to have each tube filled with its own color. Thus, there
18
-		is (tubes minus one) different colors divided in (tubeLevel) layers
19
-		mixed in the tubes.
20
-		One tube is empty to allow movement.
21
-	*/
22
-	initializeColorTubes(tubeLevel)
23
-	{
24
-		let nbTubes = this.tubes.length - 1;
25
-		let allColors = [];
26
-		
27
-		for (let i = 0; i < nbTubes; i++)
28
-		{
29
-			let coloridx = i % this.#colorsBank.length;
30
-			for (let times = 0; times < tubeLevel-1; times++)
31
-			{
32
-				allColors.push(this.#colorsBank[coloridx]);
33
-			}
34
-		}
35
-		
36
-		for (let i = allColors.length - 1; i > 0; i--) {
37
-			let j = Math.floor(Math.random() * (i + 1));
38
-			let temp = allColors[i];
39
-			allColors[i] = allColors[j];
40
-			allColors[j] = temp;
41
-		}
42
-		
43
-		for (let index = 0; index < allColors.length; index++)
44
-		{
45
-			let tubeIndex = Math.floor(index/(tubeLevel-1));
46
-			this.tubes[tubeIndex].addColorLayer(allColors[index]);
47
-		}
48
-	}
49
-	
50
-	selectTube(tubeId)
51
-	{
52
-		let newSelectedTube = this.tubes[tubeId];
53
-		
54
-		if (this.selectedTube == newSelectedTube)
55
-			this.selectedTube = null;
56
-		else if (this.canPourInto(this.selectedTube, newSelectedTube))
57
-			this.pourColorInto(this.selectedTube, newSelectedTube);
58
-		else if (!newSelectedTube.isEmpty())
59
-			this.selectedTube = newSelectedTube;
60
-	}
61
-	
62
-	canPourInto(sourceTube, targetTube)
63
-	{
64
-		return sourceTube != null && targetTube != null
65
-			&& sourceTube != targetTube
66
-			&& (targetTube.isEmpty() || sourceTube.peekTopColor() == targetTube.peekTopColor())
67
-			&& !targetTube.isFull();
68
-	}
69
-	
70
-	pourColorInto(sourceTube, targetTube)
71
-	{
72
-		while (this.canPourInto(sourceTube, targetTube))
73
-		{
74
-			targetTube.addColorLayer(sourceTube.removeColorLayer());
75
-		}
76
-		
77
-		this.checkTubeCompletion(sourceTube);
78
-		this.checkTubeCompletion(targetTube);
79
-	}
80
-	
81
-	checkTubeCompletion(tube)
82
-	{
83
-		if (tube.isComplete()) 
84
-		{
85
-			let tubeIndex = this.tubes.indexOf(tube);
86
-			
87
-			this.tubes.splice(tubeIndex, 1);
88
-			
89
-			if (this.selectedTube == tube) this.selectedTube = null;
90
-			
91
-			this.checkGameCompletion();
92
-		}
93
-	}
94
-	
95
-	checkGameCompletion()
96
-	{
97
-		if (this.tubes.length == 1 && this.tubes[0].isEmpty())
98
-		{
99
-			this.tubes = [];
100
-		}
101
-	}
102
-}

js/p5.min.js → js/lib/p5.min.js 查看文件


+ 16
- 0
js/main.js 查看文件

@@ -0,0 +1,16 @@
1
+let controller;
2
+
3
+function setup()
4
+{
5
+	controller = new Controller();
6
+}
7
+
8
+function draw()
9
+{
10
+	controller.runLoop();
11
+}
12
+
13
+function mousePressed(e)
14
+{
15
+	controller.mousePressed(e);
16
+}

+ 67
- 0
js/model/game.js 查看文件

@@ -0,0 +1,67 @@
1
+class Game {
2
+	#tubes;
3
+	#selectedTube;
4
+	
5
+	constructor(nbTubes, tubeLevel)
6
+	{
7
+		this.#tubes = [];
8
+		this.#selectedTube = null;
9
+		
10
+		for (let i = 0; i < nbTubes; i++)
11
+		{
12
+			this.#tubes.push(new Tube(tubeLevel));
13
+		}
14
+	}
15
+	
16
+	tubeAt(tubeIndex)
17
+	{
18
+		if (!this.isInRange(tubeIndex)) return null;
19
+		
20
+		return this.#tubes[tubeIndex];
21
+	}
22
+	
23
+	selectedTube()
24
+	{
25
+		return this.#selectedTube;
26
+	}
27
+	
28
+	selectTubeAt(index)
29
+	{
30
+		if (this.isInRange(index))
31
+		{
32
+			this.#selectedTube = this.#tubes[index];
33
+		}
34
+	}
35
+	
36
+	removeTube(tube)
37
+	{
38
+		let tubeIndex = this.#tubes.indexOf(tube);
39
+		
40
+		if (tubeIndex != -1)
41
+		{
42
+			let removed = this.#tubes.splice(tubeIndex, 1)[0];
43
+			if (removed = this.#selectedTube) this.unselectTube();
44
+		}
45
+	}
46
+	
47
+	clean()
48
+	{
49
+		this.#tubes = []
50
+		this.unselectTube();
51
+	}
52
+	
53
+	unselectTube()
54
+	{
55
+		this.#selectedTube = null;
56
+	}
57
+	
58
+	tubesNumber()
59
+	{
60
+		return this.#tubes.length;
61
+	}
62
+	
63
+	isInRange(index)
64
+	{
65
+		return index >= 0 && index < this.#tubes.length;
66
+	}
67
+}

js/tube.js → js/model/tube.js 查看文件

@@ -28,6 +28,11 @@ class Tube {
28 28
 		this.#colors = [];
29 29
 	}
30 30
 	
31
+	height()
32
+	{
33
+		return this.#maxLevels;
34
+	}
35
+	
31 36
 	isFull()
32 37
 	{
33 38
 		return this.#colors.length == this.#maxLevels;
@@ -38,7 +43,7 @@ class Tube {
38 43
 		return this.#colors.length == 0;
39 44
 	}
40 45
 	
41
-	emptySpaceSize()
46
+	remainingSpace()
42 47
 	{
43 48
 		return this.#maxLevels - this.#colors.length;
44 49
 	}
@@ -59,7 +64,7 @@ class Tube {
59 64
 
60 65
 	isComplete()
61 66
 	{
62
-		if (this.emptySpaceSize() != 1) return false;
67
+		if (this.remainingSpace() != 1) return false;
63 68
 		
64 69
 		let reference = this.#colors[0];
65 70
 		

正在加载...
取消
保存