Jump to content

reepblue

Developers
  • Posts

    2,500
  • Joined

  • Last visited

Posts posted by reepblue

  1. On 9/21/2023 at 5:25 PM, Josh said:

    While this example works, it's not working in the way needed for game saves. The reload function throws an exception when trying to read a file and you get a bufferstream overflow with the example below. Also, since Reload doesn't create anything, would I need to load the map file before the save file? If so, what's the best way to know way to know what save file goes to which map?

    #include "UltraEngine.h"
    
    using namespace UltraEngine;
    
    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();
    
        //Create a framebuffer
        auto framebuffer = CreateFramebuffer(window);
    
        //Create a scene
        auto scene = LoadMap(world, "Maps/savetest.ultra");
    
        //Save the starting scene to memory
        shared_ptr<BufferStream> stream = NULL;
        shared_ptr<BufferStream> binstream = NULL;
    
        //Main loop
        while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false)
        {
            if (window->KeyHit(KEY_F5))
            {
                Print("SAVE");
                if (stream) stream = NULL;
                if (binstream) binstream = NULL;
                stream = CreateBufferStream();
                binstream = CreateBufferStream();
                scene->Save(stream, binstream);
            }
    
            //Reload the starting scene when space key is pressed
            if (window->KeyHit(KEY_F6))
            {
                if (stream and binstream)
                {
                    stream->Seek(0);
                    binstream->Seek(0);
                    scene->Reload(stream, binstream);
                }
            }
    
            world->Update();
            world->Render(framebuffer);
        }
        return 0;
    }

     

  2. How would I use World::GetFrameCaptures() to have my app take a screenshot of the game? I know Steam can do this, but I'd like the application to be able to do this alone. 

        void Program::TakeScreenshot()
        {
            if (mainapp != NULL)
            {
                auto f = stage->gameworld->GetFrameCaptures();
                //auto game = mainapp->As<GraphicsWindow>();
                //if (game) game->framebuffer->Capture();
            }
        }

     

  3. Noticed the following:

    • Entity's Static checkbox doesn't get saved,
    • Spinner widget for the the entity's mass cannot return back to 0 if ever given mass.
    • Collision Type dropdown can't revert back to "None" when changed.
    • Friction Spinners swap x and y values. upon deselection and reselection. 
    • Spinner widget for the entity's Elasticity value just doesn't get to be saved.

    I tested this by making a brush and then edit each widget, changed one setting, unselected it, then reselected it to see if the value was the same. I didn't test all component type widgets since I only have the default two at the moment. 

    Also, the window title leaves a * at the end of the map name,

    • Thanks 1
  4. Ok, so can just for loop all the entities within the world, and then add it to the scene? I'll give it a try and play around with it. My goal is to have Half Life 2 like save/load states almost transparent to the end user.

    Might want to do this for every save call since things like bullets or instanced objects can spawn at any time.

  5. The properties panel is very broken in the latest build. Changes don't get applied or saved anymore. I tried adding another component to an entity in a map and although the panel says it's there, reloading the map and rechecking it shows that the changes were not saved.

    Also manually changing properties such as the entity's position in the panel doesn't apply the changes. 

    The editor is kind of unusable outside of making brushes at this point. :(

  6. Note: Scene::Save() works fine but doesn't copy over component data. 

    The current map doesn't load any components in this test, but it should be worth testing.

    #include "UltraEngine.h"
    using namespace UltraEngine;
    
    void main(const char* args, const int argc)
    {
        //Get the displays
        auto displays = GetDisplays();
    
        //Create a window
        auto window = CreateWindow("Ultra Engine", 0, 0, 1280, 720, displays[0], WINDOW_TITLEBAR | WINDOW_CENTER);
    
        //Create a framebuffer
        auto framebuffer = CreateFramebuffer(window);
    
        //Create a world
        auto world = CreateWorld();
    
        //Load a scene
        auto scene = LoadMap(world, "Maps/savetest.ultra");
    
        //Main loop
        while (!window->Closed() and !window->KeyHit(KEY_ESCAPE))
        {
            // Save 
            if (window->KeyHit(KEY_F5))
            {
                world->Save("save.ultra", SAVE_DEFAULT);
            }
    
            //Load
            if (window->KeyHit(KEY_F6))
            {
                scene = NULL;
                scene = LoadMap(world, "save.ultra");
            }
    
            //Update world
            world->Update();
    
            //Render world
            world->Render(framebuffer, true);
        }
    }

     

    savetest.zip

  7. This example no longer works. The EVENT_FRAMECAPTURE doesn't seem like it gets emitted anymore. 

    #include "UltraEngine.h"
    
    using namespace UltraEngine;
    
    void main(const char* args, const int argc)
    {
        //Get the displays
        auto displays = GetDisplays();
    
        //Create a window
        auto window = CreateWindow("Ultra Engine", 0, 0, 1280, 720, displays[0], WINDOW_TITLEBAR | WINDOW_CENTER);
    
        //Create a framebuffer
        auto framebuffer = CreateFramebuffer(window);
    
        //Create a world
        auto world = CreateWorld();
    
        //Create a camera
        auto camera = CreateCamera(world);
        camera->SetClearColor(0.125f);
        camera->SetPosition(0, 0, -2);
    
        //Create a light
        auto light = CreateBoxLight(world);
        light->SetRotation(45, 35, 0);
        light->SetRange(-10, 10);
        light->SetColor(2);
    
        //Create a model
        auto box = CreateBox(world);
        box->SetColor(0, 0, 1);
    
        //Load the FreeImage plugin
        auto plugin = LoadPlugin("Plugins/FITextureLoader");
    
        //Main loop
        while (!window->Closed() and !window->KeyHit(KEY_ESCAPE))
        {
            //Rotate the model
            box->Turn(0, 1, 0);
    
            //Press the space key to queue a screenshot
            if (window->KeyHit(KEY_SPACE)) 
                framebuffer->Capture();
    
            //Look for captured frames
            while (PeekEvent())
            {
                const auto e = WaitEvent();
                if (e.id == EVENT_FRAMECAPTURE)
                {
                    //Get the pixmap containing the captured frame, save and open it
                    auto pixmap = e.extra->As<Pixmap>();
                    WString path = GetPath(PATH_DESKTOP) + "/screenshot" + String(e.data + 1) + ".jpg";
                    pixmap->Save(path);
                    RunFile(path);
                }
            }
    
            //Update world
            world->Update();
    
            //Render world
            world->Render(framebuffer, true);
        }
    }

     

  8. Back in July, I talked about the idea of building a compartmentalized base application for Ultra Engine. I now want to share what I've been working on and my future plans going forward. 

    This foundation in which I'm dubbing "The Ultra Game Template" is base code and assets to help developers start their next project right. The goal was to have a base layer that did all the "not so fun" but critical elements when building a game such as scene management, input handling, window resizing, etc. 

    The scene/map space is left alone and attaching components works the same if you started your project from scratch and a lot of the back-end stuff can be customized via the config.json file. Here's a list of some of the features.

    Splash Screen

    image.png.dad67b237b3b9fe600d0567c1fb286df.png

    A splash screen is sometimes required for displaying legal notices and is useful for showing the end user that the application is loading in the background. The splash screen can be customized via the config file or disabled entirely. It should also look very familiar. :^) 

     

    Built-In Settings

    All engine settings are exposed file the built-in settings window. You no longer need to tell testers to edit any config files ever again! They can now freely change their target display, resolution, graphic settings, and key bindings! 

    image.png.51ff70aa4e5094585ddb6e52b15170ab.png

     

    Dynamic, Configurable and Easy-To-Use Input System.

    Coming from the input system from Cyclone, the template has support for key bindings. This is modeled after Steam Input where everything is defined as an action and can be contained in action sets. You can bind the same key to different actions in separated sets.  

    Defining a base scheme is simple as making a function in the main.cpp file and passing the game controller pointer through it.

    // Define default controls.
    static void InstallControls(shared_ptr<GameController> controller)
    {
        if (controller == NULL) return;
    
        // Program actions
        controller->SetAction("Pause", BUTTON_KEY_ESCAPE);
        controller->SetAction("Terminate", BUTTON_KEY_END);
        controller->SetAction("ConsoleApp", BUTTON_KEY_F1);
        controller->SetAction("Fullscreen", BUTTON_KEY_F11);
        controller->SetAction("Screenshot", BUTTON_KEY_F2);
        controller->SetAction("Quick Save", BUTTON_KEY_F5);
        controller->SetAction("Quick Load", BUTTON_KEY_F6);
    
        // Camera
        ButtonAxis moveaxis =
        {
            BUTTON_KEY_W,
            BUTTON_KEY_S,
            BUTTON_KEY_A,
            BUTTON_KEY_D
        };
        controller->SetAction("Movement", moveaxis, "InGameControls");
        controller->SetAction("Sprint", BUTTON_KEY_SHIFT, "InGameControls");
        controller->SetAction("Crouch", BUTTON_KEY_CONTROL, "InGameControls");
        controller->SetAction("Climb", BUTTON_KEY_Q, "InGameControls");
        controller->SetAction("Desent", BUTTON_KEY_E, "InGameControls");
        controller->SetAction("Camera", AXIS_MOUSE, "InGameControls");
    
        // Settings
        controller->SetSetting("Raw Mouse", false);
        controller->SetSetting("Inverse Mouse", false);
        controller->SetSetting("Mouse Smoothing", 0.0f);
        controller->SetSetting("Mouse Look Speed", 1.0f);
    }

    Then in the settings application will build the binding list for you separating the sets and settings into their own tabs. 

    image.png.c62ad1c0249d31400a061bd72ed59079.png

    All of this is built using the engine's API so it's cross platform compatible! 

     

    Event Based Console

    A developer console is something you can't live without when developing a game. When called (Default F1), a console window will pop up and will await your input. The commands are event based and there's no registering of commands required. 

    Just put something like this in your component's ProcessEvent function.

            if (e.id == EVENT_CONSOLEEXECUTE)
            {
                auto line = e.text.Split(" ");
                auto cmd = line[0].ToString();
                if (line.size() > 1 && !line[1].empty())
                {
                    if (cmd == "mycommand")
                    {
                        Print("Applied command " + QuoteString(cmd) + " to: " + line[1]);
                    }
                }
            }

    Existing commands are:

    • map - loading maps (Example: map box)
    • restart - Restart the existing map.
    • clear - Clears the current map. 
    • quit - Terminates the application.

     

    You can download it here

     

    • Like 7
  9. @Josh

    This is why:

    		shared_ptr<T> AddComponent(const bool start = true)
    		{
    			auto o = GetComponent<T>();
    			if (o) return o;
    			o = std::make_shared<T>();
    			std::shared_ptr<Component> c = std::dynamic_pointer_cast<Component>(o);
    			if (c == NULL) RuntimeError("Type must be a Component.");
    			//c->entity = As<Entity>().get();
    			if (start) c->Start();
    			m_components.push_back(c);
    			//c->entity = this;
    			c->entityptr = As<Entity>();
    			auto world = GetWorld();
    			if (world)
    			{
    				world->entitieswithnewcomponents.insert(As<Entity>());
    				InternalRecordCollisions(true);
    			}
    			return o;
    		}

    Assign the entity pointer before calling start! Actually make the start function call the LAST thing it does before returning!

  10. 6 minutes ago, Josh said:

    How is the component being added?

    By code.

    	Stage::Stage()
    	{
    		// Menu world and camera.
    		auto sz = GetProgram()->GetFramebufferSize();
    		menuworld = CreateWorld();
    
    		menucamera = CreateCamera(menuworld, PROJECTION_ORTHOGRAPHIC);
    		menucamera->SetPosition(float(sz.x) * 0.5f, float(sz.y) * 0.5f);
    		menucamera->AddComponent<LoadingScreen>();
    		menucamera->SetHidden(false);
    
    		// Create the game world.
    		gameworld = CreateWorld();
    		gameworld->SetLightQuality(GetProgram()->GetSetting(SETTING_LIGHTQUALITY, 1));
    
    		// Scene
    		gamescene = NULL;
    		pausestate = false;
    
    		// Set the menu world as the active world.
    		activeworld = menuworld;
    	}

    If you call a function after it that uses GetEntity(), it'll be fine.

    A lot of engine changes broke things on my end. My camera component loaded by the map file works fine with this,

    	virtual void Start()
    	{
    		// Enable sound.
    		GetEntity()->Listen();
    
    		Listen(EVENT_PAUSESTATE, GetProgram());
    		Listen(EVENT_GRAPHICSWINDOW, GetProgram());
    		GetInput()->CenterCursor();
    		GetInput()->SetCursorHidden(true);
    
    		GetInput()->SetActiveSet("InGameControls");
    	}

     

  11. I'm trying to fix a bug in my application where if the mouse cursor switching works after the window is rebuilt. What I need to do is reset the cursor to default before I destroy the window and then reapply the old cursor after the window is rebuilt. I need a Window::GetCursor() function to do this and none exists. 

    	bool GraphicsWindow::Initialize(const WString& title, const int width, const int height, shared_ptr<Display> display, const GraphicWindowStyles style)
    	{
    		// Release existing pointers so we can rebuild!
    		static bool firstwindow = true;
    
    		// Set the cursor to default before we delete the window.
    		MouseCursor current_cursor = CURSOR_DEFAULT;
    		if (window)
    		{
    			// I need this function.
    			current_cursor = window->GetCursor();
    			window->SetCursor(CURSOR_DEFAULT);
    		}
    
    		window = NULL;
    		framebuffer = NULL;
    
    		int w = width;
    		int h = height;
    
    		WindowStyles window_style = WINDOW_TITLEBAR | WINDOW_CENTER | WINDOW_HIDDEN;
    		switch (style)
    		{
    		case GRAPHICSWINDOW_TITLEBAR:
    			window_style = WINDOW_TITLEBAR | WINDOW_CENTER | WINDOW_HIDDEN;
    			break;
    
    		case GRAPHICSWINDOW_BORDERLESS:
    			window_style = WINDOW_CENTER | WINDOW_HIDDEN;
    			break;
    
    		case GRAPHICSWINDOW_FULLSCREEN:
    			window_style = WINDOW_FULLSCREEN | WINDOW_CENTER | WINDOW_HIDDEN;
    			break;
    
    		case GRAPHICSWINDOW_FULLSCREENNATIVE:
    			w = display->size.x;
    			h = display->size.y;
    			window_style = WINDOW_FULLSCREEN | WINDOW_CENTER | WINDOW_HIDDEN;
    			break;
    
    		default:
    			break;
    		}
    
    		windowtitle = title;
    		window = CreateWindow(windowtitle, 0, 0, w, h, display, window_style);
    		SetWindowTitlebarTheme(window, TITLEBAR_DARK);
    		framebuffer = CreateFramebuffer(window);
    
    		if (firstwindow)
    		{
    			splashscreen = std::make_shared<SplashScreen>();
    			splashscreen->Initialize(window, 1500);
    			firstwindow = false;
    		}
    		else
    		{
    			window->SetHidden(false);
    		}
    
    		// Set this to focus!
    		window->SetCursor(current_cursor);
    		window->Activate();
    
    		// Send this event with the size of the framebuffer.
    		EmitEvent(EVENT_GRAPHICSWINDOW, GetProgram(), 0, window->GetPosition().x, window->GetPosition().y, framebuffer->GetSize().x, framebuffer->GetSize().y, window);
    		return true;
    	}

     

  12. 1. I can't resize the grid with the bracket hot keys ("[" and "]")

    2. I don't know if the grid was not adjusted correctly for the unit change a while back, but nothing seems to line up anymore. The texture scale is 0.28 off.

    image.thumb.png.2141b6cbb38cd83130bced0f9321fdec.png

    image.thumb.png.599e7d0c0c3df754c092f5206b328c78.png

    3. When will I get my unit number display for brushes? 😭

    • Thanks 1
  13. When attempting to look at a model in the asset browser, you'll receive the "PostEffect is NULL" error message as the compiled post effects are missing in the Shaders folder. The current fix is to copy and paste the Post Effects folder from the Source folder to the Shaders folder. 

    The fix would involve including the copy the compiled shaders to the Shaders folder.

×
×
  • Create New...