mainLand.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. <template>
  2. <view class="main-land-container">
  3. <!-- <view class="scroll-container" @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd" >
  4. <view class="background" :style="{ transform: `translateX(${translateX}px)` }">
  5. <image class="island-image" src="/static/island/island.png" mode="heightFix"></image>
  6. </view>
  7. </view> -->
  8. <!-- 第三层:背景 -->
  9. <view class="background-layer"></view>
  10. <!-- 第二层:地图 -->
  11. <view class="map-layer" id="mapLayer" :style="{ transform: `translateX(${translateX}px)` }"
  12. @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd" @mousedown="onmousedown"
  13. @mousemove="onmousemove" @mouseup="onmouseup">
  14. <!-- 这里可以放置地图元素(示例:一个方块) -->
  15. <!-- <view style="position: absolute; top: 30%; left: 30%; width: 100px; height: 100px; background: green;"></view> -->
  16. <image class="island-image" src="/static/island/mainLand.png" mode="widthFix"
  17. style="width:2048rpx; bottom: 0rpx;left: 0rpx; position: absolute;"></image>
  18. <!-- <view style="position: absolute;width: 300rpx;left: 280rpx; bottom:230rpx;align-items: center;">
  19. <image class="house-image" src="/static/island/building/4.png" mode="widthFix" style="width:300rpx; position: static;" @click="onHouseClick" :animation="houseAnimationData"> </image>
  20. </view> -->
  21. <view style="position: absolute;width: 360rpx;left:782rpx; bottom:385rpx;align-items: center;">
  22. <image class="farm-image" src="/static/island/building/3.png" mode="widthFix"
  23. style="width:360rpx; position: static;" @click="onFarmClick" :animation="farmAnimationData">
  24. </image>
  25. </view>
  26. <view style="position: absolute;width: 360rpx;left: 335rpx; bottom:835rpx;align-items: center;">
  27. <image class="mine-image" src="/static/island/building/4.png" mode="widthFix"
  28. style="width:360rpx; position: static;"> </image>
  29. </view>
  30. <view style="position: absolute;width: 360rpx;left: 782rpx; bottom:720rpx;align-items: center;">
  31. <image class="hall-image" src="/static/island/building/5.png" mode="widthFix"
  32. style="width:360rpx; position: static;"> </image>
  33. </view>
  34. <view style="position: absolute;width: 360rpx;left: 248rpx; bottom:488rpx;align-items: center;">
  35. <image class="wood-image" src="/static/island/building/6.png" mode="widthFix"
  36. style="width:360rpx; position: static;"> </image>
  37. </view>
  38. <view style="position: absolute;width: 360rpx;left: 910rpx; bottom:108rpx;align-items: center;">
  39. <image class="shop-image" src="/static/island/building/2.png" mode="widthFix"
  40. style="width:360rpx; position: static;" @click="onShopClick" :animation="shopAnimationData">
  41. </image>
  42. </view>
  43. <view style="position: absolute;width: 360rpx;left: 1498rpx; bottom:75rpx;align-items: center;">
  44. <image class="airport-image" src="/static/island/building/7.png" mode="widthFix"
  45. style="width:360rpx; position: static;"> </image>
  46. </view>
  47. <view style="position: absolute;width: 360rpx;left: 1400rpx; bottom:380rpx;align-items: center;">
  48. <image class="house-image" src="/static/island/building/1.png" mode="widthFix"
  49. style="width:360rpx; position: static;" @click="onHouseClick" :animation="houseAnimationData">
  50. </image>
  51. </view>
  52. <!-- 回家箭头 -->
  53. <view class="home-arrow" @click="goHome" :animation="homeArrowAnimation"
  54. :style="{ opacity: homeArrowVisible ? 1 : 0 }">
  55. <!-- <image src="/static/island/home_arrow.png" mode="widthFix" style="width: 100rpx;"></image> -->
  56. <view class="arrow"></view>
  57. <text class="home-text">回家</text>
  58. </view>
  59. </view>
  60. <!-- 第一层:UI -->
  61. <view class="ui-layer">
  62. <view class="ui-content">
  63. <!-- 添加货币计数器 -->
  64. <view class="currency-display">
  65. <view class="currency-item">
  66. <image src="/static/island/UI/wd_icon_coin.png" mode="widthFix" class="currency-icon"></image>
  67. <text class="currency-value">{{userInfo.num_gmd}}</text>
  68. </view>
  69. <view class="currency-item">
  70. <image src="/static/island/UI/wd_icon_xingyuan.png" mode="widthFix" class="currency-icon">
  71. </image>
  72. <text class="currency-value">{{userInfo.num_gmg}}</text>
  73. </view>
  74. </view>
  75. <view class="ui-buttons">
  76. <image src="/static/island/icon_backpack.png" mode="widthFix" style="width:100rpx"
  77. @click="showInventory" class="ui-icon-button"></image>
  78. <!-- <button class="ui-button" @click="showCharacter">角色</button>
  79. <button class="ui-button" @click="showShop">商店</button> -->
  80. </view>
  81. </view>
  82. </view>
  83. <!-- 对话框组件 -->
  84. <backpack-dialog :visible.sync="inventoryVisible" @close="onInventoryClose"></backpack-dialog>
  85. <character-dialog :visible.sync="characterVisible" @close="onCharacterClose"></character-dialog>
  86. <shop-dialog :visible.sync="shopVisible" :shopName="currentShopName" @close="onShopClose"
  87. @buy="onShopBuy"></shop-dialog>
  88. <hua-tian :visible.sync="huaTianVisible" @close="onHuaTianClose" ref="huaTian"></hua-tian>
  89. <task-dialog :visible.sync="taskDialogVisible" @close="onTaskDialogClose"></task-dialog>
  90. </view>
  91. </template>
  92. <script>
  93. import BackpackDialog from '@/components/dialogs/BackpackDialog.vue'
  94. import CharacterDialog from '@/components/dialogs/CharacterDialog.vue'
  95. import ShopDialog from '@/components/dialogs/ShopDialog.vue'
  96. import HuaTian from './HuaTian.vue'
  97. import TaskDialog from './TaskDialog.vue'
  98. export default {
  99. components: {
  100. BackpackDialog,
  101. CharacterDialog,
  102. ShopDialog,
  103. HuaTian,
  104. TaskDialog
  105. },
  106. data() {
  107. return {
  108. // // 背景位置控制
  109. translateX: -200,
  110. startX: 0,
  111. currentX: 0,
  112. isDragging: false,
  113. // maxTranslate: 0,
  114. userInfo: {
  115. num_gmd: 0,
  116. num_gmg: 0,
  117. },
  118. moneyTimer: null, // 添加定时器变量
  119. // // 获取屏幕宽度和背景宽度
  120. screenWidth: 0,
  121. backgroundWidth: 0,
  122. islandHeight: 0,
  123. houseAnimationData: {},
  124. farmAnimationData: {},
  125. shopAnimationData: {},
  126. houseAnimating: false,
  127. farmAnimating: false,
  128. shopAnimating: false,
  129. baseTranslate: {
  130. x: -50,
  131. y: 50
  132. },
  133. inventoryVisible: false,
  134. characterVisible: false,
  135. shopVisible: false,
  136. huaTianVisible: false,
  137. taskDialogVisible: false,
  138. homeArrowAnimation: {},
  139. homeArrowAnimating: false,
  140. homeArrowVisible: false,
  141. currentShopName: '商店',
  142. }
  143. },
  144. onLoad() {
  145. let self = this;
  146. // 获取屏幕宽度
  147. uni.getSystemInfo({
  148. success: (res) => {
  149. self.screenWidth = res.windowWidth;
  150. console.log('屏幕宽度:', self.screenWidth);
  151. }
  152. });
  153. this.getUserMoney();
  154. // 启动定时器,每2秒更新一次铃钱
  155. this.moneyTimer = setInterval(() => {
  156. this.getUserMoney();
  157. }, 2000);
  158. },
  159. onShow() {
  160. // this.loadData();
  161. },
  162. onReady() {
  163. // 在组件渲染完成后获取图片尺寸
  164. setTimeout(() => {
  165. this.getImageSize();
  166. // 延迟1秒后显示箭头并开始动画
  167. setTimeout(() => {
  168. this.homeArrowVisible = true;
  169. this.startHomeArrowAnimation();
  170. }, 1000);
  171. }, 300);
  172. },
  173. onUnload() {
  174. // 清除定时器
  175. if (this.moneyTimer) {
  176. clearInterval(this.moneyTimer);
  177. this.moneyTimer = null;
  178. }
  179. },
  180. methods: {
  181. loadData() {
  182. // 可以在这里加载其他数据
  183. },
  184. getImageSize() {
  185. const query = uni.createSelectorQuery().in(this);
  186. query.select('.island-image').boundingClientRect(data => {
  187. if (data) {
  188. // 获取岛屿图片的宽度和高度
  189. this.backgroundWidth = data.width;
  190. this.islandHeight = data.height;
  191. // this.backgroundWidth = 1536;
  192. // this.islandHeight = 1024;
  193. // 设置背景高度为岛屿高度的两倍(在CSS中实现)
  194. // 计算最大可移动距离
  195. this.maxTranslate = this.backgroundWidth - this.screenWidth;
  196. // 初始位置居中
  197. // this.translateX = -this.maxTranslate / 2;
  198. // 打印调试信息
  199. // console.log('屏幕宽度:', this.screenWidth);
  200. // console.log('背景宽度:', this.backgroundWidth);
  201. // console.log('岛屿高度:', this.islandHeight);
  202. // console.log('屏幕宽度:',this.screenWidth);
  203. // console.log('最大可移动距离:',this.maxTranslate);
  204. // console.log('岛屿data:', data);
  205. } else {
  206. console.error('未能获取岛屿图片的尺寸');
  207. }
  208. }).exec();
  209. },
  210. // 触摸开始
  211. touchStart(e) {
  212. // console.log('----------- touchStart');
  213. this.startX = e.touches[0].clientX;
  214. this.currentX = this.translateX;
  215. console.log('this.startX =', this.startX);
  216. console.log('this.currentX =', this.currentX);
  217. },
  218. // 触摸移动
  219. touchMove(e) {
  220. console.log('----------- touchMove');
  221. const moveX = e.touches[0].clientX - this.startX;
  222. let newTranslateX = this.currentX + moveX;
  223. // 限制移动范围,不让背景两侧露出
  224. if (newTranslateX > 0) {
  225. newTranslateX = 0;
  226. } else if (newTranslateX < -this.maxTranslate) {
  227. newTranslateX = -this.maxTranslate;
  228. }
  229. this.translateX = newTranslateX;
  230. console.log('moveX =', moveX);
  231. console.log('this.translateX =', this.translateX);
  232. },
  233. // 触摸结束
  234. touchEnd() {
  235. console.log('----------- touchEnd');
  236. this.currentX = this.translateX;
  237. console.log('this.currentX =', this.currentX);
  238. },
  239. onmousedown(e) {
  240. console.log('----------- onmousedown');
  241. console.log('----------- e', e);
  242. this.isDragging = true;
  243. this.startX = e.clientX;
  244. this.currentX = this.translateX;
  245. mapLayer.style.cursor = 'grabbing';
  246. },
  247. onmousemove(e) {
  248. if (this.isDragging) {
  249. console.log('----------- onmousemove');
  250. const moveX = e.clientX - this.startX;
  251. let newTranslateX = this.currentX + moveX;
  252. //限制移动范围,不让背景两侧露出
  253. if (newTranslateX > 0) {
  254. newTranslateX = 0;
  255. } else if (newTranslateX < -this.maxTranslate) {
  256. newTranslateX = -this.maxTranslate;
  257. }
  258. this.translateX = newTranslateX;
  259. console.log('moveX =', moveX);
  260. console.log('this.translateX =', this.translateX);
  261. }
  262. },
  263. onmouseup(e) {
  264. console.log('----------- onmouseup');
  265. this.isDragging = false;
  266. mapLayer.style.cursor = 'grab';
  267. },
  268. onHouseClick(event) {
  269. if (this.houseAnimating) return;
  270. // 处理点击事件
  271. console.log('house clicked!');
  272. // 播放房屋的点击动画
  273. this.playAnimation('house');
  274. // 设置商店名称为"房屋商店"
  275. this.currentShopName = '材料商店';
  276. this.shopVisible = true;
  277. },
  278. onFarmClick(event) {
  279. if (this.farmAnimating) return;
  280. // 处理点击事件
  281. console.log('farm clicked!111');
  282. // 播放大厅的点击动画
  283. this.playAnimation('farm');
  284. // 打开花田对话框
  285. this.huaTianVisible = true;
  286. // 将mainLand传递给HuaTian组件
  287. this.$refs.huaTian && this.$refs.huaTian.setMainLand(this);
  288. },
  289. onShopClick(event) {
  290. if (this.shopAnimating) return;
  291. // 处理点击事件
  292. console.log('shop clicked!');
  293. // 播放商店的点击动画
  294. this.playAnimation('shop');
  295. // 设置商店名称为"花店"
  296. this.currentShopName = '花店';
  297. // 打开商店对话框
  298. this.shopVisible = true;
  299. },
  300. playAnimation(type) {
  301. let self = this;
  302. // 根据类型设置对应的动画状态
  303. if (type === 'house') {
  304. this.houseAnimating = true;
  305. } else if (type === 'farm') {
  306. this.farmAnimating = true;
  307. } else if (type === 'shop') {
  308. this.shopAnimating = true;
  309. }
  310. // 创建动画实例
  311. const animation = uni.createAnimation({
  312. duration: 400,
  313. timingFunction: 'ease',
  314. });
  315. // 定义果冻动画序列
  316. animation.scale(0.95).step({
  317. duration: 100
  318. })
  319. .scale(1.05).step({
  320. duration: 100
  321. })
  322. .scale(0.98).step({
  323. duration: 100
  324. })
  325. .scale(1).step({
  326. duration: 100
  327. });
  328. // 根据类型应用动画到对应的元素
  329. if (type === 'house') {
  330. this.houseAnimationData = animation.export();
  331. } else if (type === 'farm') {
  332. this.farmAnimationData = animation.export();
  333. } else if (type === 'shop') {
  334. this.shopAnimationData = animation.export();
  335. }
  336. // 动画结束后重置状态
  337. setTimeout(() => {
  338. if (type === 'house') {
  339. self.houseAnimating = false;
  340. } else if (type === 'farm') {
  341. self.farmAnimating = false;
  342. } else if (type === 'shop') {
  343. self.shopAnimating = false;
  344. }
  345. }, 800);
  346. },
  347. showInventory() {
  348. console.log('Opening inventory...')
  349. this.inventoryVisible = true
  350. },
  351. onInventoryClose() {
  352. console.log('Closing inventory...')
  353. this.inventoryVisible = false
  354. },
  355. showCharacter() {
  356. console.log('Opening character...')
  357. this.characterVisible = true
  358. },
  359. onCharacterClose() {
  360. console.log('Closing character...')
  361. this.characterVisible = false
  362. },
  363. showShop() {
  364. console.log('Opening shop...')
  365. this.shopVisible = true
  366. },
  367. onShopClose() {
  368. console.log('Closing shop...')
  369. this.shopVisible = false
  370. },
  371. onShopBuy(item) {
  372. console.log('Buying item:', item)
  373. },
  374. onHuaTianClose() {
  375. console.log('Closing hua tian dialog...')
  376. this.huaTianVisible = false
  377. },
  378. startHomeArrowAnimation() {
  379. if (this.homeArrowAnimating) return;
  380. this.homeArrowAnimating = true;
  381. const animation = uni.createAnimation({
  382. duration: 1000,
  383. timingFunction: 'ease-in-out',
  384. });
  385. const animate = () => {
  386. if (!this.homeArrowAnimating) return;
  387. animation.translateY(-20).step({
  388. duration: 1000
  389. });
  390. this.homeArrowAnimation = animation.export();
  391. setTimeout(() => {
  392. animation.translateY(0).step({
  393. duration: 1000
  394. });
  395. this.homeArrowAnimation = animation.export();
  396. setTimeout(() => {
  397. if (this.homeArrowAnimating) {
  398. animate();
  399. }
  400. }, 1000);
  401. }, 1000);
  402. };
  403. animate();
  404. },
  405. goHome() {
  406. uni.navigateTo({
  407. url: '/pages/isLand/homeLand'
  408. });
  409. },
  410. // 打开任务对话框
  411. onTaskClick() {
  412. console.log('Opening task dialog...')
  413. this.taskDialogVisible = true
  414. },
  415. // 关闭任务对话框
  416. onTaskDialogClose() {
  417. console.log('Closing task dialog...')
  418. this.taskDialogVisible = false
  419. },
  420. // 获取用户铃钱
  421. getUserMoney() {
  422. uni.request({
  423. url: this.$apiHost + '/User/getinfo',
  424. method: 'GET',
  425. data: {
  426. uuid: getApp().globalData.uuid
  427. },
  428. header: {
  429. 'Content-Type': 'application/x-www-form-urlencoded',
  430. 'sign': getApp().globalData.headerSign,
  431. },
  432. success: (res) => {
  433. if (res.data) {
  434. console.log("res.getUserMoney", res.data)
  435. this.userInfo = res.data;
  436. }
  437. }
  438. })
  439. },
  440. }
  441. }
  442. </script>
  443. <style lang="scss" scoped>
  444. @import './mainLand.scss';
  445. .ui-layer {
  446. position: fixed;
  447. top: 0;
  448. left: 0;
  449. right: 0;
  450. bottom: 0;
  451. pointer-events: none;
  452. z-index: 100;
  453. .ui-content {
  454. position: absolute;
  455. top: 20rpx;
  456. right: 20rpx;
  457. pointer-events: auto;
  458. z-index: 101;
  459. }
  460. .ui-buttons {
  461. display: flex;
  462. flex-direction: column;
  463. gap: 20rpx;
  464. .ui-icon-button {
  465. transition: transform 0.2s ease;
  466. &:active {
  467. transform: scale(0.9);
  468. opacity: 0.8;
  469. }
  470. }
  471. .ui-button {
  472. // background: rgba(255, 255, 255, 0.9);
  473. // border: none;
  474. width: 120rpx;
  475. padding: 16rpx 32rpx;
  476. border-radius: 8rpx;
  477. font-size: 28rpx;
  478. color: #333;
  479. // box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
  480. min-width: 120rpx;
  481. &:active {
  482. opacity: 0.8;
  483. transform: scale(0.95);
  484. }
  485. }
  486. .backpack-button {
  487. background-image: url('/static/island/icon_backpack.png');
  488. background-size: cover;
  489. background-position: center;
  490. background-repeat: no-repeat;
  491. }
  492. }
  493. }
  494. .map-layer {
  495. position: relative;
  496. z-index: 1;
  497. cursor: grab;
  498. &:active {
  499. cursor: grabbing;
  500. }
  501. }
  502. .home-arrow {
  503. // background: rgba(255, 255, 255, 0.9);
  504. position: absolute;
  505. left: 40rpx; // 调整到左边位置
  506. bottom: 460rpx;
  507. display: flex;
  508. flex-direction: column;
  509. align-items: center;
  510. cursor: pointer;
  511. z-index: 10;
  512. transition: opacity 0.5s ease-in-out; // 添加淡入效果
  513. .arrow {
  514. content: '';
  515. display: block;
  516. width: 60rpx;
  517. height: 60rpx;
  518. background: url('/static/island/arrow.png') no-repeat center center;
  519. background-size: contain;
  520. transform: rotate(90deg);
  521. }
  522. .home-text {
  523. color: #ffffff;
  524. font-size: 32rpx;
  525. text-shadow: 2rpx 2rpx 4rpx rgba(0, 0, 0, 0.5);
  526. margin-top: 10rpx;
  527. }
  528. }
  529. </style>