<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<canvas id="myCanvas"
width=400 height=400>
</canvas>
</body>
</html>
#myCanvas{
border:1px solid black;
}
// Bonnes pratiques
let canvas, ctx, w, h, rtx;
// Les balles
let tableauDesBalles = [];
let tableauDesObstacles = [];
let etatJeu;
let monstre = {
x: 10,
y: 10,
width: 100,
height: 100,
scale:1,
couleur: "gray",
speed: 5,
speedX : 0,
speedY: 0,
setScale: function(scale) {
this.scale = scale;
this.width = this.width * this.scale;
this.height = this.height * this.scale;
},
move: function() {
this.x += this.speedX;
this.y += this.speedY;
},
draw: function () {
// Bonne pratique: on sauve et on restaure le contexte
ctx.save();
ctx.translate(this.x, this.y);
ctx.scale(this.scale, this.scale);
// Tete ctx.fillRect(0, 0, 100, 100);
ctx.lineWidth=2;
ctx.fillStyle=this.couleur;
ctx.fillRect(0, 0, 100, 100);
ctx.lineWidth=5;
ctx.strokeRect(0, 0, 100, 100);
ctx.lineWidth=5;
ctx.strokeRect(25, 25, 20, 20);
ctx.fillStyle="red";
ctx.fillRect(20,0, 10, 10);
ctx.fillRect(70,0, 10, 10);
ctx.fillRect(30,10, 10, 10);
ctx.fillRect(60,10, 10, 10);
ctx.fillRect(20,20, 60, 10);
ctx.fillRect(10,30, 80, 10);
ctx.fillStyle="black";
ctx.fillRect(30,30, 10, 10);
ctx.fillRect(60,30, 10, 10);
ctx.fillStyle="red";
ctx.fillRect(0,40, 100, 10);
ctx.fillRect(0,50, 100, 10);
ctx.fillStyle="black";
ctx.fillRect(10,50, 10, 10);
ctx.fillRect(30,50, 10, 10);
ctx.fillRect(60,50, 10, 10);
ctx.fillRect(80,50, 10, 10);
ctx.fillStyle="red";
ctx.fillRect(0,60, 100, 10);
ctx.fillStyle="black";
ctx.fillRect(10,60, 10, 10);
ctx.fillRect(30,60, 10, 10);
ctx.fillRect(40,60, 10, 10);
ctx.fillRect(50,60, 10, 10);
ctx.fillRect(60,60, 10, 10);
ctx.fillRect(80,60, 10, 10);
ctx.fillStyle="red";
ctx.fillRect(30,70, 40, 10);
ctx.fillStyle="red";
ctx.fillRect(20,80, 10, 10);
ctx.fillRect(70,80, 10, 10);
ctx.fillRect(10,90, 10, 10);
ctx.fillRect(80,90, 10, 10);
ctx.restore();
}
};
// On exécutera init que quand la page
// sera chargée
window.onload = init;
function init() {
console.log("page chargée");
canvas = document.querySelector("#myCanvas");
w = canvas.width;
h = canvas.height;
ctx = canvas.getContext('2d');
// On créée les écouteurs de touches
document.addEventListener("keydown", traiteToucheEnfoncee, false);
document.addEventListener("keyup", traiteToucheRelachee, false);
// Initialiser le monstre
monstre.setScale(0.5);
// Créer des balles
creerDesBalles(10);
creerDesObstacles(2);
//etatJeu = "EcranAccueil";
etatJeu = "Jeu";
// on démarre l'animation
requestAnimationFrame(mainloop);
/*
setInterval(function() {
if(monstre.couleur == "black") {
monstre.couleur = "white";
} else {
monstre.couleur="black";
}
}, 500);*/
}
//------- CODE DES ECOUTEURS
function traiteToucheEnfoncee(evt) {
console.log("touche enfoncée code = " + evt.keyCode);
switch(evt.keyCode) {
case 39:
// fleche à droite
monstre.speedX = monstre.speed;
break;
case 37:
// fleche à gauche
monstre.speedX = -monstre.speed;
break;
case 40:
// fleche en bas
monstre.speedY = monstre.speed;
break;
case 38:
// fleche en haut
monstre.speedY = -monstre.speed;
break;
case 32:
// barre d'espace
if(etatJeu === "GameOver") {
newGame();
}
break;
}
}
function newGame() {
etatJeu = "Jeu";
monstre.x = 0;
monstre.y = 0;
monstre.speedX = monstre.speedY = 0;
// etc...
}
function traiteToucheRelachee(evt) {
console.log("touche relachee");
// Si fleche haut ou bas relachee, on annule juste la vitesse
// verticale
if((evt.keyCode === 40) || (evt.keyCode === 38))
monstre.speedY = 0;
if((evt.keyCode === 37) || (evt.keyCode === 39))
monstre.speedX = 0;
}
// ------ BOUCLE PRINCIPALE DU JEU
// boucle d'animation
function mainloop() {
// 1) on efface le contenu du canvas
ctx.clearRect(0, 0, w, h);
switch(etatJeu) {
case "Jeu":
// 2) On dessine dans le canvas des objets
//b1.draw();
dessinerLesBalles();
dessinerLesObstacles();
monstre.draw();
// 3) On déplace le monstre
monstre.move();
deplaceLesBalles();
// 4) On teste s'il y a collision
if((monstre.x + monstre.width) >= w) {
monstre.speedX = -monstre.speedX;
monstre.x = w - monstre.width;
}
if(monstre.x <= 0) {
monstre.speedX = -monstre.speedX;
monstre.x = 0;
}
if((monstre.y + monstre.height) >= h) {
monstre.speedY = -monstre.speedY;
monstre.y = h - monstre.height;
}
if(monstre.y <= 0) {
monstre.speedY = -monstre.speedY;
monstre.y = 0;
}
break;
case "GameOver":
afficheGameOver();
break;
case "MenuAccueuil":
break;
case "AfficheHighScores":
break;
}
// 5) on rappelle la boucle 60 fois par seconde
requestAnimationFrame(mainloop);
}
// ECRAN GAME OVER
function afficheGameOver() {
ctx.save();
ctx.font="40px Arial";
ctx.fillStyle="red";
ctx.fillText("GAME OVER", 150, 150);
ctx.strokeStyle = "black";
ctx.lineWidth=5;
ctx.strokeText("GAME OVER", 150, 150);
ctx.restore();
}
// ---- OBSTACLES
function Obstacle(x, y, width, height , couleur) {
this.x = x;
this.y = y;
this.width= width;
this.height= height;
this.couleur = couleur;
this.draw = function() {
ctx.fillStyle = this.couleur;
ctx.fillRect(x,y,width, height);
ctx.fillStyle = this.couleur;
ctx.fill();
};
}
function dessinerLesObstacles() {
// Méthode 1
for(var i = 0; i < tableauDesObstacles.length; i++) {
var b = tableauDesObstacles[i];
b.draw();
}
}
function creerDesObstacles(n) {
var tabCouleur = ["red", "orange", "green"];
for(var i = 0; i < n; i++) {
var x = 80 +(80 * i + 80) * i;
var y = 50 * i;
var numCouleur = Math.round(Math.random() * tabCouleur.length);
var couleur = tabCouleur[numCouleur];
this.width= 50;
this.height= 300;
var b = new Obstacle(x, y, width, height , couleur);
// tableauDesBalles[i] = b;
tableauDesObstacles.push(b);
}
}
// ------------------ MODELES POUR LES BALLES
function Balle(x, y, rayon, couleur, speedX, speedY) {
// les propriétés
this.x = x;
this.y = y;
this.r = rayon;
this.couleur = couleur;
this.speedX = speedX;
this.speedY = speedY;
this.draw = function() {
// On dessine une balle circulaire
ctx.beginPath(); // remet le buffer à zero
// ajoute l'ordre de dessiner un cercle dans le path
ctx.arc(this.x, this.y, this.r, 0, 2*Math.PI);
ctx.fillStyle = this.couleur;
// Pour dessiner tout le chemin
ctx.fill();
};
this.move = function() {
this.x += this.speedX;
this.y += this.speedY;
};
}
function dessinerLesBalles() {
// Méthode 1
for(var i = 0; i < tableauDesBalles.length; i++) {
var b = tableauDesBalles[i];
b.draw();
}
// Méthode 2
/*
tableauDesBalles.forEach(function(b, index) {
b.draw();
});
*/
}
function deplaceLesBalles() {
// Méthode 1
var collision = false;
tableauDesBalles.forEach((b, index) => {
b.move();
// tester Collisions avec les murs
if((b.x+b.r) > w) {
b.speedX = -b.speedX;
b.x = w-b.r;
}
if((b.x-b.r) < 0) {
b.speedX = -b.speedX;
b.x = b.r;
}
if((b.y+b.r) > h) {
b.speedY = -b.speedY;
b.y = h - b.r;
}
if((b.y-b.r) < 0) {
b.speedY = -b.speedY;
b.y = b.r;
}
if(testBallObstacle(b)) {
console.log(" ###### COLLISION");
}
if(testRectObstacle(monstre)) {
console.log("COLLISION11");
}
// Ici test de collision avec le monstre
if(circRectsOverlap(monstre.x, monstre.y, monstre.width, monstre.height, b.x, b.y, b.r)) {
collision = true;
}
});
// Si il y a au moins une collision on change la couleur
if(collision) {
monstre.couleur = "white";
} else {
monstre.couleur = "black";
}
}
function testBallObstacle(b){
var collision = false;
tableauDesObstacles.forEach(function(o, index) {
if(circRectsOverlap(o.x, o.y, o.width, o.height, b.x,b.y, b.r)){
// si la balle est plus bas que l'obstacle, ou plus haut, alors collision
// avec les côtés haut et bas
// On inversera que speedY
if((b.y < o.y) || (b.y > o.y + o.height)) {
// est-ce qu'on monte ou on descend?
if(b.speedY < 0) {
// collision avec le bas
b.y = o.y + o.height + b.r;
} else {
// collision avec le haut
b.y = o.y - b.r;
}
b.speedY = -b.speedY;
} else {
// La balle entre en collision avec
// un des deux côtés verticaux
// on inverse speedX
// est-ce que la balle allait de droite à gauche ?
if(b.speedX < 0)
b.x = o.x + o.width + b.r;
else
b.x = o.x - b.r;
b.speedX = -b.speedX;
}
}
});
}
function testRectObstacle(monstre){
var collision = false;
tableauDesObstacles.forEach(function(o, index) {
if(rectsOverlap(monstre.x, monstre.y, monstre.width, monstre.height, o.x, o.y, o.width, o.height)){
// Game over, si le monstre touche un obstacle il a perdu
etatJeu = "GameOver";
}
});
}
function creerDesBalles(n) {
var tabCouleur = ["red", "orange", "green"];
for(var i = 0; i < n; i++) {
var x = Math.random() * w; // entre 0 et largeur du canvas
var y = Math.random() * h; // entre 0 et heuteur du canvas
var rayon = 10 + 10*Math.random();
var numCouleur = Math.round(Math.random() * tabCouleur.length);
var couleur = tabCouleur[numCouleur];
var speedX = Math.random() * 5;
var speedY = Math.random() * 5;
var b = new Balle(x, y, rayon, couleur, speedX, speedY);
// Vérifier qu'elle n'est pas sur le
// monstre
if(circRectsOverlap(monstre.x, monstre.y, monstre.width, monstre.height, b.x, b.y, b.r*5)) {
i--;
} else {
// tableauDesBalles[i] = b;
tableauDesBalles.push(b);
}
}
}
// Detection de collisions
//---------------------------
// Collisions between rectangle and circle
function circRectsOverlap(x0, y0, w0, h0, cx, cy, r) {
var testX=cx;
var testY=cy;
if (testX < x0) testX=x0;
if (testX > (x0+w0)) testX=(x0+w0);
if (testY < y0) testY=y0;
if (testY > (y0+h0)) testY=(y0+h0);
return (((cx-testX)*(cx-testX)+(cy-testY)*(cy-testY))< r*r);
}
// Collisions between aligned rectangles
function rectsOverlap(x1, y1, w1, h1, x2, y2, w2, h2) {
if ((x1 > (x2 + w2)) || ((x1 + w1) < x2))
return false; // No horizontal axis projection overlap
if ((y1 > (y2 + h2)) || ((y1 + h1) < y2))
return false; // No vertical axis projection overlap
return true; // If previous tests failed, then both axis projections
// overlap and the rectangles intersect
}
function circleCollide(x1, y1, r1, x2, y2, r2) {
var dx = x1 - x2;
var dy = y1 - y2;
return ((dx * dx + dy * dy) < (r1 + r2)*(r1+r2));
}
//--------------------------------------- MODELES POUR LES BALLES
function Obstacle(x, y, width, height , couleur) {
this.x = x;
this.y = y;
this.width= width;
this.height= height;
this.couleur = couleur;
this.draw = function() {
ctx.fillStyle = this.couleur;
ctx.fillRect(x,y,width, height);
ctx.fillStyle = this.couleur;
ctx.fill();
};
}
function dessinerLesObstacles() {
// Méthode 1
for(var i = 0; i < tableauDesObstacles.length; i++) {
var b = tableauDesObstacles[i];
b.draw();
}
}
function creerDesObstacles(n) {
for(var i = 0; i < n; i++) {
var x = 120+(80 * i + 80) * i;
var y = 80 * i;
this.width= 30;
this.height= 250;
var b = new Obstacle(x, y, width, height , "blue");
// tableauDesBalles[i] = b;
tableauDesObstacles.push(b);
}
}
Output
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |