html5在线俄罗斯方块,Html5原创俄罗斯方块(基于canvas)

第一次写俄罗斯方块的时候已经是1年多前了,也是我刚刚学js不久。

为了加强对js的理解又加上对游戏的爱好,于是在没有参考他人的思路和代码下,自己用最基本的js代码写出了基于canvas的俄罗斯方块。

3b5df38ccb82e94e095c882961db2390.png

在大三的暑假,我又用了es6的语法进行了改进,包含了class的语法糖、箭头函数等,进一步增加自己对es6的理解,代码有400+行

想要做这个小游戏,必须先熟悉H5的canvas,js对数组的处理,键盘事件监听和处理,定时器的使用等,其他的就是基本的逻辑处理了。

游戏的规则就是核心,也是我们代码的重中之重

这里的逻辑核心是需要判断方块是否碰撞(当前运动的方块和已经定位好的方块有碰撞以致于当前的运动的方块不能在向下走,因为我们的方块默认是向下走的,如果不能向下走,是视为已经定位好的方块,然后在生成一个新的方块从初始位置继续往下走)。

而且这个碰撞还需要应用在方块变形的时候,同样地,如果方块在变形的过程中和其他定位好的方块进行碰撞,则我们应该阻止这个方块进行变形成功,

附上代码,欢迎讨论和指正

es6-重构俄罗斯方块(基于canvas)

#tetris{ margin: 10px 250px;}

当前分数:0

/**

* [一个完整的俄罗斯方块类 design by magic_xiang]

* @param {number} side [每个方块边长(px),默认35]

* @param {number} width [一行包含的方块数(个),默认20]

* @param {number} height [一列包含的方块数(个),默认15]

* @param {number} speed [方块下落移动速度(ms),默认400]

*/

class tetris{

constructor(side=35, width=20, height=15, speed=400){

this.side = side // 每个方块边长

this.width = width // 一行包含的方块数

this.height = height // 一列包含的方块数

this.speed = 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_color = [] // 存放到达底部所有方块的颜色

this.paints = document.getElementById('tetris').getContext('2d')

//获取画笔

self = this

}

// 封装paints方法,让代码更简洁

paintfr(x, y, scale=1){

this.paints.fillRect(x*this.side, y*this.side, scale*this.side, scale*this.side)

}

// 游戏开始

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 = color

this.arr_bX.forEach((item, index) => {

this.paintfr(item, this.arr_bY[index], 0.9)

})

this.paints.closePath()

}

// 画已经在定位好的方块

drawStaticBlock(){

this.arr_store_X.forEach((item, index) => {

this.paints.beginPath()

this.paints.fillStyle = this.arr_store_color[index]

this.paintfr(item, this.arr_store_Y[index], 0.9)

this.paints.closePath()

})

}

// 生成随机数返回方块类型或颜色类型

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)

break

case 2:

this.arr_bX.push(temp,temp-1,temp-1,temp+1)

this.arr_bY.push(1,0,1,1)

break

case 3:

this.arr_bX.push(temp,temp-1,temp+1,temp+2)

this.arr_bY.push(0,0,0,0)

break

case 4:

this.arr_bX.push(temp,temp-1,temp,temp+1)

this.arr_bY.push(0,0,1,1)

break

case 5:

this.arr_bX.push(temp,temp+1,temp,temp+1)

this.arr_bY.push(0,0,1,1)

break

}

}

if (type == 'rColor'){ //如果是颜色类型

let num_color = Math.round(Math.random()*8+1)

switch(num_color){

case 1:

this.type_color='#3EF72A'

break

case 2:

this.type_color='yellow'

break

case 3:

this.type_color='#2FE0BF'

break

case 4:

this.type_color='red'

break

case 5:

this.type_color='gray'

break

case 6:

this.type_color='#C932C6'

break

case 7:

this.type_color= '#FC751B'

break

case 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.length)

this.initBlock()

}

this.clearUnderBlock()

this.drawBlock(this.type_color)

this.drawStaticBlock()

this.gameover()

}

//方向键为左右的左移动函数

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 i=0; i < this.arr_bY.length; i++){

this.arr_bX[i] = this.arr_bX[i]-1

}

}

}

this.drawBlock(this.type_color)

this.drawStaticBlock()

}

//方向键为空格的变换方向函数

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){

case 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)

break

case 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)

break

case 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)

break

case 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){

case 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)

break

case 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)

break

case 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)

break

case 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)

break

}

}

if (num_blcok == 3) {

switch(this.direction%4){

case 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)

break

case 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)

break

case 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)

break

case 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)

break

case 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)

break

case 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)

break

case 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) {

//计算成绩grade

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.move(-1)

tetrisObj.drawBlock(tetrisObj.type_color)

break

case 39: // 方向为右

tetrisObj.initBackground()

tetrisObj.move(1)

tetrisObj.drawBlock(tetrisObj.type_color)

break

}

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值