Впервые я написал тетрис больше года назад, а js я изучил совсем недавно.
Чтобы укрепить мое понимание JS и добавить любви к играм, я написал тетрис на основе Canvas, используя самый простой код JS, не обращаясь к идеям и кодам других людей.
Во время летних каникул на первом курсе я использовал синтаксис es6, чтобы улучшить его, включая синтаксический сахар классов, стрелочные функции и т. д., чтобы еще больше улучшить свое понимание es6. В коде более 400 строк.
Если вы хотите создать эту маленькую игру, вы должны сначала ознакомиться с канвой H5, обработкой массивов js, мониторингом и обработкой событий клавиатуры, использованием таймера и т. д. Остальное — базовая логическая обработка.
Правила игры — это ядро и главный приоритет нашего кода.
Основная логика здесь заключается в том, чтобы определить, сталкивается ли блок (движущийся в данный момент блок сталкивается с уже позиционированным блоком, так что движущийся в данный момент блок не может двигаться вниз, поскольку наш блок по умолчанию движется вниз. Если он не может двигаться вниз, считается, что он движется вниз. как блок, который был позиционирован, а затем генерируется новый блок, который продолжает двигаться вниз от исходного положения).
И это столкновение также необходимо применять, когда блок деформируется. Аналогично, если блок сталкивается с другими расположенными блоками в процессе деформации, мы должны предотвратить успешную деформацию блока.
Код прилагается, обсуждения и исправления приветствуются.
<!DOCTYPE html><html lang=en><head> <meta charset=UTF-8> <title>es6-Реконструкция тетриса (на основе холста)</title> <style type=text/css> #tetris{ поле: 10 пикселей 250 пикселей;} </style></head><body> <canvas width=700 height=525 id=tetris></canvas> <div id=text style='color: red;font-size: 30px;'>Текущая оценка: 0</div> <script type=text/javascript> /** * [Полный дизайн класса Тетриса от Magic_xiang] * @param {число} сторона [длина каждой стороны квадрата (пиксели), по умолчанию 35] * @param {число} ширина [количество квадратов в одной строке (число), по умолчанию 20] * @param {число} высота [Количество блоков, включенных в столбец (по умолчанию 15)] * @param {number} скорость [Скорость падения блока (мс), по умолчанию 400] */ class tetris{constructor(side=35, width=20, height=15) , Speed=400){ this.side = Side // Длина стороны каждого блока this.width = ширина // Количество блоков, содержащихся в строке this.height = высота // Количество блоков, содержащихся в столбце this .speed = скорость // Скорость падения блока this.num_blcok // Числовая переменная текущего типа блока this.type_color // Строковая переменная текущего типа цвета this.ident // Идентификатор setInterval this.direction = 1 // Значение направление блока, инициализируется 1, по умолчанию Статус this.grade = 0 // Используется для подсчета очков this.over = false // Окончена ли игра this.arr_bX = [] // Сохраняем координату X текущего блока this.arr_bY = [] // Сохраняем координату Y текущего блока this.arr_store_X = [] // Сохраняем координату X всех блоков, достигших нижнего уровня this.arr_store_Y = [] // Сохраняем координату Y всех блоков, достигших нижнего уровня this.arr_store_Y = [] // Сохраняем координату Y всех блоков, достигших нижнего уровня this. arr_store_color = [] // Сохраняем все блоки, дошедшие до дна. Цвет квадрата this.paints = document.getElementById('tetris').getContext('2d') //Получаем кисть self = this } // Инкапсулируйте метод рисования, чтобы сделать код более кратким. ) } // Игра запускается gameStart(){ this.init() this.run() } // Работа по инициализации init(){ this.initBackground() this.initBlock() } // Блок автоматически падает run(){ this.ident = setInterval(self.down_speed_up(), this.speed) } // Инициализируем карту initBackground(){ this.paints.beginPath() this.paints.fillStyle='#000000 ' //Цвет заливки карты черный for(let i = 0; i < this.height; i++){ for(let j = 0; j < this.width; j++){ this.paintfr(j, i) } } this.paints.closePath() } // Инициализируем позицию и цвет блока initBlock(){ this.paints.beginPath() this.createRandom('rColor') // Генерируем строку цвета, this.paints.fillStyle = this.type_color this.createRandom('rBlock') //Создаем номера типов блоков this.arr_bX.forEach((item, index) => { this.paintfr(item, this.arr_bY[index], 0.9) }) this.paints.closePath() } // Используем массив для Блок рисования drawBlock(color){ this.paints.beginPath() this.paints.fillStyle = цвет this.arr_bX.forEach((item, index) => { this.paintfr(item, this.arr_bY[index], 0.9) }) this.paints.closePath() } // Рисуем уже позиционированный блок drawStaticBlock( ){ this.arr_store_X.forEach((элемент, индекс) => { this.paints.beginPath() this.paints.fillStyle = this.arr_store_color[index] this.paintfr(item, this.arr_store_Y[index], 0.9) this.paints.closePath() }) } // Генерируем случайное число и возвращаем тип или цвет блока type createRandom( type){ let temp = this.width/2-1 if (type == 'rBlock'){ //Если это тип блока this.num_blcok = Math.round(Math.random()*4+1) switch(this.num_blcok){ case 1: this.arr_bX.push(temp,temp-1,temp, temp+ 1) this.arr_bY.push(0,1,1,1) разрывает случай 2: this.arr_bX.push(temp,temp-1,temp-1,temp+1) this.arr_bY.push(1,0,1,1) прерывает случай 3: this.arr_bX.push(temp,temp-1,temp+1,temp+2) this.arr_bY.push(0,0,0, 0) случай прерывания 4: this.arr_bX.push(temp,temp-1,temp,temp+1) this.arr_bY.push(0,0,1,1) прерывание случая 5: this.arr_bX.push(temp,temp+1,temp,temp+1) this.arr_bY.push(0,0,1,1) Break } } if (type == 'rColor'){ //if Это тип цвета. 2: случай прерывания this.type_color='yellow' 3: случай прерывания this.type_color='#2FE0BF' 4: случай прерывания this.type_color='red' 5: случай прерывания this.type_color='gray' 6: this.type_color ='#C932C6' прерывание случая 7: this.type_color= '#FC751B' прерывание случая 8: this.type_color= '#6E6EDD' Break Case 9: this.type_color= '#F4E9E1' Break } } } // Определяем, сталкиваются ли блоки (нижние) и пересекают ли они нижнюю границу во время деформации JudgeCollision_down(){ for(let i = 0 ; i < this.arr_bX.length; i++){ if (this.arr_bY[i] + 1 == this.height){ //Пересечена ли нижняя граница при деформации return false } if (this.arr_store_X.length != 0) { //Определяем, сталкиваются ли блоки (нижние) for(let j = 0; j < this.arr_store_X.length; j++ ){ if (this.arr_bX[i] == this.arr_store_X[j]) { if (this.arr_bY[i] + 1 == this.arr_store_Y[j]) { return false } } } } } return true } //Оцениваем, сталкиваются ли блоки (слева и справа) и пересекают ли они левую и правую границы во время деформации JudgeCollision_other(num){ for(let i = 0; i < this.arr_bX.length; i++){ if (num == 1) { //Пересекается ли правая граница при деформации if (this.arr_bX[i] == this.width - 1) return false } if (num == -1) { //Пересекается ли левая граница во время деформации if (this.arr_bX[i] == 0) return false } if (this.arr_store_X.length != 0) {//Определяем, сталкиваются ли блоки (слева и справа) for(let j = 0; j < this.arr_store_X.length; j++){ if (this.arr_bY[i] == this.arr_store_Y[j]) { if (this.arr_bX[i] + num == this.arr_store_X[j]) { return false } } } } } return true } //Функция ускорения для down_speed_up( ){ let flag_all_down = true flag_all_down = this.judgeCollision_down() if (flag_all_down) { this.initBackground() for(let i = 0; i < this.arr_bY.length; i++){ this.arr_bY[i] = this.arr_bY[i] + 1 } } else{ for(let i=0; i < this.arr_bX.length; i++){ this.arr_store_X.push(this.arr_bX[i]) this.arr_store_Y.push(this.arr_bY[i]) this.arr_store_color.push(this.type_color) } this.arr_bX.splice(0,this.arr_bX.length) this.arr_bY.splice(0,this.arr_bY. длина) this.initBlock() } this.clearUnderBlock() this.drawBlock(this.type_color) this.drawStaticBlock() this.gameover() } //Клавиша направления — это движение влево function move(dir_temp){ this.initBackground() if (dir_temp == 1) { //Вправо let flag_all_right = true flag_all_right = this.judgeCollision_other(1) if (flag_all_right) { for(let i = 0; i < this.arr_bY.length; i++){ this.arr_bX[i] = this.arr_bX[i]+1 } } } else{ let flag_all_left = true flag_all_left = this.judgeCollision_other(-1) if (flag_all_left) { for(let я=0; я < this.arr_bY.length; я++){ this.arr_bX[i] = this.arr_bX[i]-1 } } } this.drawBlock(this.type_color) this.drawStaticBlock() } //Клавиша направления — это направление преобразования пространства function up_change_direction(num_blcok){ if (num_blcok == 5) { return } let arr_tempX = [] let arr_tempY = [] //Поскольку я не знаю, будет ли преобразование успешным, я сначала сохраняю его for(let i = 0;i < this.arr_bX.length; i++){ arr_tempX.push(this.arr_bX[i]) arr_tempY.push(this.arr_bY[i]) } this.direction++ //Извлекаем координаты центра и деформируем их с помощью текущий центр должен преобладать. let ax_temp = this.arr_bX[0] let ay_temp = this.arr_bY[0] this.arr_bX.splice(0, this.arr_bX.length) //Очистка массива this.arr_bY.splice(0, this.arr_bY.length) if (num_blcok == 1) { switch(this.direction%4){ случай 1: this.arr_bX.push(ax_temp,ax_temp-1,ax_temp,ax_temp+1) this.arr_bY.push(ay_temp,ay_temp+1,ay_temp+1,ay_temp+1) прерывает случай 2: this.arr_bX.push(ax_temp,ax_temp-1,ax_temp,ax_temp) this.arr_bY.push(ay_temp,ay_temp, ay_temp-1,ay_temp+1) нарушает случай 3: this.arr_bX.push(ax_temp,ax_temp-1,ax_temp,ax_temp+1) this.arr_bY.push(ay_temp,ay_temp,ay_temp+1,ay_temp) прерывает регистр 0: this.arr_bX.push(ax_temp,ax_temp,ax_temp, ax_temp+1) this.arr_bY.push(ay_temp,ay_temp-1,ay_temp+1,ay_temp) Break } } if (num_blcok == 2) { switch(this.direction%4){ случай 1: this.arr_bX.push(ax_temp,ax_temp -1,ax_temp-1,ax_temp+1) this.arr_bY.push(ay_temp,ay_temp,ay_temp-1,ay_temp) прерывает случай 2: this.arr_bX.push(ax_temp,ax_temp,ax_temp,ax_temp-1) this.arr_bY.push(ay_temp,ay_temp-1,ay_temp+ 1 ,ay_temp+1) нарушить вариант 3: this.arr_bX.push(ax_temp,ax_temp-1,ax_temp+1,ax_temp+1) this.arr_bY.push(ay_temp,ay_temp,ay_temp,ay_temp+1) прерывает регистр 0: this.arr_bX.push(ax_temp,ax_temp, ax_temp,ax_temp+1) this.arr_bY.push(ay_temp,ay_temp-1,ay_temp+1,ay_temp-1) перерыв } } if (num_blcok == 3) { переключатель(this.direction%4){ случай 1: this.arr_bX.push(ax_temp ,ax_temp-1,ax_temp+1,ax_temp+2) this.arr_bY.push(ay_temp,ay_temp,ay_temp,ay_temp) прерывает случай 2: this.arr_bX.push(ax_temp,ax_temp,ax_temp,ax_temp) this.arr_bY.push(ay_temp,ay_temp-1,ay_temp+1,ay_temp+ 2 ) разбить случай 3: this.arr_bX.push(ax_temp,ax_temp-1,ax_temp+1,ax_temp+2) this.arr_bY.push(ay_temp,ay_temp,ay_temp,ay_temp) прерывает регистр 0: this.arr_bX.push(ax_temp,ax_temp,ax_temp, ax_temp) this.arr_bY.push(ay_temp,ay_temp-1,ay_temp+1,ay_temp+2) Break } } if (num_blcok == 4) { switch(this.direction%4){ case 1: this.arr_bX.push(ax_temp ,ax_temp-1,ax_temp,ax_temp+1) this.arr_bY.push(ay_temp,ay_temp,ay_temp+1,ay_temp+1) прерывает случай 2: this.arr_bX.push(ax_temp,ax_temp,ax_temp+1,ax_temp+1) this.arr_bY.push(ay_temp,ay_temp+ 1) ,ay_temp,ay_temp-1) нарушить вариант 3: this.arr_bX.push(ax_temp,ax_temp,ax_temp-1,ax_temp+1) this.arr_bY.push(ay_temp,ay_temp-1,ay_temp,ay_temp-1) прерывает регистр 0: this.arr_bX.push(ax_temp,ax_temp, ax_temp+1,ax_temp+1) this.arr_bY.push(ay_temp,ay_temp-1,ay_temp,ay_temp+1) Break } } if (! (this.judgeCollision_other(-1) && this.judgeCollision_down() && this.judgeCollision_other(1) )) { // Если преобразование не удалось, выполните следующий код this.arr_bX.splice(0, this.arr_bX.length) this.arr_bY.splice(0, this.arr_bY.length) for(let i=0; i< arr_tempX.length; i++){ this.arr_bX.push(arr_tempX[i]) this.arr_bY.push(arr_tempY[i] ]) } } this.drawStaticBlock() } //Когда строка заполнена, очищаем блоки, а координата Y верхнего блока равна +1 ClearUnderBlock(){ //Удалить блоки нижнего уровня let arr_row=[] let line_num if (this.arr_store_X.length != 0) { for(let j = this.height-1; j >= 0; j--) { for (let i = 0; i < this.arr_store_color.length; i++){ if (this.arr_store_Y[i] == j) { arr_row.push(i) } } if (arr_row.length == this.width) { line_num = j Break }else { arr_row.splice(0, arr_row.length) } } } if (arr_row.length == this.width ) { //Рассчитать оценку this.grade++ document.getElementById('text').innerHTML = 'Текущая оценка:'+this.grade for(let i = 0; i < arr_row.length; i++){ this.arr_store_X.splice(arr_row[i]-i, 1) this.arr_store_Y.splice(arr_row[i]-i, 1) this.arr_store_color. splice(arr_row[i]-i, 1) } //Пусть верхний блок опустится на один пробел for(let i = 0; i < this.arr_store_color.length; i++){ if (this.arr_store_Y[i] < line_num) { this.arr_store_Y[i] = this.arr_store_Y[i]+1 } } } //Оцениваем конец игры gameover() { for (let i=0; i < this.arr_store_X.length; i++){ if (this.arr_store_Y[i] == 0) {clearInterval(this.ident) this.over = true } } } } let tetrisObj = new tetris() tetrisObj.gameStart() //Функция клавиши направления document.onkeydown = (e) => { if (tetrisObj.over) return switch(e.keyCode){ case 40: // Направление вниз tetrisObj.down_speed_up() Break case 32: // Пространство для изменения направления tetrisObj.initBackground() // Перерисовываем карту tetrisObj.up_change_direction(tetrisObj.num_blcok) tetrisObj.drawBlock(tetrisObj.type_color) break case 37: // Направление слева tetrisObj.initBackground() tetrisObj .переместить (-1) tetrisObj.drawBlock(tetrisObj.type_color)break case 39: // Направление правильное tetrisObj.initBackground() tetrisObj.move(1) tetrisObj.drawBlock(tetrisObj.type_color) Break } } </script></body></ html >
Выше приведено все содержание этой статьи. Я надеюсь, что она будет полезна для изучения всеми. Я также надеюсь, что все поддержат сеть VeVb Wulin.