ecmjohnson

LD 41

So many MotherDucking fantastic games!!

It's been a pleasure to have participated in my first Ludum Dare game jam alongside so many incredible games! I haven't got the chance to play many games quite yet, but I'm really looking forward to it (I've got a very long list on itch)!

I thought you folks might be interested in a time lapse of our creation coming together! It was the first real weekend of spring here in Ottawa and we chose to spend it bringing this wonderful monstrosity into the world. The time lapse only covers 48 hours, since that's all the time we could get together to work on our game.

https://youtu.be/J8PeJ9DeReA

The game we made is MotherDucker and we eschewed the theme to bring to life an idea we'd had the week before when brainstorming. Our game is a mother duck simulator where you play as MommaQuack and try to get her home through a terrifying mix of bear traps, saw blades, and cannons. Good duck leading your babies to safety through this strange and quacky world!

https://youtu.be/m1wH7l75kz4

LD 43

AkimBear doesn't follow rules

AKIMBEAR_menu.gif

I really just wanted to show off all effort I put into a reflective water surface

2D Reflections in AkimBear

I’d like to share my approach for creating reflections for AkimBear in Unity since I think it turned out rather well and could give you some ideas for future projects. I am a technical one so there will be code, but I’ll try to keep it to a minimum.

Inspiration

If our reflections look at all familiar that’s because I based them on this post from Kingdom’s TIGsource. I wasn’t as strict on my pixel precision and didn’t do any of the perspective correction that Kingdom details (this being a game jam after all).

Overview

You can get an idea of the final result (if you haven’t played AkimBear yet) from the trailer:

https://youtu.be/avRx-U6SNHk

I felt that a flowchart of the rendering to attain the reflection would give the best sense for how this effect is achieved at a system level:

RenderFlow.png

In terms of components, the system is just a camera for capturing the area to be reflected and the reflection itself.

ReflectionSystem.PNG

Easy, right? Stick around for the alignment issues.

More perspectives on the world

Apparently, a camera in Unity cannot both display on the screen and render to a texture. Initially I found this disappointing as that’s what reflection is right? I think this may have actually been a blessing in disguise; AkimBear has a rather lively camera (both position and orthographic size are constantly changing) and I might have ended up with even more mess if I’d been trying to use that camera to generate reflections.

A second camera it was! This camera is offset up from the main camera and it has a render texture set as its target texture. Other than that, it’s identical to the main camera… or so I thought initially (see camera property matching script later). This was my first eureka moment, since I could see the screen in the inspector for the render texture:

ScreenTexture_inspector.PNG

The TIGsource thread from Kingdom had stated that this was not possible without the Pro version of Unity so I was very, very happy when this just worked without being pay-walled.

It’s basically done now right?

Sitting under a tree on a sunny day

The task of the shader is quite simple: take a sample from both the screen texture and the highlight texture and then combine them. The sample into the screen texture should ripple to give the sense of water and the highlight should show some flow. I’ve commented this snippet (shader source here) to give you an idea of what everything does:

fixed4 frag(v2f IN) : SV_Target { // Generate an offset value in both x and y directions float offx = noise(15.0 * IN.texcoord - 1.5 * _Time.yx); float offy = noise(0.05 * IN.texcoord); // Sample the screen texture offset in the x direction float2 uv = IN.texcoord + float2(0.02 * offx, 0.0); fixed4 c = tex2D(_ScreenTex, uv) * IN.color; // Sample the highlight texture uv.y += offy; fixed4 h = tex2D(_Highlights, 3.0 * uv + _Time.yx / 2.0) * IN.color; // This is not good shader code; should be no dynamic branching! // maybe o = lerp(c, h, h.a) would have worked as well? fixed4 o; if (h.a > 0.5) { o = lerp(c, h, 0.5); } else { o = c; } o.rgb *= o.a; return o; }

Why did I use a noise function seeded with a 2D vector? This is a legitimate question and I’m not sure (I’m sure it made more sense at the time). The same result could have been attained with a few trig functions and would likely have been more efficient.

Why all the magic numbers? If you take their product it spells game jam in ascii. Just take my word for that.

All done right?

alignment_bad.gif

Well, its kind of reflecting.

The last 10% is 90% of the work (but not of this post)

A few unacceptable issues are apparent. They all stem from using Cinemachine to control our camera for following Grizzle and creating screen shake. This means that it isn't as simple as just attaching our second camera and reflection surface to the main camera. This was solved with a few scripts to exactly follow the Cinemachine (main) camera on any axis and match the parameters for the two cameras. The parameter matching is incredibly hacky: it uses linear interpolation across empirical values to keep the reflection camera at the right offset while the orthographic size is varying.

After much hacking, both the reflection camera and surface were following the wild zooms and shakes. This took much longer than the actual reflection to get right.

Remaining bug

The last remaining (apparent) issue with the reflection system is quite awful. I really wished I’d had time to fix it (maybe a variable passed to the shader on a per-frame basis to compensate for it?). But I’ve yet to hear anyone notice it on their own, so if you see it keep it to yourself.

Find the bug yourself by playing AkimBear!

This was a pretty quick overview, so if you want to know more, feel free to reach out! If you want further detail than the comments allow, my email is ecmjohnson at gmail.com

Making a Vlambear style game

In the making of AkimBear, we chose to use this talk from Vlambeer‘s Jan Willem Nijman, a true master of arcade action games, as our inspiration. In fact, as soon as we had the rough sketch of our idea (i.e. akimbo-wielding bear with sacrifice used in the gameplay design), we watched the talk in order to get it in our heads when we started building the game. The trailer can give you a good idea of the game we ended up with:

https://youtu.be/avRx-U6SNHk

I highly recommend watching the talk if you have an interest in building games with strong immediate feedback. I also really like Nijman’s perspective on the layers of feedback in creating interactive experiences. In the talk he takes a basic game and adds tweaks to get something that is much more appealing to play. Those points are below and I’ve annotated them to show how we used them. The bold points were taken directly and the italic points were only partially implemented in AkimBear.

  1. Basic animations & sound
  2. Lower enemy HP
  3. More enemies
  4. Bigger bullets BiggerBullets.PNG
  5. Muzzle flash
  6. Faster bullets
  7. Less accuracy (missed this one!)
  8. Impact effects ImpactEffects.PNG
  9. Hit animation (and effects) HitEffects.PNG
  10. Enemy knockback
  11. Permanence
  12. Camera lerp
  13. Camera position
  14. Screen shake screen_shake.gif
  15. Player knockback
  16. Sleep (time slowdown)
  17. Gun delay
  18. Gun kick
  19. Strafe
  20. More permanence Permanence.PNG
  21. More bass
  22. Super machinegun
  23. (Random) explosions BiggerExplosions.PNG
  24. Faster enemies
  25. More enemies
  26. Even higher rate of fire
  27. Camera kick
  28. Bigger explosions
  29. Even more permanence
  30. Meaning meaning.gif

A lot of the above are obvious when you see our gameplay. I’d like to talk about one of the less obvious points that we used when designing AkimBear: Player Knockback. During his talk, Nijman says “if you put a button in a game … give someone a reason not to press it.” This was the inspiration for deciding that Grizzle should stop moving while shooting and how this could be the gameplay sacrifice.

I’ve gotten some feedback about the time slowdown being too strong and I think this is quite valid since it feels almost like framerate issues sometimes (particularly when off screen enemies are killed). I limited the permanence by using a ring buffer object pool for the number of bullets at any time for pre-emptive performance reasons. I know “premature optimization is the root of all evil,” but once you start pooling objects there’s really no reason not to pool everything. In this case, I would disagree with Nijman; despite computers being very good now, you should default to defensive and performant coding (if possible, for your experience level) until there is a design reason to expand. Limiting runtime memory is always a good idea to avoid unnecessary garbage collection (this is especially crucial for mobile devices).

Check out the gameplay by playing AkimBear!

If you have any questions at all, don’t hesitate to ask! My email is ecmjohnson at gmail.com

Ludum Dare 53

Currently Unnamed Game About Teeth

Looks like I'm opting out of the theme since I misread it as teeth

Main menu

teethemmenu/emselectionemnonsplit/emsmall.gif

Pulling teeth with harpoons

teeth_gameplay.gif

Ludum Dare 54

Ludum Dare 57

Bowling, but it's Kerbal Space bowling

Bowling balls do not normally allow enough user expression, so I took a page from Kerbal Space Program and added a building system to the game of bowling:

Bowlding

I made sure to include a flail, which I've always wanted while at the alley!

building_small.png