Physics.qml 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. import QtQuick 2.5
  2. import Box2D 2.0
  3. import Qt.labs.settings 1.0
  4. import "../effects"
  5. Item {
  6. id: root
  7. signal togglePause
  8. signal toggleChaos
  9. signal next
  10. property var pictureDelegate: Qt.createComponent("HorizontalArtDelegate.qml")
  11. property var effectDelegate: Qt.createComponent("../VisualEffect.qml")
  12. anchors.fill: parent
  13. Settings {
  14. id: physicsSettings
  15. category: "Physics"
  16. property int itemTravel: 0
  17. property real pace: 1
  18. property bool globalWorld: false
  19. // Very computationally heavy: 40% vs 20% for 0.1 vs 0
  20. property real restitution: 0
  21. }
  22. QtObject {
  23. id: d
  24. property real pace: physicsSettings.pace/60.0
  25. property int itemCount: 0
  26. property int itemTravel: physicsSettings.itemTravel
  27. property int primedColumns: 0
  28. property int columnCount: generalSettings.columnCount
  29. property bool running: primedColumns >= columnCount
  30. property bool globalWorld: physicsSettings.globalWorld
  31. property string effect: generalSettings.effect
  32. function reset() {
  33. itemCount = 0
  34. primedColumns = 0
  35. }
  36. onColumnCountChanged: reset()
  37. }
  38. World {
  39. id: world
  40. timeStep: d.pace
  41. running: d.globalWorld && d.running
  42. property var limbo: World {
  43. timeStep: world.timeStep
  44. running: world.running
  45. }
  46. }
  47. Component {
  48. id: columnComponent
  49. Item {
  50. id: column
  51. property int stackHeight: 0
  52. property bool full: false
  53. property int xOffset: width * index
  54. onStackHeightChanged: {
  55. if (!column.full && (stackHeight > root.height)) {
  56. d.primedColumns += 1
  57. column.full = true
  58. }
  59. }
  60. function considerImage() {
  61. if (stackHeight < (1.3 + 1/d.columnCount)*root.height) {
  62. addImage()
  63. }
  64. }
  65. function addImage() {
  66. var image = pictureDelegate.createObject(column, { x: -1000, y: -1000 })
  67. if (d.effect !== "" && Effects.validate(d.effect)) {
  68. image.effect = effectDelegate.createObject(column, { target: image, effect: d.effect })
  69. }
  70. image.beyondThePale.connect(removeImage)
  71. image.world = d.globalWorld ? world : isolatedWorld
  72. image.x = xOffset
  73. stackHeight += (image.height + d.itemTravel)
  74. image.y = floor.y - stackHeight
  75. pictureArray.push(image)
  76. d.itemCount++
  77. }
  78. function removeImage(image) {
  79. if (image.effect) {
  80. image.effect.destroy()
  81. }
  82. stackHeight -= (image.height + d.itemTravel)
  83. image.destroy()
  84. d.itemCount--
  85. }
  86. function shiftImageToLimbo() {
  87. if (pictureArray.length > 0) {
  88. var image = pictureArray.shift()
  89. image.world = image.world.limbo
  90. addImage()
  91. }
  92. }
  93. width: parent.width/d.columnCount
  94. anchors { top: parent.top; bottom: parent.bottom }
  95. property var pictureArray: []
  96. property bool fixedRotation: true
  97. World {
  98. id: isolatedWorld
  99. timeStep: d.pace
  100. running: !d.globalWorld && d.running
  101. property var limbo: World {
  102. timeStep: isolatedWorld.timeStep
  103. running: isolatedWorld.running
  104. }
  105. }
  106. RectangleBoxBody {
  107. id: floor
  108. world: isolatedWorld
  109. height: 0
  110. width: parent.width
  111. x: xOffset
  112. anchors {
  113. top: parent.bottom
  114. }
  115. friction: 1
  116. }
  117. Timer {
  118. id: pumpTimer
  119. interval: Math.random()*500 + 500
  120. repeat: true
  121. running: true
  122. onTriggered: considerImage()
  123. }
  124. Timer {
  125. id: deathTimer
  126. running: d.running
  127. repeat: true
  128. interval: 1000*(generalSettings.interval > 60 ? 60*(generalSettings.interval-60) : generalSettings.interval)*(Math.random()+1)
  129. onTriggered: shiftImageToLimbo()
  130. }
  131. Connections {
  132. target: root
  133. onTogglePause: deathTimer.running = !deathTimer.running
  134. onNext: deathTimer.triggered()
  135. onToggleChaos: fixedRotation = !fixedRotation
  136. }
  137. Timer {
  138. id: settleTimer
  139. running: false
  140. interval: 200
  141. onTriggered: deathTimer.triggered()
  142. }
  143. }
  144. }
  145. // floor
  146. RectangleBoxBody {
  147. id: globalFloor
  148. world: world
  149. height: 0
  150. anchors {
  151. left: parent.left
  152. right: parent.right
  153. top: parent.bottom
  154. }
  155. friction: 1
  156. }
  157. DebugDraw {
  158. id: debugDraw
  159. enabled: false
  160. z: 1
  161. world: world
  162. anchors.fill: parent
  163. opacity: 0.75
  164. visible: enabled
  165. }
  166. Repeater {
  167. model: d.columnCount
  168. delegate: columnComponent
  169. }
  170. // TODO: The boot (Monty Python foot) of death to be applied to the stacks
  171. RectangleBoxBody {
  172. id: rect
  173. enabled: false
  174. visible: false
  175. friction: 1.0
  176. density: 1000
  177. color: "red"
  178. width: 50; height: 50
  179. bullet: true
  180. SequentialAnimation {
  181. id: murderAnimation
  182. //loops: Animation.Infinite
  183. //running: true
  184. ScriptAction { script: { root.togglePause() } }
  185. ScriptAction { script: { rect.world = worldArray.pop() } }
  186. PropertyAction { target: rect; property: "x"; value: -rect.width }
  187. PropertyAction { target: rect; property: "y"; value: root.height }
  188. ParallelAnimation {
  189. NumberAnimation { target: rect; property: "x"; to: 2560; duration: 1000 }
  190. NumberAnimation { target: rect; property: "y"; to: 0; duration: 1000 }
  191. }
  192. }
  193. }
  194. Rectangle {
  195. visible: generalSettings.viewItemCount
  196. z: 1
  197. color: "black"
  198. anchors { right: parent.right; top: parent.top }
  199. width: itemCountLabel.width
  200. height: itemCountLabel.height
  201. Text {
  202. id: itemCountLabel
  203. font.pixelSize: 100
  204. text: d.itemCount
  205. color: "white"
  206. }
  207. }
  208. Keys.onUpPressed: root.togglePause()
  209. Keys.onDownPressed: root.toggleChaos() //root.next()
  210. Component.onCompleted: {
  211. pictureDelegate.status !== Component.Ready && console.log('Component failed with:' + pictureDelegate.errorString())
  212. effectDelegate.status !== Component.Ready && console.log('Component failed with:' + effectDelegate.errorString())
  213. }
  214. }