Interessante Aufgabe. Ich denke schon, dass das mit Javascript möglich ist.
Zitat
Fakt ist, das Spiel sollte letztendlich auch Internetfähig sein, also man sollte es schon zu zweit spielen können, auch wenn die Spielpartner nicht gerade nebeneinander sitzen.
Das ist eine gewisse Herausforderung, aber sicher auch machbar. Vor allem, wenn man ein Verfahren verwendet, bei dem man nicht wie bei einem Video die Bewegungen Frame-für-Frame überträgt, sondern nur die Anfangsparameter wie Stoßrichtung und Stoßstärke und die Bewegungen dann auf der anderen Seite neu berechnet.
Zitat
Aber alles erstmal Schritt für Schritt.
Das ist sicher zu empfehlen. Ich habe vor einiger Zeit mal den ersten Schritt getan und den elastischen Stoß programmiert:
<!doctype html>
<html>
<head>
<script src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
</head>
<body>
<style>
#bouncewrapper {
width: 800px;
height: 600px;
position: relative;
}
.ball {
width: 38px;
height: 38px;
border-radius: 20px;
border: 2px solid black;
position: absolute;
}
#ball2 {
left: 200px;
top: 150px;
}
</style>
<div id="bouncewrapper">
<div class="ball" id="ball1"></div>
<div class="ball" id="ball2"></div>
</div>
<script>
var balls = [
{ ele: $("#ball1"), x: 0, y: 0, radius: 20, speedx: 0, speedy: 0, factor: 10, mass: 1 },
{ ele: $("#ball2"), x: 200, y: 150, radius: 20, speedx: 0, speedy: 0, factor: 10, mass: 1 }
];
var dragging = false, collided = false;
function insideball(idx, x, y) {
var centerx = balls[idx].x + balls[idx].radius;
var centery = balls[idx].y + balls[idx].radius;
var dx = centerx - x;
var dy = centery - y;
var dist = Math.sqrt(dx * dx + dy * dy);
return dist < balls[idx].radius;
}
function collision() {
var distx = balls[1].x - balls[0].x;
var disty = balls[1].y - balls[0].y;
var dist = Math.sqrt(distx * distx + disty * disty);
if (dist < (balls[0].radius + balls[1].radius)) {
if (!collided) {
collided = true;
manage_bounce(balls[0], balls[1]);
//var xspeed1 = balls[0].speedx;
//var yspeed1 = balls[0].speedy;
//var speed1 = Math.sqrt(xspeed1 * xspeed1 + yspeed1 * yspeed1);
//var speed2 = 0;
//var angle1 = Math.atan(balls[0].speedy / balls[0].speedx);
//var anglecoll1 = Math.atan(disty / distx);
//var anglecoll = anglecoll1 - angle1;
//var speed1new = speed1 * Math.abs(Math.sin(anglecoll));
//var speed2new = speed1 * Math.abs(Math.cos(anglecoll));
//if (anglecoll < 0) var angle1new = angle1 + anglecoll + Math.PI / 2;
//else var angle1new = angle1 + anglecoll - Math.PI / 2;
//var angle2new = angle1 + anglecoll;
//balls[0].speedx = speed1new * Math.cos(angle1new);
//balls[0].speedy = speed1new * Math.sin(angle1new);
//balls[1].speedx = speed2new * Math.cos(angle2new);
//balls[1].speedy = speed2new * Math.sin(angle2new);
//console.log(dist, collided);
}
}
}
function manage_bounce(ball1, ball2) {
dx = ball1.x - ball2.x;
dy = ball1.y - ball2.y;
collision_angle = Math.atan2(dy, dx);
magnitude_1 = Math.sqrt(ball1.speedx * ball1.speedx + ball1.speedy * ball1.speedy);
magnitude_2 = Math.sqrt(ball2.speedx * ball2.speedx + ball2.speedy * ball2.speedy);
direction_1 = Math.atan2(ball1.speedy, ball1.speedx);
direction_2 = Math.atan2(ball2.speedy, ball2.speedx);
new_speedx_1 = magnitude_1 * Math.cos(direction_1 - collision_angle);
new_speedy_1 = magnitude_1 * Math.sin(direction_1 - collision_angle);
new_speedx_2 = magnitude_2 * Math.cos(direction_2 - collision_angle);
new_speedy_2 = magnitude_2 * Math.sin(direction_2 - collision_angle);
final_speedx_1 = ((ball1.mass - ball2.mass) * new_speedx_1 + (ball2.mass + ball2.mass) * new_speedx_2) / (ball1.mass + ball2.mass);
final_speedx_2 = ((ball1.mass + ball1.mass) * new_speedx_1 + (ball2.mass - ball1.mass) * new_speedx_2) / (ball1.mass + ball2.mass);
final_speedy_1 = new_speedy_1;
final_speedy_2 = new_speedy_2;
ball1.speedx = Math.cos(collision_angle) * final_speedx_1 + Math.cos(collision_angle + Math.PI / 2) * final_speedy_1;
ball1.speedy = Math.sin(collision_angle) * final_speedx_1 + Math.sin(collision_angle + Math.PI / 2) * final_speedy_1;
ball2.speedx = Math.cos(collision_angle) * final_speedx_2 + Math.cos(collision_angle + Math.PI / 2) * final_speedy_2;
ball2.speedy = Math.sin(collision_angle) * final_speedx_2 + Math.sin(collision_angle + Math.PI / 2) * final_speedy_2;
}
function move() {
balls.forEach(function (ball, idx) {
ball.x += ball.speedx * ball.factor;
ball.y += ball.speedy * ball.factor;
ball.ele.css({ left: ball.x + "px", top: ball.y + "px" });
ball.factor *= 0.99;
});
collision();
requestAnimationFrame(move);
}
$("#bouncewrapper").on("mousedown", function (e) {
//var x = e.pageX - $(e.target).offset().left;
//var y = e.pageY - $(e.target).offset().top;
var x = e.pageX - $(this).offset().left;
var y = e.pageY - $(this).offset().top;
if (insideball(0, x, y)) {
console.log(x, y, "inside");
dragging = true;
balls[0].mousedx = x - balls[0].x;
balls[0].mousedy = y - balls[0].y;
balls[0].starttime = Date.now();
balls[0].startx = balls[0].x;
balls[0].starty = balls[0].y;
} else console.log(x, y, "outside");
});
$("#bouncewrapper").on("mousemove", function (e) {
var x = e.pageX - $(this).offset().left;
var y = e.pageY - $(this).offset().top;
if (dragging) {
balls[0].x = x - balls[0].mousedx;
balls[0].y = y - balls[0].mousedy;
balls[0].ele.css({ left: balls[0].x + "px", top: balls[0].y + "px" })
}
});
$("#bouncewrapper").on("mouseup", function (e) {
dragging = false;
var deltatime = Date.now() - balls[0].starttime;
balls[0].speedx = (balls[0].x - balls[0].startx) / deltatime;
balls[0].speedy = (balls[0].y - balls[0].starty) / deltatime;
balls[0].speed = Math.sqrt(balls[0].speedx * balls[0].speedx + balls[0].speedy * balls[0].speedy);
balls[0].factor = 10;
console.log(balls[0].speedx, balls[0].speedy);
requestAnimationFrame(move);
});
</script>
</body>
</html>
Alles anzeigen
Den Ball links oben kann man durch Ziehen mit der Maus bewegen. Nach Loslassen rollt er weiter und wird entsprechend der Reibung langsamer. Und wenn man gut gezielt hat, trifft er den zweiten Ball. 
Das mit dem Ziehen und Loslassen trifft die Vorgänge beim richtigen Billard noch nicht optimal. Auf Anhieb fällt mir aber keine bessere und einfache Lösung ein. Ich dachte daran, eine Queue zu zeichnen, wo man die Richtung mit der Maus durch Ziehen einstellt und durch schnellen Klick den Stoß auslöst, aber optimal wäre das auch nicht.