14. Обработка событий
Примеры
praxis/14/examples/01/index.htm
Содержимое файла index.htm
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<HTML id="html" lang="ru">
<HEAD>
<META http-equiv="Content-Type"
content="text/html; charset=windows-1251">
<META http-equiv="imagetoolbar" content="no">
<SCRIPT type="text/javascript" src="main.js"></SCRIPT>
<TITLE>Тестируем всплытие</TITLE>
</HEAD>
<BODY id="body">
<H1>Тестируем всплытие</H1>
<P id="p">
<IMG id="pic" src="pic/pic.png" width=119 height=91 alt="" title="">
</P>
<H2>Протокол работы обработчиков событий</H2>
</BODY>
</HTML>
Содержимое файла main.js
// Обработчик события onload
// Функциональный литерал будет вызван после полной загрузки документа
// и построения DOM
window.onload = function ()
{
// Назначим единственный обработчик события всем объектам
document.getElementById("pic").onclick = say;
document.getElementById("p").onclick = say;
document.getElementById("body").onclick = say;
document.getElementById("html").onclick = say;
// Сам обработчик
function say()
{
var text = "id элемента: " + this.id;
appendP(text); // Добавим абзац в документ
}
// Добавить абзац к документу
function appendP(text)
{
// Создадим элемент "абзац"
var el = document.createElement("p");
// Добавим к созданному элементу потомка -- текстовый элемент
el.appendChild(document.createTextNode(text));
// Добавим построенный элемент к BODY -- и он сразу отобразится на экране
document.body.appendChild(el);
}
};
praxis/14/examples/02/index.htm (не работает в IE)
Содержимое файла index.htm
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<HTML id="html" lang="ru">
<HEAD>
<META http-equiv="Content-Type"
content="text/html; charset=windows-1251">
<META http-equiv="imagetoolbar" content="no">
<SCRIPT type="text/javascript" src="main.js"></SCRIPT>
<TITLE>Тестируем распространение события</TITLE>
</HEAD>
<BODY id="body">
<H1>Тестируем распространение события</H1>
<P id="p">
<IMG id="pic" src="pic/pic.png" width=119 height=91 alt="" title="">
</P>
<H2>Протокол работы обработчиков событий</H2>
</BODY>
</HTML>
Содержимое файла main.js
// Обработчик события onload
// Функциональный литерал будет вызван после полной загрузки документа
// и построения DOM
window.onload = function ()
{
// Назначим обработчик события объектам на фазе захвата
document.getElementById("pic").addEventListener("click",say1,true);
document.getElementById("p").addEventListener("click",say1,true);
document.getElementById("body").addEventListener("click",say1,true);
document.getElementById("html").addEventListener("click",say1,true);
// Назначим обработчик события объектам на фазе всплытия
document.getElementById("pic").addEventListener("click",say2,false);
document.getElementById("p").addEventListener("click",say2,false);
document.getElementById("body").addEventListener("click",say2,false);
document.getElementById("html").addEventListener("click",say2,false);
// Обработка на этапе захвата
function say1()
{
var text = "Захват, id элемента: " + this.id;
appendP(text); // Добавим абзац в документ
}
// Обработка на этапе всплытия
function say2()
{
var text = "Всплытие, id элемента: " + this.id;
appendP(text); // Добавим абзац в документ
}
// Добавить абзац к документу
function appendP(text)
{
// Создадим элемент "абзац"
var el = document.createElement("p");
// Добавим к созданному элементу потомка -- текстовый элемент
el.appendChild(document.createTextNode(text));
// Добавим построенный элемент к BODY -- и он сразу отобразится на экране
document.body.appendChild(el);
}
};
praxis/14/examples/03/index.htm
Содержимое файла index.htm
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<HTML lang="ru">
<HEAD>
<META http-equiv="Content-Type"
content="text/html; charset=windows-1251">
<META http-equiv="imagetoolbar" content="no">
<LINK rel="stylesheet" type="text/css" href="main.css">
<SCRIPT type="text/javascript" src="animateCSS.js"></SCRIPT>
<SCRIPT type="text/javascript" src="main.js"></SCRIPT>
<TITLE>Картинки, которые возвращаются</TITLE>
</HEAD>
<BODY>
<H1>Картинки, которые возвращаются</H1>
<P>
<IMG src="pic/06.png" width=119 height=91 alt="" title="">
На этой странице много картинок. Их можно перетаскивать мышью в
любое место окна. Когда перетаскивание завершается, картинка
возвращается на прежнее место. Однако HTML-код совершенно не в курсе,
что для картинок на странице задано такое поведение. Все делает
скрипт, подключенный к странице.
<P>
<IMG src="pic/00.png" width=364 height=55 alt="" title="">
<P>
<IMG src="pic/01.png" width=65 height=106 alt="" title="">
<IMG src="pic/02.png" width=56 height=96 alt="" title="">
<IMG src="pic/03.png" width=105 height=103 alt="" title="">
<IMG src="pic/04.png" width=98 height=74 alt="" title="">
<IMG src="pic/05.png" width=107 height=104 alt="" title="">
</P>
</BODY>
</HTML>
Содержимое файла main.js
// ===================================================================
// Cкрипт, который после подключения к странице, позволяет все
// картинки на странице перетаскивать мышью. По окончанию
// перетаскивания, картинка самостоятельно возвращается на прежнее
// место по сложной траектории. Этот скрипт наделяет таким
// свойством любую страницу, к которой подключается, без каких
// либо дополнительных разметок на этой страницы.
//
// Это скрипт работает во всех браузерах кроме IE.
// ===================================================================
// Обработчик события onload
// Функциональный литерал будет вызван после полной загрузки документа
// и построения его объектной модели
window.onload = function ()
{
// Назначим обработчики события mousedown на все картинки страницы
// и зададим для них относительное позиционирование
for(var i=0; i<document.images.length; i++)
{
// Обработка нажатия кнопки мыши
document.images[i].onmousedown = downHandler;
// Назначим относительное позиционирование
document.images[i].style.position = "relative";
}
// Общие переменные
var xStartMouse, yStartMouse; // Координаты мыши во время нажатия на кнопку
var element; // Элемент на котором выполнено нажатие на кнопку
var isСomeBack = false; // Картинка двигается на место?
// Обработать нажатие кнопки мыши
function downHandler(event)
{
if(!isСomeBack) // Реагировать только на неподвижную картинку
{ // (игнорировать щелчок по двигающейся картинке)
// Работа началась, щелчки не обрабатывать
isСomeBack = true;
// Запомним элемент, на котором выполнено нажатие на кнопку
element = this;
// Сохраним координаты мыши во время нажатия на кнопку
xStartMouse = event.clientX;
yStartMouse = event.clientY;
// Поднимем картинку на слой выше
this.style.zIndex = 1;
// Зарегистрируем обработчики событий mousemove и mouseup,
// которые последуют за событием mousedown. Зарегистрируем эти
// события на весь документ, так как перетаскиваемый объект может
// не поспевать за указателем мыши, и события возникнут вне его.
// В методе addEventListener укажем true, что будет означать
// обработку события на фазе захвата.
document.addEventListener("mousemove", moveHandler, true);
document.addEventListener("mouseup", upHandler, true);
// Событие mousedown обработано, прервём
// его дальнейшее распространение
event.stopPropagation();
// На всякий случай запретим действие по умолчанию
event.preventDefault();
}
}
// Обработать перемещение мыши
function moveHandler(event)
{
// Переместить элемент в текущие координаты указателя мыши
element.style.left = event.clientX-xStartMouse + "px";
element.style.top = event.clientY-yStartMouse + "px";
// Прервать дальнейшее распространение события
event.stopPropagation();
}
// Обработать заключительное событие -- отпускание кнопки мыши
function upHandler(event)
{
// Удалить обработчики событий mouseup и mousemove
document.removeEventListener("mousemove", moveHandler, true);
document.removeEventListener("mouseup", upHandler, true);
// Прервать дальнейшее распространение события
event.stopPropagation();
// Запустить анимацию, которая возвратит элемент на место
toHome();
}
function toHome()
{
var numFrames = 100; // Число кадров в анимации картинки
var v0 = 10; // Начальная скорость картинки
// Коодинаты картинки относительно её исходного положения,
// которое есть (0,0). Функция parseInt забирает число, отбрасывая "px"
var left = parseInt(element.style.left);
var top = parseInt(element.style.top);
// Вычисляем ускорения по двум направлениям
var aLeft = (Math.abs(left)-v0*numFrames)/(numFrames*numFrames);
var aTop = (Math.abs(top)-v0*numFrames)/(numFrames*numFrames);
// Запускаем анимацию
animateCSS(element, numFrames, 10,
{
left: function(frame,time)
{
return (left-sign(left)*(v0*frame+aLeft*frame*frame))+"px";
},
top: function(frame,time)
{
return (top-sign(top)*(v0*frame+aTop*frame*frame))+"px";
}
}, function ()
{
// Картинка закончила движение
isСomeBack = false; // Теперь ее снова можно двигать
// Подровняем картинку на её законном месте
element.style.left = element.style.top = 0;
// Поставим её в свой слой
element.style.zIndex = 0;
});
}
// Функция, вычисляющая знак числа
function sign(a) { return a<0 ? -1:1;}
};
praxis/14/examples/04/index.htm
Содержимое файла index.htm
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<HTML lang="ru">
<HEAD>
<META http-equiv="Content-Type"
content="text/html; charset=windows-1251">
<META http-equiv="imagetoolbar" content="no">
<LINK rel="stylesheet" type="text/css" href="main.css">
<SCRIPT type="text/javascript" src="animateCSS.js"></SCRIPT>
<SCRIPT type="text/javascript" src="main.js"></SCRIPT>
<TITLE>Картинки, которые возвращаются</TITLE>
</HEAD>
<BODY>
<H1>Картинки, которые возвращаются</H1>
<P>
<IMG src="pic/06.png" width=119 height=91 alt="" title="">
На этой странице много картинок. Их можно перетаскивать мышью в
любое место окна. Когда перетаскивание завершается, картинка
возвращается на прежнее место. Однако HTML-код совершенно не в курсе,
что для картинок на странице задано такое поведение. Все делает
скрипт, подключенный к странице.
<P>
<IMG src="pic/00.png" width=364 height=55 alt="" title="">
<P>
<IMG src="pic/01.png" width=65 height=106 alt="" title="">
<IMG src="pic/02.png" width=56 height=96 alt="" title="">
<IMG src="pic/03.png" width=105 height=103 alt="" title="">
<IMG src="pic/04.png" width=98 height=74 alt="" title="">
<IMG src="pic/05.png" width=107 height=104 alt="" title="">
</P>
</BODY>
</HTML>
Содержимое файла main.js
// ===================================================================
// Cкрипт, который после подключения к странице, позволяет все
// картинки на странице перетаскивать мышью. По окончанию
// перетаскивания, картинка самостоятельно возвращается на прежнее
// место по сложной траектории. Этот скрипт наделяет таким
// свойством любую страницу, к которой подключается, без каких
// либо дополнительных разметок на этой страницы.
//
// Это скрипт работает во всех браузерах (и в IE).
// ===================================================================
// Обработчик события onload
// Функциональный литерал будет вызван после полной загрузки документа
// и построения его объектной модели
window.onload = function ()
{
// Назначим обработчики события mousedown на все картинки страницы
// и зададим для них относительное позиционирование
for(var i=0; i<document.images.length; i++)
{
// Обработка нажатия кнопки мыши
document.images[i].onmousedown = downHandler;
// Назначим относительное позиционирование
document.images[i].style.position = "relative";
}
// Общие переменные
var xStartMouse, yStartMouse; // Координаты мыши во время нажатия на кнопку
var element; // Элемент на котором выполнено нажатие на кнопку
var isСomeBack = false; // Картинка двигается на место?
// -------------- для IE-4 -----------------------------------------
// Переменные, в которых будем хранить старые значения
// свойств mousemove и mouseup. Вместо удаления соответствующих
// событий (удаление нет в IE-4) будем возвращать сохранненные значения
var oldMoveHandler;
var oldUpHandler;
// -----------------------------------------------------------------
// Обработать нажатие кнопки мыши
function downHandler(event)
{
if(!isСomeBack) // Реагировать только на неподвижную картинку
{ // (игнорировать щелчок по двигающейся картинке)
// Если аргумент не передан, это IE, и тогда присвоим локальной
// переменной event ссылку на глобальный объект window.event,
// в котором IE хранит свойства события.
event = event || window.event;
// Работа началась, щелчки не обрабатывать
isСomeBack = true;
// Запомним элемент, на котором выполнено нажатие на кнопку
element = this;
// Сохраним координаты мыши во время нажатия на кнопку
xStartMouse = event.clientX;
yStartMouse = event.clientY;
// Поднимем картинку на слой выше
this.style.zIndex = 1;
// Зарегистрируем обработчики событий mousemove и mouseup,
// которые последуют за событием mousedown. Зарегистрируем эти
// события на весь документ, так как перетаскиваемый объект может
// не поспевать за указателем мыши, и события возникнут вне его.
if (document.addEventListener) // Если работает модель DOM W3C
{
// В методе addEventListener укажем true, что будет означать
// обработку события на фазе захвата.
document.addEventListener("mousemove", moveHandler, true);
document.addEventListener("mouseup", upHandler, true);
}
else if (document.attachEvent) // Если работает модель IE5+
{
// В модели IE5+ перехват события производится вызовом
// метода setCapture элемента, выполняющего перехват.
// После вызова этого метода все события мыши будут направляться
// элементу до отмена перехвата (метод releaseCapture)
element.setCapture();
document.attachEvent("onmousemove", moveHandler);
document.attachEvent("onmouseup", upHandler);
// Интерпретировать событие потери перехвата как событие mouseup.
// Потеря перехвата может случится в результате потери браузером
// фокуса ввода, появления модального окна (например, alert),
// отображения системного меню и в других подобных случаях.
document.attachEvent("onlosecapture", upHandler);
}
else // Модель событий IE4
{
// В модели IE4 нельзя использовать attachEvent и setCapture,
// поэтому вставляем обработчики и надеемся на то, что
// требуемые события мыши всплывут к объекту document.
// Предварительно сохраним значения событийных свойств.
oldMoveHandler = document.onmousemove;
oldUpHandler = document.onmouseup;
document.onmousemove = moveHandler;
document.onmouseup = upHandler;
}
// Событие mousedown обработано, прервём
// его дальнейшее распространение
if(event.stopPropagation) // Если работает модель DOM W3C
event.stopPropagation(); // DOM W3C
else event.cancelBubble = true; // IE
// На всякий случай запретим действие по умолчанию
if(event.preventDefault) // Если работает модель DOM W3C
event.preventDefault(); // DOM W3C
else event.returnValue = false; // IE
}
}
// Обработать перемещение мыши
function moveHandler(event)
{
// Если аргумент не передан, это IE, и тогда присвоим локальной
// переменной event ссылку на глобальный объект window.event,
// в котором IE хранит свойства события.
event = event || window.event;
// Переместить элемент в текущие координаты указателя мыши
element.style.left = event.clientX-xStartMouse + "px";
element.style.top = event.clientY-yStartMouse + "px";
// Прервать дальнейшее распространение события
if(event.stopPropagation) // Если работает модель DOM W3C
event.stopPropagation(); // DOM W3C
else event.cancelBubble = true; // IE
}
// Обработать заключительное событие -- отпускание кнопки мыши
function upHandler(event)
{
// Если аргумент не передан, это IE, и тогда присвоим локальной
// переменной event ссылку на глобальный объект window.event,
// в котором IE хранит свойства события.
event = event || window.event;
// Удалить обработчики событий mouseup и mousemove
if(document.removeEventListener) // Если работает модель DOM W3C
{
document.removeEventListener("mousemove", moveHandler, true);
document.removeEventListener("mouseup", upHandler, true);
}
else if(document.detachEvent) // Если работает модель IE5+
{
document.detachEvent("onlosecapture", upHandler);
document.detachEvent("onmouseup", upHandler);
document.detachEvent("onmousemove", moveHandler);
// Остановим перенаправление событий мыши к элементу
element.releaseCapture();
}
else // Модель событий IE4
{
// Восстановить первоначальное значение событийных свойств
document.onmousemove = oldMoveHandler;
document.onmouseup = oldUpHandler;
}
// Прервать дальнейшее распространение события
if(event.stopPropagation) // Если работает модель DOM W3C
event.stopPropagation(); // DOM W3C
else event.cancelBubble = true; // IE
// Запустить анимацию, которая возвратит элемент на место
toHome();
}
function toHome()
{
var numFrames = 100; // Число кадров в анимации картинки
var v0 = 10; // Начальная скорость картинки
// Коодинаты картинки относительно её исходного положения,
// которое есть (0,0). Функция parseInt забирает число, отбрасывая "px"
var left = parseInt(element.style.left);
var top = parseInt(element.style.top);
// Вычисляем ускорения по двум направлениям
var aLeft = (Math.abs(left)-v0*numFrames)/(numFrames*numFrames);
var aTop = (Math.abs(top)-v0*numFrames)/(numFrames*numFrames);
// Запускаем анимацию
animateCSS(element, numFrames, 10,
{
left: function(frame,time)
{
return (left-sign(left)*(v0*frame+aLeft*frame*frame))+"px";
},
top: function(frame,time)
{
return (top-sign(top)*(v0*frame+aTop*frame*frame))+"px";
}
}, function ()
{
// Картинка закончила движение
isСomeBack = false; // Теперь ее снова можно двигать
// Подровняем картинку на её законном месте
element.style.left = element.style.top = 0;
// Поставим её в свой слой
element.style.zIndex = 0;
});
}
// Функция, вычисляющая знак числа
function sign(a) { return a<0 ? -1:1;}
};
praxis/14/examples/05/index.htm
Содержимое файла index.htm
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<HTML lang="ru">
<HEAD>
<META http-equiv="Content-Type"
content="text/html; charset=windows-1251">
<META http-equiv="imagetoolbar" content="no">
<LINK rel="stylesheet" type="text/css" href="main.css">
<SCRIPT type="text/javascript" src="main.js"></SCRIPT>
<TITLE>Почти Арканоид</TITLE>
</HEAD>
<BODY>
<H1>Почти Арканоид</H1>
<DIV id="field">
<IMG id="ball" src="pic/disc.gif" width=11 height=11 alt="" title="">
<DIV id="racket"><IMG src="pic/empty.gif"
width=1 height=1 alt="" title=""></DIV>
</DIV>
<P>
Старт — пробел<BR>
Ракетка — стрелки
</P>
</BODY>
</HTML>
Содержимое файла main.js
// Обработчик события onload
// Функциональный литерал будет вызван после полной загрузки документа
// и построения его объектной модели
window.onload = function ()
{
// =================== Константы и переменные ======================
// Размеры игрового поля
var widthField = 600;
var heightField = 400;
// Размеры ракетки
var widthRacket = 100;
var heightRacket = 10;
// Движение ракетки
var step0Racket=5; // Начальный шаг смещения ракетки
var stepMaxRacket=10; // Максимальный шаг смещения ракетки
var stepRacket=step0Racket; // Текущий шаг смещения ракетки
var aRacket=1.05; // Ускорение: stepRacket *= aRacket на каждом шаге
var dtRacket = 10; // Временной интервал перерисовки ракетки
var timerRacket = null; // Таймер для движения ракетки
var dirMoveRacket = 0; // -1 -- ракетка двигается влево
// 0 -- ракетка стоит на месте
// 1 -- ракетка двигается вправо
// =================== Ссылки на объекты ===========================
// Ссылки на объекты
var field = document.getElementById("field"); // Поле
var racket = document.getElementById("racket"); // Ракетка
// =================================================================
// =================== Представление ===============================
// Стили игрового поля
field.style.width = widthField+"px";
field.style.height = heightField+"px";
// Стили ракетки
racket.style.width = widthRacket+"px";
racket.style.height = heightRacket+"px";
racket.style.left = 0;
// =================================================================
// =================== Обработчики событий =========================
document.onkeydown = keydownHandler; // Нажата клавиша
document.onkeyup = keyupHandler; // Отпущена клавиша
// =================== Нажата клавиша ========================
function keydownHandler(event)
{
event = event || window.event;
switch(event.keyCode)
{
case 37: // Стрелка влево -------------------------------------
if(timerRacket) // Если ракетка уже двигается влево,
{ // то игнорировать нажатие.
if(dirMoveRacket == -1) return;
clearMoveRacket(); // В противном случае (когда вправо),
} // прекратить движение
// Запустим движение ракетки влево
dirMoveRacket = -1;
timerRacket = setInterval(leftRacket, dtRacket);
break;
case 39: // Стрелка вправо ------------------------------------
if(timerRacket) // Если ракетка уже двигается вправо,
{ // то игнорировать нажатие.
if(dirMoveRacket == 1) return;
clearMoveRacket(); // В противном случае (когда влево),
} // прекратить движение
// Запустим движение ракетки влево
dirMoveRacket = 1;
timerRacket = setInterval(rightRacket, dtRacket);
break;
case 32: // Пробел ---------------------------------------------
start();
}
}
// =================== Отпущена клавиша ========================
function keyupHandler(event)
{
if(!timerRacket) return; // Если движения ракетки нет, игнорировать
event = event || window.event;
// Остановить движение ракетки в каждом из двух случаев:
// 1) Отпущена стрелка влево в тот момент, когда ракетка двигается влево
// 2) Отпущена стрелка вправо в тот момент, когда ракетка двигается вправо
var stop = false;
if((event.keyCode == 37 // Отжата стрелка влево, когда ракетка двигается влево
&& dirMoveRacket == -1) || // или
(event.keyCode == 39 // Отжата стрелка вправо, когда ракетка двигается вправо
&& dirMoveRacket == 1)) stop = true;
if(stop) clearMoveRacket();
}
// =================== Остановить движение ракетки =================
function clearMoveRacket()
{
// Прервать работу таймера
clearInterval(timerRacket);
timerRacket = null;
// Восстановить начальный шаг смещения ракетки
stepRacket = step0Racket;
// Сбросить флаг направления движения ракетки
dirMoveRacket = 0;
}
// =================== Ракетка на шаг влево =================
function leftRacket()
{
var x = parseInt(racket.style.left);
if((stepRacket *= aRacket) > stepMaxRacket) stepRacket = stepMaxRacket;
if(x-stepRacket > 0) racket.style.left = (x-stepRacket)+"px";
else racket.style.left = 0;
}
// =================== Ракетка на шаг вправо =================
function rightRacket()
{
var x = parseInt(racket.style.left);
if((stepRacket *= aRacket) > stepMaxRacket) stepRacket = stepMaxRacket;
if(x+widthRacket+stepRacket < widthField) racket.style.left = (x+stepRacket)+"px";
else racket.style.left = (widthField-widthRacket)+"px";
}
// =================== Старт игры =========================
function start()
{
alert("старт")
}
};
praxis/14/examples/06/index.htm
Содержимое файла index.htm
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<HTML lang="ru">
<HEAD>
<META http-equiv="Content-Type"
content="text/html; charset=windows-1251">
<META http-equiv="imagetoolbar" content="no">
<LINK rel="stylesheet" type="text/css" href="main.css">
<SCRIPT type="text/javascript" src="animateCSS.js"></SCRIPT>
<SCRIPT type="text/javascript" src="main.js"></SCRIPT>
<TITLE>Почти Арканоид</TITLE>
</HEAD>
<BODY>
<H1>Почти Арканоид</H1>
<DIV id="field">
<IMG id="ball" src="pic/disc.gif" width=11 height=11 alt="" title="">
<DIV id="racket"><IMG src="pic/empty.gif"
width=1 height=1 alt="" title=""></DIV>
</DIV>
<DIV id="time">Время игры</DIV>
<DIV id="record">Рекорд</DIV>
<P>
Старт — пробел<BR>
Ракетка — стрелки
</P>
</BODY>
</HTML>
Содержимое файла main.js
// Почти Арканоид
// (C) март 2010 А.А.Дуванов
// ------------------------
// Обработчик события onload
// Функциональный литерал будет вызван после полной загрузки документа
// и построения его объектной модели
window.onload = function ()
{
// =================== Константы и переменные ======================
// Размеры игрового поля
var widthField = 600;
var heightField = 400;
// Размеры ракетки
var widthRacket = 100;
var heightRacket = 10;
// Движение ракетки
var step0Racket=5; // Начальный шаг смещения ракетки
var stepMaxRacket=10; // Максимальный шаг смещения ракетки
var stepRacket=step0Racket; // Текущий шаг смещения ракетки
var aRacket=1.05; // Ускорение: stepRacket *= aRacket на каждом шаге
var dtRacket = 10; // Временной интервал перерисовки ракетки
var timerRacket = null; // Таймер для движения ракетки
var dirMoveRacket = 0; // -1 -- ракетка двигается влево
// 0 -- ракетка стоит на месте
// 1 -- ракетка двигается вправо
// Шарик
var widthBall = 11;
var heightBall = 11;
var ismoveBall = false; // true, если шарик в игре
var timerBall = null; // Таймер для шарика
var dtBall = 10; // Временной интервал перерисовки шарика
var fiBall; // Угол, под которым двигается шарик
var dx0Ball = 6; // Начальная величина шага шарика по горизонтали
var dy0Ball = -6; // Начальная величина шага шарика по вертикали
var dxBall; // Величина шага движения шарика по горизонтали
var dyBall; // Величина шага движения шарика по вертикали
// Время игры и рекорд
var timeGame;
var timeRecord=0;
// =================== Ссылки на объекты ===========================
// Ссылки на объекты
var field = document.getElementById("field"); // Поле
var racket = document.getElementById("racket"); // Ракетка
var ball = document.getElementById("ball"); // Шарик
var time = document.getElementById("time"); // Время игры
var record = document.getElementById("record"); // Рекорд
// =================================================================
// =================== Представление ===============================
// Стили игрового поля
field.style.width = widthField+"px";
field.style.height = heightField+"px";
// Стили ракетки
racket.style.width = widthRacket+"px";
racket.style.height = heightRacket+"px";
racket.style.left = 0;
// Стили шарика
ball.style.visibility = "hidden";
// =================================================================
// =================== Обработчики событий =========================
document.onkeydown = keydownHandler; // Нажата клавиша
document.onkeyup = keyupHandler; // Отпущена клавиша
// =================== Нажата клавиша ========================
function keydownHandler(event)
{
event = event || window.event;
switch(event.keyCode)
{
case 37: // Стрелка влево -------------------------------------
if(timerRacket) // Если ракетка уже двигается влево,
{ // то игнорировать нажатие.
if(dirMoveRacket == -1) return;
clearMoveRacket(); // В противном случае (когда вправо),
} // прекратить движение
// Запустим движение ракетки влево
dirMoveRacket = -1;
timerRacket = setInterval(leftRacket, dtRacket);
break;
case 39: // Стрелка вправо ------------------------------------
if(timerRacket) // Если ракетка уже двигается вправо,
{ // то игнорировать нажатие.
if(dirMoveRacket == 1) return;
clearMoveRacket(); // В противном случае (когда влево),
} // прекратить движение
// Запустим движение ракетки влево
dirMoveRacket = 1;
timerRacket = setInterval(rightRacket, dtRacket);
break;
case 32: // Пробел ---------------------------------------------
start();
}
}
// =================== Отпущена клавиша ========================
function keyupHandler(event)
{
if(!timerRacket) return; // Если движения ракетки нет, игнорировать
event = event || window.event;
// Остановить движение ракетки в каждом из двух случаев:
// 1) Отпущена стрелка влево в тот момент, когда ракетка двигается влево
// 2) Отпущена стрелка вправо в тот момент, когда ракетка двигается вправо
var stop = false;
if((event.keyCode == 37 // Отжата стрелка влево, когда ракетка двигается влево
&& dirMoveRacket == -1) || // или
(event.keyCode == 39 // Отжата стрелка вправо, когда ракетка двигается вправо
&& dirMoveRacket == 1)) stop = true;
if(stop) clearMoveRacket();
}
// =================== Остановить движение ракетки =================
function clearMoveRacket()
{
// Прервать работу таймера
clearInterval(timerRacket);
timerRacket = null;
// Восстановить начальный шаг смещения ракетки
stepRacket = step0Racket;
// Сбросить флаг направления движения ракетки
dirMoveRacket = 0;
}
// =================== Ракетка на шаг влево =================
function leftRacket()
{
var x = parseInt(racket.style.left);
if((stepRacket *= aRacket) > stepMaxRacket) stepRacket = stepMaxRacket;
if(x-stepRacket > 0) racket.style.left = (x-stepRacket)+"px";
else racket.style.left = 0;
}
// =================== Ракетка на шаг вправо =================
function rightRacket()
{
var x = parseInt(racket.style.left);
if((stepRacket *= aRacket) > stepMaxRacket) stepRacket = stepMaxRacket;
if(x+widthRacket+stepRacket < widthField) racket.style.left = (x+stepRacket)+"px";
else racket.style.left = (widthField-widthRacket)+"px";
}
// =================== Старт игры =========================
function start()
{
if(!ismoveBall)
{
// Установим флаг начала движения шарика
ismoveBall=true;
// Установим шарик на середину ракетки
ball.style.left = parseInt(racket.style.left)+
(widthRacket/2 - widthBall/2) + "px";
ball.style.top = (heightField-heightRacket-heightBall) + "px";
// Сделаем шарик видимым
ball.style.visibility = "visible";
// Сгенерируем угол, под которым стартует шарик
fiBall = Math.PI*Math.random()/6;
if (fiBall > Math.PI/6) fiBall += 7*Math.PI/12;
else fiBall += Math.PI/4;
// Установим шаги движения шарика
dxBall = dx0Ball;
dyBall = dy0Ball;
// Установим время игры
timeGame = 0;
// Запустим движение шарика
timerBall = setInterval(moveBall, dtBall);
}
}
// =================== Движение шарика =========================
function moveBall()
{
// Время игры
timeGame++;
time.innerHTML = "Время игры: " + timeGame;
// Смещение шарика
var left = parseInt(ball.style.left);
var top = parseInt(ball.style.top);
var dx = dxBall*Math.cos(fiBall);
var dy = dyBall*Math.sin(fiBall);
left += dx;
top += dy;
if (left < -widthBall/2)
{
dxBall = -dxBall;
left = -widthBall/2;
}
else if(left > widthField-widthBall/2)
{
dxBall = -dxBall;
left = widthField-widthBall/2;
}
if (top < -heightBall/2)
{
dyBall = -dyBall;
top = -heightBall/2;
}
else if (top >= heightField-heightRacket-heightBall/2)
{
var racketLeft = parseInt(racket.style.left);
// Проверим, нет ли под шариком ракетки
if(racketLeft-widthBall/2 < left && left <
racketLeft + widthRacket+widthBall/2)
{
// Да, ракетка есть
dyBall = -dyBall;
top = heightField-heightRacket-heightBall/2;
}
else
{
// Ракетки нет
ismoveBall=false;
clearInterval(timerBall);
ball.style.visibility = "hidden";
if (timeRecord < timeGame) timeRecord = timeGame;
record.innerHTML = "Рекорд: " + timeRecord;
}
}
ball.style.left = left + "px";
ball.style.top = top + "px";
}
};