SpaceGame Menu

Intro

Lets create an intro, which is shown first. For that goto ‘File -> New’.

Specify the project name ‘SpaceGame’ and scene name ‘Intro’. For the SpaceGame project, the intro.scene will be created. Uncheck C++ project creation, but check ‘Create own AppState’.

Furthermore check the property ‘Ignore Global Scene’, as we do not want, that the global game object space ship is created for the intro scene.

Now a new C++ AppState called IntroState is prepared and added as state in the MainApplication.cpp.

Goto to the ‘MainApplication.cpp’ file and change in the function ‘startAppState(“GameState”)’ to ‘startAppState(“IntroState”)’.

Note: If more than one lights (SunLight) are used, the light mode should be set to ‘Forward Clustered’ or at least ‘Forward’, so that another light like a spot light will be visible.

In the intro scene, a block with the LOGO shall be falling down. If hitting the ground a particle effect shall be played. After that a spot light will be moved from left to right and lighten the Logo details and a nice sound played. Everything will be timed, hence the TimeLineComponent will be used.

Lets first create a plane.

Go to the left panel and choose ‘Plane’ from the root tree. Place the plane in the scene and adjust the coordinates to 0 0 0.

Note:

In the root section some useful game objects with some already properly configured components will be created.

Now press either ‘ctrl + shift + C’ or click the ‘C’ button on the right panel of the plane game object and add or search for the Component ‘Artifact’ which will match the ‘PhysicsArtifactComponent.

Now this plane is a rigid physics body for collision. Physics artifact means, that besides moving this body in the editor, when starting the simulation, it will never move.

Hence for the game object the attribute ‘Dynamic’ can be deactivated or later via menu ‘Optimize Scene’ will do this for us automatically. This floor should later not be visible in the scene. Thus either set now ‘Visible’ to ‘false’ or later via lua script.

After that create the box with the logo. For that search for ‘box’ in the left panel or open the ‘Objects’ tree.

Place the box somewhere and adjust the coordinates to: 0 10 0 and scale it: 2 1 1, so it can fall on the ground.

Name the game object ‘Logo’ and create a new category with the name ‘Logo’. This category will be required for physics materials and for reaction, if the box hit the ground.

Now press either ‘ctrl + shift + C’ or click the ‘C’ button on the right panel of the Logo game object and add or search for the Component: PBS which will match the ‘DatablockPbsComponent’.

Add that component. With this component the visual appearance can be tweaked. Set as diffuse texture name your logo image file.

Its advised, also to create a normal map, roughness, specular, emissive map of that image.

A good tool for that is the ShaderMap 4 tool. Open the proper images for the given map types. Play around with the other parameters.
Maybe choose a metallic workspace. If you like, press the play button to see what happens.

The Logo should fall down with a gravity value of 0 -19.7 0 newton meters.

Note:

In games the gravity is much more higher as in real. Usually the gravity on earth is approx. 9.7, but try to set this value and you will see, that the Logo will fall like on the moon.

Next add for the Logo a PhysicsActiveComponent. Set the constraint axis to 0 0 1, which will constraint just the z-axis, because physics should only take place for x-y-axis.

Create a ‘LuaScriptComponent’ and set the script name, to what you like, e.g. logo.lua. In this script, later some mechanics will be programmed.

Furthermore create for this game object a PhysicsMaterialComponent. Choose the categories: ‘Logo’ and ‘Default’.

Note:

Each newly created game object belongs to the default category, if nothing else specified.

Choosing those two categories, means, that for all game objects with physics components, the given physics parameter will take place and its now also possible to specify, what should happen, if game objects of those two categories do collide:

  1. Overlap: Lua function is called, when the bounding boxes of the game objects do overlap.
  2. Contact: Lua function is called, when the game objects physically touch each other, each time.
  3. Contact Once: Same as contact, but function is only called once, they touch. It would be called another time, if the user pulls back the game object, so that it will touch the other game object again.

We are interested in collision behavior 3). Set the lua function name to ‘onHitFloorContact’ and press the ‘G’-Button. Now this function will automatically be created in the logo.lua script.

Next, create a ‘SimpleSoundComponent’ and choose the sound ‘Hit2.wav’. Set attribute ‘Activated’ to false.

After that, create the ‘ParticleUniverseComponent’ and name the component ‘Smoke1’. Set attribute ‘Activated’ to false. Choose the particle effect name: ‘woosh’.

The intro will be run for a specific amount of time, and some timed behavior will be processed. For this timing, create for this game object the ‘TimeLineComponent’.

Set the time point count to 1 and the following attributes:

  • StartTime: 2 seconds
  • Duration: 4 seconds
  • Timepoint Start Event Name: MoveLightTimePoint -> Press ‘G’-Button, in order to generate the lua function in script.

Later, a light will start moving, after 2 seconds and will move for 4 seconds.

The last component for this game object, is the FadeComponent, which will fade out the scene. Set the following attributes:

  • FadeMode: FadeOut
  • Duration: 5 seconds
  • Fade Completed Event Name: onFadeCompleted -> Press ‘G’-Button, in order to generate the lua function in script.

Thats it for the logo game object.

In the further course, we will create the moving spot light. For this, choose in the Resources panel the ‘Other Resource’ -> ‘Light (Spot)’. Place the game object somewhere.

Adjust the coordinates, approx. to: -1.8 0.34428 3

Set the power scale to 10 and set ‘Show Dummy Entity’ to false.

Now, in order to move the game object physically, we need a PhysicsActiveComponent and a JointSliderActuatorComponent. Create those two components.

For the ‘JointSliderActuatorComponent’, set the following attributes:

  • Pin: 1 0 0
  • Target Position: 10 meters
  • Linear Rate: 1
  • Min Force: 1
  • Max Force: -1 (unlimited)
  • Min Stop Distance: 0
  • Max Stop Distance: 5

Now as soon as this components gets activated, it will move along the pin x-axis from 0 to 5 meters, at a linear rate of 1.

Note: This joint has no predecessor, hence the newton world itself is automatically the root predecessor.
At last create a SimpleSoundComponent, set ‘Activated’ to false and choose the sound: ‘introStartFx.wav’.

The last thing missing, is a second camera. Because we want a static, not movable camera, when the simulation is started.

Hence create from the ‘Other Resources’, the camera game object and place it somewhere in the scene. Name the game object ‘IntroCamera’.

Adjust the coordinates in the CameraComponent position to 0 0.5 10.

Note:

Camera is somewhat special and has its own transform and the game object itself has no transform attributes.

Set the attribute ‘Active’ to false. Note: Using the active attribute, cameras can be switched.

Note:

As the camera game object has been created, along with that, the default ‘PbsWorkspaceComponent’ has been created, because each camera must know how to render the scene.

Note:>

Its also possible to delete the ‘PbsWorkspaceComponent’ and choose another one.

Thats it for the design part. Next we will concentrate on the lua script part.

For that goto ‘menu -> edit -> Open Project Folder’.

Open the logo.lua file with the ZeroBrane Studio.

Before we start writing some lua code. I will explain some yet pre-configured codings.

Take a look the the first line: module(“Logo”, package.seeall);

This line is really important! It allows, that each game object can have its own script and environment, instead of a static script, which would affect all game objects. Its like, this script is just used for this game object logo instance!

Also the global script require(“init”); is also already included, which here is not necessary yet, but does not harm.

Next, there are also some lua script table functions already available:

  • connect: Is called, when the simulation is started, this function is called, which is good for setting some attributes properly.
  • disconnect: Is called, when the simulation has ended and useful to tidy up some attributes.

Optional:

  • update: Is called with the parameter dt (delta time) in milliseconds, if the developer wants to simulate something. This function is called for alle game objects before the rendering has taken place.
  • lateUpdate: Is called, after all physics, inputs, game objects have been updated and is called just before the rendering. This should only be used in order to move a camera manually etc. to prevent some visual artifacts.

Now lets start creating some variables, which are required for this script. Write them outside the functions:


module("Logo", package.seeall);

physicsActiveComponent = nil;
cameraComponent = nil;
soundComponent = nil;
introSoundFxComponent = nil;
particleComponent = nil;
spotLightJoint = nil;
fadeComponent = nil;

Logo = {}

-- Scene: Intro

require("init");

I will first write code and then explain, what is happening.


Logo["connect"] = function(gameObject)
PointerManager:showMouse(false);
physicsActiveComponent = gameObject:getPhysicsActiveComponent();
soundComponent = gameObject:getSimpleSoundComponent();
particleComponent = gameObject:getParticleUniverseComponentFromName("Smoke1");
fadeComponent = gameObject:getFadeComponent();

cameraComponent = AppStateManager:getGameObjectController():getGameObjectFromName("IntroCamera"):getCameraComponent();
cameraComponent:setActivated(true);

local spotLightGameObject = AppStateManager:getGameObjectController():getGameObjectFromName("SpotLight");
spotLightJoint = spotLightGameObject:getJointSliderActuatorComponent();
introSoundFxComponent = spotLightGameObject:getSimpleSoundComponent();
end

In the connect function, first the mouse is hidden and after that, some required components are received.
Note: Those functions are all called for the logo game object. The components of the logo can be get by calling ‘gameObject:getMyComponent’.

We also specified a name for the particle universe component, so it can be received by calling ‘gameObject:getParticleUniverseComponentFromName(“Smoke1”)’.

We also need the intro camera, which is a different game object, so get first the game object from name ‘IntroCamera’ and then the component. The intro camera gets activated, so that the editor camera will be deactivated automatically.

After that, we create a local variable called spotLightGameObject, which we get from the game object name. We also need the spot light joint, with the moving behavior and the sound.

Next, the ‘disconnect’ function is explained.


Logo["disconnect"] = function()
PointerManager:showMouse(true);
cameraComponent:setActivated(false);
fadeComponent:setActivated(false);
AppStateManager:getGameObjectController():getGameObjectFromName("MainCamera"):getCameraComponent():setActivated(true);
soundComponent:setActivated(false);
introSoundFxComponent:setActivated(false);
particleComponent:setActivated(false);
spotLightJoint:setActivated(false);
end

In this function we revert everything, that has been activated in the ‘connect’ function. So when pressing the play button in the editor, things get activated and when stopping the simulation, things get deactivated again.

Now, we react when the log fell on the ground.


Logo["onHitFloorContact"] = function(gameObject0, gameObject1, contact)
soundComponent:setActivated(true);
particleComponent:setActivated(true);
end

In this case, the sound component is activated, whichs starts playing the ‘Hit2.wav’ sound and the particle is activated with the smoke or woosh effect.

Next, we react if the time line component has started.


Logo["MoveLightTimePoint"] = function(timePointSec)
spotLightJoint:setActivated(true);
introSoundFxComponent:setActivated(true);
if (Core:isGame() == true) then
fadeComponent:setActivated(true);
end
end

If it starts after 2 seconds, we activate the slider actuator joint and the intro sound. Now, notice the condition, if we are in game mode.

If we are in game mode, the fade component is activated, which will start fade out. We just want this, when the SpaceGame.exe is started and not in editor mode, because later, when the fading is finished, a new scene should be loaded.

At last, we react, if the fading has finished in game mode.


Logo["onFadeCompleted"] = function()
if (Core:isGame() == true) then
AppStateManager:changeAppState("MenuState");
end
end

If we are in game mode, we change the current application state to the ‘MenuState’. Which has yet not been created. That does not matter, if we start the game for testing, in the Ogre.log just a message is written,
which informs us, that the application state cannot be changed, because the ‘MenuState’ does not exist.

Menu

If the intro is done, lets start creating the menu. For that, goto new and set the project name to ‘SpaceGame’ and the scene name to ‘Menu’. Also check the option ‘Create scene in own AppState’.

NOWA will create the MenuState.cpp and MenuState.h file for us. Also check the option ‘Ignore global scene’. Now open the C++ project and you should see the MenuState.cpp/.h file. Open to the MainApplication.cpp file.

Include the MenuState.h file:


#include "MenuState.h"

After that, like the static creation of the IntroState, create the MenuState:


MenuState::create(NOWA::AppStateManager::getSingletonPtr(), “MenuState”, “MenuState”);

This will make the MenuState available for the AppStateManager. Now compile the project in x64 and release mode.

Ok, back to NOWA-Design.

The Menu will have no meshes, but just MyGUI Widgets. We will create a nice effect, in which all menu buttons will jump from the right side into the scene. When a button is hovered, the button will also jump and make a noise.

I think, the ‘MainGameObject’ is a good place to add MyGUI widget components. Hence lets start creating the menu.

First create a ‘LuaScriptComponent’. After that create a MyGUIButtonComponent. Name it ‘ContinueButton’. Set the following attributes:

  • Activated: False -> Note: This button shall only be visible under certain circumstances.
  • Position: 1 0.2 -> Note: This values are always relative to the screen size. The value 1 means, this button starts right out of the scene and y is at 20% of the y-screen size.
  • Size: 0.8 0.07
  • Color: 0.59375 0.26679 0.03943 0.6 -> Note: You can also play with different colors.
  • Mouse Click Event: onContinueClicked -> Note: Press the ‘G’ button, so that this function will be created in the lua script.
  • Mouse Click Event: onContinueEnter -> Note: Press the ‘G’ button, so that this function will be created in the lua script.
  • Mouse Click Event: onContinueLeave -> Note: Press the ‘G’ button, so that this function will be created in the lua script.
  • Font Height: 40
  • Text Align: Center
  • Text Offset: 500 0 -> Note: The x-margin for the text.
  • Text Color: 0 0 0 1

Now in order to slide the text from the right side, create a MyGUIPositionControllerComponent, name it ‘ContinueController’ and fill in the following attributes:

  • Source Id: Choose the id of the prior created MyGUIButtonComponent. In my example the id is: 3574170270
  • Coordinate Relative: 0.4 0.2 0 0 -> Note: The Button shall slide from its current position to x 0.4 and keep y the same as the button y 0.2.
  • Function: Jump
  • Duration Sec: 0.5

Before we start creating the other buttons, we adapt the lua script and test our first button. Open the project folder and the corresponding lua script in the ZeroBrane studio.

Create outside the function the variable:


mainGameObject = nil;

This one will be used in all function.

Fill the ‘connect’ function with the following content:


MainGameObject["connect"] = function(gameObject)
mainGameObject = AppStateManager:getGameObjectController():castGameObject(gameObject);

PointerManager:showMouse(true);

OgreALModule:setContinue(true);

-- If game has already started and was just paused, continue
if (AppStateManager:hasAppStateStarted("GameState") == true) then
mainGameObject:getMyGUIButtonComponentFromName("ContinueButton"):setActivated(true);
mainGameObject:getMyGUIButtonComponentFromName("SaveButton"):setEnabled(true);
end
end

Now I will describe something new. You see the line with the casting function? This is optional and will help ZeroBrane Studio for its autocompletion, to have the correct type.

Because lua is typeless and if just using the game object from the function. If you press ‘gameObject.’, ZeroBrane cannot recognize, which type you mean. By casting via the function ‘castGameObject’
and assign to our local variable, ZeroBrane now knows the type!

Note:

Also see the command ‘OgreALModule:setContinue(true);’. OgreAL or more specifically OpenAL is somewhat a diva. Its not possible to have several OpenAL instances. But we want to use for our menu a background music. But as soon as we change the application state e.g. to the SaveState, the music would stop, because the OgreALModule would be destroyed and re-created. By calling this command, we tell the OgreALModule,
that we want to keep it for this state, no matter what happens. It will not be destroyed and the music will continue playing, if we change e.g. to the LoadAppState or SaveAppState later.

In the next line:


if (AppStateManager:hasAppStateStarted("GameState") == true) then

We check, if another application state has already started, in this case our game. If this is the case. We active (set visible) our fresh created ‘ContinueButton’ and enable the ‘SaveButton’.

But since we now want to test our ‘ContinueButton’, in the second line of this function active the button:


mainGameObject:getMyGUIButtonComponentFromName("ContinueButton"):setActivated(true);

Do not forget later to remove this line again.

Now go back to NOWA-Design and start the simulation. The ‘ContinueButton’ should jump from the right screen.

Now we will repeat this 2 components creation for all other buttons in a similar way. We just adapt the y-position of each other button and controller.

The next button and controller to create is the ‘NewButton’ and ‘NewController’. The event names are the same as for the Continue-Button, but instead of e.g. ‘onContinueClicked’, set to ‘onNewClicked’.

Also do not forget to set the correct source id for the controller each time to its prior button component. The y-position will each time be incremented by 0.15.

That means the NewButton will have the position: 1 0.35, the next button: 1 0.5 and so on.

Create and name the following buttons:

  • LoadButton, LoadConroller
  • SaveButton, SaveConroller
  • ExitButton, ExitConroller

At last we have 5 buttons by total.

Now we still need some other components. Lets create two additional ‘MyGUIPositionController’. Name the first on ‘LeftController’ and the second one ‘RightController’.

Those controllers will be used for every enter and leave button. That is, when you hover a button, it will jump a bit to the left and when you leave the button, it will jump back left to its origin position.

We will control this in the lua script later. But for now, set the following attributes:

  • LeftController, RightController
  • Coordinate Relative: 0.4 0.6 0 0
  • Function: Inertional
  • Duration Sec: 0.2

At last create two SimpleSoundComponent’s, one for the hover effect sound and the other for the background music.

Set for the first sound component the sound to ‘Click.wav’ and deactivate the sound and choose a nice background music for the second one, like: ‘Juhani Junkala [Retro Game Music Pack] Title Screen.wav’.

Also set ‘Loop’ and ‘Stream’ to true. Note: Longer sounds, music should be streamed instead of loading the whole big file into the buffer at once. This will avoid jitter when the menu state is loaded and is more performant
and less memory hungry.

Go back to the lua script. The ‘disconnect’ function does look as follows:


OgreALModule:setContinue(false);

local positionController1 = mainGameObject:getMyGUIPositionControllerComponentFromName("LeftController");
local positionController2 = mainGameObject:getMyGUIPositionControllerComponentFromName("RightController");
positionController1:setSourceId("0");
positionController2:setSourceId("0");

mainGameObject:getMyGUIButtonComponentFromName("ContinueButton"):setActivated(false);
mainGameObject:getMyGUIButtonComponentFromName("SaveButton"):setEnabled(false);

If this application state will be disconnected, do not continue OgreAL anymore. E.g. when the GameState will be started.
Reset also our left- and right-controller.

Fill the following functions with life:


MainGameObject["onContinueClicked"] = function(thisComponent)
thisComponent = AppStateManager:getGameObjectController():castMyGUIButtonComponent(thisComponent);

AppStateManager:popAppState();

end

MainGameObject["onContinueEnter"] = function(thisComponent)
thisComponent = AppStateManager:getGameObjectController():castMyGUIButtonComponent(thisComponent);

local positionController = mainGameObject:getMyGUIPositionControllerComponentFromName("LeftController");
positionController:setSourceId(thisComponent:getId());
positionController:setCoordinate(Vector4(0.37, 0.2, 0, 0));
positionController:setActivated(true);

local clickSound = mainGameObject:getSimpleSoundComponent();
clickSound:setActivated(true);

end

MainGameObject["onContinueLeave"] = function(thisComponent)
thisComponent = AppStateManager:getGameObjectController():castMyGUIButtonComponent(thisComponent);

local positionController = mainGameObject:getMyGUIPositionControllerComponentFromName("RightController");
positionController:setSourceId(thisComponent:getId());
positionController:setCoordinate(Vector4(0.4, 0.2, 0, 0));
positionController:setActivated(true);

local clickSound = mainGameObject:getSimpleSoundComponent();
clickSound:setActivated(false);
end

In the first function, if we click on the ‘ContinueButton’, this application state will be removed from the stack. Note: This will not work yet, because we never started the GameState.

If the GameState would be present and wo go back to the menu, we keep the GameStack on the stack and just push the MenuState on the top of the GameState. When clicking on continue, we pop the MenuState and
the next application state on the stack would be the GameState. If you want, comment this line.

In the second function ‘onContinueEnter’, we get our left controller, set the source id to the id of the ‘ContinueButton’ and adapt the coordinates. We also get and activate the sound component.

In the ‘onContinueLeave’ function, we do the opposite.

We will do this for all 5 buttons:


MainGameObject["onNewClicked"] = function(thisComponent)
thisComponent = AppStateManager:getGameObjectController():castMyGUIButtonComponent(thisComponent);

AppStateManager:popAllAndPushAppState("GameState");

--AppStateManager:getGameProgressModule():changeWorld("Level1");
end

MainGameObject["onNewEnter"] = function(thisComponent)
thisComponent = AppStateManager:getGameObjectController():castMyGUIButtonComponent(thisComponent);

local positionController = mainGameObject:getMyGUIPositionControllerComponentFromName("LeftController");
positionController:setSourceId(thisComponent:getId());
positionController:setCoordinate(Vector4(0.37, 0.35, 0, 0));
positionController:setActivated(true);

local clickSound = mainGameObject:getSimpleSoundComponent();
clickSound:setActivated(true);

end

MainGameObject["onNewLeave"] = function(thisComponent)
thisComponent = AppStateManager:getGameObjectController():castMyGUIButtonComponent(thisComponent);

local positionController = mainGameObject:getMyGUIPositionControllerComponentFromName("RightController");
positionController:setSourceId(thisComponent:getId());
positionController:setCoordinate(Vector4(0.4, 0.35, 0, 0));
positionController:setActivated(true);

local clickSound = mainGameObject:getSimpleSoundComponent();
clickSound:setActivated(false);
end

MainGameObject["onLoadClicked"] = function(thisComponent)
thisComponent = AppStateManager:getGameObjectController():castMyGUIButtonComponent(thisComponent);

AppStateManager:pushAppState("LoadMenuState");
end

MainGameObject["onLoadEnter"] = function(thisComponent)
thisComponent = AppStateManager:getGameObjectController():castMyGUIButtonComponent(thisComponent);

local positionController = mainGameObject:getMyGUIPositionControllerComponentFromName("LeftController");
positionController:setSourceId(thisComponent:getId());
positionController:setCoordinate(Vector4(0.37, 0.5, 0, 0));
positionController:setActivated(true);

local clickSound = mainGameObject:getSimpleSoundComponent();
clickSound:setActivated(true);
end

MainGameObject["onLoadLeave"] = function(thisComponent)
thisComponent = AppStateManager:getGameObjectController():castMyGUIButtonComponent(thisComponent);

local positionController = mainGameObject:getMyGUIPositionControllerComponentFromName("RightController");
positionController:setSourceId(thisComponent:getId());
positionController:setCoordinate(Vector4(0.4, 0.5, 0, 0));
positionController:setActivated(true);

local clickSound = mainGameObject:getSimpleSoundComponent();
clickSound:setActivated(false);
end

MainGameObject["onSaveClicked"] = function(thisComponent)
thisComponent = AppStateManager:getGameObjectController():castMyGUIButtonComponent(thisComponent);

AppStateManager:pushAppState("SaveMenuState");
end

MainGameObject["onSaveEnter"] = function(thisComponent)
thisComponent = AppStateManager:getGameObjectController():castMyGUIButtonComponent(thisComponent);

local positionController = mainGameObject:getMyGUIPositionControllerComponentFromName("LeftController");
positionController:setSourceId(thisComponent:getId());
positionController:setCoordinate(Vector4(0.37, 0.65, 0, 0));
positionController:setActivated(true);

local clickSound = mainGameObject:getSimpleSoundComponent();
clickSound:setActivated(true);
end

MainGameObject["onSaveLeave"] = function(thisComponent)
thisComponent = AppStateManager:getGameObjectController():castMyGUIButtonComponent(thisComponent);

local positionController = mainGameObject:getMyGUIPositionControllerComponentFromName("RightController");
positionController:setSourceId(thisComponent:getId());
positionController:setCoordinate(Vector4(0.4, 0.65, 0, 0));
positionController:setActivated(true);

local clickSound = mainGameObject:getSimpleSoundComponent();
clickSound:setActivated(false);
end

MainGameObject["onExitClicked"] = function(thisComponent)
thisComponent = AppStateManager:getGameObjectController():castMyGUIButtonComponent(thisComponent);

AppStateManager:exitGame();

end

MainGameObject["onExitEnter"] = function(thisComponent)
thisComponent = AppStateManager:getGameObjectController():castMyGUIButtonComponent(thisComponent);

local positionController = mainGameObject:getMyGUIPositionControllerComponentFromName("LeftController");
positionController:setSourceId(thisComponent:getId());
positionController:setCoordinate(Vector4(0.37, 0.8, 0, 0));
positionController:setActivated(true);

local clickSound = mainGameObject:getSimpleSoundComponent();
clickSound:setActivated(true);
end

MainGameObject["onExitLeave"] = function(thisComponent)
thisComponent = AppStateManager:getGameObjectController():castMyGUIButtonComponent(thisComponent);

local positionController = mainGameObject:getMyGUIPositionControllerComponentFromName("RightController");
positionController:setSourceId(thisComponent:getId());
positionController:setCoordinate(Vector4(0.4, 0.8, 0, 0));
positionController:setActivated(true);

local clickSound = mainGameObject:getSimpleSoundComponent();
clickSound:setActivated(false);

end

Please test this scenario carefully and also check, if there are lua errors.

Save

The save state will be a part of the menu state and will be required in order to save the current game. It should be possible to interrupt the game at any time, by pressing the escape button. In menu state, a different music will be running and shall also continue, when navigating to the save sub menu.

Note:

Due to OpenAL restrictions, only one instance of audio system can be present. Navigating to save state would kill the instance.

Hence in lua script TODO which script set the flag TODO flag. Now the save state will not touch the current OgreAL instance and the Background music play will continue.

Load

The load state is similar to the save state.