Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Puzzle-adventure game architecture

Discussion in 'Scripting' started by mervesaglik, Aug 23, 2023.

  1. mervesaglik

    mervesaglik

    Joined:
    Dec 22, 2022
    Posts:
    5
    "Hello,

    I am making a 2D, top-down, puzzle-adventure game. I want to implement a single 'interaction' key (like 'space' or 'E') that players can use for various mechanics such as pushing objects, opening doors, and activating switches. So if the character is near the interactable object, and pressing the designated key; it should trigger relevant actions, as like as in Creaks or Eastward.

    But I am not sure where to start or what kind of systems or design patterns I need to use. I am open to any kind of advice, any keyword to search for, or a starting point.

    One specific challenge is the placement of interaction scripts. I think the interaction scripts should not be on the player. But I am not sure to attach the scripts to the objects beacause there are repeated actions (e.g. opening doors) that multiple objects share. And duplicating same scripts to objects individualy are not the ideal solution.

    Thank you in advance for any insights or guidance you can provide!
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    There are millions of "Press E to interact" tutorials on Youtube. Nobody is going to retype on in this little tiny box.

    Pick the first three (3) tutorials and do them until you can explain them to your dog.

    Plenty of tutorials here too. Interfaces and/or subclassing may be useful, but don't tangle yourself up in complexity. Get a SINGLE interaction going first, and understand all parts of it before moving forward.

    Tutorials and example code are great, but keep this in mind to maximize your success and minimize your frustration:

    How to do tutorials properly, two (2) simple steps to success:

    Step 1. Follow the tutorial and do every single step of the tutorial 100% precisely the way it is shown. Even the slightest deviation (even a single character!) generally ends in disaster. That's how software engineering works. Every step must be taken, every single letter must be spelled, capitalized, punctuated and spaced (or not spaced) properly, literally NOTHING can be omitted or skipped.

    Fortunately this is the easiest part to get right: Be a robot. Don't make any mistakes.
    BE PERFECT IN EVERYTHING YOU DO HERE!!


    If you get any errors, learn how to read the error code and fix your error. Google is your friend here. Do NOT continue until you fix your error. Your error will probably be somewhere near the parenthesis numbers (line and character position) in the file. It is almost CERTAINLY your typo causing the error, so look again and fix it.

    Step 2. Go back and work through every part of the tutorial again, and this time explain it to your doggie. See how I am doing that in my avatar picture? If you have no dog, explain it to your house plant. If you are unable to explain any part of it, STOP. DO NOT PROCEED. Now go learn how that part works. Read the documentation on the functions involved. Go back to the tutorial and try to figure out WHY they did that. This is the part that takes a LOT of time when you are new. It might take days or weeks to work through a single 5-minute tutorial. Stick with it. You will learn.

    Step 2 is the part everybody seems to miss. Without Step 2 you are simply a code-typing monkey and outside of the specific tutorial you did, you will be completely lost. If you want to learn, you MUST do Step 2.

    Of course, all this presupposes no errors in the tutorial. For certain tutorial makers (like Unity, Brackeys, Imphenzia, Sebastian Lague) this is usually the case. For some other less-well-known content creators, this is less true. Read the comments on the video: did anyone have issues like you did? If there's an error, you will NEVER be the first guy to find it.

    Beyond that, Step 3, 4, 5 and 6 become easy because you already understand!

    Finally, when you have errors, don't post here... just go fix your errors! Here's how:

    Remember: NOBODY here memorizes error codes. That's not a thing. The error code is absolutely the least useful part of the error. It serves no purpose at all. Forget the error code. Put it out of your mind.

    The complete error message contains everything you need to know to fix the error yourself.

    The important parts of the error message are:

    - the description of the error itself (google this; you are NEVER the first one!)
    - the file it occurred in (critical!)
    - the line number and character position (the two numbers in parentheses)
    - also possibly useful is the stack trace (all the lines of text in the lower console window)

    Always start with the FIRST error in the console window, as sometimes that error causes or compounds some or all of the subsequent errors. Often the error will be immediately prior to the indicated line, so make sure to check there as well.

    Look in the documentation. Every API you attempt to use is probably documented somewhere. Are you using it correctly? Are you spelling it correctly?

    All of that information is in the actual error message and you must pay attention to it. Learn how to identify it instantly so you don't have to stop your progress and fiddle around with the forum.


    Imphenzia: How Did I Learn To Make Games:

     
  3. mervesaglik

    mervesaglik

    Joined:
    Dec 22, 2022
    Posts:
    5
    Thank you for your response, and I appreciate your insights.

    I'd like to clarify my intention and emphasize a particular aspect of my query. While I understand the availability of "Press E to interact" tutorials on platforms like YouTube, my intention was not to request specific lines of code for individual interactions. Rather, I'm seeking guidance on a more fundamental level: how to create overarching systems that handle diverse interactions across various objects in a game. I apologize if my initial inquiry seemed to focus solely on code replication. My intent was to engage in a broader discussion about learning the principles behind building complex systems and architectures.

    I'd like to explain my situation a bit more to provide a better understanding of my goals and challenges. While I'm not entirely new to Unity and have completed a couple of games through tutorials, I'm now aiming to challenge myself by delving into more complex projects that involve creating systems rather than relying on individual scripts. While I'm familiar with various methods and practices, I'm not a software engineer, and I feel like I'm missing crucial aspects, such as proper architecture, to effectively structure my projects.

    My goal is to move beyond the beginner stage and acquire a deeper understanding of game development architecture. However, I've found that the learning resources available tend to be either very basic or highly specific, leaving a gap when it comes to intermediate-level concepts. While there are numerous tutorials on individual interactions like 'Press E to open doors' or 'Press E to push objects,' I'm struggling to find guidance on how to create holistic systems and architectures that can accommodate different interactions within a game.

    I believe this challenge extends beyond just where to attach scripts. I'm interested in understanding how to start designing the overall game system when there's no tutorial to follow. How do developers learn to build new games from scratch? Is it a matter of gradually adding features to existing projects, or is there a more structured approach?

    In regard to my original question, I'm seeking to create a versatile 'interaction system' that handles distinct interactions for various objects. For instance, if there are five main interaction types and each object may have different interactions, it doesn't seem ideal to attach the same script to all objects. However, I also want to avoid ending up with an extensive list of conditional statements. While tutorials about individual interactions are abundant, I'm struggling to find resources that guide me through creating comprehensive systems and making informed decisions about architecture.

    I apologize if my initial inquiry seemed to focus solely on code replication. My intent was to engage in a broader discussion about learning the principles behind building complex systems and architectures. I understand that this might not have a straightforward answer, but I believe in the power of learning from the community's shared experiences and insights. I'd like to highlight the importance of forums in addressing questions that extend beyond tutorials. I think forums play a crucial role in fostering discussion, sharing experiences, and gaining insights from those who have encountered similar challenges.

    I'm grateful for your advice, and I'm also looking forward to tapping into the collective knowledge of forums to enhance my knowledge on game development.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    This is great. All complex games are actually done one step at a time, never all at once.

    This doesn't change if someone here magically dumps the source code for an object interaction system that matches exactly what you want: you would still need to integrate it into your entire game, and if you didn't understand what it does, you're back in the same spot.

    So decompose your problem into parts and start on ANY part. If you find you can't do that part because another part isn't in place, go to that other part and do it, then move forward.
     
    mervesaglik likes this.
  5. mervesaglik

    mervesaglik

    Joined:
    Dec 22, 2022
    Posts:
    5
    Thank you sincerely for your advice. I've realized that I've been trying to solve everything at once, and this has caused me to struggle. Your suggestion to break down the problem into smaller parts and address them individually is indeed invaluable.
     
  6. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,104
    I think attaching components to the interactable objects would be a good, scalable, and commonly used approach. One extra component in each interactable object isn't anything to worry about in terms of performance. But having one huge switch statement with a 100 different cases for all the different interactables would be a nightmare to use.

    Focused classes with a clear single responsibility are almost always better than one huge class that does dozens of things - even if you need to do some repetition as a result. It's easy to read through a short script focused on just doing one thing, understand everything about it fully, and make changes to it without breaking anything. But if a script does dozens of things, you might accidentally break thing #13 and #27 when you were just trying to tweak thing #6 :confused: Especially if you use inheritance too heavily (making changes in base classes can be really dangerous, as it could cause things to break in any derived class).


    Workflow-wise, you might want to be mindful about how you structure your interactable prefabs and related components, so that it'll be easy to make modifications to systems shared by multiple game objects, without having to manually selects dozens of objects in different scenes and asset folders, and apply the same changes to all of them.

    For example, exposing different settings of components in the Inspector as serialized fields can be super useful for rapid iteration, but can in some cases also make it very difficult to change those values later on for all existing instances. So, once you've found good values for these settings, you might want to consider changing them into a const fields, or extracting them into a separate scriptable object asset, so that changes can made to them later on, and you'll be sure that those will automatically get reflected on all instances.

    Alternatively, careful use of shared base prefabs and prefab variants for different interactable objects could also work for this - but I've found this to be more a error prone approach (adding per instance overrides is too easy to do by accident, and it's not always necessarily clear that prefabs have base prefabs when you're working on them).


    One bit of annoyance I've noticed in some Unity projects I've worked on, is that all the different animations for a character tend to naturally get listed inside just one animator controller. If your game will contain a bunch of unique animations for different interactable objects, the state machine for the player character could get quite complicated and the variable list long.

    This has never gotten so bad so as to be come unmanageable in any of the projects I've worked on though, so maybe it's nothing to worry about... But I wonder if attaching the animation data to the interactable objects themselves instead might work better for an adventure game.
     
  7. dlorre

    dlorre

    Joined:
    Apr 12, 2020
    Posts:
    700
    If you want something to show up when your player comes near an object then you can use colliders.
     
  8. mervesaglik

    mervesaglik

    Joined:
    Dec 22, 2022
    Posts:
    5
    This was exactly what I needed to know! Thank you very much for your advice and detailed explanations. I'm also grateful for your input regarding character animations; I completely forgot about that aspect, and now I'll consider animation implementation more thoroughly. I'll also be cautious about other aspects you've mentioned, such as inheritance and prefabs.
    Your response has provided valuable insights, expanding my understanding and guiding me. Thank you sincerely for sharing your expertise; your insights have become a crucial reference point as I continue refining my game development process.
     
    SisusCo likes this.
  9. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    I can agree, to a point. But when it comes to a situation where it doesn't make sense to make another or several scripts, then your logic handled by that one class should be separated into functions/methods that require a simple parameter, and release a simple result.

    To explain further, it's basically what another class would do, handling a "certain responsibility", (value in)>(value out). But only if it makes sense in that class alone. If it's a functionality that can be used in multiple places(classes) then absolutely make it it's own class. As you'll find over-doing it will have 100 scripts, when you easily just could've had 20.

    But I always make separate functions/methods for things, in my case too simple of things, but it still makes sure things won't break down the line(unless massive refactor). i.e:
    Code (CSharp):
    1. public void SetRandomTroops()
    2. {
    3.     SetTroops(Random.Range(1, hexManager.maxTroopGain));
    4. }
    As whatever calls this to make just a random set, could easily just say it where it is in that class. But if further down the line you want to make changes, or add something like a print for debugging? You don't need to go every place where this simple action is called, you just modify it right here.

    But I'll agree that thinking out too far ahead, and trying to cover every thought that might be a possible, before you even start typing code, is very detrimental(as is refactoring 1000 lines of code). But just as SisusCo says it, as long as things are in chunks, and simple methods made in their own functions, you'd only ever have to change 1 thing. :)
     
    Last edited: Aug 27, 2023
    mervesaglik and SisusCo like this.
  10. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,104
    @wideeyenow_unity I agree. Extracting larger chunks of code into smaller helper methods can be really powerful for improving readability.

    And just the simple fact of having to come up with a name for the method, which is both accurate as well as comprehensive, focuses your mind to think about everything that the code does: what is its main purpose, and what are all of its side effects.

    This has actually lead me into making improvements to the code I was extracting several times, as I realize there are actually some sketchy side effects that really shouldn't be there, or there's some possible edge case scenario outside the happy path that isn't being handled properly and could result in a bug.

    It's probably my favorite refactoring technique.
     
    mervesaglik likes this.
  11. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    lol! I have that problem, a youtuber I once watched said "Don't worry about naming your methods, just name it 'purpleLizard' for now, don't waste time thinking of a perfect name, it'll come eventually, just keep progressing"..

    In response to sitting there wasting 10 minutes trying to think of a perfect name of what the method should do. But once I go back to it later, not remembering what it did, it's all too clear what to name it then, and problem solved.

    Also had the problem with short-handing the names of variables and such, for quicker typing just to get the idea out. But now it's total force of habit of naming it how ever long it takes, so later down the ladder of code there's no question to what var is what.
     
    mervesaglik and SisusCo like this.