Pārlūkot izejas kodu

feat: 完成 观察记忆训练 页面下的交互逻辑和UI页面

YuJing 2 nedēļas atpakaļ
vecāks
revīzija
541bd80dd2

+ 1 - 1
AppScope/app.json5

@@ -1,6 +1,6 @@
 {
   "app": {
-    "bundleName": "com.ytpm.ltlab",
+    "bundleName": "com.ytpm.jmzj",
     "vendor": "example",
     "versionCode": 1000000,
     "versionName": "1.0.0",

+ 3 - 3
build-profile.json5

@@ -5,11 +5,11 @@
         "name": "default",
         "material": {
           "storeFile": "sign/basic.p12",
-          "storePassword": "000000181F0EECD983295AB4504A961E19D1B5914CB198FA414395A09865788F96EFF93C84981A55",
+          "storePassword": "000000186C8C6C768E09966170A33478A0A3F425A24D6C89127FB6A923A941CEA74AA8F0E352F99C",
           "keyAlias": "yt112233",
-          "keyPassword": "0000001871572C6DAC842AAE8EF9A99F0F746307476E0F0ACF919CC12B0F81467CF5B0CCDBF97E2D",
+          "keyPassword": "00000018157D987A630DF9B0587F65242F42EE17C3CD29E75EE7DD5E0C2798F49CAE78188FFFE415",
           "signAlg": "SHA256withECDSA",
-          "profile": "sign/聊天恋爱宝调试证书.p7b",
+          "profile": "sign/军迷之家调试Debug.p7b",
           "certpath": "sign/调试证书.cer"
         }
       }

+ 204 - 0
features/feature/src/main/ets/components/observationalComp.ets

@@ -0,0 +1,204 @@
+import { observationalModel } from "../model/AnimationModel";
+
+@ComponentV2
+export struct observationalComp {
+  // 训练开始与否
+  @Param trainStarted: number = 0
+  @Event gameOver: () => void
+
+
+  @Local iconArray: Array<observationalModel> = []
+
+  // 匹配对数
+  @Local matchCount: number = 0
+  // 尝试次数
+  @Local tryCount: number = 0
+  // 是否可以翻转
+  @Local canFlip: boolean = false
+
+  // 点击的 icon
+  clickIcon: Array<number> = []
+
+  timer: number = -1
+
+  lastTime: number = 0
+
+  /**
+   * 随机打乱iconArray数组中的元素顺序 - 开始游戏
+   */
+  shuffleIconArray(): void {
+    setTimeout(() => {
+      this.flipAll(false)
+
+      const array = this.iconArray;
+      for (let i = array.length - 1; i > 0; i--) {
+        const j = Math.floor(Math.random() * (i + 1));
+        let temp = array[i]
+        array[i] = array[j]
+        array[j] = temp
+      }
+
+      if(this.timer != -1) clearTimeout(this.timer)
+      this.timer = setTimeout(() => {
+        this.flipAll(true)
+        this.timer = -1
+        this.canFlip = true
+      }, 2000)
+    }, 0)
+  }
+
+  // 翻牌  - 翻开 - 单张
+  flipCard(i: observationalModel, index: number): void {
+    let now = Date.now()
+    if(now - this.lastTime < 200) return
+    this.lastTime = now
+
+    if(!this.canFlip || !i.flip || this.trainStarted != 1) return
+    this.getUIContext().animateTo({duration: 500}, () => {
+      i.flip = false
+    })
+
+    this.clickIcon.push(index)
+    if(this.clickIcon.length == 2){
+      this.tryCount += 1
+      if(this.iconArray[this.clickIcon[0]].type  == this.iconArray[this.clickIcon[1]].type) {
+        this.matchCount += 1
+        if(this.matchCount == 4) {
+          this.gameOver()
+        }
+      } else {
+        this.canFlip = false
+        let i1 = this.clickIcon[0]
+        let i2 = this.clickIcon[1]
+        setTimeout(() => {
+          this.getUIContext().animateTo({duration: 500}, () => {
+            this.iconArray[i1].flip = true
+            this.iconArray[i2].flip = true
+            this.canFlip = true
+          })
+        }, 500)
+      }
+      this.clickIcon = []
+    }
+  }
+
+  // 翻牌  - 所有的牌
+  flipAll(flip: boolean = false) {
+    this.getUIContext().animateTo({duration: 500}, () => {
+      this.iconArray.forEach(item => {
+        item.flip = flip
+      })
+    })
+  }
+
+  @Monitor('trainStarted')
+  trainStartedChange(){
+    if(this.trainStarted == 1) {
+      this.canFlip = false
+      this.matchCount = 0
+      this.tryCount = 0
+      this.shuffleIconArray()
+    } else if(this.trainStarted == 0) {
+      if(this.timer != -1) {
+        clearTimeout(this.timer)
+        this.timer = -1
+      }
+    } else {
+      setTimeout(() => {
+        this.flipAll(false)
+      }, 0)
+      this.matchCount = 0
+      this.tryCount = 0
+    }
+  }
+
+  aboutToAppear(): void {
+    new Array(8).fill('').forEach((_: string, index) => {
+      // 需确保 文件名 没有被更改 icon_observational_%{num}
+      let tag = (index+1)%5 || 4
+      this.iconArray.push(new observationalModel($r(`app.media.icon_observational_${tag}`), false, tag))
+    })
+
+    console.log(`this.iconArray = ${JSON.stringify(this.iconArray)}`)
+  }
+
+  build() {
+    Column() {
+      Grid(){
+        Repeat(this.iconArray)
+          .each(item => {
+            GridItem(){
+              Stack(){
+                Row(){
+                  Text(`装备${item.index+1}`)
+                    .fontSize(14)
+                    .fontWeight(400)
+                    .fontColor('#FFA4A4A4')
+                }
+                .width("100%")
+                .aspectRatio(1)
+                .borderRadius(5)
+                .backgroundColor('#FF555555')
+                .justifyContent(FlexAlign.Center)
+                .alignItems(VerticalAlign.Center)
+                .zIndex(item.item.flip ? 1 : -1)
+
+                Row(){
+                  Image(item.item.src)
+                    .width("60%")
+                    .aspectRatio(1)
+                }
+                .width("100%")
+                .aspectRatio(1)
+                .borderRadius(5)
+                .backgroundColor('#FF555555')
+                .alignItems(VerticalAlign.Center)
+                .justifyContent(FlexAlign.Center)
+              }
+              .width("100%")
+              .aspectRatio(1)
+              .rotate({ y: 2, angle: item.item.flip ? 0 : 180, perspective: 200 }) // 设置组件旋转轴向量坐标和旋转角度
+              .onClick(() => { this.flipCard(item.item, item.index) })
+            }
+          })
+          .key(item => item.id.toString())
+      }
+      .width("100%")
+      .rowsGap(25)
+      .columnsGap(20)
+      .layoutWeight(1)
+      .columnsTemplate('repeat(3, 1fr)')
+
+      Row({space: 73}){
+        ForEach(['匹配对数', '尝试次数'], (item: string, index) => {
+          Column({space: 13}){
+            Text(item)
+              .fontSize(14)
+              .fontWeight(400)
+              .fontColor('#FFFFFFFF')
+
+            Text() {
+              if(index == 0) {
+                Span(`${this.matchCount}/4`)
+              } else {
+                Span(this.tryCount.toString())
+              }
+            }
+              .fontSize(14)
+              .fontWeight(400)
+              .fontColor('#FFFFFFFF')
+          }
+          .alignItems(HorizontalAlign.Center)
+        })
+      }
+      .width("100%")
+      .justifyContent(FlexAlign.Center)
+    }
+    .width("100%")
+    .height("100%")
+    .borderRadius(10)
+    .backgroundColor('#454545')
+    .justifyContent(FlexAlign.SpaceBetween)
+    .padding({top: 23, left: 18, right: 18, bottom: 30})
+  }
+}

+ 17 - 0
features/feature/src/main/ets/model/AnimationModel.ets

@@ -10,4 +10,21 @@ export class Location{
     this.x = x
     this.y = y
   }
+}
+
+@ObservedV2
+export class observationalModel{
+  @Trace src: Resource
+  // 是否翻开了
+  @Trace flip: boolean
+
+  type: number
+  id: number
+
+  constructor(src: Resource, flip: boolean, type: number) {
+    this.src = src
+    this.flip = flip
+    this.type = type
+    this.id = new Date().getTime()
+  }
 }

+ 80 - 0
features/feature/src/main/ets/pages/observationalPage.ets

@@ -0,0 +1,80 @@
+import { RouterPage } from 'basic';
+import { observationalComp } from '../components/observationalComp';
+import { _YtHeader } from '../components/YtComp/_YtHeader';
+import { observationalViewModel } from '../viewModel/PageVm/observationalViewModel';
+
+@ComponentV2
+@RouterPage
+struct observationalPage {
+  @Local vm: observationalViewModel = new observationalViewModel();
+
+  build() {
+    NavDestination() {
+      Column() {
+        _YtHeader({
+          title: '观察记忆训练',
+        })
+
+        Column(){
+          Row(){
+            Text('点击“开始训练”查看军事装备, 记住他们的位置!')
+              .fontSize(14)
+              .fontWeight(400)
+              .fontColor('#FF333333')
+          }
+          .width("100%")
+          .padding({left: 21, right: 21})
+          .justifyContent(FlexAlign.Center)
+
+          Column(){
+            observationalComp({
+              trainStarted: this.vm.trainStarted,
+              gameOver: () =>{ this.vm.trainStarted = 0 }
+            })
+          }
+          .padding({top: 23})
+          .width("100%")
+          .layoutWeight(1)
+
+          Row(){
+            Text()
+
+            Row(){
+              Text(this.vm.trainStarted ? '暂停训练' : '开始训练')
+            }
+            .borderRadius(8)
+            .padding({top: 16, left: 44, right: 44, bottom: 16})
+            .linearGradient({colors: [['#FFFFCC00', 0], ['#FFFF9F02', 0.7]], angle: 90})
+            .onClick(() => { this.vm.toggleTrain() })
+
+            Image($r('app.media.icon_reset'))
+              .width(33)
+              .aspectRatio(1)
+              .onClick(() => { this.vm.resetTrain() })
+          }
+          .width("100%")
+          .justifyContent(FlexAlign.SpaceBetween)
+          .padding({top: 18, bottom: 46, left: 37, right: 37})
+        }
+        .width("100%")
+        .layoutWeight(1)
+        .padding({top: 20})
+        .padding({left: 16, right: 16, top: 25})
+        .borderRadius({topLeft: 23, topRight: 23})
+        .backgroundColor('rgba(255, 255, 255, 0.3)')
+      }
+      .width('100%')
+      .height('100%')
+      .justifyContent(FlexAlign.Start)
+      .alignItems(HorizontalAlign.Start)
+    }
+    .hideTitleBar(true)
+    .padding({ top: this.vm.safeTop, bottom: this.vm.safeBottom })
+    .linearGradient({ colors: [['#FF7FF9C3', 0], ['#FFEEECED', 0.3]]})
+  }
+}
+
+@Builder
+function observationalBuilder() {
+  observationalPage()
+}

+ 12 - 0
features/feature/src/main/ets/view/FourView.ets

@@ -46,6 +46,18 @@ export struct FourView {
       case 0:
         yTRouter.pushPathByName('reagencyPage', null)
         break
+      case 1:
+        yTRouter.pushPathByName('stabilityPage', null)
+        break
+      case 2:
+        yTRouter.pushPathByName('observationalPage', null)
+        break
+      case 3:
+        yTRouter.pushPathByName('visionPage', null)
+        break
+      case 4:
+        yTRouter.pushPathByName('chessPage', null)
+        break
     }
   }
 

+ 43 - 0
features/feature/src/main/ets/viewModel/PageVm/observationalViewModel.ets

@@ -0,0 +1,43 @@
+import { YTAvoid, yTRouter } from "basic"
+
+@ObservedV2
+export class observationalViewModel{
+
+  @Trace safeBottom: number = 0
+  @Trace safeTop: number = 0
+  // 训练的运行状态 -1 重置 0 未开始 1 开始
+  @Trace trainStarted: number = 0
+
+  lastTime: number = 0
+
+
+  resetTrain() {
+    // 节流
+    let now = new Date().getTime()
+    if(now - this.lastTime < 800) return
+    this.lastTime = now
+
+    this.trainStarted = -1
+    setTimeout(() => {
+      this.trainStarted = 0
+    }, 10)
+  }
+
+  toggleTrain() {
+    // 节流
+    let now = new Date().getTime()
+    if(now - this.lastTime < 800) return
+    this.lastTime = now
+
+    this.trainStarted = this.trainStarted === 1 ? 0 : 1
+  }
+
+
+  constructor() {
+    this.safeTop = AppStorage.get(YTAvoid.SAFE_TOP_KEY) as number
+    this.safeBottom = AppStorage.get(YTAvoid.SAFE_BOTTOM_KEY) as number
+  }
+
+  
+
+}

BIN
features/feature/src/main/resources/base/media/icon_observational_1.png


BIN
features/feature/src/main/resources/base/media/icon_observational_2.png


BIN
features/feature/src/main/resources/base/media/icon_observational_3.png


BIN
features/feature/src/main/resources/base/media/icon_observational_4.png


+ 5 - 0
features/feature/src/main/resources/base/profile/router_map.json

@@ -14,6 +14,11 @@
       "name": "reagencyPage",
       "pageSourceFile": "src/main/ets/pages/reagencyPage.ets",
       "buildFunction": "reagencyBuilder"
+    },
+    {
+      "name": "observationalPage",
+      "pageSourceFile": "src/main/ets/pages/observationalPage.ets",
+      "buildFunction": "observationalBuilder"
     }
   ]
 }

BIN
sign/军迷之家调试Debug.p7b