game_model.dart 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. import 'dart:math';
  2. import 'package:assets_audio_player/assets_audio_player.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:get/get.dart';
  5. import 'package:trackoffical_app/generated/assets.dart';
  6. import 'package:trackoffical_app/global.dart';
  7. import 'package:trackoffical_app/service/app.dart';
  8. import 'package:trackoffical_app/utils.dart';
  9. import '../../model/game_state.dart';
  10. import '../../model/m_control_point.dart';
  11. import '../../model/m_position.dart';
  12. import 'package:sensor/sensor.dart' as sensor;
  13. import '../../model/map_mode.dart';
  14. import '../../widget/matrix_gesture_detector.dart';
  15. import 'package:trackoffical_app/appcore/ffi.dart' as ffi;
  16. class GameModel{
  17. DateTime? get startAt {
  18. final save = gameSrcState.value.pbGameSave;
  19. return save.hasStartAt()? save.startAt.toModel(): null;
  20. }
  21. DateTime? get endAt {
  22. final save = gameSrcState.value.pbGameSave;
  23. if(save.hasStopAt()){
  24. if(save.stopAt.seconds==0){
  25. return null;
  26. }
  27. return save.stopAt.toModel();
  28. }
  29. return null;
  30. }
  31. final mapTransformMatrix = Matrix4.identity().obs;
  32. bool get isStarted => startAt != null;
  33. bool get isFinish => endAt != null;
  34. final compassDiameter = 160.0.obs;
  35. final myPositionHistory = <MPosition>[].obs;
  36. final myPositionHistoryTmp = <MPosition>[];
  37. final speedMPreS = 0.0.obs;
  38. final isWalking = false.obs;
  39. Rx<MPosition?> get myPosition => App.to.position;
  40. final Rx<Offset?> myPositionOnMap = Rx(null);
  41. final heartRate = 0.obs;
  42. final heartRatePercent = 0.0.obs;
  43. final ei = 0.0.obs;
  44. final ck = 0.0.obs;
  45. final kCal = 0.0.obs;
  46. final exerciseKcal = 0.0.obs;
  47. final hrMean = 0.obs;
  48. final hrMax = 0.obs;
  49. final stepCount = 0.obs;
  50. /// 指北针弧度,移动时通过GPS判断
  51. final compassRadiansFused = 0.0.obs;
  52. final compassRadiansSrc = 0.0.obs;
  53. final orientation = sensor.Orientation().obs;
  54. final mapMode = MapMode.compass.obs;
  55. Offset? mapRotateCenter;
  56. var isAlwaysShowMyLocation = true;
  57. var isEnableMyLocation = true;
  58. /// 用户设置是否锁定旋转中心
  59. final isLockScreenCenterToMyPosition = false.obs;
  60. bool get isLockScreenCenterToMyPositionSystem =>
  61. isLockScreenCenterToMyPosition.value
  62. && isEnableUserLocation;
  63. var accelerometerEvent = sensor.Orientation();
  64. var isMoving = false;
  65. final Rx<ffi.ZoneType?> zone = Rx(null);
  66. final _isEnableUserLocation = App.to.userProfile.isEnableUserLocation.val.obs;
  67. bool get isEnableUserLocation => _isEnableUserLocation.value;
  68. set isEnableUserLocation(v){
  69. _isEnableUserLocation.value = v;
  70. App.to.userProfile.isEnableUserLocation.val =v;
  71. }
  72. /// 虚拟点打点有效半径冗余
  73. static const controlPointEffectiveAreaRadiusKmOffset=0.002;
  74. /// 虚拟点打点有效半径
  75. double get controlPointEffectiveAreaRadiusKm =>
  76. GlobalVar.isGpsTest? 100:
  77. gameSrcState.value.pbGameData.vcpRadius.toDouble()/1000
  78. + controlPointEffectiveAreaRadiusKmOffset;
  79. /// 是否允许在开始点前预览所有点
  80. bool get isAllowPreviewControlPoint => gameSrcState.value.pbGameData.isPreview;
  81. /// 是否允许显示地图
  82. bool get isShowMap => gameSrcState.value.pbGameData.isShowMap;
  83. /// 是否允许跳点
  84. bool get isAllowedPassCP => gameSrcState.value.pbGameData.maxPassPoint > 0;
  85. final trajectoryPoints = <Offset>[].obs;
  86. /// 用户选项是否显示轨迹
  87. final isShowTrajectory = true.obs;
  88. bool get isDrawTrajectory => isShowTrajectory.value && isEnableUserLocation;
  89. final controlPointWantSequence = <MControlPoint>[].obs;
  90. final myPositionHistoryLen = 0.meter.obs;
  91. final gameSrcState = GameState().obs;
  92. bool get isUseRealNorth => App.to.userProfile.isCompassUseRealNorth.val;
  93. set isUseRealNorth(v){ App.to.userProfile.isCompassUseRealNorth.val = v; }
  94. var compassRealNorthOffset = 0.0;
  95. var deviceSpeed = 0.0;
  96. Duration get gameQuestionShowDuration => gameSrcState.value.pbGameData.oiShowTime.seconds;
  97. Distance get myPositionHistoryLenFromLastCP{
  98. if(checkedPointsHistory.isEmpty){
  99. return myPositionHistoryLen.value;
  100. }
  101. final cp = checkedPointsHistory.last;
  102. return myPositionHistoryLen.value - cp.checkDistanceAfterStart;
  103. }
  104. Duration get startedDuration{
  105. final b = startAt;
  106. if(b!= null){
  107. return App.to.now.difference(b);
  108. }
  109. return 0.seconds;
  110. }
  111. final paceSecondKm = 0.seconds.obs;
  112. final paceSecondKmFromLastCP = 0.seconds.obs;
  113. final checkedPointsHistory = <MControlPoint>[].obs;
  114. int get checkedCount {
  115. var i = 0;
  116. for (var one in gameSrcState.value.pbGameSave.checkedSortedList) {
  117. if (one.isCheckSuccess) {
  118. i++;
  119. }
  120. }
  121. return i;
  122. }
  123. final Rx<int?> nextPlanPointIndex=Rx(null);
  124. int get validCPCount{
  125. var cpChecked = checkedCount;
  126. if(cpChecked < 0){
  127. cpChecked = 0;
  128. }
  129. return cpChecked;
  130. }
  131. // 所有计分点数量
  132. int get validCPAllNum{
  133. return controlPointWantSequence.length;
  134. }
  135. // 打卡进度
  136. double get checkProgress {
  137. if (controlPointWantSequence.isEmpty) {
  138. return 0;
  139. }
  140. return (checkedCount).toDouble() / (controlPointWantSequence.length);
  141. }
  142. MControlPoint? getNextWantPoint(int offset){
  143. final i = checkedCount + offset;
  144. return controlPointWantSequence.length > i?
  145. controlPointWantSequence[i] : null;
  146. }
  147. MControlPoint? get nextPlanPoint{
  148. final i = nextPlanPointIndex.value;
  149. if(i==null){
  150. return getNextWantPoint(0);
  151. }
  152. return controlPointWantSequence.length > i?
  153. controlPointWantSequence[i] : null;
  154. }
  155. set nextPlanPoint(MControlPoint? v){
  156. if(v==null){
  157. nextPlanPointIndex.value=null;
  158. return;
  159. }
  160. for(var i=0;i<controlPointWantSequence.length;i++ ){
  161. if(v.intId==controlPointWantSequence[i].intId){
  162. if(i < checkedCount){
  163. return;
  164. }
  165. nextPlanPointIndex.value=i;
  166. AssetsAudioPlayer.newPlayer().open(
  167. Audio(Assets.soundCpJump),
  168. autoStart: true,
  169. showNotification: false
  170. );
  171. return;
  172. }
  173. }
  174. }
  175. bool get isInWantControlPointArea {
  176. final p = getNextWantPoint(0);
  177. if(p != null){
  178. final disKm = nextWantCPDistanceKm;
  179. if(disKm != null && p.type == MControlPointType.gps){
  180. return disKm <= controlPointEffectiveAreaRadiusKm.km;
  181. }
  182. }
  183. return false;
  184. }
  185. bool get isInPlanControlPointArea {
  186. final p = nextPlanPoint;
  187. if(p != null){
  188. final disKm = nextPlanCPDistanceKm;
  189. if(disKm != null && p.type == MControlPointType.gps){
  190. return disKm <= controlPointEffectiveAreaRadiusKm.km;
  191. }
  192. }
  193. return false;
  194. }
  195. Distance? get nextWantCPDistanceKm{
  196. final p1 = myPosition.value;
  197. final p2 = getNextWantPoint(0)?.position;
  198. if(p1 != null && p2 != null){
  199. return p2.distance(p1);
  200. }
  201. return null;
  202. }
  203. Distance? get nextPlanCPDistanceKm{
  204. final p1 = myPosition.value;
  205. final p2 = nextPlanPoint?.position;
  206. if(p1 != null && p2 != null){
  207. return p2.distance(p1);
  208. }
  209. return null;
  210. }
  211. double get compassPlantRadian {
  212. if(mapMode.value == MapMode.compass){
  213. return compassRadiansFused.value;
  214. }
  215. final ogRm = mapTransformMatrix.value.clone();
  216. double radian = MatrixGestureDetector.decomposeToValues(ogRm).rotation;
  217. return radian;
  218. }
  219. int get compassShowDegrees{
  220. var d1 = -( compassPlantRadian - compassRadiansFused.value);
  221. if(mapMode.value == MapMode.compass){
  222. d1 = -compassPlantRadian;
  223. }
  224. var d = d1 *180~/pi;
  225. while(d < 0){
  226. d+=360;
  227. }
  228. while(d > 360){
  229. d-=360;
  230. }
  231. return d;
  232. }
  233. void setRotateCenterToScreenCenter(){
  234. final screenCenter =
  235. Offset(App.to.screenSize.width / 2, App.to.screenSize.height / 2);
  236. mapRotateCenter = screenCenter;
  237. }
  238. void clear(){
  239. gameSrcState.value = GameState();
  240. myPositionHistory.clear();
  241. myPositionHistoryTmp.clear();
  242. checkedPointsHistory.clear();
  243. controlPointWantSequence.clear();
  244. myPositionOnMap.value = null;
  245. heartRate.value = 0;
  246. heartRatePercent.value = 0;
  247. ei.value = 0;
  248. ck.value = 0;
  249. myPositionHistoryLen.value = 0.meter;
  250. nextPlanPointIndex.value=null;
  251. }
  252. }