Billard en javascript c'est possible !

Soyez le premier à donner votre avis sur cette source.

Vue 13 540 fois - Téléchargée 2 291 fois

Description

Hello tout le monde,
je reviens en force avec un petit jeu que je suis en train de terminer, un jeu de billard en full javascript !
-le programme est basé sur mon moteur de collision encore quelques tout petits bugs sur les chocs (cas extrêmes qui n'arrive pas souvent)
-la queue de billard est dessinée à partir de l'algorithme de Bresenham (tracage de segement) + une modif perso pour l'épaisseur de la droite

vous pouvez déjà commencer à voir un aperçu du futur jeu, même si il n'est pas encore finalisé!
Même si il reste une grosse partie à faire, j'ai programmé la partie la plus difficile !

20/04/09 : ajout d'une méthode ultra rapide qui détecte les croisements de segements, cela me permet de détecter les rebords + les trous, les rebonds se font désormés en fonction de l'angle du rebord ... :)
dans le jeux cela correspond à l'encadré en rouge (pour enlever l'affichage tu rectangle rouge, remplacer dans le source "var d=true;" par "var d=false;"

Source / Exemple :


var balles = new Array();
var tmp = null;
var d=false ; //debug = true
var minx=10,miny=30,maxx=440,maxy=230; //position absolu de la fenetre de jeux
var rad2deg=180/Math.PI; //conversion du radian au degres
var deg2rad=Math.PI/180; //conversion du degres au radian
var coefLin=0.005 ; //coeficient de ralentissement (décroissance liénaire)
var seuilStop=0.1; // stop le deplacement si vitesse<seuil
var	a_v1 = 0, v_v1 = 5;
var pause = true;
var col=/*j*/1,/**/2,1,/**/1,3,2,/**/2,1,2,1,/**/1,2,1,2,2;	
var src=['blanche','jaune','rouge','noir']
var fichier
//distance & force maxi de la queue
var dmin = 10, dmax = 70, fmax = 30;

//creation de la bille
function Balle(id,x,y,a,v,r,t)
{
	this.id = id; //identifiant
	this.x =x; //position x
	this.nx =x; // prochaine position -> pour les chocs
	this.y =y;
	this.ny =y;
//TODO: remplacer angle,vitesse par dx & dy (+rapide pr les calculs)
	this.a = a; //angle
	this.v = v; //vitesse
	this.m = 4; //masse
	this.r = r; //rayon
	this.t = t; //couleur/type de la balle
	this.bouge =true; //patch pour eviter les chevauchements
}

/*creation de la queue
angle : angle entre queue et boule 
deltaF : distance de la boule en fonction de la force
posX,posY : position de la boule

  • /
function dessinQueue(angle,deltaForce,posX,posY) { Lq = 200; // longueur de la queue pcos=Math.cos(angle); psin=Math.sin(angle); xmin= posX+(dmin+deltaForce)*pcos; ymin= posY+(dmin+deltaForce)*psin; xmoy= posX+(dmin+deltaForce+10)*pcos; ymoy= posY+(dmin+deltaForce+10)*psin; xmax= posX+(dmin+deltaForce+Lq)*pcos; ymax= posY+(dmin+deltaForce+Lq)*psin; htm=ligne2(xmin,ymin,xmoy,ymoy,6,'#c0c0c0');//embout htm+=ligne2(xmoy,ymoy,xmax,ymax,6,'brown'); return htm; } /* convertie position souris en angle + distance => force
  • /
function bougerQ(px,py) { //coordonnée de la balle blanche var posX = balles[0].x,posY = balles[0].y; py-=miny;px-=minx; a_v1= Math.atan2(py-posY,px-posX); deltaForce= Math.sqrt((py-posY)*(py-posY)+(px-posX)*(px-posX)); deltaForce=((deltaForce+dmin)>dmax) ? dmax : deltaForce; deltaForce=(deltaForce<dmin) ? dmin : deltaForce; v_v1 = deltaForce/10; balles[0].a = a_v1 * rad2deg + 180; balles[0].v = v_v1; _("ecran2").innerHTML=dessinQueue(a_v1,deltaForce,posX,posY); } /* capture deplacement de la souris (onmousemove)
  • /
function bougerQueue(event) { var ev = event || window.event; //getProp(ev); if (pause) { tmp=setTimeout("bougerQ("+(ev.pageX||ev.clientX)+","+(ev.pageY||ev.clientY)+")",10); } } /* capture clic de la souris (onclick)
  • /
function tirer() { pause=false; _("ecran2").innerHTML=""; boucle(); } //pr simplifier les appel des objets function _(idx) {return document.getElementById(idx);} function _v(idx) {return parseFloat(document.getElementById(idx).value,10);} //initialisation/reset function depart() { //Retourne l'air du plateau + onresize getPosition(); //efface tempo if (tmp!=null) {clearTimeout(tmp);} //lise des boules balles = new Array(); //coefficient de freinage //decroissance linéaire coefLin = 0.005; //ajout de la boule blanche balles.push(new Balle("b1",120,120,a_v1,v_v1,8.5,0)); blanche=balles[0]; //d=false; //ajout des boules + disposition en triangle n=0; for (x=0;x<6;x++) for (y=0;y<x;y++) { balles.push(new Balle("r"+n,270+x*20,150-y*20-(5-x)*10,0,0,9,col[n])); n++; } //affiche les boules a l'ecran ajoutBalle(); //associe les evenements document.onmousemove=bougerQueue; } function getPosition() { //position de l'air du plateau, ok sous IE & firefox minx=parseInt(_("ecran").offsetLeft,10); miny=parseInt(_("ecran").offsetTop,10); maxx=parseInt(_("ecran").offsetWidth,10); maxy=parseInt(_("ecran").offsetHeight,10); //ajuste le div de la queue _("ecran2").style.left=minx; _("ecran2").style.top=miny; _("ecran2").style.width=maxx; _("ecran2").style.height=maxy; } //retourne les proprietes d'un objet (debug) function getProp(x) { htm=""; for (e in x) htm+=e+":"+x[e]+"<br>"; _("debug_").innerHTML=htm; } //boucle de deplacement function boucle() { //deplace les boules bougeMoi(); //test les chocs contre les murs et entre les boules testChoc(); //replace les boules placeMoi(); //relance la fonction apres 10ms //a ajuster en fonction de la vitesse de la machine if (!pause) { tmp = setTimeout("boucle()",10); } } function testChoc() { for (e=0;e<balles.length;e++) { b=balles[e]; //collision avec les murs if (b.nx<b.r) {b.nx=b.r; b.a = 180-b.a;} if ((b.nx+b.r)>maxx) {b.nx=maxx-b.r; b.a = 180-b.a;} if (b.ny<b.r) {b.ny=b.r; b.a = -b.a;} if ((b.ny+b.r)>maxy) {b.ny=maxy-b.r; b.a = -b.a;} } for (e=0;e<balles.length;e++) { b=balles[e]; for (k=e+1;k<balles.length;k++) { bk=balles[k]; //distance entre 2 balles < sommes des 2 rayons //version light pr la vitesse d'execution distn=(b.nx-bk.nx)*(b.nx-bk.nx)+(b.ny-bk.ny)*(b.ny-bk.ny); if ((distn<=((b.r+bk.r)*(b.r+bk.r)))&&(b.v>0||bk.v>0)) { collision(b,bk); b.bouge=false; } } } //attribue les nouvelles positions à la boule for (e=0;e<balles.length;e++) { b=balles[e]; if(b.bouge) { b.x = b.nx; b.y = b.ny; } b.bouge=true; } } //test de collision function collision(aa,bb) { angle= Math.atan2(bb.ny-aa.ny,bb.nx-aa.nx); //dy/dx ra=aa.a*deg2rad;rb=bb.a*deg2rad;m2=aa.m+bb.m;//constante pr eviter les recalculs ca=Math.cos(angle); sa=Math.sin(angle); //if (d) alert("aa [angle depart="+aa.a+", vitesse="+aa.v+"]\nbb [angle depart="+bb.a+", vitesse="+bb.v+"]\n angle collision="+angle*rad2deg); //calcul des vitesses normal et perpendiculaire au choc va_norm=aa.v*Math.cos(-ra+angle); va_perp=aa.v*Math.sin(-ra+angle); vb_norm=bb.v*Math.cos(-rb+angle); vb_perp=bb.v*Math.sin(-rb+angle); //if (d) alert("va_norm :"+va_norm+", va_perp :"+va_perp+"\nvb_norm :"+vb_norm+", vb_perp :"+vb_perp); //conservation energie va2_norm=( (aa.m-bb.m)/m2)*va_norm+( (2*bb.m)/m2 )*vb_norm; vb2_norm=( (bb.m-aa.m)/m2)*vb_norm+( (2*aa.m)/m2 )*va_norm; //if (d) alert("va2_norm :"+va2_norm+", vb2_norm :"+vb2_norm); //nouvelle position, on resort ses cours de maths va2x=va2_norm*ca-va_perp*Math.cos(angle+Math.PI/2); //cos(a+PI/2) = -sin(a) va2y=va2_norm*sa-va_perp*Math.sin(angle+Math.PI/2); //sin(a+PI/2) = cos(a) vb2x=vb2_norm*ca-vb_perp*Math.cos(angle+Math.PI/2); vb2y=vb2_norm*sa-vb_perp*Math.sin(angle+Math.PI/2); //if (d) alert("va2x :"+va2x+", va2y :"+va2y+"\nvb2x :"+vb2x+", vb2y :"+vb2y); //recalcul angle + vitesse aa.v = Math.sqrt(va2x*va2x+va2y*va2y); bb.v = Math.sqrt(vb2x*vb2x+vb2y*vb2y); aa.a = Math.atan2(va2y,va2x)*rad2deg; bb.a = Math.atan2(vb2y,vb2x)*rad2deg; } //effecute le deplacement de la boule function bougeMoi() { htm=""; stopper = false; for (e=0;e<balles.length;e++) { b=balles[e]; //seuil de deplacement avant stop if (b.v<seuilStop) b.v=0; if (b.v>0 && !stopper) stopper = true; //b.v*=0.998; b.v-=coefLin; //retourne un angle entre 0 & 360 if (b.a<0) do {b.a+=360;} while(b.a<0); if (b.a>360) do {b.a-=360;} while(b.a>360); nx=b.x;ny=b.y; if (b.v>0) //en javascript 0*cos(a) <>0 ??? { nx = b.x+b.v*Math.cos(b.a*deg2rad); ny = b.y+b.v*Math.sin(b.a*deg2rad); } //TODO: il faudrait trouver un truc ici pr eviter que les boules se chevauche b.nx=nx; b.ny=ny; //si mode debug on affiche les info de positions //if (d) htm+="a :"+parseInt(b.a,10)+" - x :"+parseInt(nx,10)+" - y :"+parseInt(ny,10)+" - v :"+parseInt(b.v*100)/100+"<br>"; } if (!stopper) { //alert('stop'); pause = true; } //pause = !stopper; if (d) _("debug_").innerHTML=htm; } //replace les boules au bonne positions function placeMoi() { for (e in balles) { b=balles[e]; _(b.id).style.left=parseInt(b.x,10)-b.r+minx; _(b.id).style.top=parseInt(b.y,10)-b.r+miny; } } //places les elements à l'ecran function ajoutBalle() { htm=""; for (e in balles) { b=balles[e]; htm+="<img id='"+b.id+"' src='img/"+src[b.t]+".png' style='position:absolute; top:"+(b.y-b.r+miny)+"px;left:"+(b.x-b.r+minx)+"px;width:"+(b.r*2)+"px;height:"+(b.r*2)+"px;'>"; } _("ecran").innerHTML = htm; } //------------------------------------- //------------------------------------- function ajoutPix(x, y, l, h, c) { return "<div style='left:"+x+"px;top:"+y+"px;width:"+l+"px;height:"+h+"px;background-color:"+c+";overflow:hidden;position:absolute;'><\/div>"; } /* tracer d'une droite avec l'algorithme Bresenham -modifié pour créer un effet d'epaisseur x1,y1,x2,y2 : coordonnée du segment diam : diametre du segment c : couleur
  • /
function ligne2(x1, y1, x2, y2, diam, c) { htm=""; if (c==null) c="black"; //couleur par defaut if (diam==null) diam=2; //epaiseur par defaut if(x1 > x2) { //swap(x1,x2); var z = x2;x2 = x1;x1 = z; z = y2;y2 = y1;y1 = z; } var dx = x2-x1, dy = Math.abs(y2-y1); //delta x & y var x = x1, y = y1; var ySens = (y1 > y2)? -1 : 1; //direction de Y if(dx < dy) { var d2 = diam>>1; //equivalent à Math.round(diam/2); var dxy = 2*(dx - dy), p = 2*dx-dy, py = y; if(y2 > y1) { while(dy > 0) { --dy; y += ySens; if(p > 0) { htm+=ajoutPix(x++, py, diam, y-py+d2,c); p += dxy; py = y; } else p += 2*dx; } htm+=ajoutPix(x2, py, diam, y2-py+d2+1,c); } else { while(dy > 0) {--dy; if(p > 0) { htm+=ajoutPix(x++, y, diam, py-y+d2,c); y += ySens; p += dxy; py = y; } else { y += ySens; p += 2*dx; } } htm+=ajoutPix(x2, y2, diam, py-y2+d2,c); } } else { var dxy = 2*(dy - dx), p = 2*dy-dx, px = x; d2 = diam>>1 ; while(dx > 0) {--dx; ++x; if(p > 0) { htm+=ajoutPix(px, y, x-px+d2, diam,c); y += ySens; p += dxy; px = x; } else p += 2*dy; } htm+=ajoutPix(px, y, x2-px+d2+1, diam,c); } return htm; }

Codes Sources

A voir également

Ajouter un commentaire Commentaires
Messages postés
7
Date d'inscription
mardi 13 février 2018
Statut
Membre
Dernière intervention
26 février 2018

j'ai oublié de préciser qu'il faut utiliser firefox dans cet essai!
Messages postés
7
Date d'inscription
mardi 13 février 2018
Statut
Membre
Dernière intervention
26 février 2018

merci amrounix! a partir de ton idee j'ai fait un petit jeu de billard 3 boules
qu'on peut voir en ligne sans engagement ici https://danBill7.github.io
Messages postés
26
Date d'inscription
dimanche 29 mars 2009
Statut
Membre
Dernière intervention
9 septembre 2013

Bonjour,

je viens de faire un post : http://www.phpcs.com/forum/sujet-CHOC-ELASTIQUE-SUR-GLOBE_1574797.aspx

je suis sur un projet similaire mais sur une sphère (la terre) donc mais angles de déplacement sont des caps, je vais donc essayer de reprendre ta source pour l'appliquer à mon projet.

Est ce que tu aurais une idée ?
Messages postés
647
Date d'inscription
samedi 30 décembre 2000
Statut
Membre
Dernière intervention
20 juillet 2012
6
Bonjour,

Comment fais-tu ta décélération des boules de billard, cela m'intéresse pour un autre projet

Merci,

JDMCreator
Messages postés
78
Date d'inscription
lundi 10 mars 2003
Statut
Membre
Dernière intervention
12 juillet 2010

HeLLo les amis ... un petit message pour vous prévenir que j'avais mis a jour mon code, avec pas mal d'amélioration :

-correction des collisions; on avait les boules qui se chevauchaient dans certains cas, le problème était du à la distance entre les boules (variable distn) explication :
b[x,y] : boule d'origine N°1, b[nx,ny] : nouvelle position
b2[x,y] : boule d'origine N°2, b2[nx,ny] : nouvelle position
la distance était calculé entre les boules b[nx,ny] & b2[nx,ny], sauf qu'on ne tennait pas compte de la position d'origine ! bref la distance² correspond à la vitesse² donc pour pallier à ce pb, j'ai fait : distn = distn - b.v² - b2.v² qui correspond au pire scénario ... Je crois que j'ai perdu des gens en route... lol

-les rebords se font par détection de croisement, entre les segements de déplacement de la boule b[x,y] à b[nx,ny] et le rebord, si ca se croise il y'a donc collision, on récupère la normale du plan de contact "p.n" et on sort son livre de physique sur la réflexion d'onde et puis voila ! lol

bon ok j'arret de vous saouler , ce qui compte c'est de pouvoir s'amuser ! En ce moment je cherche les règles du jeux de pool pour adapter le jeu avec les vrais règles ! c'est bientôt la fin ...
Afficher les 17 commentaires

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.