Jump to content
  • Advertisement

Zakwayda

Member
  • Content Count

    12857
  • Joined

  • Last visited

  • Days Won

    7

Everything posted by Zakwayda

  1. Got it. For something like a simple casual game with relatively few textures it seems like the system might be overkill, but it makes sense for what you're describing. You know the specifics of what you have in mind of course, and I'm just speculating here. But, I can imagine cases even in the scenario you present where a texture might be unloaded and then reloaded unnecessarily - due to, for example, a texture being unused, but only for a few seconds (in which case the unloading/reloading might not be beneficial). Variations on your approach that come to mind include manually flagging textures as purgeable or non-purgeable (you could then flag e.g. large or high-resolution textures as purgeable), flagging textures as purgeable automatically based on how much memory they use, or making purging a manual step that you'd run at times when you know a lot of textures are going from used to unused or vice versa. I'm not saying that any of these is better than what you're doing now - I'm just throwing out ideas. As for your original question about how best to dynamically update resources while maintaining contiguous object data, my only other thought is to look at existing ECS implementations or references on that topic to see if such questions are addressed (I don't think you specifically mentioned ECS, but what you're doing seems to have that flavor). But maybe you've already done all that research In any case, maybe someone else will jump in with a suggestion on how to handle that particular issue. (And your current idea seems workable, provided of course that the various implementation pitfalls are avoided.)
  2. I haven't implemented this particular kind of system, and maybe there are standard solutions that someone else could point you toward. That said, I think I understand what you have in mind. The idea, as I understand it, is that object data (including texture handles) is stored contiguously by value (for good cache behavior), and the texture objects themselves are responsible for modifying the object's copy of the texture handle as appropriate if the texture handle changes. This certainly seems like it could work in principle. I know what you posted is just example code, but looking at it, I suspect the details of the implementation is where things might get interesting. The example code brings to mind various potential issues, such as the 'rule of 3/5', the possibility of dangling pointers/references, the technical and semantic implications of storing references as members, the implications of reallocating the object data storage or creating and destroying objects, and so on. Maybe you've already thought about all that, but I suspect that in actually implementing such a system fully, some of those issues might come into play. Also, just out of curiosity, is there any particular reason you want to unload textures whenever they become even temporarily unused? Maybe you have a good reason, but that seems a little atypical (in a games context at least), and it seems like the resource management might be simpler without that requirement.
  3. Apologies if the answer to this is obvious, but is the idea that the objects store texture reference objects by value, and the texture objects reference their associated texture reference objects by pointer or reference? (Maybe I'm misunderstanding, but it seems like that would have to be the case in order to get the contiguousness you seem to be after.)
  4. Zakwayda

    fill fixed byte with values

    Apologies if I'm missing the obvious, but can you just write and read the ints/floats/etc. in sequence? (One of the threads I linked to suggests serializing vectors in this way.)
  5. Zakwayda

    fill fixed byte with values

    I don't know the answer, as I'm not up to date with Unity and am not sure what features are available there. I did find a couple threads that might (or might not) be relevant (the information may be out of date though - the threads are a few years old): 1 2 Also, it sounds like you've already figured out how to serialize integers (which I assume doesn't mean only bytes). How are you doing that? It seems like the solution for other types (e.g. floats) could be related.
  6. This is all just low-hanging fruit based on a quick look at some of the code (some of the things pointed out here come up pretty commonly in code review requests): - In C++, the use of the preprocessor for constants is generally discouraged for various reasons (at or towards the top of that list would probably be that preprocessor macros are scope-unaware). C++ provides (arguably) better tools for this, such as 'const' and 'constexpr'. - Very minor, but I'd suggest expressing the 'degree to radians' constant in terms of pi (e.g. 'pi / 180.0') rather than expressing it as a literal. Since it's dependent on a constant you've already defined, there may be no particular reason to express it directly (which, among other things, runs the risk of getting it wrong). Technically you could probably also get pi from a trig function, although that's probably less important. (Although the chances of getting these constants wrong is obviously low, the general goal here is to minimize the number of hard-coded values - especially values that have invariant relationships to one another - and therefore reduce the potential for error.) - It's idiomatic to pass instances of non-trivial types like std::string by reference (constant reference if mutability isn't required, which I would think is usually the case), which may avoid some overhead. - How much to use 'const' is a matter of taste and opinion, but if you want (this is my preference), there are some things you can or might be able to make constant that aren't currently (e.g. immutable function arguments, member fields, locals, etc.). - In the 'Game' class, you're creating and deleting m_GameSceneManager manually, but it would probably be safer and more idiomatic to use e.g. std::unique_ptr for this. Among other things, this would remove the need for deleting it explicitly in the destructor and elsewhere. - '#pragma once' is widely supported, but technically non-standard. Just something to be aware of, depending on what your portability goals are. - Here: if (m_GameSceneManager == nullptr) m_GameSceneManager = ...; You have a control structure without braces. Opinions may differ on this, but it's often recommended to always include the braces (one reason being that if you decide to add additional statements later, you won't run the risk of introducing bugs by forgetting to add the braces, and also won't have to go to the trouble of adding them after the fact at all). - Just as a point of interest, 'return 0' in main() is the default behavior, so its inclusion is optional. I suppose some might recommend including it for clarity regardless (as you're doing). There are probably some other things, but I didn't look at all the code, and in any case that's probably enough for one post. Overall it looks very good
  7. Your original post was a bit hard to parse for me, so maybe I didn't understand what you meant. My only thought at the moment is that maybe it's the translations in the 'if' statements that need to be in a different space - local instead of global in this case. In other words, you could try using Transform.Translate() there (using the 'local space' option, implicitly or explicitly) instead of modifying the position directly. Again though, there are some things in your code that don't make immediate sense to me, so I'm guessing a bit here. [Edit: Upon reflection, it does seem like maybe you intended for those corrective translations to be local rather than global. That would seem to make a certain amount of sense given what you've written.]
  8. There are some aspects of the code I'm not quite clear on, but I'll make one observation. Here: transform.Translate(0, moveVertical * speed * Time.deltaTime, 0); You're using an overload of Transform.Translate() that assumes local space (as I suspected). Try using an overload that allows you to specify the space, and specify world space. (Or you could just modify the position directly, which you're doing elsewhere anyway.)
  9. This sounds like more of a programming question than an art question. In any case, what you describe sounds like the object is being moved along a local axis rather than along the global x axis, but we'd probably need to see some code to be sure. So, maybe you could post the bit of code that moves the object.
  10. Zakwayda

    Sprite batching problem

    Maybe the error is obvious in what you've posted, but it's more than I'm up to analyzing right now. Maybe someone else will jump in, but meanwhile I'll offer some more advice. Try calling glGetError(), if you're not already doing so, in order to catch any obvious errors. I also noticed you're negating the texture coordinate y values - you might double-check that that's what you want and that your texture parameters are set up appropriately for it. (Although unless your texture has some white in it, it seems more likely that texturing isn't working at all.) Did you set the sampler2D uniform? Anyway, this is a good exercise in debugging, I think. You said you successfully implemented rendering a single textured quad, so obviously there's some disconnect between that code and your current code - some step you've left out or something you've done differently. I'd suggest a careful analysis and comparison (perhaps just rendering a single sprite rather than many for the time being) to try to find where the disconnect is. I'll have to leave it there for now, but maybe something there will help get you pointed in the right direction.
  11. Zakwayda

    Sprite batching problem

    I see. That's a fair amount of code to look through, but irrespective of that, I think there's code missing that we'd have to see anyway. For example, I don't see anything having to do with program or texture creation or setup (presumably that happens elsewhere). In any case, there's probably little point in implementing something like sprite batching until you get the basics working. So, what I'd recommend is to write the simplest program you can that renders a single textured quad. There are plenty of tutorials that cover that material, so it should be fairly easy to find step-by-step instructions that will cover all the necessary steps. Once you have that working, you can move back to what you're doing currently, and if you find things aren't working, you can refer back to the simple example to see if you've missed anything, and/or post back here with your revised code.
  12. Zakwayda

    Sprite batching problem

    If you're on a deadline of some sort, a discussion forum might not be the best way to resolve your issue. Just to be safe, let me ask, is this for homework of some sort?
  13. Zakwayda

    Sprite batching problem

    It's likely that someone can help you solve the problem, but could you paste your code into a post so that it's easier to examine?
  14. Glad to hear you were able to get it working 🙂
  15. There's more there than I can easily sort out, but I'll point out one thing. XMVector3Transform() treats the input vector as a point (with w = 1), which probably isn't what you want for the direction vector. XMVector3TransformNormal() may do what you want there (in other words, use XMVector3Transform() for the origin and XMVector3TransformNormal() for the direction). I suspect that may be an issue, but it may not be the only issue. There are many places that picking or raycasting (or any similarly complex geometric algorithm) can go awry, and there could easily be other issues at play here. But, I'd at least give the XMVector3Transform()/XMVector3TransformNormal() suggestion a try. I can think of some other things that might make it easier to get this sorted out, but I'll refrain from offering them unless asked, as they're somewhat tangential and may not constitute the kind of feedback you're interested in.
  16. When you refer to only working at the origin, I'm not sure if you mean it only works when the ray originates at the origin, or when the model is positioned at the origin. In any case, in TestOBBIntersection(), you don't appear to be factoring in the model position, which seems like it could be related. Also, I don't know the details of the math library you're using, but keep in mind the distinction between positions and vectors when applying transforms.
  17. Zakwayda

    2.5d game vs 3d game

    I could be wrong, but I'm not sure 2.5d necessarily means 2-d with 3-d shaders (assuming by 3-d shaders you mean programmable pipelines in APIs like OpenGL and Direct3D). I Googled the term, and it seems to mean different things, with the meaning perhaps having changed over time. I remember it being used to describe 3-d games with 2-d sprites and various spatial limitations, like Doom and Marathon, but the usage seems to be different now. In any case, if this is your first project, I'd recommend starting with a simple 2-d game. There will be plenty of challenges entailed in that even without adding extra dimensions (or half-dimensions 🙂).
  18. Zakwayda

    making sound support in my engine

    You may already be aware of this, but OpenGL is deprecated on Apple platforms. Realistically I suspect it might continue to be supported for the foreseeable future, but the fact that it's deprecated might be worth keeping in mind. Regarding the audio issue, I'm basically working on the same problem right now, so I'll comment based on my experience so far. As zhangdoa mentioned, there are professional/commercial third-party solutions available if that's an option for you. There may also be free/open-source cross-platform solutions, but I don't have any suggestions in that category off the top of my head. There's OpenAL, as mentioned previously, but (also mentioned previously) it's deprecated on iOS. I'm not sure what its status on Android is, but it doesn't seem to be the recommended solution in that environment. You mentioned desktop, but didn't specify platforms. If you're targeting e.g. macOS, Windows, and Linux, obviously that adds some complexity to the problem. I'm currently just targeting iOS and Android, so I'll stick to commenting on that. I don't know if OpenSL is available on iOS (I Googled but didn't find a clear answer offhand). iOS offers various technologies though, such as AVAudioEngine, that are fairly straightforward to use. Things seem to be a little more complicated on Android. Options include: - SoundPool for short preloaded sounds. Its feature set is fairly small, which can make it a little difficult to work with, and there have been some reports of environment-specific bugs (although that seems common for Android in general). - MediaPlayer for longer sounds (e.g. music). There may be problems with seamless looping when using the 'looping' feature, which can be a showstopper for e.g. games. There may be some workarounds, but I don't know how reliable they are. - ExoPlayer is an open-source third-party alternative to MediaPlayer. Empirically it appears to support seamless looping, although that may be environment-dependent. - AudioTrack, which is lower-level and requires more effort to use. - On the native side, there's OpenSL, the newer AAudio, and the third-party library Oboe, which wraps both of these. These are all more complicated, I think, at least compared to e.g. SoundPool and MediaPlayer. The seamless looping issue seems to be a vexing problem. If it wasn't for that I'd just recommend SoundPool and MediaPlayer. You didn't mention what sort of audio features you need though, and if you're looking for e.g. complex 3-d audio with effects and so on, then those tools may not be sufficient. If you need more input, it seems like some relevant questions would be what desktop platforms you want to support, and what sorts of audio features you need.
  19. I do still wonder about the normalization, but I'd have to know more about the rest of the code to guess at what effect it might have, so I'll move on from that. Something else that might be worth mentioning is that the slab test can be vulnerable to error if one or more direction components is zero or has very small magnitude. So we'd be talking about division by zero or numbers with small magnitude in this statement: const XMFLOAT3 dirfrac{ 1.0f / rayDirection.m128_f32[0], 1.0f / rayDirection.m128_f32[1], 1.0f / rayDirection.m128_f32[2] }; You may be relying on language- or environment-specific behavior here, but I just thought I'd mention it in case you hadn't thought about it. What I'm more curious about though is this. Here: bool TestOBBIntersection(ModelClass* model, XMFLOAT3 origin, XMFLOAT3 dir, XMFLOAT3 lb, XMFLOAT3 rt, float & dist) For 'dir', what are you passing in? The inverted (and normalized) direction vector? The original unmodified direction vector? Or something else?
  20. Generally speaking you also have to make sure Euler-angle conventions match from one place to another. I'm not saying they don't in your case, just that it can be a source of errors. That was my guess, but e.g. 'lb' for left-bottom seemed a little confusing because it seems to suggest 2-d, whereas this is 3-d. Something like 'min' and 'max' (which you of course referred to above) would probably be more typical naming. What's the purpose of normalizing the inverse direction? And is it the normalized inverse (rather than the original direction vector) that you're transforming by the model transform later? Not saying what you're doing is wrong - it's just not immediately obvious to me what all is going on (and there's too much code for me to analyze it fully at the moment), so I'm just curious if you can elaborate on that part of things.
  21. Here are some things I noticed looking over your code: I don't know what all your variable names mean, and I haven't tried to fully analyze the functions for correctness, but are you sure your ray vs axis-aligned box test is implemented correctly? Have you tested it with a variety of input parameters? The math you're doing and the name 'dirfrac' seem to suggest that TestAABBIntersection() expects some 'prepared' data related to the direction vector, but in TestOBBIntersection() you just seem to be passing in the direction vector without any such preparation. You appear to be applying an Euler-angle rotation. If the Euler-angle conventions you're using in this code don't match the conventions used elsewhere, you could get erroneous results. I don't see you addressing the model's position anywhere in your code. Maybe something there will be helpful.
  22. This post is absolutely just my personal opinion and personal experience working on projects of my own, and may not be in keeping with standard or best practice or what's done in widely-used frameworks that use ECS or other types of entity-component system. This doesn't mean much (it's just anecdotal), but I've always handled everything within the entity-component system and haven't encountered any disadvantages with that approach (I haven't specifically implemented an ECS system though, so maybe there are considerations there that I'm not aware of). To me, trying to separate out certain things seems redundant and like it could lead to duplication of effort and introduce the additional burden of facilitating communication between the entity-component system and other systems. Also, for what it's worth, I think with Unity's old 'game object' system, pretty much everything went through that system. I don't remember there being separate consideration for certain types of things. (I'm not familiar with Unity's new ECS system though. Maybe things are different with it than with the 'game object' system.) Maybe you could start by asking, what possible benefits do you see in handling certain types of things (e.g. backgrounds and UI elements, to use your examples) outside the entity-component system? And/or, conversely, what possible disadvantages do you see in handling such things within the entity-component system? The answers to these questions might shed some light on the issue for you. To address some things specifically: Personally it doesn't seem odd for an entity-component system to draw such things - it seems natural. Also, it sounds like maybe you might be reading too much into the word 'entity'. In this context, I'd interpret it just to mean 'thing', which is pretty all-inclusive. This seems like a hint that there may not be much if anything to be gained by handling such things separately. Something like an in-game pop-up window certainly seems like an entity to me, and I've treated such things as entities in my own projects. Again though, I've typically treated everything as an entity, with no exceptions. Since discussion of topics related to entity-component systems can sometimes become contentious, let me reiterate that these are just my opinions and initial thoughts in response to what you posted. Maybe I'm completely off base and others will provide better feedback than I have here.
  23. I mentioned that as well, but maybe I should have highlighted it more. Anyway, 6000 to 80 ms is a big improvement - glad you were able to fix the issue, more or less at least
  24. This may be obvious, but one suggestion is to make sure your environment is set up for more or less optimal performance. In e.g. C/C++ this would entail getting the timings from a release rather than debug build. I don't know exactly what environment you're working in (Unity? standalone?), but it might be worth double-checking that it's set up optimally for performance (whatever that means for your particular environment). Another fairly obvious suggestion is to use a profiler. For the record, I realize you may have already considered all of the above - I'm just trying to be thorough. This is tangential, but your use of 'continue' seems a little atypical. It seems like the same thing could be accomplished with if-else, which I think would be easier to read. You didn't include the code for GetAdjacentTilePositions(), but in any case it looks like that aspect of things could be done in place, eliminating the function call and the (presumed) creation of a new 'List' object each iteration. It looks like you do this: _tiles[(int) adjacentTiles[i].x, (int) adjacentTiles[i].y].RoomIndex Twice. If tiles are stored by reference, you could grab the tile once and save the extra indexing. You could probably also avoid the repeated 'adjacentTiles' indexing, although as mentioned earlier you could instead do the 3x3 block iteration in place. There's one or two other places you do the same indexing more than once, so you could maybe change that as well. It looks like you might be assigning 'currentRoomIndex' to the same cells more than once (unless I'm misreading the logic), which would represent some unnecessary work. If I'm right about that, you should take out the one in the innermost loop. (Again though, I may not be tracking on the logic accurately.) It might be faster just to, in the outer loop, skip 'tilesToFloodFill' tiles that don't need to be processed, rather than removing them as you go, since removal might be expensive for various reasons. You might even be able to eliminate the separate first pass that way, although obviously the first pass isn't costing you much. There may be other obvious algorithmic improvements that could be made, but I'll stop there. In summary, it looks like there might be some low-hanging fruit you could go after, but ultimately you'll probably want to profile if you haven't already.
  25. Zakwayda

    sprite collision

    All other issues in this thread aside, in the interest of preventing possible confusion for future readers I'll say that although I haven't confirmed the code in question is correct, it's not immediately obvious to me that it isn't. If you think it's wrong it might be helpful to specify exactly how it's wrong. Irrespective of whether this particular implementation is correct, I'd argue there's nothing wrong with expressing the algorithm as it's expressed here. This is essentially a separating axis test, which is often expressed exactly in this way - that is, returning false if any axis is a separating axis, and returning true if there is no such axis.
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!