ДЕМО: http://cnwander.com/demo/billiards/
Исходный адрес: http://cnwander.com/blog/?p=11.
Серия мини-игр JS:
[JS мини-игра] Змея + подробные комментарии
Сначала вставьте код:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd ">
<html xmlns=" http://www.w3.org/1999/xhtml ">
<голова>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Бильярд от CNwander</title>
<style type="text/css">
* {поле: 0; дополнение: 0}
тело {фон: черный; выравнивание текста: размер шрифта: 12 пикселей;
h1 {размер шрифта: 12 пикселей; цвет: серый; вес шрифта: высота строки: 200%}
h1 .sub {вертикальное выравнивание: супер; цвет: красный; размер шрифта: 9 пикселей;
.info {позиция:абсолютная;правая:0;цвет:серый};
#table {позиция: относительная; ширина: 800 пикселей; поле: 20 пикселей автоматически 10 пикселей; фон: URL ( ); _background: none; _filter: progid: DXImageTransform.Microsoft.AlphaImageLoader (enabled = 'true', sizingMethod =' масштаб', src=" ); _background:none; _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', sizingMethod='scale', src=" ); _background:none; _filter: progid:DXImageTransform.Microsoft .AlphaImageLoader(enabled='true', sizingMethod='scale', src=" ) no-repeat}
#force {position:absolute; left:0; top:18px; width:75px; background:url( ) no-repeat;
#scoreBoard {позиция: абсолютный; z-индекс: 3; верхний: 230 пикселей; размер шрифта: 50 пикселей; цвет: альфа (непрозрачность = 0); -moz-opacity: 0; }
#советы {padding:15px 0 0 20px; text-align: left; цвет: размер шрифта: 12 пикселей}
</стиль>
<тип сценария="текст/javascript">
// общий
функция $(строка) {
вернуть document.getElementById(str);
}
функция $tag(str,target) {
цель = цель || документ;
return target.getElementsByTagName(str);
}
функция addEventHandler(obj,eType,fuc){
если (obj.addEventListener) {
obj.addEventListener(eType,fuc,false);
}иначе если(obj.attachEvent){
obj.attachEvent("on" + eType,fuc);
}еще{
obj["on" + eType] = fuc;
}
}
функция RemoveEventHandler(obj,eType,fuc){
если (obj.removeEventListener) {
obj.removeEventListener(eType,fuc,false);
}иначе если(obj.attachEvent){
obj.detachEvent("on" + eType,fuc);
}
}
функция randowNum (начало, конец) {
return Math.floor(Math.random()*(конец - начало)) + начало;
}
Array.prototype.remove=function(dx) {
if(isNaN(dx)||dx>this.length){возвращает false;}
for(var i=0,n=0;i<this.length;i++)
{
если(это[i]!=это[dx])
{
это[n++]=это[я]
}
}
this.length-=1
}
//константа
var TOTALR = 15, //Радиус шара (включая тень)
R = 12, //Истинный радиус шара
ПОКЕР = 20,
W = 736, //ширина корпуса
H = 480, //высота корпуса
ТОЛЩИНА = 32, //толщина края
RATE = 100, //частота обновления
F = 0,01, //сила трения
ПОТЕРЯ = 0,2, // Потеря скорости при столкновении
СОВЕТЫ = ["Совет 1: контрольный мяч, целевой мяч, целевой мешок, три очка и одна линия, это самый простой способ забить голы","Совет 2: синяя полоса в правом нижнем углу представляет силу удара. Небольшая сила легче контролировать положение битка», «Совет 3: синяя точка на белом шаре в правом нижнем углу контролирует точку удара. Она контролирует верхнюю планку, нижнюю планку и пробку. Разница между мастерами и мастерами часто здесь. «,»Совет 4: В настольном теннисе целевой шар на самом деле не играется, это биток»];
таблица var, // случай
cueBall, //биток
guideBall, //опорный шар
dotWrap, //опорная строка
скорость = 12,
свернуть вверх = 0,
роллРайт = 0,
таймер,
силаТаймер,
шары = [],
движущиеся шары = [],
тыкает = [[0,0],[W/2,-5],[W,0],[0,H],[W/2,H+5],[W,H]],
hasShot = ложь;
shots = 0 //Количество комбо-шотов;
window.onload = функция() {
инициализация таблицы();
initShootPos();
показатьПодсказки();
Начать игру();
}
функция startGame() {
initBall();
addEventHandler(таблица, "mousemove",dragCueBall);
addEventHandler(таблица, "mouseup", setCueBall);
}
функция initTable() {
таблица = $("таблица");
var dotWrapDiv = document.createElement("div"),
guideBallDiv = document.createElement("div");
dotWrapDiv.id = "dotWrap";
guideBallDiv.className = "Направляющий шар";
setStyle(guideBallDiv, «дисплей», «нет»);
dotWrap = table.appendChild(dotWrapDiv);
guideBall = table.appendChild(guideBallDiv);
}
функция initBall() {
//Добавляем биток
cueBall = новый шар("кий",170,H/2);
balls.push(cueBall);
//Добавляем целевой мяч
for(var я = 0; я <5; я++) {
for(var j = 0; j <= i; j++) {
var ball = new Ball("target",520 + i*2*R, H/2 - R*i + j*2*R);
balls.push(мяч);
}
}
}
функция initShootPos() {
var Wrap = $("shootPos"),
обработчик = $("точка"),
стрелкаR = 18;
addEventHandler(wrap, «mousedown», selectDot);
функция selectDot(e) {
е = е || событие;
вар pos = getElemPos (обертка),
x = e.clientX - pos[0] - handler.offsetWidth/2,
y = e.clientY - pos[1] - handler.offsetHeight/2;
if(Math.sqrt((x-22)*(x-22) + (y-22)*(y-22)) > стрелкаR) {
угол вар = Math.atan2(x-22,y-22);
x = стрелкаR*Math.sin(угол) + 22;
y = стрелкаR*Math.cos(угол) + 22;
}
setPos (обработчик, х, у);
}
}
функция getElemPos(цель,ссылка) {
ссылка = ссылка || документ;
вар слева = 0, сверху = 0;
вернуть getPos (цель);
функция getPos(цель) {
если(цель != ссылка) {
влево += target.offsetLeft;
верх += target.offsetTop;
вернуть getPos(target.parentNode);
} еще {
вернуться [влево, вверху];
}
}
}
// класс мяча
функция Ball(type,x,y) {
var div = document.createElement("div");
div.className = тип + «шар»;
this.elem = table.appendChild(div);
this.type = тип;
this.x = х // позиция;
это.у = у;
this.angle = 0 // Угол
this.v = 0; //Скорость (без учета направления)
setBallPos(this.elem,x,y);
верните это;
}
функция setCueBall() {
RemoveEventHandler(таблица, "mousemove",dragCueBall);
RemoveEventHandler(таблица, «mouseup», setCueBall);
НачатьВыстрел();
}
функция startShot() {
показать(cueBall.elem);
addEventHandler(таблица, «mousemove», showGuide);
addEventHandler(таблица, «mousedown», updateForce);
addEventHandler(таблица, "mouseup",shotCueBall);
}
функция dragCueBall(e) {
вар toX, toY;
е = е || событие;
toX = e.clientX - table.offsetLeft - ТОЛЩИНА,
toY = e.clientY - table.offsetTop - ТОЛЩИНА;
toX = toX >= R ? toX : R;
toX = toX <= 170 ? toX: 170;
toY = toY >= R ? toY : R;
toY = toY <= H - R ? toY : H - R;
setBallPos(cueBall,toX,toY);
}
функцияshotCueBall() {
RemoveEventHandler(таблица, «mousemove», showGuide);
RemoveEventHandler(таблица,"mousedown",updateForce);
RemoveEventHandler(таблица, "mouseup",shotCueBall);
window.clearInterval(forceTimer);
скорость = $("force").offsetWidth * 0,15;
вар dotDisX = $("точка").offsetLeft-22,
dotDisY = $("точка").offsetTop-22,
dotDis = Math.sqrt(dotDisX*dotDisX + dotDisY*dotDisY),
dotAngle = Math.atan2(dotDisX,dotDisY);
rollRight = Math.round(dotDis*Math.sin(dotAngle))/5;
rollUp = -Math.round(dotDis*Math.cos(dotAngle))/5;
вар formPos = getBallPos(cueBall.elem),
toPos = getBallPos(guideBall),
угол = Math.atan2(toPos[0] - formPos[0],toPos[1] - formPos[1]);
скрыть (dotWrap);
скрыть(guideBall);
cueBall.v = скорость;
cueBall.angle = угол;
movingBalls.push(cueBall);
таймер = window.setInterval(roll,1000/RATE);
}
функция showGuide(e) {
вар fromX, fromY, toX, toY;
е = е || событие;
toX = e.clientX - table.offsetLeft - ТОЛЩИНА,
toY = e.clientY - table.offsetTop - ТОЛЩИНА;
setBallPos(guideBall,toX,toY);
показать (dotWrap);
показать (guideBall);
рисоватьЛинию();
//опорная линия
функция drawLine() {
вар dotNum = 16,
pos = getBallPos(cueBall.elem);
dotWrap.innerHTML = "";
изX = позиция [0];
изY = позиция[1];
var partX = (toX - fromX)/dotNum,
partY = (toY - fromY) / dotNum;
for(var я = 1; я <dotNum; я++) {
вар x = fromX + partX * i,
y = fromY + partY * i;
drawDot (dotWrap, x, y);
}
}
}
функция ролл() {
if(movingBalls.length <= 0) {
if(!hasShot) выстрелы = 0;
else выстрелы ++; //накопленные комбо
hasShot = ложь;
setStyle($("force"),"width",80+"px");
setPos($("точка"),22,22);
window.clearInterval(таймер);
if(shots > 1) showScore(shots); //Показать количество комбо
НачатьВыстрел();
}
for(var i = 0; i < movingBalls.length; i++) {
вар мяч = movingBalls[i],
грех = Math.sin(шар.угол),
соз = Math.cos(ball.angle);
ball.v -= F;
//Удалить неподвижный шар
if(Math.round(ball.v) == 0) {
мяч.в = 0;
movingBalls.remove(i);
продолжать;
}
вар vx = ball.v * sin,
vy = ball.v * потому что;
ball.x += vx;
ball.y += вы;
//Положим в сумку
если (isPocket(ball.x,ball.y)) {
скрыть(ball.elem);
if(ball.type == "кий") {
if(!hasShot) выстрелы = 0;
hasShot = ложь;
window.setTimeout(функция(){
мяч.в = 0;
setBallPos(шар,170,250);
},500);
}еще {
//Удаляем застрявшие мячи
hasShot = правда;
мяч.в = 0;
for(var k = 0, l =0; k < balls.length; k++) {
if(balls[k] != шар) {
шары[l++] = шары[k];
}
}
шары.длина -= 1;
}
возвращаться;
}
//столкновение краев
if(ball.x < R || ball.x > W - R) {
мяч.угол *= -1;
ball.angle %= Math.PI;
ball.v = ball.v * (1 - ПОТЕРЯ);
vx = ball.v*Math.sin(ball.angle);
vy = ball.v*Math.cos(ball.angle);
if(ball.x < R) ball.x = R;
if(ball.x > W - R) ball.x = W - R;
//набивка битка
if(ball.type == "кий") {
if(ball.angle > 0) vy -=rollRight;
иначе vy +=rollRight;
vx += свернуть;
свернуть*= 0,2;
роллРайт *= 0,2;
ball.v = Math.sqrt(vx*vx + vy*vy);
ball.angle = Math.atan2(vx,vy);
}
}
if(ball.y < R || ball.y > H - R) {
ball.angle = ball.angle > 0 Math.PI - ball.angle: - Math.PI - ball.angle;
ball.angle %= Math.PI;
ball.v = ball.v * (1 - ПОТЕРЯ);
vx = ball.v*Math.sin(ball.angle);
vy = ball.v*Math.cos(ball.angle);
if(ball.y < R) ball.y = R;
if(ball.y > H - R) ball.y = H - R;
//набивка битка
if(ball.type == "кий") {
if(Math.abs(ball.angle) < Math.PI/2) vx +=rollRight;
иначе vx -=rollRight;
вы += свернуть;
свернуть*= 0,2;
роллРайт *= 0,2;
ball.v = Math.sqrt(vx*vx + vy*vy);
ball.angle = Math.atan2(vx,vy);
}
}
//столкновение мяча
for(var j = 0; j < balls.length; j++) {
вар obj = шары [j];
если (obj == мяч) продолжить;
вар disX = obj.x - ball.x,
disY = obj.y - ball.y,
разрыв = 2*R;
if(disX <= пробел && disY <= пробел) {
var dis = Math.sqrt(Math.pow(disX,2)+Math.pow(disY,2));
if(dis <= пробел) {
//Если он неподвижен, добавляем его в массив movingBalls
если(Math.round(obj.v) == 0)
movingBalls.push(obj);
//Поворот координат по оси X для расчета столкновений
// Вычисляем угол и значения синуса и косинуса — точные значения
//var c = (obj.x*ball.y - obj.y*ball.x)/(2*R),
// d = Math.sqrt(ball.x*ball.x + ball.y*ball.y),
// угол = Math.asin(ball.y/d) - Math.asin(c/d) - ball.angle%(Math.PI/2),
//угол = Math.asin(oy / (2 * R)),
//Восстанавливаем состояние касания двух шаров - приблизительное значение
ball.x -= (пробел - dis)*sin;
ball.y -= (пробел - dis)*cos;
disX = obj.x - ball.x;
disY = obj.y - ball.y;
// Вычисление угла, значений синуса и косинуса
угол вар = Math.atan2(disY, disX),
хитсин = Math.sin(угол),
hitcos = Math.cos(угол),
objVx = obj.v * Math.sin(obj.angle),
objVy = obj.v * Math.cos(obj.angle);
//trace(angle*180/Math.PI);
// Поворот координат
вар x1 = 0,
у1 = 0,
x2 = disX * hitcos + disY * хитсин,
y2 = disY * hitcos - disX * хитсин,
vx1 = vx*hitcos + vy*хицин,
vy1 = vy*hitcos - vx*хицин,
vx2 = objVx * hitcos + objVy * хитсин,
vy2 = objVy * hitcos - objVx * hitsin;
// Скорость и положение после столкновения
вар плюсVx = vx1 - vx2;
вх1 = вх2;
vx2 = плюсVx + vx1;
//набивка битка
if(ball.type == "кий") {
vx1 += свернуть;
свернуть*= 0,2;
}
х1 += vx1;
х2 += vx2;
// Поворот позиции назад
var x1Final = x1 * hitcos - y1 * hitsin,
y1Final = y1 * hitcos + x1 * хитсин,
x2Final = x2 * hitcos - y2 * hitsin,
y2Final = y2 * hitcos + x2 * хитсин;
obj.x = ball.x + x2Final;
obj.y = ball.y + y2Final;
ball.x = ball.x + x1Final;
ball.y = ball.y + y1Final;
// Возвращаем скорость назад
vx = vx1 * hitcos - vy1 * хитсин;
vy = vy1 * hitcos + vx1 * хитсин;
objVx = vx2 * hitcos - vy2 * хитсин;
objVy = vy2 * hitcos + vx2 * hitsin;
//конечная скорость
ball.v = Math.sqrt(vx*vx + vy*vy) * (1 - 0);
obj.v = Math.sqrt(objVx*objVx + objVy*objVy) * (1 - 0);
// Вычисляем угол
ball.angle = Math.atan2(vx, vy);
obj.angle = Math.atan2(objVx, objVy);
//перерыв;
}
}
}
setBallPos(ball,ball.x,ball.y);
}
}
функция isPocket(x,y) {
if(y < POKER) return check(0,2);
иначе, если (y > H - ПОКЕР) вернуть проверку(3,5);
иначе вернуть ложь;
проверка функции(m,n) {
for(var i=m; i<=n; i++) {
if(x >= pokes[i][0] - ПОКЕР && x <= pokes[i][0] + ПОКЕР) {
var dis = Math.sqrt(Math.pow(x - pokes[i][0],2) + Math.pow(y - pokes[i][1],2));
if(dis <= ПОКЕР) возвращает true;
иначе вернуть ложь;
}
}
}
}
функция getBallPos(obj) {
вар ПОС = [];
pos.push(obj.offsetLeft - ТОЛЩИНА + ВСЕГО);
pos.push(obj.offsetTop - ТОЛЩИНА + ВСЕГО);
возврат позиции;
}
функция setPos(obj,x,y) {
obj.style.left = x + «px»;
obj.style.top = y + «px»;
}
функция setBallPos(ball,x,y) {
if(ball.constructor == Шар) {
мяч.х = х;
мяч.y = y;
мяч = мяч.элемент;
}
setPos(ball,x + ТОЛЩИНА - ВСЕГО,y + ТОЛЩИНА - ВСЕГО);
}
функция drawDot(wrap,x,y) {
var elem = document.createElement("div");
setStyle(элемент,{
позиция: «абсолютная»,
ширина: «1 пиксель»,
высота: "1px",
Размер шрифта: "1px",
фон: «белый»
});
setPos (элемент, х, у);
обертка.appendChild(элемент);
}
функция updateForce() {
вар obj = $("сила"),
лен = 80,
вверх = правда;
ForceTimer = window.setInterval(обновление,10);
обновление функции() {
if(up) setStyle(obj,"width",len+++"px");
иначе setStyle(obj,"width",len--+"px");
если (длина > 136) вверх = ложь;
если (len <= 0) вверх = true;
}
}
функция setStyle() {
if(arguments.length == 2 && typeof аргументы[1] == "объект") {
for(ключ var в аргументах[1]) {
аргументы[0].стиль[ключ] = аргументы[1][ключ];
}
} еще если (arguments.length > 2) {
аргументы[0].стиль[аргументы[1]] = аргументы[2];
}
}
функция скрыть(объект) {
setStyle(obj,"дисплей","нет");
}
функция шоу (объект) {
setStyle(obj,"дисплей","блок");
}
//выводимая информация
функция трассировка(sth,кто) {
кто = кто $("советы");
если (document.all) who.innerText = sth;
еще who.textContent = sth;
вернуть кто;
}
функция showScore(n) {
var обертка = $("scoreBoard");
трассировка(n+"шатун",wrap);
FadeIn (обертка);
}
функция FadeIn(obj){
вар fromY = 230,
posStep = [8,14,19,23,26,28,29,29,30,30,30],
opaStep = [0,0.05,0.1,0.15,0.2,0.25,0.3,0.4,0.5,0.6,0.8],
изОпа = 0,
т = 0,
шаг = posStep.length,
inTimer = window.setInterval(showIn,20),
ауттаймер;
функция showIn() {
setOpacity(obj,opaStep[t]);
obj.style.top = fromY + posStep[t] + «px»;
т++;
если(т>=шаг) {
window.clearInterval(inTimer);
outTimer = window.setInterval(fadeOut,50);
}
}
функция FadeOut() {
т--;
setOpacity(obj,opaStep[t]);
obj.style.top = fromY + posStep[t] + «px»;
если (т <= 0) {
window.clearInterval(outTimer);
скрыть (объект);
}
}
}
функция setOpacity(obj,n) {
obj.style.cssText = "filter:alpha(opacity="+ n*100 +"); -moz-opacity:"+ n +"; непрозрачность:"+ n;
}
функция showTips() {
вар я = 0;
кончик();
window.setInterval(подсказка,3000);
функция подсказка() {
трассировка (СОВЕТЫ [я++]);
если (я >= СОВЕТЫ.длина) я = 0;
}
}
</скрипт>
</голова>
<тело>
<div class="info">Обсудить: <a href=" http://bbs.blueidea.com/thread-2951566-1-1.html"> Blueidea</a > <a href=" http: //cnwander.com/blog/?p=11">Пространство странствий</a></div>
<h1>Китайцы встаньте! <span class="sub">60 лет</span></h1>
<div id="таблица">
<div id="scoreBoard"></div>
</div>
<div class="bot">
<div id="советы"></div>
<класс div = «ctrl»>
<div id="force"></div>
<div id="shootPos">
<div id="dot"></div>
</div>
</div>
</div>
</тело>
</html>
Хотя его бессовестно называют настольным теннисом, на самом деле он далек от настоящего настольного тенниса, и есть еще много возможностей для совершенствования.
Конкретные вопросы, которые необходимо решить:
Обязательно будет много других проблем. Боюсь, что слишком отвлекусь на каникулах и не смогу продолжить дальше. Я просто закончу все за один раз. немного тороплюсь. Позже я медленно решу задачи. Сначала выложу их для студентов, интересующихся этой темой. Обсудите и обсудите.
Математика в колледже — это, по сути, просто формальность, и я очень мало забыл о физике и математике в старшей школе. Только когда я действительно начал что-то делать, я понял, что я слишком слаб в этой области. Я надеюсь, что у студентов больше опыта в этой области. область даст мне несколько советов.