[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: Зацениваем игру "Колобок"
bodja
Вообще собирался сделать игру "танчики" но inpost мне показал свою игрушку и я был немного заинтригован сложностью ее реализации.
Дело в том ,что у подобной игры есть подводные камни связанные с торможением из за большого количества одновременно перемещаемых элементов в ДОМ.
Решением этой проблемы было не располагать элементы уровня ,а просто нарисовать в качестве фона и его перемещать.Тем самым увеличили скорость и убили проблему со скроллингом.Создаем отдельно и перемещаем одновременно с уровнем только бонусы ,которые будут исчезать из уровня.Кстати они тоже перемещаются в фоне ,накладываясь прозрачной картинкой,а не через top ,left.
В итоге все работает достаточно шустро.
Твердую поверхность и расположение бонусов мы описываем в массиве ,как и предыдущей игре.
Здесь код игры.Есть два уровня.

Свернутый текст
//Главный класс
function Colobok() {
//Указатель на елемент в документе ,где будет наша игрушка
this.container = document.getElementById('game');
//Инициализация неба
this.nebo = document.createElement('div');
this.nebo.style.cssText = 'position:absolute;width:600px;height:400px;top:0px;left:0px;background:url("./nebo.png");background-repeat:no-repeat;background-position:-60px 0px;';
this.container.appendChild(this.nebo);
//Инициализация колобка
this.ballStep = 0;//
this.ballY = 300;//
this.ballUpY = 0;//
this.ball = document.createElement('div');
this.ball.style.cssText = 'position:absolute;width:50px;height:400px;top:0px;left:250px;background:url("./ball.png");background-repeat:no-repeat;background-position:0px 300px;';
this.container.appendChild(this.ball);
//Инициализация уровня
this.level = 1;//номер уровня
this.bg = document.createElement('div');
this.bg.style.cssText = 'position:absolute;width:600px;height:400px;top:0px;left:0px;background-repeat:no-repeat;';
this.container.appendChild(this.bg);
//Инициализация жизней
this.lifeCount = 3;//количество жизней
this.life = document.createElement('span');
this.life.style.cssText = 'position:absolute;width:auto;height:auto;top:5px;left:10px;font:bold 16px Arial;color:#fff;';
this.life.innerHTML = 'ЖИЗНЕЙ : ' + this.lifeCount;
this.container.appendChild(this.life);
//Инициализация очков
this.counterCount = 0;//Количество очков
this.counter = document.createElement('span');
this.counter.style.cssText = 'position:absolute;width:auto;height:auto;top:5px;left:200px;font:bold 16px Arial;color:#fff;';
this.counter.innerHTML = 'ОЧКИ : ' + this.counterCount;
this.container.appendChild(this.counter);
//Инициализация уровня
this.level = 1;
this.stageCount = 1;
this.stage = document.createElement('span');
this.stage.style.cssText = 'position:absolute;width:auto;height:auto;top:5px;left:400px;font:bold 16px Arial;color:#fff;';
this.stage.innerHTML = 'УРОВЕНЬ : ' + this.stageCount;
this.container.appendChild(this.stage);

//Обработчик события нажатия клавиш "пробел", "вправо", "влево"
document.body.onkeydown = function (o) {
return function (event) {
var e=event||window.event;
if (e.keyCode == 32) {
if (o.ballStep == 0) {
o.ballStep = -5;
o.ballUpY = o.ballY - 150;
o.ballCycles();
}
}

if (e.keyCode == 37) {
if (o.bgStep == 0) {
o.bgStep = 10;
o.bgCycles();
}
}

if (e.keyCode == 39) {
if (o.bgStep == 0) {
o.bgStep = -10;
o.bgCycles();
}
}
}
}

(this);

//Обработчик события отпускания клавиш
document.body.onkeyup = function (o) {
return function (event) {
var e=event||window.event;
if (e.keyCode == 37 || e.keyCode == 39) {
o.bgStep = 0;
}
}
}

(this);

//Обработчик циклов перемещения фона уровня и неба
this.bgCycles = function () {
if (this.bgStep != 0) {
setTimeout(function (o) {
return function () {
if ((level[o.level][parseInt(o.ballY / 50) + 1][-parseInt((o.bgX + o.bgStep - 250) / 50)] != 1) && (level[o.level][parseInt(o.ballY / 50) + 1][-parseInt((o.bgX - 40 + o.bgStep - 250) / 50)] != 1)) {
if (o.ballStep == 0) {
o.ballStep = 5;
o.ballCycles();
}
}

if ((level[o.level][parseInt((o.ballY + 40) / 50)][-parseInt((o.bgX + o.bgStep - 250) / 50)] != 1) && (level[o.level][parseInt((o.ballY + 40) / 50)][-parseInt((o.bgX - 40 + o.bgStep - 250) / 50)] != 1) && (o.bgX + o.bgStep > -1900) && (o.bgX + o.bgStep < 300)) {
o.bgX += o.bgStep;
}
o.bg.style.backgroundPosition = o.bgX + 'px 0px';
o.nebo.style.backgroundPosition = parseInt(o.bgX / 5) - 60 + 'px 0px';
o.bgCycles();
for (var x = 0; x < o.bonusArr.length; x++) {
o.bonusArr[x].set(o.ballY, o.bgX);
}
}
}

(this), 20);
}
}


//Обработчик циклов перемещения колобка
this.ballCycles = function () {
if (this.ballStep != 0) {
setTimeout(function (o) {
return function () {
if (o.ballY < o.ballUpY || o.ballY < 5 || (level[o.level][parseInt(o.ballY / 50)][-parseInt((o.bgX - 250) / 50)] == 1) || (level[o.level][parseInt(o.ballY / 50)][-parseInt((o.bgX - 295) / 50)] == 1)) {
o.ballStep = 5;
}
if (o.ballY > 340) {
o.ballStep = 0;
o.ballY = 300;
o.bgX = 0;
o.bgStep = 0;
o.ball.style.backgroundPosition = '0px ' + o.ballY + 'px';
o.bg.style.backgroundPosition = o.bgX + 'px 0px';
o.nebo.style.backgroundPosition = parseInt(o.bgX / 5) - 60 + 'px 0px';
o.lifeCount--;
o.life.innerHTML = 'ЖИЗНЕЙ : ' + o.lifeCount;
if (o.lifeCount == 0) {
document.body.onkeydown = '';
alert('Игра окончена');
}
}

if ((o.ballStep == 5) && ((level[o.level][parseInt(o.ballY / 50) + 1][-parseInt((o.bgX - 250) / 50)] == 1) || (level[o.level][parseInt(o.ballY / 50) + 1][-parseInt((o.bgX - 295) / 50)] == 1))) {
o.ballStep = 0;
}
o.ballY += o.ballStep;
o.ball.style.backgroundPosition = '0px ' + o.ballY + 'px';
if (o.bgStep == 0) {
for (var x = 0; x < o.bonusArr.length; x++) {
o.bonusArr[x].set(o.ballY, o.bgX);
}
}

o.ballCycles();
}
}

(this), 20);
}
}


//Запускаем уровень
this.open = function () {
this.bgX = 0;
this.bgStep = 0;
this.bg.style.background = 'url("' + bglevel[this.level] + '")';
this.bg.style.backgroundRepeat = 'no-repeat';
this.bg.style.backgroundPosition = '0px 0px';
//Определяем количество обьектов бонусов и располагаем на на уровне
this.bonusCount = 0;
this.bonusArr = [];
for (var y = 0; y < 8; y++) {
for (var x = 0; x < 32; x++) {
if (level[this.level][y][x] != 0 && level[this.level][y][x] != 1) {
this.bonusArr[this.bonusCount] = new Bonus(this, y, x, level[this.level][y][x]);
this.bonusCount++;
}
}
}
}

this.open();
}


//Класс бонусов
function Bonus(obj, y, x, mode) {
this.close = false;//
this.opacity = 100;//
this.obj = obj;//
this.X = 50 * x;//
this.Y = 50 * y;//
this.mode = mode;//

//Инициализация элемента бонуса

this.el = document.createElement('div');
this.el.style.cssText = 'position:absolute;width:600px;height:400px;top:' + this.Y + 'px;left:' + this.X + 'px;background:url("' + imgbonus[this.mode] + '");background-repeat:no-repeat;';
this.obj.container.appendChild(this.el);

//Инициализация элемента цифры бонуса
this.starInt = parseInt((Math.random() * 5) + 1) * 100;
this.star = document.createElement('span');
this.star.innerHTML = this.starInt;

//Определяем ,столкнулся ли колобок с нашим обьектом бонуса
this.set = function (y, x) {
this.el.style.left = this.X + x + 'px';
if ((y + 50) > this.Y && y < (this.Y + 50) && (-x + 300) > this.X && (-x + 200) < this.X) {
if (this.close == false) {
this.close = true;
this.obj.container.removeChild(this.el);
this.obj.counterCount += this.starInt;
this.obj.counter.innerHTML = 'ОЧКИ : ' + this.obj.counterCount;
if (this.mode == 3) {
this.obj.lifeCount++;
this.obj.life.innerHTML = 'ЖИЗНЕЙ : ' + this.obj.lifeCount;
}
if (this.mode == 4) {
if (this.obj.ballStep == 0) {
this.obj.ballStep = -5;
this.obj.ballUpY = this.obj.ballY - 150;
this.obj.ballCycles();
} else {
this.obj.ballStep = -5;
this.obj.ballUpY = this.obj.ballY - 150;
}
}

this.Y -= 20;
this.obj.bonusCount--;
if (this.obj.bonusCount != 0) {
this.star.style.cssText = 'position:absolute;width:auto;height:auto;top:' + this.Y + 'px;left:' + (this.X + x) + 'px;font:bold 13px Arial;color:#fff;';
this.obj.container.appendChild(this.star);
this.cycles();
} else {
this.obj.ballStep = 0;
this.obj.ballY = 300;
this.obj.ballUpY = 0;
this.obj.level++;
this.obj.stage.innerHTML = 'УРОВЕНЬ : ' + this.obj.level;
this.obj.ball.style.backgroundPosition = '0px 300px';
if (this.obj.level < level.length) {
alert('Переходим на следующий уровень');
this.obj.container.style.background = 'url("' + bglevel[this.obj.level] + '")';
this.obj.open();
} else {
document.body.onkeydown = '';
alert('Поздравляем! Вы прошли все уровни!');
}
}
}
}
}


//Анимация исчезающей цифры бонуса
this.cycles = function () {
setTimeout(function (o) {
return function () {
o.star.style.opacity = o.opacity / 100;
o.opacity -= 5;
o.Y -= 1;
o.star.style.top = o.Y + 'px';
if (o.opacity != 0) {
o.cycles();
} else {
o.obj.container.removeChild(o.star);
}
}
}

(this), 20)
}
}


//картинки фрнов уровней
var bglevel = ['', 'level1.png', 'level2.png'];

//картинки бонусов
var imgbonus = ['', '', './bonus1.png', './bonus2.png', './bonus3.png']

//массивы уровней,0-пустота,1-твердая поверхность,2-3-4 вариации бонусов
var level = [];
level[1] = [
[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0],
[
0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0],
[
0, 1, 1, 0, 0, 0, 2, 0, 0, 0, 1, 1, 0, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 3, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 4, 0, 1],
[
0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 2, 0, 0, 0, 3, 1, 0, 0, 0, 0],
[
0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0]]
level[2] = [
[
3, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 2, 1, 0, 3, 2, 0, 1, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0],
[
0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 2, 0, 1, 0, 0, 3, 0, 0, 0, 0, 0],
[
0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 2],
[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0],
[
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 2, 0, 0, 1, 0, 0, 0, 0],
[
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 4, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[
0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0],
[
4, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 4, 1, 0, 1, 1, 0, 1, 4, 4, 1, 0, 0, 0, 1, 0, 4, 1, 4, 0, 1, 4]]

//Запускаем игру после загрузки страницы
window.onload = function () {
var game = new Colobok();
}


Здесь сама игра

Если кому не лень сделать гиф-анимашку ходячего колобка вправо-влево буду признателен.

ЗЫ inpost -это подарок вам,на базе такого "движка" можно наделать кучу разных вариаций игр,подпиляв под свои задачи.
В целом по играм на JS все ясно,думаю на этом буду пока закруглятся.



Спустя 2 минуты, 56 секунд (13.08.2012 - 21:54) Игорь_Vasinsky написал(а):
Цитата
В целом по играм на JS все ясно,думаю на этом буду пока закруглятся.

респект wink.gif
а я не сном не духом biggrin.gif

Спустя 8 минут, 12 секунд (13.08.2012 - 22:02) inpost написал(а):
bodja
Если ты не возражаешь, я немного прокомментирую. По одной оси прокрутка и у меня работала, глюки очень сильные начинались, когда шла прокрутка сразу по двум осям. Я пробовал сравнивать скорость с перемещением заднего фона - та же проблема, к тому же фон даже хуже результаты давал. Прокрутка лишь по одной оси не тормозит, как и у тебя. Если есть возможность, попробуй в своей схеме сразу по двум осям прокрутку.
Далее вторая проблема такая же как и у меня. Если мы зажимаем влево кнопку - объект начинает движение, но если мы отжимаем кнопку - создаётся слишком большая очередь и движение сразу не прекращается. Поэтому если резко попробовать нажать вправо - мы стоим на месте. Дело в том, что одновременно будет отрабатывать и движение влево и движение вправо, итого на одной точке.
Ну и третья проблема, которая уже у тебя - это дёрганное изображение, то есть в моей вариации оно было более гладкое лишь потому, что чаще выполнялось действие и из-за этого очередь слишком большой становилось...

А в целом - молодец. Но я пришел к выводу, что на JS делать даже 8-битные игры не вариант, как-то всё ужасно работает. Мне кажется, что этот же код на том же С++ просто летал бы с современными компами...

Спустя 2 минуты, 8 секунд (13.08.2012 - 22:04) Игорь_Vasinsky написал(а):
а завидовать не хорошо tongue.gif

Спустя 1 минута, 52 секунды (13.08.2012 - 22:06) Каролина написал(а):
только на 2 уровне нет выхода

Спустя 1 минута, 54 секунды (13.08.2012 - 22:08) inpost написал(а):
Игорь_Vasinsky
Зависть? Так всё одинаковое smile.gif Одни и те же проблемы, одни и те же глюки. Чуть лучше у меня с движением, тут с прыжками, вот и всё smile.gif

Спустя 4 минуты, 15 секунд (13.08.2012 - 22:12) killer8080 написал(а):
Цитата (Каролина @ 13.08.2012 - 23:06)
только на 2 уровне нет выхода


Выход есть! красный крестик в правом верхнем углу окна biggrin.gif

Спустя 6 минут, 16 секунд (13.08.2012 - 22:19) Игорь_Vasinsky написал(а):
inpost
да лан.. я угарнул же))

Спустя 15 часов, 9 минут, 25 секунд (14.08.2012 - 13:28) bodja написал(а):
inpost
Ох трудно тебе угодить,все мелкие недочеты высмотрел biggrin.gif
Физика этих клюков немного другая,теперь по порядку.
.style.backgroundPosition принимает сразу два аргумента по X и Y ,я не думаю что мы увидим заметную разницу что в перемещении в одной координате ,что в двух сразу.
Некоторые дергания имеют место быть ,но я думаю это связано с не очень чистой логикой проверки касания по поверхности с учетом направления движения.
По перемещению вправо-влево ,мы имеем один метод ,а не два и два потока,там меняется шаг на отрицательный ,а при отпускании шаг равен 0 ,в итоге если отпустим кнопку позже чем нажмем кнопку противоположного направления движение остановится.Я думаю здесь тоже стоит доработать логику.
Тесты я проводил на большое количество элементов ,вот здесь залепил за сотню.
http://bodja74.narod2.ru/games/colobok/test.html
Как видим заметной разницы нет.

Спустя 3 часа, 45 минут, 50 секунд (14.08.2012 - 17:14) VELIK505 написал(а):
Круто! Молодец!

Спустя 12 минут, 18 секунд (14.08.2012 - 17:26) inpost написал(а):
bodja
дергаются в полёте тоже, а вообще это заметно лишь потому, что изменяешь ты положение шарика не на 1-2px, а больше. На глаз около 5-10px каждую итерацию, но в код не смотрел насчёт этого.
Я не понял, объясни, будь добр, ты говоришь, что не прокрутку делаешь, а меняешь фон. Ты двигаешь сразу все объекты? Или как?

Спустя 1 час, 9 минут, 15 секунд (14.08.2012 - 18:36) bodja написал(а):
По вертикали у меня 5px по горизонтали 10px а по диагонали тогда выходит и того больше,возможно тоже из за этого.
Теперь по фону ,смотри.
1 Ставим все дивы на весь размер поверх другого,картинку в фон.

this.el.style.cssText = 'position:absolute;width:600px;height:400px;top:0px;left:0px;background:url("./bonus.png");background-repeat:no-repeat;';


2 потом просто меняем смещение фона.

this.el.style.backgroundPosition = this.X + 'px '+this.Y+'px';


Для того чтобы обратится ко всем обьектам сразу ,я сначала вычисляю и создаю их количество согласно карте при создаии уровня,складываю их в массив ,потом по длине массива в цикле вгоняю в них новые значения.
Вот и все.

Спустя 11 минут, 43 секунды (14.08.2012 - 18:47) inpost написал(а):
bodja
Спасибо. Почитаю.

Спустя 17 дней, 2 часа, 30 минут, 17 секунд (31.08.2012 - 21:18) Ramzes_Ra написал(а):
bodja
ну ты мужик... я на такое не способен вообще..
Всегда мечтал понять, как создавать такие игры, но когда увидел код - понял, что если делать это, то надо учиться на программиста)

Спустя 6 минут, 54 секунды (31.08.2012 - 21:24) Игорь_Vasinsky написал(а):
rolleyes.gif
практика...только практикка.
и ты прав. это достойно уважения.

и инпост кстати тоже написал подобное.

Спустя 16 минут, 43 секунды (31.08.2012 - 21:41) Ramzes_Ra написал(а):
Игорь_Vasinsky
инпост тоже мужик, я это давно уже знаю.. Он настоящий кодер от слова КОД)))

у меня есть в проекте одна игруха.. как я за неё возьмусь и сделаю хотя бы демо версию, выложу на оценку.. и попрошу inposta научить некоторым приемам, если я сам не освою на тот момент..

Спустя 4 минуты, 26 секунд (31.08.2012 - 21:46) Игорь_Vasinsky написал(а):
на то и есть этот форум дружище) учится, учится и когда нить другим помочь учиться wink.gif

Спустя 12 часов, 37 минут, 51 секунда (1.09.2012 - 10:23) bodja написал(а):
Ramzes_Ra
Все дело в стереотипах.

Когда ты выбросиш из головы ХТМЛ шаблоны и разметку, и начнеш относиться к элементу как к обьекту (а в DOM элемент и есть обьект), тогда ты ощутиш полный контроль над ними.

Когда ты выбросиш из головы размытые определения инкапсуляции наследования и полиморфизма ,и кто что умное ляпнул по этому поводу, и сядеш сам разберешся в этом вопросе , тогда ты ощутиш тотальный контроль над своим кодом.

Все... Далее уже не важно, что ты не умел делать,с этого момента ты можеш строить любое взаимодействие кода и визуально его проэцировать. Твою фантазию будет ограничивать только возможности браузера и... твоя собственная фантазия.

ЗЫ может слишком лирично сказал, но оно так есть.
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.