ASIMOV BLIND - audio game with no graphics
Project timescale
Below is a downloadable for my audio game that was developed using XAudio2. To play it simply unzip the folder and run the exe file. Headphones are needed to follow the 3D sounds in the game.
Underneath the downloadable is the report I wrote on the project.
Underneath the downloadable is the report I wrote on the project.
asimovbline_exe.zip | |
File Size: | 6874 kb |
File Type: | zip |
Overview
The application is a simple game where the player must navigate through 3 different rooms, finding the door in each one. The player takes control of a robot called Asimov who, after an encounter with a monster known as “the beast”, has had his vision sensors disabled. An unnamed character speaks to Asimov through his inbuilt radio and speakers placed in the rooms to give the player instructions.
The player moves by pressing the up arrow to key to take a step forward. Pressing the left or right arrow keys turns the player 90 degrees left and right accordingly. When the player comes into contact with a wall, they will not move further forward and a sound effect of hitting the wall will play. When the player comes into contact with a door, a door opening sound effect will play and the player will exit the room.
There are speakers in the first and second room above the doors and the audio that comes through them is positional. Other positional sounds include; the sound of a dripping pipe in the second room, the sound of a fly buzzing which moves around the second room and the sound of the beast which has a sound cone coming out of the door in the third room.
C++ Source Code Structure
The program was written using Allan C. Milne’s XAudio2 framework and Stuart Milne’s vector3 class. Other classes used are the following: AsimovBlind, Room, FirstRoom, SecondRoom, ThirdRoom, Player, My3DSound and FlySound. The Player class was written by Allan C. Milne. Allan C. Milne also wrote the My3DSound and Room classes but they were expanded upon by the author of this Application. The author added further functionality to the My3DSound class and rewrote the Room class so that it inherited from the IState strategy class found in the framework and acted as a base class for different rooms with their own layouts and sounds. The rest of the classes were written by the author of the application.
The AsimovBlind class inherits from the IState strategy class and controls the application; updating the current room the player is in and changing rooms when the player goes through a door. The Room class is used as a base class for each room and, as previously stated, inherits from the IState strategy class also. Contains logic used to move the player and check when they hit a wall or door. Also contains variables and functions to be defined by each different room. The Player class encapsulates an X3DAudio listener and allows it to be moved and rotated in 3D space. The My3DSound class inherits from the Updateable class and stores a XASound and X3DAudio emitter that maintains the coordinates of the sound. It uses this emitter with a pointer to the listener, to make the sound 3D. This means that the sound will pan and change in volume as the player moves in relation to the sound. The FlySound class inherits from the My3DSound class and adds a function that makes the sound repeatedly find a random point in space and move towards it, selecting a new random point upon reaching the previous one. The FirstRoom, SecondRoom and ThirdRoom class all inherit from the room class. They each have their own defined dimensions, layout and sounds.
Implementation
All the dialogue sounds that play directly to the player, use a filter that makes them sound like they’re coming out of a radio. This is a high pass filter, with a low cut off frequency and low 1 over Q value. When a room has more than one of these dialogue sounds, they need to play at specific points so that they don’t play over each other or play repeatedly. This is done with a combination of booleans to flag if sounds have played already and checks to see if a sound is currently playing. There are 6 different sounds played by the speakers. Each sound is represented by an instance of the My3DSound class and stored in a vector. Only one of these sounds plays at a time and an integer is used to store the index of the sound currently updating. The PlayRandomSpeakerSound function is used to do this. It checks if the sound currently updating has finished playing. If it has then it deactivates the current sound, uses a random number generator to select one of the 6 sounds at random and then activates this sound. The dripping pipe sound is represented by an instance of the My3DSound class like the speaker sounds. The buzzing fly uses the FlySound class so that it moves randomly around the room. The MoveAroundRoom function checks if the fly has reached its current destination. If it has then it gets two vectors; the fly’s current position which acts as the fly’s new starting point and a random point in the room which becomes the fly’s new destination. It finds the difference between the two vectors and uses this to calculate the directional components needed to move the fly towards its new destination. Every frame it will use these components with delta time and a constant speed to move in the direction of its destination. After moving it will get its current position and use that to find out much distance it has covered since its starting point. If this distance is greater than or equal to the distance between the start point and destination, the fly has reached its current destination. It will then repeat the process to keep moving in new directions. For the beast sound, a XASound and X3DAudio emitter are used with an X3DAudio cone. The emitter is placed outside the door in the third room and the cone is directed, from the emitter, into the room. This means that the sound isn’t heard until the player is near the door and the sound is clearest when the player is standing in front of the door way.
It was originally planned that the radio filter would be used on the speaker sounds rather than the main dialogue. However using filters on 3D sounds proved to be problematic since the filter would cause error in the 3D calculations. The beast sound was going to be an instance of the My3DSound class, rather than the XASound class but accessing the emitter to set the cone properties had complications. The values could not be set directly due to access write violations and getting a reference to the emitter and setting the properties that way, resulting in the values being lost. It was far more straightforward to just have the emitter be a member of the ThirdRoom class instead.
The application is a simple game where the player must navigate through 3 different rooms, finding the door in each one. The player takes control of a robot called Asimov who, after an encounter with a monster known as “the beast”, has had his vision sensors disabled. An unnamed character speaks to Asimov through his inbuilt radio and speakers placed in the rooms to give the player instructions.
The player moves by pressing the up arrow to key to take a step forward. Pressing the left or right arrow keys turns the player 90 degrees left and right accordingly. When the player comes into contact with a wall, they will not move further forward and a sound effect of hitting the wall will play. When the player comes into contact with a door, a door opening sound effect will play and the player will exit the room.
There are speakers in the first and second room above the doors and the audio that comes through them is positional. Other positional sounds include; the sound of a dripping pipe in the second room, the sound of a fly buzzing which moves around the second room and the sound of the beast which has a sound cone coming out of the door in the third room.
C++ Source Code Structure
The program was written using Allan C. Milne’s XAudio2 framework and Stuart Milne’s vector3 class. Other classes used are the following: AsimovBlind, Room, FirstRoom, SecondRoom, ThirdRoom, Player, My3DSound and FlySound. The Player class was written by Allan C. Milne. Allan C. Milne also wrote the My3DSound and Room classes but they were expanded upon by the author of this Application. The author added further functionality to the My3DSound class and rewrote the Room class so that it inherited from the IState strategy class found in the framework and acted as a base class for different rooms with their own layouts and sounds. The rest of the classes were written by the author of the application.
The AsimovBlind class inherits from the IState strategy class and controls the application; updating the current room the player is in and changing rooms when the player goes through a door. The Room class is used as a base class for each room and, as previously stated, inherits from the IState strategy class also. Contains logic used to move the player and check when they hit a wall or door. Also contains variables and functions to be defined by each different room. The Player class encapsulates an X3DAudio listener and allows it to be moved and rotated in 3D space. The My3DSound class inherits from the Updateable class and stores a XASound and X3DAudio emitter that maintains the coordinates of the sound. It uses this emitter with a pointer to the listener, to make the sound 3D. This means that the sound will pan and change in volume as the player moves in relation to the sound. The FlySound class inherits from the My3DSound class and adds a function that makes the sound repeatedly find a random point in space and move towards it, selecting a new random point upon reaching the previous one. The FirstRoom, SecondRoom and ThirdRoom class all inherit from the room class. They each have their own defined dimensions, layout and sounds.
Implementation
All the dialogue sounds that play directly to the player, use a filter that makes them sound like they’re coming out of a radio. This is a high pass filter, with a low cut off frequency and low 1 over Q value. When a room has more than one of these dialogue sounds, they need to play at specific points so that they don’t play over each other or play repeatedly. This is done with a combination of booleans to flag if sounds have played already and checks to see if a sound is currently playing. There are 6 different sounds played by the speakers. Each sound is represented by an instance of the My3DSound class and stored in a vector. Only one of these sounds plays at a time and an integer is used to store the index of the sound currently updating. The PlayRandomSpeakerSound function is used to do this. It checks if the sound currently updating has finished playing. If it has then it deactivates the current sound, uses a random number generator to select one of the 6 sounds at random and then activates this sound. The dripping pipe sound is represented by an instance of the My3DSound class like the speaker sounds. The buzzing fly uses the FlySound class so that it moves randomly around the room. The MoveAroundRoom function checks if the fly has reached its current destination. If it has then it gets two vectors; the fly’s current position which acts as the fly’s new starting point and a random point in the room which becomes the fly’s new destination. It finds the difference between the two vectors and uses this to calculate the directional components needed to move the fly towards its new destination. Every frame it will use these components with delta time and a constant speed to move in the direction of its destination. After moving it will get its current position and use that to find out much distance it has covered since its starting point. If this distance is greater than or equal to the distance between the start point and destination, the fly has reached its current destination. It will then repeat the process to keep moving in new directions. For the beast sound, a XASound and X3DAudio emitter are used with an X3DAudio cone. The emitter is placed outside the door in the third room and the cone is directed, from the emitter, into the room. This means that the sound isn’t heard until the player is near the door and the sound is clearest when the player is standing in front of the door way.
It was originally planned that the radio filter would be used on the speaker sounds rather than the main dialogue. However using filters on 3D sounds proved to be problematic since the filter would cause error in the 3D calculations. The beast sound was going to be an instance of the My3DSound class, rather than the XASound class but accessing the emitter to set the cone properties had complications. The values could not be set directly due to access write violations and getting a reference to the emitter and setting the properties that way, resulting in the values being lost. It was far more straightforward to just have the emitter be a member of the ThirdRoom class instead.