Jump to content

Josh

Staff
  • Posts

    23,143
  • Joined

  • Last visited

Everything posted by Josh

  1. I've made some additions: Instead of Component_::GetEntity() there is now a raw pointer for the entity. It's can't be a shared pointer or it would create a circular reference and prevent the entity from ever being deleted. I think this will be okay, I was doing the same thing in the preprocessor component system. Entity::components is now accessible (read-only vector containing all attached components). Component_::Collide method will now get called by the engine. Added Component_::Copy(). This will get called when an entity is instantiated or copied, so you can duplicate objects in memory and retain all properties. This will also allow duplication of complex C++ data that can't be stored in a JSON file: virtual shared_ptr<Component_> Copy() { auto component = std::make_shared<Mover>(*this);// copies all members // // Make any adjustments here // return component; } My current outlook is that processing data for each component isn't that hard, and with C# and Lua that process can probably be automated using reflection. What is hard is editing and storing the component data in a standard way, so that is what the engine should focus on. Filling in a Component::Save method so your class members get saved into a JSON file isn't too terribly difficult, and the overly complicated alternative I came up with is probably worse. Maybe something like this can be utilized in the future. Here is a working example that copies an entity with a component: #include "UltraEngine.h" using namespace UltraEngine; class Mover : public Component_ { public: Vec3 movement; Vec3 rotation; bool globalcoords = false; virtual void Update() { if (globalcoords) { this->entity->Translate(movement / 60.0f, true); } else { this->entity->Move(movement / 60.0f); } this->entity->Turn(rotation / 60.0f, globalcoords); } virtual shared_ptr<Component_> Copy() { return std::make_shared<Mover>(*this); } }; int main(int argc, const char* argv[]) { //Get the displays auto displays = GetDisplays(); //Create a window auto window = CreateWindow("Ultra Engine", 0, 0, 1280, 720, displays[0], WINDOW_CENTER | WINDOW_TITLEBAR); //Create a world auto world = CreateWorld(); world->SetAmbientLight(0); //Create a framebuffer auto framebuffer = CreateFramebuffer(window); //Load FreeImage plugin auto plg = LoadPlugin("Plugins/FITextureLoader"); //Load model //Cyber Samurai by Khoa Minh: https://sketchfab.com/3d-models/cyber-samurai-26ccafaddb2745ceb56ae5cfc65bfed5 auto model = LoadModel(world, "https://github.com/UltraEngine/Documentation/raw/master/Assets/Models/Characters/cyber_samurai.glb"); model->Turn(0, 180, 0, true); model->SetPosition(1, 0, 0); //=================================================================== // Add a component to the entity //=================================================================== auto mover = model->AddComponent<Mover>(); mover->rotation.z = 10; //=================================================================== // Copy an entity with components (very cool) //=================================================================== auto model2 = model->Instantiate(world); model2->SetPosition(-1, 0 , 0); //Environment maps auto specmap = LoadTexture("https://github.com/UltraEngine/Assets/raw/main/Materials/Environment/footprint_court/specular.dds"); auto diffmap = LoadTexture("https://github.com/UltraEngine/Assets/raw/main/Materials/Environment/footprint_court/diffuse.dds"); world->SetEnvironmentMap(diffmap, ENVIRONMENTMAP_BACKGROUND); world->SetEnvironmentMap(specmap, ENVIRONMENTMAP_SPECULAR); world->SetEnvironmentMap(diffmap, ENVIRONMENTMAP_DIFFUSE); //Create a camera auto camera = CreateCamera(world); camera->SetClearColor(0.125); camera->SetPosition(0, 0.9, -2); camera->SetFov(70); camera->AddPostEffect(LoadPostEffect("Shaders/PostEffects/FXAA.json")); //Create light auto light = CreateBoxLight(world); light->SetRange(-10, 10); light->SetArea(15, 15); light->SetRotation(45, 35, 0); light->SetColor(1.2); //Main loop while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false) { world->Update(); world->Render(framebuffer); } return 0; }
  2. In fact, I think the game configuration can include a setting for "Entity Component System" or "Object-Oriented". The actual difference in the editor would just be selecting one class vs. adding multiple components, but it's a different way of thinking. Here's an example of the new proposed approach that will work right now in 1.0.2. I named the base component class Component_ to avoid interfering with the existing system. The only methods that will get called right now are Start() and Update(). #include "UltraEngine.h" using namespace UltraEngine; class CameraControls_ : public Component_ { public: bool freelookstarted = false; float mousesmoothing = 0.0f; float mouselookspeed = 1.0f; float movespeed = 4.0f; Vec3 freelookmousepos; Vec3 freelookrotation; Vec2 lookchange; virtual void Update() { auto entity = GetEntity(); auto window = ActiveWindow(); if (window == NULL) return; if (!freelookstarted) { freelookstarted = true; freelookrotation = entity->GetRotation(true); freelookmousepos = window->GetMouseAxis(); } auto newmousepos = window->GetMouseAxis(); lookchange.x = lookchange.x * mousesmoothing + (newmousepos.y - freelookmousepos.y) * 100.0f * mouselookspeed * (1.0f - mousesmoothing); lookchange.y = lookchange.y * mousesmoothing + (newmousepos.x - freelookmousepos.x) * 100.0f * mouselookspeed * (1.0f - mousesmoothing); if (Abs(lookchange.x) < 0.001f) lookchange.x = 0.0f; if (Abs(lookchange.y) < 0.001f) lookchange.y = 0.0f; if (lookchange.x != 0.0f or lookchange.y != 0.0f) { freelookrotation.x += lookchange.x; freelookrotation.y += lookchange.y; entity->SetRotation(freelookrotation, true); } freelookmousepos = newmousepos; float speed = movespeed / 60.0f; if (window->KeyDown(KEY_SHIFT)) { speed *= 10.0f; } else if (window->KeyDown(KEY_CONTROL)) { speed *= 0.25f; } if (window->KeyDown(KEY_E)) entity->Translate(0, speed, 0); if (window->KeyDown(KEY_Q)) entity->Translate(0, -speed, 0); if (window->KeyDown(KEY_D)) entity->Move(speed, 0, 0); if (window->KeyDown(KEY_A)) entity->Move(-speed, 0, 0); if (window->KeyDown(KEY_W)) entity->Move(0, 0, speed); if (window->KeyDown(KEY_S)) entity->Move(0, 0, -speed); } }; int main(int argc, const char* argv[]) { //Get the displays auto displays = GetDisplays(); //Create a window auto window = CreateWindow("Ultra Engine", 0, 0, 1280, 720, displays[0], WINDOW_CENTER | WINDOW_TITLEBAR); //Create a world auto world = CreateWorld(); world->SetAmbientLight(0); //Create a framebuffer auto framebuffer = CreateFramebuffer(window); //Load FreeImage plugin auto plg = LoadPlugin("Plugins/FITextureLoader"); //Load model //Cyber Samurai by Khoa Minh: https://sketchfab.com/3d-models/cyber-samurai-26ccafaddb2745ceb56ae5cfc65bfed5 auto model = LoadModel(world, "https://github.com/UltraEngine/Documentation/raw/master/Assets/Models/Characters/cyber_samurai.glb"); model->Turn(0, 180, 0, true); //Environment maps auto specmap = LoadTexture("https://github.com/UltraEngine/Assets/raw/main/Materials/Environment/footprint_court/specular.dds"); auto diffmap = LoadTexture("https://github.com/UltraEngine/Assets/raw/main/Materials/Environment/footprint_court/diffuse.dds"); world->SetEnvironmentMap(diffmap, ENVIRONMENTMAP_BACKGROUND); world->SetEnvironmentMap(specmap, ENVIRONMENTMAP_SPECULAR); world->SetEnvironmentMap(diffmap, ENVIRONMENTMAP_DIFFUSE); //Create a camera auto camera = CreateCamera(world); camera->SetClearColor(0.125); camera->SetPosition(0, 1.4, -1); camera->SetFov(70); camera->AddPostEffect(LoadPostEffect("Shaders/PostEffects/FXAA.json")); //Camera controls camera->AddComponent<CameraControls_>(); //auto actor = CreateActor(camera); //actor->AddComponent<CameraControls>(); //Create light auto light = CreateBoxLight(world); light->SetRange(-10, 10); light->SetArea(15, 15); light->SetRotation(45, 35, 0); light->SetColor(1.2); //Main loop while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false) { world->Update(); world->Render(framebuffer); } return 0; }
  3. It wasn't my preference but it was absolutely necessary for the type of "method collection" the current system does. The Actor has methods defined by the components that are attached to it. Calling the Actor method calls the same method on each component that has it. Since these methods don't get defined until your game is compiled, it's not possible to attach them directly to the entity class in the engine. I don't really like component systems anyways, so I'm fine just doing it the way people expect it to work coming from unity. I'm happy with a single object attached to each entity with an OOP hierarchy, which is also doable with this.
  4. For entity properties, I plan to use JSON files that define the properties that appear in the editor, rather than parsing the script or code files. This will provide more control and less confusing about how properties can be described, and it can be standard for Lua / C++ / C# and even no-code (third-party games). Something like this: { "componentTemplate": { "name": "player", "label": "Player", "language": "c++", "properties": [ { "name": "health", "label": "Health", "type": "INTEGER", "minimum": 1, "maximum": 100, "default": 75 }, { "name": "target", "label": "Target", "type": "ENTITY", "default": null } ] } } These configuration files can either be stored in the game folder, or in a folder of config settings that get loaded based on a command line switch. For example, a configuration for the game Quake can be stored and loaded with a lunch parameter: Editor.exe +game Quake We will have a standard way of defining available properties and getting data into Ultra Engine, for use with any supported language. We also now have a way of exposing C++ classes to Lua with official documentation, and I have worked out all the gotchas of the binding code and documented the information. It's not super easy to set up, but it's also not super hard, and the results it provides are very very good. This has led me to think about the current design of C++ components. Here are the things I like: Standardizing load, save, copy, and updating is very good. The syntax shared_ptr<T> AddComponent<T>() is very good. Making C++ components header-only, while not required, provides a very convenient way to include bits of functionality. Here are the things I don't like: C++ components work slightly differently from Lua scripts attached to entities, and it will also be different from the C# implementation. The Actor / Entity dichotomy is strange but necessary for the design to work. Parsing header files is never going to be perfect. The behavior of C++ components is interesting but extremely nonstandard. The preprocessor works reliably, but it is a piece of technical debt that will undoubtedly require additional work in the future. I'm thinking it may be best to dial things back a bit, keep the good aspects of this, but try to make something that syncs up better with how people will expect their games to work. The way both Lua and C++ in Ultra call a function on each component when you make a single function call is very clever and innovative, but I am not sure the benefit is great enough to justify breaking peoples' expectations and introducing ambiguity. Here is what I am picturing: C++ components are attached directly to an entity with an Entity::AddComponent<T>() method. No "Actor" class. Methods can only be explicitly called on the component you want to call it on. Load and save methods are manually filled in for each component. The engine will call the methods, but the end user needs to fill in the values. Start(), Update(), Collision(), Load(), and Save() still get called by the engine at the appropriate times, for each component. C++, C#, and Lua components all work the same way. C++ example: #include "Components/HealthManager.hpp" auto component = entity->AddComponent<HealthManager>(); component->health = 75; Lua example: local component = entity:AddComponent("Scripts/Components/HealthManager.lua") component.health = 75 C# example (???): #include "Components/HealthManager.cs" var component = entity.AddComponent<HealthManager>(); component.health = 75; What do you think?
  5. 1.0.2 Updated C++ library with all recent changes. Documentation for exposing C++ classes to Lua is complete. It's a lot to take in, but it covers all the nuances and is very powerful. Use Core::LuaState() instead of the GetLuaState() function in the docs, for now.
  6. 1.0.2 Editor now using Lua with UTF-8 strings File thumbnails are disabled until I rework these No environment maps will be set temporarily and PBR materials will appear darker than normal (file opening bug, there is an error in the DDS loader and I don't know why, probably some low-level file read change...) It looks like the DDS load error is happening with every single DDS file...stay tuned... Fixed! (An integer overload of Max() was returning a double causing the calculated mipmap size to be wrong.) You can see the unicode working if you copy and paste this text into the console and press return to run it: Notify("Message: Unicode❤♻Test", "Title: Unicode❤♻Test")
  7. 1.0.2 Baseline Lua example now works ZenMode module now using light user data for HWND pointer
  8. I think the only way to get that done is to go through all the documentation and write examples for every command. All the information about how Lua works is very explicit in Ultra: https://www.ultraengine.com/learn/Scripting
  9. This Lua code will work right now in the current build of 1.0.2: --Get the displays local displays = GetDisplays() --Create a window local window = CreateWindow("Ultra Engine", 0, 0, 1280, 720, displays[1], WINDOW_CENTER | WINDOW_TITLEBAR) --Create a framebuffer local framebuffer = CreateFramebuffer(window) --Create a world local world = CreateWorld() --Create a camera local camera = CreateCamera(world, 2) camera:SetClearColor(0,0,1,1) camera:SetPosition(0,0,-2) --Create a model local box = CreateBox(world) --Create a light --local light = CreateBoxLight(world) --light:SetRotation(45,35,0) while window:KeyDown(KEY_ESCAPE) == false and window:Closed() == false do --Rotate the model box:Turn(0,0.1,0) --Update the world world:Update() --Render the world to the framebuffer world:Render(framebuffer) end And this shows how the C++ side is set up: https://github.com/UltraEngine/Documentation/blob/master/CPP/PollDebugger.md
  10. 1.0.2 All recent changes are now available in the C++ library Updated C++ library to Lua 5.4.4 Added some system Lua files in the game template Added PollDebugger() function Added .vscode folder in game template for development with VSCode @CanardiaPrint() now takes an optional bool for the line return. This function does not attempt to be thread-safe in any way!
  11. This shows how Lua scripting in the editor works:
  12. 1.0.2 Updated editor to Lua 5.4.4 and everything seems to work fine. This adds a utf8 library, bitwise operations, constants, integers, to-be-closed variables, and goto. See here for details, previous version was Lua 5.1: https://www.lua.org/versions.html#5.4 A copy of Lua is available here for building modules.
  13. 1.0.2 Did a lot of work on editor Lua debugging and it works really well now. I recommend doing an uninstall / reinstall of version 1.0.2 to clear out the scripts.
  14. This was a bug in the way the window position was saved. I fixed this in the latest build.
  15. Update 1.0.2 In-editor Lua debugging now works with Visual Studio Code: Run VSCode Select the File > Open Folder menu item Open your Ultra Engine install directory (C:/Program Files/Ultra Engine) When prompted, install the Lua debugger extension. (Devcat Lua Debugger) Select the Debug option in the left-side panel and press the run button. Or just select the "Scripting > Open Editor Folder in Visual Studio Code" menu item. You can set breakpoints and examine variables when they are hit and step through the code. Set a breakpoint in one of the Lua files in "Scripts/Start/Extensions".
  16. Updated 1.0.2 Editor Added EVENT_ERROR which gets triggered in a RuntimeEvent. EmitEvent now returns a boolean. See docs for explanation. Fixed bug in WAV loader Modules (Lua DLLs) now stored in Scripts/Modules Added some critical system scripts in Scripts/Start/System Editor will now remember window position I recommend uninstalling and reinstalling version 1.0.2. Not the whole client, just the install process in the client. It only takes a minute and it will get rid of some scripts that I moved. This prepares for Lua debugging of the editor from VSCode. I haven't run the Lua debugger in a long time but I think it will all work to allow debugging of editor extensions.
  17. This will give you a better idea of how editor scripting works: https://www.ultraengine.com/learn/EditorEvents?lang=lua The editor emits a lot of extra events to trigger actions. You can intercept these events and override them or add your own functionality. For example, you could intercept the EVENT_OPENASSET event and make a script file open in a new script editor interface.
  18. Did you try deleting Documents / Ultra Engine / Settings.json?
  19. Is this win 10 or 11?
  20. Updated 1.0.2 Lua listeners will now be executed in such a way that errors will be shown Added PreviewSound.lua extension, which plays a WAV file when the popup preview window is displayed
  21. Example: https://www.ultraengine.com/learn/LoadMaterial?lang=lua
  22. This works: RewriteCond %{QUERY_STRING} ^lang=lua$ RewriteRule "^learn/(.+)$" "learn.php?page=$1&lang=lua" RewriteCond %{QUERY_STRING} ^lang=cs RewriteRule "^learn/(.+)$" "learn.php?page=$1&lang=cs" RewriteCond %{QUERY_STRING} ^lang=cpp RewriteRule "^learn/(.+)$" "learn.php?page=$1&lang=cpp" RewriteRule "^learn/(.+)$" "learn.php?page=$1"
  23. I am using this .ntaccess rewrite rule to prettify the documentation URLs: RewriteRule "^learn/(.+)$" "learn.php?page=$1" This makes it so the URL "https://www.ultraengine.com/learn/Entity" gets treated as "https://www.ultraengine.com/learn?page=Entity". However, if I have trailing arguments like "?lang=lua" they get omitted from the redirected URL. How can I add those into the rewrite rule? I want to use a URL like this: https://www.ultraengine.com/learn/Entity?lang=lua
×
×
  • Create New...