GameView.qml 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. import QtQuick 2.15
  2. import QtQuick.Controls 2.15
  3. import StandardOfIron 1.0
  4. Item {
  5. id: gameView
  6. property bool isPaused: false
  7. property real gameSpeed: 1
  8. property bool setRallyMode: false
  9. property string cursorMode: "normal"
  10. property var pressedKeys: ({
  11. })
  12. signal mapClicked(real x, real y)
  13. signal unitSelected(int unitId)
  14. signal areaSelected(real x1, real y1, real x2, real y2)
  15. function setPaused(paused) {
  16. isPaused = paused;
  17. if (typeof game !== 'undefined' && game.setPaused)
  18. game.setPaused(paused);
  19. }
  20. function setGameSpeed(speed) {
  21. gameSpeed = speed;
  22. if (typeof game !== 'undefined' && game.setGameSpeed)
  23. game.setGameSpeed(speed);
  24. }
  25. function issueCommand(command) {
  26. console.log("Command issued:", command);
  27. }
  28. objectName: "GameView"
  29. Keys.onPressed: function(event) {
  30. if (typeof game === 'undefined')
  31. return ;
  32. var yawStep = (event.modifiers & Qt.ShiftModifier) ? 8 : 4;
  33. var inputStep = (event.modifiers & Qt.ShiftModifier) ? 2 : 1;
  34. var shiftHeld = (event.modifiers & Qt.ShiftModifier) !== 0;
  35. switch (event.key) {
  36. case Qt.Key_Escape:
  37. if (typeof mainWindow !== 'undefined' && !mainWindow.menuVisible) {
  38. mainWindow.menuVisible = true;
  39. event.accepted = true;
  40. }
  41. break;
  42. case Qt.Key_Space:
  43. if (typeof mainWindow !== 'undefined') {
  44. mainWindow.gamePaused = !mainWindow.gamePaused;
  45. gameView.setPaused(mainWindow.gamePaused);
  46. event.accepted = true;
  47. }
  48. break;
  49. case Qt.Key_W:
  50. beginPanKey(event);
  51. game.cameraMove(0, inputStep);
  52. ensurePanTimerRunning();
  53. event.accepted = true;
  54. break;
  55. case Qt.Key_S:
  56. if (game.hasUnitsSelected && !shiftHeld) {
  57. if (game.onStopCommand)
  58. game.onStopCommand();
  59. event.accepted = true;
  60. } else {
  61. beginPanKey(event);
  62. game.cameraMove(0, -inputStep);
  63. ensurePanTimerRunning();
  64. event.accepted = true;
  65. }
  66. break;
  67. case Qt.Key_A:
  68. if (game.hasUnitsSelected && !shiftHeld) {
  69. game.cursorMode = "attack";
  70. event.accepted = true;
  71. } else {
  72. beginPanKey(event);
  73. game.cameraMove(-inputStep, 0);
  74. ensurePanTimerRunning();
  75. event.accepted = true;
  76. }
  77. break;
  78. case Qt.Key_D:
  79. beginPanKey(event);
  80. game.cameraMove(inputStep, 0);
  81. ensurePanTimerRunning();
  82. event.accepted = true;
  83. break;
  84. case Qt.Key_M:
  85. if (game.hasUnitsSelected) {
  86. game.cursorMode = "normal";
  87. event.accepted = true;
  88. }
  89. break;
  90. case Qt.Key_Up:
  91. beginPanKey(event);
  92. game.cameraMove(0, inputStep);
  93. ensurePanTimerRunning();
  94. event.accepted = true;
  95. break;
  96. case Qt.Key_Down:
  97. beginPanKey(event);
  98. game.cameraMove(0, -inputStep);
  99. ensurePanTimerRunning();
  100. event.accepted = true;
  101. break;
  102. case Qt.Key_Left:
  103. beginPanKey(event);
  104. game.cameraMove(-inputStep, 0);
  105. ensurePanTimerRunning();
  106. event.accepted = true;
  107. break;
  108. case Qt.Key_Right:
  109. beginPanKey(event);
  110. game.cameraMove(inputStep, 0);
  111. ensurePanTimerRunning();
  112. event.accepted = true;
  113. break;
  114. case Qt.Key_Q:
  115. game.cameraYaw(-yawStep);
  116. event.accepted = true;
  117. break;
  118. case Qt.Key_E:
  119. game.cameraYaw(yawStep);
  120. event.accepted = true;
  121. break;
  122. case Qt.Key_R:
  123. game.cameraOrbitDirection(1, shiftHeld);
  124. event.accepted = true;
  125. break;
  126. case Qt.Key_F:
  127. game.cameraOrbitDirection(-1, shiftHeld);
  128. event.accepted = true;
  129. break;
  130. case Qt.Key_X:
  131. if (game.selectAllTroops)
  132. game.selectAllTroops();
  133. event.accepted = true;
  134. break;
  135. case Qt.Key_P:
  136. if (game.hasUnitsSelected) {
  137. game.cursorMode = "patrol";
  138. event.accepted = true;
  139. }
  140. break;
  141. case Qt.Key_H:
  142. if (game.hasUnitsSelected && game.onHoldCommand) {
  143. game.onHoldCommand();
  144. event.accepted = true;
  145. }
  146. break;
  147. }
  148. }
  149. function beginPanKey(e) {
  150. if (!e.isAutoRepeat && !pressedKeys[e.key]) {
  151. pressedKeys[e.key] = true;
  152. renderArea.keyPanCount += 1;
  153. mainWindow.edgeScrollDisabled = true;
  154. }
  155. }
  156. function ensurePanTimerRunning() {
  157. if (!keyPanTimer.running)
  158. keyPanTimer.start();
  159. }
  160. Keys.onReleased: function(event) {
  161. if (typeof game === 'undefined')
  162. return ;
  163. var movementKeys = [Qt.Key_W, Qt.Key_A, Qt.Key_S, Qt.Key_D, Qt.Key_Up, Qt.Key_Down, Qt.Key_Left, Qt.Key_Right];
  164. if (movementKeys.indexOf(event.key) !== -1) {
  165. if (pressedKeys[event.key]) {
  166. pressedKeys[event.key] = false;
  167. renderArea.keyPanCount = Math.max(0, renderArea.keyPanCount - 1);
  168. }
  169. var anyHeld = false;
  170. for (var k in pressedKeys) {
  171. if (pressedKeys[k]) {
  172. anyHeld = true;
  173. break;
  174. }
  175. }
  176. if (!anyHeld) {
  177. if (keyPanTimer.running)
  178. keyPanTimer.stop();
  179. if (renderArea.keyPanCount === 0 && !renderArea.mousePanActive)
  180. mainWindow.edgeScrollDisabled = false;
  181. }
  182. }
  183. if (event.key === Qt.Key_Shift) {
  184. if (renderArea.keyPanCount === 0 && !renderArea.mousePanActive)
  185. mainWindow.edgeScrollDisabled = false;
  186. }
  187. }
  188. focus: true
  189. Timer {
  190. id: keyPanTimer
  191. interval: 16
  192. repeat: true
  193. running: false
  194. onTriggered: {
  195. if (typeof game === 'undefined')
  196. return ;
  197. var step = (Qt.inputModifiers & Qt.ShiftModifier) ? 2 : 1;
  198. var dx = 0;
  199. var dz = 0;
  200. if (pressedKeys[Qt.Key_W] || pressedKeys[Qt.Key_Up])
  201. dz += step;
  202. if (pressedKeys[Qt.Key_S] || pressedKeys[Qt.Key_Down])
  203. dz -= step;
  204. if (pressedKeys[Qt.Key_A] || pressedKeys[Qt.Key_Left])
  205. dx -= step;
  206. if (pressedKeys[Qt.Key_D] || pressedKeys[Qt.Key_Right])
  207. dx += step;
  208. if (dx !== 0 || dz !== 0)
  209. game.cameraMove(dx, dz);
  210. }
  211. }
  212. GLView {
  213. id: renderArea
  214. property int keyPanCount: 0
  215. property bool mousePanActive: false
  216. anchors.fill: parent
  217. engine: game
  218. focus: false
  219. Component.onCompleted: {
  220. if (typeof game !== 'undefined' && game.cursorMode)
  221. gameView.cursorMode = game.cursorMode;
  222. }
  223. Connections {
  224. function onCursorModeChanged() {
  225. if (typeof game !== 'undefined' && game.cursorMode)
  226. gameView.cursorMode = game.cursorMode;
  227. }
  228. target: game
  229. }
  230. MouseArea {
  231. id: mouseArea
  232. property bool isSelecting: false
  233. property real startX: 0
  234. property real startY: 0
  235. anchors.fill: parent
  236. acceptedButtons: Qt.LeftButton | Qt.RightButton
  237. hoverEnabled: true
  238. propagateComposedEvents: true
  239. preventStealing: true
  240. cursorShape: (gameView.cursorMode === "normal") ? Qt.ArrowCursor : Qt.BlankCursor
  241. enabled: gameView.visible
  242. onEntered: {
  243. if (typeof game !== 'undefined' && game.setHoverAtScreen)
  244. game.setHoverAtScreen(0, 0);
  245. }
  246. onExited: {
  247. if (typeof game !== 'undefined' && game.setHoverAtScreen)
  248. game.setHoverAtScreen(-1, -1);
  249. }
  250. onPositionChanged: function(mouse) {
  251. if (isSelecting) {
  252. var endX = mouse.x;
  253. var endY = mouse.y;
  254. selectionBox.x = Math.min(startX, endX);
  255. selectionBox.y = Math.min(startY, endY);
  256. selectionBox.width = Math.abs(endX - startX);
  257. selectionBox.height = Math.abs(endY - startY);
  258. } else {
  259. if (typeof game !== 'undefined' && game.setHoverAtScreen)
  260. game.setHoverAtScreen(mouse.x, mouse.y);
  261. }
  262. }
  263. onWheel: function(w) {
  264. var dy = (w.angleDelta ? w.angleDelta.y / 120 : w.delta / 120);
  265. if (dy !== 0 && typeof game !== 'undefined' && game.cameraZoom)
  266. game.cameraZoom(dy * 0.8);
  267. w.accepted = true;
  268. }
  269. onPressed: function(mouse) {
  270. if (mouse.button === Qt.LeftButton) {
  271. if (gameView.setRallyMode) {
  272. if (typeof game !== 'undefined' && game.setRallyAtScreen)
  273. game.setRallyAtScreen(mouse.x, mouse.y);
  274. gameView.setRallyMode = false;
  275. return ;
  276. }
  277. if (gameView.cursorMode === "attack") {
  278. if (typeof game !== 'undefined' && game.onAttackClick)
  279. game.onAttackClick(mouse.x, mouse.y);
  280. return ;
  281. }
  282. if (gameView.cursorMode === "guard")
  283. return ;
  284. if (gameView.cursorMode === "patrol") {
  285. if (typeof game !== 'undefined' && game.onPatrolClick)
  286. game.onPatrolClick(mouse.x, mouse.y);
  287. return ;
  288. }
  289. isSelecting = true;
  290. startX = mouse.x;
  291. startY = mouse.y;
  292. selectionBox.x = startX;
  293. selectionBox.y = startY;
  294. selectionBox.width = 0;
  295. selectionBox.height = 0;
  296. selectionBox.visible = true;
  297. } else if (mouse.button === Qt.RightButton) {
  298. renderArea.mousePanActive = true;
  299. mainWindow.edgeScrollDisabled = true;
  300. if (gameView.setRallyMode)
  301. gameView.setRallyMode = false;
  302. if (typeof game !== 'undefined' && game.onRightClick)
  303. game.onRightClick(mouse.x, mouse.y);
  304. }
  305. }
  306. onReleased: function(mouse) {
  307. if (mouse.button === Qt.LeftButton && isSelecting) {
  308. isSelecting = false;
  309. selectionBox.visible = false;
  310. if (selectionBox.width > 5 && selectionBox.height > 5) {
  311. areaSelected(selectionBox.x, selectionBox.y, selectionBox.x + selectionBox.width, selectionBox.y + selectionBox.height);
  312. if (typeof game !== 'undefined' && game.onAreaSelected)
  313. game.onAreaSelected(selectionBox.x, selectionBox.y, selectionBox.x + selectionBox.width, selectionBox.y + selectionBox.height, false);
  314. } else {
  315. mapClicked(mouse.x, mouse.y);
  316. if (typeof game !== 'undefined' && game.onClickSelect)
  317. game.onClickSelect(mouse.x, mouse.y, false);
  318. }
  319. }
  320. if (mouse.button === Qt.RightButton) {
  321. renderArea.mousePanActive = false;
  322. mainWindow.edgeScrollDisabled = (renderArea.keyPanCount > 0) || renderArea.mousePanActive;
  323. }
  324. }
  325. }
  326. Rectangle {
  327. id: selectionBox
  328. visible: false
  329. border.color: "white"
  330. border.width: 1
  331. color: "transparent"
  332. }
  333. }
  334. Item {
  335. id: customCursorContainer
  336. visible: gameView.cursorMode !== "normal"
  337. width: 32
  338. height: 32
  339. z: 999999
  340. x: (typeof game !== 'undefined' && game.globalCursorX) ? game.globalCursorX - 16 : 0
  341. y: (typeof game !== 'undefined' && game.globalCursorY) ? game.globalCursorY - 16 : 0
  342. Item {
  343. id: attackCursorContainer
  344. property real pulseScale: 1
  345. visible: gameView.cursorMode === "attack"
  346. anchors.fill: parent
  347. Canvas {
  348. id: attackCursor
  349. anchors.fill: parent
  350. scale: attackCursorContainer.pulseScale
  351. transformOrigin: Item.Center
  352. onPaint: {
  353. var ctx = getContext("2d");
  354. ctx.clearRect(0, 0, width, height);
  355. ctx.strokeStyle = "#ff4444";
  356. ctx.lineWidth = 3;
  357. ctx.beginPath();
  358. ctx.moveTo(16, 4);
  359. ctx.lineTo(16, 28);
  360. ctx.stroke();
  361. ctx.beginPath();
  362. ctx.moveTo(4, 16);
  363. ctx.lineTo(28, 16);
  364. ctx.stroke();
  365. ctx.fillStyle = "#ff2222";
  366. ctx.beginPath();
  367. ctx.arc(16, 16, 4, 0, Math.PI * 2);
  368. ctx.fill();
  369. ctx.strokeStyle = "rgba(255, 68, 68, 0.5)";
  370. ctx.lineWidth = 1;
  371. ctx.beginPath();
  372. ctx.arc(16, 16, 7, 0, Math.PI * 2);
  373. ctx.stroke();
  374. ctx.strokeStyle = "#e74c3c";
  375. ctx.lineWidth = 2;
  376. ctx.beginPath();
  377. ctx.moveTo(8, 12);
  378. ctx.lineTo(8, 8);
  379. ctx.lineTo(12, 8);
  380. ctx.stroke();
  381. ctx.beginPath();
  382. ctx.moveTo(20, 8);
  383. ctx.lineTo(24, 8);
  384. ctx.lineTo(24, 12);
  385. ctx.stroke();
  386. ctx.beginPath();
  387. ctx.moveTo(8, 20);
  388. ctx.lineTo(8, 24);
  389. ctx.lineTo(12, 24);
  390. ctx.stroke();
  391. ctx.beginPath();
  392. ctx.moveTo(20, 24);
  393. ctx.lineTo(24, 24);
  394. ctx.lineTo(24, 20);
  395. ctx.stroke();
  396. }
  397. Component.onCompleted: requestPaint()
  398. }
  399. SequentialAnimation on pulseScale {
  400. running: attackCursorContainer.visible
  401. loops: Animation.Infinite
  402. NumberAnimation {
  403. from: 1
  404. to: 1.2
  405. duration: 400
  406. easing.type: Easing.InOutQuad
  407. }
  408. NumberAnimation {
  409. from: 1.2
  410. to: 1
  411. duration: 400
  412. easing.type: Easing.InOutQuad
  413. }
  414. }
  415. }
  416. Canvas {
  417. id: guardCursor
  418. visible: gameView.cursorMode === "guard"
  419. anchors.fill: parent
  420. onPaint: {
  421. var ctx = getContext("2d");
  422. ctx.clearRect(0, 0, width, height);
  423. ctx.fillStyle = "#3498db";
  424. ctx.strokeStyle = "#2980b9";
  425. ctx.lineWidth = 2;
  426. ctx.beginPath();
  427. ctx.moveTo(16, 6);
  428. ctx.lineTo(24, 10);
  429. ctx.lineTo(24, 18);
  430. ctx.lineTo(16, 26);
  431. ctx.lineTo(8, 18);
  432. ctx.lineTo(8, 10);
  433. ctx.closePath();
  434. ctx.fill();
  435. ctx.stroke();
  436. ctx.strokeStyle = "#ecf0f1";
  437. ctx.lineWidth = 2;
  438. ctx.beginPath();
  439. ctx.moveTo(13, 16);
  440. ctx.lineTo(15, 18);
  441. ctx.lineTo(19, 12);
  442. ctx.stroke();
  443. }
  444. Component.onCompleted: requestPaint()
  445. }
  446. Canvas {
  447. id: patrolCursor
  448. visible: gameView.cursorMode === "patrol"
  449. anchors.fill: parent
  450. onPaint: {
  451. var ctx = getContext("2d");
  452. ctx.clearRect(0, 0, width, height);
  453. ctx.strokeStyle = "#27ae60";
  454. ctx.lineWidth = 2;
  455. ctx.beginPath();
  456. ctx.arc(16, 16, 10, 0, Math.PI * 2);
  457. ctx.stroke();
  458. ctx.fillStyle = "#27ae60";
  459. ctx.beginPath();
  460. ctx.moveTo(26, 16);
  461. ctx.lineTo(22, 13);
  462. ctx.lineTo(22, 19);
  463. ctx.closePath();
  464. ctx.fill();
  465. ctx.beginPath();
  466. ctx.moveTo(6, 16);
  467. ctx.lineTo(10, 13);
  468. ctx.lineTo(10, 19);
  469. ctx.closePath();
  470. ctx.fill();
  471. ctx.beginPath();
  472. ctx.arc(16, 16, 3, 0, Math.PI * 2);
  473. ctx.fill();
  474. }
  475. Component.onCompleted: requestPaint()
  476. }
  477. }
  478. }