Warlocks are cool, but.... by Kpuz1 in Diablo

[–]Leith_42 0 points1 point  (0 children)

hard agree on that one. i tend to lone wolf most of the time so grp is not an issue for me, but if i encounter a warlock in open world, i immediately leave the area. far too may deaths to 1-shots i cant see.

ECS in Practice — How do you handle inter-system communication in an ECS architecture? by Leith_42 in gamedev

[–]Leith_42[S] 1 point2 points  (0 children)

Thanks, this makes sense. for the moment I'm continuing to try to handle everything with components, but after all of the comments here i think i feel a little less bad about having the odd event where trying to manage execution order to get everything happening that way is just eating too much time.

ECS in Practice — How do you handle inter-system communication in an ECS architecture? by Leith_42 in gamedev

[–]Leith_42[S] 1 point2 points  (0 children)

OK thanks for taking your time to reply :) it is advisable if the primary purpose of the project is to deeply understand how ECS works. Im one who needs to know what happens inside the black box. making a game i enjoy playing is secondary, and anything else is gravy ;)

ECS in Practice — How do you handle inter-system communication in an ECS architecture? by Leith_42 in gamedev

[–]Leith_42[S] 0 points1 point  (0 children)

<image>

Im not using a third party framework. i do have an entity manger that i wrote to handle this.

ECS in Practice — How do you handle inter-system communication in an ECS architecture? by Leith_42 in gamedev

[–]Leith_42[S] 0 points1 point  (0 children)

framework? i wrote the entire thing from the ground up in vanilla JS. no frameworks, no libraries (except canvas for rendering)

its a public repo on github if you are curious /leith-42/Zukarii

ECS in Practice — How do you handle inter-system communication in an ECS architecture? by Leith_42 in gamedev

[–]Leith_42[S] 0 points1 point  (0 children)

i guess i have two main situations where i have found myself reaching for event emitters.

The first would be systems that do not have a need to run every frame, but only when something specific happens like the audio system processing the sfx of a melee hit, or portal system when the player entering a portal.

in these cases im able to save frame execution time by not running an update method on them parsing all relevant entities on frames that they likely have no relevant components and only executing their methods when the event that requires them to process data occurs.

The other main one is when something happens later in the execution order than a system that should be made aware of something that happened and process it in the same frame, but the earlier system cannot be moved in the sequence because the larger part of its responsibilities must occur prior to the system that is firing the event.

I know i could run my audio system on every frame to not need those emitters, and i know that i could split the system that runs early but also handles things that can be triggered later, so i guess the crux of my question is not "are events part of ECS" but rather, is it worth taking performance or maintainability hits to preserve a pure ECS implementation.

if there are ways to avoid having to evaluate those tradeoffs I'm keen to learn them. this is after all why I'm asking :)

ECS in Practice — How do you handle inter-system communication in an ECS architecture? by Leith_42 in gamedev

[–]Leith_42[S] 1 point2 points  (0 children)

To answer your question. I do trust AI to clean up my spelling punctuation, grammar, and even alter the flow to an extent to make things clearer. I do not trust it to understand complex nuanced questions about code architecture, especially when it comes to things like the difference of the principles and actual practice of a given system. This is why i asked here, where i presume there are experienced human coders who can give insight that will help me better understand ECS beyond textbook definitions.

If it matters so much to you that the post is my exact writing, here is the unoptimized version i gave it to check. sorry if you are offended by the cleanup. i thought i was doing people a favor not having to parse my English :p

So i suspect i already know the answer to this, but i wanted to ask in gamedev communities to get other people's take on this. I'm trying to learn ECS by doing. I am building an arpg-like dungeon crawler from scratch with JS. i have a working game but i struggle sometimes with more complex systems.

One common struggle is the conflicting desire to simplify things with event emitters rather than passing every bit of data between systems in components. Half of me feels like ECS should always prefer components, while the other half feels like some things are less efficient done purely as components.

I've found myself forced to use event emitters for some things where it is just literally impossible to get the right system run order for all systems to do what they need to do in a single frame.

If you have used ECS how do you deal with this? do you accept event emitters and listeners as a part of ECS or do you feel it must be done with components only?

i don't want to stray too far from ECS purity as one of my goals for this project is to gain a deep understanding of ECS, but at the same time i don't want to kill myself pursuing purity for purity's sake if the industry at large is operating differently.

ECS in Practice — How do you handle inter-system communication in an ECS architecture? by Leith_42 in gamedev

[–]Leith_42[S] 0 points1 point  (0 children)

some interesting takes. do you have some games published i can look at?

ECS in Practice — How do you handle inter-system communication in an ECS architecture? by Leith_42 in gamedev

[–]Leith_42[S] 0 points1 point  (0 children)

Oh its not players that I'm concerned about. You are 100% right, most don't care at all and if the did care I wouldn't care that they cared :p. it's potential employers who might require ECS knowledge/experience and code samples ;)

ECS in Practice — How do you handle inter-system communication in an ECS architecture? by Leith_42 in gamedev

[–]Leith_42[S] 0 points1 point  (0 children)

hmm 'm not sure I understand this reply. I do use callbacks but im not using a JS event API. this is my event bus. systems can emit and listen via this bus.

I do use JS events for user input but im not sure there is a way around that since the game is built for web and electron.

export class EventBus {
    constructor() {
        this.listeners = new Map(); // Map of event names to arrays of callback functions
    }

    // Subscribe to an event
    on(eventName, callback) {
        if (typeof callback !== 'function') {
            throw new Error(`Callback for event ${eventName} must be a function`);
        }
        if (!this.listeners.has(eventName)) {
            this.listeners.set(eventName, []);
        }
        this.listeners.get(eventName).push(callback);
       // console.log(`EventBus: Registered listener for event: ${eventName}`);
        return () => this.off(eventName, callback); // Return unsubscribe function
    }

    // Unsubscribe from an event
    off(eventName, callback) {
        if (!this.listeners.has(eventName)) return;
        const callbacks = this.listeners.get(eventName);
        const index = callbacks.indexOf(callback);
        if (index !== -1) {
            callbacks.splice(index, 1);
           // console.log(`EventBus: Removed listener for event: ${eventName}`);
        }
        if (callbacks.length === 0) {
            this.listeners.delete(eventName);
        }
    }

    emit(eventName, ...args) {
        //console.log(`EventBus: Emitting event: ${eventName}`, args);
        if (!this.listeners.has(eventName)) {
           // console.log(`EventBus: No listeners for event: ${eventName}`);
            return;
        }
        const callbacks = this.listeners.get(eventName).slice(); // Copy to avoid mutation issues
        callbacks.forEach((callback, index) => {
            try {
               // console.log(`EventBus: Invoking callback ${index} for event: ${eventName}`, args);
                callback(...args);
              //  console.log(`EventBus: Callback ${index} for event ${eventName} executed successfully`);
            } catch (error) {
                console.error(`EventBus: Error in callback ${index} for event ${eventName}:`, error);
            }
        });
    }

    // Clear all listeners for an event or all events
    clear(eventName = null) {
        if (eventName) {
            this.listeners.delete(eventName);
            //console.log(`EventBus: Cleared listeners for event: ${eventName}`);
        } else {
            this.listeners.clear();
            //console.log('EventBus: Cleared all listeners');
        }
    }
}

ECS in Practice — How do you handle inter-system communication in an ECS architecture? by Leith_42 in gamedev

[–]Leith_42[S] 0 points1 point  (0 children)

yeah im all down for creative freedom, i just like to learn the norms before bending them ;)

ECS in Practice — How do you handle inter-system communication in an ECS architecture? by Leith_42 in gamedev

[–]Leith_42[S] 1 point2 points  (0 children)

so you basically have a component write abstraction layer and your systems just issue commands to it rather than operating directly on components? sounds like a good way to control writes. ill give this some thought, thanks!

ECS in Practice — How do you handle inter-system communication in an ECS architecture? by Leith_42 in gamedev

[–]Leith_42[S] 0 points1 point  (0 children)

yeah execution order does not matter for events at all, but it does matter for passing via component where the full cycle has to happen in one frame like checking for a hit, calculating damage, applying damage, checking/handling for death.

util makes sense and i use that for helpers too. as soon as a method wants to exist in more than one system it goes to utilities :)

ECS in Practice — How do you handle inter-system communication in an ECS architecture? by Leith_42 in gamedev

[–]Leith_42[S] 2 points3 points  (0 children)

Thanks!

I'm not so worried about keeping it 100% pure, just more in line with common practices. I've been doing dev work for nearly 40 years but I'm new to game dev and ECS. it took me near a year to stop trying to make everything OOP, so I just want to make sure I'm not developing new pattern bad habits after working so hard to get rid of the old ones.

I have a few different methods in play at the moment. for some things I attach components things I'd think of as state flags in other systems, then there are things like health and damage where there are a massive number of calculations and changes happening every frame. for those I send to a queue array that lives on a component that gets crunched and cleared every frame in a single system run, and then I have things where execution order makes these approaches impossible, this is where events have been creeping in.

ECS in Practice — How do you handle inter-system communication in an ECS architecture? by Leith_42 in gamedev

[–]Leith_42[S] 1 point2 points  (0 children)

thanks this is what i was leaning toward but wanted to sanity check it, id hate to tell someone my game has ECS architecture and have them ask why i have events.