Jump to content
  • Advertisement


  • Content Count

  • Joined

  • Last visited

  • Days Won


Shaarigan last won the day on July 11

Shaarigan had the most liked content!

Community Reputation

1125 Excellent


About Shaarigan

  • Rank
    Advanced Member

Personal Information

  • Role
    Artificial Intelligence
  • Interests


  • Github

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. There was a similar kind of question some time ago in the Engines and Middelware Forum so you might read https://www.gamedev.net/forums/topic/699905-writing-a-game-engine-need-beginner-ish-structure-advice/ and take a look what people gave advice for. It is mostly about the project and how to do the architecture arround it. You might have already seen those open source engines Urho3D, Unreal Engine and/or Cry Engine. They come along with a lot and I mean A LOT of tools and config arround their products to keep the code clean and maintainable
  2. @Anri as my limited knowledge to XBO development results, there was a break in Microsoft's politics to open their XBO market for indie games and small sized people a while ago @Pascua2019 The point here is that vendors of those systems have at one side invested a lot of money and time to research for the technology and it's OS, on the other side keeping the cost as low as possible to get a whole market to buy their product. Nintendo has had more innovations in past years while Sony has had better games and (this is a point of personal oppinion) more performance than similar console generations of Nintendo and MS. The performance point is the difference in writing games for PC or Console. Normally a console has a single locked thread to run the OS on and other threads that are reserved for the software a user is actively using. Normally no scheduling happens here while on PC you have hundrets of services running in background and multiple programs a user launched that each need it's time and space to run on a limited core CPU. This is why the OS on a PC schedules tasks certain ammount of execution time. Consoles this way need less hardware power and so keep the price in a range that nearly everyone could buy a console against a PC of 4 or 5 times the price. See Sony's PS VR in opposite to Occulus for example. Another point is that every player wants (if he/she really needs is another question) social environments like in-game firends, messaging and also a store to lazily grab his games from including payment information. This shows a kind of security issue when the COS would be open for anyone, grabbing those information or even the whole money of a person just by putting a game with some spy software onto a user's maschine would be quite easy. That's why vendors provide SDKs and resources to verified developers only and software is encrypted and digitial signed by Sony before it can execute on Playstation or Nintentdo or whatever vendor you like to place here. I've developed some games for PS and also the old NDS devices. A runtime based language like C# or Java would be very slow and insecure on the hardware so the way to go is C++ with access to some STL implementations made by Sony or Nintendo themself and anything else needs to drive the provided SDKs. They include code to access hardware level features like Atomics, grab Input or establish Network Play for your game. And the point why it is that limited to get resources is the verification process. You need to have an established company, buy special versions of the hardware made for especially development (driving less security features so you could for example debugg your code) for multiple thousands of $ and at the end get your product reviewed to the guidelines of Sony or Nintendo before accomblish to sales. This is a process of spending a lot of time and money you need to get back during sale so no one will post ressources outside of the community of verified devs. I believe this is also against the guidelines of Sony and Nintendo and you could get banned from dev-program for that
  3. I can't help with assets (especially those from the asset store) but if I would start such a project, there are a couple of thoughts I have to this topic. Use a quad tree. This is a standard structure used in any game that has a map and/or is open world or at least open world in the meaning of a limited sized map you could walk arround like in Starbound. This will help locating where the player is, where the blocks are he/she could manipulate. Use a two dimensional byte or 16 bit integer array in your quad tree to represent the editable map. This way you could place an ID inside the cells that stands for a specific block asset in your game. I think 65536 -1 blocks should be way enougth for such a game and will just consume round about 35 MB of RAM. -1 because you should not forgett the <empty> block so air. For the back- and potentially foreground I would define texture regions. This way you don't need to manage a second and third array because your background won't be shuttered the same way as your editable middle map is. On the surface you have sky, inside the earth you have an earth background, going deeper you have some lava caverns and whatever so a reagion is enougth here. Append this information together into your quad tree and you are done with the general management of your map. I wouldn't append a collider to each block because this would be overkill for the physics engine. Instead you could just check against your map data and because this is made of a grid, either apply colliders/do collidion detection on demand only in a very small region or remove it completely and handle basics physics by yourself. Doing cell physics isn't that hard in this scenario. Last but not least map generation. What you need to make your game performing well is a good editing vs. static texture management. This is also a reason I suggested the quad tree because you already have your map ordered in cells that could go down to different resolutions. Bake a static texture for each of those cells (where a cell should be at least a couple of blocks wide) and another static texture for each quad of higher ordered cells. This is your LOD (level of detail) you want to swap each time the player moves because of render performance. Sending each block one by one to the graphics renderer will cause an infinity long render loop, baking regions together the player can't actually see or even edit and send those as batch to the render engine will pass a lot faster and you could show a lot larger maps. When a player now walks arround, you need to enable a minimal set of blocks for modify by stop render their LOD and instead render each block by its own. This sounds against what I talked about above but as you just enable a minimal region for edit, you'll end up with lets say 5x5 blocks so a 25 block region or even less you pass to the render pipeline and anything else will still be a huge LOD. For multiplayer you do the same on the other player's side and just send LOD updates to any other player in the party, that would be enougth to handle that
  4. Shaarigan

    WinAPI Raw Input confusion

    Even if Microsoft suggest this, it isn't the practise we really want to do. XInput is driving the same route these days catching on driver level while WM-Messages are quite looped through all the messages a window is receiving from the OS, including repaints and whatever so dont do this! I was fighting with that some time too because I wanted to also grab HID Gamepad inputs from the OS without linking to the Media library. So HID was the only route to not have to worm with XInput. You first need the Windows Driver SDK or define the bindings yourself and just lookup at initialization when needed. These are: #ifndef INITGUID #define INITGUID #endif #ifdef interface #undef interface #endif #include <Windows.h> #include <Dbt.h> typedef struct _HIDD_ATTRIBUTES { ULONG Size; USHORT VendorID; USHORT ProductID; USHORT VersionNumber; } HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES; typedef USHORT USAGE; typedef struct _HIDP_CAPS { USAGE Usage; USAGE UsagePage; USHORT InputReportByteLength; USHORT OutputReportByteLength; USHORT FeatureReportByteLength; USHORT Reserved[17]; USHORT NumberLinkCollectionNodes; USHORT NumberInputButtonCaps; USHORT NumberInputValueCaps; USHORT NumberInputDataIndices; USHORT NumberOutputButtonCaps; USHORT NumberOutputValueCaps; USHORT NumberOutputDataIndices; USHORT NumberFeatureButtonCaps; USHORT NumberFeatureValueCaps; USHORT NumberFeatureDataIndices; } HIDP_CAPS, *PHIDP_CAPS; typedef enum _HIDP_REPORT_TYPE { HidP_Input, HidP_Output, HidP_Feature } HIDP_REPORT_TYPE; typedef struct _USAGE_AND_PAGE { USAGE Usage; USAGE UsagePage; } USAGE_AND_PAGE, *PUSAGE_AND_PAGE; typedef struct _HIDP_BUTTON_CAPS { USAGE UsagePage; UCHAR ReportID; BOOLEAN IsAlias; USHORT BitField; USHORT LinkCollection; // A unique internal index pointer USAGE LinkUsage; USAGE LinkUsagePage; BOOLEAN IsRange; BOOLEAN IsStringRange; BOOLEAN IsDesignatorRange; BOOLEAN IsAbsolute; ULONG Reserved[10]; union { struct { USAGE UsageMin, UsageMax; USHORT StringMin, StringMax; USHORT DesignatorMin, DesignatorMax; USHORT DataIndexMin, DataIndexMax; } Range; struct { USAGE Usage, Reserved1; USHORT StringIndex, Reserved2; USHORT DesignatorIndex, Reserved3; USHORT DataIndex, Reserved4; } NotRange; }; } HIDP_BUTTON_CAPS, *PHIDP_BUTTON_CAPS; typedef struct _HIDP_VALUE_CAPS { USAGE UsagePage; UCHAR ReportID; BOOLEAN IsAlias; USHORT BitField; USHORT LinkCollection; USAGE LinkUsage; USAGE LinkUsagePage; BOOLEAN IsRange; BOOLEAN IsStringRange; BOOLEAN IsDesignatorRange; BOOLEAN IsAbsolute; BOOLEAN HasNull; UCHAR Reserved; USHORT BitSize; USHORT ReportCount; USHORT Reserved2[5]; ULONG UnitsExp; ULONG Units; LONG LogicalMin, LogicalMax; LONG PhysicalMin, PhysicalMax; union { struct { USAGE UsageMin, UsageMax; USHORT StringMin, StringMax; USHORT DesignatorMin, DesignatorMax; USHORT DataIndexMin, DataIndexMax; } Range; struct { USAGE Usage, Reserved1; USHORT StringIndex, Reserved2; USHORT DesignatorIndex, Reserved3; USHORT DataIndex, Reserved4; } NotRange; }; } HIDP_VALUE_CAPS, *PHIDP_VALUE_CAPS; typedef struct _HIDP_DATA { USHORT DataIndex; USHORT Reserved; union { ULONG RawValue; BOOLEAN On; }; } HIDP_DATA, *PHIDP_DATA; typedef void* PHIDP_PREPARSED_DATA; #define HIDP_STATUS_SUCCESS 0x110000 BOOLEAN (__stdcall *HidD_GetAttributes)(HANDLE device, PHIDD_ATTRIBUTES attrib) = 0; BOOLEAN (__stdcall *HidD_GetSerialNumberString)(HANDLE device, PVOID buffer, ULONG buffer_len) = 0; BOOLEAN (__stdcall *HidD_GetManufacturerString)(HANDLE handle, PVOID buffer, ULONG buffer_len) = 0; BOOLEAN (__stdcall *HidD_GetProductString)(HANDLE handle, PVOID buffer, ULONG buffer_len) = 0; BOOLEAN (__stdcall *HidD_SetFeature)(HANDLE handle, PVOID data, ULONG length) = 0; BOOLEAN (__stdcall *HidD_GetFeature)(HANDLE handle, PVOID data, ULONG length) = 0; BOOLEAN (__stdcall *HidD_GetIndexedString)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len) = 0; BOOLEAN (__stdcall *HidD_GetPreparsedData)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data) = 0; BOOLEAN (__stdcall *HidD_FreePreparsedData)(PHIDP_PREPARSED_DATA preparsed_data) = 0; BOOLEAN (__stdcall *HidD_SetNumInputBuffers)(HANDLE handle, ULONG number_buffers) = 0; NTSTATUS (__stdcall *HidP_GetCaps)(PHIDP_PREPARSED_DATA preparsed_data, HIDP_CAPS *caps) = 0; NTSTATUS (__stdcall *HidP_GetValueCaps) (HIDP_REPORT_TYPE ReportType, PHIDP_VALUE_CAPS ValueCaps, PUSHORT ValueCapsLength, PHIDP_PREPARSED_DATA PreparsedData) = 0; NTSTATUS (__stdcall *HidP_GetButtonCaps) (HIDP_REPORT_TYPE ReportType, PHIDP_BUTTON_CAPS ButtonCaps, PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData) = 0; NTSTATUS (__stdcall *HidP_GetData) (HIDP_REPORT_TYPE ReportType, PHIDP_DATA DataList, PULONG DataLength, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength) = 0; ULONG (__stdcall *HidP_MaxDataListLength) (HIDP_REPORT_TYPE ReportType, PHIDP_PREPARSED_DATA PreparsedData) = 0; #include <string> #undef INITGUID #ifdef UNICODE typedef struct _DEV_BROADCAST_HID { DWORD dbcc_size; DWORD dbcc_devicetype; DWORD dbcc_reserved; GUID dbcc_classguid; wchar_t dbcc_name[200]; }DEV_BROADCAST_HID; #else typedef struct _DEV_BROADCAST_HID { DWORD dbcc_size; DWORD dbcc_devicetype; DWORD dbcc_reserved; GUID dbcc_classguid; char dbcc_name[200]; }DEV_BROADCAST_HID; #endif I encapsulated this into conditional defined files to keep the whole thing multiplatform (Windows, Linux, Android). Defining those bindings by myself was neccessary because of the Windows Driver SDK just for working with that I and everyone else in my team needed to download and install this complicated to get piece of memory just to grab some header files. You then need to first enumerate your devices using uint32 count = 0; GetRawInputDeviceList(0, (PUINT)&count, sizeof(RAWINPUTDEVICELIST)); if(count <= 0) return false; Array<RAWINPUTDEVICELIST> devices(count, allocator); if((count = GetRawInputDeviceList((PRAWINPUTDEVICELIST)&devices[0], (PUINT)&count, sizeof(RAWINPUTDEVICELIST))) <= 0) return false; To know the targets for RID_DEVICE_INFO _deviceInfo; _deviceInfo.cbSize = sizeof( RID_DEVICE_INFO ); uint32 val_size = _deviceInfo.cbSize; GetRawInputDeviceInfo(device.handle, RIDI_DEVICEINFO, &_deviceInfo, (PUINT)&val_size)); and RAWINPUTDEVICE rdv = RAWINPUTDEVICE(); rdv.hwndTarget = (HWND)handle; rdv.usUsage = static_cast<USHORT>(target); rdv.usUsagePage = static_cast<USHORT>(extra); rdv.dwFlags = 0; return boolean_cast(RegisterRawInputDevices(&rdv, 1, sizeof(RAWINPUTDEVICE))); To enable your window to get input events for the specified device(s). Before you could handle what arrives in WM_INPUT, you need to find the protocol definition of your device. HID is a general tehcnic that routes information from the device to your program and vice versa so you need to know hot to communicate with your device. This a kind of protocol which defines the meaning of each single byte in your HID-Input-Report. An XBox Gamepad has different alignment than one from Logitech so the protocol bytes handle that properly. int32 val_size = 0; GetRawInputDeviceInfoA((HANDLE)*device, RIDI_DEVICENAME, 0, (PUINT)&val_size ); if(val_size) { string path(device.GetAllocator()); path.Resize(val_size); GetRawInputDeviceInfoA((HANDLE)*device, RIDI_DEVICENAME, path.Begin(), (PUINT)&val_size ); *(path.Begin() + 1) = '\\'; return CreateFileA(path.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); } if(!HidD_GetPreparsedData(ntHandle, (PHIDP_PREPARSED_DATA*)&ind.protocol) && ind.Type == InputDevice::HID) { CloseHandle(ntHandle); continue; } CloseHandle(ntHandle); First captures the size of the device path in driver cache and then grabs that path to open the HID-Protocl file. Those paths usually are in the form of HID\VID_046D&PID_C046\6&78d1573&0&0000 (my USB Mouse for example) You will then obtain the protocol file using the GetPreparsedData call and anything is fine. Last step is getting input from the WM_INPUT message. uint32 val_size = sizeof(RAWINPUT); RAWINPUT report; Drough::memset(&report, 0, sizeof(report)); if(GetRawInputData((HRAWINPUT)data, RID_INPUT, &report, (PUINT)&val_size, sizeof(RAWINPUTHEADER)) < signed_cast(-1)) { switch(report.header.dwType) { ... case HID: { uint16 size = static_cast<uint16>(report.data.hid.dwSizeHid * report.data.hid.dwCount); if(raw.Size() != size) raw.Resize(size); Drough::memcpy(raw.Begin(), report.data.hid.bRawData, size); } } } This fills the fixed size data buffer (it is dynamic array in my case so don't wonder about raw.Resize()) from the msg.lParam part of WM_INPUT message. Finally get the real HID input from the preparsed data and the protocol HIDP_DATA* dta = (HIDP_DATA*)(raw.Begin() + raw.Offset()); ULONG length = (ULONG)raw.Offset() / sizeof(HIDP_DATA); if(HidP_GetData((HIDP_REPORT_TYPE)0, dta, &length, (PHIDP_PREPARSED_DATA)device.Protocol(), (PCHAR)raw.Begin(), (ULONG)raw.Size()) != HIDP_STATUS_SUCCESS || length == 0) return false; And if anything was successfull, you'll end up with an array of HIDP_DATA objects that each contain information about the kind of input like Button/Axis and it's state [On/Off]/Delta. Depending on how often you resize data, you'll end up with input latency of a few ms. Hope this brief overview helps
  5. Shaarigan

    Starting point for game editor

    Writing this stuff in C# and connect it via a bridge assembly to your how-ever written engine might be the best approach in my opinion after working for a couple of years in the industry at the tools side and this will also be cross-platform as long as you don't use any heavy Windows or Linux only features running either .NET or Mono. The good thing about C# is that you can manage anything using interfaces and some hidden auto-binding-assembly generation in .NET 4.0 and upwards so you define your interface, tagg it's methods with coresponding external bindings and let your runtime code generator do anything else. If you are driving the C++ side of engine code, then you might also want some kind of RTTI to make working with your bridge assembly more easy. What I think an editor should have is a simple but also powerfull design while I agree on ATF and want to push other systems like Unreal, Unity or even Godot into race for bad heavy overloaded UI Design. The simplest thing you need for startup is just a window rendering your 3D scene holding a render context from your engine and access to your objectives you want to place in the scene. Anything else will occure when you have need for it
  6. Shaarigan

    Game code architecture

    You misunderstand ECS. In ECS, your Components are known by the system but not vice versa so if you have a centralized storage that keeps your components and entity relations in Core, your renderer can access any component it needs but your Core won't need to know renderer. Why should it?
  7. I started my own route in 2009 when I started at university first in C# using an OpenGL wrapper and later changed to C++. I had a lot of try and throw away prototypes up to my current stable version and also tried the same ammount of project architecture. Having a look at certain features of other engines like Unreal Engine 4, Urho3D, Cry Engine and anything I found on the web is a good approach when you are at a state where you have basic knowledge of what you do and especially why you do something. First and most important point that I think when looking back today is your general project structure. This sounds redundant but as your project grows you will end up with a mess of code and script/ config files quickly if you don't take care about that early. As I wrote in this post, I'm currently on the go to analyse the dependency structure when building and print those diagrams for project analysis in order to keep the project clean. Second thing that pointed out in past years is your building pipeline. There is nothing more annoyng than a bunch of plain script files and/or the need to maintain those or call some magic make/nmake every time you want to setup or compile your code. This is why I started to dissect Unreal's build tool and 'm now on the go to write my own one. I figured out that there are little information you need to setup project files for different Visual Studio, Visual Studio Code and whatever IDE you prefer while most of those informations like platform settings are always the same for the whole project. I'm also now on the road to quit the use of config files for my build completely after reading this article about automated build systems. My build tool currently performs a complete project folder analysis using certain hard coded rules like Every subfolder in my project root is an own project For every project found in root collect all files and decide what kind of project it is Every project in root can contain multiple projects (mixing C# and C++ files result in two project files on the same project) Use code analysis to find relations between projects in the same root So what should I say, it works suprisingly well :D Another clue about my build tool is a Javascript kind of mechanic, mixins. I use the same method Unreal does using .Build.cs files all over my project root and sub folders to control my build tool's behavior. This is what Gigi Sayfan did with his Python scripts. But no, those aren't "just another build file" you need to maintain, those are micro plugins. My program detects all of them and loads them into the runtime to add/extend or override single functions that stay in specially marked classes; just as Javascript mixins work. I also have the chance to provide plugins but they are limited to predefined interfaces to provide build profiles (local build, remote build, cloud build ...), build systems (C#, C++ and whatever or even different platform exports) and I use C# for any of my tools because it pointed out that C# is a good language for rapid tooling and tool prototyping. The last important point in my opinion is modularity. I seperated my engine into several modules each maintaining it's own sub-project. This has the reason that I wanted my design to be flexible to the needs of the game it is used for and one could easily work in parallel on different features. This comes with nearly no overhead in C++ because of static linking. Any module I have is a static library. Another advantage of the modular approach is also the project setup. I have a package manager tool that is able to download features and their dependencies from GitHub for example (and also may include additional .Build.cs files if needed) Now I want to tell you something about how I started and what my modules contain, you may take or don't take this as a suggestion for a roadmap. I first started with my current implementation (after several reworks since 2009) to think about basics. New and delete wasted my early code and also leaded to heavy memory leaks at some of past professional prohjects I participated to so I found and read this blog post about memory management and implemented a similar approach including my own STL like container structures for better control over memory consumption. It pointed out that a lot of classes could just inherit from my Array class (dynamic resizeable continious memory management class that behaves like a plain C array but could dynamically resize to certain element count) like Vector (as I come from the C# world, some more convinience was needed like the C# List<T> equivalent), Queue, Stack, hashTable and Map for example are such classes. I force any function that operates on blocks of memory to have the Allocator& parameter pointing to the default allocator set once at startup. Driving this route I never had hidden memory leaks again in my code because the Allocator instantly complained about unreleased memory. Then I added some file and asset management because this is the most used topic in every modern game and every modern engine. Assets are always present and have to be loaded, cached and cleaned frequently while playing. Anything working with data in my engine uses streams because they provide some features like the position pointer that benefit in my opinion against plain arrays of data. One of those features for example is caching (in case of files) or the position pointer (very usefull on parsing/processing data). Memory Mapped Files also turned out to be a basic technology you won't want to miss inc ase of threaded asset loading. RTTI/ Reflection and dynamic calling was a research topic just for interest but I don't want to renounce nowdays. Driving my own implementation tooks some research but especially in case of serialization and editor to engine code it is very usefull. I also added a huge delegate and dynamic calling feature into my engine that is used for example in the in-game console to parse and call methods in game code. Another Javascript/ Typescript mechanic I used here for my editor interface are dynamic interfaces defining an interface class and convert a matching object to that interface even if it dosent belong to the inheritance chain is quite usefull to bind functionality to editor components and also enables hot reloading. I havent used it that much but you could also write a wrapper struct that behaves like an C# object, assigning any kind of class/ struct and convert it back to whatever it was when needed. Last but not least ECS. It is an overused buzzword these days that is true but it is also usefull and you again don't want to miss it once tasted. The principles of ECS are to provide objects that define their existence of components that could interact with static business code in systems. So far one could say that ECS is the most flexible way to define data that is used in certain way to reach an expected result. Using systems for rendering, UI and gameplay elements is an easy alternative to OOP because you know the data to expect and could write logic once on a centrally place instead of spreading the logic all over classes and class specializations. This also prevents the so called god object to occure. ECS is for example used in the render graph, a feature that decides of those objects to render, performs object parent/ child relation chaining and transformation updates. In Unity or Unreal, a scene contains of a render graph. This are just my thoughts so feel free to take whatever you need
  8. Shaarigan

    Game code architecture

    In general your approach of project architecture is as good as any other approach as long as it works for you and dosen't cause circular dependencies. This would be the case if Renderer needs to now stuff from Core and vice versa so what I do when creating such a project (and my current game engine architecture looks the same) is to think about usages. All modules stay on the same layer of dependencie and If you know code isn't used by any other module on the same layer that's fine, otherwise you should move it one layer back to have anything depending on it in a layer above it. This sounds very complicated but as I rewrote and 'm still rewriting my build tool (I run my own build tool in C# to create and build my C#/C++ projects), I also added some kind of code analysis to have an overview over my code. This produces diagrams like this one So as you can see, the dependency graph shows relationship between classes (this is as C# project so don't worry about circular dependencies between classes) and could also point to external classes from other projects in the same solution. I did this for the exact same reason, to know what modules and especially what code depends on other code to always have an overview of my architecture. Yes you can do this. Take a look for example at the Pokemon TCG App (it is free to play so feel free to do so). When you play a card that isn't cached yet, the App downloads the resource from their server and a progress bar appears on the cards. I think your delay wouldn't be that straight but it is absolutely valid. Most games put their assets into a package so you minimize disk access time (that is the most performance impact when loading assets) and for example use Memory Mapped Files for fast parallel reading access. This is just a tip if you feel your asset loading is too slow ;) You shouldn't use shared_ptr here if you want cache cleanup. The struct implies that it will handle Garbage Collection for you but that isn't true. When loading a texture, you usually load it directly into your graphics card rather than keeping a pointer on your heap and in this case shared_ptr won't help anything because it is a heap structure not a VRAM one. What I do in this case is rolling my own handle that can also take some more actions into account than just simply hold a ressource reference. My RessourceHandle struct for example that keeps a reference to some default texture. This handle is returned immediately from the asset manager while it also starts loading the asset in background. The renderer could just use the asset and behave as normal while the real asset is loaded in background and flipped once the process is ready. If you already use some kind of Components, why not driving the ECS path and just let your renderer work on lists of components instead of passing knowledge about GameObject to it? You could maintain component relations in different concurent arrays of components of the same kind and let your renderer just pick those arrays to do a linear iteration and render pass over them. This would not just save management overhead but also time because you won't need to pick every game object, fetch its contents from memory to just fetch it's mesh, texture and whatever from memory again causing a possible CPU cache replace
  9. Sounds like you are using a project that includes Editor specific code that dosen't play very well with a newer Unity version. This may be because Unity depricated some functions and/or replaced how certain functions work. This is the most occuring cause of issues when migrating from an older Unity version. Unity meanwhile does a little bit of self healing trying to replace old/depricated function calls in the code base to newer API functions if possible but the problem will stay the same. You may have some Assets or Plugins that don't play very well with the newer version
  10. This isn't true at all because accessing through the []-operator is just convinience. What the compiler in the background does (normally) is to move the base pointer by certain ammount of bytes and return the result. Accessing an element in a plain array of integer simply is int* myArray = new int[20]; //int x = myArray[7] -> int x = *(myArray + (sizeof(int) * 7)); delete[] myArray; What I learned during study was that the OS maintains a list of memory chunks when you delete something. Any new allocation request is then passed through the list of returned chunks so if something matching is found, an allocation will return that chunk or at least a new piece of it. This is the reason why memory fragmentation occures more and more the longer a program runs. I used to force run my own memory management and allocator classes whenever possible, also as @Gnollrunner wrote in his first post, use my own STL like container classes. I wrote Array (dynamic resizing), Vector (dynamic add/remove), Stack, Queue, HashTable, Map and whatever I used to need in my code. All of these are based on Array because what you get when allocating memory using the API features of C/C++ is a block of memory of certain size. Malloc isn't interested in the kind of cobject you want to place in there except for its size on the platform. What I do when allocating memory for an array of integers is to calculate the padded size of the type and multiply this with the ammount of elements I want to place inside memory. In C/C++ it is a mighty tool to shift pointers left or right some bytes, this can result in a much better performance. While C/C++ dosen't has any garbage collection (SmartPtr dosen't count because it just deletes it's contents on leaving scope) this is the reason for the ammount of garbage collection libs out in the wild. Games heavy rely on good memory management because they do even more allocation/deallocation than a normal office program does. There are some models how memory management and garbage collection work. One approach is for example to put ranges of memory in buckets of different size so you know when allocating an integer, it will always stay in a heap reagion whos size wont exceed certain limit while an other approach is to return smart pointer objects instead of plain ones so on garbage collection there is a chance to move objects arround in memory without causing data corruption on access
  11. In C#, any character in a string is 2 Byte Int16 so you will always get the correct UTF8 character back from your string and won't have any false positives. In C++/C you have the chance to test the string before processing. UTF8 strings are variable byte so you can test if a character is UTF8 and what character it is if you seek for something else. I wrote a small UTF8 encoding class for my HTML Parser uint32 Utf8::Decode(const char* str, uint32& length) { if(length < 1) return false; uint8 seqlen; uint32 uc; if(((byte)*str & 0x80) == 0) { length = 1; return (*str & 0x7F); } else if(((byte)*str & 0xE0) == 0xC0) { uc = (*str & 0x1F); seqlen = 2; } else if(((byte)*str & 0xF0) == 0xE0) { uc = (*str & 0x0F); seqlen = 3; } else if(((byte)*str & 0xF8) == 0xF0) { uc = (*str & 0x07); seqlen = 4; } else return false; if(seqlen > length) return false; for(uint8 i = 1; i < seqlen; i++) { if((str[i] & 0xC0) != 0x80) return false; } switch(seqlen) { case 2: { if(!IsInRange(*str, 0xC2, 0xDF)) return signed_cast(-1); } break; case 3: { switch ((byte)*str) { case 0xE0: { if(!IsInRange(str[1], 0xA0, 0xBF)) return signed_cast(-1); } break; case 0xED: { if(!IsInRange(str[1], 0x80, 0x9F)) return signed_cast(-1); } break; default: { if(!IsInRange(*str, 0xE1, 0xEC) && !IsInRange(*str, 0xEE, 0xEF)) return signed_cast(-1); } break; } } break; case 4: { switch ((byte)*str) { case 0xF0: { if(!IsInRange(str[1], 0x90, 0xBF)) return signed_cast(-1); } break; case 0xF4: { if(!IsInRange(str[1], 0x80, 0x8F)) return signed_cast(-1); } break; default: { if(!IsInRange(*str, 0xF1, 0xF3)) return signed_cast(-1); } break; } } break; } for(uint8 i = 1; i < seqlen; i++) uc = ((uc << 6) | (str[i] & 0x3F)); length = seqlen; return uc; } I designed this code for performance while it isn't as fast as plain ASCII read a character and forgett about anything else, it is possible for my HTML parser to work with over 35.000 characters in not even 2 seconds avarage so the impact should be minimal
  12. You seem to struggle on basics so you should first learn how to structure your projects correctly and how to link libraries to your project. .lib files are static linked libraries, you reference them as usally but they are placed directly into your program rather than stay aside .dll files stay aside of your program and are solved at runtime Take a look at the docs on how to load dependencies if you have problems solving this. For my solution option you need to compile your code as native dll and put it aside to a short C# wrapper that will handle anything for startup. You need to expose some function that initializes your code similar to the main function and then write a short C# program that calls this function. Here is also a short how-to showing how you use p/invoke to drive that route. You can then simply start ana dditional thread or whatever to run your "scripted" game code and call into your C++ app
  13. You should normally start from a specific scene or have a scene just with your manager objects that you load in addition to whatever scene your start from, both works and the managing scene gives ya a place for all your objects so it would be easier to find for changes. Don't forgett to trigger Object.DontDestroyOnLoad function so that your manager objects live forever
  14. If it has to be Visual Studio supported language, you could also try to wrapp your Cpp into a library and use C# to bootstrap your Cpp to have C# communicate with it
  • Advertisement

Important Information

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

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

Sign me up!