Skip to content

Commit 8c44fd9

Browse files
committed
Add support for "non-timer" subscriptions.
1 parent a6b84a9 commit 8c44fd9

File tree

2 files changed

+81
-15
lines changed

2 files changed

+81
-15
lines changed

src/main/scala/net/kogics/kojo/gaming/package.scala

Lines changed: 79 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,31 @@ import net.kogics.kojo.core.{Picture, Point, SCanvas}
2020
package object gaming {
2121
trait GameMsgSink[Msg] {
2222
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
2333
}
2434

25-
trait Sub[Msg] {
35+
trait TimerSub[Msg] extends Sub[Msg] {
2636
def fire(gameMsgSink: GameMsgSink[Msg]): Unit
2737
}
2838

2939
object Subscriptions {
30-
case class OnAnimationFrame[Msg](mapper: () => Msg) extends Sub[Msg] {
40+
case class OnAnimationFrame[Msg](mapper: () => Msg) extends TimerSub[Msg] {
3141
def fire(gameMsgSink: GameMsgSink[Msg]): Unit = {
3242
val msg = mapper()
3343
gameMsgSink.triggerIncrementalUpdate(msg)
3444
}
3545
}
3646

37-
case class OnKeyDown[Msg](mapper: Int => Msg) extends Sub[Msg] {
47+
case class OnKeyDown[Msg](mapper: Int => Msg) extends TimerSub[Msg] {
3848
def fire(gameMsgSink: GameMsgSink[Msg]): Unit = {
3949
val pressedKeys = net.kogics.kojo.staging.Inputs.pressedKeys
4050
pressedKeys.foreach { keyCode =>
@@ -44,7 +54,7 @@ package object gaming {
4454
}
4555
}
4656

47-
case class OnMouseDown[Msg](mapper: Point => Msg) extends Sub[Msg] {
57+
case class OnMouseDown[Msg](mapper: Point => Msg) extends TimerSub[Msg] {
4858
def fire(gameMsgSink: GameMsgSink[Msg]): Unit = {
4959
import net.kogics.kojo.staging.Inputs
5060
if (Inputs.mousePressedFlag && Inputs.mouseBtn == 1) {
@@ -54,11 +64,27 @@ package object gaming {
5464
}
5565
}
5666

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+
5781
def onAnimationFrame[Msg](mapper: => Msg): Sub[Msg] = OnAnimationFrame(() => mapper)
5882

5983
def onKeyDown[Msg](mapper: Int => Msg): Sub[Msg] = OnKeyDown(mapper)
6084

6185
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)
6288
}
6389

6490
class Game[Model, Msg](
@@ -77,33 +103,73 @@ package object gaming {
77103
firstTime = false
78104
currModel = init
79105
currSubs = subscriptions(currModel)
106+
nonTimerSubs.foreach(_.activate(this))
80107
currView = view(currModel)
81108
currView.draw()
82109
}
83110
else {
84111
fireTimerSubs()
85-
val oldView = currView
86-
currView = view(currModel)
87-
oldView.erase()
88-
currView.draw()
112+
updateView()
89113
}
90114
}
91115

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+
}
95146
}
147+
}
148+
149+
def checkForStop(): Unit = {
96150
if (currSubs.isEmpty) {
97151
canvas.stopAnimationActivity(gameTimer)
98152
}
99153
}
100154

155+
def fireTimerSubs(): Unit = {
156+
timerSubs.foreach { sub =>
157+
sub.fire(this)
158+
}
159+
checkForStop()
160+
}
161+
101162
def triggerIncrementalUpdate(msg: Msg): Unit = {
102163
if (currSubs.nonEmpty) {
103-
currModel = update(currModel, msg)
104-
currSubs = subscriptions(currModel)
164+
updateModelAndSubs(msg)
105165
}
106166
}
167+
168+
def triggerUpdate(msg: Msg): Unit = {
169+
updateModelAndSubs(msg)
170+
updateView()
171+
checkForStop()
172+
}
107173
}
108174

109175
class CollisionDetector(implicit canvas: SCanvas) {

src/main/scala/net/kogics/kojo/lite/Versions.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ package net.kogics.kojo.lite
33
object Versions {
44
val KojoMajorVersion = "2.9"
55
val KojoVersion = "2.9.24"
6-
val KojoRevision = "r10"
7-
val KojoBuildDate = "23 November 2022"
6+
val KojoRevision = "r11"
7+
val KojoBuildDate = "24 November 2022"
88
val JavaVersion = {
99
val jrv = System.getProperty("java.runtime.version")
1010
val arch = System.getProperty("os.arch")

0 commit comments

Comments
 (0)