Kotlin 2
We’ve all agreed to fork the repo. I’m on my own, more or less, and already confused even though I haven’t started.”
Yesterday, I was writing the article in iPad Scrivener, a lovely tool that in some ways I like better than the full-baot Mac version. It was odd going back and forth from the Mac keyboard to program and back to the iPad to write, so today I’m composing in Sublime. I think that’ll be mostly better.
Last night, Tuesday, the Friding Night Zoom Ensemble got all five computers running on the same repo. As an outsider in the IDEA / maven realm, it seems to me that if these tools are supposed to be used by multiple people at multiple computers, working on the same repo … well … they ought to work. I’m told by my betters that no, at the beginning of every project you spend a week getting everyone set up, and every time you onboard someone you hack until they are set up, and then you forget about all that until next time.
Seems wrong to me, but I sure don’t have the time, ability, or inclination to fix it.
Last night we sort of agreed that we’d all clone disconnected copies of Hill’s starting repo, to use to build up whatver came to mind, and then next Tuesday, we’ll do show and tell, and beginto decide what we want to do as a joint project. I was kind of the instigator of that decision, I guess, because I feel the need to fumble around for a while, learning the basics. But the rest could have decided all to work in the one repo and no one voted for that, so anyway, that’s what we’re going to do.
What To Do?
Yesterday I started with the Robot World stuff, because it’s fresh in my mind from Codea, but as I think about it, while it might be a fun game, it probably isn’t what we want to do. We do probably want a game with a planar map that scrolls around (We are admonished not to call it a side-scroller unless it meets some criteria that we do not yet know). We’ll probaby do a game with things moving actively on the screen and your little avatar deals with stuff, or maybe even something more ambitious with lots of little avatars or robot people or dups going around doing stuff. And therefore ….
The Robot World isn’t a very good example, because it really doesn’t run in “real time”. It’s true that in Codea it paints the screen 60 or 120 times a second, but the screen never changes unless you move the robot, which you do maybe once a second or twice if you’re twitchy. So it’s not very much like what we’ll probably do.
That said—someone was whining on the internet the other day about that phrase—there’s plenty of learning for me to do before I need to worry about that.
I’m glad we had this little chat, I think I know what I’ll do today.
Learn Hill’s Game
The repo as it stands now has a tiny start at a game: it displays a light blue window with a bucket at the bottom of the screen, and you can move the bucket side to side with arrow keys (or A and D). The game is supposed to have drips falling and you’re supposed to catch them, but that’s not done yet.
I think I’ll start by using that to figure out a bit about how it works, fiddle with it to loosen up, and try to write down what I’m thinking and learning, in the vain hope that what I do will be useful to people learning a new scheme, if only as a bad example.
I think I’ll do my work in Hill’s repo, not my own, but I’ll probably reset out most of my work. That’s to be decided if and when.
Down To It
Git tells me that my repo fgno-tornadofx is up to date.
The current game starts here, in MakerMain.kt:
class MakerMain : App(MakerView::class)
fun main(args: Array<String>) {
URL.setURLStreamHandlerFactory(Handler.HandlerFactory())
launch<MakerMain>(args)
}
I consider that to be boilerplate with no utility to me other than to copy the style when it comes to my game. I’m not sure yet why Hill calls the view “MakerView”, but we recall that he always considers two ways of llooking at an application, the App view, used by users, and the Maker view, used by the developers. What we have here is the Makerview, and we can therefore suppose that it may sometimes have in it things that don’t apply to the actual bucket game.
Looking further, at MakerView.kt, I’ll not show it in toto, but instead trek through in the order that I think one wants to look at these things.
class MakerView : View("Raindrops") {
...
}
Subclass of View, which is a Kotlin tornadofx class. I was told that such a thing has to have a root, and sure enough we have this:
override val root = pane {
minWidth = SCREEN_WIDTH
maxWidth = SCREEN_WIDTH
minHeight = SCREEN_HEIGHT
maxHeight = SCREEN_HEIGHT
background = Background(BackgroundFill(Color.LIGHTBLUE, null, null))
isFocusTraversable = true
addEventHandler(KeyEvent.KEY_PRESSED) { event: KeyEvent ->
input.handle(event)
}
addEventHandler(MouseEvent.MOUSE_CLICKED) { _ ->
requestFocus()
}
this += bucket
}
OK, pane
is a method somewhere in tornadofx. I don’t understand how this works. I don’t even understand what the syntax means. pane
is a function, if I’m understanding what IDEA is telling me.
Oh this is interesting, now IDEA makes it look like this, with the “this: Pane” bit only seems to show up when IDEA wants it to, and isn’t copied when I copy to paste here”
override val root = pane { this: Pane
minWidth = SCREEN_WIDTH
maxWidth = SCREEN_WIDTH
minHeight = SCREEN_HEIGHT
maxHeight = SCREEN_HEIGHT
background = Background(BackgroundFill(Color.LIGHTBLUE, null, null))
isFocusTraversable = true
addEventHandler(KeyEvent.KEY_PRESSED) { event: KeyEvent ->
input.handle(event)
}
addEventHandler(MouseEvent.MOUSE_CLICKED) { _ ->
requestFocus()
}
this += bucket
}
Time Passes …
I just, well, about 3 hours ago, made a mistake. I tried to understand the syntax above. I trolled through the Kotlin docs and never stumbled on what that syntax even means, then got in a /chat with Hill, who sorted me out, but by then the wind was gone from my sails, and I moved on to browsing a bit of Kotlin doc, a bit of tornadofx doc, a bit of Cryptonomicon, and a bit of dozing because I was up early and am old.
Along the way, I discovered that somehow, IDEA had forgotten how to build and run the project, so I had to divert from my intended destination and work out how to set up run configurations. After longer than it would take me next time, I was back to looking at that code and not understanding it.
So anyway, what I could have done is obvious. It’s clear that somehow that code creates the pane and in the pane there is a blue background and a couple of event handlers, and a bucket, which you can find here:
val bucket = imageview {
x = SCREEN_HALF - BUCKET_HALF
y = SCREEN_HEIGHT - BUCKET_HEIGHT
image = Image("/bucket.png")
}
You see that on the screen when you run the program:
So what it does is pretty obvious, and you can quickly get a sense of how to change it to make it be a box instead of a bucket or maybe to add another bucket or a cat if you have one. But I wanted to know more, I wanted not to just have boilerplate that I could copy and mash, I wanted to understand what the code really is.
Well, now I know.
What It Is
We can consider the bucket as a shorter case:
val bucket = imageview {
x = SCREEN_HALF - BUCKET_HALF
y = SCREEN_HEIGHT - BUCKET_HEIGHT
image = Image("/bucket.png")
}
bucket
receives the result returned from the function imageview
, which is somewhere up in our hierarchy. IDEA pops up this info:
This tells us that the method is in the class EventTarget and that it takes three parameters. The last one, this is not obvious if you dont know Kotlin, which I don’t, yet, the last one is a funtion to be provided, which returns Unit
which is Kotlin for void
, i.e. returns nothing. It’s passed the ImageView object that it creates, and our function in the braces fills in parameters.
Because, yes, the stuff in the brackets is a lambda, a function expressed inline, receiving no parameters and returning no result (Unit
). It turns out that you can, when the last parameter to a function is a lambda, you can just write the function name and the lambda in braces.
I am not sure what happens to the other parameters here, which are listed in the picture above, the url
and lazyload
but no doubt they are dealt with in some useful way.
So now, hours later, I have a small understanding of what this odd syntax does and why it does what it does.
I knew that going in: this is creating a pane and a bucket. But it was as if someone had handed me a paragraph in Greek and told me what the paragraph meant, maybe even a few of the words. I could maybe change it, but I couldn’t produce it. Now I’m close to being able to produce it.
It’s like this when you’re just learning. Incantations that work, that you can change a bit and they often do what you expect, and yet you really have very little idea what you’re doing. Well, I say “you”, but I mean me. I suppose it’s similar for other people but I don’t know that for sure.
Now … I have a slightly better idea what’s going on. Not enough to go to market and argue philosophy with that guy sitting there asking questions, but I can probably come home with some tomatoes instead of just olives.
Summary
I might do some more later today, but more likely I’m done until tomorrow. Very small progress: I’ve not changed a line of code for the better, or even for worse. But I know a little more than I did when I got up. That makes it a good day.
See you soon, I hope!