<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<p><audio id="player" src="https://mainline.i3s.unice.fr/mooc/guitarRiff1.mp3" controls><p>
Vitesse : 0 <input id="sliderVitesse" type="range" min=0 max=30 value=3 step=0.1>
<span id="speedValue">3</span>
<br>
<canvas width=400 height=400 id="myCanvas">
</canvas>
</body>
</html>
#myCanvas {
border:1px solid;
background-color:lightgrey;
}
window.onload = init;
let canvas, ctx;
let tableauObjetsGraphiques = [];
// etats des touches
let inputs = {};
// position souris
let mousePos = {x:10, y:10}
// etat du jeu
let gameState = "MENU START GAME";
let player;
function init() {
// programme principal appelé quand toute la page et ses ressources
// ont été chargées
// On récupère le canvas
//canvas = document.getElementById("myCanvas");
canvas = document.querySelector("#myCanvas");
// Pour dessiner on a besoin d'un contexte
ctx = canvas.getContext("2d");
creerEcouteursClavier();
creerEcouteurSouris();
let sliderVitesse = document.querySelector("#sliderVitesse");
sliderVitesse.oninput = (event) => {
const v = event.target.value;
console.log("vitesse = " + v)
document.querySelector("#speedValue").innerHTML = v;
augmenteVitesseObjetsGraphiques(event.target.value);
}
creerDesObjets(5);
player = document.querySelector("#player");
player.start();
requestAnimationFrame(animationloop);
}
function creerEcouteurSouris() {
window.onmousemove = (evt) => {
const rect = evt.target.getBoundingClientRect()
mousePos.x = evt.clientX - rect.left;
mousePos.y = evt.clientY - rect.top;
//console.log(mousePos);
}
}
function augmenteVitesseObjetsGraphiques(v) {
tableauObjetsGraphiques.forEach(o => {
//console.log(typeof v)
v = parseInt(v);
if(o.vitesse < 0)
o.vitesseX = -v;
else
o.vitesseX = v;
})
}
function creerEcouteursClavier() {
window.onkeyup = traiteKeyUp;
window.onkeydown = traiteKeyDown;
}
function traiteKeyUp(event) {
switch(event.key) {
case "ArrowRight":
inputs.right = false;
break;
case "ArrowLeft":
inputs.left = false;
break;
case "ArrowUp":
inputs.up = false;
break;
case "ArrowDown":
inputs.down = false;
break;
case "s":
inputs.s = false;
break;
case " ":
console.log("space relâchée")
inputs.space = false;
break;
}
}
function traiteKeyDown(event) {
//console.log(event.key)
switch(event.key) {
case "ArrowRight":
inputs.right = true;
break;
case "ArrowLeft":
inputs.left = true;
break;
case "ArrowUp":
inputs.up = true;
break;
case "ArrowDown":
inputs.down = true;
break;
case "s":
inputs.s = true;
break;
case " ":
console.log("space enfoncee")
inputs.space = true;
break;
}
}
class ObjetGraphique {
constructor(x, y, l, h, vx, vy, c) {
this.x = x;
this.y = y;
this.l = l;
this.h = h;
this.c = c;
this.vitesseX = vx;
this.vitesseY=vy;
}
draw(ctx) {
// BONNE PRATIQUE : sauver et restaurer le contexte
// On sauve au début on restaure à la fin
ctx.save();
// autre bonne pratique: on dessine toujours en 0, 0
// et on utilise plutôt les transformations géométriques
// ctx.translate, rotate, scale, etc.
// on positionne le repère en this.x, this.y
ctx.translate(this.x, this.y);
//ctx.scale(2,2);
ctx.rotate(this.angle);
ctx.translate(-this.l/2, -this.h/2);
ctx.strokeStyle = "black";
ctx.fillStyle = this.c;
ctx.lineWidth=4,
ctx.fillRect(0, 0, this.l, this.h);
//ctx.strokeRect(this.x, this.y, this.l, this.h);
// on restaure le contexte
ctx.restore();
}
move() {
this.x += this.vitesseX;
this.y += this.vitesseY;
}
}
class Joueur {
imageURL = 'https://www.icone-png.com/png/34/33500.png';
image = undefined;
constructor() {
this.x = 100;
this.y = 100;
this.vx = 1;
this.l = 50;
this.h = 50;
this.image = new Image();
this.image.src = this.imageURL;
this.image.onload = () => {
console.log("image chargée, prête à être dessinée");
}
}
draw(ctx) {
if(this.image)
ctx.drawImage(this.image, this.x, this.y, this.l, this.h);
}
}
let j = new Joueur();
class Monstre extends ObjetGraphique {
constructor(x, y, l, h, vx, vy, c, angle) {
super(x, y, l, h, vx, vy, c);
this.angle = angle;
}
draw(ctx) {
ctx.save();
// on positionne le repère en this.x, this.y
ctx.translate(this.x, this.y);
//ctx.scale(2,2);
ctx.rotate(this.angle);
ctx.translate(-this.l/2, -this.h/2);
this.l = 40;
this.h = 40;
ctx.fillStyle = "yellow"
ctx.fillRect(0, 0, this.l, this.h);
// oeil
ctx.fillStyle = "black"
ctx.fillRect(5, 10, 5, 5);
// second oeil
ctx.fillRect(30, 10, 5, 5);
ctx.restore();
}
move() {
this.x += this.vitesseX;
this.angle += 0.1;
}
}
let o = new ObjetGraphique(10, 10, 100, 100, 1, 1, "red");
function animationloop(tempsEcoule) {
// 1 - On efface le contenu du canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// pour du blur
//ctx.fillStyle = "rgb(0, 0, 0, 0.3)";
//ctx.fillRect(0, 0, canvas.width, canvas.height);
switch(gameState) {
case "MENU START GAME" :
ctx.font = "20pt Calibri";
ctx.fillText("PRESS <SPACE> TO START GAME", 30+Math.random()*5, 100);
if(inputs.space) gameState = "JEU EN COURS";
break;
case "GAME OVER" :
ctx.font = "20pt Calibri";
ctx.fillText("GAME OVER ! PRESS <touche S> TO START GAME", 20+Math.random()*5, 100);
if(inputs.s) gameState = "MENU START GAME";
break;
case "JEU EN COURS" :
// 2 - On dessine
dessinerLesObjets(ctx);
dessinerLeJoueur(ctx);
// 3 - On déplace les objets
deplacerLesObjets();
// on déplace le joueur
if(inputs.right) j.x+= j.vx;
if(inputs.left) j.x--;
if(inputs.up) j.y--;
if(inputs.down) j.y++;
if(inputs.space) j.y-=10;
detecteCollisionsJoueurEnnemis();
break;
}
// On demande au navigateur de rappeler cette fonction
// dans 1/60ème de seconde
requestAnimationFrame(animationloop);
}
function detecteCollisionsJoueurEnnemis() {
tableauObjetsGraphiques.forEach((o, index) => {
if(rectsOverlap(j.x, j.y, j.l, j.h, o.x-o.l/2, o.y-o.h/2, o.l, o.h)) {
console.log("COLLISION !");
tableauObjetsGraphiques.splice(index, 1);
}
});
if(tableauObjetsGraphiques.length === 0)
gameState = "GAME OVER";
}
function dessinerLeJoueur(ctx) {
// si on veut le déplacer à la souris
j.x = mousePos.x;
j.y = mousePos.y;
j.draw(ctx);
}
function creerDesObjets(n) {
for(let i=0; i < n; i++) {
let x = Math.random()*canvas.width;
let y= Math.random()*canvas.height;
let maxTaille = 50;
let minTaille = 10;
let l = minTaille + Math.random()*(maxTaille-minTaille);
let h = minTaille + Math.random()*(maxTaille-minTaille);
// vitesses entre -10 et +10 pixels par image
let vitesseMax = 5;
let vx = vitesseMax - Math.random()*2*vitesseMax;
let vy = vitesseMax - Math.random()*2*vitesseMax;
let r = Math.floor(Math.random()*255);
let g = Math.floor(Math.random()*255);
let b = Math.floor(Math.random()*255);
let c = `rgb(${r}, ${g}, ${b})`;
console.log("couleur = " + c);
let random = Math.random();
if(random > 0.5) {
tableauObjetsGraphiques.push(new Monstre(x, y, l, h, vx, vy, c, 0));
} else {
tableauObjetsGraphiques.push(new ObjetGraphique(x, y, l, h, vx, vy, c));
}
}
}
function deplacerLesObjets() {
tableauObjetsGraphiques.forEach(o => {
o.move();
// 4 - test des collisions
if ((o.x + o.l/2) > canvas.width){
o.vitesseX = -o.vitesseX;
// On remet l'objet au point de collision
this.x = canvas.width-o.l/2;
} else if(o.x-o.l/2 < 0) {
// on remet au point de contact
o.x = o.l/2;
o.vitesseX = -o.vitesseX;
} else if((o.y + o.h/2) > canvas.height) {
o.vitesseY = - o.vitesseY;
//o.y = canvas.height - o.h/2;
} else if(o.y-o.h/2 < 0) {
o.vitesseY = - o.vitesseY;
o.y = o.h/2;
}
});
}
function dessinerLesObjets(ctx) {
tableauObjetsGraphiques.forEach(o => {
o.draw(ctx);
});
}
// Collisions between aligned rectangles
function rectsOverlap(x1, y1, w1, h1, x2, y2, w2, h2) {
ctx.save();
ctx.strokeRect(x1, y1, w1, h1);
ctx.strokeRect(x2, y2, w2, h2);
ctx.restore();
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 update() {
o.move();
// 4 - test des collisions
if ((o.x + o.l) > canvas.width){
o.vitesseX = -o.vitesseX;
// On remet l'objet au point de collision
this.x = canvas.width-o.l;
} else if(o.x < 0) {
o.vitesseX = -o.vitesseX;
// on remet au point de contact
o.x = 0;
} else if((o.y + o.h) > canvas.height) {
o.vitesseY = - o.vitesseY;
o.y = canvas.height - o.h;
} else if(o.y < 0) {
o.vitesseY = - o.vitesseY;
o.y = 0;
}
}
*/
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. |