Blueprint Generating Procedural Rooms | Live Training | Unreal Engine
Introduction to Procedural Generation
Overview of the Stream
- The stream marks the first session of the new year, with a warm welcome and New Year wishes to viewers.
- Technical writer Ian Shadon introduces his project focused on generating dungeons through tile-based random generation for a turn-based strategy game.
Project Details
- Ian mentions that the project will be available online after the stream, likely next week.
- He discusses creating a new actor in Unreal Engine, emphasizing common pitfalls in procedural map generation.
Challenges in Procedural Map Generation
Common Issues Faced
- Many beginners struggle with using static meshes for procedural generation, leading to performance issues when generating numerous actors.
- Instead of traditional methods, Ian suggests using instant static mesh components for faster generation.
Implementation Steps
- Initial setup involves defining variables such as Max X and Max Y for grid dimensions and tile size.
- These variables are exposed for easy adjustments; default values are set at 32x32 tiles with each tile measuring 100x100 units.
Creating a Grid Layout
Looping Through Tiles
- Ian explains how to calculate the total number of tiles by multiplying Max X and Max Y, adjusting for zero indexing.
- A loop is established to iterate through these calculations, converting indices into coordinates suitable for placement in world space.
Transformations and Instance Creation
- The calculated grid locations are multiplied by tile size to determine their positions in world space.
- A vector is created from these coordinates to add instances into the instant static mesh component effectively.
Debugging and Adjustments
Testing Generated Grids
- After implementing changes, Ian tests by dragging the generated floor into the world but encounters an issue due to miscalculations.
- A viewer points out an error related to division versus multiplication during instance addition; this feedback proves valuable.
Performance Insights
- With corrections made, Ian demonstrates rapid grid generation capabilities without significant performance drops compared to traditional methods.
Generating a Dynamic Map in Unreal Engine
Understanding the Initial Setup
- The speaker discusses the limitations of the generated floor, noting that it lacks collision and is not useful for gameplay.
- A proposal is made to create an array called
tile typeto represent different elements of the map (e.g., floors, walls, corners).
- The initial setup involves filling this array with zeros for floors, ones for walls, and so forth.
Efficient Array Management
- To optimize performance, the speaker emphasizes resizing the array only once based on known dimensions rather than repeatedly during loops.
- The process includes setting all elements of the array to zero using a loop that matches indices.
Adding Complexity with Randomization
- After initializing the array, another loop iterates through
tile type, allowing for more complex structures beyond just a flat plane.
- The introduction of random integers allows for varied generation of pillars and floors instead of uniformity.
Performance Considerations
- The speaker highlights efficiency in rendering by mentioning only two draw calls plus shader processing involved in generating dynamic maps.
- A comparison is made between static mesh components and dynamic generation methods regarding performance benefits.
Addressing Common Issues
- A question arises about whether resizing takes into account length or last index; clarification indicates both should yield similar results.
- Discussion touches on common programming pitfalls like off-by-one errors when defining grid sizes.
Methodology Overview
- The speaker shares their approach using quad trees to define room layouts within generated maps.
- An overview of eight distinct tiles used in creating a randomly generated map is provided as part of their methodology.
Dynamic Lighting and Quad Tree Structure in Game Development
Understanding Shadows and Light Interaction
- The speaker discusses how light sources cast shadows, demonstrating the visibility of shadows when positioned correctly.
- When lights are moved further away, they no longer cast distinct shadows but instead create an overlap with a crossfade effect between different lights, enhancing visual efficiency.
- The importance of dynamic lighting is emphasized; static lighting can severely limit performance when more than 20 lights are used.
Quad Tree Implementation for Room Generation
- Introduction to quad trees: a spatial partitioning structure that divides space into smaller squares recursively, aiding in efficient room generation.
- The speaker explains how quad trees help define room-like structures within a game map by identifying breaks and divisions in space.
- Randomness plays a significant role in defining room sizes and placements within the quad tree structure, allowing for varied gameplay environments.
Construction Process of Game Rooms
- The game mode controls the construction process, ensuring data flows seamlessly between different components during initialization.
- A random stream is utilized to maintain consistency across room generation; initial boundaries are set up using functions that spawn new quadrants based on defined parameters.
Room Size Constraints and Creation Logic
- Mathematical constraints limit the size of generated rooms to prevent them from becoming too small or unmanageable during creation cycles.
- Random slicing along X and Y axes generates new rooms while checking if they fit within specified dimensions (minimum size, wall thickness).
Finalizing Room Structures
- Once rooms are created successfully, they are added to an expanding array that tracks all generated quads for further processing.
Dungeon Design and Actor Utilization
Connecting Dungeon Areas
- The discussion begins with the concept of connecting different areas of a dungeon, emphasizing that they do not need to be on the same level or related (e.g., siblings).
Utilizing Actors as Data Classes
- Programmers can use actors in Unreal Engine similarly to data classes, allowing for rapid creation without rendering overhead. This is particularly useful when managing numerous collision objects.
Collision Objects and Their Purpose
- Thousands of collision objects are utilized within the game environment, each represented by an actor. These serve various functions such as defining mouse-over interactions and unit team assignments.
Efficiency of Non-rendering Actors
- Creating non-rendering empty actors is efficient for holding data, although not as optimal as using C++ classes. However, it remains a practical solution for many developers.
Random Room Placement in Dungeons
- It is possible to randomly place pre-crafted rooms within the dungeon layout. Developers can insert these rooms based on size compatibility with existing structures.
Distance Fields and Light Mapping
Distance Field Generation Capabilities
- Recent updates allow instant static mesh components to utilize distance fields effectively, addressing previous issues where instances were incorrectly positioned at the origin.
Light Mapping Considerations
- There are uncertainties regarding light mapping capabilities for dynamically generated content at runtime; however, if built correctly in construction scripts, light mapping may be feasible.
Room Spawning Mechanics
Defining Pre-crafted Rooms
- Developers can designate specific rooms (like a starting room or boss chamber) while allowing other rooms to spawn randomly based on defined parameters like proximity calculations.
Parameters for Room Connections
- Rooms must meet minimum size requirements and wall thickness specifications to ensure proper connections between them during random spawning processes.
World Generation Techniques
Quad Tree Generation Overview
- The quad tree generation establishes boundaries for room placement. Following this step, grid data is used to create actual room tiles based on these boundaries.
Boundary Calculations
Room Generation Techniques
Defining Room Boundaries
- The speaker discusses an unconventional method for defining room boundaries, suggesting that it may be easier to generate random numbers from the sides to establish a center point.
- A main room is defined with a range around its center, which influences the size of smaller rooms generated within this space.
Random Stream Utilization
- The use of random streams is highlighted as beneficial; saving a seed allows for map regeneration without needing to save the entire map.
- The current unit generation process has not been refactored yet, but all other aspects of the map are influenced by the stream.
Calculating Room Dimensions
- The process involves comparing generated values against predefined boundaries to determine room dimensions while considering wall borders.
- A series of conditional checks are performed to adjust half X and half Y values based on comparisons with maximum room sizes.
Room Generation Logic
- New room dimensions are established through random number generation between minimum sizes and calculated half values, leading to successful or unsuccessful room generation outcomes.
- If a room cannot fit due to size constraints, adjustments are made until valid dimensions are found.
Tile Digging Process
- The logic for determining tile placement involves checking if tiles can fit within the newly generated space before proceeding with digging operations.
- Tiles are spawned based on new sizes and positions, including a chance mechanism for adding lighting features in rooms.
Implementing 2D Array Logic
- The digging process requires determining boundaries and using nested loops for efficient tile placement from left-to-right or top-to-bottom based on size comparisons.
- A macro is created to convert XY coordinates into a one-dimensional index suitable for array manipulation since two-dimensional arrays aren't available in blueprints.
Finalizing Room Types
- After successfully digging out rooms, types such as hollow spaces and corridors are assigned numerical identifiers (e.g., hollow = 0, corridor = 2).
Room Generation and Connection Logic
Overview of Leaf Nodes and AABBs
- The discussion begins with the handling of leaf nodes, focusing on blanking out a set of variables related to rooms contained within an Axis-Aligned Bounding Box (AABB) passed from outside.
- All generated AABBs from a quad tree are filtered in, which is crucial for generating connections between rooms that are not siblings.
Room Connectivity Checks
- The process involves querying the AABB to check if it has children; actions depend on whether the length is greater than zero.
- Various tests are conducted to determine room existence and sibling relationships, leading to distance checks for connection purposes.
Finding Closest Rooms
- The algorithm identifies the closest leaf room that isn't already connected, preventing orphaned rooms or excessive connections.
- Distance comparisons help establish which room should be connected next based on proximity.
Connecting Child Rooms
- For connecting child rooms, a round-robin approach is utilized, visualized as rooms forming a 'C' shape during generation.
- An example illustrates how sibling rooms connect while adhering to specific logic constraints.
Corridor Digging Logic
Corridor Creation Process
- The function responsible for digging corridors operates by tracing paths between room centers at angles, creating L-shaped corridors.
- Tile types are set accordingly; specifically, type '2' represents corridor tiles.
Finalizing Floor Layout
- After corridor creation, only floors would remain visible if rendered without additional elements since corridors count as floor space.
Wall Generation Mechanism
Wall Generation Functionality
- The wall generation process involves iterating through tile types and determining boundaries based on neighboring tiles’ states (zeros or ones).
- By assessing eight surrounding directions in a 2D array format, walls can be accurately constructed based on adjacent tile information.
Iteration Through Tile Types
- This function returns surrounding tiles' statuses and uses this data to inform wall placement decisions effectively.
Understanding Wall and Floor Logic in Game Design
Initial Setup and Looping Through the Array
- The process begins by checking for neighbors to determine if a floor exists. If not, the array index is set to 99, representing a base wall.
- A loop is initiated to identify walls within the test array, asking specific questions about neighboring tiles (north, south, east, west).
Identifying Wall Types
- The logic assesses whether adjacent tiles are walls or floors to classify the current tile as a single wall section or part of a larger structure.
- Various configurations are evaluated: if both north and south are walls, it indicates a wall; if north and east are walls, it may suggest a corner.
Corner and Pillar Detection
- Outside corners are identified based on surrounding tile types; if north and east are walls while south and west are floors, it's likely an outside corner.
- If none of the previous conditions hold true after extensive testing, the tile is classified as an inside corner or pillar depending on its surroundings.
Finalizing Tile Types
- After looping through all tiles again for detailed tests on inside corners, instances of each type are added efficiently.
- The system checks if filler has been created for styles before generating static meshes. Each tile type is stored in an array for future use.
Collision Generation and Pathfinding Integration
- Once all tests conclude successfully, collision generation occurs based on defined tile types (walls, corridors).
- The grid completion triggers pathfinding preparations using the established tile type array.
Visual Choices in Game Design
Rendering Blank Tiles
- Discussion arises regarding rendering blank tiles with light; setting them to UNL black creates a more immersive underground environment.
Character Interaction with Environment
- Considerations include how characters interact with their surroundings—like boring through terrain—while maintaining visual appeal without excessive draw calls.
Managing Visibility with Portals
Exploring Efficient Room Generation Techniques
Visual Testing and Map Efficiency
- The speaker discusses visual testing in a corridor setting, emphasizing the importance of visibility as characters approach rooms.
- They mention that as characters move out, certain rooms could disappear to enhance efficiency, suggesting that not all areas need to be visible at once.
Instant Static Mesh Components
- A question arises about instant tech mesh actors; the speaker clarifies that they are primarily components rather than standalone actors.
- The process of converting static meshes into blueprints is explained, allowing for more efficient management of repeated elements like windows and doors.
Procedural Generation and Terrain Linking
- The discussion shifts to procedural generation limitations, questioning if terrains can link with other grids. The speaker speculates on potential methods for linking terrain pieces effectively.
- They propose using islands in an ocean scenario where terrain forms based on specific locations, hinting at possible implementations.
Room Generation Strategies
- A query about generating rooms from a central point leads to a confirmation that this method is feasible by adjusting indices accordingly.
- The conversation touches on navigation data usage for determining room placement relative to starting points, highlighting the speed advantages of using EQS over traditional methods.
Draw Call Management
- The speaker explains how instance static mesh components help reduce draw calls significantly compared to individual static mesh components.
What Makes Efficient Level Generation Possible?
Advantages of Level Generation Techniques
- The speaker highlights the efficiency of a specific level generation method, noting its quick rendering and generation capabilities, which they describe as "magic."
- They reference an early version created by a user named Amber on forums during Unreal Engine 4's beta phase, emphasizing tightly packed corridors and rooms.
- The speaker expresses their intention to create compact combat scenarios reminiscent of Diablo, indicating that design choices depend heavily on the game's objectives.
- Speed is emphasized; blueprint compilation takes about 10 seconds while map generation for a 64x64 area takes under two seconds.
Implementing Navigation Meshes
- Initially, the navigation mesh (nav mesh) was non-functional, prompting the speaker to devise their own solution using tile data.
- They mention utilizing A* pathfinding algorithm principles to determine efficient routes within the game environment.
Understanding A* Pathfinding
- The A* algorithm is described as a method for finding the most efficient path towards a goal by evaluating distances and potential obstacles along various routes.
- The choice of tile size matching player dimensions (100 units) simplifies development processes and interactions within the game world.
Path Node Implementation
- The speaker discusses using an actor as a data class for path nodes that store relevant A* data temporarily but effectively aids in navigation tasks.
Navigational Logic and Optimization
- Key logic points include checking if the last node equals the end node to confirm successful pathfinding or breaking out if search limits are reached.
- Various factors such as terrain type (e.g., oil tiles affecting movement speed), valid directions for movement, and diagonal cutting options are considered in route calculations.
- Emphasis is placed on avoiding duplicate nodes and adjusting goals based on proximity to ensure efficient navigation through complex environments.
Error Handling in Grid Navigation
- The importance of managing out-of-range errors when accessing grid locations is discussed, highlighting how these can lead to log spam during development.
- Strategies for improving log readability include ensuring proper data handling during first-time operations within grid systems.
Pathfinding and Object Placement Techniques
Pathfinding Logic and Optimization
- The pathfinding algorithm is designed to minimize unnecessary computations by ensuring that the M close array only triggers when it is empty, thus reducing spam.
- Various mathematical methods for pathfinding are discussed, including Manhattan distance and diagonal shortcuts. Users can swap algorithms based on project settings.
- Increasing map size (e.g., 512x512) requires significant iterations (up to two billion), emphasizing the need for efficient tile generation.
- A tiebreaker mechanism is established for determining valid paths, focusing on setting new F values and managing path nodes effectively.
- The character controller integrates the found path into gameplay mechanics, allowing manual movement of pawns without relying on character movement components.
Mesh Placement Strategies
- Questions arise about placing multiple meshes evenly along structures like walls or temples; a grid-based approach is suggested for optimal placement.
- Instead of simple directional checks, a more complex method involves assessing multiple layers above and below to determine wall placements accurately.
- Room dimensions play a crucial role in object placement; understanding room size allows for strategic positioning of items like torches or campfires within defined spaces.
- Specific implementation details include calculating boundaries based on object sizes to ensure proper placement without overlap against walls or other objects.
- Random coordinate selection within adjusted boundaries facilitates dynamic object placement while maintaining spatial integrity in room design.
Enhancing Environmental Design
- The process includes generating additional data during wall creation to enhance environmental features such as lighting elements strategically placed throughout rooms.
- To avoid cluttered visuals, lights must be spaced adequately apart (e.g., 15 units), preventing excessive illumination that detracts from ambiance.
Encounter Generation and Room Difficulty
Defining Encounter Difficulty
- The discussion begins with the challenge of defining the difficulty of a room or encounter in game design, emphasizing that random generation is not ideal.
- Key factors for determining difficulty include environmental influences such as temperature (hot or cold), moisture levels, and an "evil" modifier to represent overall challenge.
Environmental Influences on Encounters
- Specific environmental conditions can dictate the types of monsters encountered; for example, a furnace in a room may lead to fire-based monsters due to higher ambient temperatures.
- Reference is made to a map generator by Zeus, who utilizes similar data-driven approaches for efficient encounter generation. His work reportedly allows for quick generation times even for large maps.
Community Engagement and Resources
- There’s mention of community feedback regarding the complexity of Zeus's blueprints, indicating they are highly detailed and effective.
- Participants are encouraged to look up Zeus's work online, highlighting its impressive nature and potential utility in game development.
Future Availability and Updates
- Information is provided about when the video will be available on Twitch and YouTube, ensuring viewers know where to find it post-session.
- The team plans to monitor forum posts for questions after the session ends, indicating ongoing community support and engagement.
Closing Remarks