jglrxavpok's blog

Random thoughts and progress on my personal projects.

Creating my own game engine: Carrot

Categories:
carrot
game-engine

Sponza scene with a BMW from Need for Speed Most Wanted, and the glTF sample "Damaged Helmet"

Peeler, Scene editor of Carrot (Click image to see original)

What?

Oldest screenshot of Carrot

Logo of the engine, made by a friend

Carrot is a game engine, made mostly for fun and learning purposes. Currently only supports Windows, and only tested on a RTX 3070 (and rarely a GTX 950M). Here’s a quick list of features:

* some features might actually be a problem

How?

Libraries

Tools

Why?

Why not?

Carrot allows me to explore rendering & optimisation techniques that no other project could provide. Also it’s fun, and I’m learning a lot while doing this engine.

If you want some history

According to my Git history, I started working on this engine on 2020/11/21, almost three years ago already!

At the time I had just finished playing through Pikmin 3 on Nintendo Switch with my roommate, and Pikmin 4 was still a vague rumour. I wanted more Pikmin. Therefore I decided to take matters into my own hands.

Oldest screenshot of Carrot

Oldest screenshot of Carrot I still have around (Click image to see original)

After getting a basic skeletal animation system going (which has been rewritten twice or thrice since), I decided to add support for raytracing, to learn how hardware raytracing is used.

That’s where things got out of hand.

First working version of raytraced lighting

Years later, I had a basic scene editor…

Also see the image at the top of the page for a more recent image.


Render graph support

Render graph debug view

Support for render graphs. This is only a debug view, render graphs are only modifiable inside code.


Finally, a few months ago (3 years after starting the project!), I finally got around to starting a prototype of a Pikmin clone:

All gameplay logic is handled in C#, here’s an example to handle doors destroyed by Pikmin:

using System.Collections.Generic;
using System.IO;
using Carrot;

namespace PikminClone.ECS {
    // Declares a new system for the ECS
    public class DoorDestructionSystem: LogicSystem {
        
        public DoorDestructionSystem(ulong handle) : base(handle) {
            // this system will work with entities which have both TransformComponent and DoorComponent
            AddComponent<TransformComponent>();
            AddComponent<DoorComponent>();
        }
        
        public override void Tick(double deltaTime) {
            ForEachEntity<TransformComponent, DoorComponent>((entity, transform, door) => {
                // set the door's health when it is spawned
                if (door.firstFrame) {
                    door.firstFrame = false;
                    door.health = door.MaxHealth;
                }

                // update health text
                if (door.HealthIndicator != null) {
                    TextComponent healthIndicatorText = door.HealthIndicator.GetComponent<TextComponent>();
                    if (healthIndicatorText != null) {
                        healthIndicatorText.Text = $"{(int)((door.health / door.MaxHealth) * 100)}%";
                    }
                }
                
                // if bots are attacking this door, decrease health
                double healthDecrement = 1.0f;
                foreach (var bot in door.botsAttacking) {
                    door.health -= (float)(deltaTime * healthDecrement);
                }

                // kill door entity
                if (door.health < 0.0f) {
                    door.DetachBots();
                    entity.Remove();
                }
            });
        }
    }
}

And there is still A LOT I want to add to my small engine.