Why I'm Documenting My Game Code Now

Поділитися
Вставка
  • Опубліковано 27 жов 2024

КОМЕНТАРІ • 56

  • @PhilipNorton42
    @PhilipNorton42 5 днів тому +2

    If I was going into a refactoring progress of this sort of scale I would create some unit tests first. I don't know if they exist in unity, but that might be worth exploring. That way, you can be sure that once you've changed something that eveything will still work. I did this recently on an old legacy codename and refactored about 1,500k lines of code into about 30. The unit tests really helped me make sure that I hadn't broken anything.
    Also, we'll done for getting the thing useful or intelligible out of chatgpt, every single thing it had produced for me has been subtly wrong that I stopped accepting things at face value. After that, I just stopped. 😊

    • @ccl1195
      @ccl1195 5 днів тому +1

      Hahaha. I know this isn't the central subject of the video, but on your chatgpt comment, I have basically reached the same place. I would recommend trying Anthropic's Claude, it is more technically competent, has a more useful tone, and owns up to its mistakes. A good use for it too is asking it to give you 3 C# exercises for the afternoon, for example. But regarding gpt, what it frequently does for me is gives a solution that is mostly correct, and then it's always the penultimate step that is either so vague as to not be actionable, or more commonly, 100% wrong. I've honestly begun to feel that some "I hate humans" quality has emerged from it, and it's taking sadistic pleasure in giving you a solution so close to the truth, but would waste tons of time if acted on by a person who was out of their depth. I won't tell someone to never talk to an LLM, but, I have gotten waaaay more benefit per unit time from just reading authoritative books on C# and taking courses by people with a solid background in software or game design. Most people I speak to who are trying to do Unity are just leaning on the LLMs and refusing to pick up a book or sit through a course.

    • @JimMakesGames
      @JimMakesGames  4 дні тому +1

      ChatGPT definitely will make mistakes. I think the key is to use it for what it is good for and not for what it isn't. Like if I want a big block of code reformatted or a series of if statements quickly converted to a switch or something along those lines then it's great. I have it write some code for me, but I always read it and understand it (and often fix it) before letting it become part of my codebase. I think programmers are going to have to get used to this being part of the toolset.
      I haven't got any experience with unit testing, but I'm not sure how much they are used in game development, at least at this level. It's definitely something I should learn though.

  • @pacbilly
    @pacbilly 6 днів тому +4

    What if, instead of talking your way out of an encounter, you could talk your way into an advantage or disadvantage? So the encounter is inevitable, but maybe you get an extra card, lose a card, get a buff, lose some shield, whatever, depending on the outcome of the interaction.

    • @pacbilly
      @pacbilly 6 днів тому

      OR MAYBE... It isn't YOUR ship it affects, but the enemy ship. So if you make them extra mad, they may have +THIS or -THAT at the start of combat. Or maybe you affect the way they approach battle. Seem weak so they become over-confident and act recklessly. Convince them to be intimidated so they're more likely to surrender. Without knowing the exact mechanics, it's hard to give concrete examples, but this may be a good jumping off point.

    • @JimMakesGames
      @JimMakesGames  6 днів тому

      Ah yeah. Like the dialogue lets you choose a bonus or something. Good idea!

    • @JediMB
      @JediMB 4 дні тому

      I had the same thought while watching the video. Basically a flavorful way to nudge the difficulty level in one way or another.

  • @BoardGameMaker4108
    @BoardGameMaker4108 6 днів тому +1

    +1 to the intro, absolutely hilarious.
    One of my Unity projects was a strategy game. It had no separation of concerns and a lot of the game was deeply tied together, this even caused a couple of crashes because of some circular dependencies. This lead me to the same discoveries you had about making layers, decoupling and so on.
    What I've found more recently is that actually, too much separation can be a bad thing too. It might look ugly/disorganized to have it all in one file, but if you split it out across multiple files the project oftentimes grows in complexity -> now you have to connect the files together and keep the information in your head as you go from file to file. This is especially a problem when the code base grows really big - you forget how certain "concerns" connect together, and it can be difficult to see the forest for the trees.
    My rule of thumb, which others may disagree with, is if there's a dependency, the dependency should be unambiguously clear to the programmer from both sides. This might look more ugly at first (no event systems, no dynamic dispatch/virtual functions) but if someone else stumbles across the code, they will immediately see how the concepts connect together and they don't need to dance through interfaces/events to work it out. My opinion on event systems has completely turned around over the years - where before I was using them all the time to connect things together, now I just use them for one-to-many triggers in special cases. A code-base which is full of events or dynamic dispatch can be more difficult to follow later on. This is not a problem if you keep the number of layers small or document the connections (as you have done).
    That said, I think a card game is a perfect use-case for events. There's lots of card-games that have trigger sources and it's natural to represent them with events in code. You can dynamically subscribe/unsubscribe from events, which is very handy for cards that aren't there all the time.
    So the trade-off here is locality of behavior vs separation of concerns, and it's an interesting problem for sure.

    • @JimMakesGames
      @JimMakesGames  6 днів тому +1

      Yeah there is definitely a way to take it too far. It seems like in game development there are so many balancing acts and trade offs. Thanks for your thoughts! I will take it on board :)
      My first game had no structure to it like this and development became glacial towards the end. It was so difficult to do anything without it all unravelling.
      I am sure I still have a lot to learn about how to make the balance right. But I relish the challenge.

    • @PhyloGenesis
      @PhyloGenesis 6 днів тому +2

      ​@@JimMakesGamesAfter about 20 years I've also stopped using events and such that way except in special cases. I finally realized a dependency is a dependency because it is conceptually required, not because of the code, and you can't prevent that. You can represent it explicitly or add an abstraction layer, and I've found explicit is way, way better.
      Trying to enforce a tree of dependencies is basically impossible on large scale code. Forcing it just adds implicit dependencies that are way worse to deal with.
      I isolate as much as I can explicitly conceptually do so, and no more. I use layers, modules, interfaces, and more towards that end but recommend avoiding event systems or generic message passing unless you specifically need that.
      For example, microservices are just the same program but spread out where all your usual coding and debugging tools don't work, but there are some cases for scaling and related to downtime that make it worth pulling some things out into a separate service.

  • @leakyzinc
    @leakyzinc 8 днів тому +2

    Very interesting update, good to hear how about the behind-the-scenes engineering. Regarding the conversation system - could there be conversation-type or "diplomacy" cards that can be played at opportune moments to affect the course of gameplay? Would tie the alien interactions into the core premise of the gameplay.

    • @JimPlaysGames
      @JimPlaysGames 8 днів тому

      That's an interesting idea! I guess these would go into a different deck, but you could choose them instead of other cards. The question is what would the cards actually do? Something to ponder...

  • @a6gittiworld
    @a6gittiworld 6 днів тому

    Really like your video! Me myself and i are also a indie game dev using unity. Interesting stuff! U got yourself a sub mate

  • @hawkbirdtree3660
    @hawkbirdtree3660 5 днів тому +1

    Programming is like hitting yourself in the face with a hammer, and then wondering why your head hurts.

  • @TipsyAdonis
    @TipsyAdonis 8 днів тому +2

    I understood almost none of this... But the game looks like it's going to be super fun!
    A heavily Star Trek inspired card-based combat game and it's not called All Hands on Deck?
    You're a better man than me for avoiding such low hanging fruit.

    • @JimMakesGames
      @JimMakesGames  8 днів тому +1

      Thanks! I'll do my best to capture the Star Trek space battle vibe :D
      Oh I would have loved to have called it All Hands On Deck. But I checked and there's already a game called that on Steam. A pirate themed game and it's not even a card game. They wasted a pun!

  • @mohammadalaaelghamry8010
    @mohammadalaaelghamry8010 6 днів тому

    Great video, I got a lot of benefit out of it. Thank you.

  • @AgnisNeZvers
    @AgnisNeZvers 6 днів тому

    OOP is not bad, but this is the rabbit hole that OOP makes you go. I explored some languages and how people program to land on my current approach.
    Globals are not bad and have their use, but there's an alternative - shared context. You change context data and react to the state of the context data.
    That context data can be a just a bool, struct or a class. In some cases it's useful to have an event/callback when data has been changed. That's why I do state manipulation through "public" functions as allowed way to be manipulated and there can happen callbacks to react to.

    • @JimMakesGames
      @JimMakesGames  4 дні тому

      I'm not clear on the difference between shared context and global state. Is there a resource you can recommend that covers how to use this approach?

  • @straybasilisk2689
    @straybasilisk2689 5 днів тому +1

    You mention how different aspects of the UI need to interact with each other, and that can be hard to manage...
    But can you expand on why these different parts would need to talk to each other?
    It seems like most of the UI should be either:
    - Triggering a gameplay action
    - Visually reflecting some gameplay state
    - Perhaps managing some simple UI state (e.g. showing / hiding a UI panel)
    And so, ideally, not much cross-talk is required.

    • @JimMakesGames
      @JimMakesGames  4 дні тому

      That's a good point. A lot of it will be separated. But if I want to reuse some code that will be common to different parts of the UI then that would require some shared stuff right? I guess I can make a UI-Base namespace that has all those common elements which other UI namespaces would use.

    • @straybasilisk2689
      @straybasilisk2689 2 години тому

      @@JimMakesGames I see! So you're talking more about UI classes and components sharing functionality and code, rather than specific parts of the in-game UI needing to communicate amongst themselves?
      In that case, having a layer for the common components, and another for game-specific bits of the UI, seems like it would make sense. This might also be a case where "composition over inheritance" can play a role?

    • @JimMakesGames
      @JimMakesGames  Годину тому +1

      @@straybasilisk2689 Indeed! I think I will use a layer for the common UI elements that higher layers use. However the part I am working on now involves a circular dependency between the CardUI (the part that manages the visual aspect of the cards) and the Schematics (the diagrams on the side panels of the bridge that show the ships' systems).
      The issue I'm having is that when a card that has targeting options is played, it has a visual slideout element that displays a copy of the schematic of the enemy ship, allowing the player to select one of the enemy modules like a weapon or engines. Because of this, the card needs to know about the schematic, and the schematic needs to know about the card. I think I'll have to fix this with some events as I have before or some sort of generic interface. Still trying to work out the best way to do that. But that's an example of the kind of cross-talk and circularity that has been making my head spin recently XD
      I think going forward with the idea of keeping namespaces small in mind I will probably be able to avoid creating this kind of problem in the first place.
      I'm curious about the approach you have in your game development to this sort of problem. Is there a particular model / approach you're following? I've found it really hard to find good resources about how to structure code on the large scale in game development.

    • @straybasilisk2689
      @straybasilisk2689 27 хвилин тому

      @@JimMakesGames For the Cards and Schematics, I'm not totally sure why the Schematics would need to know about the Card in that case, vs just the Card knowing about the Schematic.
      Another approach is for the "schematic panel" (the thing on the side of the bridge) and the Card both to know about a "schematic diagram", since they both need to display these diagrams in their own different contexts. This way they both contain the lower level "schematic diagram" component, but don't know about each other.
      As for an overall approach - personally I've tried to stick to a couple of principles:
      - Separate the "game state" from the UI which displays / visualises that state, and triggers gameplay actions which modify the state. This is kind of an "MVC" (model-view-controller) approach
      - Use events judiciously. They can make things harder to follow, by obfuscating the way things interact, and making things implicit which should ideally be explicit. But they are great for the core game logic of this kind of turn-based gameplay. e.g. when a card is played it triggers some event (e.g. dealing damage), ship systems might respond to the event (e.g. by cancelling it or modifying the damage amount), and eventually it is applied to the target
      However I totally feel your pain about the lack of comprehensive guidance on how to structure large projects! I almost think going through this pain yourself is the only way to gain a true appreciation of the practical issues involved - and just reading a guide will never truly be able to convey the wisdom you need to be able to do this in practice.

  • @judgegroovyman
    @judgegroovyman 7 днів тому

    This was a great video with amazing edits and script that make it easy to understand.
    Few (if any) programmers actually have their methodology figured out so well they can build a large project from scratch and get it right the first time without refactoring.
    I love how you made dependency diagrams and that doxygen system is nice! I also love how you are leveraging chatgpt.
    I also love how great the game is looking. I thought it looked great before but now it looks amazing!

    • @JimMakesGames
      @JimMakesGames  6 днів тому

      Thanks! Glad you enjoyed it. Yeah I think it will always be an iterative process.
      I hope to polish the game quite a bit more before it gets to a release candidate

  • @sakurachan206
    @sakurachan206 6 днів тому

    I actually understood some of this! Mainly here for moral support (and business jellyfish obviously)

  • @ccl1195
    @ccl1195 5 днів тому +1

    I'm only 20 seconds in and that was brilliant. I was capable of reading and understanding every line at the speed of light because I too do this all day in C# for Unity. Looks exactly like my scripts 😅😭 This class extends Monobehaviour, and "Oh God why please not another interface why am I doing this fml."

    • @JimMakesGames
      @JimMakesGames  4 дні тому +1

      Thanks! Glad you enjoyed it!
      What's the issue with interfaces? I've found them really helpful.

    • @ccl1195
      @ccl1195 4 дні тому

      @@JimMakesGames Haha, yes good video. There's no real issue with interfaces, they're fine. I just feel this way with lots of things depending on the day. Sometimes it's interfaces, other times events and delegates, other times just inheritance in the first place. I think overall what I just mean is that sometimes you can find yourself layering layers of OOP architecture complexity on your system where it's not really necessary. Maybe some simplistic C# would do just fine, or maybe you discover Unity has a built-in system you weren't aware of that would do everything you needed already. Or, sometimes some multi-level, abstracted OOP structure actually is what's appropriate that day, and you're just not in the mood to do it! And, if your code isn't commented (ahem), you come back in 2 months and have to follow the chain of OOP breadcrumbs until you remember what the hell you had been trying to do! 🙃

    • @JimMakesGames
      @JimMakesGames  3 дні тому +1

      @@ccl1195 oh yeah I am really disillusioned with inheritance actually. I find a component based archietecture much more practical. For example before I would have had the Hand, DrawPile, DiscardPile and so on be children of Pile. But now they are composite objects with a Pile component and a Draw, Discard or Hand component. With inheritance I'd have to keep looking back through parent objects to find functionality, but with a component architecutre it's a lot more readable. I talked about that in more detail in a previous dev log: How I Untangled My Spaghetti Code: ua-cam.com/video/XTQIK_RkfK4/v-deo.html

    • @ccl1195
      @ccl1195 3 дні тому

      @@JimMakesGames Thank you! I will look forward to watching that. I don't know very much about composition but some people have recommended it to me.

  • @archiep9162
    @archiep9162 6 днів тому +1

    Should look into data driven game architecture done in lyra

    • @JimMakesGames
      @JimMakesGames  4 дні тому

      I looked it up but it seems to be an Unreal engine thing? I'm using Unity.

  • @bloodlotus_
    @bloodlotus_ 7 днів тому

    I just love the thumbnail.
    Lmfaoooo.
    Will watch this video tomorrow

  • @AdmiralJonB
    @AdmiralJonB 5 днів тому

    I think everything you've said here (about documenting and structuring your code) is something you can only ever learn by experience. It's just not something you can truly understand if you've never coded on a larger project, or never gone back to look on your own code a few years down the line.

    • @JimMakesGames
      @JimMakesGames  4 дні тому

      Yeah there is no teacher like experience, and failure.

  • @solmateusbraga
    @solmateusbraga 6 днів тому

    Commenting your code is absolutely necessary. I always had trouble though, as it'd take a good portion of my time since I'm too much of a perfectionist and would rather not write anything than those ugly one-liners everywhere. Now I write shitty ones and ask ClaudeDEV to organize it for me! 😅

    • @JimMakesGames
      @JimMakesGames  6 днів тому +1

      Oooh I hadn't heard of CladeDev. Just looked it up, and I may have to install that.
      I think I learned some wrong lessons from reading Clean Code. The idea that comments can be counter productive if they aren't maintained along with the code. But now I think that surely just means you need to be diligent about keeping the comments up to date if the code changes.
      Does ClaudeDev tell you if your comments are not describing the code properly?

  • @latertheidiot
    @latertheidiot 6 днів тому +1

    This is so relatable LOL

  • @AdmiralJonB
    @AdmiralJonB 5 днів тому

    My thoughts: don't overly focus on restructuring your code. It is very easy to get lost down this hole and then spending waaaaaaaay too much time doing things that don't do anything, or just lose your will to work on the project anymore.

    • @JimMakesGames
      @JimMakesGames  4 дні тому

      It's definitely a balancing act. I need to be sure not to do it too much. But I'm actually feeling way more energised about it now than I have in a while. So I think I'm on the right track, for now at least.

  • @ehutch79
    @ehutch79 5 днів тому

    Uhhhh... circular dependencies are always a problem. You probably want to start thinking about signals of some sort or pub/sub.

    • @JimMakesGames
      @JimMakesGames  4 дні тому

      When you say always do you mean literally in every single case? For instance if there's a namespace that just deals with some visual doodads and it consists of a few classes talking to each other to create some small visual element. Is it really necessary to ensure that there are no circular dependencies between those classes even if they're very simple?
      I'm afraid I'm not familiar with signals or pub/sub. Can you recommend a resource to learn more about them?

  • @nobody8717
    @nobody8717 6 днів тому +1

    not writing your code with emoji and using superlongnamestodescribeeverythinginstead.
    you gotta level up bro.

  • @bunkashaaa1
    @bunkashaaa1 День тому

    You are obviously ripping off another game`s game-design, but you are trying to figure it out on your own how to design the code structure, why not do both? or are you afraid? delving too much in technicalities might delude your critical eye towards your own creation. In the end it would be a more rewarding experience to try to make a original title and likely financially too.

    • @JimMakesGames
      @JimMakesGames  День тому

      Games are an iterative medium. Is Duke Nukem a rip-off of Doom? Is Hearhtstone a rip-off of Magic the Gathering? Sure I'm using much of the same mechanics established in Slay the Spire, but I'm iterating on them. It's not a straight up copy and I think it will play differently enough. There are a great many games that have emulated the gameplay mechanics of Slay the Spire, and many of those have had a decent amount of financial success. It's pretty much a subgenre of its own now.
      Regarding originality, I actually think it's more risky to make something very different from what has come before. How do you do market research based on something no-one has decided that they want yet? You have to do all the work of convincing people that this is something they want to play. If you make something iterative you can look at what has been successful before. How many sales is a game of this genre with this level of production value likely to make? You can actually look at data to help answer that.
      Original games are amazing when they are good. Consider Among Us and Vampire Survivors. These both created a new sub-genre, with numerous imitators of varying levels of success. But these games languished in obscurity for a while before being discovered. Because most people looked at it and dismissed them because their gameplay wasn't immediately recognisable as something worth paying attention to. It was only because of pure chance that those games got found by big streamers who showed people why this new gameplay was worth giving their time.
      So much of a game's success isn't even traditional marketing any more. It's the algorithm. Steam will show my game to FAR more people than I could ever reach on my own. So am I more likely to sell a game that is original and doesn't look like anything players will click "follow" or "wishlist" on? Or do I have a better shot making something iterative that looks like a new spin on something people already enjoy?
      Thanks for the question. It's given me an idea for a new video!

  • @pixelsymbols
    @pixelsymbols 5 днів тому +1

    Why not avoid circular imports and this weird spaghetti design where each component relies on other, when you can use composition, dependency injection and strategy patterns? Also ECS
    Make each component accept other components (by interface), and they wouldnt know about each other, but would know contract that they should accept/implement

    • @JimMakesGames
      @JimMakesGames  4 дні тому

      I do use composition in some places, such as the card piles, which consist of one class, the Pile, which has functionality common to all piles, and a class like Hand, Draw, Discard for the functionality that is particular to that type of pile.
      Dependency injection is something I have so far not got to grips with. I've read about it a bit and I've so far failed to understand the purpose and methodology behind it. Something I do need to learn I think.