• Advertisement


Popular Content

Showing content with the highest reputation since 12/24/17 in all areas

  1. 12 points
    I'm gonna call [citation needed] on that one. We don't really know what consciousness is yet. Not all of us believe in souls or the supernatural, incidentally. From my point of view, dismissing AI on the grounds that it can't possibly have something that we haven't demonstrated to even exist, never mind form a fundamental aspect of consciousness, seems... premature. This looks like an attempt to have a religion thread...
  2. 10 points
    Beginners don't understand how game development works. They think game X hasn't been made just because no one thought to do it; they never think that it wasn't made because it's either unfun or too difficult to program, or both. There are people who do the same with science, assuming that the only reason science doesn't accept something is because no one came up with the idea. It's a form of the Dunning-Krueger Effect, really. Beginners also tend to underestimate costs and assume that because their idea is obviously so perfect, people are going to swarm in and volunteer to do all the work for free just for a cut of "the profits", which they imagine must be millions and millions of dollars that just keep on coming. So they don't understand how markets work, either. More Dunning-Krueger here. I'm not innocent; I was one of those idiot beginners.
  3. 9 points
    I've always loved video games. As a child, I spent hours playing on my Atari 2600, on our home PC, or at a friend's house on his Nintendo and Super Nintendo. As time went on, I discovered QBasic and started to learn to make simple programs. It clicked - this is how the creators of the games were doing it! From there, I became very interested in learning about the creation process. I experimented, read articles in magazines, and as the World Wide Web took off I ventured online to learn more. Games got bigger and fancier, and some of them in special editions with documentaries about the creation, and I loved all of it. Well funded teams of hundreds of people were now working to create fantastic games with hours of gameplay and breathtaking visuals. I read articles and watched "making of" documentaries which described how developers would work long hours, forgoing days off, working late nights, and sometimes even sleeping in the office to meet deadlines. I was so impressed with the effort and dedication they put in. How much must you love a product to give up your nights and weekends, and spend time away from your family to finish it off? This was how great games were made, and I was in awe of the industry and the process. This was what I idolized. This was what I aspired to. I was wrong. The process I have described above is not necessary, and it is not cool. Developers do not need to sacrifice their free time, their sleep, and their health to create great games. The science is in. Numerous studies have shown that well-rested people are more productive and less prone to mistakes. The stress of this schedule and lack of sleep is profoundly damaging to people's health, causes burnout, and drives talented developers away from our industry. Just think about a cool feature that you loved in a AAA game. If the team went through a period of crunch, the developer who created that feature may have burned out and left the industry - they might not be creating awesome things for gamers anymore. We should not idolize a process that is harmful to developers. When we hear about crunch, the overwhelming reaction should be that this is not ok. Crunch is not cool, and developers still using this process should work towards a better way. Happier, healthier developers will produce better work, and in the long run, they will produce it more efficiently. Happier, healthier developers are more likely to stay in our industry rather than seeking greener pastures, resulting in more people with extensive experience who can then work on more advanced tasks and ideas, and push the industry forward. Thankfully, a growing number of developers have moved on or are moving on from this toxic culture of overtime and crunch, and a growing number of people are willing to speak up. Unfortunately, it's far from everyone, and there are many developers still exploiting workers. I'm putting my foot forward to say that I do not support a culture of overtime and crunch. We can do better, and we need to do better. I'm not the first person to share these sentiments, and I'm not an influential person, but I hope I won't be the last, and if I can convince even one more developer to stand up for better treatment of workers, then hopefully I've made some small difference. If you agree with me, next time you hear someone discussing crunch as if it's just a normal part of the process, let them know that there's a better way and that you don't support crunch and overtime. Let them know that crunch isn't cool.
  4. 9 points
    I think a big factor is that video games aren't physical things, but just data. Game development does - at least in theory(!!) - not require any money, supporters or physical resources beyond what most people (at least in rich countries) already own anyway. With infinite time and infinite knowledge, you could really create any sort of game completely on your own. You don't need to buy anything (all required software is available for free), you usually don't need to care about laws, and there is nobody you depend on who could just say "no" for whatever reason. Compare this to constructing a building: Even if you had all the knowledge that is required for all aspects of the construction, you still need to buy land to build on, you need to buy building material and machines, many tasks are probably physically impossible to do alone, and you need to folllow a ton of regulations to avoid being shut down. Without all these things, it is not so surprising that the efforts of game development are drastically underestimated by many people. Two more thoughts: - Since there is no initial risk involved at all, fantasizing about crazily huge unrealistic software development projects is just much less frightening. All you need to invest is some time, and if you fail, you haven't lost anything other than that time.. - The less you understand about software development, the less you can imagine how much work it is. Everbody has somewhat of an idea of what it takes to build a house, because you can see people doing it frequently somewhere in your town. But in a non-developer's everyday life, you usually don't see people working on video games, so how could you get a realistic impression of it?
  5. 8 points
    You're doing this: http://highexistence.com/spiritual-bypassing-how-spirituality-sabotaged-my-growth/ http://highexistence.com/10-spiritual-bypassing-things-people-total-bullshit/ Even if our brains are some kind of magical antenna that channels in a magical spirit consciousness from another plane of existence... what's stopping us from building our own mechanical antennae that channel magical spirit consciousness into our AI's?
  6. 6 points
    I'd definitely recommend starting with D3D11. IMHO it really is the best all around graphics API. All the concepts that you learn in pretty much any GPU API will translate to every other API, so learning the "wrong one" not a waste of time. GL would be my second choice, and then Vulkan/D3D12 in tied third place. My main points would be something like: |D3D9 |D3D11|D3D12 |Vulkan| GL | Easily draw a cube | Yes | No | No | No | Yes | Validation Layer | No | Yes | Yes | Yes | No* | Validated Drivers | MS | MS | MS | Open | No | Legacy APIs mixed in| Yes | No | No | No | Yes | Vendor extensions | No^ | No^ | No^ | Yes | Yes | CPU/GPU concurrency |Auto |Auto |Manual|Manual|Auto | Can crash the GPU | No | No | YES | YES | No* | HLSL | Yes | Yes | Yes | Yes# | No$ | GLSL | No$ | No$ | No$ | Yes | Yes | SPIR-V | No | No$ | No$ | Yes | No* | Windows | Yes | Yes | Yes | Yes | Yes | Linux | No$ | No | No | Yes | Yes | MacOS | No$ | No | No | No$ | Yes@| * = available with vendor extensions ^ = not officially, but vendors hacked them in anyway # = work in progress support $ = DIY/Open Source/Middleware can get you there... @ = always a version of the spec that's 5 years old... D3D10 useless now -- D3D11 lets you support D3D10-era hardware and do all the same things -- so we'll ignore it. The one good thing with ancient APIs (e.g. GL v1.1, D3D9) is that very simple apps are very simple. In comparison, modern APIs make you do a lot of legwork to even get started. When I was starting out, writing simple GL apps with glBegin, glVertex, etc, was great fun If you came across any readable tutorials or books for these old API versions, they could still be a fun learning exercise. Having a validation layer built into the API is really useful for catching your incorrect code. Of course you want to check all of your function calls for errors, but having the debugger halt execution and a several-sentence-long error message appear describing your coding mistake is invaluable. D3D does a great job here. D3D9 used to have a validation layer but MS has broken it on modern Windows (got a WinXP machine handy? ) GL2/3/4 tries to clean up their API every version and officially throws out all the old ways of doing things... but unofficially, all the old ways of doing things still hang around (except on Mac!), making it possible to end up with a horrible mixture of three different APIs. It can also make tutorials a bit suspect when you're not quite sure if you're learning core features from the version you want or not D3D9 also suffers from this, with it supporting both an ancient-style fixed-function drawing API and a modern shader-based drawing API... Vendor extensions are great -- they allow you to access the latest features of every GPU before those features become standard, but for a beginner they just add confusion. D3D made the choice of banning them. They're actually still there, but you have to download some extra vendor-specific SDKs to hack around the official D3D restrictions D3D12 and Vulkan code has to be perfect. If you've got any mistakes in it, you could straight up crash your GPU. This isn't too bad, as Windows will just turn it off and on again... but it can be a nightmare to debug these things. That doesn't make for a good learning environment. This would make them unusable, except that they've got the great validation layers to help guide you! D3D9/D3D11/GL present an abstraction where it looks like your code is running in serial with the GPU -- i.e. you say to draw something, then the GPU draws it immediately. In reality, the GPU is often buffering up several frames of commands and acting on them asynchronously (in order to achieve better throughput), however, D3D11/GL do a great job of hiding all the awful details that make this possible. This makes them much easier to use. In D3D12/Vulkan, it's your job to implement this yourself. To do that, you need to be competent at multi-threaded programming, because you're trying to schedule two independent processors and keep them both busy without either ever stalling/locking the other one. If you mess this up, you can either instantly halve your performance, or worse, introduce memory corruption bugs that only occur sporadically and seem impossible to fix D3D is a middle layer built by Microsoft -- there's your app, then the D3D runtime, then your D3D driver (Intel/NVidia/AMD's code). Microsoft validates that the runtime is correct and that the drivers are interacting with it properly. Finding out that your code runs differently on different GPU's is exceedingly rare. GL is the wild west -- your app talks directly to the GL driver (Intel/NVidia/AMD's code), and there's no authority to make sure that they're implementing GL correctly. Finding out that your code runs differently on different GPU's is common. Vulkan is much better -- your app still talks directly to the Vulkan driver (Intel/NVidia/AMD's code), but there's an open source suite of tests that make sure that they're implementing Vulkan correctly, and the common validation layer written by Khronos. For shading languages, GLSL and HLSL are both valid, but I just have a personal preference for HLSL. There's also a lot of open source projects designed at converting from HLSL->GLSL, but not as many for GLSL->HLSL. Also note, the above choices are valid for desktop PC's. For browsers you have to use WebGL. On Android you have to use GL|ES, and on iOS you can use GL|ES or Metal. On Mac you can use Metal too. On game consoles, there's almost always a custom API for each console. If you end up doing graphics programming as a job, you will learn a lot of different APIs!
  7. 6 points
    It sounds like you have several good reasons to accept the new job. It's up to you to consider what "committed to a 3-month long project" means, as in what type of commitment you made. You dont tell us. So, it's your call as to whether you're breaking some moral code of yours. But generally I'll say that if the company put all their eggs in one basket, so to speak, by having a new project that relies so heavily on just one person, then they are the ones who put the "company in that position" and not you. But again, I dont know what commitment you made to them. Maybe you just accepted the project, or maybe you gave your word that you would be there until completion. Those are different levels of commitment. Assuming your "commitment" was just to accept the project, then I'd say you should take the new job because of all the reasons you gave. You need to do what's best for you and your family, and let the company do what's best for them. If the tables were turned and the company thought it would be best to let you go, they might feel very badly about it, but at the end of the day I'd expect that they'd do what's best for the company. You can also offer to help them with the transition to a new engineer on the project. I'm not sure what the specific details of that would be, but maybe it's something to consider. Maybe you could even work for them on a freelance basis for a while to help them transition, and ask the new company if they'd allow you to work there part-time while you do that. I dont know, you have to think about it. But there might be some way to mitigate the transition for your old company if you really want to.
  8. 6 points
    Yep, here is my contribution to GameDev 2018 Missile Command. The source code is inside the zip :https://github.com/wybifu/missile_command/archive/master.zip github: https://github.com/wybifu/missile_command Windows users: Windows_version.exe Linux users: Linux_version or just compile it for any other OS. language: C library: SDL2 I feel that I have to explain myself as the code is awful: I was just writing as I was thinking when a new Idea popup I just hardcoded it and didn't care if it fits the rest of the code that can provide strange lines like: if (((Agent *)(((Agent *)(a->ptr0))->ptr1)) != NULL) ((Agent *)(((Agent *)(a->ptr0))->ptr1))->visible = BKP_F YEAH !! Absolutely horrible. a small video of gameplay : another shootscreen for pleasure:
  9. 6 points
    This is in no way limited to game development - every teenager with an electric guitar thinks they will be the next Jimi Hendrix too. It's easy to underestimate the difficulty of anything, before you have tried and failed a few times.
  10. 6 points
    If that's a problem, give up game development. It's largely thankless, so if you're not doing it for yourself, you shouldn't do it at all.
  11. 6 points
    I n some cases it's because they have what I call a "glorious vision" of what their game will be. They are imagining that they will re-create reality when, and that in their game things are going to be like reality. It's not until they actually try to make the game that they will realize that, just like everyone else's games, their game will necessarily function in the same simple ways as everyone else's games do. You can imagine the combat in your game being just like in real life right up to the point that you attempt to actually implement it. That is when reality sets in. This is one of the better reasons for creating a detailed design document, one that works out exactly and specifically how key aspects of the game will actually work. Because this is the process that shatters the "glorious vision" and brings you back to the reality of how simple it is actually going to be in the end compared to the wishful thinking of your "glorious vision".
  12. 5 points
    You could start by writing very simple games. When people ask about how and what I keep suggesting the following: Take a simple game: 4Wins, Tic Tac Toe or Battleship. Decide up on a programming language you want to learn/use in order to write the game - It can be a mix of languages later, but you should start with one first. Could be C, C++, C#, Pascal, Python, that's really up to you. Then you start by writing your game for the little command line window, text output only. You will learn about text input and output, how to read from the keyboard and how to print your things on screen, probably reading and writing from files and to files. Once your - let's say Tic Tac Toe - works, because you figured out the game logic before, you extend your existing game. You could add a little menu, where you could select from "New Game", "Options", "Highscore", "Exit". New Game starts a new round, inside Options you could modify the text colour, highscore lists all your previous games and sorts them by the moves it took to win the game or something similar, and Exit returns to your OS. Once that works, you could introduce different game modes, Player vs Player, Player vs Computer, Computer vs Computer, maybe as a sub menu in the New Game menu Once that works, you could jump from a console window to something more sophisticated, 2D sprites, textures, colourful backgrounds. Either by handcrafting all the glue required for that or by using some existing libraries or frameworks like SDL, sfml, freeglut, plain old windows GDI+ or the linux/mac counterparts. Once you got that working, why not add music? Background music, Sounds for placing Xs and Os, Win/Loss, Menu music. Once that works, make the game more interesting, Fiddle with modes like the player only has ten/three/two/one seconds to decide on a spot to put his X or O or the game will be lost. As the counter runs down, the music could become more dramatic Once that works, why not look at networking. Players of your great game could gather in a lobby, with little chat rooms where they can just hang and talk about great Tic Tac Toe games from the past, or plan tactics on how to defeat certain players or computers. You probable need a new menu for that where you can start a game or join a game of some sort. Eventually you might add some matchmaking system taking rank and other aspects into account for people to play together. Maybe even have some ladder system, game of hall or similar. Depending wether you want your game to be 2D or 3D you could level up the dimensions of your game now. and make it a 3D Game. The battlefield becomes 3D and more plastic, instead of sprites you might use real objects, models. While writing that, I got another idea. If you add networking, players could even provide their own little figurine (sprite/model) to be used while rendering the playground instead of the default ones (could be an optional setting somewhere) Of course you don't write all that within a week. But you can create little tasks out of those chunks. Tasks which can be easily achieved and keep you motivated as you see yourself progressing. Create a little todo.txt, or create a project on those sites like GitHub, BitBucket, Gitlab . They all come with a ticketsystem, where you can organise your todos if you prefer that over a simple textfile. When you are stuck somewhere you grab your little duck and talk to it/her/him, listen to what he/she/it tells you or debug your things which don't work. If you can't figure it out, you join us here and ask for help. I hope any of what I said above makes any sense to anyone.
  13. 5 points
    In my own opinion, this is NOT a bad thing. Being competitive and striving to be the best is a very good thing. Such competitive, over-ambitious, overzealous and talented youngsters only need to be mentored and well directed by an experienced guru in the field Imagine a very talented sports person (footballer, ...) but he or she is playing in a team without a manager. The consequence is that they be will all over the place, without proper overarching strategy, without good structure and will be learning from their mistakes the hard way I was like that... without a mentor, so I followed only my instincts and I paid dearly for that. A lot of wasted years. Probably not fully recovered yet. But it wasn't because of my over-ambitions and competitiveness, rather it was because I wasn't mentored or guided.
  14. 5 points
    Realistically speaking it's nearly impossible to find people who will be as motivated and driven as yourself towards your own project. It does happen, but there's a reason why entry level positions are typically filled with people who provide crappy service. Think of it like this; the person who pumps gas likely doesn't want to do that forever, they likely would rather own the gas station. Therefore you get someone who is 'just doing a job' and likely isn't providing the best service possible. People who do provide the best service possible likely get promoted, and then someone else fills their spot at the bottom ensuring that quality service is always hard to find. Ultimately a really driven person would likely want to rise through the ranks and then start their own business in the field they rose up through. It's the same with any field of work. Finding someone who will give you 100% as an employee/team member is truly a diamond in the rough. If you compare the above example to game development, you can't really expect everyone who might want to work with you to be as driven and dedicated as you are. When you do find someone as driven as you are it's likely that they will be using their position to gain experience to one day lead their own team. Some people are fine staying in the middle, and providing 100%, but it's tough to find those kinds of driven people. The passion for your project has to come from you. As leader of a project you then work to inspire those on your team to work with you and be as passionate about the project as you are, lead by example. Most teams lead by two people are married, siblings or long time friends. There's a reason for this, it's because they share the same passions and work well together. Finding one person to work in perfect harmony with you is rare, having that with an entire team is nearly unheard of. As for "wasting your life making a product that is never gonna be as good as the rest of the industry", your life is yours to do with as you please. If you enjoy the creation process, then to me, it's not a waste at all. A sense of purpose for ones life should come from many things, not just work, but social life, hobbies, recreation, etc, it's a balancing act. That way if any one thing doesn't work out it's not such a far fall from being content. Comparing your work or the potential of your work to 'the rest of the industry' to me is counter productive if its uninspiring to you. Remember that there can only be one 'the best', and only a few 'top of the game'. There are billions of people on the planet, the odds are stacked against you. It's also important to remember that what you see as an end user is a polished product, not a prototype. So you're seeing the best that could be brought forward. Each individual on a team has their own respective portfolios of work that also represents their current best, and it's something they update as they get better. What we as end users rarely see is the crappy stuff that doesn't make release, the 'unpolished' work if you will. Think of a painter who has their work on exhibition at a gallery. Everything we see at the gallery is what they believe to be their best work. Now think of their studio, the stuff left behind wasn't good enough to make the cut at the gallery. On top of that they will have scores of work they didn't like and never completed, not the mention the work from X years before they were finished mastering their skill that they no longer show anyone. Something I always remember is that it'll take you around 10,000 hours in each skill to get good enough to be professional. If you're trying to develop a game then whatever asset skill you have will take that same 10k hours. If you lead the team, then team leadership is another skill requiring 10k hours. Each skill you will use will take you 10k hours. Some skills will overlap and allow you to 'level up' at the same time, others wont. This is why most people work on one skill at a time, or join teams in order to only be in charge of one skill. They can then learn from each other and master other skills together. If you've ever watched interviews or behind the scenes of some of your favorite productions, be it videos games, music, movies, stand-up comedy, etc, one thing you'll notice is most artists will be unhappy with work they were once happy with. This is a representation of their skills improving as an artist. Clerks by Kevin Smith is one of my favorite movies, he talks smack about it all the time, because he's evolved as a writer/director. Another good example of the things I've mentioned are some of the costume concepts for the superhero movies over the years. Some of them are super bad, and needed to be entirely reworked, but ultimately we as end users got something that looked really good on screen. Without looking behind the scenes, the average user never knows how much work went into making something perfect. Stand-up comedy is the same, we don't often get to see comedians in their early years bombing at 50 person bars, we see their 1 hour specials a decade into their career. Many assume that what we see came out perfect on the first try, when in reality it's far from that easy. In the end it's important that you enjoy the creation process, and are truly dedicated to making your project/skill as perfect as possible within reason. If you don't enjoy it, then why bother? It doesn't matter what others think, art typically shines best when you make it for yourself and not for others.
  15. 4 points
    Time for an update. So what have I been working on in the last couple of weeks? Firstly the lighting and particle systems are activated. The particle system is pretty unintrusive with the most notable aspect being the chimney smoke rising from the different steampunk engines. Alongside this there is now a bit of splashing water and a few sparks flying around. Much more noticeable is the lighting system as demonstrated in the new screenshots. Here there is now a day / night cycle - I spent quite a long time making sure that the night was not too dark and I already have a game setting allowing this to be turned off (while this will lose a lot of the atmosphere just having day light slightly improves performance ... no other lights need to be active ... and maximises visibility). Introducing other lights was a bit more problematic than expected. Firstly, it took a while to get the light fall off fine-tuned correctly and secondly I upgraded the code quite a bit. Originally, the light manager would always choose the lights nearest to the player, meaning that a maximum of 7 lights (beyond the sunlight) could be active in any scene. Okay, but it did mean that more distant lights would suddenly flick on. The new logic activates lights nearest to each game object or map tile currently being drawn, allowing a much greater number of lights to be shown in any scene. In general the list of lights to activate are pre-calculated as each map section is loaded, with only lighting for moving objects being calculated on the fly. So far seems to be working nicely - if I overloaded a particular area with lights there could still be light pop-up, but with sensible level design this can be avoided. I did consider pre-baking the lighting but with the day/night cycle and the desire to alter light intensity and even colour on the fly this was going to be too complex and the performance of the current solution seems to be very good. The other task I've been working on is the introduction of two new map zones. The objective was to introduce something distinct from what had been done so far and to this end I have been working on a wilderness and an industrial zone. And the wilderness zone completely failed to work. It's a beginner zone so there wasn't any intention to overload it with complex gameplay, but even so it's just empty and uninteresting - back to the drawing board on that one. As for the industrial zone this one is going better. There are a number of new models being used and a few more to add with a couple of objectives in mind. First off the aim is to create a little bit the confusion of a steampunk factory - pipes, big machines, smoke and steam. Secondly, to hint at the down side of (steampunk) industrialisation with the texturing more grimy and even the addition of waste stacks (handily blocking off the player's progression requiring them to navigate their way round more carefully). An early draft is shown in the screenshot below - the ground texturing needs to be changed with green grass needing to be replaced by rock and sand and I will also be working on the lighting and fog - to draw in the view and create a darker scene even in the middle of the day. The scene may be a bit too busy at the moment, but I will see how I feel once these changes are made. Hope the update was interesting - as before any feedback most welcome.
  16. 4 points
    The basic building block of competency is strong familiarity with the language. You only get that with practice and experience, just like with any other skill. With skill and competency comes the ability to solve ever more complex problems. (And an RPG of any significant scale and scope is a quite complex problem.) A child doesn't start out running marathons; she starts out crawling first, then walking a few steps. Similarly, you won't be building that Dark Souls or Witcher 3-like RPG anytime soon, not until you've learned to run. Tutorials can only get you so far, are very frequently of poor quality, and are a very poor substitute for basic competency. A tutorial is tantamount to that child using a chair to hold herself up in a standing position. In order to build the RPG you envision, you MUST get past the "I need a tutorial to teach me this" stage. You have to be able to reason about and design and construct solutions on your own, and there just aren't any tutorials for that.
  17. 4 points
    I think your terminology is a bit off -- a descriptor heap is a huge area of memory where descriptors can be allocated. You can only have a single combined SRV/CBV/UAV-type descriptor heap bound to the device at a time, and changing this binding is expensive, so you're encouraged to only ever have a single one bound. You can create extra ones as staging areas where you can pre-create SRV's which can later be copied into your main/bound heap. Within a heap, you create descriptor-tables, which get bound to the root signature. The resource binding model in our engine has 8 "resource list" slots, which each contain an array of SRV's. In D3D11, each "resource list" is mapped to a contiguous range of t# registers in the shader. e.g. If a shader has ResList#0 with 4 textures and ResList#1 with 2 textures, the binding system is configured to copy ResList#0 into SRV slots [0,3] and ResList#1 into SRV slots [4,5]. In D3D12, each "resource list" is mapped to a root-descriptor-table parameter. Each shader generates a root-signature where param#0 is a table of CBV's, and param #1,2... are the res-list SRV tables. When submitting a draw-call, we determine if any res-list slots have changed since the previous draw-call (or if the previous draw-call used a different root signature). If so, a descriptor table is allocated for each new res-list within a ring-buffer, the SRV's for that root signature are copied into that new allocation from a non-shader-visible (staging) descriptor heap, and these new tables are set as root parameters. When creating a texture, it's SRV is pre-created in the non-shader-visible descriptor heap, while the shader-visble descriptor heap is just a ring-buffer of these transient tables.
  18. 4 points
    First thing's first, let's address what is perhaps the greatest flaw any open world game has, emptiness. I'm not saying that every open world game has this flaw, but if this flaw goes unchecked, it can cripple an otherwise brilliant game. Many games have overcome this and have risen to be legends such as The Witcher 3: The Wild Hunt, Assassin's Creed: Origins, and (my personal favorite) Legend of Zelda: Breath of the Wild. However, the one thing that no-one can deny about these games is that they have limits. I'm not saying that's a bad thing, rather the fact that those games have limits is probably what made them great because the developers could work extra hard to make everything they offered the finest they could. Be it through a colorful and motley cast of characters, utterly unique content, and compelling gameplay. But I'm not here to talk about your average ordinary Open World games, I'm talking about a special, new, and somewhat unrefined form of video game that offers an endless world to explore. An example: No Man's Sky. No Man's Sky was incredibly appealing because it offered a game world whose vastness was beyond compare. It offered an endless amount of places to go, but that was it's undoing. Video games aren't just about going places, they are about doing things. When I played No Man's Sky, what I got most interested in was finding upgrades for the ship and multi-tool. But it lost it's appeal to me because I realized that despite the fact that you had an endless amount of places to go, you had a severely limited amount of things to do. Sure you could interact with the different species and scan the local fauna, but it was all the same to me, the multi-tool was your primary method of interacting with the world, but you could only interact with the world in certain particular ways. Another example: Minecraft. Minecraft came close to defeating the flaw of an endless open world to the point where No Man's Sky tried to mimic it to save itself. You can build anything in Minecraft, and because of that, it can offer an endless amount of things to do. But it isn't the kind of thing that appeals to everyone, probably because not everyone has fun being creative just for the sake of creativity. The most creative thing I built was a flat-sided square building, first out of cobblestone, then out of solid stone, to serve as a home base for exploration, but what really appealed to me was crafting because crafting was doing something that could enhance future ways to do other things. I did have fun exploring, but once you've seen one cave, you've seen them all. So in a nutshell, Minecraft offered an endless world and an endless amount of things to do, but it did so in a way that they didn't match up well and doesn't appeal to everyone. Some of my favorite games were (and are) Super Mario Sunshine, Banjo Kazooie, Banjo Tooie, Ty The Tasmanian Tiger 1, 2, and 3, Okami, Rayman 3, Far Cry 4 and Primal, and Sonic Adventure 1 and 2. What they all have in common is that they're sandbox games. Orthodox sandbox games generally revolve around collecting things or fulfilling goals to collect things, but collecting those things rarely serves to enhance gameplay other than to make a way to collect more of those things. But despite this, I keep coming back to those games. After thinking long and hard, I decided that what keeps me coming back is discovery and testing the limits of my skills. Now to the hypothesis. The appeal to an open world game is endless discovery and endless things to do. But even with procedural generation, it is impossible to make a game like that without things getting a little stale and similar. Even if the game implements discoverable things that add new mechanics, eventually the players will run out of new things to discover and new things to do. But there might be a method to do it in a way which can allow the player to have a number of mechanics, tactics, and methods at their disposal so great that it would be impossible for one player to uncover them all. Instead of a discovery being just an achievement or new gameplay element, it should also offer the possibility to unlock more achievements and elements depending on how the player matches up or arranges the discovery with others. That way even if the number of discoveries is limited, the possibilities each discovery offers are beyond what anyone could do by themselves. And maybe a good way to go about it is to make the number of uses each discovery has limited so that the player has to constantly venture out in the world to get the most out of their favorite discoveries. But above all, the challenges offered to the player must not call for one specific mechanic, there might be a few that would make the challenge easier, but even if using any other mechanic would make conquering the achievement harder, it would encourage players to test the limits of their creativity and skills without making them feel restricted. How could something like this be implemented? I don't know. That's why I'm posting it here like a thesis so that maybe someone with the right capabilities would read this and make the game I and possibly many others have been waiting a very long time for. I had a few ideas myself, but that is a post for another time. A few games that I feel helped me realize these ideas were Megaman Battle Network and Castlevania: Aria of Sorrow (Because of the number of abilities and mechanics they offered) Magika (Because of the mixing up of abilities) and Super Mario Odessey (for the different captures changing up the mechanics). Like my ideas, want to add or expand on them, or have some of your own? Please, leave a reply!
  19. 4 points
    Like always, it comes down to what your ultimate goals are. But in general I'd say yes. Refactoring code is usually a good learning experience, especially when you're doing so with the goal of making it more cross-platform compatible or you're factoring out engine components to use later. You will end up with a set of tools that you can reuse, and you'll understand better what the different parts are and how they relate to each other.
  20. 4 points
    I'm not Bregma, but one thing that comes to mind is that it allows you use the enum value as "type code" at runtime. That has a number of use cases, but the one that comes to mind is cases where you convert between ID types and you want to validate at runtime that your ID points at what you think it's pointing at. For example, you might have an object hierarchy where Animal and Tree both inherit from Actor; you have ActorID, AnimalID, and TreeID. AnimalID and TreeID can be converted to ActorID and vice versa. Now you have a potential case where an ActorID that actually points at an Animal could be converted to a TreeID, which you probably want to validate at runtime! You don't strictly NEED to use an enum for the type code, but it simplifies the problem of having unique IDs per type. Especially in an environment where RTTI is disabled. This article illustrates an example of how to set up a handle type that uses "indices with type code" handles: http://gamesfromwithin.com/managing-data-relationships Another thought that comes to mind is that you might want to use the "type code" itself as an index or key. For example, suppose you have some content that specifies a table mapping object type onto some parameter that's uniform across all objects of those types, because the designers don't want to have to set that parameter on every single object definition of that type in content. If you have a type code that's mappable to a simple array index, you can have a flat array in the content and just index into that to get the value you're looking for. Another option that hasn't been mentioned is specializing your handle type on the actual type it's supposed to refer to, eg. struct Animal { // ... }; using AnimalID = IDType<Animal, unsigned int>; This obviates the need for an extraneous type that never gets used just for the tag.
  21. 4 points
    Once a project has been selected (depending on who holds the purse strings), management will usually select some sort of broad resource plan for the whole project, deciding how many programmers/designers/artists/etc will work on the project, and at which stages in the project lifetime. The project is often divided up into milestones, which act as checkpoints to verify that the project is being delivered as expected and on time. Less formal projects might have a handful of milestones, whereas big publisher-funded projects often have a formal milestone delivery process where the build is explicitly handed over every so often (monthly, or six-weekly, or quarterly, etc) to be assessed. Each milestone typically has a bunch of intended 'deliverables' - they are ideally working features, but can also be assets that may or may not yet be integrated into a feature. And there can be different expectations for the state of a deliverable (e.g. "prototype", "working", "finished", etc). The actual state of those deliverables, relative to what was promised, dictates whether the milestone is 'passed' or 'failed'. In the latter case the team is usually expected to fix up those failed deliverables before the next milestone is handed over. If you keep failing milestones, the publisher may terminate the project, as they lose confidence in your ability to complete it. Scheduling within a milestone is usually done via some sort of agile planning process. With a given set of deliverables in mind, the heads of each department and the project management team ("producers") come up with a list of prioritised tasks and decide who to allocate them to. Those people receive the task descriptions and implement them. The day-to-day work of each person depends entirely on their job and their task. There may be a 'daily standup' meeting or Scrum where people briefly discuss what they're working on and ask for help if they're stuck. Beyond that, they communicate via conversation/meetings/email/Slack to resolve ambiguities and discuss details. The rest of the time, they're probably at their computer, executing their current task by creating code, art, whatever.
  22. 4 points
    Hi everyone! It has been more than two months since I released I Am Overburdened and since I wrote a devlog entry. Please accept my apology for this, I was super busy with the release and support of the game. But now I’m back with an in-depth analysis how the overall production and final numbers turned out . Summary I want to do a fully detailed breakdown of the development and business results, but I don’t want break it up into a typical postmortem format (good, bad, ugly). I’ve drawn my conclusions, I know what I have to improve for my upcoming projects, but I don’t want to dissect the I Am Overburdened story this way, I want emphasize how much work goes into a game project and focus more on how a journey like this actually looks and feels like. If you really want know my takeaways, here it goes in a super short format: I consider the game a success from a development perspective (good), but I failed from a marketing and sales standpoint (bad and ugly). Now I go into the details, but will focus more on the objective “what happened, how it went, what it took” parts. Development The game started out as a simple idea with a simple goal in mind. I partially abandoned my previous project, because it ballooned into a huge ball of feature creep, so I wanted to finish a more humble concept in a much shorter time period. The original plan was to create a fun game in 4 months. I really liked the more casual and puzzle-y take on the roguelike genre like the classic Tower of the sorcerer game, or the more recent Desktop dungeons and the Enchanted cave games so I set out to create my own take. I designed the whole game around one core idea: strip out every “unnecessary” RPG element/trope and keep only the items/loot, but try to make it just as deep as many other roguelikes regardless of its simplicity. From this approach the “differentiating factor” was born, a foolishly big inventory, which helped me to define and present what I Am Overburdened really is. A silly roguelike full of crazy artifacts and a “hero” who has 20 inventory slots. Most of the prototyping and alpha phases of the development (first two months) went smoothly, then I had to shift gears heavily… Reality check After 3 months of development, when all of the core systems were in place and when I deemed big parts of the content non-placeholder, the time came to show the game to others. I realized something at that point, forcing me to make a huge decision about the project. The game was not fun . The idea was solid, the presentation was kind-of ok, but overall it was simply mediocre and a month of polishing and extra content in no way could change that! Back than I was super stressed out due to this and I thought about this as my hardest decision as a game maker, but looking back I think I made the right choice (now I feel like I actually only had this one). I decided to postpone release, explore the idea further even if it doubles!!! the originally planned development time (and it happened ) and most importantly I decided to not make or release a “shovelware”, because the world really isn’t interested in another one and I’m not interested in making/publishing one… Final scope So after 4 months of development, feeling a bit glum, but also feeling reinvigorated to really make the most out of I Am Overburdened I extended the scope of the design & content and I also planned to polish the hell out of the game . This took another 4 months and almost a dozen private beta showings, but it resulted in a game I’m so proud of, that I always speak of it as a worthy addition to the roguelike genre and as a game that proudly stands on its own! Some numbers about the end result: It takes “only” around 30 to 40 minutes to complete the game on normal mode in one sitting, but due to its nature (somewhat puzzle-y, randomized dungeons & monster/loot placements + lots of items, unlocks and multiple game modes), the full content cannot be experienced with one play-through. I suspect it takes around 6 to 12 full runs (depending on skill and luck) to see most of what the game has to offer so it lends quite a few hours of fun . There are 10 different dungeon sets and they are built from multiple dozens of hand authored templates, so that no level looks even similar to the other ones in one session. They are populated by 18 different monsters each having their own skill and archetype (not just the same enemy re-skinned multiple times). And the pinnacle, the artifacts. The game has more than 120 unique items, all of them having a unique sprite and almost all of them having unique bonuses, skills (not just +attributes, but reactive and passive spells) and sound effects. This makes each try feel really different and item pickup/buy choices feel important and determinative. The game was also localized to Hungarian before release, because that is my native language so I could do a good job with the translation relatively fast and this also made sure, that the game is prepared to be easily localized to multiple languages if demand turns out to be high. Production numbers How much code I had to write and content I had to produce all in all to make this game? It is hard to describe the volume/magnitude with exact numbers, because the following charts may mean a totally different thing for a different game or in case of using different underlaying technologies, but a summary of all the asset files and the code lines can still give a vague idea of the work involved. Writing and localization may not sound like a big deal, but the game had close to 5000 words to translate ! I know it may be less than the tenth of the dialogue of a big adventure or RPG game, but it is still way larger than the text in any of my projects before… I’ll go into the detailed time requirements of the full project too after I painted the whole picture, because no game is complete without appropriate marketing work, a super stressful release period and post-release support with updates and community management work . Marketing If you try to do game development (or anything for that matter) as a business, you try to be smart about it, look up what needs to be done, how it has to be approached etc… I did my homework too and having published a game on Steam before I knew I had to invest a lot into marketing to succeed, otherwise simply no one will know about my game. As I said this is the “bad” part and I’ll be honest. I think I could have done a much better job, not just based on the results, but based on the hours and effort I put in, but let’s take it apart just like the development phase. Development blog/vlog I started writing entries about the progress of the game really early on. I hoped to gather a small following who are interested in the game. I read that the effectiveness of these blogs are minimal, so I tried to maximize the results by syncing the posts to at least a dozen online communities. I also decided to produce a video version because it is preferred over text these days + I could show game-play footage too every now and then. I really enjoyed writing my thoughts down and liked making the videos so I will continue to do so for future projects, but they never really reached many people despite my efforts to share them here and there… Social media I’ve tried to be active on Twitter during development, posting GIFs, screen-shots and progress reports multiple times a week. Later on I joined other big sites like Facebook and Reddit too to promote the game. In hindsight I should have been more active and should have joined Reddit way earlier. Reddit has a lot of rules and takes a lot more effort than Twitter or Facebook, but even with my small post count it drove 10 times more traffic to my store page, than any other social media site. Since the game features some comedy/satire and I produced a hell of a lot of GIFs, I tried less conventional routes too like 9gag, imgur, GIPHY and tumblr, but nothing really caught on. Wishlist campaign I prepared a bunch of pictures up-front featuring some items and their humorous texts from the game. I posted one of these images every day starting from when the game could be wishlisted on Steam. I got a lot of love and a lot of hate too , but overall the effectiveness was questionable. It only achieved a few hundred wishlists up until the release day. Youtube & Twitch For my previous Steam game I sent out keys on release day to a 100 or so Youtubers who played any kind-of co-op game before, resulting in nearly 0 coverage. This time I gathered the contact info of a lot of Youtubers and Twitch streamers upfront. Many were hand collected + I got help from scripts, developer friends and big marketing lists ! I categorized them based on the games they play and tried talking to a few of those who played roguelikes way before release to peak their interest. Finally I tried to make a funny press release mail, hoping that they will continue reading after the first glance. I sent out 300 keys the day before release and continued the following weeks, sending out 900 keys total. And the results?! Mixed, could be worse, but it could be much better too. 130 keys were activated and around 40 channels covered the game, many already on release day and I’m really thankful for these people as their work helped me to reach more players. Why is it mixed then? First, the videos did generate external traffic, but not a huge one. Second, I failed to capture the interest of big names. I also feel like I could have reached marginally better results by communicating lot a more and a lot earlier. Keymailer I payed for some extra features and for a small promotion on this service for the release month. It did result in a tiny extra Youtube coverage, but based on both the results and the service itself all in all it wasn’t money well spent for me (even if it wasn’t a big cost). Press This was a really successful marketing endeavor considering the efforts and the resulting coverage. I sent out 121 Steam keys with press release mails starting from the day before release. Both Rock Paper Shotgun and PC Gamer wrote a short review about it in their weekly unknown Steam gems series and the game got a lovely review from Indiegames.com. Also a lot of smaller sites covered it many praising it for being a well executed “chill” tongue-in-cheek roguelike . The traffic generated by these sites was moderate, but visible + I could read some comforting write-ups about the quality of the game. Ads I tried Facebook ads during and a bit after the release week + in the middle of the winter sale. Since their efficiency can not be tracked too well I can only give a big guesstimate based on the analytics, sales reports and the comparison of the ad performances. I think they payed back their price in additional sales, but did not have much more extra effect. I believe they could work in a bigger scale too with more preparation and with testing out various formats, but I only payed a few bucks and tried two variants, so I wouldn’t say I have a good understanding of the topic yet. Some lifetime traffic results: So much effort and so many people reached! Why is it “bad”, were the results such a mixed bag? Well, when it comes to development and design I’m really organized, but when it comes to marketing and pr I’m not at all. As I stated I never were really “active” on social media and I have a lot to learn about communication. Also the whole thing was not well prepared and the execution especially right at the release was a mess. The release itself was a mess . I think this greatly effected the efficiency! Just to be more specific I neglected and did not respond in time to a lot of mails and inquiries and the marketing tasks planned for the launch and for the week after took more than twice as much time to be completed as it should have. I think the things I did do were well thought out and creative, but my next releases and accompanying campaigns should be much more organized and better executed. Time & effort I don’t think of myself as a super-fast super-productive human being. I know I’m a pretty confident and reliable programmer and also somewhat as a designer, but I’m a slowpoke when it comes art, audio and marketing/pr. For following my progress and for aiding estimations I always track my time down to the hour level. This also gives me confidence in my ability to deliver and allows me to post charts about the time it took to finish my projects . Important thing to note before looking at the numbers: they are not 100% accurate and missing a portion of the work which were hard to track. To clarify, I collected the hours when I used my primary tools on my main PC (e.g.: Visual Studio, GIMP), but it was close to impossible to track all the tasks, like talking about the game on forums & social media, writing and replying-to my emails, browsing for solutions to specific problems and for collecting press contact information, you get the idea… All in all these charts still show a close enough summary. 288 days passed between writing down the first line in the design doc and releasing the game on Steam. I “logged” in 190 full-time days. Of course more days were spent working on the game, but these were the ones when I spent a whole day working and could track significant portion of it + note that in the first 4 months of the project I spent only 4 days each week working on I Am Overburdened (a day weekly were spent on other projects). Release So how the release went? It was bad, not just bad, “ugly”. After I started my wishlist campaign, close to the originally planned date (2017. Oct. 23.) I had to postpone the release by a week due still having bugs in the build and not having time to fix them (went to a long ago planned and payed for vacation). I know this is amateurish, but the build was simply not “gold” two weeks prior to release . Even with the extra week I had to rush some fixes and of course there were technical issues on launch day. Fortunately I could fix every major problem in the first day after going live and there were no angry letters from the initial buyers, but having to fight fires (even though being a common thing in the software/game industry) was super tiring while I had to complete my marketing campaign and interact with the community at the same time. The game finally went live on Steam and itch.io on 2017. Nov. 2 ! I did not crunch at all during development, but I don’t remember sleeping too much during the week before and after launching the game. Big lesson for sure . I saw some pictures about the game making it to the new and trending list on Steam, but it most probably spent only a few hours there. I never saw it even though I checked Steam almost every hour. I did saw it on the front-page though, next to the new and trending section in the under 5$ list . It spent a day or two there if I remember correctly. On the other hand, itch.io featured it on their front page and it’s been there for around a whole week ! With all the coverage and good reviews did it at least sale well, did it make back it’s development costs, if not in the first weeks at least in the last two months? Nope and it is not close to it yet… Sales In the last two months a bit more than 650 copies of I Am Overburdened were sold. Just to give an overview, 200 copies in the first week and reached 400 by the end of November, the remaining during the winter sale. This is not a devastating result, it is actually way better than my first Steam game, but I would be happier and optimistic about my future as game developer with reaching around 3 to 4 times the copies by now. To continue as a business for another year in a stable manner around 7 to 8 times the copies total (with price discounts in mind) during 2018 would have to be reached. I’m not sure if the game will ever reach those numbers though . If you do the math, that is still not “big money”, but it could still work for me because I live in eastern Europe (low living costs) + I’m not a big spender. Of course this is an outcome to be prepared for and to be expected when someone starts a high-risk business, so I’m not at all “shocked” by the results. I knew this (or even a worse one) had a high chance. No matter how much effort one puts into avoiding failure, most of the game projects don’t reach monetary success. I’m just feeling a bit down, because I enjoyed every minute of making this game, a.k.a. “dream job” , maybe except for the release , but most probably I won’t be able to continue my journey to make another “bigger” commercial game. I may try to build tiny ones, but certainly will not jump into a 6+ months long project again. Closing words It is a bit early to fully dismiss I Am Overburdened and my results. It turned out to be an awesome game. I love it and I’m super proud of it. I’m still looking for possibilities to make money with it (e.g.: ports) + over a longer time period with taking part in several discount events the income generated by it may cover at least a bigger portion of my investment. No one buys games for full price on PC these days, even AAA games are discounted by 50% a few months after release , so who knows… If you have taken a liking to play the game based on the pictures/story you can buy it (or wishlist it ) at Steam or at itch.io for 4.99$ (may vary based on region). As an extra for getting all the way here in the post, I recorded a “Gource” video of the I Am Overburdened repository right before Christmas. I usually check all the files into version control, even marketing materials, so you can watch all the output of almost a year of work condensed into 3 minutes. Enjoy ! Thank you very much for following my journey and thanks for reading. Take care!
  23. 4 points
    Isn't that field of science called psychology? Or science itself is just applied philosophy at the end of the day... BTW, they already have metrics for measuring whether an object is conscious or not, which have been demonstrated to be able to tell the difference between normal awake brains, sleeping brains, dreaming brains, anesthetized brains, vegetative comatose brains, minimally conscious brains, and "locked in syndrome" brains (which would otherwise appear similar to other comatose brains, but on this metric, shows high levels of consciousness). Science does peer into those mechanisms. People's free will is surprisingly easy to influence... Again, that's psychology (or hypnotism too, if you like). The exact mechanisms of exactly how this process works though -- or any specific human action, when trying to explain the entire chain of consequence from genesis of thought to action -- are too complex for any human to ever understand (a thousand trillion synaptic connections, multiplied by all the other variables is an inconceivable amount of data, even when just considering a single moment in time...). There's also the camp who believes that the actual physical mechanisms behind thought is rooted in quantum behavior, which is probabilistic, which makes the whole thing "just physics" without having to say that it's deterministic (keeping the "free" part of "free will" free, and leaving the door open for a God who rolls dice).
  24. 4 points
  25. 4 points
    None of this makes any sense.
  26. 4 points
    I don't believe @Alberth could have explain that better, the problem is that it isn't a very simple thing to do; So I added images to show some details. Sorry I am at work and don't have the time to make it at a great quality. So I will show you what Alberth said: First you need what is known as tiling textures, these are the rectangles: The important part is that you can make a larger image from them because they tile. Next you need a mask, this is the form of your country: It's common for masks to be gray scale or black and white, this saves a lot of data. The way a mask works is that you will tell your fragment shader to render the grass texture where the white is, because white = (1,1,1) and any number times 1 = it self. Example 0.5 * 1 = 0.5. You can just multiply the color of the texture with the white. Black = (0,0,0) and Any number times black = 0. Your end result should look like this: Next you tell your fragment shader just to skip all pixels that is Black (0,0,0) and it should render only the grass part. After rendering the grass part you do the same using your rock texture. Then you render first the rock texture a bit lower and to the left of the image, then you render the grass where you want it. Click image for full size. For the edge you just use an edge detect or you can also store it in the mask. Using tiling textures and a mask you can create all the content you need.
  27. 4 points
    As others mentioned, it isn't just games, and it isn't just beginners. It can be that you'll lose an unrealistic amount of weight as your new years resolution, or you'll finish an assignment by some deadline, or you're Apple releasing a watch a week after the official release date, or Duke Nukem Forever released about 15 years late. The problem has been around for all of humanity. A bit of web searching shows even in the ancient world, the ancient Roman, Greek, and Babylonian cultures made assorted promises and resolutions each new year, including documented promises to return objects, pay debts, and follow better care. People have been setting (and failing to meet) overambitious unrealistic goals for all of recorded history. It doesn't matter even if we have experience. We KNOW we aren't going to drop that much weight, but we think that THIS TIME we might be able to. We KNOW that every year we wait to file taxes but we commit to THIS TIME doing it earlier. We KNOW that similar assignments have required more time, but we think that THIS TIME we can make it by an earlier deadline. We KNOW a game like the one we see has a 15-minute long scrolling list of names in the credits, but we think we can do it. As typical, Wikipedia's got a writeup listing a bunch of proposed reasons with references. It looks like something psychologists have been writing about since the 1960s. Given the history of new year's promises, I can imagine Hammurabi reading the stone tablet newspaper at the new year describing how he can help keep his goals of losing weight and keeping it off.
  28. 4 points
    We are the music-makers, And we are the dreamers of dreams, Wandering by lone sea-breakers And sitting by desolate streams; World losers and world forsakers, On whom the pale moon gleams: Yet we are the movers and shakers Of the world for ever, it seems. With wonderful deathless ditties We build up the world’s great cities. And out of a fabulous story We fashion an empire’s glory: One man with a dream, at pleasure, Shall go forth and conquer a crown; And three with a new song’s measure Can trample an empire down. We, in the ages lying In the buried past of the earth, Built Nineveh with our sighing, And Babel itself with our mirth; And o’erthrew them with prophesying To the old of the new world’s worth; For each age is a dream that is dying, Or one that is coming to birth. From "Ode" by Arthur O'Shaughnessy
  29. 4 points
    It's been a few months since the last staff blog update, and I apologize for that. It was a busy end of 2017. We've recently announced several new community features here on GameDev.net that I'd like to go through - if you haven't spent time exploring all of GameDev.net then you might have missed these! GameDev Challenges Spawned from this forum request: GameDev Challenges is a new community "game jam"-like event for developers looking to test their skills or learn through short-form projects intended to take no more than a month or two to develop. Developers who complete the challenges in the allotted time earn a badge on their profile. Of course, developers can complete challenges after the allotted time, but right now the badges are not awarded. Right now we are using the GameDev Challenges forum to manage these (Forums -> Community -> GameDev Challenges), and we're currently on the 3rd challenge where developers need to create a clone of the arcade classic Missile Command. The first two challenges were for a Pong! clone and an Arcade Battle Arena along the lines of the classic Bubble Bobble. I encourage everyone to check out the threads and entries for all the challenges! In the near future we'll integrate Challenges with our latest announcement: Projects and Developer Profiles. Projects As we announced: The Project profile is pretty extensive. We recommend setting up a developer blog for each Project, which can then be used to provide updates for the Project and will show on your Project page. A Gallery is also automatically created for your Project (if you don't already have one), and from there you can upload screenshots and videos of your Project - these will also show in your Project page. The rest of your Project profile includes links to your Project homepage, store links, descriptions, platforms, and other details about your project. You can even upload and manage files for others to download. Here's the feature list from the announcement: Browse, download, and comment on projects from other Developers Provide updates to your project by linking your GameDev.net Blog Create your own Developer profile, including with a GameDev.net subdomain (in progress)! Showcase your Project with screenshots from your project's linked GameDev.net Album Manage your projects through your Developer Dashboard Market your project's website, Facebook, Twitter, Steam, Patreon, Kickstarter, and GameDev.Market pages Track project views and downloads through Google Analytics Upload and manage file downloads for your Project, allowing others to try it out and give feedback Link to your project with an embeddable widget (link auto-embeds on GameDev.net) Showcase your project with a trailer on YouTube or Vimeo Import your project from IndieDB or itch.io Developer Profiles Developer Profiles are a new feature of your GameDev.net profile for showcasing your development team(s). We have basic features for this right now with plans to expand it. You'll find all the settings for your Developer Profile in the Project Dashboard mentioned earlier. NeHe Source Code on GitHub Also mentioned recently is that we've put all of the NeHe tutorial source code on GitHub at https://github.com/gamedev-net/nehe-opengl. We will accept updates to the source code via pull request. NeHe is our long-running OpenGL tutorial site for developers wanting to learn OpenGL in a very accessible, straightforward manner, and is available at http://nehe.gamedev.net. GameDev Loadout Podcast And finally, if you're into podcasts then I suggest checking out our new Podcast section. We've recently partnered with Tony at GameDev Loadout to showcase his podcasts on GameDev.net. Tony interviews industry professionals and indie developers about a number of game development related topics. He's approaching his 80th episode, which is quite a feat! Next? We have bigger plans with Projects, Developer Profiles, and GameDev Challenges, so keep an eye out for more updates. We'll also be re-evaluating the home page in the near future (yes, again) to try to make it easier to find content you're interested in seeing across the entire site. Oh, one last announcement - the Game Developers Conference is quickly approaching, and GameDev.net members can get 10% off All Access and GDC Conference passes using this code: GDC18DEV As always, please share any thoughts and feedback in the comments below!
  30. 4 points
    I caught wind of the Missile Command challenge earlier in the month and figured I'd knock it out during Christmas break. I was planning on coding more on my Car Wars prototype but the challenge took up most of my programming time. Sleeping late, hanging out with my family, and playing video games took up the rest of my free time. All in all, it was a great way to slide into the new year. I spent some effort keeping the code clean (mostly) and even did a couple of hours worth of commenting and code reorganization before zipping up the package. Many sample projects are quick and dirty affairs so aren't really a good learning resource for new programmers. Hopefully my project isn't too bad to look at. What went right? Switching to Unity a few years ago. This was definitely the right call for me. It helped me land my dream job and allows me to focus on making games rather than coding EVERYTHING from the ground up. KISS (Keep It Simple Stupid) - I started thinking about doing my own take on Missile Command but decided on doing just a simple clone. The known and limited scope let me keep the project clean and kept development time down to something reasonable. Playing the original at http://my.ign.com/atari/missile-command was a big help for identifying features I wanted. Getting the pixel perfect look of old-school graphics was a little bit tricky, but thanks to a well written article I was able to get sharp edges on my pixels. https://blogs.unity3d.com/2015/06/19/pixel-perfect-2d/ I had done some research on this earlier so I knew this would be a problem I'd have to solve. Or rather see how someone else solved it and implement that. Using free sounds from freesound.org was a good use of time. There are only 4 sound effects in the game and it only took me an hour or two to find what I felt were the right ones. What went ok? Making UI's in Unity doesn't come naturally to me yet. I just want some simple elements laid out on the screen. Sometimes it goes pretty quickly, other times I'm checking and unchecking checkboxes, dragging stuff around in the heirarchy, and basically banging around on it until it works. I got the minimal core features of Missile Command, but not all of it. You don't really think about all the details until you start making them. I'm missing cruise missiles, bombers, and the splitting of warheads. Dragging the different sprites into position on the screen was manual and fiddly. There's probably a better way to do this, but it didn't take too long. You can't shoot through explosions, which makes the game a little more challenging. And you can blow up your own cities if you shoot defense warheads too close to them. It was easy enough to fix, but I left it in there. What went wrong? I spent a ton of time getting the pixel perfect stuff right. Playtesting in editor, it was set to Maximize on Play. There wasn't quite enough room to see the full screen so the scale was at 0.97 making the display 97% what it should be and thus, blurred all my sharp edges. I didn't see that setting though... >.< I pulled my hair out trying to see the problem in my math, and even downloaded a free pixel perfect camera which was STILL showing blurry stuff. Finally, I built the game and ran it outside the editor and saw things were just fine. There's also an import setting on sprites for Compression that I cleared to None. I'm not sure if this second step was necessary. I've been bit by the Editor not being 100% accurate to final game play and wished I would have tried that sooner. I had trouble with the scoring screen. I wanted to put the missiles up on the score line like Missile Command does, but ran into trouble with game sized assets and canvas sized UI elements. After 45 minutes or so I said screw it, and just put a count of the missiles and cities up. I didn't data drive the game as much as I wanted. The data is in the code itself so users can't mod the game without downloading the source code. I'm also only using one set of colors for the level. If I put any more time into this, I'll probably tackle this issue next, and then worry about the features I missed out on. Final thoughts Working on this project makes me appreciate how awesome the programmers of old really were. With the tools I have (Unity, Visual Studio, etc.) it took me a couple of weekends. And even then I didn't recreate all the features of the original. I'm including a link to the zipped up project in case anyone wants to see the source code to play around with it. Hopefully someone finds it useful. If so, let me know. EcksMissileCommand.zip - Executable if you want to play. EcksMissileCommand_Source.zip - The project if you want to mess around with it. Sound Credits freesound.org https://freesound.org/people/sharesynth/sounds/344506/ - Explosion.wav https://freesound.org/people/sharesynth/sounds/344525/ - LevelStartAlarm.wav LevelStartAlarm_Edit.wav - I used Audacity to edit the above sound. I took the first six beeps then faded them to silence. https://freesound.org/people/Robinhood76/sounds/273332/ - MissileLaunch.wav https://freesound.org/people/sharesynth/sounds/341250/ - ScoreCount.wav
  31. 4 points
    You started to big with your project (I have seen your posts on the forum). You should have made a small game first, you would have gotten to the reward faster. Then you should have made a small team project, 2-3 members and only after that should you have dived into your large project and assembling a large team. It takes around 12 years for you to reach the point where you can make your "The Game" and only the possible parts.( I still can't make that talking AI I wanted.) Making games is hard, it's expensive, the people you make it for will hate for it and others will tell you it isn't a real job. Find some reason to make games, without it you will be crushed. I don't believe that a hobby team of around 12 people with random skills and around $500 000 budget, could match 250-500 dedicated professionals with a $40 000 000 budget. Even Big Indie developers spend millions on there games. For indie developers the goal should be something like Minecraft or Five Nights At Freddy's; special games that isn't too expensive to make and breaks the mold.
  32. 4 points
    This question is pretty vague. I'll just describe how I generally do the main game loop, but this is just one of many ways that it can work. I have an object Game... this is the object that contains the main game loop. It also contains a member called ActiveGameScene which implements the interface IGameScene. The IGameScene has three primary responsibilites... Respond to a request, Update the GameState or Render the gamestate. The IGameScene contains a list of IGameSystems. Game Systems are very tightly focused "functionality packets" so, one system may be my input system and another may be my rendering system and there may be many more... lighting systems, ai systems etc. Each System has methods ProcessRequest, Update, and Render. So, the Game contains a Scene which contains a set of Systems and the main game loop is //Pseudo Code //In Game while(running) { while(requestsPending) Scene.ProcessRequest(request); Scene.Update(); Scene.Render(); } //In GameScene ProcessRequest(){ Foreach(ISystem sys in Systems) sys.ProcessRequest(request); } Update(){foreach(ISystem sys in Systems) sys.Update();} Render(){foreach(ISystem sys in Systems) sys.Render();} Then, it's in the specific systems where the interesting things happen. Maybe there is an AI System... //In AI System ProcessRequest(request){ } Update(){ Foreach(AIUnit){ if (AIUnit.CurrentAction==null) { AIUnit.CurrentAction = AIUnit.ChooseNextAction(); } switch(AIUnit.CurrentAction) { case Idle : Break; case Attack: AIUnit.Attack(); break; case Move: AIUnit.Position+= (AIUnit.Dest-AIUnit.Pos).Normalize(); } } }
  33. 4 points
    My turn. Source file and exec are in the zip here https://github.com/wybifu/missile_command/archive/master.zip and also : and album
  34. 4 points
    Seems you need to do your debugging yourself Did you try to output variables to screen one after another, something like: SkyColors[DTID.xy] = float4(X,Y,r, 1); You can make some conclusions based at the colors you see. If this does not help you can create a debug buffer, store variables there, read back to CPU and print them so you can spot NaNs or infinites. That's annoying but once set up you can use that debugging for each shader.
  35. 4 points
    The title is vague, so I'll explain. I was frustrated with UI dev (in general), and even more-so when working with a application that needed OpenGL with embedded UI. What if I wanted to make a full application with OpenGL? (Custom game engine anyone?) Well I did want to. And I'm working on it right now. But it started me onto making what I think is a great idea of a styling language; I present KSS (pron. Kiss) The multitudes more programmable version of CSS.... (only for desktop dev) /* It has all the 'normal' styling stuff, like you'd expect. */ elementName { /*This is a styling field.*/ font-color: rgb(0,0,0), font: "Calibri", font-size: 12px } .idName { color: rgba(255,255,255,0) } uiName : onMouse1Click{ color: vec3(0,0,0) } BUT It also has some cool things. I've taken the liberty to add variables, templates (style inheritance), hierarchy-selection, events (as objects), native function calls, in-file functions. var defaultColor: rgb(0,0,0) var number : 1.0 /*Types include: rgb, rgba, vec2, vec3, vec4, number, string, true, false, none (null), this*/ fun styleSomeStuff{ .buttons{ color: defaultColor, text-color: rgb(number,255,number) } } template buttonStyle{ color: rgb(255,255,0) } .buttons{ use: buttonStyle, otherTemplateName /*copies the templates styling field*/ color: defaultColor; } .buttons : onMouse1Click{ /* events not assigned as a value are initialized when read from file*/ styleSomeStuff();*/* call the in-file function*/ *nativeFunctionCall();/*call a native function that's binded*/ var a : 2; /*assign a variable, even if not initially defined.*/ } /*storing an event in a 'value' will allow you to operate on the event itself. It is only ran when 'connected', below.*/ val ON_CLICK2 = .buttons : onMouse2Click{ use: templateName } connect ON_CLICK2; disconnect ON_CLICK2; /*you can make a function to do the same.*/ fun connectStuff{ connect ON_CLICK2; } But wait, you ask... what If I need to select items from a hierarchy? Surely using element names and id's couldn't be robust enough! Well: /*We use the > to indicate the item next element is a 'child' to itemA in the hierarchy*/ itemA > itemAChild : onMouse1Click{ } .itemId > .itemAChild > itemAChildsChild{ } /*want to get all children of the element at hand?*/ elementName > .any{ /*this will style all the elements children*/ } /*What about if we want to use conditional styling? Like if a variable or tag inside the element is or isnt something?*/ var hello : false; var goodbye : true; itemA [var hello = false, var goodbye != false] { /*passes*/ } itemA [@tagName = something]{ /*passes is the tag is equal to whatever the value u asked.*/ } The last things to note are event-pointers, how tagging works, 'this', and general workflow. Tagging works (basically) the same as Unity, you say @tagName : tagValue inside a styling field to assign that element a tag that's referable in the application. You have the ability to refer to any variable you assign within the styling sheet, from say.. source-code. The backend. As such, being able to set a variable to 'this' (the element being styled) allows you to operate with buttons who are currently in focus, or set the parent of an item to another element. All elements are available to use as variables inside and outside the styling sheet, so an event can effectively parent an element or group of elements to a UI you specify. Ill show that in a figure below, Event pointers are so that you can trigger an event with a UI component, but affect another, below- /*We use the -> to point to a new element, or group of elements to style.*/ .buttons : onMouse1Click -> .buttons > childName{ visible : false parent: uiName; } /* In this case, we style something with the name "childName" whos parented to anything with the id 'buttons'. Likewise, we if there was a element with the name 'uiName', it would parent the childName element to it. */ Lastly: The results/workflow. I'm in the process of building my first (serious) game engine after learning OpenGL, and I'm building it with Kotlin and Python. I can bind both Kotlin and Python functions for use inside the styling sheet, and although I didn't show the layout-language (cause its honestly not good), this is the result after a day of work so far, while using these two UI languages I've made (In the attachments.) It's also important to note that while it does adopt the CSS Box-model, it is not a Cascading layout. That's all I had to show. Essentially, right now Its a Kotlin -backed creation, but can be made for Java specifically, C++, C#, etc. I'm planning on adding more into the language to make it even more robust. What's more, it doesn't need to be OpenGL backed- it can use Java paint classes, SFML, etc etc. I just need to standardize the API for it. I guess what I'm wondering is, if I put it out there- would anyone want to use it for desktop application dev? P.S. Of course the syntax is subject to change, via suggestion. P.S.[2] The image in the middle of the editor is static, but wont be when I put 3D scenes in the scene-view.
  36. 4 points
    What exactly is an Octree? If you're completely unfamiliar with them, I recommend reading the wikipedia article (read time: ~5 minutes). This is a sufficient description of what it is but is barely enough to give any ideas on what it's used for and how to actually implement one. In this article, I will do my best to take you through the steps necessary to create an octree data structure through conceptual explanations, pictures, and code, and show you the considerations to be made at each step along the way. I don't expect this article to be the authoritative way to do octrees, but it should give you a really good start and act as a good reference. Assumptions Before we dive in, I'm going to be making a few assumptions about you as a reader: You are very comfortable with programming in a C-syntax-style language (I will be using C# with XNA). You have programmed some sort of tree-like data structure in the past, such as a binary search tree and are familiar with recursion and its strengths and pitfalls. You know how to do collision detection with bounding rectangles, bounding spheres, and bounding frustums. You have a good grasp of common data structures (arrays, lists, etc) and understand Big-O notation (you can also learn about Big-O in this GDnet article). You have a development environment project which contains spatial objects which need collision tests. Setting the stage Let's suppose that we are building a very large game world which can contain thousands of physical objects of various types, shapes and sizes, some of which must collide with each other. Each frame we need to find out which objects are intersecting with each other and have some way to handle that intersection. How do we do it without killing performance? Brute force collision detection The simplest method is to just compare each object against every other object in the world. Typically, you can do this with two for loops. The code would look something like this: foreach(gameObject myObject in ObjList) { foreach(gameObject otherObject in ObjList) { if(myObject == otherObject) continue; //avoid self collision check if(myObject.CollidesWith(otherObject)) { //code to handle the collision } } } Conceptually, this is what we're doing in our picture: Each red line is an expensive CPU test for intersection. Naturally, you should feel horrified by this code because it is going to run in O(N^2) time. If you have 10,000 objects, then you're going to be doing 100,000,000 collision checks (hundred million). I don't care how fast your CPU is or how well you've tuned your math code, this code would reduce your computer to a sluggish crawl. If you're running your game at 60 frames per second, you're looking at 60 * 100 million calculations per second! It's nuts. It's insane. It's crazy. Let's not do this if we can avoid it, at least not with a large set of objects. This would only be acceptable if we're only checking, say, 10 items against each other (100 checks is palatable). If you know in advance that your game is only going to have a very small number of objects (i.e., asteriods), you can probably get away with using this brute force method for collision detection and ignore octrees altogether. If/when you start noticing performance problems due to too many collision checks per frame, consider some simple targeted optimizations: 1. How much computation does your current collision routine take? Do you have a square root hidden away in there (ie, a distance check)? Are you doing a granular collision check (pixel vs pixel, triangle vs triangle, etc)? One common technique is to perform a rough, coarse check for collision before testing for a granular collision check. You can give your objects an enclosing bounding rectangle or bounding sphere and test for intersection with these before testing against a granular check which may involve a lot more math and computation time. Use a "distance squared" check for comparing distance between objects to avoid using the square root method. Square root calculation typically uses the newtonian method of approximation and can be computationally expensive. 2. Can you get away with calculating fewer collision checks? If your game runs at 60 frames per second, could you skip a few frames? If you know certain objects behave deterministically, can you "solve" for when they will collide ahead of time (ie, pool ball vs. side of pool table). Can you reduce the number of objects which need to be checked for collisions? A technique for this would be to separate objects into several lists. One list could be your "stationary" objects list. They never have to test for collision against each other. The other list could be your "moving" objects, which need to be tested against all other moving objects and against all stationary objects. This could reduce the number of necessary collision tests to reach an acceptable performance level. 3. Can you get away with removing some object collision tests when performance becomes an issue? For example, a smoke particle could interact with a surface object and follow its contours to create a nice aesthetic effect, but it wouldn't break game play if you hit a predefined limit for collision checks and decided to stop ignoring smoke particles for collision. Ignoring essential game object movement would certainly break game play though (ei, player bullets stop intersecting with monsters). So, perhaps maintaining a priority list of collision checks to compute would help. First you handle the high priority collision tests, and if you're not at your threshold, you can handle lower priority collision tests. When the threshold is reached, you dump the rest of the items in the priority list or defer them for testing at a later time. 4. Can you use a faster but still simplistic method for collision detection to get away from a O(N^2) runtime? If you eliminate the objects you've already checked for collisions against, you can reduce the runtime to O(N(N+1)/2), which is much faster and still easy to implement. (technically, it's still O(N^2)) In terms of software engineering, you may end up spending more time than it's worth fine-tuning a bad algorithm & data structure choice to squeeze out a few more ounces of performance. The cost vs. benefit ratio becomes increasingly unfavorable and it becomes time to choose a better data structure to handle collision detection. Spatial partitioning algorithms are the proverbial nuke to solving the runtime problem for collision detection. At a small upfront cost to performance, they'll reduce your collision detection tests to logarithmic runtime. The upfront costs of development time and CPU overhead are easily outweighed by the scalability benefits and performance gains. Conceptual background on spatial partitioning Let's take a step back and look at spatial partitioning and trees in general before diving into Octrees. If we don't understand the conceptual idea, we have no hope of implementing it by sweating over code. Looking at the brute force implementation above, we're essentially taking every object in the game and comparing their positions against all other objects in the game to see if any are touching. All of these objects are contained spatially within our game world. Well, if we create an enclosing box around our game world and figure out which objects are contained within this enclosing box, then we've got a region of space with a list of contained objects within it. In this case, it would contain every object in the game. We can notice that if we have an object on one corner of the world and another object way on the other side, we don't really need to, or want to, calculate a collision check against them every frame. It'd be a waste of precious CPU time. So, let's try something interesting! If we divide our world exactly in half, we can create three separate lists of objects. The first list of objects, List A, contains all objects on the left half of the world. The second list, List B, contains objects on the right half of the world. Some objects may touch the dividing line such that they're on each side of the line, so we'll create a third list, List C, for these objects. We can notice that with each subdivision, we're spatially reducing the world in half and collecting a list of objects in that resulting half. We can elegantly create a binary search tree to contain these lists. Conceptually, this tree should look something like so: In terms of pseudo code, the tree data structure would look something like this: public class BinaryTree { //This is a list of all of the objects contained within this node of the tree private List m_objectList; //These are pointers to the left and right child nodes in the tree private BinaryTree m_left, m_right; //This is a pointer to the parent object (for upward tree traversal). private BinaryTree m_parent; } We know that all objects in List A will never intersect with any objects in List B, so we can almost eliminate half of the number of collision checks. We've still got the objects in List C which could touch objects in either list A or B, so we'll have to check all objects in List C against all objects in Lists A, B & C. If we continue to sub-divide the world into smaller and smaller parts, we can further reduce the number of necessary collision checks by half each time. This is the general idea behind spatial partitioning. There are many ways to subdivide a world into a tree-like data structure (BSP trees, Quad Trees, K-D trees, OctTrees, etc). Now, by default, we're just assuming that the best division is a cut in half, right down the middle, since we're assuming that all of our objects will be somewhat uniformly distributed throughout the world. It's not a bad assumption to make, but some spatial division algorithms may decide to make a cut such that each side has an equal amount of objects (a weighted cut) so that the resulting tree is more balanced. However, what happens if all of these objects move around? In order to maintain a nearly even division, you'd have to either shift the splitting plane or completely rebuild the tree each frame. It'd be a bit of a mess with a lot of complexity. So, for my implementation of a spatial partitioning tree I decided to cut right down the middle every time. As a result, some trees may end up being a bit more sparse than others, but that's okay -- it doesn't cost much. To subdivide or not to subdivide? That is the question. Let's assume that we have a somewhat sparse region with only a few objects. We could continue subdividing our space until we've found the smallest possible enclosing area for that object. But is that really necessary? Let's remember that the whole reason we're creating a tree is to reduce the number of collision checks we need to perform each frame -- not to create a perfectly enclosing region of space for every object. Here are the rules I use for deciding whether to subdivide or not: If we create a subdivision which only contains one object, we can stop subdividing even though we could keep dividing further. This rule will become an important part of the criteria for what defines a "leaf node" in our octree. The other important criteria is to set a minimum size for a region. If you have an extremely small object which is nanometers in size (or, god forbid, you have a bug and forgot to initialize an object size!), you're going to keep subdividing to the point where you potentially overflow your call stack. For my own implementation, I defined the smallest containing region to be a 1x1x1 cube. Any objects in this teeny cube will just have to be run with the O(N^2) brute force collision test (I don't anticipate many objects anyways!). If a containing region doesn't contain any objects, we shouldn't try to include it in the tree. We can take our subdivision by half one step further and divide the 2D world space into quadrants. The logic is essentially the same, but now we're testing for collision with four squares instead of two rectangles. We can continue subdividing each square until our rules for termination are met. The representation of the world space and corresponding data structure for a quad tree would look something like this: If the quad tree subdivision and data structure make sense, then an octree should be pretty straight forward as well. We're just adding a third dimension, using bounding cubes instead of bounding squares, and have eight possible child nodes instead of four. Some of you might wonder what should happen if you have a game world with non-cubic dimensions, say 200x300x400. You can still use an octree with cubic dimensions -- some child nodes will just end up empty if the game world doesn't have anything there. Obviously, you'll want to set the dimensions of your octree to at least the largest dimension of your game world. Octree Construction So, as you've read, an octree is a special type of subdividing tree commonly used for objects in 3D space (or anything with 3 dimensions). Our enclosing region is going to be a three dimensional rectangle (commonly a cube). We will then apply our subdivision logic above, and cut our enclosing region into eight smaller rectangles. If a game object completely fits within one of these subdivided regions, we'll push it down the tree into that node's containing region. We'll then recursively continue subdividing each resulting region until one of our breaking conditions is met. At the end, we should expect to have a nice tree-like data structure. My implementation of the octree can contain objects which have either a bounding sphere and/or a bounding rectangle. You'll see a lot of code I use to determine which is being used. In terms of our Octree class data structure, I decided to do the following for each tree: Each node has a bounding region which defines the enclosing region Each node has a reference to the parent node Contains an array of eight child nodes (use arrays for code simplicity and cache performance) Contains a list of objects contained within the current enclosing region I use a byte-sized bitmask for figuring out which child nodes are actively being used (the optimization benefits at the cost of additional complexity is somewhat debatable) I use a few static variables to indicate the state of the tree Here is the code for my Octree class outline: public class OctTree { BoundingBox m_region; List m_objects; /// /// These are items which we're waiting to insert into the data structure. /// We want to accrue as many objects in here as possible before we inject them into the tree. This is slightly more cache friendly. /// static Queue m_pendingInsertion = new Queue(); /// /// These are all of the possible child octants for this node in the tree. /// OctTree[] m_childNode = new OctTree[8]; /// /// This is a bitmask indicating which child nodes are actively being used. /// It adds slightly more complexity, but is faster for performance since there is only one comparison instead of 8. /// byte m_activeNodes = 0; /// /// The minumum size for enclosing region is a 1x1x1 cube. /// const int MIN_SIZE = 1; /// /// this is how many frames we'll wait before deleting an empty tree branch. Note that this is not a constant. The maximum lifespan doubles /// every time a node is reused, until it hits a hard coded constant of 64 /// int m_maxLifespan = 8; // int m_curLife = -1; //this is a countdown time showing how much time we have left to live /// /// A reference to the parent node is nice to have when we're trying to do a tree update. /// OctTree _parent; static bool m_treeReady = false; //the tree has a few objects which need to be inserted before it is complete static bool m_treeBuilt = false; //there is no pre-existing tree yet. } Initializing the enclosing region The first step in building an octree is to define the enclosing region for the entire tree. This will be the bounding box for the root node of the tree which initially contains all objects in the game world. Before we go about initializing this bounding volume, we have a few design decisions we need to make: 1. What should happen if an object moves outside of the bounding volume of the root node? Do we want to resize the entire octree so that all objects are enclosed? If we do, we'll have to completely rebuild the octree from scratch. If we don't, we'll need to have some way to either handle out of bounds objects, or ensure that objects never go out of bounds. 2. How do we want to create the enclosing region for our octree? Do we want to use a preset dimension, such as a 200x400x200 (X,Y,Z) rectangle? Or do we want to use a cubic dimension which is a power of 2? What should be the smallest allowable enclosing region which cannot be subdivided? Personally, I decided that I would use a cubic enclosing region with dimensions which are a power of 2, and sufficiently large to completely enclose my world. The smallest allowable cube is a 1x1x1 unit region. With this, I know that I can always cleanly subdivide my world and get integer numbers (even though the Vector3 uses floats). I also decided that my enclosing region would enclose the entire game world, so if an object leaves this region, it should be quietly destroyed. At the smallest octant, I will have to run a brute force collision check against all other objects, but I don't realistically expect more than 3 objects to occupy that small of an area at a time, so the performance costs of O(N^2) are completely acceptable. So, I normally just initialize my octree with a constructor which takes a region size and a list of items to insert into the tree. I feel it's barely worth showing this part of the code since it's so elementary, but I'll include it for completeness. Here are my constructors: /*Note: we want to avoid allocating memory for as long as possible since there can be lots of nodes.*/ /// /// Creates an oct tree which encloses the given region and contains the provided objects. /// /// The bounding region for the oct tree. /// The list of objects contained within the bounding region private OctTree(BoundingBox region, List objList) { m_region = region; m_objects = objList; m_curLife = -1; } public OctTree() { m_objects = new List(); m_region = new BoundingBox(Vector3.Zero, Vector3.Zero); m_curLife = -1; } /// /// Creates an octTree with a suggestion for the bounding region containing the items. /// /// The suggested dimensions for the bounding region. /// Note: if items are outside this region, the region will be automatically resized. public OctTree(BoundingBox region) { m_region = region; m_objects = new List(); m_curLife = -1; } Building an initial octree I'm a big fan of lazy initialization. I try to avoid allocating memory or doing work until I absolutely have to. In the case of my octree, I avoid building the data structure as long as possible. We'll accept a user's request to insert an object into the data structure, but we don't actually have to build the tree until someone runs a query against it. What does this do for us? Well, let's assume that the process of constructing and traversing our tree is somewhat computationally expensive. If a user wants to give us 1,000 objects to insert into the tree, does it make sense to recompute every subsequent enclosing area a thousand times? Or, can we save some time and do a bulk blast? I created a "pending" queue of items and a few flags to indicate the build state of the tree. All of the inserted items get put into the pending queue and when a query is made, those pending requests get flushed and injected into the tree. This is especially handy during a game loading sequence since you'll most likely be inserting thousands of objects at once. After the game world has been loaded, the number of objects injected into the tree is orders of magnitude fewer. My lazy initialization routine is contained within my UpdateTree() method. It checks to see if the tree has been built, and builds the data structure if it doesn't exist and has pending objects. /// /// Processes all pending insertions by inserting them into the tree. /// /// Consider deprecating this? private void UpdateTree() //complete & tested { if (!m_treeBuilt) { while (m_pendingInsertion.Count != 0) m_objects.Add(m_pendingInsertion.Dequeue()); BuildTree(); } else { while (m_pendingInsertion.Count != 0) Insert(m_pendingInsertion.Dequeue()); } m_treeReady = true; } As for building the tree itself, this can be done recursively. So for each recursive iteration, I start off with a list of objects contained within the bounding region. I check my termination rules, and if we pass, we create eight subdivided bounding areas which are perfectly contained within our enclosed region. Then, I go through every object in my given list and test to see if any of them will fit perfectly within any of my octants. If they do fit, I insert them into a corresponding list for that octant. At the very end, I check the counts on my corresponding octant lists and create new octrees and attach them to our current node, and mark my bitmask to indicate that those child octants are actively being used. All of the left over objects have been pushed down to us from our parent, but can't be pushed down to any children, so logically, this must be the smallest octant which can contain the object. /// /// Naively builds an oct tree from scratch. /// private void BuildTree() //complete & tested { //terminate the recursion if we're a leaf node if (m_objects.Count <= 1) return; Vector3 dimensions = m_region.Max - m_region.Min; if (dimensions == Vector3.Zero) { FindEnclosingCube(); dimensions = m_region.Max - m_region.Min; } //Check to see if the dimensions of the box are greater than the minimum dimensions if (dimensions.X <= MIN_SIZE && dimensions.Y <= MIN_SIZE && dimensions.Z <= MIN_SIZE) { return; } Vector3 half = dimensions / 2.0f; Vector3 center = m_region.Min + half; //Create subdivided regions for each octant BoundingBox[] octant = new BoundingBox[8]; octant[0] = new BoundingBox(m_region.Min, center); octant[1] = new BoundingBox(new Vector3(center.X, m_region.Min.Y, m_region.Min.Z), new Vector3(m_region.Max.X, center.Y, center.Z)); octant[2] = new BoundingBox(new Vector3(center.X, m_region.Min.Y, center.Z), new Vector3(m_region.Max.X, center.Y, m_region.Max.Z)); octant[3] = new BoundingBox(new Vector3(m_region.Min.X, m_region.Min.Y, center.Z), new Vector3(center.X, center.Y, m_region.Max.Z)); octant[4] = new BoundingBox(new Vector3(m_region.Min.X, center.Y, m_region.Min.Z), new Vector3(center.X, m_region.Max.Y, center.Z)); octant[5] = new BoundingBox(new Vector3(center.X, center.Y, m_region.Min.Z), new Vector3(m_region.Max.X, m_region.Max.Y, center.Z)); octant[6] = new BoundingBox(center, m_region.Max); octant[7] = new BoundingBox(new Vector3(m_region.Min.X, center.Y, center.Z), new Vector3(center.X, m_region.Max.Y, m_region.Max.Z)); //This will contain all of our objects which fit within each respective octant. List[] octList = new List[8]; for (int i = 0; i < 8; i++) octList = new List(); //this list contains all of the objects which got moved down the tree and can be delisted from this node. List delist = new List(); foreach (Physical obj in m_objects) { if (obj.BoundingBox.Min != obj.BoundingBox.Max) { for (int a = 0; a < 8; a++) { if (octant[a].Contains(obj.BoundingBox) == ContainmentType.Contains) { octList[a].Add(obj); delist.Add(obj); break; } } } else if (obj.BoundingSphere.Radius != 0) { for (int a = 0; a < 8; a++) { if (octant[a].Contains(obj.BoundingSphere) == ContainmentType.Contains) { octList[a].Add(obj); delist.Add(obj); break; } } } } //delist every moved object from this node. foreach (Physical obj in delist) m_objects.Remove(obj); //Create child nodes where there are items contained in the bounding region for (int a = 0; a < 8; a++) { if (octList[a].Count != 0) { m_childNode[a] = CreateNode(octant[a], octList[a]); m_activeNodes |= (byte)(1 << a); m_childNode[a].BuildTree(); } } m_treeBuilt = true; m_treeReady = true; } private OctTree CreateNode(BoundingBox region, List objList) //complete & tested { if (objList.Count == 0) return null; OctTree ret = new OctTree(region, objList); ret._parent = this; return ret; } private OctTree CreateNode(BoundingBox region, Physical Item) { List objList = new List(1); //sacrifice potential CPU time for a smaller memory footprint objList.Add(Item); OctTree ret = new OctTree(region, objList); ret._parent = this; return ret; } Updating a tree Let's imagine that our tree has a lot of moving objects in it. If any object moves, there is a good chance that the object has moved outside of its enclosing octant. How do we handle changes in object position while maintaining the integrity of our tree structure? Technique 1: Keep it super simple, trash & rebuild everything. Some implementations of an Octree will completely rebuild the entire tree every frame and discard the old one. This is super simple and it works, and if this is all you need, then prefer the simple technique. The general consensus is that the upfront CPU cost of rebuilding the tree every frame is much cheaper than running a brute force collision check, and programmer time is too valuable to be spent on an unnecessary optimization. For those of us who like challenges and to over-engineer things, the "trash & rebuild" technique comes with a few small problems: You're constantly allocating and deallocating memory each time you rebuild your tree. Allocating new memory comes with a small cost. If possible, you want to minimize the amount of memory being allocated and reallocated over time by reusing memory you've already got. Most of the tree is unchanging, so it's a waste of CPU time to rebuild the same branches over and over again. Technique 2: Keep the existing tree, update the changed branches I noticed that most branches of a tree don't need to be updated. They just contain stationary objects. Wouldn't it be nice if, instead of rebuilding the entire tree every frame, we just updated the parts of the tree which needed an update? This technique keeps the existing tree and updates only the branches which had an object which moved. It's a bit more complex to implement, but it's a lot more fun too, so let's really get into that! During my first attempt at this, I mistakenly thought that an object in a child node could only go up or down one traversal of the tree. This is wrong. If an object in a child node reaches the edge of that node, and that edge also happens to be an edge for the enclosing parent node, then that object needs to be inserted above its parent, and possibly up even further. So, the bottom line is that we don't know how far up an object needs to be pushed up the tree. Just as well, an object can move such that it can be neatly enclosed in a child node, or that child's child node. We don't know how far down the tree we can go. Fortunately, since we include a reference to each node's parent, we can easily solve this problem recursively with minimal computation! The general idea behind the update algorithm is to first let all objects in the tree update themselves. Some may move or change in size. We want to get a list of every object which moved, so the object update method should return to us a boolean value indicating if its bounding area changed. Once we've got a list of all of our moved objects, we want to start at our current node and try to traverse up the tree until we find a node which completely encloses the moved object (most of the time, the current node still encloses the object). If the object isn't completely enclosed by the current node, we keep moving it up to its next parent node. In the worst case, our root node will be guaranteed to contain the object. After we've moved our object as far up the tree as possible, we'll try to move it as far down the tree as we can. Most of the time, if we moved the object up, we won't be able to move it back down. But, if the object moved so that a child node of the current node could contain it, we have the chance to push it back down the tree. It's important to be able to move objects down the tree as well, or else all moving objects would eventually migrate to the top and we'd start getting some performance problems during collision detection routines. Branch Removal In some cases, an object will move out of a node and that node will no longer have any objects contained within it, nor have any children which contain objects. If this happens, we have an empty branch and we need to mark it as such and prune this dead branch off the tree. There is an interesting question hiding here: When do you want to prune the dead branches off a tree? Allocating new memory costs time, so if we're just going to reuse this same region in a few cycles, why not keep it around for a bit? How long can we keep it around before it becomes more expensive to maintain the dead branch? I decided to give each of my nodes a count down timer which activates when the branch is dead. If an object moves into this nodes octant while the death timer is active, I double the lifespan and reset the death timer. This ensures that octants which are frequently used are hot and stick around, and nodes which are infrequently used are removed before they start to cost more than they're worth. A practical example of this usefulness would be apparent when you have a machine gun shooting a stream of bullets. Those bullets follow in close succession of each other, so it'd be a shame to immediately delete a node as soon as the first bullet leaves it, only to recreate it a fraction of a second later as the second bullet re-enters it. And if there's a lot of bullets, we can probably keep these octants around for a little while. If a child branch is empty and hasn't been used in a while, it's safe to prune it out of our tree. Anyways, let's look at the code which does all of this magic. First up, we have the Update() method. This is a method which is recursively called on all child trees. It moves all objects around, does some house keeping work for the data structure, and then moves each moved object into its correct node (parent or child). public void Update(GameTime gameTime) { if (m_treeBuilt == true) { //Start a count down death timer for any leaf nodes which don't have objects or children. //when the timer reaches zero, we delete the leaf. If the node is reused before death, we double its lifespan. //this gives us a "frequency" usage score and lets us avoid allocating and deallocating memory unnecessarily if (m_objects.Count == 0) { if (HasChildren == false) { if (m_curLife == -1) m_curLife = m_maxLifespan; else if (m_curLife > 0) { m_curLife--; } } } else { if (m_curLife != -1) { if(m_maxLifespan <= 64) m_maxLifespan *= 2; m_curLife = -1; } } List movedObjects = new List(m_objects.Count); //go through and update every object in the current tree node foreach (Physical gameObj in m_objects) { //we should figure out if an object actually moved so that we know whether we need to update this node in the tree. if (gameObj.Update(gameTime)) { movedObjects.Add(gameObj); } } //prune any dead objects from the tree. int listSize = m_objects.Count; for (int a = 0; a < listSize; a++) { if (!m_objects[a].Alive) { if (movedObjects.Contains(m_objects[a])) movedObjects.Remove(m_objects[a]); m_objects.RemoveAt(a--); listSize--; } } //recursively update any child nodes. for( int flags = m_activeNodes, index = 0; flags > 0; flags >>=1, index++) if ((flags & 1) == 1) m_childNode[index].Update(gameTime); //If an object moved, we can insert it into the parent and that will insert it into the correct tree node. //note that we have to do this last so that we don't accidentally update the same object more than once per frame. foreach (Physical movedObj in movedObjects) { OctTree current = this; //figure out how far up the tree we need to go to reinsert our moved object //we are either using a bounding rect or a bounding sphere //try to move the object into an enclosing parent node until we've got full containment if (movedObj.BoundingBox.Max != movedObj.BoundingBox.Min) { while (current.m_region.Contains(movedObj.BoundingBox) != ContainmentType.Contains) if (current._parent != null) current = current._parent; else break; //prevent infinite loops when we go out of bounds of the root node region } else { while (current.m_region.Contains(movedObj.BoundingSphere) != ContainmentType.Contains)//we must be using a bounding sphere, so check for its containment. if (current._parent != null) current = current._parent; else break; } //now, remove the object from the current node and insert it into the current containing node. m_objects.Remove(movedObj); current.Insert(movedObj); //this will try to insert the object as deep into the tree as we can go. } //prune out any dead branches in the tree for (int flags = m_activeNodes, index = 0; flags > 0; flags >>= 1, index++) if ((flags & 1) == 1 && m_childNode[index].m_curLife == 0) { m_childNode[index] = null; m_activeNodes ^= (byte)(1 << index); //remove the node from the active nodes flag list } //now that all objects have moved and they've been placed into their correct nodes in the octree, we can look for collisions. if (IsRoot == true) { //This will recursively gather up all collisions and create a list of them. //this is simply a matter of comparing all objects in the current root node with all objects in all child nodes. //note: we can assume that every collision will only be between objects which have moved. //note 2: An explosion can be centered on a point but grow in size over time. In this case, you'll have to override the update method for the explosion. List irList = GetIntersection(new List()); foreach (IntersectionRecord ir in irList) { if (ir.PhysicalObject != null) ir.PhysicalObject.HandleIntersection(ir); if (ir.OtherPhysicalObject != null) ir.OtherPhysicalObject.HandleIntersection(ir); } } } else { } } Note that we call an Insert() method for moved objects. The insertion of objects into the tree is very similar to the method used to build the initial tree. Insert() will try to push objects as far down the tree as possible. Notice that I also try to avoid creating new bounding areas if I can use an existing one from a child node. /// /// A tree has already been created, so we're going to try to insert an item into the tree without rebuilding the whole thing /// /// A physical object /// The physical object to insert into the tree private void Insert(T Item) where T : Physical { /*make sure we're not inserting an object any deeper into the tree than we have to. -if the current node is an empty leaf node, just insert and leave it.*/ if (m_objects.Count <= 1 && m_activeNodes == 0) { m_objects.Add(Item); return; } Vector3 dimensions = m_region.Max - m_region.Min; //Check to see if the dimensions of the box are greater than the minimum dimensions if (dimensions.X <= MIN_SIZE && dimensions.Y <= MIN_SIZE && dimensions.Z <= MIN_SIZE) { m_objects.Add(Item); return; } Vector3 half = dimensions / 2.0f; Vector3 center = m_region.Min + half; //Find or create subdivided regions for each octant in the current region BoundingBox[] childOctant = new BoundingBox[8]; childOctant[0] = (m_childNode[0] != null) ? m_childNode[0].m_region : new BoundingBox(m_region.Min, center); childOctant[1] = (m_childNode[1] != null) ? m_childNode[1].m_region : new BoundingBox(new Vector3(center.X, m_region.Min.Y, m_region.Min.Z), new Vector3(m_region.Max.X, center.Y, center.Z)); childOctant[2] = (m_childNode[2] != null) ? m_childNode[2].m_region : new BoundingBox(new Vector3(center.X, m_region.Min.Y, center.Z), new Vector3(m_region.Max.X, center.Y, m_region.Max.Z)); childOctant[3] = (m_childNode[3] != null) ? m_childNode[3].m_region : new BoundingBox(new Vector3(m_region.Min.X, m_region.Min.Y, center.Z), new Vector3(center.X, center.Y, m_region.Max.Z)); childOctant[4] = (m_childNode[4] != null) ? m_childNode[4].m_region : new BoundingBox(new Vector3(m_region.Min.X, center.Y, m_region.Min.Z), new Vector3(center.X, m_region.Max.Y, center.Z)); childOctant[5] = (m_childNode[5] != null) ? m_childNode[5].m_region : new BoundingBox(new Vector3(center.X, center.Y, m_region.Min.Z), new Vector3(m_region.Max.X, m_region.Max.Y, center.Z)); childOctant[6] = (m_childNode[6] != null) ? m_childNode[6].m_region : new BoundingBox(center, m_region.Max); childOctant[7] = (m_childNode[7] != null) ? m_childNode[7].m_region : new BoundingBox(new Vector3(m_region.Min.X, center.Y, center.Z), new Vector3(center.X, m_region.Max.Y, m_region.Max.Z)); //First, is the item completely contained within the root bounding box? //note2: I shouldn't actually have to compensate for this. If an object is out of our predefined bounds, then we have a problem/error. // Wrong. Our initial bounding box for the terrain is constricting its height to the highest peak. Flying units will be above that. // Fix: I resized the enclosing box to 256x256x256. This should be sufficient. if (Item.BoundingBox.Max != Item.BoundingBox.Min && m_region.Contains(Item.BoundingBox) == ContainmentType.Contains) { bool found = false; //we will try to place the object into a child node. If we can't fit it in a child node, then we insert it into the current node object list. for(int a=0;a<8;a++) { //is the object fully contained within a quadrant? if (childOctant[a].Contains(Item.BoundingBox) == ContainmentType.Contains) { if (m_childNode[a] != null) m_childNode[a].Insert(Item); //Add the item into that tree and let the child tree figure out what to do with it else { m_childNode[a] = CreateNode(childOctant[a], Item); //create a new tree node with the item m_activeNodes |= (byte)(1 << a); } found = true; } } if(!found) m_objects.Add(Item); } else if (Item.BoundingSphere.Radius != 0 && m_region.Contains(Item.BoundingSphere) == ContainmentType.Contains) { bool found = false; //we will try to place the object into a child node. If we can't fit it in a child node, then we insert it into the current node object list. for (int a = 0; a < 8; a++) { //is the object contained within a child quadrant? if (childOctant[a].Contains(Item.BoundingSphere) == ContainmentType.Contains) { if (m_childNode[a] != null) m_childNode[a].Insert(Item); //Add the item into that tree and let the child tree figure out what to do with it else { m_childNode[a] = CreateNode(childOctant[a], Item); //create a new tree node with the item m_activeNodes |= (byte)(1 << a); } found = true; } } if (!found) m_objects.Add(Item); } else { //either the item lies outside of the enclosed bounding box or it is intersecting it. Either way, we need to rebuild //the entire tree by enlarging the containing bounding box //BoundingBox enclosingArea = FindBox(); BuildTree(); } } Collision Detection Finally, our octree has been built and everything is as it should be. How do we perform collision detection against it? First, let's list out the different ways we want to look for collisions: Frustum intersections. We may have a frustum which intersects with a region of the world. We only want the objects which intersect with the given frustum. This is particularly useful for culling regions outside of the camera view space, and for figuring out what objects are within a mouse selection area. Ray intersections. We may want to shoot a directional ray from any given point and want to know either the nearest intersecting object, or get a list of all objects which intersect that ray (like a rail gun). This is very useful for mouse picking. If the user clicks on the screen, we want to draw a ray into the world and figure out what they clicked on. Bounding Box intersections. We want to know which objects in the world are intersecting a given bounding box. This is most useful for "box" shaped game objects (houses, cars, etc). Bounding Sphere Intersections. We want to know which objects are intersecting with a given bounding sphere. Most objects will probably be using a bounding sphere for coarse collision detection since the mathematics is computationally the least expensive and somewhat easy. The main idea behind recursive collision detection processing for an octree is that you start at the root/current node and test for intersection with all objects in that node against the intersector. Then, you do a bounding box intersection test against all active child nodes with the intersector. If a child node fails this intersection test, you can completely ignore the rest of that child's tree. If a child node passes the intersection test, you recursively traverse down the tree and repeat. Each node should pass a list of intersection records up to its caller, which appends those intersections to its own list of intersections. When the recursion finishes, the original caller will get a list of every intersection for the given intersector. The beauty of this is that it takes very little code to implement and performance is very fast. In a lot of these collisions, we're probably going to be getting a lot of results. We're also going to want to have some way of responding to each collision, depending on what objects are colliding. For example, a player hero should pick up a floating bonus item (quad damage!), but a rocket shouldn't explode if it hits said bonus item. I created a new class to contain information about each intersection. This class contains references to the intersecting objects, the point of intersection, the normal at the point of intersection, etc. These intersection records become quite useful when you pass them to an object and tell them to handle it. For completeness and clarity, here is my intersection record class: public class IntersectionRecord { Vector3 m_position; /// /// This is the exact point in 3D space which has an intersection. /// public Vector3 Position { get { return m_position; } } Vector3 m_normal; /// /// This is the normal of the surface at the point of intersection /// public Vector3 Normal { get { return m_normal; } } Ray m_ray; /// /// This is the ray which caused the intersection /// public Ray Ray { get { return m_ray; } } Physical m_intersectedObject1; /// /// This is the object which is being intersected /// public Physical PhysicalObject { get { return m_intersectedObject1; } set { m_intersectedObject1 = value; } } Physical m_intersectedObject2; /// /// This is the other object being intersected (may be null, as in the case of a ray-object intersection) /// public Physical OtherPhysicalObject { get { return m_intersectedObject2; } set { m_intersectedObject2 = value; } } /// /// this is a reference to the current node within the octree for where the collision occurred. In some cases, the collision handler /// will want to be able to spawn new objects and insert them into the tree. This node is a good starting place for inserting these objects /// since it is a very near approximation to where we want to be in the tree. /// OctTree m_treeNode; /// /// check the object identities between the two intersection records. If they match in either order, we have a duplicate. /// ///the other record to compare against /// true if the records are an intersection for the same pair of objects, false otherwise. public override bool Equals(object otherRecord) { IntersectionRecord o = (IntersectionRecord)otherRecord; // //return (m_intersectedObject1 != null && m_intersectedObject2 != null && m_intersectedObject1.ID == m_intersectedObject2.ID); if (otherRecord == null) return false; if (o.m_intersectedObject1.ID == m_intersectedObject1.ID && o.m_intersectedObject2.ID == m_intersectedObject2.ID) return true; if (o.m_intersectedObject1.ID == m_intersectedObject2.ID && o.m_intersectedObject2.ID == m_intersectedObject1.ID) return true; return false; } double m_distance; /// /// This is the distance from the ray to the intersection point. /// You'll usually want to use the nearest collision point if you get multiple intersections. /// public double Distance { get { return m_distance; } } private bool m_hasHit = false; public bool HasHit { get { return m_hasHit; } } public IntersectionRecord() { m_position = Vector3.Zero; m_normal = Vector3.Zero; m_ray = new Ray(); m_distance = float.MaxValue; m_intersectedObject1 = null; } public IntersectionRecord(Vector3 hitPos, Vector3 hitNormal, Ray ray, double distance) { m_position = hitPos; m_normal = hitNormal; m_ray = ray; m_distance = distance; // m_hitObject = hitGeom; m_hasHit = true; } /// /// Creates a new intersection record indicating whether there was a hit or not and the object which was hit. /// ///Optional: The object which was hit. Defaults to null. public IntersectionRecord(Physical hitObject = null) { m_hasHit = hitObject != null; m_intersectedObject1 = hitObject; m_position = Vector3.Zero; m_normal = Vector3.Zero; m_ray = new Ray(); m_distance = 0.0f; } } Intersection with a Bounding Frustum /// /// Gives you a list of all intersection records which intersect or are contained within the given frustum area /// ///The containing frustum to check for intersection/containment with /// A list of intersection records with collisions private List GetIntersection(BoundingFrustum frustum, Physical.PhysicalType type = Physical.PhysicalType.ALL) { if (m_objects.Count == 0 && HasChildren == false) //terminator for any recursion return null; List ret = new List(); //test each object in the list for intersection foreach (Physical obj in m_objects) { //skip any objects which don't meet our type criteria if ((int)((int)type & (int)obj.Type) == 0) continue; //test for intersection IntersectionRecord ir = obj.Intersects(frustum); if (ir != null) ret.Add(ir); } //test each object in the list for intersection for (int a = 0; a < 8; a++) { if (m_childNode[a] != null && (frustum.Contains(m_childNode[a].m_region) == ContainmentType.Intersects || frustum.Contains(m_childNode[a].m_region) == ContainmentType.Contains)) { List hitList = m_childNode[a].GetIntersection(frustum); if (hitList != null) { foreach (IntersectionRecord ir in hitList) ret.Add(ir); } } } return ret; } The bounding frustum intersection list can be used to only render objects which are visible to the current camera view. I use a scene database to figure out how to render all objects in the game world. Here is a snippet of code from my rendering function which uses the bounding frustum of the active camera: /// /// This renders every active object in the scene database /// /// public int Render() { int triangles = 0; //Renders all visible objects by iterating through the oct tree recursively and testing for intersection //with the current camera view frustum foreach (IntersectionRecord ir in m_octTree.AllIntersections(m_cameras[m_activeCamera].Frustum)) { ir.PhysicalObject.SetDirectionalLight(m_globalLight[0].Direction, m_globalLight[0].Color); ir.PhysicalObject.View = m_cameras[m_activeCamera].View; ir.PhysicalObject.Projection = m_cameras[m_activeCamera].Projection; ir.PhysicalObject.UpdateLOD(m_cameras[m_activeCamera]); triangles += ir.PhysicalObject.Render(m_cameras[m_activeCamera]); } return triangles; } Intersection with a Ray /// /// Gives you a list of intersection records for all objects which intersect with the given ray /// ///The ray to intersect objects against /// A list of all intersections private List GetIntersection(Ray intersectRay, Physical.PhysicalType type = Physical.PhysicalType.ALL) { if (m_objects.Count == 0 && HasChildren == false) //terminator for any recursion return null; List ret = new List(); //the ray is intersecting this region, so we have to check for intersection with all of our contained objects and child regions. //test each object in the list for intersection foreach (Physical obj in m_objects) { //skip any objects which don't meet our type criteria if ((int)((int)type & (int)obj.Type) == 0) continue; if (obj.BoundingBox.Intersects(intersectRay) != null) { IntersectionRecord ir = obj.Intersects(intersectRay); if (ir.HasHit) ret.Add(ir); } } // test each child octant for intersection for (int a = 0; a < 8; a++) { if (m_childNode[a] != null && m_childNode[a].m_region.Intersects(intersectRay) != null) { List hits = m_childNode[a].GetIntersection(intersectRay, type); if (hits != null) { foreach (IntersectionRecord ir in hits) ret.Add(ir); } } } return ret; } Intersection with a list of objects This is a particularly useful recursive method for determining if a list of objects in the current node intersect with any objects in any child nodes (See: Update() method for usage). It's the method which will be used most frequently, so it's good to get this right and efficient. What we want to do is start at the root node of the tree. We compare all objects in the current node against all other objects in the current node for collision. We gather up any of those collisions as intersection records, and insert them into a list. We then pass our list of tested objects down to our child nodes. The child nodes will then test their objects against themselves, then against the objects we passed down to them. The child nodes will capture any collisions in a list, and return that list to its parent. The parent then takes the collision list received from its child nodes and appends it to its own list of collisions, finally returning it to its caller. If you count out the number of collision tests in the illustration above, you can see that we conducted 29 hit tests and recieved 4 hits. This is much better than [11*11 = 121] hit tests. private List GetIntersection(List parentObjs, Physical.PhysicalType type = Physical.PhysicalType.ALL) { List intersections = new List(); //assume all parent objects have already been processed for collisions against each other. //check all parent objects against all objects in our local node foreach (Physical pObj in parentObjs) { foreach (Physical lObj in m_objects) { //We let the two objects check for collision against each other. They can figure out how to do the coarse and granular checks. //all we're concerned about is whether or not a collision actually happened. IntersectionRecord ir = pObj.Intersects(lObj); if (ir != null) { intersections.Add(ir); } } } //now, check all our local objects against all other local objects in the node if (m_objects.Count > 1) { #region self-congratulation /* * This is a rather brilliant section of code. Normally, you'd just have two foreach loops, like so: * foreach(Physical lObj1 in m_objects) * { * foreach(Physical lObj2 in m_objects) * { * //intersection check code * } * } * * The problem is that this runs in O(N*N) time and that we're checking for collisions with objects which have already been checked. * Imagine you have a set of four items: {1,2,3,4} * You'd first check: {1} vs {1,2,3,4} * Next, you'd check {2} vs {1,2,3,4} * but we already checked {1} vs {2}, so it's a waste to check {2} vs. {1}. What if we could skip this check by removing {1}? * We'd have a total of 4+3+2+1 collision checks, which equates to O(N(N+1)/2) time. If N is 10, we are already doing half as many collision checks as necessary. * Now, we can't just remove an item at the end of the 2nd for loop since that would break the iterator in the first foreach loop, so we'd have to use a * regular for(int i=0;i tmp = new List(m_objects.Count); tmp.AddRange(m_objects); while (tmp.Count > 0) { foreach (Physical lObj2 in tmp) { if (tmp[tmp.Count - 1] == lObj2 || (tmp[tmp.Count - 1].IsStatic && lObj2.IsStatic)) continue; IntersectionRecord ir = tmp[tmp.Count - 1].Intersects(lObj2); if (ir != null) intersections.Add(ir); } //remove this object from the temp list so that we can run in O(N(N+1)/2) time instead of O(N*N) tmp.RemoveAt(tmp.Count-1); } } //now, merge our local objects list with the parent objects list, then pass it down to all children. foreach (Physical lObj in m_objects) if (lObj.IsStatic == false) parentObjs.Add(lObj); //parentObjs.AddRange(m_objects); //each child node will give us a list of intersection records, which we then merge with our own intersection records. for (int flags = m_activeNodes, index = 0; flags > 0; flags >>= 1, index++) if ((flags & 1) == 1) intersections.AddRange(m_childNode[index].GetIntersection(parentObjs, type)); return intersections; } ;i++)> Screenshot Demos This is a view of the game world from a distance showing the outlines for each bounding volume for the octree. This view shows a bunch of successive projectiles moving through the game world with the frequently-used nodes being preserved instead of deleted. Complete Code Sample I've attached a complete code sample of the octree class, the intersection record class, and my generic physical object class. I don't guarantee that they're all bug-free since it's all a work in progress and hasn't been rigorously tested yet.
  37. 3 points

    From the album ScreenShotSaturday

    Another one of our new UI for #screenshotsaturday. This is the inventory screen for showing what animal fossils you have collected so far. #gamedev #indiedev #sama
  38. 3 points
    According to the people who keep attacking wage growth while also complaining that people don't spend enough money any more...
  39. 3 points
    I took the last two weeks of December off for holidays, so no production was done for Spellbound during that time. I met up with my friend Russel (Magforce7) for an afternoon at my office and gave him a demo of Spellbound in VR. He works for Firaxis, so it was interesting to compare notes on development and production. Without a doubt, he's a lot more experienced with production and development, so I tried to glean as many tips and tricks as I could. It was also his first time trying VR, so I gave him a bunch of quick VR demos so that he could get familiar with the medium and how to interface with it. It's interesting to compare the differences between producing a traditional video game vs. a room scale VR video game. In terms of production, I've written out the complete narrative manuscript for Episode 1 of Spellbound and have begun shopping it around to anyone willing read it. It's not "done" by any stretch, it's just the first draft, and the first draft is always going to be susceptible to lots of revisions. Currently, it's about 40 pages in length. That's about what I had expected. Now, I need to go through and do a ton of polishing passes. I think of the story sort of like one of those JPG images which loads over a slow internet connection. The very first version of the image is this highly artifacted mess which barely holds a semblance to the actual image, but with each pass, the resolution of the image improves and the details get more refined each time, until you end up with a perfectly clear image. With regards to writing narrative for a VR game, I think the pass process is going to be a lot more convoluted. The first pass is just trying to write the story itself and figure out what the story even is. The writer explores a bunch of different directions and the final product is the choices by the writer which yield the most interesting story. But, you can't just take the story of a writer and plop it into a VR game and call it perfect. In fact, the writer must keep in mind the medium they're writing for and what the capabilities of that medium are. If you're writing a script for a movie, you have to think about what scenes you're going to create and possibly consider a shot list, and also think about the actors who will portray your characters and the acting style. You can effectively frame the shot of the scene to show exactly what you want the audience to see. That's a great amount of power and control over the audience experience. Writing for VR is completely backwards. I have to preface this by saying that I'm a novice writer and have never written a script, much less, a script for VR, so take my words with a hefty grain of salt. My writing technique mostly consists of putting myself into the body of the character. I am that character. That character has a personal history. A personality. A style. Stated interests, and unstated secret interests and ambitions. Character flaws, and character strengths. I see the scene from the eyes of the character, see the state of the world, listen to what was just said, and then react based on the traits of my embodied character. The character should always be trying to progress their ambitions. Character conflict should happen when ambitions collide. When it comes to VR games, the protagonist is the player themselves, so you have to keep in mind that the protagonist has agency which the writer can't control. They experience the story from the first person perspective, through the eyes of the character they embody. So, whatever happens to the main character also happens to the player. With VR, the player brings their own body and hands into the scene, so those are things the writer can interface with. Maybe the player gives a bow to a king? What if they don't bow before royalty? Maybe when you meet a new character, they extend a hand to give a handshake? What happens if you don't shake their hand? Maybe a character comes forward to give the player a huge hug? The secret sauce for VR is finding these new ways to develop interpersonal connections with characters in the world and using that to drive story and player experience. I try to keep this at the forefront of my mind when writing for VR -- first hand player experience is king. I also want to give my characters depth, so I do this mostly through subtle narrative exposition, mostly in the form of ambient banter between characters. For the sake of simplicity of production, the main character doesn't have narrative conversation choices. This means I don't have to create conversation trees or user interfaces for dialogue choices and the flow of dialogue can be seamless and uninterrupted. I am starting to audition for character voices. I've got a list of local voice actor talents and am asking a few of them to send me a few demo lines from the manuscript and a quote for their day rates. It's hugely inspiring to hear the voices of the characters saying the lines I've written. It feels like these characters might actually exist somewhere outside of my imagination, and I owe it to them to give them the very best lines I can come up with to portray their nature and ambitions correctly. A few people have read my manuscript and given mostly positive feedback, so that suggests that I'm roughly on the right track. I'm going to spend a few days taking it to various writers meet up groups and getting critical feedback, so this will help me immensely to get to a higher level of polish and clarity. If you're interested in reading the manuscript and my production notes, feel free to read the google doc and supply feedback in the comments below: https://docs.google.com/document/d/1IvNYNf9NqtdikD6UZuGq-rUo9yU5LVqqgIlWsz6n2Qs/edit?usp=sharing (Note: It's a work in progress, so you can see changes happening live as I edit it.) The ideal is to write a story which is so compelling that it grabs people and makes them want to read it. I want to be able to drop a 40 page manuscript in someones lap and tell them to read it. They'll be thinking, "oh god, more bullshit. I don't want to read this crappy novice writing. I'll humor them and read two pages." So, they read two pages. It's good. They decide to read another page. It's also good. In fact, it's getting better. They turn to the next page to keep going. Wow. It's actually a decent story. They keep turning pages. Forty pages later, they're surprised to have read the whole thing and they are left wanting more. It's a pleasant surprise. The story should be good enough that it stands strongly on its own legs. It doesn't need anything else to be a compelling experience. Now, if you experience the same story in VR, and characters act out their lines, and the voice acting is stellar, the experience of the story is just multiplied by the talent and quality. This is the ideal I'm shooting for. Spellbound will be a story centered VR game, rather than a game which happens to have a shallow story layered on top. It's worth taking the time to nail the story and get it right, so I'm taking my time. When the manuscript is complete, I'll have voice actors voice out each of the characters. I really don't want to have to do a lot of dialogue resamples, so I need to make sure that the first time a line is voiced is also the last time it's voiced. The goal is to avoid revisions. So, how do I do this? My current plan is to polish the story and get it as close to perfection as possible. Hiring voice actors costs money. When I drop voiced lines into the game, I am going to need to know whether the line works in the current scene with the current context. So, a part of the creative writing process will require for me to experience the scene and adapt the writing for context and length through a bunch of iterations. I'm going to voice act my own characters with a crappy headphone mic and use these assets as placeholders. It'll be a really good way for me to quickly iterate on the character interactions and player experience. I kind of feel silly, like I'm just playing with dolls who are having a conversation with each other. But hey, maybe that's really the core of script writing in hollywood too? On a personal note, I've decided to give up all social media for a month. No facebook, no twitter, no reddit, no youtube, etc. The primary reason is because it costs me too much time. Typically, my day starts by waking up, pulling out my laptop and checking twitter and facebook for updates to my news feed. That costs me about 30-45 minutes before I get out of bed. Then I go to work. I get to work an hour later, start a build or compile, and since it's going to take 5 minutes to complete, I decide "Hey, I'll spend five minutes checking facebook while I wait.". That five minutes turns into twenty minutes without me realizing it. And this happens ten times a day. I can easily waste hours of my day on social media without consciously realizing it. It adds up, especially over the course of days and weeks. And for what? To stay updated and informed on the latest developments in my news feeds? Why do I actually care about that? What value does it add to my life? How is my life better? Or, is my life actually better? What if social media is actually unhealthy? What if its like cigarettes? Cigarettes cause lung cancer with prolonged use, so maybe social media causes mental health problems like depression, low self worth and narcissism with prolonged use? What if social media is inherently an anti-social activity? Anyways, I've consciously decided to abstain for a full month without social media as an experiment. So far, I'm five days in and realizing how much I was using it as an outlet for self expression. Something happens to me and my default reaction is, "Oh, this would be good to share in a post!", and now I realize "Oh, I can't share this on social media. Who am I actually trying to share this with? Why am I trying to share this? Can I just forget about sharing and just relish the experience in this fleeting moment?" The secondary effect of abstaining from social media is that I'm also trying to pull away from technology a bit more so I can find a more healthy balance between technology and life. Currently, if I'm not staring at a screen, I'm at a loss for what to do with my time. Should I really live my whole life staring at glowing rectangles? Is there more to life than that? How would I feel if I'm laying on my deathbed and reflecting on my life, realizing that I spent most of it looking at screens? I need new hobbies and passions outside of screens. So, I've picked up my old love for reading by starting in on some fantasy books. Currently, I'm well on my way through "The Way of Kings" by Brandon Sanderson. I'm reading his first book slowly, digesting it sentence by sentence, and thinking about it from the eyes of a writer instead of a reader. It's an amazingly different experience. He's got some amazingly clever lines in his book, and there are some amazing pieces of exposition which the author uses as a proxy to share his own attitudes and life philosophies. I am going to steal some of the writing techniques and use them myself. I'm also still doing VR contract work on the side in order to make money to finance my game project. The side work is picking up slightly and I'm getting better at it. I have this ambitious idea for a new way to create VR content using 360 video and pictures. Most clients are trying to capture an experience or create a tour of something in VR and taking audiences through it. Essentially, it's mostly just video captured in 360 and then projected onto the inside of a sphere, and then setting the player camera at the center of the sphere. It's somewhat simple to implement. My critique is that this isn't a very compelling virtual reality experience because it's really just a passive experience in a movie theater where the screen wraps all around the viewer. There's very little interaction. So, my idea is to flip this around. I'd like to take a 360 camera and place it at various locations, take a photograph/video, and then move the camera. Instead of having a cut to the next scene, the viewer decides when to cut and where to cut. So, let's pretend that we're creating a virtual reality hike. We incrementally move the 360 camera down the trail, 50 feet at a time, for the entire length of the hike. A hike may not be perfectly sequentially linear, there may be areas where you take a detour to experience a look out on the side of the trail. So, on the conceptual data structure level, we are going to have a connected node graph arranged spatially, and the viewer will transition between connected nodes based on what direction they want to go on the hiking trail. I'll have ambisonic audio recording, so you'll be able to hear birds chirping in the trees and a babbling brook in the side of the trail, etc. The key difference here is that the viewer drives the pace of the experience, so they can spend as much or as little time as they want, experiencing an environment/scene, and since they can control what nodes to visit next, they have agency over their entire experience. This is the magic of VR, and if I get a prototype proof of concept working, I think it can be a new type of service to sell to clients. I can go around Washington State and go create virtual recreations of hikes for people to experience. There's some beautiful hikes through the Cascade mountains. We have a desert on the eastern half of washington, filled with sage brush and basalt lava rocks. We also have a temperate rainforest on the Olympic peninsula, where we get 300+ inches of rain a year, with six feet of moss hanging off of tree branches. The geography, flora and fauna are somewhat unique to Washington state, so if I can create a library of interactive virtual reality experiences of various parts of our state, it would be a pretty cool experience, where you can get virtual tours of various parts of the state. It would almost be as good as visiting in person and a good way to preview a place you might want to experience. IF it is a popular form of content, I can expand my content library by offering virtual reality tours of other parts of the world people wouldn't otherwise be able to visit. Would you like to explore the tropical jungles of Costa Rica? Would you like to climb the mountains of Nepal? Would you like to walk around in Antarctica? Would you like to go to the Eiffel Tower? If I do this right, I could create a fun VR travel channel and combine some educational elements to the experience. It would be a good way for me to get out of the office and experience the world. I'm currently working on building a prototype proof of concept to figure out the technical side and user interface, and will probably have something rough built out by the end of the month. This could turn into a cool new way to do interactive cinema in VR. I haven't seen anyone else do something like this before, but I may just be under informed.
  40. 3 points
    During the interview for the job I have now, I told the interviewer that I felt it was my obligation to help my previous (then current) company finish an important project and asked them to let me start 2 months later. I expected that to be a problem for them, but quite the contrary: After the interview, they told me they had talked about that and found it meant I was a loyal person and that they felt assured that if I ever left the new company, I'd give them enough time to find a replacement, too. Have you tried talking to the new company about the issue? Maybe they are more open to it than you think.
  41. 3 points
    Are there differences in terms of the efficiency of generated code? Probably not. Are there differences in terms of meaning? Definitely. You inherit to be reused. Unless you plan on using your Ids through a pointer or reference to their common base class (and it's not clear why you'd ever want to do that, since weak typing was the root of your troubles to start with), you should stay away from using inheritance and stick with the type alias. Note that instead of using struct AnimalIdTag{} you could also use an enumeration or strongly-typed enumeration (an enum or an enum class) or set of constexpr constants and a non-type template parameter. Again, it won't make any difference in terms of code efficiency, but it might be better in terms of code clarity. enum class ObjectType { Animal, Tree, }; template<ObjectType T, typename ValueType = std::uint32_t> struct IdType { ValueType value; // member functions as desired }; using AnimalId = IdType<ObjectType::Animal>;
  42. 3 points
    Technically, no, you don't have to be very good at drawing to be a good 3D artist, as the process is more akin to sculpting. However, the ability to look at the third dimensional world around you and translate that to create a believable image on a two dimensional surface (i.e. draw good) can really help out while doing 3D, from creating concept art for yourself and others, to learning about shape language, to hand painting textures, and more. Might be worth trying out on occasion, while working on 3D as your main skill set. I started out in kindergarten, coloring outside the lines with wax crayons. I doodled in all of my notebooks throughout my school years, and received a lot of positive feedback, so I stuck with it. I saw some real improvement when I started copying some of my favorite comic covers, found on an image repository, back when the internet was young. Then saw another jump in skill when I started drawing things around me, and studied perspective. There are tons of resources out there these days - from video tutorials on YouTube, Gnomon or Gumroad, to online articles, to forums with members willing to give critique, even books at the local library if you want to go old school. It's true that you have a lot of catching up to do if you want to master the skills, but people much older than you have done exactly that, it's all about dedication.
  43. 3 points
    Hi all, I'm an indie app n game developer during my spare times; mainly focused on iOS for the time being ... recently having published a few simple 2d iOS games on the Apple App Store which can be found from my website http://techchee.com , would love to learn from peers how to promote or market mobile games or develop more sophisticated ones 😄
  44. 3 points
    I think this is key. If you're going for telling a good story, the rule is "show don't tell" -- which means in a visual medium like a video game, the explicit bits take place offscreen and you just see the reactions and results. A little bit of titillation never hurts and can set the scene to advance the story, but a graphic depiction of adult acts is just porn and ruins the story (just as any other tell instead of show would). On the other hand, I always add unpixelate patches to The Sims because the not-telling there is overboard. People are all naked under their clothes, adding pixellation just titillates where it's unnecessary to advance the story. Remember the other golden rule: always leave them wanting more. If people achieve the (cognitive) satisfaction of a visceral reward in the middle of a game, why continue with the playthrough? Tease them. Make them want the ending, but hold off on it for as long as you can. Make them say your name.
  45. 3 points
    Normally this is called a layered approach. Minecraft is a great example of just how far you can take this and how you can use it to build a looping progress mechanic. The reason why it's considered layers on not dimensions is because these parts of the games are linked in series. For example in XCOM to advance the campaign you do need to play the battles. A dimension approach would be something where the one play style doesn't effect the other. For example in 2D adding a value to X doesn't advance you on the Y axis. Dimension are independent, but by using both you can get to points where you want to be. Visual novels are more of a Dimension type of games. If you want to unlock some special parts of the stories you need to do something with one character, then something else with a other character; yet you can also just progress the game by just focusing on one character. Most common layers is often only 2-3 and often is combined with a story dimension tree. The only limits to both is physical. How many layers or dimensions can you make in 1-3 years, it's all about how much money and time you can spend planing it all out. If your a immortal with unlimited time you could add unlimited dimensions or layers to a game; or at least to the point where the game fills your computer with data.
  46. 3 points
    You don't feel really comfortable with this programming language. I would like to suggest you taking some lessons before moving on. This will definitely be a win-win.
  47. 3 points
    https://msdn.microsoft.com/en-us/library/br230430.aspx This method differs from ComPtr::GetAddressOf in that this method releases a reference to the interface pointer. Use ComPtr::GetAddressOf when you require the address of the interface pointer but do not want to release that interface.
  48. 3 points
    Same problem, honestly. The issues are whether it's a) recognizable (will you pop up on the original IP owner's radar); and b) likely to cause consumer confusion (if you actually want to fight it when they send you the C&D). If it's highly recognizable you're more likely to get the threat of legal action. The more invisible your product, generally speaking (this is by no means absolute), the less likely you are to face legal action. The more successful your product, the higher the likelihood of legal action if any of your IP touches a big pocket's IP.
  49. 3 points
    I call this "The Betty White Effect". In her later years Betty White did a few roles where she played an evil character. The fact that she seemed so over-the-top happy and nice just made her seem even more evil and she did very well in those roles, which you wouldn't expect her too. The opposite look and feel of what you are going for can sometimes actually enhance the effect, rather than detract from it as you would expect it too.
  50. 3 points
    A few days have passed since I uploaded the game. I did no advertising whatsoever, but the two blog entries I had here. So I've been watching the dashboard closely, to see if somebody actually looked at and installed the game. And a handful (literally) did Joy! I even got a feedback which can all be conveniently inspected in the dashboard. Unfortunately I've also got crash reports. In one case I received a stack trace. I have a hunch what might be the cause (I've called QueryInterface without checking the HRESULT. I should've known better!) Currently I'm on vacation and have only access to a Windows 7 laptop. And unfortunately on this Visual Studio 2015 prefers to crash when I try to create new packages. I'm pretty happy I can actually compile though; and also the manual package creation via command line does work fine. Go figure. Downside, I obviously can't test or debug the compiled game at all. So I have to wait before uploading a fix to the store. In the meantime I got access to a Windows mobile phone (which is actually pretty good IMHO). Just for kicks I deployed the game and it worked perfectly. If you disregard no possible keyboard entry or back button support. Over the last few days I've made a few adjustments to the code so now back button works, and overlay touch controls are also available (for phone only). I have also tried to add tilt support (both via Gyro and OrientationSensor - the first one is not supported by that phone, and the latter seems to be lagging quite a bit). Once I manage to get keyboard support I also have to try to make the game GUI somewhat more phone friendly (a tree control isn't really all that fit for big fingers). Overall I'm pretty satisfied as how well the same app performs as pure Win32, as UWP app on desktop and on phone.
  • Advertisement