JavaScript的乐趣:创建一个2048的网页版游戏
最编程
2024-08-15 10:16:17
...
/*
2048游戏逻辑
# 变量组
data 存放数据
score 存放分数
1. 绘制界面 4*4 双层 for 计算left top
*/
var data = [];//数据
var score = 0; //分数
var flag = true;
var bgColor = {//不同数字单元格背景颜色
2:'#eee4da',
4:'#ede0c8',
8:'#f2b179',
16:'#f59563',
32:'#f67c5f',
64:'#f65e3b',
128:'#edcf72',
256:'#edcc61',
512:'#9c0',
1024:'#33b5e5',
2048:'#09c',
4096:'#a6c',
8192:'#93c'
}
var fontColor=function(num){//数字颜色
if(num<=4){
return "#776e65";
}
return "#fff";
}
$(function(){
newGame()
})
// 新游戏
function newGame(){
//绘制界面
drawSence();
score =0;
util.updateScore();
util.hightScore();
//随机生成2个数字
getNumber();
getNumber();
flag=true;
}
//绘制界面函数
function drawSence(){
var grid=$('.grid');
grid.empty();
for (var i = 0; i < 4; i++) {
for(var j = 0; j < 4; j++){
$('<div>').attr({
class:'grid-cell',
id:'g'+i+j
}).css({
top:util.pos(i),
left:util.pos(j)
}).appendTo(grid)
}
}
//初始化数据
for(var i=0;i<4;i++){
data[i]=[];
for(var j=0;j<4;j++){
data[i][j]=0;
}
}
//创建number-cell
showdata()
console.log(data)
}
function showdata(){
var grid=$('.grid');
$('.number-cell').remove(); //清除所有number-cell元素
for(var i=0;i<4;i++){
for(var j=0;j<4;j++){
var numberCell = $('<div>');
numberCell.attr({
class:'number-cell',
id:'n'+i+j
}).appendTo(grid);
if(data[i][j]==0){
numberCell.css({
width:0,
height:0,
left:util.pos(j)+50,
top:util.pos(i)+50
})
}else{
numberCell.css({
width:100,
height:100,
left:util.pos(j),
top:util.pos(i)
})
numberCell.css({
backgroundColor:bgColor[data[i][j]],
color:fontColor(data[i][j]),
}).text(data[i][j]);
}
}
}
}
function getNumber(){
if(util.space(data)){
return true;
}
//随机单元格 位置
var x = Math.floor(Math.random()*4);
var y = Math.floor(Math.random()*4);
while(data[x][y]!=0){
x = Math.floor(Math.random()*4);
y = Math.floor(Math.random()*4);
}
//随机数字
var num = Math.random()<0.5?2:4;
data[x][y] = num;
util.showNumber(x,y,num);
console.log(data)
return false;
}
// 监听键盘按键
$(document).keydown(function(e){
if(!flag){return;}
switch(e.keyCode){
case 37:
moveLeft();
break;
case 38:
moveTop();
break;
case 39:
moveRight();
break;
case 40:
moveBottom();
break;
default:
break;
}
})
// 键盘左键
function moveLeft(){
isGameOver();
if(!canMoveLeft()){
return false;
}
for(var i=0;i<4;i++){
for(var j=1;j<4;j++){
if(data[i][j]!=0){
for(var k=0;k<j;k++){
if(data[i][k]==0&&noBlockH(i,k,j,data)){
//move()
util.moveAnimate(i,j,i,k);
data[i][k]=data[i][j];
data[i][j]=0;
continue;
}else if(data[i][k]==data[i][j]&&noBlockH(i,k,j,data)){
//move()
util.moveAnimate(i,j,i,k);
//add
data[i][k]+=data[i][j];
data[i][j]=0;
score+=data[i][k];//增加分数
util.updateScore();//更新分数
continue;
}
}
}
}
}
setTimeout(getNumber,100);
setTimeout(showdata,100);
}
// 键盘上键
function moveTop(){
isGameOver();
if(!canMoveTop()){
return false;
}
for(var i=1;i<4;i++){
for(var j=0;j<4;j++){
if(data[i][j]!=0){
for(var k=0;k<i;k++){
if(data[k][j]==0&&noBlockV(j,k,i,data)){
//move()
util.moveAnimate(i,j,k,j);
data[k][j]=data[i][j];
data[i][j]=0;
continue;
}else if(data[k][j]==data[i][j]&&noBlockV(j,k,i,data)){
//move()
util.moveAnimate(i,j,k,j);
//add
data[k][j]+=data[i][j];
data[i][j]=0;
score+=data[k][j];//增加分数
util.updateScore();//更新分数
continue;
}
}
}
}
}
setTimeout(getNumber,100);
setTimeout(showdata,100);
}
// 键盘下键
function moveBottom(){
isGameOver();
if(!canMoveBottom()){
return false;
}
for(var i=2;i>=0;i--){
for(var j=0;j<4;j++){
if(data[i][j]!=0){
for(var k=3;k>i;k--){
if(data[k][j]==0&&noBlockV(j,i,k,data)){
//move()
util.moveAnimate(i,j,k,j);
data[k][j]=data[i][j];
data[i][j]=0;
continue;
}else if(data[k][j]==data[i][j]&&noBlockV(j,i,k,data)){
//move()
util.moveAnimate(i,j,k,j);
//add
data[k][j]+=data[i][j];
data[i][j]=0;
score+=data[k][j];//增加分数
util.updateScore();//更新分数
continue;
}
}
}
}
}
setTimeout(getNumber,100);
setTimeout(showdata,100);
}
// 键盘右键
function moveRight(){
isGameOver();
if(!canMoveRight()){
return false;
}
for(var i=0;i<4;i++){
for(var j=2;j>=0;j--){
if(data[i][j]!=0){
for(var k=3;k>j;k--){
if(data[i][k]==0&&noBlockH(i,j,k,data)){
//move()
util.moveAnimate(i,j,i,k);
data[i][k]=data[i][j];
data[i][j]=0;
continue;
}else if(data[i][k]==data[i][j]&&noBlockH(i,j,k,data)){
//move()
util.moveAnimate(i,j,i,k);
//add
data[i][k]+=data[i][j];
data[i][j]=0;
score+=data[i][k];//增加分数
util.updateScore();//更新分数
continue;
}
}
}
}
}
setTimeout(getNumber,100);
setTimeout(showdata,100);
}
function canMoveLeft(){
for(var i=0;i<4;i++){
for(var j=1;j<4;j++){
if(data[i][j]!=0){
if(data[i][j-1]==0||data[i][j-1]==data[i][j]){
return true;
}
}
}
}
return false;
}
function canMoveTop(){
for(var i=1;i<4;i++){
for(var j=0;j<4;j++){
if(data[i][j]!=0){
if(data[i-1][j]==0||data[i-1][j]==data[i][j]){
return true;
}
}
}
}
return false;
}
function canMoveRight(){
for(var i=0;i<4;i++){
for(var j=0;j<3;j++){
if(data[i][j]!=0){
if(data[i][j+1]==0||data[i][j+1]==data[i][j]){
return true;
}
}
}
}
return false;
}
function canMoveBottom(){
for(var i=0;i<3;i++){
for(var j=0;j<4;j++){
if(data[i][j]!=0){
if(data[i+1][j]==0||data[i+1][j]==data[i][j]){
return true;
}
}
}
}
return false;
}
function noBlockH(row,col1,col2,data){
for(var i=col1+1;i<col2;i++){
if(data[row][i]!=0){
return false;
}
}
return true;
}
function noBlockV(col,row1,row2,data){
for(var i=row1+1;i<row2;i++){
if(data[i][col]!=0){
return false;
}
}
return true;
}
// 游戏结束
function isGameOver(){
if(!canMoveTop()&&!canMoveBottom()&&!canMoveLeft()&&!canMoveRight()){
alert('GameOver');
flag=false;
}
}
推荐阅读
-
用纯JavaScript编写一个适用于移动设备的网页版2048小游戏
-
Java 8新特性探究(十三)JavaFX 8新特性以及开发2048游戏-JavaFX历史## 跟java在服务器端和web端成绩相比,桌面一直是java的软肋,于是Sun公司在2008年推出JavaFX,弥补桌面软件的缺陷,请看下图JavaFX一路走过来的改进 从上图看出,一开始推出时候,开发者需使用一种名为JavaFX Script的静态的、声明式的编程语言来开发JavaFX应用程序。因为JavaFX Script将会被编译为Java bytecode,程序员可以使用Java代码代替。 JavaFX 2.0之后的版本摒弃了JavaFX Script语言,而作为一个Java API来使用。因此使用JavaFX平台实现的应用程序将直接通过标准Java代码来实现。 JavaFX 2.0 包含非常丰富的 UI 控件、图形和多媒体特性用于简化可视化应用的开发,WebView可直接在应用中嵌入网页;另外 2.0 版本允许使用 FXML 进行 UI 定义,这是一个脚本化基于 XML 的标识语言。 从JDK 7u6开始,JavaFx就与JDK捆绑在一起了,JavaFX团队称,下一个版本将是8.0,目前所有的工作都已经围绕8.0库进行。这是因为JavaFX将捆绑在Java 8中,因此该团队决定跳过几个版本号,迎头赶上Java 8。 ##JavaFx8的新特性 ## ###全新现代主题:Modena 新的Modena主题来替换原来的Caspian主题。不过在Application的start方法中,可以通过setUserAgentStylesheet(STYLESHEET_CASPIAN)来继续使用Caspian主题。 参考http://fxexperience.com/2013/03/modena-theme-update/ ###JavaFX 3D 在JavaFX8中提供了3D图像处理API,包括Shape3D (Box, Cylinder, MeshView, Sphere子类),SubScene, Material, PickResult, LightBase (AmbientLight 和PointLight子类),SceneAntialiasing等。Camera类也得到了更新。从JavaDoc中可以找到更多信息。 ###富文本 强化了富文本的支持 ###TreeTableView ###日期控件DatePicker 增加日期控件 ###用于 CSS 结构的公共 API
-
JavaScript的乐趣:创建一个2048的网页版游戏
-
AST 语法树 python ast 语法树解析 - 首先,让我们了解一下 AST 的基本理论? 抽象语法树(AST)或简称语法树(SST)是源代码语法结构的抽象表示。它以树的形式表示编程语言的语法结构,树中的每个节点代表源代码中的一个结构。 与抽象语法树相对的是具体语法树(通常称为分析树)。一般来说,在翻译和编译源代码的过程中,语法分析器会创建分析树。创建 AST 后,在后续处理过程中(如语义分析阶段)会添加一些信息。 可以这样理解,语法树是作为 JavaScript 的编译器或解释器使用的,编译后的 JS 才能真正转换成计算机可识别的机器代码,并最终成功运行。 具体语法树是编译后记录所有细节的树结构,抽象语法树则是具体语法树的简化版,那么相对来说,抽象语法树的运行速度要快得多,比如 ESLint、Webpack 等工具都是使用 AST 来提高性能的,同时,AST 也足以满足这些工具运行时所需的信息。 让我们来看看抽象语法树的结构,举例说明
-
go语言Socket编程-Socket编程 什么是Socket Socket,英文含义是插座、插孔,一般称之为套接字,用于描述IP地址和端口。可以实现不同程序间的数据通信。 Socket起源于Unix,而Unix基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。Socket就是该模式的一个实现,网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。Socket也具有一个类似于打开文件的函数调用:Socket,该函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。 套接字的内核实现较为复杂,不宜在学习初期深入学习,了解到如下结构足矣。 套接字通讯原理示意 在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程。“IP地址+端口号”就对应一个socket。欲建立连接的两个进程各自有一个socket来标识,那么这两个socket组成的socket pair就唯一标识一个连接。因此可以用Socket来描述网络连接的一对一关系。 常用的Socket类型有两种:流式Socket(SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。 网络应用程序设计模式 C/S模式 传统的网络应用设计模式,客户机(client)/服务器(server)模式。需要在通讯两端各自部署客户机和服务器来完成数据通信。 B/S模式 浏览器(Browser)/服务器(Server)模式。只需在一端部署服务器,而另外一端使用每台PC都默认配置的浏览器即可完成数据的传输。 优缺点 对于C/S模式来说,其优点明显。客户端位于目标主机上可以保证性能,将数据缓存至客户端本地,从而提高数据传输效率。且,一般来说客户端和服务器程序由一个开发团队创作,所以他们之间所采用的协议相对灵活。可以在标准协议的基础上根据需求裁剪及定制。例如,腾讯所采用的通信协议,即为ftp协议的修改剪裁版。 因此,传统的网络应用程序及较大型的网络应用程序都首选C/S模式进行开发。如,知名的网络游戏魔兽世界。3D画面,数据量庞大,使用C/S模式可以提前在本地进行大量数据的缓存处理,从而提高观感。 C/S模式的缺点也较突出。由于客户端和服务器都需要有一个开发团队来完成开发。工作量将成倍提升,开发周期较长。另外,从用户角度出发,需要将客户端安插至用户主机上,对用户主机的安全性构成威胁。这也是很多用户不愿使用C/S模式应用程序的重要原因。 B/S模式相比C/S模式而言,由于它没有独立的客户端,使用标准浏览器作为客户端,其工作开发量较小。只需开发服务器端即可。另外由于其采用浏览器显示数据,因此移植性非常好,不受平台限制。如早期的偷菜游戏,在各个平台上都可以完美运行。 B/S模式的缺点也较明显。由于使用第三方浏览器,因此网络应用支持受限。另外,没有客户端放到对方主机上,缓存数据不尽如人意,从而传输数据量受到限制。应用的观感大打折扣。第三,必须与浏览器一样,采用标准http协议进行通信,协议选择不灵活。 因此在开发过程中,模式的选择由上述各自的特点决定。根据实际需求选择应用程序设计模式。 简单的C/S模型通信 Server端:Listen函数 func Listen(network, address string) (Listener, error) network:选用的协议:TCP、UDP, 如:“tcp”或 “udp” address:IP地址+端口号, 如:“127.0.0.1:8000”或 “:8000” Listener 接口: type Listener interface { Accept (Conn, error) Close error Addr Addr } Conn 接口: type Conn interface { Read(b byte) (n int, err error) Write(b byte) (n int, err error) Close error LocalAddr Addr RemoteAddr Addr SetDeadline(t time.Time) error SetReadDeadline(t time.Time) error SetWriteDeadline(t time.Time) error } 参看 [<u>https://studygolang.com/pkgdoc</u>](https://studygolang.com/pkgdoc) 中文帮助文档中的demo: 示例代码:TCP服务器.go package main import ( "net" "fmt" ) func main { // 创建监听 listener, err:= net.Listen("tcp", ":8000") if err != nil { fmt.Println("listen err:", err) return } defer listener.Close // 主协程结束时,关闭listener fmt.Println("服务器等待客户端建立连接...") // 等待客户端连接请求 conn, err := listener.Accept if err != nil { fmt.Println("accept err:", err) return } defer conn.Close // 使用结束,断开与客户端链接 fmt.Println("客户端与服务器连接建立成功...") // 接收客户端数据 buf := make(byte, 1024) // 创建1024大小的缓冲区,用于read n, err := conn.Read(buf) if err != nil { fmt.Println("read err:", err) return } fmt.Println("服务器读到:", string(buf[:n])) // 读多少,打印多少。 }
-
重新编写标题:游戏化的2048网页版挑战:前端开发在Web环境中的威力