2024年夏季《移动软件开发》实验报告
姓名和学号? | |
---|---|
本实验属于哪门课程? | 中国海洋大学24夏《移动软件开发》 |
实验名称? | 实验6:推箱子游戏 |
博客地址? | |
Github仓库地址? |
一、实验目标
1、综合所学知识创建完整的推箱子游戏;2、能够在开发过程中熟练掌握真机预览、调试等操作。
二、实验步骤
1.视图设计
1)导航栏设计
app.json
代码如下:
"window": {
"navigationBarBackgroundColor": "#E64340",
"navigationBarTitleText": "推箱子游戏"
},
2)页面设计
公共样式设计
app.wxss
代码如下:
/* 引入 weui 组件 */
@import './miniprogram_npm/weui-miniprogram/weui-wxss/dist/style/weui.wxss';
page {
--footer-height: 10vh;
--button-size: 16vw;
--button-color: #353535;
--button-icon-size: 6vw;
}
page {
background: #f6f6f6;
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.container {
display: flex;
flex-direction: column;
align-items: center;
box-sizing: border-box;
min-height: 100vh;
overflow-x: hidden;
}
button {
background: initial;
}
button:focus {
outline: 0;
}
button::after {
border: none;
}
.form-group {
width: calc(100% - 40px);
margin: 10px 20px;
border-radius: 10px;
background: white;
}
.form-group_label {
align-self: flex-start;
margin-left: 20px;
color: #8D8D8D;
font-size: 15px;
}
.form-group_label:not(:first-child) {
margin-top: 20px;
}
.form-cell {
padding: 20px 15px;
}
.form-cell:not(:last-child) {
border-bottom: rgba(0, 0, 0, 0.05) solid 1px;
}
.form-cell.inline {
display: flex;
justify-content: flex-start;
align-items: center;
}
首页设计
pages/index/index.wxml
代码如下:
<!--index.wxml-->
<view class="container">
<!--标题-->
<view class="title">游戏选关</view>
<!--关卡列表-->
<view class="box" wx:for="{{levels}}" wx:key="levels{{index}}" bindtap='chooseLevel' data-level="{{index}}">
<image src="/images/{{item}}"></image>
<text>第{{index+1}}关</text>
</view>
</view>
pages/index/index.wxss
代码如下:
.container {
display: flex;
flex-direction: column;
height: 100%;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx;
background-color: #fff;
}
.back-icon, .more-icon, .scan-icon {
width: 40rpx;
height: 40rpx;
}
.title {
font-size: 36rpx;
font-weight: bold;
}
.more-options {
display: flex;
align-items: center;
}
.user-info {
display: flex;
align-items: center;
padding: 20rpx;
background-color: #fff;
}
.user-icon {
width: 80rpx;
height: 80rpx;
margin-right: 20rpx;
}
.user-name {
display: flex;
flex-direction: column;
}
.user-name text {
font-size: 32rpx;
margin-bottom: 10rpx;
}
.options {
display: flex;
flex-wrap: wrap;
border-top: 1px solid #ebebeb;
border-bottom: 1px solid #ebebeb;
}
.option {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 20rpx;
border-right: 1px solid #ebebeb;
}
.option-icon {
width: 60rpx;
height: 60rpx;
margin-bottom: 10rpx;
}
.section {
display: flex;
flex-direction: column;
padding: 20rpx;
border-bottom: 1px solid #ebebeb;
}
.section-title {
display: flex;
justify-content: space-between;
align-items: center;
}
.arrow-right {
width: 20rpx;
height: 20rpx;
}
.section-description {
margin-top: 10rpx;
font-size: 28rpx;
color: #666;
}
page {
background-color: #f8f8f8;
}
.login-container {
height: 400rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
}
/* 图标的样式 */
.contact-filled {
width: 150rpx;
margin-bottom: 16rpx;
}
/* 登录按钮的样式 */
.btn-login {
width: 90%;
border-radius: 100px;
margin: 15px 0;
background-color: #3F3F3F;
color: #f8f8f8;
}
/* 按钮下方提示消息的样式 */
.tips-text {
font-size: 12px;
color: gray;
}
游戏页面设计
pages/game/game.wxml
代码如下:
<!--pages/game/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>
</view>
pages/game/game.wxss
代码如下:
/* pages/game/game.wxss */
/*游戏画布样式*/
canvas{
border:lrpx solid;
width:320px;
height:320px;
}
/*方向键按钮整体区域*/
.btnBox{
display:flex;
flex-direction: column;
align-items:center;
}
/*方向键按钮第二行*/
.btnBox view{
display:flex;
flex-direction:row;
}
/*所有方向键按钮*/
.btnBox button{
width:90rpx;
height:90rpx;
}
/*所有按钮样式*/
button{
margin:10rpx;
}
2.逻辑实现
1)公共逻辑
utils/data.js
代码如下:
//关卡1
var map1 =[
[0,1,1,1,1,1,0,0],
[0,1,2,2,1,1,1,0],
[0,1,5,4,2,2,1,0],
[1,1,1,2,1,2,1,1],
[1,3,1,2,1,2,2,1],
[1,3,4,2,2,1,2,1],
[1,3,2,2,2,4,2,1],
[1,1,1,1,1,1,1,1]
]
//关卡2
var map2=[
[0,0,1,1,1,0,0,0],
[0,0,1,3,1,0,0,0],
[0,0,1,2,1,1,1,1],
[1,1,1,4,2,4,3,1],
[1,3,2,4,5,1,1,1],
[1,1,1,1,4,1,0,0],
[0,0,0,1,3,1,0,0],
[0,0,0,1,1,1,0,0]
]
//关卡3
var map3 =[
[0,0,1,1,1,1,0,0],
[0,0,1,3,3,1,0,0],
[0,1,1,2,3,1,1,0],
[0,1,2,2,4,3,1,0],
[1,1,2,2,5,4,1,1],
[1,2,2,1,4,4,2,1],
[1,2,2,2,2,2,2,1],
[1,1,1,1,1,1,1,1]
]
//关卡4
var map4 = [
[0,1,1,1,1,1,1,0],
[0,1,3,2,3,3,1,0],
[0,1,3,2,4,3,1,0],
[1,1,1,2,2,4,1,1],
[1,2,4,2,2,4,2,1],
[1,2,1,4,1,1,2,1],
[1,2,2,2,5,2,2,1],
[1,1,1,1,1,1,1,1]
]
module.exports = {
maps:[map1,map2,map3,map4]
}
2)首页逻辑
pages/index/index.js
代码如下:
// index.js
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
}
)
},
3)游戏页逻辑
pages/game/game.js
代码如下:
// pages/game/game.js
var data = require('../../utils/data')
//地图图层数据
var map = [
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
]
//箱子图层数据
var box = [
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
]
//方块的宽度
var w = 40
//初始化游戏主角的行与列
var row = 0
var col = 0
Page({
/**
* 页面的初始数据
*/
data: {
level:1
},
//初始化地图数据
initMap:function(level){
//读取原始的游戏地图数据
let mapData = data.maps[level]
//使用双重for循环记录地图数据
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
}
}
}
},
//绘制地图
drawCanvas:function(){
let ctx = this.ctx
//清空画布
ctx.clearRect(0,0,320,320)
for(var i = 0;i < 8;i++){
for(var j = 0;j < 8;j++){
let img = 'ice'
if(map[i][j] == 1){
img = 'stone'
}else if(map[i][j] == 3){
img = 'pig'
}
//绘制地图
ctx.drawImage('/images/icons/' + img + '.png',j*w,i*w,w,w)
if(box[i][j] == 4){
//叠加绘制箱子
ctx.drawImage('/images/icons/box.png',j*w,i*w,w,w)
}
}
}
//叠加绘制小鸟
ctx.drawImage('/images/icons/bird.png',col*w,row*w,w,w)
ctx.draw()
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
//获取关卡
let level = options.level
//更新页面关卡标题
this.setData(
{
level:parseInt(level) + 1
}
)
//创建画布上下文
this.ctx = wx.createCanvasContext("myCanvas")
//初始化地图数据
this.initMap(level)
//绘制画布内容
this.drawCanvas()
},
//上
up:function(){
if(row > 0){
if(map[row - 1][col] != 1 && box[row - 1][col] != 4){
row = row - 1
}
else if(box[row - 1][col] == 4){
if(row - 1 > 0){
if(map[row - 2][col] != 1 && box[row - 2][col] != 4){
box[row - 2][col] = 4
box[row - 1][col] = 0
row = row - 1
}
}
}
//重新绘制地图
this.drawCanvas()
//检查游戏是否成功
this.checkWin()
}
},
//下
down:function(){
if(row < 7){
if(map[row + 1][col] != 1 && box[row + 1][col] != 4){
row = row + 1
}
else if(box[row + 1][col] == 4){
if(row + 1 < 7){
if(map[row + 2][col] != 1 && box[row + 2][col] != 4){
box[row + 2][col] = 4
box[row + 1][col] = 0
row = row + 1
}
}
}
//重新绘制地图
this.drawCanvas()
//检查游戏是否成功
this.checkWin()
}
},
//左
left:function(){
if(col > 0){
if(map[row][col - 1] != 1 && box[row][col - 1] != 4){
col = col - 1
}
else if(box[row][col - 1] == 4){
if(col - 1 > 0){
if(map[row][col - 2] != 1 && box[row][col - 2] != 4){
box[row][col - 2] = 4
box[row][col - 1] = 0
col = col -1
}
}
}
//重新绘制地图
this.drawCanvas()
//检查游戏是否成功
this.checkWin()
}
},
//右
right:function(){
if(col < 7){
if(map[row][col + 1] != 1 && box[row][col + 1] != 4){
col = col + 1
}
else if(box[row][col + 1] == 4){
if(col + 1 < 7){
if(map[row][col + 2] != 1 && box[row][col + 2] != 4){
box[row][col + 2] = 4
box[row][col + 1] = 0
col = col + 1
}
}
}
//重新绘制地图
this.drawCanvas()
//检查游戏是否成功
this.checkWin()
}
},
//判断游戏是否成功
isWin:function(){
for(var i = 0; i < 8; i++){
for(var j = 0;j < 8;j++){
if(box[i][j] == 4 && map[i][j] != 3){
return false
}
}
}
return true
},
//游戏成功处理
checkWin:function(){
if(this.isWin()){
wx.showModal({
title: '恭喜',
content: '游戏成功!',
showCancel:false
})
}
},
//重新开始游戏
restartGame:function(){
//初始化地图数据
this.initMap(this.data.level - 1)
//绘制画布内容
this.drawCanvas()
}
})
三、程序运行结果
四、问题总结与体会
在本次实验中,面对的主要挑战在于理解和实现游戏的逻辑,特别是玩家角色与环境的交互,如移动和推箱动作的检测与执行。比如,在处理玩家移动时,需要确保地图上的每个位置都可以正确响应玩家的动作,同时还要考虑到箱子的存在可能会阻碍移动等等。本次实验加深了我对前端开发流程的认识,在响应式设计和代码调试方面有了更多的实践经验。