php开发俄罗斯方块,动手打造html5俄罗斯方块的(图文)

2023-11-15

在正文开始之前还要啰嗦一下,标题中所谓自给自足,是在没有参考任何设计思路的前提下去开发这游戏的,你可能会不解,如果参考优秀的思路,岂不是事半功倍,当然,参考与不参考都有利,我只说不参考的利,当我煞费苦心、历经数十个BUG修改,终于完成一件作品的时候,我可以很自豪地对别人说:“看,我开发的游戏!”当然,创意不是我的,但这并不影响自己那份“虚荣心”,为一款经典的游戏赋予自我的理解,并将它融入游戏中,岂不是一件有意思的事,而且,回过头来再看一看别人的思路,有时会拍案而起,“这个我当初怎么就没想到呢?”,“原来这个问题可以这样解决”,“这个设计思路比我的思路好多了!”,诸如此类总比开始就直接看别人的思路而阻塞自己的思考要强得多,对吧?

好叻,正文开始~

想先看效果的,先跳转试玩一下吧!

俄罗斯方块,主游戏界面应该由一个一个的方块组成,如下图,当然成品里面这些网格是看不到的,这里只是助于理解,主界面尺寸为400×500,设定每块砖(网格)的尺寸为20×20,则每行有20个砖块,每列有25个砖块。相关代码:brickWidth = 20, //砖块大小

width = 400, height = 500; //画布宽高,20X25

a3ac1c38bdbab4b8a3823072743c871c.png

提到主界面的网格,就要提到一个非常重要的变量了,它就是BOARD,一个二维数组,形象化地说其尺寸是20×26,存储的值为0或1,0表示该位置没有砖块,1表示该位置有砖块,在接下来的一些判定中有重要作用,游戏细心的同学可能发现,为什么是20×26,而不是对应主界面网格的20×25,我在一开始的时候也是设定为20×25的,后来注意到如果加一行而且这一行的值都为1就可以很容易判断砖块是否到触及主界面底部了。相关代码:// 初始化BOARD,注意纵向有26个,最后一排用来判断是否触底

for(i=0;i<20;i++){

BOARD[i] = [];

for(j=0;j<26;j++) {

if(j==25) {

BOARD[i][j] = 1

} else {

BOARD[i][j] = 0;

}

}

}

d6bb474b182ba79d35e38128b8569546.png

接下来看由4个砖块组成的“形状”,有五种,为了好描述,我把它们为别命名,Tian(田),Chu(锄头),Tu(凸起来),Thunder(闪电),Line(一横),哈哈有趣的名字,原谅我没找到它们的英文名字吧。

首先定义一个砖头类Brick:function Brick() { }

其下有几个原型变量和方法:Brick.prototype.embattle = null; //砖块的布局(需重载)

Brick.prototype.isOverturn = 0; //是否翻转

Brick.prototype.originX = 9; //砖头的绘制起点X

Brick.prototype.originY = -3; //砖头的绘制起点Y

Brick.prototype.direction = 0; //砖头朝向

Brick.prototype.autoMoveTimer = null; //自动移动计时器

Brick.prototype.draw = function() { …… } //画砖块的方法

Brick.prototype.move = function(moveX, moveY) { …… } //移动的方法

Brick.prototype.autoMove = function() { …… } //自动移动的方法

Brick.prototype.change = function() { …… } //变换砖头朝向

Brick的子类有:Tian,Chu,Tu,Thunder,Line五个,每个子类中都重载Brick的embattle变量,embattle是什么,英译中的意思是布阵,这个阵是个什么阵呢?首先,同学们要理解我的思路,用Tu的embattle来举例,其代码如下:this.embattle = [

[ [0,4,5,8], [1,4,5,6], [1,4,5,9], [0,1,2,5] ], //布局表为4X4表格,数字为砖头位置

[ [0,4,5,8], [1,4,5,6], [1,4,5,9], [0,1,2,5] ] //次行为翻转的情况];

embattle是一个三维数组,第一维是是否翻转isOverturn(形象来说就像图片的水平翻转),第二维是方向direction(上左下右),第三维是形状的4个砖块分布情况,我把每个新形状对象定义在一个4×4的阵中,例如,Tu的this.embattle[0][0]为[0,4,5,8],数字即该砖块的所在位置,如下图:

87e9dd7b3f673dd35498113fb91add28.png

所以要确定一个形状的位置和样子,需要isOverturn确定是否翻转,需要direction确定其方向,需要originX和originY确定“阵”的位置。

接下来,分别解释Brick的4个原型方法。

Brick.prototype.drawctx.fillStyle = 'rgb('+Math.floor(Math.random()*256)+','+Math.floor(Math.random()*256)+',

'+Math.floor(Math.random()*256)+')';

for(i=0;i<4;i++) {

tmp = this.embattle[this.isOverturn][this.direction][i];

ctx.fillRect((this.originX+tmp%4)*brickWidth, (this.originY+Math.floor(tmp/4))*brickWidth, brickWidth, brickWidth);

ctx.strokeRect((this.originX+tmp%4)*brickWidth+1, (this.originY+Math.floor(tmp/4))*brickWidth+1, brickWidth-2, brickWidth-2); //注意+1和减2

}

有上面说的确定形状的位置和样子的方法,之后就是纯粹canvas画图,4个砖块一个一个地画,不要看代码很长其实就是那么一点点,originX、originY和砖块在阵中的位置就可以确定画砖块的起点了。注意到代码的注释了没有,画边框的时候,它是从起点向外面画的,就像我把一个塑料袋套在另一个塑料袋的外面,为了以后的清除的方便且不影响其他的砖块,把边框画进fillRect的领土,就像我现在把这个塑料袋不套在外面而是放进这另一个塑料袋里面一样,就这个意思。

Brick.prototype.move

这是最长的一个了,移动的时候,moveX和moveY表示横纵的增量,没有同时非0的情况(这是人为的设定,要么横向移动要么纵向移动),当然要判断即将移动到的位置是否违规:

横向:

如果阵贴靠主界面左侧则不能向左移即moveX不能为-1

(this.originX==0 && moveX==-1)

判断右边时比较麻烦,因为不能直接用阵来判断是否贴靠右侧(看前面的图就知道阵的右边和下边可能没有砖块的),这时要一个个地判断4个砖块是否有至少有一个在最右,这时不能向右移动|| (this.originX+tmp[0]%4==19 && moveX==1)

|| (this.originX+tmp[1]%4==19 && moveX==1)

|| (this.originX+tmp[2]%4==19 && moveX==1)

|| (this.originX+tmp[3]%4==19 && moveX==1)

最后还要判断即将到达的位置是否已经有砖块了。|| (BOARD[this.originX+tmp[0]%4+moveX][this.originY+Math.floor(tmp[0]/4)]==1)

|| (BOARD[this.originX+tmp[1]%4+moveX][this.originY+Math.floor(tmp[1]/4)]==1)

|| (BOARD[this.originX+tmp[2]%4+moveX][this.originY+Math.floor(tmp[2]/4)]==1)

|| (BOARD[this.originX+tmp[3]%4+moveX][this.originY+Math.floor(tmp[3]/4)]==1)

纵向:

即将到达的位置是否已经有砖块了,注意到下面的代码的&& moveX==0,原来是没有的,后来发现每次砖块怎么刚刚靠上下面堆着的砖块就不能再移动了,原来横向移动的时候也进行了这个判断,即刚刚靠上下面的砖块,如果这时想左右移动,但下方有砖块,但是问题来了,下面有没有砖块跟我左右移动有什么关系呢?是吧。if((as==1 || bs==1 || cs==1 || ds==1) && moveX==0) { …… }

纵向终止判断里面主要做了几件事:清除autoMoveTimer,设置BOARD在该形状当前位置的值为1,有可以消除的整行就消除,加分改分,判断胜利/失败,删除当前对象,召唤下一个形状。

横纵都没违规时:

这时,把该形状前一个位置的砖块清除,更新originX和originY,再画出来。for(i=0;i<4;i++) {

tmp = this.embattle[this.isOverturn][this.direction][i];

ctx.clearRect((this.originX+tmp%4)*brickWidth, (this.originY+Math.floor(tmp/4))*brickWidth, brickWidth, brickWidth);

}

this.originX += moveX;

this.originY += moveY;

this.draw();

Brick.prototype.autoMove

只做一件事,设置计时器,定时向下移动。var status, self = this;this.autoMoveTimer = setInterval(function() {

status = self.move(0,1);

},speed);

Brick.prototype.change

改变形状的朝向,很好办啊,不是有embattle数组了吗?当然没有那么简单,不只是换个数组这么简单。要考虑改变方向之后占用的位置是否已经有砖块了,如果形状是贴着主界面右边界就更糟糕了,比如原来是竖着的Line,改变其方向变为横,占用阵的0、1、2、3,如果Line贴着右边界,originX为19,变为横向,占用阵的0、1、2、3,后面三个砖块已经溢出了主界面。

659a61cb5cc78ac903c7f5c6d60daae9.png

解决方案是:如果有越界的砖块就把阵往左挪一挪,直到不再越界。while(ox+tmp[0]%4 > 19 || ox+tmp[1]%4 > 19 || ox+tmp[2]%4 > 19 || ox+tmp[3]%4 > 19) {

ox -= 1;

}

最后,如果都没事,就可以清除原位置,画出改变方向之后的形状了。

并不是太完美,因为有些卡位的情况没考虑进来,什么是卡位,看下图,你知道Line实例调用change方法的结果是什么了吗?事实上,它不应该成功改变方向的,对吧?还有其他一些卡位的情况。

bcbcd86612d1cd404ba4e87f9c050e1f.png

Brick的4个原型方法就介绍到这里了。现在如果我要在右边的信息界面显示下一个的形状,最直接的方法就是,通过该形状的构造函数实例化一个对象,为防止其自动调用autoMove,为构造函数添加了isModel来判断是不是供提示用的。

还有按键事件监听、NextBrick函数和deleteObj自己看看吧,很容易看懂,游戏的入口就是NextBrick函数。

还有就是,我无法确定deleteObj是否真的成功让GC把对象回收了。

还有就是,我本想增加关卡功能,因为可以自由设置速度(speed变量),就把这功能放一放了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

php开发俄罗斯方块,动手打造html5俄罗斯方块的(图文) 的相关文章

  • matplotlib绘制出光滑曲线

    用matplotlib库绘制光滑的曲线图 注意点 坐标要是用range 表示的话用这个方法拟合平滑曲线会报错 查了别人说的把range 转化成list range 感觉并没有用 所以还是用了穷举法表示的x坐标 import numpy as
  • MOM和MES区别

    对于工业软件 中国的制造业企业并不模式 尤其是在生产排产过程中 MES 制造执行系统 的应用早已普及 不过 SiemensPLM Software DER业务中国区总经理戚锋近日在接受记者采访时表示 MES已经无法跟上时代潮流 MES 的升
  • 机器学习(周志华) 习题 参考答案 第十六章

    周志华老师的 机器学习 的第16章的习题答案较少 网上的参考答案链接分别为答案一和答案二 以下是个人对这章的习题的理解 如有问题 欢迎指正 16 1比较UCB方法与 贪心法和Softmax方法的异同 1 UCB选则值最大的摇臂 是100 选
  • python 词频统计

    python 词频统计 描述 谁动了我的奶酪 是美国作家斯宾塞 约翰逊创作的一个寓言故事 该书首次出版于1998年 书中主要讲述4个 人物 两只小老鼠 嗅嗅 Sniff 匆匆 Scurry 和两个小矮人 哼哼 Hem 唧唧 Haw 找寻奶酪
  • Use gitk to understand git

    https lostechies com joshuaflanagan 2010 09 03 use gitk to understand git
  • 红帽认证-RHCSA

    目录 RHCSA认证考的是 Server A 题目 一 按要求配置网络 二 配置系统使用默认存储库 三 调试SELinux 四 创建用户账户 五 配置cron 作业 六 创建协作目录 七 配置NTP 八 配置 autofs 九 配置 var
  • 牛客网-华为机考-HJ30 字符串合并处里--详细解题思路,并有详细解题代码和注解

    注意 代码和解题思路在后面 HJ30 字符串合并处理 描述 按照指定规则对输入的字符串进行处理 详细描述 第一步 将输入的两个字符串str1和str2进行前后合并 如给定字符串 dec 和字符串 fab 合并后生成的字符串为 decfab
  • 排序之sort排序

    C 的STL里面有个sort函数 可以直接对数组排序 复杂度为n log2 n 使用这个函数 需要包含头文件
  • 【计算机毕业设计】228图书商城网站

    一 系统截图 需要演示视频可以私聊 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术 让传统数据信息的管理升级为软件存储 归纳 集中处理数据信息的管理方式 本图书商城网站就是在这样的大环境下诞生 其可以帮助管理者在短时间内处理完毕庞大
  • ModuleNotFoundError: No module named 'cv2' (安装cv2)

    1 问题 ModuleNotFoundError No module named cv2 Pycharm 中 import cv2 出现错误 2 解决 安装cv2 pip install opencv python 如果只用主模块 使用这个
  • vulnhub靶机Looz

    下载地址 Looz 1 VulnHub 主机发现 arp scan l 端口扫描 nmap min rate 10000 p 192 168 21 155 扫描端口信息 nmap sV sT O p22 80 139 3306 8081 1
  • flask中文学习教程

    2019独角兽企业重金招聘Python工程师标准 gt gt gt http flask123 sinaapp com 转载于 https my oschina net 935572630 blog 371473
  • vue中 关于 同一个 页面 使用搜索功能 数据不更新

    注意 我这里的搜索是在 公共的头部里面如图 我这里点击搜索是跳到搜索页面 并且传参 代码如下 div class search div
  • mipi协议_学习共享——MIPI

    点击上方蓝字 记得关注我们 MIPI名词解释 MIPI Mobile Industry Processor Interface 移动行业处理器接口 是2003年由ARM Nokia ST TI等公司成立的一个联盟发起的为移动应用处理器定制的
  • 3D纹理,立体纹理,三维纹理示例配置

    1 下载freeglut并使用cmake配置 编译安装 https github com FreeGLUTProject freeglut git clone https github com FreeGLUTProject freeglu
  • c++学习——构造函数和析构函数

    构造函数和析构函数 简要概述 构造函数和析构函数的简单调用 构造函数和析构函数能够函数重载 默认的构造函数和析构函数 拷贝构造 构造函数的分类和调用 匿名对象 拷贝构造函数的调用时机 构造函数的调用规则 多个对象的构造函数和析构函数 深浅拷
  • 数组越界访问会发生什么错误?怎样避免该错误?_后缀数组跳坑笔记

    记点写题的时候遇到的坑 可能会更新 多组数据相关 1 h数组需要清空 别的一般不需要 除了倍增算法中为简化代码把上一迭代的rk数组开成两倍的情况 那个场合会有因为字符串长度不同而导致访问到以前填写的不知道什么鬼东西的情况导致rk算错 大概就
  • [790]win环境Maven安装配置

    文章目录 什么是Maven Maven是一个项目管理和整合的工具 Maven为开发者提供了一套完整的构建生命周期框架 开发团队基本不用花多少时间就能自动完成工程的基础构建配置 因为Maven使用了一个标准的目录结构和一个默认的构建生命周期
  • 【UE4】多视角相机捕获图像如何同屏拼接在一起

    前段时间有个Demo移植的需求 需要把实时裸眼3D多视角立体显示的Unity版本移植到UE4 主要包含后处理Shader 相机矩阵变换 多视角画面平铺拼接三大部分 10 10 多视角相机捕获图拼接效果 对现有的多窗口显示方法进行查阅后 发现

随机推荐

  • 不一样的视角,不一样的Kinect for Windows 2.0

    随着科技的发展 智能硬件已经越来越多的出现在我们的生活当中 侦探片中的无线内耳耳机已经变成了蓝牙耳机 而 少数派报告 中手势操作的荧幕界面也已变成现实 对人机交互有很高要求的开发者来讲 于7月正式发售的Kinect for Windows
  • pytorch 线性回归拟合sin函数

    目录 1 库文件 2 定义超参数 3 获取数据集 4 加载训练集 测试集 5 搭建线性网络 6 实例化网络和优化器 7 训练网络 8 可视化 9 结果展示 10 完整代码 1 库文件 os 文件是为了消除matplotlib 绘图的错误 T
  • Yolox_s可视化网络结构图

    Yolox共有七种网络结构 包含2种轻量级网络 和5种标准网络 轻量级网络 1 Yolox Nano可视化网络结构图 点击查看 2 Yolox Tiniy可视化网络结构图 点击查看 标准网络 1 Yolox s可视化网络结构图 点击查看 2
  • Java中对象实例化过程中的多态特性

    通过上述代码 始终明确调用的方法必须是实例化子类中重写的方法 首先 在main函数中 new B new了一个B类的实例化对象 在实例化对象时 调用了B类中的构造函数 执行 super 5 也就是public A int v gt setV
  • 14.应用层HTTP协议

    目录 一 OSI七层协议 vs TCP IP五层协议 二 HTTP协议 URL 1 1URL 中的可省略部分 2 请求消息Request 2 1请求行 2 2请求头 2 3空行 2 4请求数据 2 5HTTP 请求方法 3 响应消息Resp
  • sql developer默认是不自动提交事务的,如何查询未被提交的事务

    select SQL TEXT status from v sql v transaction where LAST ACTIVE TIME START DATE 上面的语句可以查询未被提交的事务 如果你查询或更新时很长时间没反应 一般是另
  • 二分查找BinarySearch

    二分查找 在包含size个元素 从小到大排序的int数组array里查找元素p 如果找到返回下标 如果未找到返回 1 int BinarySearch int array int size int p int left 0 查找区间的左端点
  • 5.7及以上版本的MySQL下载、安装及配置教程

    对版本的说明 之所以说是MySQL5 7及以上版本 是因为从MySQL5 7版本之后 其安全机制有所改变 在安装完成后 登陆MySQL时 需要输入一个密码 这个密码其实是在配置MySQL的过程中生成的一个随机密码 而我们必须找到这个随机密码
  • Eclipse中启动Tomcat无任何反应

    推动了软件业不断发展的可以说有3个方面的东西 过程 方法 技术 方法附会到哲学上应该就是方法论了 做很多事情都是需要方法的 比如写一篇案例 随心随意写也可以写出来 但是别人能否理解 如何检测自己描述清晰都是没有参考的 如果有个模板的 这样按
  • 韩顺平_java 学习路线

    链接 目录 阶段一 Java基础 阶段二 Java高级 阶段三 Java Web 阶段四 主流框架 项目管理相关的技术 阶段五 分布式 微服务 并行架构 阶段六 DevOps 开发运维一体化 自动部署项目管理 解决 CI CD 阶段七 大数
  • 【目标检测】单阶段算法--YOLOv3详解

    论文题目 YOLOv3 An Incremental Improvement 论文地址 https pjreddie com media files papers YOLOv3 pdf 一文读懂YOLOv1 YOLOv1 一文读懂YOLOv
  • 链表(详解)

    一 链表 1 1 什么是链表 1 链表是物理存储单元上非连续的 非顺序的存储结构 数据元素的逻辑顺序是通过链表的指针地址实现 有一系列结点 地址 组成 结点可动态的生成 2 结点包括两个部分 1 存储数据元素的数据域 内存空间 2 存储指向
  • gitee最详细使用教程,汇总了全网,看这一篇就够了

    1 gitee是什么 基于git的代码托管协助平台 2 git网站上的注册登录 打开gitee官网Gitee 基于 Git 的代码托管和研发协作平台打开注册登录即可 邮箱注册最好 非邮箱在个人 设置里添加自己的邮箱 新手请公开自己的邮箱 如
  • 《Vision Transformer (ViT)》论文精度,并解析ViT模型结构以及代码实现

    AN IMAGE IS WORTH 16X16 WORDS TRANSFORMERS FOR IMAGE RECOGNITION AT SCALE 论文共有22页 表格和图像很多 网络模型结构解释的很清楚 并且用四个公式展示了模型的计算过程
  • springboot枚举反序列化,@JsonCreator注解各种报错解决方案

    你多努力一点 获得的打击就多一点 今天使用枚举传参就出现了各种报错 比如这样的 org springframework http converter HttpMessageNotReadableException JSON parse er
  • Android Fragment之间跳转

    1 创建一个接口 public interface ChangeFragment void changge int postion 2 设置一个全局变量 public class GlobalParms private static Hom
  • OpenCV在图片中输出中文乱码解决方案

    转自 http www jeepxie net article 789204 html 一 缘起 在一个项目中需要把中文字符输出到图片上 也就是输出到Mat上 OpenCV 的putText函数不能输出中文 通过搜索 网上普遍的解决方案是使
  • C++不定参数函数实现方式

    文章目录 define 函数定义 VA LIST栈 c 11初始化列表 c 11 变长参数模板template
  • java使用jsch连接ssh服务并远程执行命令、上传、下载操作

    java使用jsch连接ssh服务并远程执行命令 上传 下载操作 关键依赖 jsch 0 1 54 jar 第一 使用用户名和密码连接 使用用户名和密码连接 Test public void test1 throws JSchExcepti
  • php开发俄罗斯方块,动手打造html5俄罗斯方块的(图文)

    在正文开始之前还要啰嗦一下 标题中所谓自给自足 是在没有参考任何设计思路的前提下去开发这游戏的 你可能会不解 如果参考优秀的思路 岂不是事半功倍 当然 参考与不参考都有利 我只说不参考的利 当我煞费苦心 历经数十个BUG修改 终于完成一件作