Игровой баннер типа “Шутер”

07.08.2008, автор Stormit, рубрики: ActionScript, Игровые баннеры

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

Некоторые приемы уже были описаны ранее в статьях. Из нового здесь только такое физическое явление, как гравитация (новое на сайте).  Можно было выкрутиться и сделать подпрыгивание бутылок анимацией, но мне захотелось внести больше разнообразия - пусть подпрыгивают на разную высоту, крутятся с разной скоростью, по разному в стороны разлетаются. Тем более, что сделать это программно совсем не сложно.

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

При равномерном движении можно просто прибавлять к координате число. Но введение понятия “Скорость” позволяет организовать замедление и ускорение.

Осталось разобраться с гравитацией. Это сила, которая с постоянной величиной действует вертикально вниз на все объекты (в программировании обычно на все незакрепленные объекты). То есть постоянно (по событию enterFrame) прибавляет какое-то значение к скорости (переменной speedY). Почему именно к скорости? Потому что к координатам применяется уже суммарный вектор всех сил (у нас пока только скорость и гравитация). Поэтому вначале применяем гравитацию к скорости, а потом скорость к координатам. Надеюсь, не намудрил.

Теперь по порядку:

  1. Рисуем объект, который должен подскакивать - бутылка. Называем его target.
  2. Слоем выше пишем код:
    lev = 0;
    gravity = 1;//величина гравитации подбирается (визуально зависит от frameRate)
    function placeTarget() {
    	lev++;
    	var d = target.duplicateMovieClip("t" + lev, lev);
    	d.speedY = -15 - Math.random() * 5;//начальные значения скорости
    	d.speedX = Math.random() * 4;// плюс небольшой разброс
    	d.rotSpeed = (Math.random() - .5) * 20;//случайный шаг для вращения
    	if (Math.random() < .5) {
    		d.speedX = -d.speedX;//больше разницы - отражаем бутылку по горизонтали
    	}
    	d.onEnterFrame = function() {
    		this.speedY += gravity;
    		this._y += this.speedY;
    		this._x += this.speedX;
    		this._rotation += this.rotSpeed;
    		if (this._y > target._y) {
    			this.removeMovieClip();//удаляем если улетела ниже экрана
    		}
    	};
    }
    count = 0;
    onEnterFrame = function () {
    	if (count++ > 15) {//добавляем бутылку каждый 15-й кадр
    		count = 0;
    		placeTarget();
    	}
    };

    Символ с бутылкой лучше сдвинуть вниз за пределы флэшки, чтобы не было видно оригинала. Уже хорошо, но бутылка вылетает всегда из одной точки. Если у нас широкий баннер, много места будет не использовано.

  3. Поэтому на уровне бутылки добавляем символ box в виде полоски (центр слева). И располагать дубликаты теперь будем случайно по ее длине. В функции placeTarget нужно дописать Одну строку:
    d._x = box._x + Math.random() * box._width;
  4. Вот так это выглядит, если отъехать камерой в космос.
  5. Чтобы интереснее было играть, устроим борьбу штрафов и бонусов. Бутылки выбивать можно, а пачки с соком нельзя. Поэтому в символе target теперь 2 кадра: в первом сок, во втором спиртное. Теперь эти символы, бутылку и сок, назовем obj. А чтобы еще интереснее было, сделаем несколько видов бутылок - внутри клипа obj (бутылка) тоже 3 кадра, в каждом свое состояние. Из рисунка выше должно быть понятно.
  6. Не сильно доверяя функции Math.random(), я ввел переменные pos и neg (позитив и негатив), которые показывают, сколько подряд вылетело бутылок или пачек с соком. Сейчас может вылететь максимум 5 бутылок подряд, потом обязательно сок. Полный код теперь такой:
    lev = 0;
    gravity = 1;
    pos = 0;
    neg = 0;
    function placeTarget() {
    	lev++;
    	var d = target.duplicateMovieClip("t" + lev, lev);
    	d.speedY = -15 - Math.random() * 5;
    	d.speedX = Math.random() * 4;
    	d.rotSpeed = (Math.random() - .5) * 20;
    	d._x = box._x + Math.random() * box._width;
    	if (Math.random() < .5) {
    		d.speedX = -d.speedX;
    	}
    	if ((Math.random() < .5 && pos < 1) || neg >= 5) {
    		d.gotoAndStop(1);//пакет с соком
    		pos++;
    		neg = 0;
    	} else {
    		d.gotoAndStop(2);//бутылка
    		var t = Math.random();//дополнительно случайно определяем тип бутылки
    		if(t < .33) {
    			d.obj.gotoAndStop(1);
    		} else if(t < .66) {
    			d.obj.gotoAndStop(2);
    		} else{
    			d.obj.gotoAndStop(3);
    		}
    		neg++;
    		pos = 0;
    	}
    	d.onEnterFrame = function() {
    		this.speedY += gravity;
    		this._y += this.speedY;
    		this._x += this.speedX;
    		this._rotation += this.rotSpeed;
    		if (this._y > box._y) {
    			this.removeMovieClip();
    		}
    	};
    }
    count = 0;
    onEnterFrame = function () {
    	if (count++ > 15) {
    		count = 0;
    		placeTarget();
    	}
    };
  7. Рисуем прицел - символ cursor. Внутри символа анимация выстрела. В первом кадре:
    stop();
  8. Рисуем взрыв - символ crash. Его можно нарисовать руками, а можно использовать программный вариант. Я использую комбинированный - жидкость прорисована покадрово руками, а осколки стекла дублируются и разлетаются программно. Символ crash будет общим для всех. Все отличия будут уже внутри него. Если для разного отображения бутылок я использовал прямое назначение, то здесь символ сам определяет каким ему быть. Для этого (дальше при создании взрыва) ему будет назначаться переменная type. А потом все внутренние символы (всплеск и очки) будут при появлении считывать эту переменную с родителя и переводить себя в нужный кадр (что-то типа: gotoAndStop(_parent.type)). Подробнее и нагляднее об этом можно почитать здесь (раздел “Полезности”, слайд 25-й). Главный плюс такого подхода - символам не обязательно быть в первом кадре чтобы самоопределиться - они могут появиться со второго кадра и более.
  9. Собираем все вместе. Добавилась переменная для хранения очков.
    Итого, имеем символ с бутылками (target), символ с прицелом (cursor), символ взрыва (crash), символ - полоску (box). Все объекты после дублирования помещаются в стек (массив all). По клику перебираем их и проверяем на пересечение с курсором. Если есть попадание, определяем тип объекта, создаем взрыв (сообщаем ему этот тип), добавляем очки, проверяем на выигрыш и удаляем объект из стека. Если объект улетает вниз экрана, он тоже удаляет себя из стека (функция removeObj()).
    Код в полном объеме теперь выглядит так:

    score = 0;
    all = [];//тут хранятся все летающие объекты
    lev = 0;
    gravity = 1;
    pos = 0;
    neg = 0;
    count = 0;
    crash._visible = false;
     
    cursor.swapDepths(12002432);//прицел выше всех бутылок
    Mouse.hide();
     
    function placeTarget() {
    	lev++;
    	var d = target.duplicateMovieClip("t" + lev, lev);
    	d.speedY = -15 - Math.random() * 5;
    	d.speedX = Math.random() * 4;
    	d.rotSpeed = (Math.random() - .5) * 20;
    	d._x = box._x + Math.random() * box._width;
    	if (Math.random() < .5) {
    		d.speedX = -d.speedX;
    	}
    	if ((Math.random() < .5 && pos < 1) || neg >= 5) {
    		d.gotoAndStop(1);
    		pos++;
    		neg = 0;
    	} else {
    		d.gotoAndStop(2);
    		var t = Math.random();
    		if(t < .33) {
    			d.obj.gotoAndStop(1);
    		} else if(t < .66) {
    			d.obj.gotoAndStop(2);
    		} else{
    			d.obj.gotoAndStop(3);
    		}
    		neg++;
    		pos = 0;
    	}
    	d.onEnterFrame = function() {
    		this.speedY += gravity;
    		this._y += this.speedY;
    		this._x += this.speedX;
    		this._rotation += this.rotSpeed;
    		if (this._y > box._y) {
    			removeObj(this);
    			this.removeMovieClip();
    		}
    	};
    	all.push(d);
    }
    function removeObj(obj){
    	var i = all.length;
    	while(i--) {
    		if(all[i] == obj) {
    			all.splice(i, 1);
    		}
    	}
    }
    function placeCrash(x, y, _t) {
    	lev++;
    	var d = crash.duplicateMovieClip("c" + lev, lev);
    	d.type = _t;
    	d._x = x;
    	d._y = y;
    }
    onEnterFrame = function () {
    	if (count++ > 15) {
    		count = 0;
    		placeTarget();
    	}
    	cursor._x = _xmouse;
    	cursor._y = _ymouse;
    };
     
    onMouseDown = function(){
    	cursor.play();//анимация выстрела
    	var i = all.length;
    	while(i--) {
    		var curT = all[i];
    		if(curT.hitTest(_root._xmouse, _root._ymouse, true)) {
    			if(curT._currentframe == 1) {
    				var type = 1;
    			} else{
    				var type = curT.obj._currentframe + 1;
    			}
    			placeCrash(curT._x, curT._y, type);
    			if(curT._currentframe == 2) {
    				score += 20;
    				if(score >= 100) {
    					trace("Вы победили");
    				}
    			}else {
    				score -= 25;
    				score = (score < 0)? 0 : score;
    			}
    			curT.removeMovieClip();
    			all.splice(i, 1);
    		}
    	}
    }
  10. Осталось добавить приятный фон и текстовое поле, которое будет следить (или назначать напрямую) за переменной score.

Тема с бутылками конечно не единственная, стрелять можно по чему угодно: по яблокам, летающим тарелкам, мячикам жонглера. Можно довести идею до абсурда. Например, черепахи, летающие на воздушных шариках - стреляем по шарикам и слоган - “Рожденный ползать - летать не должен!”.

Интересно на 50%

(52) Хитрых на тему «Игровой баннер типа “Шутер”»

  1. Hyzhak

    забыл еще добавить — по завершению игры обнулять очки. А то после 100 очков, каждый следующий выстрел по бухлу — МОЛОДЕЦ. Видать это зависимость, пристрастился и нужно совсем немного =).

  2. Яски

    Это не суть важно, но более точно координата при ускоренном движении меняется не линейно по времени, а по формуле - x += speedx * time + accel * time * time * 0.5, где speedx это скорость в предудыщей координате, а “accel * time * time * 0.5″ это путь пройденный точкой под влиянием ускорения.

  3. Hyzhak

    нелинейно меняется не x, а y – и автор правильно все считает, – вместо 1ого уравнения пишет 2, и получается численное интегрирование, в данных условиях весьма приемлемое — хотя ваша формула все же более точная (и как раз работает при постоянном ускорении — наш случай).

  4. ded pb|xto

    Что то вы палку перегибаете - смотрите проще, выглядит натурально? натурально, а по какой формуле это высчитано - неважно, главное результат! :) Зритель смотрит не код программы, а то как это выглядит на экране! :)

  5. unodj

    Прикольно :)
    А главное, как это просто выглядит со стороны ;)
    Может показаться, что подготовка клипа с примерами заняла больше времени, чем изгоовление баннера :)

    ps
    хотел спросить про такую ситуацию, может быть тоже есть какая то хитрость :)
    Есть изображение ветки дерева, довольно детальное, т.е. веточки-листики нарисованы отчетливо
    Как проще всего анимировать появление “дерева” из-за горизонта и “вырастание” листиков на веточке? :)
    В моем случае, переданный мне дизайнером исходник представляет из себя всего несколько слоев, т.е. для анимации каждого листика надо резать картинку или все-таки есть хитрость? :)
    Вот картинка слоев имеющегося исходника: http://s42.radikal.ru/i098/0808/80/176b8dd649d4.jpg

  6. zlodey

    спасибо за доходчивую информацию, не мог ты объяснить как ты сделал появление красной плашки со словом “молодец”, програмно или анимировал?

  7. Markis

    Достаточно креативненько. Может пригодиться

  8. Stormit

    to Hyzhak
    Да, забыл сброс сделать. Он так же как и здесь реализован: http://xitri.com/2008/04/28/loop-background3-game-banner.html (шаг 12, 13)
    to unodj
    Наверное проще всего анимировать маску - шейпом или покадрово
    to zlodey
    Плашка появляется шейп-твиннингом. Сделал захлест краев для пущей эффектности.

  9. Макс

    Тема на самом деле оч интересная, подумать есть о чем, но подход сложный, попроще никак низя? для простго блогера это архи сложно.

  10. Stormit

    Конечно можно.
    Можно сделать анимацией как подскакивает и крутится бутылка (все в одном символе). Потом сделать несколько копий и проверять все по клику на hitTest c координатами мыши (или вообще бутылки кнопками сделать). И проще всего открывать ссылку по первому удачному попаданию.

  11. Михаил

    Думаю такой вид баннеров может стать новой тенденцией в интернет-рекламе

  12. Hyzhak

    to Макс: ну тут вроде, не просто блогеры — тут флешеры.

  13. unodj

    to Hyzhak: тогда уж не просто флешеры, а флешеры-аниматоры… и сочувствующие :D

    Михаил, сегодня заметил рекламу одного сайта знакомств, уже эксплуатируют :)
    Правда сюжета никакого, тупо падают рандомные фотографии людей, вместо курсора мышки прицел и надпись “поймай свой идеал” или что то в этом роде :)

  14. Андрей

    ну про гравитацию я думаю многие слышали еще со школы

  15. Destroyer

    Stormit, ты же сам писал что “водка - вредно”, а в этом варианте все совсем наоборот =)
    Очки “+” за спиртное, а “-” за сок =)

  16. Stormit

    Все правильно
    “+” за уничтожение спиртного ;)

  17. Nicholass

    На самом деле настолько забавная штука, что каждый раз у Дизайнфрика её прохожу))

  18. Васек

    Блин, а я чет тупил… Хорошо, что все доходчиво расписано, как раз для меня)))

  19. yalta

    спасибо прикольно я попробую создать када получится или нет отпишуся! спс За инфу!!!

  20. Романыч

    […] автор сайта преподносит интересную информацию на следующие темы […]

  21. aleksey

    Уважуха за составление и постинг таких материалов. Я Вас очень поддерживаю за эти материалы. Кул

  22. Mba

    Я вот не дружу с флешем, но наш дезингер попробует повторить этот эксперимент;) Спасибо

  23. М3

    Классный банер)

  24. Klen

    Отличный материал и банер, спасибо!)

  25. Анапский Бомж

    Флеш баннеры скоро потеснят анимацию и т.п., единственный минус - многие пользователи имеют слабый инет в настоящее время, хотя это не важно

  26. асу тп

    Норм игра, тока быстро надоедает. Это на каком языке программный код?

  27. Мари

    Прикольно…А вообще у Вас очень хороший блог, информация всегда новая и интересная, это очень привлекает. Приглашаю пообщаться на форум с Вашими любимыми женщинами:)

  28. Stasan

    Ух-ты, какой классный сайт. И урок интересный похоже на шапку сайта www.rangers.ru

  29. Aliska

    Интересно и позновательно, а будет еще что-то по этой теме?

  30. KUSAKA

    Блог сдулся? Жаль…

  31. Димулька

    Вернись, солнышко, мы тебя любим.

  32. Валерий

    Добавил в закладки. Теперь буду почаще читать!

  33. Kalinka

    Chital pro yeto uzhe na kakom to drugom sajte, no u vas gorazdo prikolmznej napisano ;)

  34. Ixifeus

    Кажись блог накрылся медным тазом и автор на него забил - уже месяц никакой активности, или же с автором что то случилось,не дай бог конечно. Будем надеятся ,что это не так.

  35. Stormit

    Да все нормально.
    Просто отпуск и новая игра забирают все время

  36. Katrinka

    Отличная статья.Респект автору.

  37. abrizeno86

    Добавил в Закладки, очень интересный блог, таких бы по больше…

  38. mif2000

    Этот сайт еще жив?

  39. starpom

    блог интересный

  40. nunovich

    Сколько полезного нашел для себя на блоге

  41. jombo

    Народ очень интересный блог согласен с вами совсеми

  42. Shoker

    Я новичок и мало что понимаю.Хочу узнать: куда вставлять код, и если делаю flash-игру
    на Macromedia Flash 8

  43. Никита

    Делаи и все получиться, почитаи литературу.

  44. Алексей

    Как привязать размер объекта к размеру окна во FLASH, т.е. чтобы увеличивая размер окна (разворачивая или сужая) соответственно увеличивалось изображение?

  45. Vlas115

    балин, у меня функция с выпрыгиванием не работает,. Запускается без ошибок, но бутылка просто стоит, пробую задать анимацию ни вращения, ни падения… Подскажите как это исправить.

  46. Hyzhak

    некто-то пошел дальше, и сделал шутер на двоих:

    http://www.newgrounds.com/portal/view/514433

  47. Stormit

    Было бы ещё круче, если бы противник был реальный

  48. Soft

    Добрый день. Выложите пожалуйста исходник. (просто не могу разобраться)

  49. Melvin

    А можно исходник посмотреть? Что то не очень выходит… (

  50. Дикий

    Привет всем. Я всё создал, всё прелесть балгодарю админа… Я хотел бы спросить а как зделать так что бы эта игра была с меню, и мела несколько уровней? Плиз подскажите!

  51. Melvin

    Еще раз привет. Тоже все получилось, но немного другая версия. Вот там можно и меню и несколько уровней и т.д. Вот если бы уроки можно было пользователям писать как на демиарте было бы круто!

  52. Melvin

    Кто тут Одмин? Давайте сделаем уроки… какой нить минифорум? Только по флешу!

Оставить комментарий