<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/howler/1.1.28/howler.min.js"></script>
</head>
<body>
<canvas id="myCanvas" width=300 height=300></canvas>
<div id="fps"></div>
<audio id="music1" src="http://mainline.i3s.unice.fr/mooc/guitarRiff1.mp3" loop ></audio>
</body>
</html>
#myCanvas {
border:1px solid black;
/*background-color:pink;*/
}
// bonne pratique: on déclare ces variables globales
var canvas, ctx, w, h, fpsContainer;
// Etats des touches, de la souris, etc
var inputStates = {};
// les balles
var tableauDesBalles = [];
var nbBallesVivantes;
var nbBalles = 5;
// son
var plop;
// projectile
var projectile = {
x:0,
y:0,
angle:0,
dead:true,
vitesse:10,
direction:0,
draw:function() {
if(this.dead) return;
ctx.save();
console.log('draw projectile');
ctx.fillRect(this.x, this.y, 5, 5);
ctx.restore();
},
move: function() {
this.x += this.vitesse*Math.sin(-this.angle);
this.y += this.vitesse*Math.cos(this.angle);
},
};
// objet singleton
var monstre = {
x: 100,
y: 100,
speed: 3, // vitesse en pixels/image
speedX : 0,
speedY: 0,
width: 50,
height: 50,
angle: 0,
couleur: "yellow",
move: function(x, y) {
//this.x += this.speedX;
//this.y += this.speedY;
//this.y = y;
if(!this.angle) return;
this.x += 1*Math.sin(-this.angle);
this.y += 1*Math.cos(this.angle);
},
draw: function() {
// bonne pratique obligatoire !!!
ctx.save(); // on sauvegarde le contexte
ctx.translate(this.x, this.y);
ctx.rotate(this.angle);
ctx.scale(0.5, 0.5);
//ctx.translate(-50,-50);
ctx.shadowColor = "black"; // color
ctx.shadowBlur = 5; // blur level
ctx.shadowOffsetX = 5; // horizontal offset
ctx.shadowOffsetY = 5; //
// tete
ctx.beginPath();
ctx.arc(0, 0, 50, 0, Math.PI*2);
ctx.stroke();
ctx.fillRect(-20, -20, 5, 5);
ctx.fillRect(20, -20, 5, 5);
/*
ctx.fillStyle = this.couleur;
ctx.fillRect(0, 0, 100, 100);
ctx.lineWidth = 5;
ctx.strokeRect(0, 0, 100, 100);
this.drawYeux();
// nez
ctx.fillStyle = "green";
ctx.fillRect(40, 50, 10, 25);
ctx.strokeRect(40, 50, 10, 25);
// bouche
ctx.fillRect(20, 80, 50, 10);
ctx.strokeRect(20, 80, 50, 10);
ctx.fillStyle = "black";
ctx.fillRect(25, 80, 5, 10);
ctx.fillRect(40, 80, 5, 10);
ctx.fillRect(55, 80, 5, 10);
*/
// on restaure le contexte
ctx.restore();
},
drawYeux: function() {
// oeil gauche
ctx.lineWidth = 3;
ctx.strokeRect(10, 20, 20, 20);
ctx.fillStyle="red";
ctx.fillRect(17, 27, 10, 10);
// oeil droit
ctx.save();
ctx.translate(50, 0);
ctx.lineWidth = 3;
ctx.strokeRect(10, 20, 20, 20);
ctx.fillStyle="red";
ctx.fillRect(17, 27, 10, 10);
ctx.restore();
}
};
window.onload = init;
function init() {
console.log("page chargée");
canvas = document.querySelector("#myCanvas");
ctx = canvas.getContext("2d");
w = canvas.width;
h = canvas.height;
// Pour l'affichage du nombre d'images/s
fpsContainer = document.querySelector("#fps");
// on déclare des écouteurs pour les touches
// on va déplacer le monstre avec les fleches
document.addEventListener("keydown", traiteToucheEnfoncee, false);
document.addEventListener("keyup", traiteToucheRelachee, false);
// ecouteur pour la souris
canvas.addEventListener("mousemove", traiteSourisDeplacee, false);
// On démarre le jeu
//monstre.speedX = monstre.speed;
// On créer les balles
nbBallesVivantes = nbBalles;
creerDesBalles(nbBalles);
// On charge le son des balles qui touches les murs
plop = new Howl({
urls: ['http://mainline.i3s.unice.fr/mooc/plop.mp3']
});
mainloop();
//ctx.fillRect(150, 150, 100, 100);
}
// ----- BOUCLE D'ANIMATION
function mainloop(time) {
measureFPS(time);
// 1 On efface le contenu du canvas
ctx.clearRect(0, 0, w, h);
// 2 On dessine le monstre et les ennemis
//drawBall(100, 100, 15, "blue");
dessinerToutesLesBalles();
// angle entre le monstre la souris...
var dx = monstre.x - inputStates.mouseX;
var dy = monstre.y - inputStates.mouseY;
var angle = Math.atan2(dy, dx);
monstre.angle = angle+Math.PI/2;
monstre.draw();
// 3 On deplace
monstre.move();
testeCollisionsAvecMurs();
testCollisionsBallesAvecMurs();
testCollisionsBallesAvecJoueur();
// Regarder si le niveau est fini
// (toutes les balles mortes)
verifierFinNiveau();
// On vérifie l'état des touches, souris, gamepad etc.
checkInputStates();
// 4 On rappelle la boucle 60 fois par seconde
requestAnimationFrame(mainloop);
}
function checkInputStates() {
monstre.speedX = monstre.speedY = 0;
if(inputStates.right) {
monstre.speedX = monstre.speed;
}
if(inputStates.left) {
monstre.speedX = -monstre.speed;
}
if(inputStates.up) {
monstre.speedY = -monstre.speed;
}
if(inputStates.down) {
monstre.speedY = monstre.speed;
}
if(inputStates.space) {
if(projectile.dead) {
projectile.x = monstre.x ;
projectile.y = monstre.y;
projectile.angle = monstre.angle;
projectile.dead = false;
}
} else {
projectile.move();
projectile.draw();
if((projectile.x > w) || (projectile.x < 0) ||
(projectile.y > h) || (projectile.y < 0))
{
projectile.dead = true;
}
}
}
function verifierFinNiveau() {
// on a fini le niveau si toutes les balles
// sont mortes
if(nbBallesVivantes === 0) {
// On passe au niveau suivant, on crée
// deux balles de plus
nbBalles += 2;
nbBallesVivantes = nbBalles;
creerDesBalles(nbBalles);
}
}
function testCollisionsBallesAvecJoueur() {
var collision = false;
for(var i=0;i < tableauDesBalles.length; i++) {
var b = tableauDesBalles[i];
if(!b.dead) {
if(circRectsOverlap(monstre.x, monstre.y, monstre.width, monstre.height,
b.x, b.y, b.r)) {
collision=true;
b.dead = true;
nbBallesVivantes--;
}
}
if(collision) {
monstre.couleur = "green";
} else {
monstre.couleur = "yellow";
}
}
}
function testeCollisionsAvecMurs() {
if((monstre.x + monstre.width) >= w) {
monstre.speedX = 0;
monstre.x = w - monstre.width;
}
if(monstre.x <= 0) {
monstre.speedX = 0;
monstre.x = 0;
}
if((monstre.y + monstre.height) >= h) {
monstre.speedY = 0;
monstre.y = h - monstre.height;
}
if(monstre.y <= 0) {
monstre.speedY = 0;
monstre.y = 0;
}
}
// ------ les balles ----
function Balle(x, y, rayon, couleur, vitesseX, vitesseY) {
this.x = x;
this.y = y;
this.r = rayon;
this.couleur = couleur;
this.speedX = vitesseX;
this.speedY = vitesseY;
this.dead = false;
this.move = function() {
this.x += this.speedX;
this.y += this.speedY;
};
this.draw = function() {
ctx.save();
// On remet à zero le buffer des ordres de
// dessin dans le chemin/Path
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, 0, 2*Math.PI);
ctx.fillStyle = this.couleur;
ctx.strokeStyle = "red";
ctx.lineWidth = 3;
// On va dessiner les ordres dans le path
// une fois en plein et une fois en fil de fer
ctx.save();
ctx.shadowColor = "#bbbbbb"; // color
ctx.shadowBlur = 5; // blur level
ctx.shadowOffsetX = 5; // horizontal offset
ctx.shadowOffsetY = 5; //
ctx.fill();
ctx.restore();
ctx.stroke();
ctx.restore();
};
}
function creerDesBalles(n) {
for(var i=0;i < n; i++) {
var x = Math.random() * w;
var y = Math.random() * h;
var r = 10;
var couleur = "black";
var speedX = -5 + Math.random()*10;
var speedY = -5 + Math.random()*10;
var b = new Balle(x, y, r, couleur, speedX, speedY);
// Do not create a ball on the player. We augmented the ball radius
// to sure the ball is created far from the monster.
if (!circRectsOverlap(monstre.x, monstre.y,
monstre.width, monstre.height,
b.x, b.y, b.r * 3)) {
// On rajoute la balle au tableau
tableauDesBalles.push(b);
} else {
i--;
}
}
}
function dessinerToutesLesBalles() {
for(var i=0;i < tableauDesBalles.length; i++) {
var b = tableauDesBalles[i];
if(!b.dead) {
b.move();
b.draw();
}
}
}
function testCollisionsBallesAvecMurs() {
for(var i=0;i < tableauDesBalles.length; i++) {
var b = tableauDesBalles[i];
if(!b.dead){
// mur droit
if((b.x + b.r) > w) {
b.speedX = -b.speedX;
b.x = w - b.r;
plop.play();
}
// mur gauche
if(b.x-b.r <0) {
b.speedX = -b.speedX;
b.x = b.r;
plop.play();
}
// mur bas
if((b.y + b.r) > h) {
b.speedY = -b.speedY;
b.y = h - b.r;
plop.play();
}
// mur haut
if(b.y-b.r <0) {
b.speedY = -b.speedY;
b.y = b.r;
plop.play();
}
}
}
}
// ------- Mesurer le nombre d'images/s
// vars for counting frames/s, used by the measureFPS function
var frameCount = 0;
var lastTime;
var fpsContainer;
var fps;
var measureFPS = function(newTime){
// test for the very first invocation
if(lastTime === undefined) {
lastTime = newTime;
return;
}
//calculate the difference between last & current frame
var diffTime = newTime - lastTime;
if (diffTime >= 1000) {
fps = frameCount;
frameCount = 0;
lastTime = newTime;
}
//and display it in an element we appended to the
// document in the start() function
fpsContainer.innerHTML = 'FPS: ' + fps;
frameCount++;
};
// ------- DETECTION 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);
}
// ------- ECOUTEURS ------
// Les écouteurs de touches, maintenant ils sont génériques
function traiteToucheEnfoncee(evt) {
console.log("touche enfoncee code= " + evt.keyCode);
switch(evt.keyCode) {
case 39:
// fleche à droite
inputStates.right = true;
break;
case 37:
// fleche à gauche
inputStates.left = true;
break;
case 40:
// fleche en bas
inputStates.down = true;
break;
case 38:
// fleche en haut
inputStates.up = true;
break;
case 32:
// espace
inputStates.space = true;
break;
}
}
function traiteToucheRelachee(evt) {
console.log("touche relachee");
switch(evt.keyCode) {
case 39:
// fleche à droite
inputStates.right = false;
break;
case 37:
// fleche à gauche
inputStates.left = false;
break;
case 40:
// fleche en bas
inputStates.down = false;
break;
case 38:
// fleche en haut
inputStates.up = false;
break;
case 32:
// space
inputStates.space = false;
break;
}
}
function traiteSourisDeplacee(evt) {
//console.log("souris deplacee");
var rect = canvas.getBoundingClientRect();
var x = evt.clientX - rect.left;
var y = evt.clientY - rect.top;
inputStates.mouseX = x;
inputStates.mouseY = y;
}
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. |