Fork the Zombies! an Interactive Halloween Game

89665

Intro: Fork the Zombies! an Interactive Halloween Game

Trick or Treating is Back! In this Instructable, I'll provide all the ingredients you need to create your own interactive Halloween-themed game. If you've seen any of my previous instructables, you know that we're going to combine an interesting physical controller with a simple concept video game.

STEP 1: Concept and Rules

In the words of Duke Ellington: "I don't need time, what I need is a deadline." I don't know how the rest of you work, but this is completely me.

For this project, my youngest son (he's 13 now) and I were discussing a cool project that we could add to our Halloween decorations this year. Since our house tends to be zombie-themed, we decided to remain with it. It probably only took us a few minutes to flesh out the entire concept. The key element was forks- my son's idea, and we came up with some rules of how zombies are allergic to forks, and we just needed a way to fling em out there.

Now we've got a concept. Only a few things to work out:

  • The game really needs to last like 1 minute or less, as this is a party game and we need to keep the line moving
  • It's got to look cool, so people are interested when they amble up for some candy
  • We need some awesome physical hardware to play the game.

Keeping those things in mind, here's the separate pieces that needed development. We'll cover each of these below:

  1. The "Video Game" part, which is a herd of ever-increasing zombies headed your way
  2. The "ForkBow" part, the controls that you use to keep the zombies at bay
  3. Hit detect, how do we know WHERE the ForkBow is pointing, and when the trigger is pulled?
  4. Integration- pulling it all together in time.

STEP 2: The Video Game

First, let me tell you this was a ton of fun. It's also definitely NOT my major jam, so I was learning a lot the whole way. All of my development was done on a linux laptop, and I chose a 3D engine called "Urho3D" In addition to this entirely free and open source engine, you can find a terrific and supportive community interested in helping you succeed. Interested? Here they are: https://urho3d.io/

Now, Urho3D comes as a source distribution, BUT you can compile it with free tools for just about any platform. As a stroke of ultimate cool, they provide 54 example projects that show you how to implement most of what the engine can do. I started with example 6 "Skeletal Animation". In fact, you can try out this example in webgl here: https://urho3d.io/samples/06_SkeletalAnimation.html

This demo has most of what I need- animated models, walking forward. All I really need to do is substitute in some zombies and I'm most of the way there!

But there's a problem- though I can model static objects in Blender, I never learned to animate a model. With 3 weeks left, I wasn't going to get there in time. Fortunately, there's an entire marketplace of this kind of thing available, and I found a good set of zombie models available with animations for a reasonable price. Here's the one I used: https://www.turbosquid.com/3d-models/zombie-set-animations-25-3d-model-1250738

The model comes in both 'FBX' and 3DS MAX format, but Urho3D requires its own 'mdl' format. From here' Urho3D includes an "AssetImporter". If you just type 'AssetImporter' it gives you instructions to use- and you can change the format for both model and animations to the Urho mdl and ani. This worked great! And soon I had zombies shambling around instead of the warrior in the original example. One Note: when you import a model, you _may_ have to experiment with the model's scale and rotation, these are not guaranteed to be consistent. These factors are called out clearly in the example code, and easy to change.

So I added a format to the game. Your first shot *starts* the game, and zombies begin to spawn at an ever-increasing rate. To control the pace and length of the game, I have the zombies increase in frequency as the game continues. You can only launch 2 forks per second and even if you're careful, you're going to be overwhelmed in about a minute. Best you can do is take as many zombies with you as possible.

The obvious missing piece that I need is some sort of physics, or "hit detection". Urho3D has support for Bullet Physics built right in. Cue the appropriate demo!

https://urho3d.io/samples/11_Physics.html

This demo had it all- it launches an object wherever your camera is pointing, allows for gravity, and lets the chips fall (literally) where they may. I made a few changes- instead of launching a box, I changed it to a fork, and I made it fire wherever you happened to have the mouse pointer, and gave it a speed so it would drop like it was flung from a, you know, fork crossbow. OK, here's how the game came out:

Quick note: If you're looking for the source, no problem! There's a link in the last step.

STEP 3: What Are You Pointed At?

I mentioned that I like to use interesting physical controls in a game. We'll get to that in a second, but before we do, let's talk about how we're going to make it work- where exactly, are you pointing? Since you've already figured out I'm using a laser to aim our ForkBow, why don't we put a webcam out there to track it? To filter out most of the non-red light that we don't need, I found a bit of red filter material and cut a small piece to put in front of the camera while we're running. This made it WAY easier to ignore everything else on the screen, focusing only on that red laser dot (if it exists). I mentioned that I'm using the Jetson Nano (specifically the 2GB version) with a webcam to pick up these images, then determine the location of the red spot. You could also use a laptop with a built in webcam. I'll provide the python source code here, but if you're curious about what's going on, try this tutorial which supplies a great example of color filtering:

https://pythonprogramming.net/color-filter-python-opencv-tutorial/

Now that we've got a picture of our screen (and red spot) let's figure out where it's actually located! We do that two ways:

  1. We calibrate our image by projecting a known size checkerboard, and locate all of the inside corners on video. Guess what- there's an openCV function for that in Python, if you want to take a deeper dive you can do so here:https://docs.opencv.org/3.4.15/dc/dbb/tutorial_py_calibration.html We now have a series of mapped coordinates on the projection screen. We turn that into a 'Homography Map' which we can use to account for misalignment, pincushion, keystoning, and just about any other aberration that shows up in our image. Oh yeah- now the location of our dot is absolute! Let's have a quick video demonstration:
  1. Next, since the only thing left in the image (after color filtering) is the dot, we go looking for contours. There should only be one, and the centroid should be the center of it.

All good so far. If there's a dot, we know where it is. BUT, having a spot may just mean you're aiming! To complete the game, you need to tell it to fling a fork! Let's head to the next step for that.

STEP 4: The ForkBow

It was 3 days before Halloween, and while I've tested with a laser pointer, I STILL don't have a cool control mechanism to fling forks at zombies. Enter the ForkBow. I started with a 30" long scrap 2x4, and used a band saw to hand cut the general shape. Normally, I measure EVERYTHING twice and do 1/2 hour of calculations before making a cut, so this was good for me. After I had a general shape, I used a belt sander to knock off the corners and splinters. So far I'm in about 5 minutes. From there, I drilled a hole in the front to match the diameter of my laser module, cut a small trench in the top to run power wires to the laser, and drilled a few extra holes to route the wiring. I then hot-glued the laser and wires in place. From there, I designed a few pockets to hold the ESP-32 (more detail on this in a bit) and the batteries. I cut those pockets with my CNC. Please note- I built a CNC last year, and so now I use it for everything. Cutting pockets? CNC. Making a wooden marble run? CNC. Got to sign a bunch of documents? Scan your sig, strap a pen in, and do it with the CNC. The important thing is you don't need a CNC to do this project, you can get by just fine with a hand drill and a wood chisel. In spite of the fact that the whole Forkbow took like an hour to make, it generated more questions on Halloween than anything else: "Did you make that crossbow yourself? How?"

For the trigger well, I just drilled a couple of 3/4" holes with a hand drill, and chiseled the walls flat. The trigger itself is a microswitch, but it has a 3D printed shell over top. Imagine a piece of U-channel with a hole drilled through it, and you've got the idea. The microswitch itself is connected from ground to GPIO0 on the ESP32. Looking to get started on the ESP32? Great! I'd recommend starting over here: https://randomnerdtutorials.com/program-upload-code-esp32-cam/ where Sara and Rui Santos will walk you through basics, then more advanced use of these wonderful boards. You can also find some great instructables!

I covered the ESP32 pocket with a chunk of polycarbonate that I had laying in the shop. The other pocket contained the batteries. Though I didn't need to change them all night, I did leave that pocket open just in case.

For hardware- that was it. Plugged a battery in at the beginning of the evening, and it ran great. Every time you hit the trigger, the ESP32 (connected to the same wifi router as everything else) would generate a UDP packet towards the hit detector. Why the hit detector? To keep traffic at a minimum. The hit detector is always hit detecting, but doesn't report to the game until it sees this UDP packet. I'll provide the source (Python) and a block diagram in the "Integration" step.

Speaking of source, if you're feeling a bit curious, the source of the ESP32 code can be found here (not- it's arduino based!) https://github.com/pilesofspam/fork-the-zombies/tree/main/lasergun

STEP 5: Integration!

Now we've got a game, a way to locate our laser spot, and a unique control mechanism. Let's put it all together!

I put together a diagram above to show how things go together. The Nanos connect by wire to a router, one has a webcam, the other has the projector. Your ForkBow is wireless (note in the source code your wifi SSID and password). How do these things communicate? Well, the ForkBow is old-school, it's just firing a UDP packet (check out the code! I promise it's short) but everything else needs to provide a myriad of information. To relay this information, I chose a library called "ZeroMQ". This library is cross platform, brokerless, and available in just about any language you could imagine. Just getting started? I recommend the Python bindings. To get you going, check it out here.

A couple of tricks to make it all go:

1. It takes about 1/4 second before a laser spot becomes a known point on the screen, so the laser detect is running continuously. That way we've got a spot ready when your player pulls the trigger. The only drawback is that you may fire a bit behind if you're in motion when you fire, but nobody seemed to notice.

2. Location: All laser locations are normalized. Remember the checkerboard we saw earlier? When that gets projected full screen, we now have calibration points. From the bottom left of the checkerboard, your X,Y location is 0,0. Proceeding to the top right of the checkerboard, your location is 1,1, and every point in between is a fraction of that. This means that the resolution of your camera (or projector) can change, and the game will still act the same way.

2. SOUNDS- Urho3D allows for 3D sound, which can handle stereo and distance. I took the simple way out and played all sounds out of both speakers at a fixed volume. I chose sounds from freesound.org and I have a list at the bottom here to properly attribute all sound authors.

STEP 6: So, How Did It Go?

We had a blast. The image at the top of this step features a gaggle of fairies playing (gaggle? group? herd? anyway...). Pretty much every group of kids that came by gave it at least ONE shot, many stayed for a few plays, just recycling through the line. Most of the accompanying adults gave it a shot too. To keep things clean we kept the groups separated, and made hand sanitizer available to all visitors.

The batteries lasted all night without needing a change, and nothing ever broke or stopped working. We did have a few isolated incidents of "it's MY turn" but the game moved fast enough to prevent this. While I took a bunch of pictures, one thing I never did do was get a video of the game playing, so I'll get one of my older son now:

STEP 7: The Source

The Source for this project can be found here:

https://github.com/pilesofspam/fork-the-zombies

To build the game, first install the Urho3D source code from: https://github.com/urho3d/Urho3D

Then apply the above (fork-the zombies) code to Samples/06-Skeletal animation. Make sure that you have the ZMQ development library installed for your platform (Linux, Mac, WIndows, even Raspberry Pi)

The laser detect code can be found in pretty much the same place: https://github.com/pilesofspam/fork-the-zombies/tr...

And you can find the ESP32 code (for your ForkBow) here: https://github.com/pilesofspam/fork-the-zombies/tr...

For this last one, you'll first need to set up the Arduino environment available from https://www.arduino.cc/

All of the code linked in GitHub above is released MIT licence.

STEP 8: Acknowledgements

Time to credit the folks who created things present in this game:

  1. Urho3d: https://urho3d.io/
    1. To weitjong and all the other devs, seriously- this rules
  2. Sounds from freesound.org
    1. Zombie grunt: https://freesound.org/people/lolamadeus/sounds/18...
    2. Background music: Komiku, Welcome to the Machine (Creative Commons, public domain)
    3. Fork miss (ping): https://freesound.org/people/edsward/sounds/34187...
    4. Fork hitting a zombie: https://freesound.org/people/j1987/sounds/335758/
    5. Fork Fling: https://freesound.org/people/pan14/sounds/334032/
    6. Getting slapped by a zombie: https://freesound.org/people/nicholasdaryl/sounds...
    7. Zombie Death Sounds:
      1. https://freesound.org/people/tonsil5/sounds/555412...
      2. https://freesound.org/people/tonsil5/sounds/555425...
    8. End Howl: https://freesound.org/people/PhonosUPF/sounds/499...
    9. Skybox: Stitched this together: https://polyhaven.com/a/autumn_forest_03
    10. That's everything except the zombies, which I linked back up in step 2.

Thanks for having a read. Like it? Not so much? Got questions? Lets get a discussion going- leave a comment!

4 Comments

Hi,
thanks for your support.
For me the changes in /urho3D/cmake/Modules/UrhoCommon.cmake did not
work, I had success with adding -lzmq at the end of the line in Source/Samples/06_SkeletalAnimation/CMakeFiles/06_SkeletalAnimation.dir/link.txt

Its quite a lot to do whats not really described. I needed to get a font and when I tried to convert the models it was unclear for me which file should get which name. Same with the sounds. A list what asset should get what name would be really handy. Probably because of that I have still lots of missing files. I also do not know how to get Materials like Models/zombie/Materials/zombie1.xml so the figures are just white for now.
Can you help me here?


Hi Thorsten: Absolutely. My direction when writing this instructable wasn't to necessarily recreate THIS in particular, but rather provide direction on how you would go about making your own. As a result, it's missing some of the details (as you've clearly found). That said, let me get you set up with the correct assets and materials. If I can find time over the next few weeks, I'll better update this instructable with those details, and make sure you get the credit. UNTIL then, I have created a few folders in the github: https://github.com/pilesofspam/fork-the-zombies

You'll need the files in /Materials (which will ultimately go in ./Data/Models/zombie/Materials and Textures (./Data/Models/zombie/Textures).

Next the font- I had forgotten about the font, I need to credit that at the end and include the SIL licence verbiage on github- it's Creepster-font and available here: https://www.1001fonts.com/creepster-font.html
That will go in ./Data/Fonts

I have also renamed many of the sounds, and few have been edited with Audacity- mostly for length, as some had some silence at the beginning. Here's a quick table of what sounds are what- please update here if you need any additional. All of these go in ./Data/Sounds/zombies
In Game Sound -------------- Original name/format
background.ogg ----- Komiku_-_07_-_Welcome_to_the_machine.mp3
zombiewalk.wav ----- 181068__lolamadeus__zombie-vocals-grunts.wav
howl.wav ----- 499699__phonosupf__howling.wav
boing.wav ----- 334032__pan14__boing-spring-mouth-harp-04-20-13-4.wav
hit.wav ----- 335758__j1987__water-slap.wav
1.wav-4.wav ---- I uploaded these to github under ./Sounds since these were released under public domain licence (though I credited the author in the instructable)
cartoonpunch.wav ----- 563356__nicholasdaryl__cartoonpunch.wav
miss.wav ----- 341871__edsward__ping.wav

Hi,
I try to compile the project on a Ubuntu 20.04 notebook, but I get linking errors:

/usr/bin/ld: CMakeFiles/06_SkeletalAnimation.dir/SkeletalAnimation.cpp.o: in function `SkeletalAnimation::SetupZMQ()':
SkeletalAnimation.cpp:(.text+0x216a): undefined reference to `zmq_connect'
/usr/bin/ld: SkeletalAnimation.cpp:(.text+0x218c): undefined reference to `zmq_setsockopt'
/usr/bin/ld: CMakeFiles/06_SkeletalAnimation.dir/SkeletalAnimation.cpp.o: in function `SkeletalAnimation::CheckMessages()':
SkeletalAnimation.cpp:(.text+0x30dc): undefined reference to `zmq_msg_init'
/usr/bin/ld: SkeletalAnimation.cpp:(.text+0x30f0): undefined reference to `zmq_msg_recv'
/usr/bin/ld: SkeletalAnimation.cpp:(.text+0x3101): undefined reference to `zmq_msg_size'

(more similar stuff follows)

I have installed all of the libzmq stuff including the dev packages. I'm quite experienced in developing in various languages. But I'm totally new to cmake, Urho3D and game developing.
For me it looks like either the libzmq version I installed does not contain the needed functions or the make file does not even try to link it to the binary. Since the functions seem quite essential by there names I suspect a problem with the makefile.

Do you have an idea how I can fix this, or a hint how I can debug it?

Thanks
Thorsten
Thorsten! Sorry for the delay, I just got a notification that there was a comment. Yep- I got a fix for you:

First, if you don't have a laser detecting setup, you can just remove all references to zmq from SkeletalAnimation.cpp and SkeletalAnimation.h and play with a mouse.

BUT, if you intend to shoot zombies with a ForkBow like God intended, then we'll need to add it. Trick is, zmq isn't supported directly by cmake (I am new to cmake as well, this was a pain). BUT- it is supported by pkgconfig. I added zmq support with these changes:
1. Open up /urho3D/cmake/Modules/UrhoCommon.cmake, and at about line 989, you'll see something like 'if (URHO3D_LIBRARIES)' well, right under that, add this (when I get around to it later today, I'll add this to my git repository):


find_package(PkgConfig)
## use pkg-config to get hints for 0mq locations
pkg_check_modules(PC_ZeroMQ QUIET zmq)
## use the hint from above to find where 'zmq.hpp' is located
find_path(ZeroMQ_INCLUDE_DIR
NAMES zmq.hpp
PATHS ${PC_ZeroMQ_INCLUDE_DIRS}
)
## use the hint from about to find the location of libzmq
find_library(ZeroMQ_LIBRARY
NAMES zmq
PATHS ${PC_ZeroMQ_LIBRARY_DIRS}
)

BTW- zmq is awesome. Cross platform, brokerless, I'm just using the pub-sub model but found it really reliable and exceedingly easy to implement.