game_person_data.dart 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. import 'dart:math';
  2. import 'package:get/get.dart';
  3. import 'package:trackoffical_app/appcore/ffi.dart' as ffi;
  4. import 'package:trackoffical_app/logger.dart';
  5. import 'package:trackoffical_app/model.dart';
  6. import 'package:trackoffical_app/service/app.dart';
  7. import 'package:trackoffical_app/service/image.dart';
  8. import 'package:trackoffical_app/utils.dart';
  9. import 'package:flutter/material.dart';
  10. import '../generated/assets.dart';
  11. import '../global.dart';
  12. import 'game_map.dart';
  13. import 'm_control_point.dart';
  14. import 'package:trackoffical_app/pb.dart' as pb;
  15. typedef MControlPointInProject = pb.ControlPointSimple;
  16. class GamePersonData {
  17. var userId = -1;
  18. var userName = '';
  19. var userHead = MNetImage().obs;
  20. final duration = 0.seconds.obs;
  21. final gameSrcState = GameState().obs;
  22. DateTime? get startAt {
  23. final save = gameSrcState.value.pbGameSave;
  24. if (save.hasStartAt()) {
  25. if (save.startAt.seconds == 0) {
  26. return null;
  27. }
  28. return save.startAt.toModel();
  29. }
  30. return null;
  31. }
  32. DateTime? get endAt {
  33. final save = gameSrcState.value.pbGameSave;
  34. if (save.hasStopAt()) {
  35. if (save.stopAt.seconds == 0) {
  36. return null;
  37. }
  38. return save.stopAt.toModel();
  39. }
  40. return null;
  41. }
  42. final controlPointWantSequence = <MControlPoint>[].obs;
  43. final checkedPointsHistory = <MControlPoint>[].obs;
  44. final myPositionHistory = <MPosition>[].obs;
  45. MPosition? get myPosition =>
  46. myPositionHistory.isEmpty ? null : myPositionHistory.last;
  47. final myPositionOnMapHistory = <Offset>[].obs;
  48. Offset? get myPositionOnMap =>
  49. myPositionOnMapHistory.isEmpty ? null : myPositionOnMapHistory.last;
  50. final heartRate = 0.obs;
  51. final heartRatePercent = 0.0.obs;
  52. final ei = 0.0.obs;
  53. final ck = 0.0.obs;
  54. final kCal = 0.0.obs;
  55. final exerciseKcal = 0.0.obs;
  56. final hrMean = 0.obs;
  57. final hrMax = 0.obs;
  58. final stepCount = 0.obs;
  59. final pacePerKm = 0.seconds.obs;
  60. final myPositionHistoryLen = 0.0.meter.obs;
  61. final speedPreSecond = 0.meter.obs;
  62. Distance get myPositionHistoryLenFromLastCP {
  63. if (checkedPointsHistory.isEmpty) {
  64. return myPositionHistoryLen.value;
  65. }
  66. final cp = checkedPointsHistory.last;
  67. return myPositionHistoryLen.value - cp.checkDistanceAfterStart;
  68. }
  69. // 百味豆
  70. final beanCount = 0.obs;
  71. final paceSecondKm = 0.seconds.obs;
  72. final paceSecondKmFromLastCP = 0.seconds.obs;
  73. final Rx<ffi.ZoneType?> zone = Rx(null);
  74. // 打点误差
  75. Distance get _punchRadiusError =>
  76. App.to.userProfile.gameSettingsTargetErrorMeter.value.meter;
  77. // 打点半径
  78. Distance get _punchRadius => GlobalVar.isGpsTest
  79. ? 100.km
  80. : App.to.userProfile.gameSettingsPunchRadiusMeter.value.meter +
  81. _punchRadiusError;
  82. int get checkedCount {
  83. var i = 0;
  84. for (var one in gameSrcState.value.pbGameSave.checkedSortedList) {
  85. if (one.isCheckSuccess) {
  86. i++;
  87. }
  88. }
  89. return i;
  90. }
  91. final Rx<int?> nextPlanPointIndex = Rx(null);
  92. // 所有计分点数量
  93. int get validCPAllNum {
  94. return controlPointWantSequence.length;
  95. }
  96. bool get isStarted => startAt != null;
  97. bool get isFinish => endAt != null;
  98. Future<void> cpWantSequenceRefresh(
  99. GameMap gameMap, {
  100. void Function(double count, double total)? onProgress,
  101. bool loadPic = false,
  102. }) async {
  103. if (gameMap.width == 0 && gameMap.height == 0) {
  104. return;
  105. }
  106. final out = <MControlPoint>[];
  107. final checkedIndex = checkedCount;
  108. final controlPointWantSequenceSrc =
  109. gameSrcState.value.pbGameData.controlPointSortedList;
  110. for (var i = 0; i < controlPointWantSequenceSrc.length; i++) {
  111. final value = controlPointWantSequenceSrc[i];
  112. final one = value.toModel();
  113. one.sn = '$i';
  114. if (i == 0) {
  115. one.isStart = true;
  116. }
  117. if (i == controlPointWantSequenceSrc.length - 1) {
  118. one.isFinish = true;
  119. }
  120. one.isSuccess = i < checkedIndex;
  121. one.isNext = i == checkedIndex;
  122. one.onMap = await gameMap.worldToPixel(value.mapPosition.toModel());
  123. final extraInfo = one.extraInfo;
  124. if ((extraInfo is CPExtraInfoChoiceQuestion) && loadPic) {
  125. extraInfo.beanCount = gameSrcState.value.pbGameData.answerSysPoint;
  126. try {
  127. await extraInfo.image?.loadMemory();
  128. } catch (e) {
  129. warn('加载问题图片失败:$e');
  130. }
  131. }
  132. out.add(one);
  133. onProgress?.call(
  134. i.toDouble(), controlPointWantSequenceSrc.length.toDouble());
  135. }
  136. controlPointWantSequence.value = out;
  137. }
  138. Future<void> initControlPointWantSequence(
  139. GameMap gameMap, {
  140. void Function(double count, double total)? onProgress,
  141. bool loadPic = false,
  142. }) async {
  143. if (controlPointWantSequence.isNotEmpty) {
  144. return;
  145. }
  146. await cpWantSequenceRefresh(gameMap,
  147. onProgress: onProgress, loadPic: loadPic);
  148. }
  149. MControlPoint? findCPWantByNfcId(String identifier) {
  150. MControlPoint? found;
  151. for (var one in gameSrcState.value.pbGameData.controlPointSortedList) {
  152. for (var nfcId in one.nfcIdList) {
  153. if (nfcId.toUpperCase() == identifier.toUpperCase()) {
  154. found = one.toModel();
  155. break;
  156. }
  157. }
  158. }
  159. return found;
  160. }
  161. MControlPointInProject? findCPInProjectByNfcId(String identifier) {
  162. for (var one in gameSrcState.value.pbGameData.controlPointAll) {
  163. for (var nfcId in one.nfcIdList) {
  164. if (nfcId.toUpperCase() == identifier.toUpperCase()) {
  165. return one;
  166. }
  167. }
  168. }
  169. return null;
  170. }
  171. MControlPoint? findCPInRoute(MControlPoint point) {
  172. MControlPoint? found;
  173. for (var one in controlPointWantSequence) {
  174. if (one.intId == point.intId) {
  175. found = one;
  176. break;
  177. }
  178. }
  179. return found;
  180. }
  181. void checkHistoryAdd(MControlPoint cp) {
  182. checkedPointsHistory.add(cp);
  183. gameSrcState.value.pbGameSave.checkedSortedList.add(cp.toPbSave());
  184. }
  185. void updateCheckHistory(){
  186. gameSrcState.value.pbGameSave.checkedSortedList.clear();
  187. gameSrcState.value.pbGameSave.checkedSortedList.addAll(checkedPointsHistory.map((e) => e.toPbSave()).toList());
  188. }
  189. MControlPoint? get nextWantPoint {
  190. final i = checkedCount;
  191. return controlPointWantSequence.length > i
  192. ? controlPointWantSequence[i]
  193. : null;
  194. }
  195. Duration get gameQuestionShowDuration => gameSrcState.value.pbGameData.oiShowTime.seconds;
  196. Distance? get nextWantCPDistance {
  197. final p1 = myPosition;
  198. final p2 = nextWantPoint?.position;
  199. if (p1 != null && p2 != null) {
  200. return p2.distance(p1);
  201. }
  202. return null;
  203. }
  204. Distance? get nextWantCPDistanceKmShow {
  205. final real = nextWantCPDistance;
  206. if (real == null) {
  207. return null;
  208. }
  209. var show = real - _punchRadiusError;
  210. if (show < 0.meter) {
  211. show = 0.meter;
  212. }
  213. return show;
  214. }
  215. Distance? get nextPlanCPDistance{
  216. final p1 = myPosition;
  217. final p2 = nextPlanPoint?.position;
  218. if(p1 != null && p2 != null){
  219. return p2.distance(p1);
  220. }
  221. return null;
  222. }
  223. Distance? get nextPlanCPDistanceKmShow{
  224. final real = nextPlanCPDistance;
  225. if(real == null){
  226. return null;
  227. }
  228. var show = real - _punchRadiusError;
  229. if(show < 0 .meter){
  230. show = 0.meter;
  231. }
  232. return show;
  233. }
  234. double get compassRealNorthOffset=>gameSrcState.value.pbGameData.declination * pi / 180;
  235. set nextPlanPoint(MControlPoint? v){
  236. if(startAt==null){
  237. return;
  238. }
  239. if(v==null){
  240. nextPlanPointIndex.value=null;
  241. return;
  242. }
  243. for(var i=0;i<controlPointWantSequence.length;i++ ){
  244. if(v.intId==controlPointWantSequence[i].intId){
  245. if(i < checkedCount){
  246. return;
  247. }
  248. nextPlanPointIndex.value=i;
  249. App.to.soundPlayAsset(Assets.soundCpJump);
  250. return;
  251. }
  252. }
  253. }
  254. MControlPoint? get nextPlanPoint{
  255. final i = nextPlanPointIndex.value;
  256. if(i==null){
  257. return nextWantPoint;
  258. }
  259. return controlPointWantSequence.length > i?
  260. controlPointWantSequence[i] : null;
  261. }
  262. bool get isInWantControlPointArea {
  263. final p = nextWantPoint;
  264. if(p != null){
  265. final disKm = nextWantCPDistance;
  266. if(disKm != null && p.type == MControlPointType.gps){
  267. return disKm <= _punchRadius;
  268. }
  269. }
  270. return false;
  271. }
  272. bool get isInPlanControlPointArea {
  273. final p = nextPlanPoint;
  274. if(p != null){
  275. final disKm = nextPlanCPDistance;
  276. if(disKm != null && p.type == MControlPointType.gps){
  277. return disKm <= _punchRadius;
  278. }
  279. }
  280. return false;
  281. }
  282. }