Thursday, April 27, 2017

Roundtable course evaluation in CS222

This is the final full week of classes at Ball State, with one more regular class meeting on Monday before final exams Tuesday through Friday. I had planned out everything that needed planning in CS222, but this past Monday had a hole. It would have been easiest for me to schedule a "studio day," where I show up to class and help teams out with their final projects, but I decided I wanted to do something different: I held a roundtable discussion with my students about their experience this past semester. The decision was motivated in part this semester's abysmal attendance, but as I got to reflecting on it, I realized I had many more questions about the students' experience that perhaps an open discussion would address.

I announced the plan for the week to Blackboard, and I came into Monday with a fairly simple plan. My idea was to talk through four prompts: What were the highlights of the semester? What were the stressors and low points of the semester? Why was the attendance so poor all semester? What advice would you give for next year's students?

I was surprised to see a great turn out on Monday, although it was less clear to me if they had actually read the announcement of what we would be doing that day. We pushed some tables out of the way and circled the chairs for the discussion, and I opened with the first question listed above. From here, there were never really any dead spots for the 45 minutes or so we had; the conversation flowed from one topic to another. As time went by, I did occasionally steer the group to get at those four issues above, but it was much more organic than I imagined it would be.

The notes I took are mostly chronological, but I'm not sure that it makes sense to share the results in that order. My goal here is not to recreate the conversation but to provide enough notes that others—including Future Me—can use these observations to make course planning decisions. I should mention that not every student spoke up, probably about half, with some saying more than others, as these things tend to go. I don't present these notes as representative of the whole class, but as a record of what was shared.

The highlights reported by the students included "story time", which I took to mean my sharing of relevant (or not?) anecdotes to support the themes of the course. Students responded positively to the self-driven format of the course, with several stating that they had never had a class like this. One student pointed out specifically that he loved the format, even though he didn't take the most advantage of it; he would do it differently a second time, if he could. When I asked whether there was anything that could be frontloaded to encourage the kind of behavior he described, the group didn't really come up with anything. The class examples from the first third of the semester were also cited as highlights, with the observation that the examples in Clean Code tended to be abstract, but the things we built were real applications. This was interesting since our examples were, in my opinion, ridiculously small, but to the students this was still more valuable than the incomplete examples (that is, they are only portions of systems) given in the book.

A student suggested that he would like to have an example of perfect Clean Code—a project that he could look at for exemplars of all the ideas he needed to know. Several students nodded in agreement that this would be useful. I decided to play devil's advocate, and I asked them if they thought there was a poem that they could read that would show them everything they needed to know about poetry, or if there was a novel that was clearly The Best Novel in English. They realized quickly of course that this was ludicrous, and it seemed they quickly made the association back to code. I acknowledged that the desire for such a thing is not bad, but that I doubted that such a thing existed, or that it could exist. Instead, I encouraged them to think about what they would want out of this desire, and how they would get it in different ways. (When I posted a version of this story on Facebook, a friend and alumnus coined the term "Clean Code Unicorn," which I quite like.)

The discussion veered a little bit from this concept, but as part of it, students expressed a desire for more examples of high-quality code, including specific examples of Model-View-Controller architecture. The speaker acknowledged that I had, in fact, provided reference to some, such as Guava, and that Robert Martin has some wonderful lectures on YouTube. Acknowledging the authenticity of the desire for more examples, I asked what would actually motivate students to study those examples. One student said his two-week project grade was motivation enough, and another called for "points".

One student expressed a frustration that not everyone in the class knew how to learn from the book. He himself had read the book when it was assigned and studied it rigorously, but he was working on a team with students who had not done this, and so they had no concept of what they were doing wrong. It was refreshing to hear a student express this concern that so often I hear faculty discussing! Several suggestions were made to ameliorate the problem, including making a guide on how to use examples from the book, doing more whole-class work sessions to solve refactoring problems, and homework assignments with canned bad code examples. The most innovative recommendation was to have a Challenge of the Week, like a sudoku or crossword puzzle, where the class would be given some code to refactor toward cleanliness in exchange for some kind of course credit.

Another student suggested that I provide more guidance about naming conventions in general. Clean Code talks about the importance of good naming, but it doesn't get into cultural norms such as "a method should not be called setX unless it is a mutator that takes an X as a parameter," "a boolean method should be named isX for ease of reading conditionals," or "methods that make other things are often called createX methods." This student was reacting to some feedback I had given on that team's previous submission, where I gave pointers like these (maybe exactly those, actually). That is how I usually handle these cases: as students come across common problems—which will manifest differently for each team—I will provide guidance on them. After the discussion, it got me wondering if the student mistakenly thought that the team "lost points" for this kind of thing; it may be an easy mistake to make since my guidance on naming might be interleaved with more serious Clean Code violations. Since it's not clear to me that I can frontload all of the cultural naming rules in a way that students will be able to internalize, maybe what this student really wanted was clarity in which parts of my feedback were formative vs summative.

We talked about attendance a bit, but I prefaced the discussion by saying that I understood that few people really enjoyed 8AM classes: we couldn't control the scheduling, so I wondered if there was anything else contributing to low attendance. For those who don't know, I don't record student attendance or grade participation, but I won't go into my philosophical and pedagogic argument for that here—that's for another blog post. However, because I don't give "points" for attendance, one student framed it as, "People don't come to class because you don't care if they come or not." I pushed back a bit, and he backpedaled on the "don't care" part, but this idiomatic expression belies the mental model. I would argue that I don't take attendance because I do care, but it's very easy for students to misconstrue this. As in many cases, it's the students who are least capable of drawing this conclusion who are in the direst situations from missing it.

The other factor impacting attendance, according to the students, was that some of their peers have the perception that what we do in class doesn't matter: because it is not directly graded, they can simply skip class and ask their peers for a high-level view later. This is not surprising to me, since during the nine weeks of the final project, I use class time on activities that are designed to foster students' success in their projects: code reviews, philosophical discussions, UI design techniques, teamwork skills, and so on. These are not directly graded, but they are carefully designed to complement what students are doing. The ones who skip because these things "are not important" tend to be the cocky ones who can sling a bit of code, but who reject the idea that they are unprofessional in their techniques. Again, tragically, these students miss discussions of concepts such as second-order ignorance, and because they miss the discussion, they miss the point. It does make me wonder if more students would be impacted by changing some of my assessments in the course to directly bring in these concepts,  although I worry that this is a slippery slope leading way from authentic project work. As it is now, students either take my advice or not, and those who do tend to succeed, and those who do not, do not. Some of my best experiences have been with students who rejected feedback in one semester and then enrolled in my class a second time and really nailed it—these are cases where I truly believe I have made a lifelong impact on a student.

Looking over my notes on attendance and participation notes, I jotted in the margin that I could use my course's achievement system for participation somehow. This system has provided a good mechanism for rewarding the various kinds of virtuous behaviors I want students to practice. It would be very easy to add one with criteria such as, "Write a reflective essay about three in-class activities in which you participated, relating it to your final project." That's probably what I'll do for Fall.

In the last few minutes of our discussion, we focused on the advice that this semester's students would give to those taking the course in the Fall. Here's what came out of the discussion:

  • Do the assignments in the first three weeks. Students can resubmit assignments throughout the semester, one per week. Some students make the mistake then of not working on these right away. As a result, they quickly fall behind, since then they're being graded in projects on concepts they have not yet wrestled with at all.
  • Go through the book, which I interpreted to mean, actually do the assigned reading when it is assigned, so you know when you need it later.
  • Pick an easier project. I joked about this being like Hofstadter's Law: pick an easy project, then pick an easier project.
  • Name correctly. Students mentioned again that the idea of naming correctly is almost trivial, but the implications of actually naming correctly are profound.
  • Talk to other students outside class. They mentioned the programming club, Code Smash, as a good source, and just generally talking to upperclassmen, as ways to get more feedback.
  • Watch out for StackOverflow and tutorials. They are often abstract and don't follow best practices of Clean Code.
  • Keep up to date, in particular with platforms like Android, where advice from five years ago may very well not be applicable today.
I think it took me longer to type this up than the discussion itself, but I'm glad I took the time to do it. I hope that you might find something interesting in here for yourself, dear reader. As always, feel free to leave a comment about your own experience, advice, or teaching practices.

Tuesday, April 25, 2017

Ludum Dare 38: Subpar Melee

TL;DR

I made a thing! Download links to Linux, Windows, and HTML5 builds are on the game's Ludum Dare 38 page, and you can play in the browser right now (keyboard required).

A two-player space combat game

Background

Ludum Dare 38 was the 15th anniversary celebration of one of the world's largest game development events, and this alone was enough to encourage me to participate. I did some digging and was a little surprised to see that the last one I participated in was with Summoned, way back in LD29 (blogged about it here). I know I've followed the themes and done a few sketches since then, but it wasn't until LD38 that I made a full submission. Ludum Dare comes every four months, which means it aligns with the end of the Spring semester, the start of the Fall semester, and the end of the Fall semester—an epic trilogy of bad timing for students and faculty alike. Still, I love the event: it encourages anybody with some spare time and interest to make a thing and make it public. It's the spirit of this blog and of my immersive learning projects to make in public.

LD38 provided another important opportunity for me. A few weeks into the Fall 2016 semester, I decided to invest a significant amount of time learning Unreal Engine, a decision I wrote about in December. Well, it's practically final exam season here at Ball State, so why not give myself a final exam as well: could I make a game in 48 hours for LD38 using what I've learned in Unreal Engine? In some ways, it's like the final exam I gave to my Game Programming students back in 2011, to make a game about Beneficence to demonstrate what they learned, except I had 48 hours, and the theme would come from the Ludum Dare community.

Before the event, I participated in two rounds of community theme voting. At 9PM on Friday, I popped over to ldjam.com and saw the announcement that the theme was "A Small World." Of course, that terrible Disney song was the first thing to come to mind, particularly the rendition from the old 45 I had as a kid. I thought about games taking place on small worlds, and I thought about the board game Small World, but nothing really jumped out at me. That late at night is awfully late for me to start being creative, anyway. After stepping away, I got to thinking about games I've played that have small worlds in them, and my thoughts came to Star Control 2 and it's classic Super Melee space combat.


A friend gave me a copy of Star Control 2 when I was in high school or college, and it quickly became one of my favorites. For those who don't know, the game is now available for free as Ur-Quan Masters. It's an epic space opera taking place over a whole galaxy, complete with planet-roving and resource-gathering long before Mass Effect—and they did it better, too! My goodness, don't get me started on the ridiculous tedium and carpal-tunnel-inducing stress of Mass Effect 2's planet scanning.

But I digress. I decided to make a simple two-player space combat game along the lines of Star Control 2 Super Melee. I also decided to do it primarily in 2D, since I'm gearing up for a 2D reimplementation of Collaboration Station starting this summer—but more on that in another post.

Making Subpar Melee

Saturday morning, I drew a quick red spaceship in Gimp and implemented the fundamental inputs for one player to fly around the screen. I made two planning decisions that morning: to use the Unreal Engine naming conventions and to follow its framework of separating pawn, controller, game state, and game mode. As I worked, I found the former to be a bit troublesome: not every kind of asset I was dealing with had a naming convention, and not every gameplay element had a clear place in the folder-structure taxonomy. It's still not entirely clear to me how conventional these conventions really are, since I have not read enough high-quality code to build an intuition for it. From the tutorials I've seen, I think my next project will take a more emergent approach—when there's a structural problem, refactor, but keep it lean until then. I'll come back to the gameplay framework decision in a little while.

The first major hurdle I encountered was that I wanted to set walls around the play area, such that a player would bounce off of them and take some damage. I watched a Pong tutorial last semester where the developer simply placed boxes around the play area off camera, and that seemed elegant to me. However, I kept passing right through the boxes, despite the physics settings. I don't know how long I was stuck on this, but at one point I was adding spheres into the board with gravity enabled, and watching them fall and pass right through the walls, scratching my head, when I was inspired to fiddle with the box size. See, I had decided to make these boxes look like walls, so I had taken their width to zero... and it turns out that even though the wall will render, a zero-width box will not generate collisions. A silly mistake, but one I won't make again! Setting the walls' width to 0.1 was enough for it all to work brilliantly.

Next I added the planet in the center of the screen and gave it gravity. A quick search confirmed that you cannot set a point source gravity using the canned physics settings, but it was no trouble to give the planet the behavior of pulling every ship instance toward itself, and then to modify the algorithm to make this value inversely proportional to the square of the distance.

With the edges and the center collisions working, I added a damage system, and then I began to add support for exploding when health reaches zero. This is where everything took a turn for the worse, early Saturday afternoon: Unreal Engine suddenly became unreasonably unstable. I couldn't work for a minute without it crashing and restarting. I narrowed the problem down to involving the details panel, especially when dealing with a flipbook animation. I sent about a million crash reports to Epic, so hopefully they find something in there, but I was stymied. I had been working in Windows, since several weeks ago I began learning C++, and the Visual Studio bindings are clearly more robust than the Linux ones I tinkered with. For LD38, I wanted to test my ability to get something up and running quickly, and so I was only using Blueprints—UE4's visual scripting language, which is much faster to iterate with than C++. Since I was not using C++ for this project, though, I thought perhaps I could switch over to Linux... except that the version of UE4 I had installed on my Linux partition was 4.14.x, and this project was already started in 4.15.1. With the wind out of my sails, I rebooted into Linux and started the lengthy clone, dependency download, and build process. I was able to finish painting some miniatures and go out and run some errands, and when the build was complete, I was rewarded with a perfectly stable UE4 running in my preferred operating system. Success!

The next major hurdle was adding the second ship for local multiplayer. At this point, I had a PlayerShip blueprint to represent the ship, and I had written a custom PlayerController to handle transforming the input events into ship events. I had also separated the ship's health and damage into a separate GameState object. It seemed like a good idea at the time, but I had no luck getting local multiplayer working. I thought gamepads would be fun, but UE4 didn't recognize my gamepads. I spent a lot of time just trying to get my old Logitech pads recognized as XBox360 controllers in Linux so that they would be accessible in UE4. Incidentally, this is done through xboxdrv, but it took a lot of reading and fiddling to make any progress. Even when I had the controllers recognized, I had no luck getting the second player to properly be assigned a PlayerController and possess the second ship. Again, I didn't keep track of exactly how much time I whittled away here, but clearly I was not making headway. I'd still like to know what I was doing wrong, although many of the signs point to the fact that custom C++ integrations are needed to do what I wanted to do. I cut my losses and moved forward with a different input scheme: I could get away with using the keyboard for both players if I eliminated the idea of using UE4's built-in multiplayer systems and instead just faked it. I wiped out my custom PlayerController and GameState and put the keyboard events for both players directly into my map, which had references to the red and blue ships. This was straightforward to set up and had me up and testing multiple ships in short order. Remember, kids: the player cannot see your engineering.

Moving into Sunday midafternoon, I finally added the ability to shoot. I spent too long on this, since I started with the Projectile Movement component, which was fine except that I had drawn my sprites aligned to the Y-axis instead of the X-axis. This is a newbie mistake and made me have to manually rotate a few vectors to get projectiles moving the right direction. Then, I decided to tinker with having the projectiles also affected by the planet's gravity, but this required then undoing all the work with Projectile Movement, since I needed a physics object whose velocity I could manually "pull" on. I got that working, but it wasn't really noticeable or fun, and I ended up going back to the original approach.

By Sunday late afternoon I had put in the end screen and title screen, and I kicked back to look at it. My ship drawings were meant to be placeholders, but the comic badness of them had become endearing, so I decided it wasn't worth the time to futz with them. Drawing isn't my strong hand, but it also isn't my interest in this kind of work. The lack of music, on the other hand, was really noticeable. This, combined with the fact that I had never done any audio in Unreal Engine, made me think that this would be the best use of my last push. Of course, the spirit of Ludum Dare compo is that you create a game from scratch, including the music, but at this point I didn't feel like re-learning enough composition software to make a bad custom soundtrack. Instead, I turned to the reliable and amazing Kevin MacLeod (Incompetech.com), who has a browsable collection of CC-BY-licensed tunes appropriate for games. It was a little choppy figuring out how to bring the audio into the game, but no more so than I expected, never having done it before. I grabbed an explosion sound effect from the Unreal Engine Starter Kit and a laser blast from a public domain sounds site.

The last step was to create the shippable executables, which I had also never done before. The build process is slow, and at first it didn't have the window size that I wanted. I discovered that the best way to work with this was by manually editing some .ini configuration files, and once I had that right, it worked fine. I uploaded the Linux binaries, rebooted to Windows, pulled from the project's repository, and built and uploaded the Windows executables. At 8:15PM, with 45 minutes to spare, I posted to Facebook that I was done and went downstairs for a celebratory drink.

A friend with a Mac was interested in trying the game, but of course you cannot build Mac executables without a Mac. (Of course. Because reasons. And thinking different!) On Monday, I built an HTML5 version and uploaded that one too.

There is one "bug" in the game that my son and I noticed when playing together: if both players explode, then red wins. I know exactly where that is in the code, and what to do to fix it, but I decided that I'd just leave the game as-is, in the spirit of the jam. The workaround is to make sure that you get to be red.

What it all means

As I mentioned above, this was a sort of final exam to myself, and I definitely passed. I navigated through the pieces of UE4 that I had been studying and practicing, I troubleshooted a few problems by working with other engine features, and I was able to quickly learn and integrate new features. I'm still not sure how I will teach others to use this engine, but course planning is for another time.

This very modest game took me approximately 16 hours of work. If this were a three credit-hour course like my CS315 Game Programming course, that would be roughly two weeks of effort—except, of course, it's actually much more, because you'd also have to account for the extremely high cost of context switching. I heard a heuristic for designing exams that says that you should give students three times as much time as it takes you to take the exam. Let's assume that this is a good rough estimate, and we can say that my three-week project would then equate to a nine-week project by an inexperienced undergraduate. Now the amount of time I spent learning Unreal Engine the past eight months or so definitely exceeds a single course, and I have a wealth of background knowledge to draw upon. I'm afraid all of this leads me to the unfortunate conclusion that maybe something this simple is still beyond the scope of what I can expect from an average CS315 student in the Fall.

I know I've heard professors say that one of the advantages of using games as a motivating context is that students will put in more hours on them than normally required, but this feels unethical to me. Sure, some students may put in more than the expected nine effort-hours per week for a three-credit course, but the course design should not really encourage nor reward that: that's just encouraging crunch, in a field where we know it's destructive to individuals and families. I would not stop a student from learning, but I also want to be very careful to design a course that permits glorious success within the expected amount of time and effort, given the prerequisite knowledge.

I already received one pre-course complaint from a student whinging about how he doesn't like working in teams, but I think this experience shows me that teams will be necessary. My past experience with pair programming tells me that if I was learning UE4 with a friend or a cohort, I would be much further along now than I would be otherwise. Also, my time investment should help me bootstrap the students, so I can be the mentor for them that I didn't really have on my random walk through YouTube tutorials, documentation, forums, and samples.

Parting thoughts

This has become quite the epic post, but I think that's everything I wanted to record for future-me, when I'm trying to remember the kinds of mistakes I made and my thoughts about implications. I know it's easy to lose sight of how hard it is to learn something new after you've learned it. At last night's Computer Science spring banquet, an alumnus on the panel put it well, talking about programming problems: "None of us know how to do it until after we've done it." 

Two final thoughts about Ludum Dare. First, I was tickled to see a LD38 entry from an alumnus I worked with years ago, a creative and clever guy who enjoys the hobby of making little independent games. I'm so glad to see that he is finding joy in making games. Even better though is the second parting thought: one of my CS222 students was inspired by my course to make their first game this past weekend as well. With no other background besides sophomore-level computer science, this student learned Stencyl and made a fun little game from scratch, and shared it with the world as part of Ludum Dare. It doesn't get better than that!

Thanks for reading!

Thursday, April 6, 2017

Painting Runebound: The Mountains Rise

My son and I play quite a bit of Runebound. He received the The Guilded Blade expansion for his birthday a while ago, and we both really enjoyed the variety that the new cards brought to the game. He's still working on painting the miniature from that set, and it's looking pretty good. I picked up The Mountains Rise expansion so that we could get even more variety into our tabletop adventures. This expansion comes with Lothar of the Hill People Nanok of the Blade, a ridiculously wide miniature with herculean pecs.



I primarily used layering for the other Runebound heroes, but I took a different approach with Nanok, something more like I am currently doing with my Descent heroes. For the cape, I drybrushed highlights over a base color, applied a reddish-brown wash, and then brushed on slightly orange highlights. It's nothing fancy, but I like how the hint of orange adds visual interest, though it's not really evident in the pictures. The rest of him was done rather quickly with base coat, wash, highlight sequences. I mixed some blues into the metallic paints for the axe heads, inspired by the card art, and I think this gives them a nice contrast to the warm colors of the rest of the figure. The horns on his helmet needed a little attention, so I did some manual shading on them with sepia ink; similarly, the bracers/gloves are similar in hue to the flesh, so I deepened the shadows with some brownlining there as well. For the face, I brought in a technique I've seen Sorastro use on figures like Han Solo, but something that I've never tried myself: a blue glaze over the face to give the appearance of a 5 o'clock shadow. It's subtle and hard to see in the picture, in part because I was afraid to take it too far, but I'm pleased with it. Sorastro frequently uses complementary glazes to add visual interest to his models, and it's something that I would like to bring in to more of my pieces in the future.