GameView.qml 17 KB

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