Hello there people,
So as a side-project during the holidays, I took a short break from
CraftStudio development and I started a little top-down multiplayer shooting game, it's kinda like a 2D Alien Swarm. I'm calling it
Project Lockdown as a working title. Here's a short gameplay video:
(Just to be clear, this game wasn't made with CraftStudio or anything. I do plan to recreate it with CraftStudio later this year, as a way to validate CraftStudio for real game development, but for now it's just another XNA game)I setup the engine in under 30 hours (rough estimation). It's written in C# and here's how it works:
- XNA does rendering & input
- I use NuclearUI (part of my open-source set of XNA libraries) for the little GUI at start up. This was a big time saver!
- Networking is handled by Lidgren
- Maps are created using Tiled and processed using TiledLib in an XNA Content Pipeline Extension
- Scripting is done with Lua through LuaInterface. I was very glad to finally find an up-to-date Lua lib for C#! (well Lua 5.2 was just released but I'm fine with 5.1 support)
The engine fully separates game logic from rendering, building on previous work I had started for (the sadly unreleased for now) QuadSmash Online.
I have a GameLogic and a GameRenderer class. The host player instantiates both while other players only have a GameRenderer.
The GameLogic loads a Lua file describing the level and calls its OnInit() function after registering various facilities for loading maps or handling events. Here's the script for the current test level (FSQ is the API namespace, I'll change it to LKD or something else for the final game name):
FSQ.OnInit = function()
map = FSQ.LoadMap( "Map01" )
end
gate01SwitchCount = 0
FSQ.OnFloorSwitch = function( floorSwitchName, pressed )
if floorSwitchName == "switch01" or floorSwitchName == "switch02" then
if pressed then
if gate01SwitchCount == 0 then
FSQ.SetLockState( "gate01", false )
end
gate01SwitchCount = gate01SwitchCount + 1
else
gate01SwitchCount = gate01SwitchCount - 1
if gate01SwitchCount == 0 then
FSQ.SetLockState( "gate01", true )
end
end
end
end
The game runs at 60 ticks per second, and networking is 15 ticks per second. Regular object updates (position, angle updates, etc.) are sent by the server one every 4 logical ticks, and the client interpolates 4 frames between those network ticks, which means the client is always at least 1/15th of a second late (not including network latency). This is pretty much unavoidable unless you want to be doing prediction at all times for all objects. I might add some client-side prediction for player movement but for now it seems to work well enough.
One-time events (switches pressed, bullets fired, enemy damage, etc.) are sent right away by the server, specifying at which logic tick they happen. They still happen with 1/15th second delay on clients, but they are enqueued and consumed only at the correct time thanks to the precise tick info.
Here's a screenshot of the first map in the map editor:
Tiled has really grown to be a great tool. Being able to place objects and name them, and then reference them in a script file (all without writing a custom level editor) is many kinds of awesome!
That's it for now! I'll try to release a little test build of the game later this week, but I need to get back to working on animation support in CraftStudio!
Consider
following me on Twitter at @elisee if you want to be kept up to date on this project and others.
See you guys soon!