@@ -20,21 +20,31 @@ import net.kogics.kojo.core.{Picture, Point, SCanvas}
20
20
package object gaming {
21
21
trait GameMsgSink [Msg ] {
22
22
def triggerIncrementalUpdate (msg : Msg ): Unit
23
+
24
+ def triggerUpdate (msg : Msg ): Unit
25
+ }
26
+
27
+ trait Sub [Msg ]
28
+
29
+ trait NonTimerSub [Msg ] extends Sub [Msg ] {
30
+ def activate (gameMsgSink : GameMsgSink [Msg ]): Unit
31
+
32
+ def deactivate (): Unit
23
33
}
24
34
25
- trait Sub [Msg ] {
35
+ trait TimerSub [ Msg ] extends Sub [Msg ] {
26
36
def fire (gameMsgSink : GameMsgSink [Msg ]): Unit
27
37
}
28
38
29
39
object Subscriptions {
30
- case class OnAnimationFrame [Msg ](mapper : () => Msg ) extends Sub [Msg ] {
40
+ case class OnAnimationFrame [Msg ](mapper : () => Msg ) extends TimerSub [Msg ] {
31
41
def fire (gameMsgSink : GameMsgSink [Msg ]): Unit = {
32
42
val msg = mapper()
33
43
gameMsgSink.triggerIncrementalUpdate(msg)
34
44
}
35
45
}
36
46
37
- case class OnKeyDown [Msg ](mapper : Int => Msg ) extends Sub [Msg ] {
47
+ case class OnKeyDown [Msg ](mapper : Int => Msg ) extends TimerSub [Msg ] {
38
48
def fire (gameMsgSink : GameMsgSink [Msg ]): Unit = {
39
49
val pressedKeys = net.kogics.kojo.staging.Inputs .pressedKeys
40
50
pressedKeys.foreach { keyCode =>
@@ -44,7 +54,7 @@ package object gaming {
44
54
}
45
55
}
46
56
47
- case class OnMouseDown [Msg ](mapper : Point => Msg ) extends Sub [Msg ] {
57
+ case class OnMouseDown [Msg ](mapper : Point => Msg ) extends TimerSub [Msg ] {
48
58
def fire (gameMsgSink : GameMsgSink [Msg ]): Unit = {
49
59
import net .kogics .kojo .staging .Inputs
50
60
if (Inputs .mousePressedFlag && Inputs .mouseBtn == 1 ) {
@@ -54,11 +64,27 @@ package object gaming {
54
64
}
55
65
}
56
66
67
+ case class OnMouseClick [Msg ](mapper : Point => Msg )(implicit canvas : SCanvas ) extends NonTimerSub [Msg ] {
68
+ def activate (gameMsgSink : GameMsgSink [Msg ]): Unit = {
69
+ canvas.onMouseClick { case (x, y) =>
70
+ val msg = mapper(Point (x, y))
71
+ gameMsgSink.triggerUpdate(msg)
72
+ }
73
+ }
74
+
75
+ def deactivate (): Unit = {
76
+ println(" Deactivating mouse click subscription" )
77
+ net.kogics.kojo.staging.Inputs .mouseClickHandler = None
78
+ }
79
+ }
80
+
57
81
def onAnimationFrame [Msg ](mapper : => Msg ): Sub [Msg ] = OnAnimationFrame (() => mapper)
58
82
59
83
def onKeyDown [Msg ](mapper : Int => Msg ): Sub [Msg ] = OnKeyDown (mapper)
60
84
61
85
def onMouseDown [Msg ](mapper : Point => Msg ): Sub [Msg ] = OnMouseDown (mapper)
86
+
87
+ def onMouseClick [Msg ](mapper : Point => Msg )(implicit cavas : SCanvas ): Sub [Msg ] = OnMouseClick (mapper)
62
88
}
63
89
64
90
class Game [Model , Msg ](
@@ -77,33 +103,73 @@ package object gaming {
77
103
firstTime = false
78
104
currModel = init
79
105
currSubs = subscriptions(currModel)
106
+ nonTimerSubs.foreach(_.activate(this ))
80
107
currView = view(currModel)
81
108
currView.draw()
82
109
}
83
110
else {
84
111
fireTimerSubs()
85
- val oldView = currView
86
- currView = view(currModel)
87
- oldView.erase()
88
- currView.draw()
112
+ updateView()
89
113
}
90
114
}
91
115
92
- def fireTimerSubs (): Unit = {
93
- currSubs.foreach { sub =>
94
- sub.fire(this )
116
+ def timerSubs : Seq [TimerSub [Msg ]] = currSubs.filter(_.isInstanceOf [TimerSub [Msg ]]).asInstanceOf [Seq [TimerSub [Msg ]]]
117
+
118
+ def nonTimerSubs : Seq [NonTimerSub [Msg ]] = currSubs.filter(_.isInstanceOf [NonTimerSub [Msg ]]).asInstanceOf [Seq [NonTimerSub [Msg ]]]
119
+
120
+ def updateView (): Unit = {
121
+ val oldView = currView
122
+ currView = view(currModel)
123
+ oldView.erase()
124
+ currView.draw()
125
+ }
126
+
127
+ def updateModelAndSubs (msg : Msg ): Unit = {
128
+ currModel = update(currModel, msg)
129
+ val oldSubs = currSubs
130
+ currSubs = subscriptions(currModel)
131
+ handleSubChanges(oldSubs, currSubs)
132
+ }
133
+
134
+ def handleSubChanges (oldSubs : Seq [Sub [Msg ]], newSubs : Seq [Sub [Msg ]]): Unit = {
135
+ if (newSubs.length != oldSubs.length) {
136
+ val newSubsSet = Set (newSubs : _* )
137
+ oldSubs.foreach { sub =>
138
+ sub match {
139
+ case ntSub : NonTimerSub [Msg ] =>
140
+ if (! newSubsSet.contains(ntSub)) {
141
+ ntSub.deactivate()
142
+ }
143
+ case _ =>
144
+ }
145
+ }
95
146
}
147
+ }
148
+
149
+ def checkForStop (): Unit = {
96
150
if (currSubs.isEmpty) {
97
151
canvas.stopAnimationActivity(gameTimer)
98
152
}
99
153
}
100
154
155
+ def fireTimerSubs (): Unit = {
156
+ timerSubs.foreach { sub =>
157
+ sub.fire(this )
158
+ }
159
+ checkForStop()
160
+ }
161
+
101
162
def triggerIncrementalUpdate (msg : Msg ): Unit = {
102
163
if (currSubs.nonEmpty) {
103
- currModel = update(currModel, msg)
104
- currSubs = subscriptions(currModel)
164
+ updateModelAndSubs(msg)
105
165
}
106
166
}
167
+
168
+ def triggerUpdate (msg : Msg ): Unit = {
169
+ updateModelAndSubs(msg)
170
+ updateView()
171
+ checkForStop()
172
+ }
107
173
}
108
174
109
175
class CollisionDetector (implicit canvas : SCanvas ) {
0 commit comments