Home Tags LÖVE3D

Ludum Dare 33: Post Mortem

Shark Swimulator Title Screen

Another Ludum Dare has come and gone. Colby and I decided to participate again, this time taking a more active approach than four months ago when we decided to enter on a whim. We spent about a week setting up a code base we felt comfortable with and even came up with a few ideas for each potential theme to help us get the ball rolling right away. We also too an active role in voting and were very happy with the theme for Ludum Dare 33: You are the Monster.

To prepare our code, we first decided on the libraries we would be using so we could create template project that was ready to go. Firstly, we have recently switched paradigms and have moved away from class-based object-oriented programming (OOP) in favour of data-driven entity-component-systems (ECS). We have significantly improved the readability and sensibility of our code with this switch and I plan to do a write up about it at some point. Knowing that we'd be using ECS, our first library of choice was the truthfully named tiny-ecs. We've been using tiny-ecs for a little while now and it's just magical. It works great, is super fast, and very flexible. We were intent on making a 3D game so naturally we included LÖVE3D, CPML, IQE, and our new animation library anim9. I'll note here that we had a serious bug in our IQM library that has since been fixed, but was not ready for Ludum Dare. Our IQM library is about 40x faster than

Read More →

My First Ludum Dare!

Alright, now that we’ve had some much needed sleep, it’s time to talk about our project, “Not My Panties!”. We weren’t originally planning to join Ludum Dare, but once the theme was released, myself and Colby decide to at least think up some ideas. After about two hours of brainstorming, we settled on “A game where a cross-dressing boy is avoiding being outed by fighting off his pursuers with a giant DS Touch Pen”. With a subject and weapon in mind, we committed to enter our first Ludum Dare Jam.

With commitment to the jam, we needed to work out exactly what sort of game we were going to make. Since it was our first jam, we decided on taking the easy route and making a turn-based battle system. I had made one of these before for a different game, so it was minimal effort to recreate it for LD. To add a little bit of depth to the game, we decided to go with a visual novel style for the story screen. Now that we had a fully mapped out plan, we got to work.

I started working on the battle system while Colby gathered up some 3D models we had kicking around and added a basic-but-working skeletal rig to our character model. By the end of the first day, we had the basic skeleton of gameplay working, a basic UI, and some little things like circle shadows for our models. We ended up spending most of day one fighting with our

Read More →

LÖVE und PANZER - Smooth Real-time Networking

With the new networking structure in place, making everything look nice is important. In my last post, I explained the idea behind how our network code works. In this post, I will explain the details that made everything come together.

First off, a quick recap. We are sending data from the client to the server on a 20Hz frequency, whch means the client is sending data 20 times each second, or roughly once every three frames. The server grabs this data and relays it on to all other clients. Ignoring latency for a moment, that means that each client is receiving new position data every third frame. Between these updates, the other tanks will just sit on the map and then jump to their new position. This is really ugly. To solve that problem, we did two things:

1) Introduce velocity
2) Use velocity to move the tank in lieu of data

When the player pushes certain buttons on their gamepad or keyboard, (in this case, left-axis-y and W/S, respectively), those inputs are encoded as movement velocity and sent along with the current position so that the server and other clients know how fast you are moving. Coupled with rotational velocity (left-axis-x, A/D), others can know where you are, and where you will be in the next frame.

typedef struct {  
    uint16_t id;
    float turret;
    float turret_velocity;
    float position_x,     position_y,     position_z;
    float orientation_x,  orientation_y,  orientation_z;
    float velocity_x,     velocity_y,     velocity_z;
    float rot_velocity_x, rot_
Read More →

LÖVE und PANZER - Real-time Networking

I am well aware that this post is late. I was out of the province for a few weeks and hadn't the time to write. I rewrote the networking code several weeks ago and it works pretty well! Let me explain what I did.

So first off I want to explain my old networking code, and why it sucked. My first ever attempt at writing network code started a few years ago. What I ended up doing was serializing data every frame and sending it to the server. I serialized everything in a text-literal way, which is to say, I used a big ol' JSON string as my packet. Yeah. When I realize this was sending copious amounts of data over the network, I decided to try a "smarter" approach which was then copied over to LÖVE und PANZER. This approach was event-driven. Instead of sending data values every frame, I would send event flags such as "move=1" or "turn=-1" in a JSON string. On both server and client I would then interpolate moves based on which flags were active. This significantly reduced bandwidth but I was still sending JSON strings. Another hiccup was the server and client were never in parity. The server was authoritative so it was sending a force-sync command to the client every second or two with absolute data which would make objects on screen jump around a bit. After actually measuring the data in LÖVE und PANZER, I realized that I needed a whole new system that accounted for

Read More →

LÖVE und PANZER - I Broke Everything... Again

I have some good news, and some bad news. Which would you like to hear first? The bad news? Okay. The bad news is... we broke it. However, the good news is we added several new features and fixes, so let me explain those first!

First off, we felt it was important to add bounding boxes to all of our objects. Bounding boxes are very useful for things like collision, be it two players ramming into each other, or one player shooting another. We decided right away that it was important for each mesh to have its own bounding box, that way shooting the air between the cannon and the hull wouldn't cause a hit. The way we created the bounding box was quite straight forward: While loading the IQE model, we looped through each vertex and checked if that vertex had a larger or smaller x, y, or z position than the previous record holder. By the end of the loop, we knew the closest and farthest points of the mesh.

local bounds = { min = {}, max = {} }  
for i=1, #mesh.vp do  
    bounds.min.x = bounds.min.x and math.min(bounds.min.x, vp[1]) or vp[1]
    bounds.max.x = bounds.max.x and math.max(bounds.max.x, vp[1]) or vp[1]
    bounds.min.y = bounds.min.y and math.min(bounds.min.y, vp[2]) or vp[2]
    bounds.max.y = bounds.max.y and math.max(bounds.max.y, vp[2]) or vp[2]
    bounds.min.z = bounds.min.z
Read More →