.. _stdlib_first_game: ===================== Build Your First Game ===================== Let's build a simple scene with a single rotating cube and a camera to show you how to use EdenSpark. First, we need to import the necessary modules. In EdenSpark, you can import all the main modules you need with a single import statement:: require engine.core Alternatively, you can import the necessary modules individually. The page for each module will show you how to import it. The first function we need to write to create a scene is the ``on_initialize()`` function. This function is called once when the scene is first loaded:: require engine.core [export] def on_initialize() { print("Hello, World") } If you try to run this code, you will see the "No camera" message on the screen and "Hello, World" in the log (press ` to show the log). Let's get rid of the "No camera" message by replacing "Hello, World" with camera creation. We can do this by creating a scene node and adding a camera component to it:: require engine.core [export] def on_initialize() { let camera = create_node(NodeData(name="camera")) add_component(camera, new Camera()) } Now the "No camera" message should disappear; however, the scene is still empty. Let's add a cube to the scene. We should once again create a scene node and add a mesh component to it:: require engine.core [export] def on_initialize() { let camera = create_node(NodeData(name="camera")) add_component(camera, new Camera()) let cubeNode = create_node(NodeData(name="cube", position=float3(0, 0, 2))) add_component(cubeNode, new Mesh(meshId=CUBE_MESH_ID)) } Now we have a scene with a camera and a cube. The cube is not rotating yet, so let's rotate it. For this, we need to write the ``on_update()`` function. This function is called every frame:: require engine.core var cubeNode : NodeId [export] def on_initialize() { let camera = create_node(NodeData(name="camera")) add_component(camera, new Camera()) cubeNode = create_node(NodeData(name="cube", position=float3(0, 0, 2))) add_component(cubeNode, new Mesh(meshId=CUBE_MESH_ID)) } [export] def on_update() { let dt = get_delta_time() cubeNode.localRotation *= quat4(0, 0.5 * dt, 0) } In the ``on_update()`` function, we first get the delta time, which is the time between the current frame and the previous frame. We then rotate the cube around the y-axis by multiplying its current rotation with a quaternion that represents a rotation of 0.5 radians per second around the y-axis. Note that we have declared the variable `cubeNode` outside the functions because we need to access the cube node in both functions. If you run this code, you will see a rotating cube in the scene. However, you may notice that the cube lacks shadows, and overall the scene looks a bit dull. Let's add render settings to the scene to make it look better:: require engine.core var cubeNode: NodeId [export] def on_initialize() { create_render_settings() let camera = create_node(NodeData(name="camera")) add_component(camera, new Camera()) cubeNode = create_node(NodeData(name="cube", position=float3(0, 0, 2))) add_component(cubeNode, new Mesh(meshId=CUBE_MESH_ID)) } [export] def on_update() { let dt = get_delta_time() cubeNode.localRotation *= quat4(0, 0.5 * dt, 0) } ``create_render_settings()`` creates a default set of render settings — adding shadows, ambient occlusion, and other post-processing effects to the scene. It returns a node, but we don't need to store it in a variable because we use the default settings. However, if you want to change the render settings later, you can store the node and access its components to change the settings. The scene should look much better with shadows and ambient occlusion; however, the lighting is still not very good. This is because we have not added any lights to the scene. Let's add a directional light to the scene to make it look better. We can do this by creating a scene node and adding a directional light component to it:: require engine.core var cubeNode: NodeId [export] def on_initialize() { create_render_settings() let sun = create_node(NodeData(rotation=quat4(0.5, 0., 0.))) add_component(sun, new DirectionLight()) let camera = create_node(NodeData(name="camera")) add_component(camera, new Camera()) cubeNode = create_node(NodeData(name="cube", position=float3(0, 0, 2))) add_component(cubeNode, new Mesh(meshId=CUBE_MESH_ID)) } [export] def on_update() { let dt = get_delta_time() cubeNode.localRotation *= quat4(0, 0.5 * dt, 0) } Congratulations! You have created your first scene in EdenSpark! Besides ``on_initialize()`` and ``on_update()``, there are other functions that might be needed in a scene. ``on_resolution_changed(resolution : int2)`` is called when the window resolution changes and when the game starts, right after ``on_initialize()``. ``on_pause(pause : bool)`` is called when the scene is paused; it accepts a boolean argument that is true if the scene is paused and false if it is resumed. ``on_exit()`` is called when the game is closed; you can use this function to save the game state. ``on_before_reload()`` and ``on_after_reload()`` are called before and after the scene is reloaded, respectively. You can find more information about the functions and the modules in the API documentation, and more examples in the showcases folder.