2023年夏季《移动软件开发》实验报告
姓名: 学号:21020007***
姓名和学号? | 21020007*** |
---|---|
本实验属于哪门课程? | 中国海洋大学23夏《移动软件开发》 |
实验名称? | 实验4:拼图游戏 |
博客地址? | 用户Id: m0_62135967 用户名称:Pane |
Github仓库地址? | XXXXXXX |
(备注:将实验报告发布在博客、代码公开至 github 是 加分项,不是必须做的)
一、实验目标
本项目一共需要两个页面,即首页和游戏页面,其中,首页用于呈现关卡菜单,点击对应难度的关卡后进入游戏画面。
12.1.1 首页功能需求
首页功能需求如下:(1) 首页需要包含标题和关卡列表。(2) 关卡至少要有 6 个关卡选项,每个关卡显示预览图片和第几关。(3) 点击关卡列表可以打开对应的游戏画面。
12.1.2 游戏页功能需求
游戏页功能需求如下:(1)游戏页面需要显示游戏提示图、游戏画面和“重新开始”按钮。(2)每关游戏提示图显示对应的图片预览。(3)游戏画面随机将原图打乱为3×3的小方块,并且可移动被点击的方块。(4)点击“重新开始”按钮可以重新随机打乱小方块并开始游戏。
二、实验步骤
1.项目创建:本项目创建选择空白文件夹jigsawGame,效果如图所示。单击“新建”按钮完成项目创建,然后准备手动修改页面配置。
2.页面配置
(1)创建页面文件:项目创建完毕后,在根目录中会生成文件夹pags用于存放页面文件。一般来说首页默认命名为index,表示小程序运行的第一个页面;其他页面名回称可以自定义。本项目有两个页面文件,需要创建index(首页页面)和game视频讲解(游戏页面):将app.json文件内pages属性中的“pags/logs/logs改成“pages/game/game”;按快捷键Ctrl+S保存修改后会在page文件夹下自动生成game目录。
(2)删除和修改文件:删除和修改文件:按照指导删除utils文件夹及其内部所有内容,pages文件夹下的logs目录及其内部所有内容、index.wxml和index.wxss中的全部代码、Index.js中的全部代码,并输入关键词page补全函数、删除app.wxss全部代码、app.js中全部代码
3.创建其他文件:创建一个新的文件夹用于存放播放图标,文件夹名称命名为images,并将所需要用到的图片放进文件夹里
3.视图设计
(1)导航栏设计:小程序默认导航栏是黑底白字的效果,app.json中可以进行自定义导航栏标题和背景颜色,下面代码可以更改所有页面的导航栏标题文本
"window":{ "backgroundTextStyle":"light", "navigationBarBackgroundColor": "#E64340", "navigationBarTitleText": "拼图游戏", "navigationBarTextStyle":"black" },
(2)页面设计:
①公共样式设计:首先在app.wxss中设置页面窗口和顶端标题的公共样式
/* 页面容器样式 */ .container{ height: 100vh; color: #e64340; font-weight: bold; display: flex; flex-direction: column; align-items: center; justify-content: space-evenly; } /* 顶端标题样式 */ .title{ font-size: 18pt; }
②首页设计:首页主要包含两部分内容,即标题和关卡列表,如图12-7所示。计划使用如下组件:
顶端标题:<view>容器;关卡列表:<view>容器,内部使用数组循环。
相关WXSS (pages/index/index.wxss)代码片段如下:
/* 关卡区域列表 */ .levelBox{ width: 100%; } /* 单个关卡区域 */ .box{ width: 50%; float: left; margin: 25rpx 0; display: flex; flex-direction: column; align-items: center; } /* 选关图片 */ image{ width: 260rpx; height: 260rpx; }
③游戏页面设计:游戏页面需要用户点击首页的关卡列表,然后在新窗口中打开该页面口游戏页面包括游戏提示图、游戏画面和“重新开始”按钮,此时预览就可以直接显示game页面了,设计完毕后再改回“普通编译”模式即可重新显示首页。
4.逻辑实现: (1)首页逻辑:
①关卡列表展示:在JS文件的 data 中录入关卡图片的数据信息,这里以6个关卡为例 。
/** * 页面的初始数据 */ data: { levels:[ 'pic01.jpg', 'pic02.jpg', 'pic03.jpg', 'pic04.jpg', 'pic05.jpg', 'pic06.jpg', ] },
接着为关卡对应的<view>组件添加wx:for属性循环显示关卡列表数据和图片。修改后的WXML(pages/index/index.wxml)代码如下:
<view class="container"> <view class="title"> 游戏选关 </view> <view class="levelBox"> <view class="box" wx:for="{{levels}}" wx:key="levels{{index}}" bindtap="chooseLevel" data-level="{{item}}"> <image src="/images/{{item}}"></image> <text>第{{index+1}}关</text> </view> </view> </view>
②点击跳转游戏页面:若希望用户点击关卡图片即可实现跳转,需要首先为关卡列表项目添加点击事件。相关WXML(pages/index/index.wxml)代码相关片段修改如下:
<view class="box" wx:for="{{levels}}" wx:key="levels{{index}}" bindtap="chooseLevel" data-level="{{item}}">
上述代码表示为关卡添加了自定义点击事件函数chooseLevel,并且使用data--level属性携带了关卡图片信息。然后在对应的index.js文件中添加chooseLevel函数的内容,代码片段如下:
chooseLevel:function(e){ let level = e.currentTarget.dataset.level wx.navigateTo({ url: '../game/game?level='+level, }) },
(2)游戏页逻辑
游戏页主要有两个功能需要实现,一是显示提示图;二是游戏逻辑实现。
①显示提示图:在首页逻辑中已经实现了页面跳转并携带了关卡对应的图片信息,现在视频讲解需要在游戏页面接收关卡信息,并显示对应的图片内容。相关JS(pages/game/game.js)代码片段如下:
/** * 生命周期函数--监听页面加载 */ onLoad: function(options) { // console.log(options.level) // 更新图片路径地址 url = '/images/' + options.level // 更新提示图的地址 this.setData({ url: url })
②游戏逻辑实现:
a.准备工作。首先在game.js文件的顶端记录一些游戏初始数据信息。对应的JS(pages/game/game.js)代码片段添加如下:
// 方块的初始位置 var num = [ ['00', '01', '02'], ['10', '11', '12'], ['20', '21', '22'] ] // 方块的宽度 var w = 100 // 图片的初始地址 var url = '/images/pic01.jpg'
b.初始化拼图画面。传统做法是随机抽取画面中的任意两个方块,然后交换彼此位置,在进行足够多次数的交换后基本可以实现随机打乱的效果。但是这种方法有一个弊端,就是有时候会陷入无解的死局。因此可以考虑从空白方块的所在位置入手,每次随机让它和周围的邻近方块交换位置,这样可以通过方块反向移动回到最初始状态(确保本局有解),并且在交换足够多的次数后也可以实现随机打乱的效果。
/** * 自定义函数--随机打乱方块顺序 */ shuffle: function() { // 先令所有方块回归初始位置 num = [ ['00', '01', '02'], ['10', '11', '12'], ['20', '21', '22'] ] ..... },
c.上述代码表示使用for循环进行了100次打乱,开发者可以根据自己的需求更改循环次数。每次使用Math.random()方法从上下、左、右4个方向中随机产生一个方向,之后如果符合条件则交换空白方块和图片方块的位置。
/** * 自定义函数--绘制画布内容 */ drawCanvas: function() { let ctx = this.ctx // 清空画布 ctx.clearRect(0, 0, 300, 300) // 使用双重for循环语句绘制3x3拼图 for (var i = 0; i < 3; i++) { for (var j = 0; j < 3; j++) { if (num[i][j] != '22') { // 获取行和列 var row = parseInt(num[i][j] / 10) var col = num[i][j] % 10 // 绘制方块 ctx.drawImage(url, col * w, row * w, w, w, j * w, i * w, w, w) } } } ctx.draw() },
d.最后在game.js的onLoad函数中调用自定义函数shuffle和drawCanvas。对应的JS(pages/game/game.js)代码片段添加如下:
三、程序运行结果
列出程序的最终运行结果及截图。
Page({ // 命周期函数--监听页面加载 onLoad:function(options){ //更新图片路径地址提示图 url='/images/'+options.level //更新提示图的地址 this.setData({url:url}) //创建画布上下文 this.ctx=wx.createCanvasContext('myCanvas') //打乱方块顺序 this.shuffle() //绘制画布内容 this.drawCanvas() }, })
③移动被点击的方块。修改game.wxml页面中的画布组件(<canvas>),为其绑定触摸事件;在game.js文件添加自定义函数 touchBox,用于实现图片方块的移动
/** * 自定义函数--监听点击方块事件 */ touchBox: function(e) { // 如果游戏已经成功,不做任何操作 if (this.data.isWin) { // 终止本函数 return } // 获取被点击方块的坐标x和y var x = e.changedTouches[0].x var y = e.changedTouches[0].y // console.log('x:'+x+',y:'+y) // 换算成行和列 var row = parseInt(y / w) var col = parseInt(x / w) // 如果点击的不是空白位置 if (num[row][col] != '22') { // 尝试移动方块 this.moveBox(row, col) // 重新绘制画布内容 this.drawCanvas() // 判断游戏是否成功 if (this.isWin()) { // 在画面上绘制提示语句 let ctx = this.ctx // 绘制完整图片 ctx.drawImage(url, 0, 0) // 绘制文字 ctx.setFillStyle('#e64340') ctx.setTextAlign('center') ctx.setFontSize(60) ctx.fillText('游戏成功', 150, 150) ctx.draw() } } },
③判断游戏成功
首先在game.js文件中的data中添加初始数据 isWin,用于标记游戏成功与否。对应的JS(pages/game/game.js)代码片段添加如下:
data: { isWin: false },
④重新开始游戏
修改game.wxml代码,为“重新开始”按钮追加自定义函数的点击事件。WXML(pages/game/game.wxml)代码片段修改如下:
/** * 自定义函数--重新开始游戏 */ restartGame: function() { // 更新游戏状态 this.setData({ isWin: false }) // 打乱方块顺序 this.shuffle() // 绘制画布内容 this.drawCanvas() },
三、程序运行结果
列出程序的最终运行结果及截图。
四、问题总结与体会
我学习到了如何使用微信小程序框架和组件来展示新闻内容。通过阅读相关文档和教程,我了解到可以使用<view>、<text>和<image>等组件来布局和显示拼图游戏的标题、内容和配图。这个过程让我对微信小程序的组件和布局有了更深入的了解。
总的来说,通过编写拼图游戏微信小程序代码,我不仅学到了如何使用微信小程序的组件和布局技巧,还学到了如何处理用户点击事件等。这个实验让我更加熟悉了编程的一些基本概念和技巧,并提升了我的实践能力和问题解决能力。此次实验,对于我《移动软件开发》这门课的学习有非常大的帮助,同时也为我以后计算机专业的学习打下了坚实基础。