Unity 2021 Cookbook - Fourth Edition

Book description

Discover the latest features of Unity 2021 and dive deeper into the nuances of professional game development with Unity

Key Features

  • Discover the latest features of Unity 2021 including coverage of AR/VR development
  • Follow practical recipes for better 2D and 2D character development with Unity GameKits
  • Learn powerful techniques and expert best practices in building 3D objects, textures, and materials

Book Description

If you are a Unity developer looking to explore the newest features of Unity 2021 and recipes for advanced challenges, then this fourth edition of Unity Cookbook is here to help you.

With this cookbook, you’ll work through a wide variety of recipes that will help you use the essential features of the Unity game engine to their fullest potential. You familiarize yourself with shaders and Shader Graph before exploring animation features to enhance your skills in building games.

As you progress, you will gain insights into Unity's latest editor, which will help you in laying out scenes, tweaking existing apps, and building custom tools for augmented reality and virtual reality (AR/VR) experiences. The book will also guide you through many Unity C# gameplay scripting techniques, teaching you how to communicate with database-driven websites and process XML and JSON data files.

By the end of this Unity book, you will have gained a comprehensive understanding of Unity game development and built your development skills. The easy-to-follow recipes will earn a permanent place on your bookshelf for reference and help you build better games that stay true to your vision.

What you will learn

  • Discover how to add core game features to your projects with C# scripting
  • Create powerful and stylish UI with Unity’s UI system, including power bars, radars, and button-driven scene changes
  • Work with essential audio features, including background music and sound effects
  • Discover Cinemachine in Unity to intelligently control camera movements
  • Add visual effects such as smoke and explosions by creating and customizing particle systems
  • Understand how to build your own Shaders with the Shader Graph tool

Who this book is for

If you’re a Unity developer looking for better ways to resolve common recurring problems with recipes, then this book is for you. Programmers dipping their toes into multimedia features for the first time will also find this book useful. Before you get started with this Unity engine book, you’ll need a solid understanding of Unity’s functionality and experience with programming in C#.

Table of contents

  1. Title Page
  2. Copyright and Credits
    1. Unity 2021 Cookbook Fourth Edition
  3. Dedication
  4. Foreword
  5. Contributors
    1. About the authors
    2. About the reviewers
  6. Preface
    1. Who this book is for
    2. What this book covers
    3. To get the most out of this book
    4. Download the example code files
    5. Download the color images
    6. Conventions used
    7. Get in touch
    8. Reviews
  7. Displaying Data with Core UI Elements
    1. Technical requirements
    2. Displaying a "Hello World" UI text message
    3. Getting ready
    4. How to do it...
    5. How it works...
    6. There's more...
    7. Styling substrings with rich text
    8. Displaying a digital clock
    9. Getting ready
    10. How to do it...
    11. How it works...
    12. Displaying a digital countdown timer
    13. Getting ready
    14. How to do it...
    15. How it works...
    16. Creating a message that fades away
    17. Getting ready
    18. How to do it...
    19. How it works...
    20. Displaying a perspective 3D Text Mesh
    21. Getting ready
    22. How to do it...
    23. How it works...
    24. There's more...
    25. Making the text crawl as it does in the movie
    26. Where to learn more
    27. Creating sophisticated text with TextMeshPro
    28. Getting ready
    29. How to do it...
    30. How it works...
    31. There's more...
    32. Rich text substrings for colors, effects, and sprites
    33. Displaying an image
    34. Getting ready
    35. How to do it...
    36. How it works...
    37. There's more...
    38. Working with 2D sprites and UI Image components
    39. See also
    40. Creating UIs with the Fungus open source dialog system
    41. How to do it...
    42. How it works...
    43. Creating a Fungus character dialog with images
    44. How to do it...
    45. How it works...
    46. There's more...
    47. Further reading
  8. Responding to User Events for Interactive UIs
    1. Technical requirements
    2. Creating UI Buttons to move between scenes
    3. How to do it...
    4. How it works...
    5. There's more...
    6. Animating button properties on mouseover
    7. How to do it...
    8. How it works...
    9. Organizing image panels and changing panel depths via buttons
    10. Getting ready
    11. How to do it...
    12. How it works...
    13. There's more...
    14. Moving up or down by just one position, using scripted methods
    15. Displaying the value of an interactive UI Slider
    16. How to do it...
    17. How it works...
    18. Displaying a countdown timer graphically with a UI Slider
    19. Getting ready
    20. How to do it...
    21. How it works...
    22. Setting custom mouse cursors for 2D and 3D GameObjects
    23. Getting ready
    24. How to do it...
    25. How it works...
    26. Setting custom mouse cursors for UI controls
    27. Getting ready
    28. How to do it...
    29. How it works...
    30. Interactive text entry with Input Field
    31. How to do it...
    32. How it works...
    33. There's more...
    34. Toggles and radio buttons via toggle groups
    35. Getting ready
    36. How to do it...
    37. How it works...
    38. There's more...
    39. Creating text and image icon UI Drop-down menus
    40. Getting ready
    41. How to do it...
    42. How it works...
    43. There's more...
    44. Adding images to a Dropdown control
    45. Displaying a radar to indicate the relative locations of objects
    46. Getting ready
    47. How to do it...
    48. How it works...
    49. The Start() method
    50. The Update() method
    51. The FindAndDisplayBlipsForTag(...) method
    52. The CalculateBlipPositionAndDrawBlip (...) method
    53. The NormalizedPosition(...) method
    54. The CalculateBlipPosition(...) method
    55. The DrawBlip() method
    56. There's more...
  9. Inventory and Advanced UIs
    1. Technical requirements
    2. Creating a simple 2D mini-game – SpaceGirl
    3. Getting ready
    4. How to do it...
    5. How it works...
    6. Displaying single object pickups with carrying and not-carrying text
    7. Getting ready
    8. How to do it...
    9. How it works...
    10. The PlayerInventory script class
    11. The PlayerInventoryDisplay script class
    12. There's more...
    13. Collecting multiple items and display the total number carried
    14. Alternative – combining all the responsibilities into a single script
    15. Displaying single-object pickups with carrying and not-carrying icons
    16. Getting ready
    17. How to do it...
    18. How it works...
    19. Displaying multiple pickups of the same object with multiple status icons
    20. Getting ready
    21. How to do it...
    22. How it works...
    23. There's more...
    24. Revealing icons for multiple object pickups by changing the size of a tiled image
    25. Using panels to visually outline the inventory UI area and individual items
    26. Getting ready
    27. How to do it...
    28. How it works...
    29. Creating a C# inventory slot UI to display scripted components
    30. Getting ready
    31. How to do it...
    32. How it works...
    33. There's more...
    34. Modifying the game for a second inventory panel for keys
    35. Using UI Grid Layout Groups to automatically populate a panel
    36. Getting ready
    37. How to do it...
    38. How it works...
    39. There's more...
    40. Automatically inferring the number of inventory slots based on the number of GameObjects tagged Star
    41. Adding a horizontal scroll bar to the inventory slot display
    42. Automatically changing the grid cell size based on the number of slots in the inventory
    43. Displaying multiple pickups of different objects as a list of text via a dynamic list of scripted PickUp objects
    44. Getting ready
    45. How to do it...
    46. How it works...
    47. There's more...
    48. Ordering items in the inventory list alphabetically
    49. Using a Dictionary and Enums to display text totals for different objects
    50. Getting ready
    51. How to do it...
    52. How it works...
    53. Creating a runtime UI Toolkit interface
    54. Getting ready
    55. How to do it...
    56. How it works...
    57. Further reading
  10. Playing and Manipulating Sounds
    1. Technical requirements
    2. Playing different one-off sound effects with a single AudioSource component
    3. Getting ready
    4. How to do it...
    5. How it works...
    6. There's more...
    7. Playing a sound at a static point in 3D world space
    8. Playing and controlling different sounds each with its own AudioSource component
    9. Getting ready
    10. How to do it...
    11. How it works...
    12. Creating just-in-time AudioSource components at runtime through C# scripting
    13. Getting ready
    14. How to do it...
    15. How it works...
    16. There's more...
    17. Adding the CreateAudioSource(...) method as an extension to the MonoBehavior class
    18. Delaying before playing a sound
    19. Getting ready
    20. How to do it...
    21. How it works...
    22. Preventing an audio clip from restarting if it is already playing
    23. Getting ready
    24. How to do it...
    25. How it works...
    26. Waiting for the audio to finish playing before auto-destructing an object
    27. Getting ready
    28. How to do it...
    29. How it works...
    30. See also
    31. Scheduling a sound to play at a certain time
    32. Getting ready
    33. How to do it...
    34. How it works...
    35. Audio visualization from sample spectral data
    36. Getting ready
    37. How to do it...
    38. How it works...
    39. There's more...
    40. Adding visualizations to a second AudioSource component
    41. Trying out different Fast Fourier Transform (FFT) window types
    42. Synchronizing simultaneous and sequential music to create a simple 140 bpm music-loop manager
    43. Getting ready
    44. How to do it...
    45. How it works...
    46. There's more...
    47. Adding visualizations to the four playing loops
    48. Further reading
  11. Creating 3D Objects, Terrains, Textures, and Materials
    1. Technical requirements
    2. Creating 3D primitives and adding materials and textures
    3. Getting ready
    4. How to do it...
    5. How it works...
    6. There's more...
    7. Enhancing the scene – adding a spotlight and wood material
    8. Creating a new Material asset file in the Project window and then setting its Albedo to a texture
    9. Converting and importing 3D models into a project
    10. Getting ready
    11. How to do it...
    12. How it works...
    13. Highlighting GameObject materials on mouseover
    14. Getting ready
    15. How to do it...
    16. How it works...
    17. There's more...
    18. Collider needed for custom meshes
    19. Changing the material's color in response to mouse events
    20. Fading the transparency of a material
    21. How to do it...
    22. How it works...
    23. There's more...
    24. Destroying objects when fading is complete
    25. Using the GameObject's alpha as our starting alpha value
    26. Using a coroutine for our fading loop
    27. Creating geometry with ProBuilder
    28. How to do it...
    29. How it works...
    30. Creating a house with ProBuilder
    31. How to do it...
    32. How it works...
    33. Creating and texture-painting terrains
    34. How to do it...
    35. How it works...
    36. Height painting terrains
    37. Getting ready
    38. How to do it...
    39. How it works...
    40. Adding Terrain holes
    41. Getting ready
    42. How to do it...
    43. How it works...
    44. There's more...
    45. Further reading
  12. 2D Animation and Physics
    1. Technical requirements
    2. Flipping a sprite horizontally – the DIY approach
    3. Getting ready
    4. How to do it...
    5. How it works...
    6. There's more...
    7. Flipping a sprite horizontally – using Animator State Chart and transitions
    8. Getting ready
    9. How to do it...
    10. How it works...
    11. There's more...
    12. Instantaneous swapping
    13. Animating body parts for character movement events
    14. Getting ready
    15. How to do it...
    16. How it works...
    17. Creating a three-frame animation clip to make a platform continually animate
    18. Getting ready
    19. How to do it...
    20. How it works...
    21. There's more...
    22. Copying the animation relative to a new parent GameObject
    23. Making a platform start falling once stepped on using a Trigger to move the animation from one state to another
    24. Getting ready
    25. How to do it...
    26. How it works...
    27. Creating animation clips from sprite sheet sequences
    28. Getting ready
    29. How to do it...
    30. How it works...
    31. Creating a platform game with tiles and tilemaps
    32. Getting ready
    33. How to do it...
    34. How it works...
    35. There's more...
    36. Tile palettes for objects and walls
    37. Using sprite placeholders to create a simple physics scene
    38. Getting ready
    39. How to do it...
    40. How it works...
    41. There's more...
    42. Editing polygon Colliders for more realistic 2D physics
    43. Getting ready
    44. How to do it...
    45. How it works...
    46. Creating an explosionForce method for 2D physics objects
    47. Getting ready
    48. How to do it...
    49. How it works...
    50. There's more...
    51. Clipping via Sprite Masking
    52. Getting ready
    53. How to do it...
    54. How it works...
    55. There's more...
    56. Further reading
  13. Characters, Game Kits, and Starter Assets
    1. Technical requirements
    2. Creating a game with the 3D Game Kit
    3. How to do it...
    4. How it works...
    5. There's more...
    6. Creating a game with the 2D Game Kit
    7. Getting ready
    8. How to do it...
    9. How it works...
    10. Importing third-party 3D models and animations from Mixamo
    11. Getting ready
    12. How to do it...
    13. How it works...
    14. There's more...
    15. Looping the animation
    16. Scripting events to control when animation clips are played
    17. Swapping the Standard Assets Ethan for a different character 
    18. Getting ready
    19. How to do it...
    20. How it works...
    21. Importing a 3D model and adding an Animation Controller
    22. How to do it...
    23. How it works...
    24. Using scripts to control 3D animations
    25. Getting ready
    26. How to do it...
    27. How it works...
    28. There's more...
    29. Importing and using a UMA free character
    30. How to do it...
    31. How it works...
    32. There's more...
    33. Getting started with the 2021 Starter Assets package
    34. How to do it...
    35. How it works...
    36. Further reading
  14. Web Server Communication and Online Version Control
    1. Technical requirements
    2. Setting up a leaderboard using PHP and a database
    3. Getting ready
    4. How to do it...
    5. How it works...
    6. There's more...
    7. SQLite, PHP, and database servers
    8. phpLiteAdmin
    9. See also
    10. Unity game communication with a web server leaderboard
    11. Getting ready
    12. How to do it...
    13. How it works...
    14. There's more...
    15. Extracting the full leaderboard data for display within Unity
    16. Using secret game codes to secure your leaderboard scripts
    17. See also
    18. Creating and cloning a GitHub repository
    19. Getting ready
    20. How to do it...
    21. How it works...
    22. There's more...
    23. Learn more about DVCS
    24. Learn more about Git at the command line
    25. Using Bitbucket and Sourcetree visual applications
    26. Learning about Mercurial rather than Git
    27. Adding a Unity project to a local Git repository, and pushing files up to GitHub
    28. Getting ready
    29. How to do it...
    30. How it works...
    31. Unity project version control using GitHub for Unity
    32. Getting ready
    33. How to do it...
    34. How it works...
    35. There's more...
    36. Further reading on GitHub for Unity
    37. Pulling down updates from other developers
    38. Unity Collaborate from Unity Technologies
    39. Further reading
  15. Controlling and Choosing Positions
    1. Technical requirements
    2. Using a rectangle to constrain 2D Player object movement
    3. Getting ready
    4. How to do it...
    5. How it works...
    6. There's more...
    7. Drawing a gizmo yellow rectangle to visually show a bounding rectangle
    8. Player control of a 3D GameObject (and limiting movement within a rectangle)
    9. How to do it...
    10. How it works...
    11. There's more...
    12. Drawing a gizmo yellow rectangle to visually show a bounding rectangle
    13. Drawing thick gizmo lines
    14. Choosing destinations – finding a random spawn point
    15. Getting ready
    16. How to do it...
    17. How it works...
    18. See also
    19. Choosing destinations – finding the nearest spawn point
    20. Getting ready
    21. How to do it...
    22. How it works...
    23. There's more...
    24. Avoiding errors due to an empty array
    25. See also
    26. Choosing destinations – respawning to the most recently passed checkpoint
    27. Getting ready
    28. How to do it...
    29. How it works...
    30. Moving objects by clicking on them
    31. Getting ready
    32. How to do it...
    33. How it works...
    34. Firing projectiles in the direction of movement
    35. Getting ready
    36. How to do it...
    37. How it works...
  16. Navigation Meshes and Agents
    1. Technical requirements
    2. NPC to travel to destination while avoiding obstacles
    3. Getting ready
    4. How to do it...
    5. How it works...
    6. NPC to seek or flee from a moving object
    7. Getting ready
    8. How to do it...
    9. How it works...
    10. There's more...
    11. Using a Debug Ray to show a source-to-destination line
    12. Constantly updating the NavMeshAgent's destination to flee from the player's current location
    13. Maintaining a constant distance from the target ("lurking" mode!)
    14. Point-and-click move to object
    15. Getting ready
    16. How to do it...
    17. How it works...
    18. There's more...
    19. Creating a mouseover yellow highlight
    20. Point-and-click move to tile
    21. Getting ready
    22. How to do it...
    23. How it works...
    24. There's more...
    25. Using a yellow debug ray to show the destination of the AI agent
    26. Point-and-click raycast with user-defined, higher-cost navigation areas
    27. Getting ready
    28. How to do it...
    29. How it works...
    30. There's more...
    31. More intelligent pathfinding by setting different costs for custom-defined navigation areas such as mud and water
    32. Improving the UX by updating a "gaze" cursor each frame
    33. NPC NavMeshAgent to follow waypoints in a sequence
    34. Getting ready
    35. How to do it...
    36. How it works...
    37. There's more...
    38. Working with arrays of waypoints
    39. Increased flexibility with the WayPoint class
    40. Controlling object group movement through flocking
    41. Getting ready
    42. How to do it...
    43. How it works...
    44. Creating a movable NavMesh Obstacle
    45. Getting ready
    46. How to do it...
    47. How it works...
    48. Further reading
  17. Cameras and Rendering Pipelines
    1. Technical requirements
    2. Creating the basic scene for this chapter
    3. Getting ready
    4. How to do it...
    5. How it works...
    6. There's more...
    7. Working with a fixed Main Camera
    8. Getting ready
    9. How to do it...
    10. How it works...
    11. Changing how much of the screen a camera renders to
    12. Getting ready
    13. How to do it...
    14. How it works...
    15. There's more...
    16. Using Render Textures to send camera output to places other than the screen
    17. Getting ready
    18. How to do it...
    19. How it works...
    20. There's more...
    21. Inverting our mirror camera horizontally
    22. A simple snapshot of a scene at runtime
    23. Working with Unity's multipurpose camera rig
    24. How to do it...
    25. How it works...
    26. Using Cinemachine ClearShot to switch cameras to keep the player in shot
    27. Getting ready
    28. How to do it...
    29. How it works...
    30. There's more...
    31. Unity Cinemachine tutorials
    32. Will Goldstone's ClearShot tutorial
    33. Adam Myhill's Cinemachine blog posts
    34. Reading the installed Cinemachine documentation
    35. Cinemachine and Timeline
    36. Letting the player switch to a Cinemachine FreeLook camera
    37. Getting ready
    38. How to do it...
    39. How it works...
    40. Creating a project with the URP
    41. Getting ready
    42. How to do it... 
    43. How it works...
    44. Adding a vignette effect
    45. Getting ready
    46. How to do it...
    47. How it works...
    48. There's more...
    49. Creating an HDRP project with an HDRI skybox
    50. Getting ready
    51. How to do it...
    52. How it works...
    53. Further reading
  18. Shader Graphs and Video Players
    1. Technical requirements
    2. Playing videos by manually adding a VideoPlayer component to a GameObject
    3. Getting ready
    4. How to do it...
    5. How it works...
    6. There's more...
    7. Using scripting to control video playback on scene textures
    8. Getting ready
    9. How to do it...
    10. How it works...
    11. There's more...
    12. Downloading an online video (rather than a clip)
    13. Ensuring a movie is prepared before playing
    14. Getting ready
    15. How to do it...
    16. How it works...
    17. There's more...
    18. Ensuring that the movie has been prepared before playing it with coroutines
    19. Outputting video playback to a RenderTexture asset
    20. Getting ready
    21. How to do it...
    22. How it works...
    23. Using scripting to play a sequence of videos back to back
    24. Getting ready
    25. How to do it...
    26. How it works...
    27. Creating and using a simple Shader Graph
    28. How to do it...
    29. How it works...
    30. Creating a glow effect with Shader Graph
    31. Getting ready
    32. How to do it...
    33. How it works...
    34. Toggling a Shader Graph color glow effect through C# code
    35. Getting ready
    36. How to do it...
    37. How it works...
    38. There's more...
    39. Further reading
    40. Shader Graph online resources
    41. Video player online resources
  19. Advanced Topics - Gizmos, Automated Testing, and More
    1. Technical requirements
    2. Using Gizmo to show the currently selected object in the Scene window
    3. How to do it...
    4. How it works...
    5. See also
    6. Creating an editor snap-to-grid drawn by a Gizmo
    7. How to do it...
    8. How it works...
    9. There's more...
    10. Saving and loading player data – using static properties
    11. Getting ready
    12. How to do it...
    13. How it works...
    14. There's more...
    15. Hiding the score before the first attempt is completed
    16. See also
    17. Saving and loading player data – using PlayerPrefs
    18. Getting ready
    19. How to do it...
    20. How it works...
    21. See also
    22. Loading game data from a text file map
    23. Getting ready
    24. How to do it...
    25. How it works...
    26. Saving data to a file while the game is running
    27. How to do it...
    28. How it works...
    29. See also
    30. Generating and running a default test script class
    31. How to do it...
    32. How it works...
    33. There's more...
    34. Creating a default test script from the Project window's Create menu
    35. Edit mode minimum skeleton unit test script
    36. A simple unit test
    37. How to do it...
    38. How it works...
    39. There's more...
    40. Shorter tests with values in the assertion
    41. Expected value followed by the actual value
    42. Parameterizing tests with a data provider
    43. How to do it...
    44. How it works...
    45. Unit testing a simple health script class
    46. How to do it...
    47. How it works...
    48. Health.cs
    49. TestHealth.cs
    50. Creating and executing a unit test in PlayMode
    51. How to do it...
    52. How it works...
    53. PlayMode testing a door animation
    54. Getting ready
    55. How to do it...
    56. How it works...
    57. There's more...
    58. PlayMode and unit testing a player health bar with events, logging, and exceptions
    59. Getting ready
    60. How to do it...
    61. How it works...
    62. PlayMode testing
    63. Unit tests
    64. See also
    65. Reporting Code Coverage testing
    66. Getting ready
    67. How to do it...
    68. How it works...
    69. Running simple Python scripts inside Unity
    70. How to do it...
    71. How it works...
    72. Further reading
  20. Particle Systems and Other Visual Effects
    1. Technical requirements
    2. Exploring Unity's Particle Pack and reusing samples for your own games
    3. How to do it...
    4. How it works...
    5. Creating a simple particle system from scratch
    6. How to do it...
    7. How it works...
    8. Using Texture Sheets to simulate fire with a particle system
    9. Getting ready
    10. How to do it...
    11. How it works...
    12. Making particles collide with scene objects
    13. How to do it...
    14. How it works...
    15. There's more...
    16. Simulating an explosion
    17. Getting ready
    18. How to do it...
    19. How it works...
    20. Using Invoke to delay the execution of an explosion
    21. Getting ready
    22. How to do it...
    23. How it works...
    24. There's more...
    25. Further reading
  21. Virtual and Augmented Reality (VR/AR)
    1. Technical requirements
    2. Setting up Unity for VR
    3. How to do it...
    4. How it works...
    5. Setting up an Oculus Quest/2 in Developer Mode
    6. Getting ready
    7. How to do it...
    8. How it works...
    9. Creating a VR project for the Oculus Quest/2
    10. Getting ready
    11. How to do it...
    12. How it works...
    13. There's more...
    14. Build failure due to Android version
    15. Build failure due to "namespace cannot be found" error
    16. Sideloading APK files to an Android device (such as the Quest headset)
    17. Creating a VR project using the Mock HMD device
    18. Getting ready
    19. How to do it...
    20. How it works...
    21. Working with the Mozilla demo WebXR project
    22. Getting ready
    23. How to do it...
    24. How it works...
    25. There's more...
    26. Using GitHub Pages to publish your WebXR project for free
    27. Learning more about the WebXR example project
    28. Fixing pink (shader/material) problems
    29. The community maintaining more up-to-date XR resources
    30. Fixing obsolete code errors
    31. Adding 360-degree videos to a VR project
    32. Getting ready
    33. How to do it...
    34. How it works...
    35. There's more...
    36. Playing 360-degree videos on the surface of a 3D object
    37. Exploring the Unity AR samples
    38. Getting ready
    39. How to do it...
    40. How it works...
    41. There's more...
    42. Targeting iOS device builds
    43. Allowing Android APK file downloads on your phone
    44. Setting up Unity for AR
    45. How to do it...
    46. How it works...
    47. There's more...
    48. Build failure due to Android version
    49. Build failure due to Vulkan API graphics settings
    50. Creating a simple AR Foundation project
    51. Getting ready
    52. How to do it...
    53. How it works...
    54. Detecting and highlighting planes with AR Foundation
    55. Getting ready
    56. How to do it...
    57. How it works...
    58. Creating an AR furniture previewer by detecting horizontal planes
    59. Getting ready
    60. How to do it...
    61. How it works...
    62. Creating a floating 3D model over an image target
    63. Getting ready
    64. How to do it...
    65. How it works...
    66. Further reading

Product information

  • Title: Unity 2021 Cookbook - Fourth Edition
  • Author(s): Matthew Smith, Shaun Ferns
  • Release date: September 2021
  • Publisher(s): Packt Publishing
  • ISBN: 9781839217616