2024年夏季《移动软件开发》实验报告
一、实验目标
1、综合所学知识创建完整的推箱子游戏;
2、能够在开发过程中熟练掌握真机预览、调试等操作。
二、实验步骤
1. 项目创建与初始化
-
创建项目:使用微信开发者工具,新建一个小程序项目,命名为
boxGame
。选择空白模板,并在项目路径中选择合适的文件夹来存放项目文件。 -
页面配置:
- 在根目录的
app.json
文件中配置项目页面路径,设置首页为pages/index/index
,游戏页面为pages/game/game
。 - 配置项目的窗口属性,使导航栏背景色和标题文字颜色符合实验需求:
{ "pages": [ "pages/index/index", "pages/game/game" ], "window": { "navigationBarBackgroundColor": "#E64340", "navigationBarTitleText": "推箱子游戏", "navigationBarTextStyle": "white" } }
- 在根目录的
-
创建页面文件:
- 在
pages
文件夹下,分别创建index
和game
文件夹,并在每个文件夹中创建.json
、.js
、.wxml
和.wxss
文件。 - 确保每个页面的
json
文件内容为:{ "usingComponents": {} }
,确保页面组件配置正常。
- 在
2. 首页功能实现
-
需求分析:
- 首页的主要功能是展示关卡列表,用户可以选择不同的关卡进入游戏。每个关卡应显示预览图片和关卡编号。
-
数据定义:
- 在
index.js
中定义首页的数据结构。使用levels
数组存储关卡预览图片的文件名,便于在页面中循环展示。
Page({ data: { levels: [ 'level01.png', 'level02.png', 'level03.png', 'level04.png' ] }, chooseLevel: function(e) { let level = e.currentTarget.dataset.level; // 获取关卡索引 wx.navigateTo({ url: '../game/game?level=' + level, // 跳转到对应的游戏页面 }); } });
- 在
-
页面布局与组件使用:
- 在
index.wxml
中使用<view>
标签配合wx:for
循环展示关卡列表,每个关卡包含图片和文本描述,绑定bindtap
事件以实现点击跳转。
<view class="container"> <view class="title">游戏选关</view> <view class="levelBox"> <view class="box" wx:for="{{levels}}" wx:key="index" bindtap="chooseLevel" data-level="{{index}}"> <image src="/images/{{item}}" mode="aspectFit"></image> <text>第{{index + 1}}关</text> </view> </view> </view>
- 在
-
样式设计:
- 在
index.wxss
中设计页面的布局和样式,使关卡列表整齐美观。确保图片比例一致且文字居中显示。
.container { padding: 20rpx; } .title { font-size: 32rpx; text-align: center; margin-bottom: 20rpx; color: #333; } .levelBox { display: flex; flex-wrap: wrap; justify-content: space-around; } .box { width: 45%; margin: 20rpx 0; display: flex; flex-direction: column; align-items: center; } .box image { width: 100%; height: auto; } .box text { margin-top: 10rpx; font-size: 24rpx; color: #555; }
- 在
3. 游戏页面功能实现
-
功能需求分析:
- 游戏页面的功能包括显示当前关卡编号、游戏地图、控制按钮(上、下、左、右)、重新开始、跳过关卡和回退一步等操作。
-
地图和元素初始化:
- 在
game.js
中,通过initMap
函数初始化游戏地图和元素的位置。使用二维数组表示地图状态,每个位置由不同的数字表示墙、地板、目标点、箱子和人物。
initMap: function(level) { let mapData = data.maps[level]; for (var i = 0; i < 8; i++) { for (var j = 0; j < 8; j++) { box[i][j] = 0; map[i][j] = mapData[i][j]; if (mapData[i][j] == 4) { box[i][j] = 4; map[i][j] = 2; } else if (mapData[i][j] == 5) { map[i][j] = 2; row = i; col = j; } } } history = []; // 清空历史记录 this.saveState(); // 保存初始状态 }
- 在
-
游戏地图绘制:
- 使用
drawCanvas
函数通过canvas
画布绘制游戏地图元素。利用wx.createCanvasContext('myCanvas')
创建画布上下文,并在画布上绘制地板、墙壁、目标点、箱子和人物。
- 使用
-
方向控制与移动:
- 在
game.js
中定义方向控制按钮的点击事件方法(up
、down
、left
、right
),通过movePlayer
方法实现人物的移动和箱子的推动操作,并调用drawCanvas
进行重新绘制。
- 在
-
游戏胜利判断:
- 在每次操作后调用
checkWin
方法,通过检查所有箱子是否在目标点上来判断游戏是否胜利。如果胜利则提示并进入下一关,否则继续游戏。
- 在每次操作后调用
4. 游戏体验优化与创新功能实现
-
回退一步功能:
- 功能描述:允许玩家在每次操作时保存当前状态,支持玩家回退到上一步的状态,避免重置整个关卡。
- 实现方法:使用
saveState
方法在每次玩家移动或推动箱子前,将当前状态保存到history
栈中。用户点击“回退一步”按钮时,调用undo
方法从history
栈中恢复到上一个状态。
saveState: function() { history.push({ map: JSON.parse(JSON.stringify(map)), box: JSON.parse(JSON.stringify(box)), row: row, col: col }); }, undo: function() { if (history.length > 1) { history.pop(); // 弹出当前状态 let lastState = history[history.length - 1]; map = JSON.parse(JSON.stringify(lastState.map)); box = JSON.parse(JSON.stringify(lastState.box)); row = lastState.row; col = lastState.col; this.drawCanvas(); } else { wx.showToast({ title: '无法回退', icon: 'none' }); } }
- 界面设计:在游戏页面中新增“回退一步”按钮,位置放置在“重新开始”按钮和“选关跳过”按钮下方,保持样式一致。
-
跳过关卡功能:
- 功能描述:为了让玩家能够跳过当前较难的关卡,提供“跳过关卡”按钮。点击后进入下一关,如果已经是最后一关则提示无法跳过。
- 实现方法:通过在
game.js
中定义skipLevel
方法,检查是否存在下一关,并进行关卡切换和地图初始化。
skipLevel: function() { if (this.data.level < data.maps.length) { this.setData({ level: this.data.level + 1 }); this.initMap(this.data.level - 1); // 初始化下一关地图 this.drawCanvas(); // 绘制地图 } else { wx.showModal({ title: "提示", content: "已经是最后一关,无法跳过", showCancel: false }); } }
-
界面布局优化:
- 在
game.wxml
文件中添加新的控制按钮“回退一步”和“选关跳过”,调整布局以保持所有按钮样式和布局一致。确保游戏界面整洁美观,为用户提供良好的视觉体验。
<view class="container"> <view class="title">第{{level}}关</view> <canvas canvas-id="myCanvas"></canvas> <view class="btnBox"> <button type="warn" bindtap="up">↑</button> <view> <button type="warn" bindtap="left">←</button> <button type="warn" bindtap="down">↓</button> <button type="warn" bindtap="right">→</button> </view> </view> <button type="warn" bindtap="restartGame">重新开始</button> <button type="warn" bindtap="skipLevel">选关跳过</button> <button type="warn" bindtap="undo">回退一步</button> </view>
- 在
-
样式统一调整:
- 在
game.wxss
文件中保持按钮的样式一致,确保所有功能按钮的尺寸、颜色和位置均符合整体设计要求,为用户提供一致的操作体验。
- 在
三、程序运行结果
四、问题总结与体会
实验问题总结
-
地图初始化问题:
- 在实验初期,实现地图初始化时,遇到了地图元素无法正确加载的问题。通过检查代码,发现是二维数组的初始化未正确同步到画布上。解决方法是确保每个元素的正确定位,并在初始化后立刻调用画布绘制函数,保证地图和界面同步显示。
-
状态管理与回退功能实现:
- 实现“回退一步”功能时,面临的最大挑战是如何有效管理游戏状态。为了解决这个问题,采用了状态栈的设计思路,每次移动或推箱子操作前都将当前状态存入栈中。这个设计保证了状态的逐步回退,避免了重置游戏的繁琐操作。
-
多功能按钮逻辑冲突:
- 在增加多种功能按钮(如重新开始、跳关和回退一步)时,初期遇到按钮之间逻辑冲突的问题,导致游戏状态异常。通过合理的逻辑梳理和代码优化,将每个按钮的逻辑独立处理,并确保每个功能调用时不会互相干扰,从而顺利解决该问题。
心得体会
通过这次实验,我深刻认识到代码调试与问题解决在软件开发中的重要性,每次遇到的问题和错误都是提升自己能力的机会。为了优化用户体验,我尝试从用户角度出发进行创新设计,比如增加“回退一步”和“跳过关卡”功能,这让我意识到用户体验在应用开发中的关键作用。实验过程中,我还学到了小程序开发中的细节处理,尤其是在状态管理和界面优化方面的技巧。整体而言,这次实验不仅提升了我的编程技能,也让我对小程序开发有了更深入的理解,增强了对开发工作的兴趣和信心。