Вот мы и добрались до финальной части урока по созданию игры бродилки Emanuele Feronato . Для тех, кто впервые зашел к нам «на огонек», настоятельно рекомендую ознакомиться с содержанием части 1 и части 2 данного урока. Ну чтож, продолжаем!!!
ПОВЕРХНОСТЬ. На данный момент мы использовали 7 типов поверхности. Пришло время ввести еще несколько. Итак мы добавляем: Движок для игры-бродилки (часть 3) - шипы – поверхность, которая убивает (или наносит повреждения) игрока при попадании на нее - двери – непроходимая поверхность, которая может стать проходимой при условии наличия у игрока ключа - наклонные поверхности - прото наклонные поверхности. Но обращаю Ваше внимание – не делайте невозможных наклонов. На рисунке зеленым цветом показаны возможные типы наклонов, а красным – невозможные. Движок для игры-бродилки (часть 3)
Теперь, для большего реализма, пришло время ввести в нашу игру новых действующих лиц: - монеты - ключи - враги Движок для игры-бродилки (часть 3) МОНЕТЫ Собираем монеты – зарабатываем баллы.
КЛЮЧИ Необходимы для прохождения игроком закрытых дверей
ВРАГИ Ну как же без противника! Каждая игра имеет в наличии множество разнообразных врагов.
С действующими лицами определились, теперь собираем силы для последнего рывка! Итак, код:
Code
var tile_size:Number = 20; var ground_acceleration:Number = 1; var ground_friction:Number = 0.8; var air_acceleration:Number = 0.5; var air_friction:Number = 0.7; var ice_acceleration = 0.15; var ice_friction:Number = 0.95; var treadmill_speed:Number = 2; var max_speed:Number = 3; var xspeed:Number = 0; var yspeed:Number = 0; var falling:Boolean = false; var jumping:Boolean = false; var on_slope:Boolean = false;//наклонная ли текущая поверхность var gravity:Number = 0.5; var jump_speed:Number = 6; var climbing:Boolean = false; var climb_speed:Number = 0.8; var level:Array = new Array(); var enemy:Array = new Array();//матрица для врага var coin:Array = new Array();//матрица для монет var key:Array = new Array();//матрица для ключа level[0] = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; level[1] = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; level[2] = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 6, 1, 0, 0, 0, 0, 1]; level[3] = [1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 1]; level[4] = [1, 0, 1, 2, 2, 1, 0, 4, 4, 8, 3, 3, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 1]; level[5] = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 0, 0, 0, 0, 0, 1]; level[6] = [1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 6, 1, 0, 0, 0, 0, 0, 1]; level[7] = [1, 1, 1, 0, 0, 1, 0, 0, 0, 10, 1, 11, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 1]; level[8] = [1, 1, 1, 1, 0, 9, 0, 0, 10, 1, 1, 1, 11, 0, 7, 0, 0, 6, 0, 0, 0, 0, 7, 0, 1]; level[9] = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 4, 4, 1, 8, 1, 8, 1]; var walkable_tiles:Array = Array(0, 5, 6, 7, 10, 11);//отдельно определяем типы поверхностей сквозь которые может двигаться игрок var player:Array = [10, 6]; enemy[0] = [10, 3, -2];//позиция для первого врага, первые 2 элемента - координаты х и у, третий элемент - скорость движения enemy[1] = [3, 3, -2];//позиция для второго врага, первые 2 элемента - координаты х и у, третий элемент - скорость движения coin[0] = [2, 2];//позиция первой монеты, х и у coin[1] = [23, 4];//позиция второй монеты, х и у key[0] = [1, 5, 5, 8];//позиция ключа, х и у и позиция двери х и у //==========смерть игрока========================= function place_player() {//удаляем игрока с карты и аттачим его вновь в начальных координатах level_container.hero.removeMovieClip(); x_pos = player[0]*tile_size+tile_size/2; y_pos = player[1]*tile_size+tile_size/2+1; level_container.attachMovie("hero","hero",_root.level_container.getNextHighestDepth(),{_x:x_pos, _y:y_pos}); } //======создаем карту уровня========== function create_level(l) { _root.createEmptyMovieClip("level_container",1); level_height = l.length; level_width = l[0].length; for (y=0; y<level_height; y++) { for (x=0; x<level_width; x++) { if (l[y][x] != 0) { t = level_container.attachMovie("tile", "t"+y+"_"+x, _root.level_container.getNextHighestDepth(), {_x:x*tile_size, _y:y*tile_size}); t.gotoAndStop(l[y][x]); } } } place_player(); for (x=0; x<coin.length; x++) {//размещаем монеты на карте coin_mc = level_container.attachMovie("coin", "coin_"+_root.level_container.getNextHighestDepth(), _root.level_container.getNextHighestDepth(), {_x:coin[x][0]*tile_size+tile_size/2, _y:coin[x][1]*tile_size+tile_size/2+1}); coin_mc.onEnterFrame = function() { if (this.hitTest(level_container.hero._x, level_container.hero._y, true)) {//если герой пересекается с монетой она удаляется (сюда же надо добавить и счетчик баллов) this.removeMovieClip(); } }; } for (x=0; x<key.length; x++) {//размещаем на карте ключи key_mc = level_container.attachMovie("key", "key"+_root.level_container.getNextHighestDepth(), _root.level_container.getNextHighestDepth(), {_x:key[x][0]*tile_size+tile_size/2, _y:key[x][1]*tile_size+tile_size/2+1}); key_mc.ind = x; key_mc.onEnterFrame = function() { if (this.hitTest(level_container.hero._x, level_container.hero._y, true)) {//если герой пересекается с ключем - значение ячейки с дверью в массиве меняется на 0, клип с дверью удаляется с карты, ключ также удаляется open_x = [key[this.ind][2]]; open_y = [key[this.ind][3]]; level[open_y][open_x] = 0; _root.level_container["t"+open_y+"_"+open_x].removeMovieClip(); this.removeMovieClip(); } }; } for (x=0; x<enemy.length; x++) {//размещаем врагов на карте foe = level_container.attachMovie("patrol", "patrol_"+_root.level_container.getNextHighestDepth(), _root.level_container.getNextHighestDepth(), {_x:enemy[x][0]*tile_size+tile_size/2, _y:enemy[x][1]*tile_size+tile_size/2+1}); foe.speed = enemy[x][2]; foe.onEnterFrame = function() {//позиционируем врагов на карте (аналогично функции function get_edges() для игрока) и задаем математику движения this.x_pos = this._x; this.y_pos = this._y; this.x_pos += this.speed; this.left_foot_x = Math.floor((this.x_pos-6)/tile_size); this.right_foot_x = Math.floor((this.x_pos+5)/tile_size); this.foot_y = Math.floor((this.y_pos+9)/tile_size); this.bottom = Math.floor((this.y_pos+8)/tile_size); this.left_foot = level[this.foot_y][this.left_foot_x]; this.right_foot = level[this.foot_y][this.right_foot_x]; this.left = level[this.bottom][this.left_foot_x]; this.right = level[this.bottom][this.right_foot_x]; if (this.left_foot != 0 and this.right_foot != 0 and this.left == 0 and this.right == 0) { this._x = this.x_pos; } else { this.speed *= -1; } }; } } create_level(level); //======определяем варианты движения героя по разным типам поверхности=============== function ground_under_feet() { bonus_speed = 0; left_foot_x = Math.floor((x_pos-6)/tile_size); right_foot_x = Math.floor((x_pos+5)/tile_size); foot_y = Math.floor((y_pos+9)/tile_size); left_foot = level[foot_y][left_foot_x]; right_foot = level[foot_y][right_foot_x]; if (left_foot != 0) { current_tile = left_foot; } else { current_tile = right_foot; } switch (current_tile) {//если значение текущей поверхности …. case 0 : over = "air"; speed = air_acceleration; friction = air_friction; falling = true; break; case 1 : over = "ground"; speed = ground_acceleration; friction = ground_friction; break; case 2 : over = "ice"; speed = ice_acceleration; friction = ice_friction; break; case 3 : over = "treadmill"; speed = ground_acceleration; friction = ground_friction; bonus_speed = -treadmill_speed; break; case 4 : over = "treadmill"; speed = ground_acceleration; friction = ground_friction; bonus_speed = treadmill_speed; break; case 5 : over = "cloud"; speed = ground_acceleration; friction = ground_friction; break; case 6 : over = "ladder"; speed = ground_acceleration; friction = ground_friction; break; case 7 : over = "trampoline"; speed = ground_acceleration; friction = ground_friction; break; case 8 ://...равно 1, то "под ногами" игрока "шипы" over = "spikes"; if (left_foot == 8 and right_foot == 8) {//если игрок обоими ногами находится на этой поверхностью он умирает place_player(); } default ://для прочих значений поверхности задаем скорость движения и скольжения over = "ground"; speed = ground_acceleration; friction = ground_friction; break; } } //=======позиционируем игрока=============== function get_edges() { right = Math.floor((x_pos+5)/tile_size); left = Math.floor((x_pos-6)/tile_size); bottom = Math.floor((y_pos+8)/tile_size); top = Math.floor((y_pos-9)/tile_size); top_right = level[top][right]; top_left = level[top][left]; bottom_left = level[bottom][left]; bottom_right = level[bottom][right]; } //====проверка поверхности на возможность идти сквозь нее================= function is_walkable(tile) { walkable = false;//движение сквозь - запрещено if (!on_slope) {//если тип поверхности не наклоная, то…. for (x=0; x<walkable_tiles.length; x++) { if (tile == walkable_tiles[x]) {//проверяем есть ли данная поверхность в массиве поверхностей, через которые возможно движение, если да, то движение разрешено walkable = true; break; } } } else {//если наклонная поверхность, то движение разрешено walkable = true; } return (walkable); } //========движение по наклонным поверхностям============== function is_on_slope() { on_slope = false;//по умолчанию поверхность не наклонна x_slope_detector = Math.floor(x_pos/tile_size);//определяем позицию ячейки по позиции игрока y_slope_detector = Math.floor(y_pos/tile_size);//определяем позицию ячейки по позиции игрока if (jumping or falling) {//если игрок в прыжке или падении if (level[y_slope_detector][x_slope_detector] == 10 or level[y_slope_detector][x_slope_detector] == 11) {//если тут - "наклонная поверхность" то в зависимости от ее типа определяем х позицию склона if (level[y_slope_detector][x_slope_detector] == 10) { x_offset = tile_size-x_pos%tile_size; } if (level[y_slope_detector][x_slope_detector] == 11) { x_offset = x_pos%tile_size; } if (y_pos>Math.floor(y_pos/tile_size)*tile_size-9+x_offset) { // здесь возможен дополнительный код для усложнения повторного прыжка } } } if (!jumping and !falling) {//если игрок не в прыжке и не в падении, то в зависимости от типа наклонной поверхности изменяем положение игрока по вертикали if (level[y_slope_detector+1][x_slope_detector] == 10 or level[y_slope_detector+1][x_slope_detector] == 11) { y_pos = (y_slope_detector+1)*tile_size+tile_size/2+1; y_slope_detector += 1; } if (level[y_slope_detector][x_slope_detector] == 10 or level[y_slope_detector][x_slope_detector] == 11) { if (level[y_slope_detector][x_slope_detector] == 10) { x_offset = tile_size-x_pos%tile_size; } if (level[y_slope_detector][x_slope_detector] == 11) { x_offset = x_pos%tile_size; } y_pos = Math.floor(y_pos/tile_size)*tile_size-9+x_offset; on_slope = true; } } if (!jumping and !falling and !on_slope and over != "ladder") {//если игрок не прыгает, не падает, не находится на наклонной поверхности и не на лестнице определяем его положение по вертикали. y_pos = (y_slope_detector)*tile_size+tile_size/2+1; } } //========столкновение с препятствиями==================== function check_collisions() { //====столкновения при движении по вертикали=============== get_edges(); is_on_slope();//движение по наклонным поверхностям y_pos += yspeed; get_edges(); if (yspeed>0 and !on_slope) {//код идентичен коду урока 2 лишь добавленна проверка на наклонность поверхности if ((bottom_right != 0 and bottom_right != 6 and bottom_right != 10 and bottom_right != 11) or (bottom_left != 0 and bottom_left != 6 and bottom_left != 10 and bottom_left != 11)) { if (bottom_right != 5 and bottom_left != 5) { if ((bottom_right == 7 or bottom_left == 7) and (Math.abs(yspeed)>1)) { yspeed = yspeed*-1; jumping = true; falling = true; } else { y_pos = bottom*tile_size-9; yspeed = 0; falling = false; jumping = false; } } else { if (prev_bottom<bottom) { y_pos = bottom*tile_size-9; yspeed = 0; falling = false; jumping = false; } } } } if (yspeed<0) { if ((top_right != 0 and top_right != 5 and top_right != 6) or (top_left != 0 and top_left != 5 and top_left != 6)) { y_pos = bottom*tile_size+9; yspeed = 0; falling = false; jumping = false; } } //====столкновения при движении по горизонтали=============== x_pos += xspeed; get_edges(); if (xspeed<0) { // во второй части урока данная строка выглядела так - "if ((top_left != 0 and top_left != 5 and top_left != 6 and top_left != 7) or (bottom_left != 0 and bottom_left != 5 and bottom_left != 6 and bottom_left != 7))" теперь, оптимизировав код и выделив отдельно типы поверхности, сквозь которые можно проходить, мы упрощаем запись: if (!is_walkable(top_left) or !is_walkable(bottom_left)) { x_pos = (left+1)*tile_size+6; xspeed = 0; } } if (xspeed>0) { if (!is_walkable(top_right) or !is_walkable(bottom_right)) { x_pos = right*tile_size-6; xspeed = 0; } } prev_bottom = bottom; } //========двигаемся по карте=========== _root.onEnterFrame = function() { ground_under_feet(); walking = false; climbing = false; if (Key.isDown(Key.LEFT)) { xspeed -= speed; walking = true; } if (Key.isDown(Key.RIGHT)) { xspeed += speed; walking = true; } if (Key.isDown(Key.UP)) { get_edges(); if (top_right == 6 or bottom_right == 6 or top_left == 6 or bottom_left == 6) { jumping = false; falling = false; climbing = true; climbdir = -1; } } if (Key.isDown(Key.DOWN)) { get_edges(); if ((over == "ladder") or (top_right == 6 or bottom_right == 6 or top_left == 6 or bottom_left == 6)) { jumping = false; falling = false; climbing = true; climbdir = 1; } } if (Key.isDown(Key.SPACE)) { //get_edges(); if (!falling and !jumping) { jumping = true; yspeed = -jump_speed; } } if (!walking) { xspeed *= friction; if (Math.abs(xspeed)<0.5) { xspeed = 0; } } if (xspeed>max_speed) { xspeed = max_speed; } if (xspeed<max_speed*-1) { xspeed = max_speed*-1; } if (falling or jumping) { yspeed += gravity; } if (climbing) { yspeed = climb_speed*climbdir; } if (!falling and !jumping and !climbing) { yspeed = 0; } xspeed += bonus_speed; check_collisions(); level_container.hero._x = x_pos; level_container.hero._y = y_pos; xspeed -= bonus_speed; };
И вот, после долгих стараний, итоговая верстия нашей игры:
Все права принадлежат PainKiller.Net.Ru 2009-2010. Дизайн сайта разработан - PainKiller.Net.Ru
Внимание! Рип шаблона запрещен "Нарушение авторского права"!
Design bY PainKiller.Net.Ru