Уроки Flash: Metro Siberia Undeground (Часть 5)

Источник: demiart
Emanuele Ferontano (Перевод: Stasan)

Это заключительная часть туториала, по созданию игры MSU, она будет посвящена созданию дополнительных возможностей отсутствующих в оригинальной версии игры. В принципе всегда когда пишите клон игры, надо добавлять различные особенности иначе ваша игра не привлечет никакого внимания. Моя идея заключается в том, чтобы добавить в игру оружие. Вы можете сказать, что оригинальностью она не блещет, и в Интернете полно уроков по созданию стреляющих космических кораблей. Однако, просьба не забывать, что MSU это игра в которой используется лишь одна кнопка, и эта кнопка уже задействована для запуска двигателя. Я хочу сделать так чтобы, оружие работало постоянно, и уничтожало не только камни, но и резервуары с топливом, что заметно усложняет процесс их поднятия, а следовательно и всю игру.
Если вы не читали предыдущие уроки, то перед продолжением рекомендую прочесть их: Часть 1, Часть 2 и Части 3-4.

Ну, поехали. Сперва создадим новый Movie Clip, назовем его beam_spot, врубим linkage, внутри рисуем маленький красный шарик размером 2 на 2 пикселя и выравниваем его по центру.
Возвращаемся в рут на первом кадре пишем следующий код:

CODE

1. import flash.filters.GlowFilter;
2. var ship_filter:GlowFilter = new GlowFilter(0x00ff00, 0.8, 4, 4, 2, 3, false, false);
3. var smoke_filter:GlowFilter = new GlowFilter(0xff0000, 0.8, 4, 4, 2, 3, false, false);
4. var tunnel_filter:GlowFilter = new GlowFilter(0xffff00, 0.8, 4, 4, 2, 3, false, false);
5. var fuel_filter:GlowFilter = new GlowFilter(0x00ffff, 0.8, 4, 4, 2, 3, false, false);
6. var rock_filter:GlowFilter = new GlowFilter(0xffffff, 0.8, 4, 4, 2, 3, false, false);
7. var score_filter:GlowFilter = new GlowFilter(0xff00ff, 0.8, 2, 4, 2, 3, false, false);
8. gravity = 0.1;
9. thrust = 0.25;
10. yspeed = 0;
11. xspeed = 5;
12. distance = 0;
13. smoke_interval = 10000;
14. frames_passed = 0;
15. tunnel_height = 150;
16. fuel_freq = 10;
17. gasoline = 500;
18. rock_freq = 50;
19. engines = false;
20. _root.attachMovie("ship", "ship", _root.getNextHighestDepth(), {_x:150, _y:200});
21. _root.createEmptyMovieClip("beam", _root.getNextHighestDepth());
22. _root.createEmptyMovieClip("fuel_movie", _root.getNextHighestDepth());
23. _root.createEmptyMovieClip("deadly_movie", _root.getNextHighestDepth());
24. _root.attachMovie("score", "score", _root.getNextHighestDepth());
25. _root.attachMovie("beam_spot", "beam_spot", _root.getNextHighestDepth());
26. beam.filters = new Array(smoke_filter);
27. beam_spot.filters = new Array(smoke_filter);
28. ship.filters = new Array(ship_filter);
29. score.filters = new Array(score_filter);
30. ship.onEnterFrame = function() {
31.     score.sc.text = "Distance: "+distance+" - "+"Fuel: "+gasoline;
32.     if ((gasoline>0) and (engines)) {
33.         yspeed -= thrust;
34.         smoke_interval -= 0.25;
35.         gasoline -= 1;
36.     }
37.     if (Math.random()*1000<fuel_freq) {
38.         fuel = fuel_movie.attachMovie("fuel", "fuel"+fuel_movie.getNextHighestDepth(), fuel_movie.getNextHighestDepth(), {_x:510, _y:Math.random()*400+50});
39.         fuel.filters = new Array(fuel_filter);
40.         fuel.onEnterFrame = function() {
41.             this._x -= (xspeed*1.2);
42.             if (this.hitTest(beam_spot)) {
43.                 this._alpha -=5;
44.                 if (this._alpha<0) {
45.                     this.removeMovieClip();
46.                 }
47.             }
48.             dist_x = ship._x+28*Math.cos(angle)-this._x;
49.             dist_y = ship._y+28*Math.sin(angle)-this._y;
50.             dist = Math.sqrt(dist_x*dist_x+dist_y*dist_y);
51.             if (dist<10) {
52.                 gasoline += 100;
53.                 this.removeMovieClip();
54.             }
55.             if (this._x<-10) {
56.                 this.removeMovieClip();
57.             }
58.         };
59.     }
60.     if (Math.random()*1000<rock_freq) {
61.         rock = deadly_movie.attachMovie("rock", "rock"+deadly_movie.getNextHighestDepth(), deadly_movie.getNextHighestDepth(), {_x:510, _y:Math.random()*400+50, _rotation:Math.random()*360});
62.         rock.filters = new Array(rock_filter);
63.         rock.onEnterFrame = function() {
64.             this._x -= xspeed;
65.             if (this.hitTest(beam_spot)) {
66.                 this._alpha -=3;
67.                 if (this._alpha<0) {
68.                     this.removeMovieClip();
69.                 }
70.             }
71.             if (this._x<-10) {
72.                 this.removeMovieClip();
73.             }
74.         };
75.     }
76.     yspeed += gravity;
77.     this._y += yspeed;
78.     angle = Math.atan2(yspeed, xspeed);
79.     this._rotation = angle*180/Math.PI;
80.     beam.clear();
81.     beam.lineStyle(1, 0xffff00, 10+40*Math.random());
82.     beam.moveTo(this._x+30*Math.cos(angle), this._y+30*Math.sin(angle));
83.     for (x=1; x<=250; x++) {
84.         to_x = this._x+(30+x)*Math.cos(angle);
85.         to_y = this._y+(30+x)*Math.sin(angle);
86.         if ((deadly_movie.hitTest(to_x, to_y, true))or(fuel_movie.hitTest(to_x, to_y, true))) {
87.             break;
88.         }
89.     }
90.     beam.lineTo(to_x, to_y);
91.     beam_spot._x = to_x;
92.     beam_spot._y = to_y;
93.     frames_passed++;
94.     distance += xspeed;
95.     if (frames_passed>=smoke_interval) {
96.         sm = _root.attachMovie("smoke", "smoke"+_root.getNextHighestDepth(), _root.getNextHighestDepth(), {_x:this._x-2, _y:this._y});
97.         sm.filters = new Array(smoke_filter);
98.         sm.onEnterFrame = function() {
99.             this._x -= xspeed;
100.             this._width += 0.2;
101.             this._height += 0.2;
102.             this._alpha -= 2;
103.             if (this._alpha<=0) {
104.                 this.removeMovieClip();
105.             }
106.         };
107.         frames_passed = 0;
108.     }
109.     if ((this._y>400) or (this._y<0) or deadly_movie.hitTest(this._x+28*Math.cos(angle), this._y+28*Math.sin(angle), true) or deadly_movie.hitTest(this._x+8*Math.cos(angle+Math.PI/2), this._y+8*Math.sin(angle+Math.PI/2), true) or deadly_movie.hitTest(this._x+8*Math.cos(angle-Math.PI/2), this._y+8*Math.sin(angle-Math.PI/2), true)) {
110.         yspeed = 0;
111.         this._y = 200;
112.         gasoline = 500;
113.         distance = 0;
114.         deadly_movie.removeMovieClip();
115.         fuel_movie.removeMovieClip();
116.         _root.createEmptyMovieClip("fuel_movie", _root.getNextHighestDepth());
117.         _root.createEmptyMovieClip("deadly_movie", _root.getNextHighestDepth());
118.     }
119. };
120. _root.onMouseDown = function() {
121.     engines = true;
122.     smoke_interval = 10;
123. };
124. _root.onMouseUp = function() {
125.     engines = false;
126.     smoke_interval = 100000;
127. };

Пых, впечатляет правда? Давайте приступим к разбору того, что мы тут наворотили, как обычно будут объяснены только новые фрагменты кода.

21. Создаем новый Movie Clip, в котором разместим лазерный луч, это будет простая линия.
25.Аттачим beam_spot, он будет обозначать конец лазерного луча.
26-27.Применяем фильтры к созданным символам, т.к. я хочу, чтобы лазер светился красноватым цветом, то применяю фильтр созданный для дыма.
80. Очищаем Movie Clip с лучом.
81. Для Movie Clip"a с лучом устанавливаем стиль рисования.
82. Рисуем лазерный луч перед кораблем используя тригонометрию.
83. Начало цикла который, будет выполняться 250 раз, т.к. ширина лазерного луча 250 px.
84-85. Используя тригонометрию, я определяю, где будет x-овый по счету пиксель луча при заданном повороте корабля.
86-88. Если х-овый пиксель касается астероида или резервуара с топливом, выходим из цикла for.
90. Рисуем линию лазера по пиксель который дал положительный hitTest, или рисуем луч размером 250 px если такого нет.
91-92. Передвигаем beam_spot на конец лазерного луча.

Что ж теперь мы можем определит когда лазерный луч пересекает астероид или цистерну, но мы не знаем какой точно из символов оказался на пути луча.
Мы можем провести hitTest между шариком на конце лазера и каждым астероидом и резервуаром.

42. hitTest между шариком и цистерной с топливом.
43. Если верно делаем цистерну более прозрачной.
44-46. Если резервуар становится полностью прозрачным, то удаляем его.

65-70. Аналогичные действия для астероидов.

Вот что у нас получилось:


Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=17811