Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
SSIWB2504
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
template admin
SSIWB2504
Commits
7b63c40f
Commit
7b63c40f
authored
Aug 07, 2025
by
Tt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(游戏逻辑): 实现分阶段游戏流程和鱼点击验证机制
parent
f21d4bcf
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
224 additions
and
18 deletions
+224
-18
form.component.html
src/app/form/form.component.html
+2
-2
interfaces.ts
src/app/play/interfaces.ts
+72
-0
play.component.ts
src/app/play/play.component.ts
+146
-10
流程.md
流程.md
+4
-6
No files found.
src/app/form/form.component.html
View file @
7b63c40f
...
...
@@ -157,10 +157,10 @@
<div
style=
"margin-top: 5px;"
>
<nz-radio-group
[(
ngModel
)]="
question
.
imgSize
"
(
ngModelChange
)="
ngChange
()"
>
<label
nz-radio
nzValue=
"big"
>
<span
[
style
]="{
color:question
.
imgSize=
='big'
?
'#
169BD5
'
:
'#
000
'}"
>
大图片
</span>
<span
[
style
]="{
color:question
.
imgSize=
='big'
?
'#
169BD5
'
:
'#
000
'}"
>
大图片
(一屏3个图)
</span>
</label>
<label
nz-radio
nzValue=
"small"
>
<span
[
style
]="{
color:question
.
imgSize=
='small'
?
'#
169BD5
'
:
'#
000
'}"
>
小图片
</span>
<span
[
style
]="{
color:question
.
imgSize=
='small'
?
'#
169BD5
'
:
'#
000
'}"
>
小图片
(一屏4个图)
</span>
</label>
</nz-radio-group>
</div>
...
...
src/app/play/interfaces.ts
View file @
7b63c40f
...
...
@@ -74,3 +74,75 @@ export interface PositionMap {
/** 键为问题数量,值为位置数组 */
[
key
:
string
]:
Position
[];
}
/**
* 游戏阶段类
*/
export
class
Stage
{
/** 正确的问题 */
correctQuestion
:
Question
;
/** 问题列表 */
questionList
:
Question
[];
/** 随机问题列表 */
questionRandomList
:
Question
[];
/**
* 构造函数
* @param correctQuestion 正确的问题
* @param questionList 问题列表
*/
constructor
(
correctQuestion
:
Question
,
questionList
:
Question
[])
{
this
.
correctQuestion
=
correctQuestion
;
this
.
questionList
=
questionList
;
this
.
questionRandomList
=
[];
// 初始化时自动生成随机列表
this
.
randomList
();
}
/**
* 将问题列表打乱并放置到随机问题列表中
* 1. 从数组中移除正确的答案
* 2. 将打乱的数组的长度限制为不超过4
* 3. 将正确的答案添加两次到列表中
* 4. 使用深拷贝处理数据
*/
randomList
():
void
{
// 使用深拷贝复制问题列表,避免直接修改原数组
const
tempList
=
JSON
.
parse
(
JSON
.
stringify
(
this
.
questionList
));
// 从列表中移除正确答案
const
correctQuestionIndex
=
tempList
.
findIndex
(
q
=>
q
.
audio
===
this
.
correctQuestion
.
audio
&&
q
.
image
===
this
.
correctQuestion
.
image
);
if
(
correctQuestionIndex
!==
-
1
)
{
tempList
.
splice
(
correctQuestionIndex
,
1
);
}
// 使用Fisher-Yates洗牌算法打乱数组
for
(
let
i
=
tempList
.
length
-
1
;
i
>
0
;
i
--
)
{
const
j
=
Math
.
floor
(
Math
.
random
()
*
(
i
+
1
));
[
tempList
[
i
],
tempList
[
j
]]
=
[
tempList
[
j
],
tempList
[
i
]];
}
// 限制打乱后的数组长度不超过4(不包括正确答案)
const
maxLength
=
4
;
const
limitedList
=
tempList
.
slice
(
0
,
maxLength
);
// 将正确答案添加两次到列表中
const
correctQuestionCopy
=
JSON
.
parse
(
JSON
.
stringify
(
this
.
correctQuestion
));
limitedList
.
push
(
correctQuestionCopy
);
limitedList
.
push
(
JSON
.
parse
(
JSON
.
stringify
(
this
.
correctQuestion
)));
// 再次打乱数组,确保正确答案的位置随机
for
(
let
i
=
limitedList
.
length
-
1
;
i
>
0
;
i
--
)
{
const
j
=
Math
.
floor
(
Math
.
random
()
*
(
i
+
1
));
[
limitedList
[
i
],
limitedList
[
j
]]
=
[
limitedList
[
j
],
limitedList
[
i
]];
}
// 将最终打乱后的列表赋值给随机问题列表
this
.
questionRandomList
=
limitedList
;
}
}
src/app/play/play.component.ts
View file @
7b63c40f
...
...
@@ -44,7 +44,7 @@ import TWEEN from "@tweenjs/tween.js";
// ]
// }
import
{
FormData
,
Position
,
PositionMap
}
from
'
./interfaces
'
;
import
{
FormData
,
Position
,
PositionMap
,
Stage
,
Question
}
from
'
./interfaces
'
;
let
defaultFormData
:
FormData
=
{
"
score
"
:
0
,
...
...
@@ -145,6 +145,7 @@ export class PlayComponent implements OnInit, OnDestroy {
m_gameOver
=
false
;
// 游戏结束标志
selectList
=
[];
// 选中的项目列表
checkBtnElement
=
null
;
// 检查按钮元素引用
gameStages
:
Stage
[]
=
[];
// 游戏阶段数组,存储所有创建的Stage对象
// ------------------------------------
...
...
@@ -704,6 +705,24 @@ export class PlayComponent implements OnInit, OnDestroy {
private
cat_right
:
any
;
private
cat_center
:
any
;
initFishGame
()
{
const
targetList
=
[
0
,
1
,
2
,
3
,
4
,
5
,
6
];
const
questions
=
this
.
g_formData
.
questions
;
// 1. 梳理出选中的数据数组
const
selectedQuestions
=
targetList
.
map
(
index
=>
questions
[
index
]).
filter
(
q
=>
q
);
// 过滤掉可能的undefined值
// 2. 根据梳理好的数组创建多个Stage
this
.
gameStages
=
[];
// 清空之前的游戏阶段
selectedQuestions
.
forEach
(
currentQuestion
=>
{
// 为每个选中的值创建一个Stage对象
// 正确值为当前值,列表值为整个梳理后的列表
const
stage
=
new
Stage
(
currentQuestion
,
selectedQuestions
);
this
.
gameStages
.
push
(
stage
);
});
// 打印创建的Stage对象,用于调试
console
.
log
(
'
Created Stages:
'
,
this
.
gameStages
);
this
.
layoutPage
.
ref
.
visible
=
false
;
this
.
checkBtnElement
.
ref
.
visible
=
false
;
this
.
listItem
.
ref
.
visible
=
false
;
...
...
@@ -715,10 +734,45 @@ export class PlayComponent implements OnInit, OnDestroy {
this
.
cat_center
=
this
.
createCat
(
'
center
'
);
// 创建中间猫
}
// const type = 'big'
// const data = this.g_formData.questions[0];
// const fish = this.createFish(type, data);
// const paopao = this.brokePaopao(fish);
this
.
initNextStage
();
}
// 当前游戏阶段索引
private
currentStageIndex
=
0
;
// 存储用户点击的鱼的数据
private
clickedFishData
:
Question
[]
=
[];
/**
* 初始化下一个游戏阶段
* 1. 将当前Stage中的数组随机一次
* 2. 后续出鱼按照随机后的数组出现
* 3. 用户点击鱼后存储对应数据,如果数据中有两个数据为当前Stage的正确数据则清空画面,等待1秒后进行下一轮游戏
*/
initNextStage
()
{
// 清空之前点击的鱼的数据
this
.
clickedFishData
=
[];
// 检查是否还有游戏阶段
if
(
this
.
currentStageIndex
>=
this
.
gameStages
.
length
)
{
// 所有阶段都完成了,结束游戏
this
.
endGame
();
return
;
}
// 获取当前游戏阶段
const
currentStage
=
this
.
gameStages
[
this
.
currentStageIndex
];
// 将当前Stage中的数组随机一次
currentStage
.
randomList
();
console
.
log
(
'
Current Stage:
'
,
currentStage
);
console
.
log
(
'
Random List:
'
,
currentStage
.
questionRandomList
);
// 清空现有的鱼群
this
.
clearFishes
();
// 修改鱼的生成逻辑,使用当前阶段的随机问题列表
this
.
m_fishInterval
=
3000
;
// 设置鱼的生成间隔为3秒
this
.
m_lastFishTime
=
0
;
// 重置上次生成鱼的时间,使下一帧立即生成鱼
}
initVsView
()
{
...
...
@@ -997,13 +1051,62 @@ export class PlayComponent implements OnInit, OnDestroy {
}
private
touchFish
=
null
;
/**
* 处理鱼泡泡破裂
* 隐藏泡泡背景、小鱼和图片,显示泡泡破裂动画
* 存储用户点击的鱼的数据,检查是否有两个正确数据
* @param fish 被点击的鱼对象
*/
brokePaopao
(
fish
)
{
// 隐藏泡泡背景、小鱼和图片
fish
[
'
child_paopao_bg
'
].
ref
.
visible
=
false
;
fish
[
'
child_xiao_yu
'
].
ref
.
visible
=
false
;
fish
[
'
child_image
'
].
ref
.
visible
=
false
;
fish
[
'
child_paopao_ani
'
].
ref
.
visible
=
true
;
// 创建飞向水桶的小鱼动画
this
.
createFlyingFish
(
fish
);
// 获取当前游戏阶段
const
currentStage
=
this
.
gameStages
[
this
.
currentStageIndex
];
// 存储用户点击的鱼的数据
if
(
fish
.
questionData
)
{
this
.
clickedFishData
.
push
(
fish
.
questionData
);
// 检查是否点击了正确的鱼
const
isCorrect
=
fish
.
questionData
.
audio
===
currentStage
.
correctQuestion
.
audio
&&
fish
.
questionData
.
image
===
currentStage
.
correctQuestion
.
image
;
console
.
log
(
'
Clicked fish data:
'
,
fish
.
questionData
);
console
.
log
(
'
Is correct:
'
,
isCorrect
);
console
.
log
(
'
Clicked fish count:
'
,
this
.
clickedFishData
.
length
);
// 计算正确点击的次数
const
correctClicks
=
this
.
clickedFishData
.
filter
(
data
=>
data
.
audio
===
currentStage
.
correctQuestion
.
audio
&&
data
.
image
===
currentStage
.
correctQuestion
.
image
).
length
;
console
.
log
(
'
Correct clicks:
'
,
correctClicks
);
// 如果有两个数据为当前Stage的正确数据,则清空画面,等待1秒后进入下一轮游戏
if
(
correctClicks
>=
2
)
{
console
.
log
(
'
Stage completed! Moving to next stage...
'
);
// 清空画面(清除所有鱼)
this
.
clearFishes
();
// 增加当前阶段索引
this
.
currentStageIndex
++
;
// 等待1秒后进入下一轮游戏
setTimeout
(()
=>
{
this
.
initNextStage
();
},
1000
);
}
}
// 按顺序切换序列帧 pao_pao_xu_lie_zhen_1 到 pao_pao_xu_lie_zhen_9
let
currentFrame
=
1
;
const
maxFrame
=
9
;
...
...
@@ -1513,29 +1616,62 @@ export class PlayComponent implements OnInit, OnDestroy {
this
.
updateFish
();
}
/**
* 清空所有鱼
* 移除所有当前屏幕上的鱼元素
*/
clearFishes
()
{
// 从渲染对象数组中移除所有鱼
for
(
let
i
=
this
.
m_fishArray
.
length
-
1
;
i
>=
0
;
i
--
)
{
const
fish
=
this
.
m_fishArray
[
i
];
// 从渲染对象数组中移除
this
.
m_renderObject
=
this
.
m_renderObject
.
filter
(
item
=>
item
.
element
!==
fish
.
ref
);
}
// 重新构建渲染数组
this
.
m_renderArr
=
[];
this
.
m_renderObject
.
forEach
(
item
=>
{
this
.
m_renderArr
.
push
(
item
.
element
);
});
// 清空鱼群数组
this
.
m_fishArray
=
[];
}
/**
* 更新鱼的运动
* 管理鱼从右侧游到左侧的动画效果
*/
updateFish
()
{
// 如果没有游戏阶段或当前阶段索引超出范围,不生成鱼
if
(
!
this
.
gameStages
||
this
.
currentStageIndex
>=
this
.
gameStages
.
length
)
{
return
;
}
// 获取当前游戏阶段
const
currentStage
=
this
.
gameStages
[
this
.
currentStageIndex
];
// 检查是否需要创建新的鱼
const
currentTime
=
Date
.
now
();
if
(
currentTime
-
this
.
m_lastFishTime
>
this
.
m_fishInterval
)
{
// 创建新的鱼
if
(
this
.
g_formData
&&
this
.
g_formData
.
questions
&&
this
.
g_formData
.
questions
.
length
>
0
)
{
//
随机
选择一个问题数据
const
randomIndex
=
Math
.
floor
(
Math
.
random
()
*
this
.
g_formData
.
questions
.
length
);
const
fishData
=
this
.
g_formData
.
questions
[
randomIndex
];
if
(
currentStage
&&
currentStage
.
questionRandomList
&&
currentStage
.
questionRandomList
.
length
>
0
)
{
//
从当前阶段的随机问题列表中
选择一个问题数据
const
randomIndex
=
Math
.
floor
(
Math
.
random
()
*
currentStage
.
questionRandomList
.
length
);
const
fishData
=
currentStage
.
questionRandomList
[
randomIndex
];
// 创建小型鱼
const
fish
=
this
.
createFish
(
'
small
'
,
fishData
);
// 存储问题数据到鱼对象中,以便点击时可以获取
fish
.
questionData
=
fishData
;
// 设置鱼的初始位置在屏幕右侧外部
fish
.
ref
.
x
=
this
.
g_canvasWidth
+
fish
.
ref
.
width
*
fish
.
ref
.
scaleX
/
2
;
fish
.
ref
.
y
=
Math
.
random
()
*
(
this
.
g_canvasHeight
*
0.6
)
+
this
.
g_canvasHeight
*
0.2
;
// 在屏幕中间区域随机高度
// 设置鱼的游动速度
fish
.
speed
=
0.3
;
//
0.5-1.5的随机速度,
降低游动速度
fish
.
speed
=
0.3
;
// 降低游动速度
// 确保鱼已添加到渲染队列中
// createFish 方法中已经调用了 render 方法,但为了确保,这里再次检查
...
...
流程.md
View file @
7b63c40f
1.
显示大图片表示:在前端显示“3个图”这种 显示小图片表示:在前端显示“4个图”这种
2.
选择的图片组成题数。
3.
鱼出现的数组在本局开始的时候就生成好, 后续的出现鱼的顺序按照这个流程来。【鱼数量上限为5,主角鱼+1】
4.
点击鱼 正确 播放音频
5.
本局开始 播放音频
6.
1.
本局开始 播放音频
2.
点击鱼 正确 播放音频
3.
获取星星表示当前进度
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment