<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: CBanks901</title>
    <description>The latest articles on DEV Community by CBanks901 (@cbanks901).</description>
    <link>https://dev.to/cbanks901</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F822957%2F13a46aa3-ddec-4095-9f12-4730673b1073.png</url>
      <title>DEV Community: CBanks901</title>
      <link>https://dev.to/cbanks901</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cbanks901"/>
    <language>en</language>
    <item>
      <title>RPG Boss Combat Design</title>
      <dc:creator>CBanks901</dc:creator>
      <pubDate>Fri, 11 Mar 2022 00:44:25 +0000</pubDate>
      <link>https://dev.to/cbanks901/rpg-boss-combat-design-4k7m</link>
      <guid>https://dev.to/cbanks901/rpg-boss-combat-design-4k7m</guid>
      <description>&lt;p&gt;Today I'd like to talk about the process that I used to create a fully fledge rpg boss fight simiulation inside Unreal Engine 4. Before I start though there are a few disclaimers I'd like to make first which are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I use a Framework here for basic mechanics like shooting, collision, and actions or animation triggers&lt;/li&gt;
&lt;li&gt;This project was built inside unreal engine and all additional programming code was done by me&lt;/li&gt;
&lt;li&gt;Sample screenshots can be found &lt;a href="https://www.cakeresume.com/portfolios/dragon-boss-fight" rel="noopener noreferrer"&gt;at&lt;/a&gt; on my CakeResume page, the project code on my Github (since the project is large I only have the executable on here for now), and the video can be found &lt;a href="https://www.youtube.com/watch?v=rJ-sXitNokc" rel="noopener noreferrer"&gt;here&lt;/a&gt; on YouTube&lt;/li&gt;
&lt;li&gt;I will only be covering some of the most important aspects of the code here because the project is simply too large for me to cover everything, as such a lot of additional details will be skipped for simplicity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With that out of the way, I'll go ahead and begin the process I used to create this project, particularly the boss itself and the experience that i wanted it to be.&lt;/p&gt;

&lt;p&gt;Here is a overview of the things I wanted in the boss fight:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Dragon flight (at least a few determined paths).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fire projectiles since he's a dragon why not XD&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Bite grab animation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Smaller allies which come in to replace him until they are beaten&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Knockdown section when it takes too much elemental damage&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pushback particularly when screaming&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of these I was able to achieve to at least some degree if not completely. Below I'll go over some of the challenges that I faced and how I overcame them with some programming thrown into the mix. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.    Dragon&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;• Bite grab&lt;br&gt;
The dragon bite grab functionality is maintained inside the action called bite grab under the notable point reached event. The notable point reached event is a point inside the animation that I placed myself. It is the point where the dragon closes its mouth, so only during this one specific instance will it have a chance to grab the player. If it fails, nothing happens. If the player is invincible, specifically dodging or blocking it will fail to grab them as well. The bite grab action plays the grab animation and if the player is within a certain radius of the dragon’s mouth (a distance of about 2000 including z), then the players movement is disabled and a variable inside of it called sent flying is set to true. This variable is referenced inside the main game modes tick event which basically handles the animation for the player. If the player is ascending then a twist animation is playing, if the player is descending or falling then a fall animation is played until they reach the ground. Once they reach the ground, a final animation plays which recovers their stance. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ksqjsuns3iwbsq3xy4w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ksqjsuns3iwbsq3xy4w.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6cu6z29syuqcntvr0tme.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6cu6z29syuqcntvr0tme.png" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
• Attacks&lt;br&gt;
Most actions are easily executed using the ACF framework. It works similar to the normal workflow inside the engine where it allows you to handle attacks and collisions in certain places if you’d like. In this project, I set up the collision components mostly on the dragons’ claws since it doesn’t use any other elements for attacks. No tail swipe unfortunately. The collision component is also set up for the player and damage is also handled by the system. Nothing special goes on inside the actions with the exception of the bite grab&lt;/p&gt;

&lt;p&gt;• Flying (detailed)&lt;br&gt;
When the dragon’s health goes below 50%, it has a chance to activate its flying actions. This is done with a function called Initiate Flight path. In summary what it does is use a timeline to interpolate along a specific path. The path chosen is determined basically randomly using integer values and I set up a function that takes care of this for me when this event is called. Using a random integer, it determines a spline and then stores it into a variable called ActiveSpline. The timeline is only using a basic float value of 1, but the duration is reduced by a tenth so it’s longer. Once this timeline has fully executed it resets the dragons normal moveset (since at the start of this it’s changed to flight after it moves to a specified spot), and the target (player) is reinitialized because it is disabled when it moves to fly. This isn’t a full description but this picture shows the workflow of this function:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F40af6lwbmzp8a3a7ejrg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F40af6lwbmzp8a3a7ejrg.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F75u8lgqvgtinh2ha7oru.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F75u8lgqvgtinh2ha7oru.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpccilb9eakmyl48bo9pb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpccilb9eakmyl48bo9pb.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxgsb8kufygrhi2uwaem1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxgsb8kufygrhi2uwaem1.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjzba6ijnivkbttrhzyy4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjzba6ijnivkbttrhzyy4.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzbbwazqw9qyy5zm63fyv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzbbwazqw9qyy5zm63fyv.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa07iw2hml0md58ol7ope.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa07iw2hml0md58ol7ope.png" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
• Knockdown&lt;br&gt;
This knockdown portion utilizes the ACF framework itself. All it does is when the amount of damage sustained is greater than a certain amount (200), then the dragon is knocked down for a sustained period of time, about 15 to 30 seconds. During this point he is wide open to do anything to him. Afterwards he gets up and recovers, then he pushes you back if you’re close enough. This is done with a recovery action.&lt;/p&gt;

&lt;p&gt;• Fire breaths (detailed)&lt;br&gt;
Fireballs are broken into 4 separate types which are the spread fire normal, spread fire (ground), shoot fire ball air, and shoot fire ball. All of these are actions that are executed normally with the exception of the air shot. The shoot fire ball ones are pretty self-explanatory. They shoot fire balls at the player. The only thing that is done during the process is the direction is adjusted to accurately match the player. The air shot however only occurs once the dragon has taken one of the two pre-determined flight paths and is done after the dragon’s health has gone down by about 25% or a little less. The spread fire normal one shoots fire from the mouth and is different from a ball. It spreads fire from its mouth in a normal left to right spray burst. As such there are traces that are spawned in so that it appears that sparks from the mouth leave small residues that can damage the player on impact. They fade after about a few seconds however. Finally, the last type is spread fire (close). This one only occurs when the player is in close proximity of the dragon itself and as such spreads fire more closely to the ground. It works similar to the regular spread but the range of fire is much smaller and focused. &lt;/p&gt;

&lt;p&gt;• Minion Spawn &lt;br&gt;
How the minion spawn works is after the dragon’s health drops below a certain threshold, it has a chance to trigger an action known as the CallAllies action. The call allies action immediately makes the dragon levitate off the ground from wherever it is over a set period of time, about 10 seconds. There after that it moves towards a pre-determined spot on the side of the area. It is simple a scene component. Once it reaches this scene component, it disappears from view and five dragon minions spawn from that location and come flying down. The camera transitions so the player sees it from that perspective and they land in after a while. I did some simple programming using other scene components so that they all land good distances around from each other onto the scene. These actors spawn in though inside the dragon from a custom event known as callallies movement. It is proceeded by a function first though called CallAllies Sequence which initializes the basic things such as the count and gets things ready. The CallAllies Movement function simply takes care of the heavy lifting such as the spawning and making sure that the number of acts matches the limit of five in this case. Once they have all finished spawning, I created a function inside of them that is called shortly after their creation which handles their flight path to the ground. Once they have all been defeated the main dragon reappears from the spot it disappeared in and then proceeds to land back onto the field.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.    Player&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;• Grab response (bite)&lt;br&gt;
This is mostly handled and started by the dragon itself. When the dragon’s action is executed and succeeds, it disables all movement from the player until they get up and recover, which is near 8 seconds when it finally touches the ground. It gets very messy, but the code that handles this specific portion is inside the bottom portion of the Main Character Falling Handler which is inside the active game mode. Actually, the entire function itself handles the process from when the character is grabbed to flying and then recovering. There is a sequence of events that goes from one to the other until it reaches the bottom portion which I described. It’s big so I’m only going to specifically show the recovery code: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcgygxifusd5l5xf0cvj1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcgygxifusd5l5xf0cvj1.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu2cc9ezj0vok88jr9a1d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu2cc9ezj0vok88jr9a1d.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;• Abilities (fire, block, dodge)&lt;br&gt;
The player has an array of abilities in this simulation including a cloth swap, wolf summon, projectile fire shot, dash, block and dodge. With the exception of block and dodge, everything else applies damage in some way to an enemy. The wolves are an array of allies that I made that spawn near both sides of the player. There are about 8 of them total. All they do is play jumping animations and make a sound effect. Their collision zone is wide to account for the short distance they actually jump. They do a set amount of damage each when they connect so it isn’t a full-on application when one hits. The dash ability is what it sounds like in that it’s a magical dash burst over a short distance. The cloth swap simply changes the skeletal mesh to a different one along with a sample animation that I picked. The projectile fire shot shoots out a fire projectile in a linear straight line from the center of the sword (the body actually so it looks like it is, along with a spacing gap so it’s not coming out of the character body per say). As for blocking and dodging, they have custom animations as well, however they both have invincibility frames in between the animations so that damage can’t be applied to the character. I did this by adding substates (custom notify points) inside the animations themselves that once passed and exited, this feature is enabled and then disabled respectively. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.    Environment&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;• Invisible walls&lt;br&gt;
Most of the collisions that contain the player are controlled by one actor called WallV2_Bp. This blueprint is customized to specifically fit this area perfectly. It is composed of a series of box collisions that can be customized to fit any scene. I only added the ones I needed but more can be added as well. How this blueprint works is that it casts references to check if the incoming player reference is a player or not. If it is a player, then the collision is enabled. Once off the wall they are disabled. Why you ask? This is because I want the dragon as well as his minions to pass through this unaffected but also to contain the player until the dragon is defeated. Once defeated, these barriers become inactive. &lt;/p&gt;

&lt;p&gt;This is inside the level itself: &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fml0tw830avewhau9wdb1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fml0tw830avewhau9wdb1.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh20bk41x67ae8uvpdole.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh20bk41x67ae8uvpdole.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And this is the Blueprint itself: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh5n43kgkgw83zp4of342.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh5n43kgkgw83zp4of342.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;• Portal &lt;br&gt;
This portal only spawns once the dragon is defeated. Once it is defeated it disables it’s dragon boss widget from the viewport, stops the boss music from playing, and finally gets a player reference to call LookAtPortal. LookAtPortal is a special function inside the player that handles the spawning of both the final portal as well as the camera placement which interpolates to a static spot where it can be seen, specifically using set view target with blender. Finally, it zooms back into the player.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpvs00y1lxzcyyyv9pzbe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpvs00y1lxzcyyyv9pzbe.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;• Dragon paths &lt;br&gt;
Dragon Flight paths are actors with spline components attached to them. They are placed in the level and are all static and customized. They are referenced by the dragon AI controller in the beginning by using GetAllActors of class and are stored for easy reference. This variable specifically is called SplineReferences. There are some filters though, such as the entrance spline which is the one the dragon uses to come into the level. This spline is excluded from the list because it is only used once which is at the beginning. Here is a picture of some of them placed inside the level and it being reference by the AI controller: &lt;/p&gt;

&lt;p&gt;This is inside the level: &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F82ml5j9e3zsknna0e46d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F82ml5j9e3zsknna0e46d.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These two are inside the AI controller:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm09ezajawfykt8susoh2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm09ezajawfykt8susoh2.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn4nvoj02uoz9692t8xlx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn4nvoj02uoz9692t8xlx.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;• Start Zone&lt;br&gt;
I’ve called this DragonSpawnTrigger. It is simply an actor with a overlap component. When the game begins it simply gets a reference to the level sequencer event that are placed inside the level. Then when the player overlaps them, it plays the event and spawns the dragon from the start of the entrance spline of the dragon. When this short sequence is finished this actor is destroyed as this only needs to happen once. A special event was created inside the dragon actor itself to handle this special instance since normal spawning doesn’t account for this. It uses a timeline to bring it to the ground. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9phqg3fo8cc7isa6a0t9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9phqg3fo8cc7isa6a0t9.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;• Level Sequencer&lt;br&gt;
The level sequencer is merely a reference that is used in the start zone. After this it serves no purpose. I use a cinecameraactor that is placed at a specific location so that the angle zooms in from there (which is on the side) and a reference to the entrance spline itself. Here is an image of the sequence itself:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F92hczuoae6w4r3awdw0z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F92hczuoae6w4r3awdw0z.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.    Miscellaneous&lt;/strong&gt;&lt;br&gt;
• Menus (Pause, Credits, Death screen)&lt;br&gt;
All menus used in this project are simply widgets that were created by me with different specifications. The pause menu pauses the simulation and allows you to quit, exit, and selection the options menu which lays out the controls. It is activated by pressing the 1 key. The Death widget appears when you are destroyed and then respawns or terminates the application depending on the user selection. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Post Mortem:&lt;/strong&gt; &lt;br&gt;
I actually learned quite a lot from this project about both Unreal as well as the Framework that I used here. While I'm not ashamed per say about how things turned out, I did learn that there are better ways to do things and alternatives. One instance is the player recovery process. It uses tick from the main game mode, but looking back on it now, it would simply be better for me to attach this to the animation itself and add notifies that take care of this since it will only be called at the end of the animation. Not to mention I use float values that are hardcore for the recovery time as well as handlers which both of these would be unnecssary if I'd just done it in the animation itself which has the information I need. The entire process lead basically to more organizational structure code wise to make it neater and tricks here and there. My projects now aren't nearly this messy anymore XD. &lt;/p&gt;

&lt;p&gt;At any rate I'd like to thank you for reading this if you made it to the end. As I said you can find this project on my CakeResume page, on YouTube, and on my github if you'd like to play it for yourself. Till next time. &lt;/p&gt;

&lt;p&gt;Christian Banks&lt;/p&gt;

</description>
      <category>unreal</category>
      <category>blueprint</category>
      <category>ascentcombatframework</category>
    </item>
    <item>
      <title>Black hole force demo</title>
      <dc:creator>CBanks901</dc:creator>
      <pubDate>Fri, 11 Mar 2022 00:35:15 +0000</pubDate>
      <link>https://dev.to/cbanks901/black-hole-force-demo-46kk</link>
      <guid>https://dev.to/cbanks901/black-hole-force-demo-46kk</guid>
      <description>&lt;p&gt;Hello, this a small tech demo showing my take on a black hole force Black hole force for objects, particularly static meshes here. How this works is when these meshes overlap the zone it moves them and then after a certain period of time (ten seconds) it pushes them all outwards with a enormous force akin to an explosion. Almost all of the work done here is done with C++ and Unreal Engine. I'll be breaking down my thought process with this and showing some of the main aspects of the project. If you'd like to see the entire project and/or try it for yourself, please head over to my github page. Without any further delay I'll go into the details.&lt;/p&gt;

&lt;p&gt;For this to work, only two main actors are necessary; the first is the one I've called BlackHoleForce, and the second one I've called BaseMeshActor. Both are simple actor instances. The MainBaseActor is simply the parent and any actual objects are derived from it. This was done so that any objects with that same parent can be counted and added to the array for ease of access. Another important class is the BlackHoleRedoGameModeBase which is the place where I store the counters for the objects on screen. &lt;/p&gt;

&lt;p&gt;I'll start here with the MainBaseActor. &lt;br&gt;
&lt;strong&gt;The following is the header file of this class: MainBaseActor.h&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UCLASS()
class BLACKHOLEREDO_API AMainBaseActor : public AActor
{
    GENERATED_BODY()

public: 
    // Sets default values for this actor's properties
    AMainBaseActor();

    // The root of the object
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Components, meta = (AllowPrivateAccess = "true"))
    class USceneComponent* MainSceneRoot;

    // The mesh of the instance
    UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = Components, meta = (AllowPrivateAccess = "true"))
    class UStaticMeshComponent* Static_Mesh;

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

public: 
    // Called every frame
    virtual void Tick(float DeltaTime) override;

    // The direction in which the instance follows. If true it moves normally, if not it goes the other way.
    UPROPERTY(BlueprintReadWrite)
    bool NormalDirection;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything here is pretty standard with the exception of a few custom variables which include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A StaticMeshComponent(allows subclasses to change this to differnt shapes)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The sceneroot which is just the root of the object.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A custom variable called NormalDirection which tracks the direction in which this object will spin.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;This is inside the MainBaseActor.cpp file:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Sets default values
AMainBaseActor::AMainBaseActor()
{
    // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

    MainSceneRoot = CreateDefaultSubobject&amp;lt;USceneComponent&amp;gt;(FName("Root"));
    MainSceneRoot-&amp;gt;SetWorldLocation(FVector(0, 0, 0));

    // The main static meshcomponent
    Static_Mesh = CreateDefaultSubobject&amp;lt;UStaticMeshComponent&amp;gt;(TEXT("SM"));

    // Make the scene component the root of this object
    RootComponent = MainSceneRoot;

    // disable tick by default
    SetActorTickEnabled(false);

    Static_Mesh-&amp;gt;SetComponentTickEnabled(true);
    Static_Mesh-&amp;gt;bTickInEditor = true;
    Static_Mesh-&amp;gt;SetupAttachment(MainSceneRoot);
    Static_Mesh-&amp;gt;SetWorldLocation(FVector(0, 0, 0) );
    Static_Mesh-&amp;gt;SetSimulatePhysics(true);
    Static_Mesh-&amp;gt;SetEnableGravity(true);
    Static_Mesh-&amp;gt;SetNotifyRigidBodyCollision(true);
    Static_Mesh-&amp;gt;BodyInstance.SetCollisionProfileName(FName("BlockAllDynamic"));

}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The BeginPlay and Tick are left to the default settings so I didn't post them here. Mostly what's going on here is that the scene root is being initialized, and the static mesh is initializing some default vaues such as gravity, collision profile, physics and locations for use in game. The NormalDirection boolean isn't initialized here because it will constantly be changed in other places later. &lt;/p&gt;

&lt;p&gt;The next class I'd like to go over is the BlackHoleGameModeBase.&lt;br&gt;
&lt;strong&gt;Here is the BlackHoleGameModeBase.h code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class BLACKHOLEREDO_API ABlackHoleRedoGameModeBase : public AGameModeBase
{
    GENERATED_BODY()

    virtual void StartPlay() override;

protected:
    // Widget object
    UPROPERTY(VisibleInstanceOnly)
    class UUserWidget* myWidget;

    // Handles the creation of the widget
    UFUNCTION(BlueprintCallable)
    void CreateDefaultWidget();

    // Simply swap the widget in and out of view when called
    UFUNCTION()
    void ToogleWidgetView();

public:
    // Holds a reference to the Widget class itself
    UPROPERTY(EditAnywhere, Category = "Shadow")
    TSubclassOf&amp;lt;class UUserWidget&amp;gt; WidgetClassRef;

    // Counter variable that holds the number of items that are spawned in. This value is mainly used for the 
    // widget itself.
    UPROPERTY(BlueprintReadWrite)
    int spawned_items;
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Quick notes about the BlackHoleGameMode header file:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Creates a reference to the main widget that displays information to the user (mywidget)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CreateDefaultWidget method handles the setup and creation of the widget (mywidget)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ToogleWidget method disables or enables the widget from the view&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;WidgetClassRef makes it easier to get the widget class of the type that's required which is just a UserWidget&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally spawned items integer counter keeps track of the items currently avaialable on screen.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Now here's the BlackHoleGameMode.cpp file:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void ABlackHoleRedoGameModeBase::StartPlay()
{
    Super::StartPlay();

    check(GEngine != nullptr);


    if (IsValid(WidgetClassRef) )
    {
        CreateDefaultWidget();
        spawned_items = 0;          // iniitialize the number of items when the simulation is loaded
    }
    else
    {
        UE_LOG(LogTemp, Warning, TEXT("Unable to initialize widget class"));
        return;
    }

}

void ABlackHoleRedoGameModeBase::CreateDefaultWidget()
{
    if (WidgetClassRef == nullptr) return;

    // assuming that the widgetclass reference itself is valid, begin the process of creating the widget
    myWidget = Cast&amp;lt;UUserWidget&amp;gt;(CreateWidget(GetWorld(), WidgetClassRef) );

    if (myWidget != nullptr)
    {
        GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Blue, TEXT("Successful viewport creation!!"));
        ToogleWidgetView();
    }
}

void ABlackHoleRedoGameModeBase::ToogleWidgetView()
{
    // remove the widget from viewport if it is active, and if not, then add it to the viewport
    if (myWidget-&amp;gt;IsInViewport())
    {
        myWidget-&amp;gt;RemoveFromViewport();
    }
    else
    {
        myWidget-&amp;gt;AddToViewport();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Quick summary of BlackHoleGameMode.cpp file&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The startplay method just checks the class reference variable for validation and if it's valid then it initializes the spawned items counter&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The CreateDefaultWidget method simply checks if the class is valid, and from there creates a widget. Once that widget is created, it is checked for validity and if it is valid, then it is immeditately added to the viewport.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, the ToogleWidgetView method simply adds or removes the widget based on what it is currently&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With that being set up, the next class I'd like to go over is the CubeMeshActor which is a specific instance of the MainBaseActor. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is the header file for the CubeMesh class:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UCLASS()
class BLACKHOLEREDO_API ACubeMesh : public AMainBaseActor
{
    GENERATED_BODY()
public:
    ACubeMesh();
    ~ACubeMesh();

    // The custom function thats used to track object hits for this object
    UFUNCTION()
    void OnComponentHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult&amp;amp; Hit);

    // Functions as DoOnce method
    UFUNCTION()
    void EmptyMethod();

    bool dOnceA;

protected:
    virtual void BeginPlay() override;

    virtual void Destroyed();
public:
    // Called every frame
    virtual void Tick(float DeltaTime) override;

    // Increases the total count inside the game mode
    void IncreaseItemCount();

    // So we can reference the main gamemode
    UPROPERTY()
    class ABlackHoleRedoGameModeBase* gamemode;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CubeMesh class includes the components of its parent along with some extra functions which include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The hit component function which enables mesh collisions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A BlackHoleGameMode reference which we can use to reference the main game mode&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The IncreasedItemCount function increases the count by 1 inside the game mode every time a object of this type is created.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A destroyed method which is only important because before it's destroyed, it reduces the count inside the gamemode by 1&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The EmptyMethod which is the handler for time delays&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A doOnce variable that acts like a mutex for collision&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Next is the CubeMesh.cpp file:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void ACubeMesh::OnComponentHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult&amp;amp; Hit)
{

    if (OtherActor != NULL)
    {
        if (AMainBaseActor* ref = Cast&amp;lt;AMainBaseActor&amp;gt;(OtherActor) )
        {
            // If we can reset it, then basically add a impusle force to the object and change this instances direction to the
            // mirror, along with the mesh that it hit.
            if (dOnceA)
            {
                dOnceA = false;

                FVector newVec = FVector(Hit.Normal.X, Hit.Normal.Y, 1.0);
                ref-&amp;gt;Static_Mesh-&amp;gt;AddImpulse(newVec * 500, FName("None"), true);


                if (NormalDirection)
                {
                    ref-&amp;gt;NormalDirection = true;
                    NormalDirection = false;
                }
                else
                {
                    ref-&amp;gt;NormalDirection = false;
                    NormalDirection = true;
                }

                // Delay it slightly before allowing the donce variable to be reset
                FTimerHandle TimerHandle;
                GetWorld()-&amp;gt;GetTimerManager().SetTimer(TimerHandle, this, &amp;amp;ACubeMesh::EmptyMethod, .2, false);
            }
        }
    }
}

void ACubeMesh::EmptyMethod()
{
    dOnceA = true;
}

void ACubeMesh::BeginPlay()
{
    Super::BeginPlay();

    // Short life span so this actor will be destroyed after 17 seconds
    SetLifeSpan(17);

    // Enable collisions for the static mesh that was initialized inside the baseactor class
    if (Static_Mesh-&amp;gt;GetStaticMesh())
    {
        Static_Mesh-&amp;gt;OnComponentHit.AddDynamic(this, &amp;amp;ACubeMesh::OnComponentHit);
    }

    dOnceA = true;

    // Initialize a reference to the main game mode
    gamemode = Cast&amp;lt;ABlackHoleRedoGameModeBase&amp;gt;(UGameplayStatics::GetGameMode(GetWorld()));

    // Delay the instancing a bit since we'll use many of them at once.
    FTimerHandle TimerHandle;
    GetWorld()-&amp;gt;GetTimerManager().SetTimer(TimerHandle, this, &amp;amp;ACubeMesh::IncreaseItemCount, .5f, false);
}

void ACubeMesh::Destroyed()
{
    // When a instance is destroyed, subtract one from the count inside the main game mode
    if (IsValid(gamemode))
        gamemode-&amp;gt;spawned_items -= 1;
    else
        UE_LOG(LogTemp, Warning, TEXT("You're deleing?"));
}

void ACubeMesh::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
}

void ACubeMesh::IncreaseItemCount()
{
    // assuming the gamemode reference is valid, increase the spawn iitem integer variable by 1
    if (IsValid(gamemode))
    {
        gamemode-&amp;gt;spawned_items += 1;
    }
    else
        UE_LOG(LogTemp, Warning, TEXT("Impossible to access the game mode?"));
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Quick Summary of CubeMesh.cpp&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;TheOnComponentHit function first checks if the colliding object is of the same type as this actor. Then if the dOnce variable is true, it is set to false and then we add a impulse force using the hit components x and y, excluding z so no up and down motion. After this the direction of this object and the other one is inverted. Finally we pause the timer for about a quarter of a second so the impulse has time to be applied. The rest is handled inside the EmptyMethod.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The EmptyMethod simply sets the dOnce variable to true.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In BeginPlay the first thing that's done is the life span is limited to 17 seconds. The static mesh is initialized to use the hit component, the dOnce is defaulted to true, the gamemode reference is intialized, and a timer handle is used to increase the item count. This delay is only used since there are meshes in the simulation initially so this avoids access errors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The IncreaseItemCount uses the gamemode reference to increase the counter value inside it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Destroyed method does the oppisite of IncreaseItemCount and is only activated at the end of this instances life cycle.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The final actor is the BlackHoleActor class. This is the class that makes actors rotate until a time limit is passed and then pushes them outward.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here is the header file for the BlackHoleActor class:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class AMainBaseActor;   // forward declaration, this class is added in the cpp file
UCLASS()
class BLACKHOLEREDO_API ABlackHoleActor : public AActor
{
    GENERATED_BODY()

public: 
    // Sets default values for this actor's properties
    ABlackHoleActor();

    // The root of this mesh
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Components)
    class USceneComponent* CustomRoot;

    // Moves along the spline in a normal direction
    UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = Components)
    class USceneComponent* HolePosition;

    // A scene component which spins in the opposite direction from the normal scene component
    UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = Components)
    class USceneComponent* DirectionMirror;

    // The spline reference that objects follow once inside this actors radius
    UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = Components)
    class USplineComponent* customSpline;

    // Array of a generic subtype of MainBaseActors. Children from this class will be used in this example
    UPROPERTY(BlueprintReadWrite, EditAnywhere)
    TArray&amp;lt;AMainBaseActor*&amp;gt; ActorArray;

    // Should always be true except when the endtime has gone beyond ten seconds, in which case this is temporarily set to false
    UPROPERTY(BlueprintReadWrite, EditAnywhere)
    bool AllowCollisions;

    // Corresponds to the input of the spline itself. As such this only has a limit of 4 seconds because the spline only has 4 points
    UPROPERTY(BlueprintReadWrite, EditAnywhere)
    float SplineTime;

    // The total time in which all objects inside will spin before being launched
    UPROPERTY(BlueprintReadWrite, EditAnywhere)
    float EndTime;

    // Will be used as the overlap for when objects come inside this radius
    UPROPERTY(BlueprintReadOnly, Category = Components)
    class UBoxComponent* BoxCollisionComp;

    // counter for the last object added to a array of actors. This is so the direction that a object spins on the spline
    // goes in a direction opposite to the last object added
    UPROPERTY(BlueprintReadOnly)
    bool LastAddition;

    // Base cylinder meshes
    UPROPERTY()
    UStaticMesh* BaseCylinder;

    // Base cube mesh
    UPROPERTY()
    UStaticMesh* BaseCube;

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

    // Returns the inverted time
    float FlippedSplineTimeValue();

    // Used for time delays or lags before the sequence is reset
    void CustomDelayFunction();

    FTimerHandle slightdelay;

public: 
    // Called every frame
    virtual void Tick(float DeltaTime) override;

    // For when other actors begin to overlap this zone
    UFUNCTION()
    void OnBoxBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, 
        int OtherBodyIndex, bool From_Sweep, const FHitResult&amp;amp; Sweep_Result);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Quick BlackHoleActor Notes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;CustomRoot is the new root for this actor&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The HolePosition component is a scene component that will always be moving along a spline path&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DirectionMirror is the same as the HolePosition component and does the same thing but in the opposite direction&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The customspline component is the spline that both components will move along.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ActorArray contains a list of all actors of type MainBaseActor&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The AllowCollisions boolean is to keep track of when collisions are allowed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SplineTime float is a variable which should only be a maxium of four, which corresponds to the points of the spline.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;EndTime is the total time of the spin once a overlap is detected. This corresponds to the vfx which is added and spawned at this time also&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The BoxCollisioncomp is the overlap/box trigger that will be used for overlaps of objects.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The LastAddition boolean simply keeps track of the last direction of the object that was just added. This is used to flip the direction of new objects so that they don't all spin the same way&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;BaseCylinder and BaseCube are simple object types. The reason this is done here is because this object will be responsible for object creation after the initial run&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;FlippedSplineTimeValue method flips the spline time for inverted objects&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CustomDelayMethod is used for input delays later on&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The FTimerHandle is the variable that will be used for the delay function CustomDelayMethod&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;OnBoxBeginOverlap method is used for the overlap of the trigger box.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Now for the BlackHoleActor.cpp code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include "BlackHoleActor.h"
#include "Components/BoxComponent.h"
#include "Components/SplineComponent.h"
#include "Kismet/GameplayStatics.h"
#include "Math/UnrealMathUtility.h"
#include "CubeMesh.h"
#include "BlackHoleRedoGameModeBase.h"
#include "MainBaseActor.h"

// Sets default values
ABlackHoleActor::ABlackHoleActor()
{
    // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;
    SetActorTickEnabled(false);
    CustomRoot = CreateDefaultSubobject&amp;lt;USceneComponent&amp;gt;(TEXT("Root"));
    CustomRoot-&amp;gt;SetWorldLocation(FVector(0, 0, 0));
    RootComponent = this-&amp;gt;CustomRoot;

    //
    HolePosition = CreateDefaultSubobject&amp;lt;USceneComponent&amp;gt;(FName("Helper"));
    HolePosition-&amp;gt;SetupAttachment(CustomRoot);
    HolePosition-&amp;gt;SetRelativeLocation(FVector(0, 0, 100));

    // Set up the mirror scene component, initialize its world location and attach it to the root
    DirectionMirror = CreateDefaultSubobject&amp;lt;USceneComponent&amp;gt;(TEXT("MirrorLocation"));
    //DirectionMirror-&amp;gt;SetWorldLocation(FVector(0, 0, 0));
    DirectionMirror-&amp;gt;SetupAttachment(CustomRoot);
    DirectionMirror-&amp;gt;SetRelativeLocation(FVector(0, 0, 100));

    // Create the box component, set its location above a certain height, and finally attach it to the root
    BoxCollisionComp = CreateDefaultSubobject&amp;lt;UBoxComponent&amp;gt;(FName("Collision"));
    BoxCollisionComp-&amp;gt;SetWorldLocation(FVector(0, 0, 110) );
    BoxCollisionComp-&amp;gt;SetupAttachment(CustomRoot);

    // Stretch the box out here
    BoxCollisionComp-&amp;gt;SetBoxExtent(FVector(700, 700, 100));

    AllowCollisions = true;
    LastAddition = false;

    customSpline = CreateDefaultSubobject&amp;lt;USplineComponent&amp;gt;(TEXT("Spline"));
    customSpline-&amp;gt;SetupAttachment(CustomRoot);
    customSpline-&amp;gt;SetRelativeLocation(FVector(-370, 0, 260));

    // Make it closed so the loop is in a circle
    customSpline-&amp;gt;SetClosedLoop(true);

    // Clear the default spline and add new based locally to the spline
    customSpline-&amp;gt;ClearSplinePoints();
    customSpline-&amp;gt;AddSplinePoint(FVector(-89.979538, 1.889979, 80), ESplineCoordinateSpace::Local);
    customSpline-&amp;gt;AddSplinePoint(FVector(61.457996, 233.428894, 0), ESplineCoordinateSpace::Local);
    customSpline-&amp;gt;AddSplinePoint(FVector(549.934326, -7.602399, 100), ESplineCoordinateSpace::Local);
    customSpline-&amp;gt;AddSplinePoint(FVector(49.977882, -489.968689, 0.0), ESplineCoordinateSpace::Local);
    customSpline-&amp;gt;SetRelativeScale3D(FVector(1.5f, 1.0f, 1.0f));

    static ConstructorHelpers::FObjectFinder&amp;lt;UStaticMesh&amp;gt;BaseCubeRef(TEXT("StaticMesh'/Engine/Basicshapes/Cube'"));
    static ConstructorHelpers::FObjectFinder&amp;lt;UStaticMesh&amp;gt;BaseCylinderRef(TEXT("StaticMesh'/Engine/BasicShapes/Cylinder'"));

    // If the constructions objects have failed the stop
    if (BaseCylinderRef.Object != nullptr)
        BaseCylinder = BaseCylinderRef.Object;
    else
        return;

    if (BaseCubeRef.Object != nullptr)
        BaseCube = BaseCubeRef.Object;
}

// Called when the game starts or when spawned
void ABlackHoleActor::BeginPlay()
{
    Super::BeginPlay();
    BoxCollisionComp-&amp;gt;OnComponentBeginOverlap.AddDynamic(this, &amp;amp;ABlackHoleActor::OnBoxBeginOverlap);
    SetActorTickEnabled(false);
}

float ABlackHoleActor::FlippedSplineTimeValue()
{
    // Use the currentsplineTime and subtract 4 from it so it's always inverted. 
    // So 3.0f normally would return (4.0f - 3.0f) 1.0f which is the opposite end in this case.
    return 4.0f - SplineTime;
}

void ABlackHoleActor::CustomDelayFunction()
{
    AllowCollisions = true;

    for (int i = 0; i &amp;lt; ActorArray.Num(); i++)
    {
        if (IsValid(ActorArray[i]))
            ActorArray[i]-&amp;gt;Static_Mesh-&amp;gt;SetNotifyRigidBodyCollision(true);
        else
            ActorArray.RemoveAt(i);
    }

    // Remove all items from the list
    ActorArray.Empty();
    EndTime = 0.0f;

    // Makes it so the simulation continously spawns both cubes and cylinders for this example
    for (int k = 1; k &amp;lt; 4; k++)
    {
        ACubeMesh* Cylinder = GetWorld()-&amp;gt;SpawnActor&amp;lt;ACubeMesh&amp;gt;(GetActorLocation() + FVector(0, 0, k * 2000.f), FRotator());
        Cylinder-&amp;gt;Static_Mesh-&amp;gt;SetStaticMesh(BaseCylinder);
    }

    for (int i = 1; i &amp;lt; 3; i++)
    {
        ACubeMesh* Cube = GetWorld()-&amp;gt;SpawnActor&amp;lt;ACubeMesh&amp;gt;(GetActorLocation() + FVector(0, 0, i * 2000.f), FRotator());
        Cube-&amp;gt;Static_Mesh-&amp;gt;SetStaticMesh(BaseCube);
    }
}

// Called every frame
void ABlackHoleActor::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    if (EndTime &amp;lt; 10.f)
    {
        EndTime += DeltaTime;

        if (SplineTime &amp;lt; 4.0f)
        {
            SplineTime += DeltaTime;
            // Use the location based on the splinetime float variable to get a location on the spline and change the holeposition scene component to always 
            // update
            HolePosition-&amp;gt;SetWorldLocation(customSpline-&amp;gt;GetLocationAtSplineInputKey(SplineTime, ESplineCoordinateSpace::World));

            DirectionMirror-&amp;gt;SetWorldLocation(customSpline-&amp;gt;GetLocationAtSplineInputKey(FlippedSplineTimeValue(), ESplineCoordinateSpace::World));

            // Go through each element in the array and set its location and torque depending on the direction that it is current set as
            for (int i = 0; i &amp;lt; ActorArray.Num(); i++)
            {
                // Checks if the element inside the array is still active
                if (IsValid(ActorArray[i]) )
                {
                    // The normal direction
                    if (ActorArray[i]-&amp;gt;NormalDirection)
                    {
                        FVector VinterpToVec = FVector(FMath::VInterpTo(ActorArray[i]-&amp;gt;Static_Mesh-&amp;gt;GetComponentLocation(),
                            HolePosition-&amp;gt;GetComponentLocation(), DeltaTime, 2.0f).X,
                            FMath::VInterpTo(ActorArray[i]-&amp;gt;Static_Mesh-&amp;gt;GetComponentLocation(),
                                HolePosition-&amp;gt;GetComponentLocation(), DeltaTime, 2.0f).Y, 0.0f);

                        ActorArray[i]-&amp;gt;Static_Mesh-&amp;gt;SetWorldLocation(FVector(VinterpToVec.X, VinterpToVec.Y, HolePosition-&amp;gt;GetComponentLocation().Z), false, nullptr, ETeleportType::TeleportPhysics);

                        ActorArray[i]-&amp;gt;Static_Mesh-&amp;gt;AddTorqueInDegrees(FVector(90, 290, 360), FName("None"), true);
                    }
                    // The inverted direction
                    else
                    {
                        FVector VinterpToVec = FVector(FMath::VInterpTo(ActorArray[i]-&amp;gt;Static_Mesh-&amp;gt;GetComponentLocation(),
                            DirectionMirror-&amp;gt;GetComponentLocation(), DeltaTime, 2.0f).X,
                            FMath::VInterpTo(ActorArray[i]-&amp;gt;Static_Mesh-&amp;gt;GetComponentLocation(),
                                DirectionMirror-&amp;gt;GetComponentLocation(), DeltaTime, 2.0f).Y, 0.0f);

                        ActorArray[i]-&amp;gt;Static_Mesh-&amp;gt;SetWorldLocation(FVector(VinterpToVec.X, VinterpToVec.Y, DirectionMirror-&amp;gt;GetComponentLocation().Z), false, nullptr, ETeleportType::TeleportPhysics);
                        ActorArray[i]-&amp;gt;Static_Mesh-&amp;gt;AddTorqueInDegrees(FVector(90, 290, 360), FName("None"), true);
                    }
                }
                // If the element isn't valid, remove it to avoid problems
                else
                    ActorArray.RemoveAt(i);
            }
        }
        // When the timer is above four, reset it to zero so that it continously repeats
        else
            SplineTime = 0.0f;
    }
    // When the timer limit has been reached, begin the process of sending every object inside the array flying outwards 
    else
    {
        AllowCollisions = false;

        for (int i = 0; i &amp;lt; ActorArray.Num(); i++)
        {
            if (IsValid(ActorArray[i]))
            {
                FVector UpHelper = ActorArray[i]-&amp;gt;Static_Mesh-&amp;gt;GetComponentLocation();
                UpHelper.Z += 300.f;
                FVector dir = customSpline-&amp;gt;FindDirectionClosestToWorldLocation(UpHelper, ESplineCoordinateSpace::World);
                dir *= 4000.0f;
                dir += FVector(0.f, 0.f, 2000.f);
                ActorArray[i]-&amp;gt;Static_Mesh-&amp;gt;AddImpulse(dir, "NONE", true);
                ActorArray[i]-&amp;gt;Static_Mesh-&amp;gt;AddForce(FVector(0.f, 0.f, 2000.f), "NONE", true);
            }
            else
                ActorArray.RemoveAt(i);
        }

        GetWorld()-&amp;gt;GetTimerManager().SetTimer(slightdelay, this, &amp;amp;ABlackHoleActor::CustomDelayFunction, 2.0, false);
        SetActorTickEnabled(false);
    }
}

void ABlackHoleActor::OnBoxBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int OtherBodyIndex, bool From_Sweep, const FHitResult&amp;amp; Sweep_Result)
{
    // If the boolean is true to allow more collisions then proceed
    if (AllowCollisions)
    {
        // If the incoming actor is of some subset of MainBaseActor then continue, otherwise ignore for now
        if (AMainBaseActor* ref = Cast&amp;lt;AMainBaseActor&amp;gt;(OtherActor))
        {
            // If the incoming actor is not already inside the character array then proceed to add it
            if (ActorArray.Find(ref) == INDEX_NONE)
            {
                ActorArray.Add(ref);

                if (ActorArray.Num() &amp;gt; 1)
                {
                    LastAddition = !LastAddition;
                    ActorArray.Last()-&amp;gt;NormalDirection = LastAddition;
                }

                if (!IsActorTickEnabled() )
                    SetActorTickEnabled(true);
            }
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Notes about the BlackHoleActor.cpp:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The constructor method intializes all objects including both scene components, the spline, the overlap component, the boolean variables allowcollisions/lastaddition as well as initializes both the cubes and spheres objects inside this actor&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The BeginPlay method disales ticks and setups up the box component as the primary overlap&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;FlippedTimeValue returns the inverted splinetime. Since it will always be a max of 4.0f, we can just subtract it to get a inverted value&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The OnBoxBeginOverlapComponent function first checks if collisions are allowed using the allowedcollisions boolean value. If this is the case then it casts to the MainBaseActor class. If this cast is successful, then it tries to find out if the incoming object already exists in the ActorArray variables. This is to avoid duplicate entries of the same object in the list and because the object flies around it causes issues. Assuing it doesn't exist, then the new object gets added to the array. If the number of Actors inside that array are greater than 1, then everytime a instance is added, then the LastAddition boolean is inverted (true to false/false to true). The new elements' NormalDirection is then set to the new LastAddition value. This is used in the tick of this actor and makes actors go in different directions depending on this boolean. The final part of this block simply enables tick on the actor if it isn't already set to true. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Tick Function allows new objects to rotate until the endTime is reached. The first thing that happens is EndTime is checked to be less than ten. If this is true then deltaTime is constantly added to it until that threshold is reached. If this isn't true then it prepares to dispense all objects from the center by adding special impulses and forces to them. Invalid objects are disabled, the AllowCollisions bool is set to false, and the actors Tick is stopped. The CustomDelayFunction is called to reinitialize the process again. While the EndTime float value is less than 10, it also checks if the SplineTime value is less than 4.0f. If it is we add the change in time value to it, and if it exceeds 4, then it is reset back to 0. Inside the SplineTime's true component, we constantly update the HolePosition scene component and the DirectionMirror scene component to match the customSpline using a input key of SplineTime. The DirectionMirror one uses the FlippedSplineValue method as its input however. As these components are being updated, we go through all the elements inside the ActorArray variable and if they are valid their position is updated. This updated is dependent on what it's current NormalDirection boolean is. If true it follows the HolePosition scene component which is following a normal path, and if false it follows the mirror path. Regardless a Torque is also added and any invalid elements are removed immediately from the array. This is because some elements that survive through the last cycle may come back into play, but because these objects are on a timer, they may not last until the end, creating out of bounds errors. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The CustomDelayFunction activates after a complete cycle. The first thing this does allow new collisions by setting the boolean to true. Then it loops through all elements in the ActorArray and disables collisions on the static meshses or removes invalid objects (to avoid out of bounds errors). Then all valid references are cleared and the EndTimer is reset to 0 for a new cycle. Finally a set array of cubes and cylinders are spawned just aboved this actor, making this process endless until the user quits&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With all of the code completed here, the last thing that needs to be completed is actually dropping the actors into the scene but before that I'd like to explain a few things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The spline that was created follows a very specific path and is a closed looped. This was done in code but can be changed for other purposes. However, more points means that the splineTime variable will need to be updated as well since it only is intended for 4 points.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The way this simulation was initialized, you'll need to drop a few initial objects into the scene just above the BlackHoleActor itself to trigger the sequence of events. After this nothing else is required.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Additional code like the escape key, movement (limiting pitch), and the code binding the data from the gamemode to the widget is included inside the project itself. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;While this will work perfectly fine, it doesn't have any visual effect on the blackhole. In other words, the objects will fly around a target and then be pushed out. I simply wanted to use a Niagara effect to combat this so in my implementation I instantiated a blueprint instance of the BlackHoleActor so that I could add one using the information from the source code that was created. These are images of how it was done. All of this is executed via the event tick portion of the actor which is disabled until a collision is handled. Once the tick is enabled, this code is handled in such a way that it only happens once per run. Here are some sample images of that in order from left to right: &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kLAlta-V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/igk5tdrowd8g6o79fths.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kLAlta-V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/igk5tdrowd8g6o79fths.png" alt="Image description" width="880" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ArF73wdn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qvqjislyt8c5tcudxgrk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ArF73wdn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qvqjislyt8c5tcudxgrk.png" alt="Image description" width="880" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6x8efF3A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ba7exov35ywphcwrrzhq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6x8efF3A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ba7exov35ywphcwrrzhq.png" alt="Image description" width="477" height="136"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With all that in mind, it should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BkCSAL5X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yozir460jjihos0wv8xk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BkCSAL5X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yozir460jjihos0wv8xk.gif" alt="Image description" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HmBIn9WD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tbdf4bcxltu26wppxgw1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HmBIn9WD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tbdf4bcxltu26wppxgw1.gif" alt="Image description" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Postmortem:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I had previously already done this before but with characters instead of physics objects. Properties were similiar but not quite the same. For characters it was more like a suction instead of flying and they would be blasted outwards simliar to this but not as far. &lt;/p&gt;

&lt;p&gt;One thing that I learned from doing it this way was to account for multiple objects ensared in a single cycle. Because of the fact that there were many objects, one thing I had to do was temporarily disable collisions just as the blast occurs and disable them shortly after. For characters I just sent them up and backawards from the center, but because these were rotating and moving in the air, even with the correct calculations they wouldn't always fly as intended if there were more than 3. The impulse for multiple hits sent them crashing down instead of flying. &lt;/p&gt;

&lt;p&gt;The other takeaway from this is the bumping mechanism. I originally didn't put any thought into it until I got the project up and running. They would follow the path but not bump into each other in a realistic way, or they would fuse together. This is why in the code I posted above you see things like torque, and the NormalDirection boolean to account for changes on hits. &lt;/p&gt;

&lt;p&gt;Both of these lessons are key components that I'll take with me into future projects going forward. If you'd like to see the code above up close or just how it works, please have a look at my github page. &lt;/p&gt;

&lt;p&gt;Thank you for reading all the way to the end if you made it this far.&lt;/p&gt;

&lt;p&gt;Sincerely,&lt;/p&gt;

&lt;p&gt;Christian&lt;/p&gt;

</description>
      <category>unrealengine</category>
      <category>visualstudio</category>
      <category>cpp</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Codebreak simulation</title>
      <dc:creator>CBanks901</dc:creator>
      <pubDate>Tue, 08 Mar 2022 09:52:57 +0000</pubDate>
      <link>https://dev.to/cbanks901/codebreak-simulation-684</link>
      <guid>https://dev.to/cbanks901/codebreak-simulation-684</guid>
      <description>&lt;p&gt;I'd like to write about a console application that I wrote in Visual Studio in C++ called CodeBreaker. This is a simple password game application that allows users to guess up to 8 times a 4 code sequence. Besides the code limit, the additional rules are that every unique code will not have repeated numbers (so no 9912), and each code in the list will be different.&lt;/p&gt;

&lt;p&gt;The data I used are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Integer numberlist with a size of ten to hold all the numbers &lt;/li&gt;
&lt;li&gt;A integery pointer array called secretcode that will hold the codes until the programs termination, use new for dynamic memory allocation&lt;/li&gt;
&lt;li&gt;A char called repeat which holds the users decision upon success or failure of code cracking&lt;/li&gt;
&lt;li&gt;A custom struct called InfoStruct which holds all the main data necessary for the program, as well as a global instance of it so it can be changed when necessary&lt;/li&gt;
&lt;li&gt;A function called RandomKeySelection which generates the secret code when called.&lt;/li&gt;
&lt;li&gt;A function called GuessSequence which is what handles the execution and termination of the programming&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd first like to review the InfoStruct that was created. It looks like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;struct InfoStruct
{
    string codecopy, usercode;                          // Codecopy is intended to be a string copy of the actual code, and usercode a copy of the users guess.
    int userkeycounter, correctdigits, findindex;       // keycounter is for tracking input while entered, correctdigits is for number of correct digits, and findindex is for the 
                                                        // string based on the actual code (will be used to determine if what the user entered is actually in the code)
    char userinput[4];                                  // array of 4 characters that the user will enter to guess the sequence.
    bool inputretry = false;                            // Used at the end of the sequence or chances to determine if the player is going to retry or not
}; InfoStruct userinfo; // Global instance is created here since this variable will be used in different functions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Like I mentioned previously, this simply holds most of the important data of the program. The declaration is right at the end also. This instance is referenced both by the randomkeyselection function and guessingSequences, one to store all the information and the other determining input and data matching.&lt;/p&gt;

&lt;p&gt;The next piece I'd like to go over is the randomkeyselection function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// This function simply generates the random code sequnece that will be determined. At a glance, the arguments (in order) are to the code pointer, the second is to the array of 
// numbers that will be used, and the last argument is for the size of that numberlist. 
void randomKeySelection(int *code, int listRef[], int sizeL)
{
    int selectioncounter = 0;                                                                               // A counter for the current index of the secretcode
    bool usedCounter[10] = { false, false, false, false,false, false, false, false , false, false };        // If a number has been generated, the corresponding bool will be set to true
                                                                                                            // to prevent that same number being used again.
    int randomness;                                                                                         // simply a integer holder that will store the random numbers

    // Loop that will generate the code in response to the selectioncounter variable (Maximum of 4 times).
    do
    {
        randomness = rand() % sizeL;                                // Generate a random number centered around the sizeL argument, between 0 - 9;

        // Based on the randomness variable, if the value inside the usedCounter boolean is false, then proceed. Only inside this sequence will the selectioncounter be increased which
        // will stop the loop.
        // Inside the if statement, set the boolean based on that selected index to true to prevent this digit being used again, set the code based on selectioncounter to the listRef
        // argument that was passed in based on that index, finally increased the counter to proceed to break the loop.
        if (usedCounter[randomness] == false)
        {
            usedCounter[randomness] = true;
            code[selectioncounter] = listRef[randomness];
            ++selectioncounter;
        }

    } while (selectioncounter &amp;lt; 4);

    //Finally simply set the codecopy string inside the userinfo struct to the full combination of our code by converting each digit of the code into a string.
    userinfo.codecopy = to_string(code[0]) + to_string(code[1]) + to_string(code[2]) + to_string(code[3]);

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The randomkeyselection function uses a dynamic integer pointer, as well as a integer array followed by its size respectively. The reaon I put this into a function is for quick accessibility. Originally I had no intention to do so, but realized I could keep the code a bit cleaner and more organized by seperating it. This code creates a boolean array of ten items that corresponds to the index we pull from the listref parameter value. When that value is pulled this boolean array integer in the same spot is set to true. This makes it so that if the same value is attempted to be pulled again, it is skipped. This repeatedly happens, in a do while loop until the selectioncounter variable is set to four. Selectionvalue only increases when correct values are pulled out. When this is finished, I use the userinfo reference I made to copy the new data (which is the code parameter and is constantly updated through the do loop) into it as a string (codecopy). This function is called in the main branch of the program.&lt;/p&gt;

&lt;p&gt;I'd like to move on now to the guessingSequence function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// This function handles the entire sequence of the game including input, retries and termination. Its arugments in order are the code array, the number of chances, and a repeat reference 
// variable which is used inside the main scope. If a repeat is requested, recursion is used, if not then the function simply ends and the main scope terminates the program.
void guessingSequence(int *secretcode, int chances, char &amp;amp;repeat)
{
    // Set the userinfo struct parameter keycounter to 0 so we can correctly track input
    userinfo.userkeycounter = 0;

    // While the previous counter (keycounter) is less than 4, do the following.
    do
    {
        userinfo.userinput[userinfo.userkeycounter] = _getch();             // Ask the the user for a single character. Get the structs userinput character based on the specificed index.
        cout &amp;lt;&amp;lt; userinfo.userinput[userinfo.userkeycounter] &amp;lt;&amp;lt; endl;        // Simply print so the user can see their key.

        // If the key that the player entered is a valid digit, then increase the keycounter variable so we can be pass through the loop, otherwise continue to ask the player for valid
        // input
        if (isdigit(userinfo.userinput[userinfo.userkeycounter]))
            userinfo.userkeycounter++;
        else
            cout &amp;lt;&amp;lt; "Please a enter a number between 0 - 9" &amp;lt;&amp;lt; endl;


    } while (userinfo.userkeycounter &amp;lt; 4);

    // Simple for loop that basically replaces the code string (usercode) inside of our userinfo struct to the input based on the index of the loop
    for (int i = 0; i &amp;lt; 4; ++i)
        userinfo.usercode.replace(i, i + 1, 1, userinfo.userinput[i]);

    // Compare the string usercode inside the userinfo struct to the secret code inside the struct. If they are equal (0) then the code has been cracked. If not the following branch will
    // execute.
    if (userinfo.usercode.compare(userinfo.codecopy) == 0)
    {
        cout &amp;lt;&amp;lt; "Code cracked!!" &amp;lt;&amp;lt; endl;
    }
    else
    {
        // This section is for if 1 or more of the keys that the player entered is wrong. First the find index inside the struct is set to -1, and the correct digits integer is set to 0. 
        userinfo.findindex = -1;
        userinfo.correctdigits = 0;

        // Loop through the four characters that the player entered
        for (int j = 0; j &amp;lt; 4; j++)
        {
            // Set the findindex variable to the codecopy's attempt to find the digit that the user entered based on the for loop (in order).
            userinfo.findindex = userinfo.codecopy.find(userinfo.usercode[j]);

            // If the index is valid and not a no position value (if it has been found) inside the actual code
            if (userinfo.findindex != string::npos)
            {
                // If the findindex is a valid index, but it isn't equal to the current value in the loop, this means the digit exists inside the code but at the wrong place.
                // Simply tell the user that the digit is correct but not placed. The correctdigit value remains the same.
                if (userinfo.findindex != j)
                    cout &amp;lt;&amp;lt; "Correct digit " &amp;lt;&amp;lt; userinfo.codecopy[userinfo.findindex] &amp;lt;&amp;lt; " but at the wrong place." &amp;lt;&amp;lt; endl;
                else
                {
                    // If this happens that means that the digit the player entered is correct and it is in the correct spot in response to the actual code. Correct digit is increased.
                    cout &amp;lt;&amp;lt; "Successful digit entered!!!\n";
                    userinfo.correctdigits++;
                }
            }
            else
                cout &amp;lt;&amp;lt; "Wrong digit " &amp;lt;&amp;lt; userinfo.userinput[j] &amp;lt;&amp;lt; " entered" &amp;lt;&amp;lt; endl;                  // In this case the findindex is a no position which means that number doesn't
                                                                                                        // exist in the code
        }

        cout &amp;lt;&amp;lt; "Correct digits overall: " &amp;lt;&amp;lt; userinfo.correctdigits &amp;lt;&amp;lt; endl;

        // If the number of chances left is greater than 0, we simply use recursion to call this function again but we decrease the number of chances by 1. This will continue either 
        // until the code has been cracked, or the player runs out of chances all together. If they make it here again with no chances, it simply tells them that they have no chances
        // left.
        if (chances &amp;gt; 0)
        {
            cout &amp;lt;&amp;lt; "Chance remaining " &amp;lt;&amp;lt; chances &amp;lt;&amp;lt; endl;
            return guessingSequence(secretcode, chances - 1, repeat);
        }
        else
            cout &amp;lt;&amp;lt; "Sorry you are out of chances." &amp;lt;&amp;lt; endl;
    }


    cout &amp;lt;&amp;lt; "Would you like to continue? Y or N" &amp;lt;&amp;lt; endl;

    // Set the input retry boolean inside the struct to false for the following section of the code
    userinfo.inputretry = false;

    // While the retry boolean is false, keep asking the player if they want to continue or not by pressing y, Y, n or N. Regardless set the inputretry bool to true to break this 
    // whil loop. If the input is something else, keep asking for a valid input over and over again.
    while (userinfo.inputretry == false)
    {
        repeat = _getch();
        if (repeat == 'y' || repeat == 'Y')
            userinfo.inputretry = true;
        else if (repeat == 'n' || repeat == 'N')
            userinfo.inputretry = true;
        else
            cout &amp;lt;&amp;lt; "Please type y or n. \n";
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function is the bread and butter of the application. The first thing that it does is initialize the counter inisde the userinfo struct and then repeatedly asks for user input until the key counter inside the struct reaches 4. It uses the isdigit function to check if the players input is actually a digit and limits input to a single key press. &lt;/p&gt;

&lt;p&gt;The next thing that the function does is update the usercode variable inside the userinfostruct because I used something different for input so it needs to be transfered over. &lt;/p&gt;

&lt;p&gt;The next thing that happens is the code is compared to the codecopy variable inside the userinfostruct. You're probably wondering why I did this? It's because in the randomkeygenerate function I copied the final code into this value so thats why userinfo is used twice but with different parameters. Now if the code isn't correct, the program basically goes through a sequence of events which tells you if you entered a correct digit inside the code as well as if the number is correct but at the wrong spot. For example a code 1256 with user input 1465 will tell you that 1 is correct, 4 is completely wrong, and 5 and 6 are correct but at the wrong spot. At the end of that it will also display how many digits you had correct, overall, using another parameter inside the userinfo struct. At the end of this branch it references the number of chances you have left to either repeat the function or tell the user they failed and have no chances left.&lt;/p&gt;

&lt;p&gt;Regardless of whether the player succeeded or failed, then it asks the user if they'd like to try again. It simply asks for a y or n character and if the character is y, it calls the function again to repeat the entire process, if the key is not n it repeats endless, and if it is no, then it ends the process. In both yes and no it sets the inputretry to true. The reason for this is because the repeat parameter (pass by reference) is changed in both cases to one or the other which is referenced by the main function. Anything other than y or Y will terminate the program. This will be explained next.&lt;/p&gt;

&lt;p&gt;This is what the main section looks like that starts the process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;int main()
{
    srand(time(NULL));      // random time seed for randomness
    int numberlist[10] = { 0, 1, 2, 3, 4, 5, 6, 7 ,8 , 9 };     // array of numbers that will be used for references later
    int *secretcode = new int[4];                               // dynamic pointer that will be used for secrete code until the end of the programs life cycle
    char repeat('y');                                           // a repeat character that is initialized to Y initially

    // Perform this loop while the repeat variable is equal to Y or y for yes. Repeat variable is changed inside the guessingSequence function
    do
    {
        randomKeySelection(secretcode, numberlist, size(numberlist));       // custom function that sets the secret code based on the numberlist array

        cout &amp;lt;&amp;lt; "Welcome. You have 8 chances to guess the correct 4 digit code sequence." &amp;lt;&amp;lt; endl;
        guessingSequence(secretcode, 7, repeat);                            // This function asks the user to guess the code and handles all important brances such as continuations and failures
    } while (repeat == 'y' || repeat == 'Y');

    // This means the end. If the secretcode is not equal to NULL, destroy it and release the memory
    if (secretcode != NULL)
        delete secretcode;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see here the main function intializes the basic functions and checks for input only when the guessingSequence function is finished. When it's yes everything is repeated, when no this loop stops and finally the secretcode pointer is dereferenced and released.&lt;/p&gt;

&lt;p&gt;These are the header files if you'd like to build the application and test it for yourself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;random&amp;gt;
#include &amp;lt;ostream&amp;gt;
#include &amp;lt;string&amp;gt;
#include &amp;lt;sstream&amp;gt;
#include &amp;lt;istream&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No external software, toolkits and frameworks were used here other than visual studio (2017) itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Postmortem:&lt;/strong&gt; &lt;br&gt;
So there are a few things I learned in this project before it reached its conclusion. The first was input. Originally it wasn't only a simple character input, but I opted for an entire sequence of character and the approach was different. While I was able to limit it to about four characters I determined that my current approach ultimately suited my needs better and makes it easy to prevent errors, something I initially did not notice until I started stress testing the application. The second thing I opted for was the InfoStruct to hold all my information. This turned out to be a good decision as intially the program was initially more clunky and messier than it is now. I failed to fully plan out the scope and depth of this project which is something I'll keep in mind for my projects going forward. &lt;/p&gt;

&lt;p&gt;If you made it this far thank you so much for reading. I hope you were able to learn a little bit not only about the application but my thought process as well. Till next time,&lt;/p&gt;

&lt;p&gt;Christian&lt;/p&gt;

</description>
      <category>visualstudio</category>
      <category>cpp</category>
      <category>programming</category>
    </item>
    <item>
      <title>Library Simulation</title>
      <dc:creator>CBanks901</dc:creator>
      <pubDate>Tue, 08 Mar 2022 09:41:51 +0000</pubDate>
      <link>https://dev.to/cbanks901/library-simulation-27ll</link>
      <guid>https://dev.to/cbanks901/library-simulation-27ll</guid>
      <description>&lt;p&gt;I’d like to talk about a library simulation that I created using C++. Basically, it simulates an environment of people going into a library and checking out books, as well as outputting information about books such as their shelves, pages, etc. There are a few things to know beforehand:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. This program uses quite a few classes and structs that are linked together in a fashion to display data i.e. (Bookshelf contains the books, books contain history, and the people are linked to active books etc.)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. There are no external libraries like boost included in this project&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The data is predetermined but also randomized from a hardcoded set of values meaning the output won’t always be exactly the same but will be similar every time&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Each book only has three copies, so when that limit is reached, the book cannot be checked out again&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With that out of the way I’d like to break down all of the functions that I used here:&lt;/p&gt;

&lt;p&gt;• &lt;u&gt;struct DualReturnType&lt;/u&gt; – a custom struct I made that allows me to store pointer data as well as its size in one return value as a means of easy access&lt;/p&gt;

&lt;p&gt;• &lt;u&gt;LibraryGuests int const&lt;/u&gt; - a constant integer value that holds the maximum number of people I wanted in the simulation&lt;/p&gt;

&lt;p&gt;• &lt;u&gt;ID&lt;/u&gt; – a static counter that increases when the guests are added&lt;/p&gt;

&lt;p&gt;• &lt;u&gt;Class Person&lt;/u&gt; – class that holds all information about an individual such as their names and the books that they have currently&lt;/p&gt;

&lt;p&gt;• &lt;u&gt;class BookHistory&lt;/u&gt; – A custom class that specifically holds the history of a book, primarily being who checked it out with information about the name in a way that can be easily printed out&lt;/p&gt;

&lt;p&gt;• &lt;u&gt;class Book&lt;/u&gt; – a book class that holds information about a book including its name, the number of pages, copies available, and a reference to a BookHistory instance&lt;/p&gt;

&lt;p&gt;• &lt;u&gt;class BookShelf&lt;/u&gt; – Acts as a real-world bookshelf so it contains a list of only 13 books per shelf (instance) and is something that is referenced when looking for books. Shelves correspond to the letter A-Z&lt;/p&gt;

&lt;p&gt;• &lt;u&gt;class BookGroup&lt;/u&gt; – The database of this program. It references almost all other classes such as Books and shelves and handles has references to them. When a request is made, it is done through this class.&lt;/p&gt;

&lt;p&gt;• &lt;u&gt;void SetUpBookNames&lt;/u&gt; function – Takes care of the task of seting up the BookGroup main reference with data such as the names and pages that are used in the program&lt;/p&gt;

&lt;p&gt;• &lt;u&gt;void setUpBookNames&lt;/u&gt; function – Same as the SetUpBookNames but with the library guests only.&lt;/p&gt;

&lt;p&gt;• &lt;u&gt;void Main&lt;/u&gt; – Sets up the program with required instancing of the guests, book names and book group instance in order to run. Made to loop until the user terminates the program&lt;/p&gt;

&lt;p&gt;• &lt;u&gt;class UserInputHelperClass&lt;/u&gt; – a class that handles the input directions that the user takes, whether that is searching for a person, book, or terminating the program&lt;/p&gt;

&lt;p&gt;Now I’d like to give a synopsis of each of these variables and functions in more detail.&lt;/p&gt;

&lt;p&gt;The first being the DualReturn Type struct. The DualReturnType struct is a struct that takes in a pointer and its size as references in its constructor. The only purpose of this is to make it easier for me reference pointers in other spaces of the program, particularly in the BookShelf class.&lt;/p&gt;

&lt;p&gt;Here is the code for that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Helper struct that returns pointers and their sizes for use in other functions
struct DualReturnType
{
    // The default constructor. Parameters are the array and size.
    DualReturnType(int *Ref, int Size)
    {
        // checker to make sure the parameter value isn't equal to NULL
        if (Ref != NULL)
        {
            int_Array = Ref;
            int_size = Size;
        }
        // If the incoming pointer is NULL, output an error message
        else
            cout &amp;lt;&amp;lt; "Error: failed to initialize integer dual type" &amp;lt;&amp;lt; endl;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// The default constructor for this struct. Makes everything NULL
DualReturnType()
{
    int_Array = NULL;
    int_size = 0;
}

// An integer array pointer, and a integer size variable
int *int_Array, int_size;

// Same as the specialized constructor but as a void function
void Initialize_Int_Type(int *Ref, int Size)
{
    if (Ref != NULL)
    {
        int_Array = Ref;
        int_size = Size;
    }
    else
        cout &amp;lt;&amp;lt; "Error: Failed to initialize integer dual type" &amp;lt;&amp;lt; endl;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;};&lt;/p&gt;

&lt;p&gt;The next class is the person class. The person class in its constructor initializes some default values including the name, the two books (array) they are allowing to check (“” or empty) as well as the book counter (hash key) which increases when a book is added to this class. The class also has a ID similar to a library card that is specifically used to identify people even if you don’t know their name and it can be easily tracked. The only three functions of this class are to update the books array inside it (to take away or add books) and to display their info in the special function when desired. &lt;/p&gt;

&lt;p&gt;Here is the code for that below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// The Person/Guest for this simulation. Has parameters attached to it such as ID, booklimits, name, etc...
class Person
{
public:
    //Default constructor which initializes all values to basic functions.
    Person()
    {
        name = "Empty";
        BookLimit = 2;
        behavior = "Browsing";
        GuestID = 0;
        books[0] = "";
        books[1] = "";
        bookcounter = 0;
    }

    // Copy constructor
    Person(const Person &amp;amp;copy)
    {
        name = copy.name;
        BookLimit = copy.BookLimit;
        behavior = copy.behavior;
        GuestID = copy.GuestID;
        books[0] = "";
        books[1] = "";
        bookcounter = 0;
    }

    // Initialize name if the incoming string is valid
    Person(string Name)
    {
        if (!Name.empty())
            this-&amp;gt;name = Name;
        else
        {
            cout &amp;lt;&amp;lt; "This person doesn't have a valid name." &amp;lt;&amp;lt; endl;
            name = "Empty";
        }
        BookLimit = 2;
        behavior = "Browsing";

        books[0] = "";
        books[1] = "";
        bookcounter = 0;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Default destructor
~Person()
{

}

// Adds a book to the person's book array
void AddBook(string BookName)
{
    if (bookcounter &amp;lt;= 1)
    {
        books[bookcounter] = BookName;
        bookcounter++;
    }
    else
        cout &amp;lt;&amp;lt; "Person()::AddBook cannot add more books\n";
}

// Prints the books that a person added
void PrintBooks()
{
    if (bookcounter &amp;gt; 0)
    {
        cout &amp;lt;&amp;lt; name &amp;lt;&amp;lt; " current books:              ";
        for (int i = 0; i &amp;lt; bookcounter; ++i)
        {
            if (books[i] != "")
                cout &amp;lt;&amp;lt; i+1 &amp;lt;&amp;lt; ": " &amp;lt;&amp;lt; books[i] &amp;lt;&amp;lt; "      ";
        }

        cout &amp;lt;&amp;lt; "\n";
    }
    else
        cout &amp;lt;&amp;lt; name &amp;lt;&amp;lt; " has no history yet.\n";
}

// Prints the general info about this person
void PrintGeneralInfo()
{
    cout &amp;lt;&amp;lt; "Name: " &amp;lt;&amp;lt; name &amp;lt;&amp;lt; "\tBooks in possession: " &amp;lt;&amp;lt; bookcounter &amp;lt;&amp;lt; "\tGuestID: " &amp;lt;&amp;lt; GuestID &amp;lt;&amp;lt; endl;
}

string name, behavior, books[2];                        // Name of the person, and arrayof booknames
int BookLimit, GuestID, bookcounter;                    // BookLimit to limit the person inside the library to a certain amount, and that persons GuestID, bookcounter to access current book   
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;};&lt;/p&gt;

&lt;p&gt;The next class is BookHistory. It has a public BookName menu, a private counter variable, Person pointer called people, a integer variable called currentlimit and a string order variable. There are only two functions inside this class which are AddHistory and PrintHistory. AddHistory takes an incoming Person object and adds it to the people reference of this class, and the other one simply prints out the data contained in this class along with the bookname. &lt;/p&gt;

&lt;p&gt;Here is what all that looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Records the history of a book which can be called at any time later
class BookHistory
{
public: 
    string bookName;                            // Name of the book that is recorded
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Default constructor which initializes all variables
BookHistory()
{
    people = new Person[3];
    currentLimit = 3;
    currentCounter = 0;
    order[0] = "first.";
    order[1] = "second.";
    order[2] = "third.";
}

// Copy constructor which initializes based on another bookHistory reference
BookHistory(const BookHistory &amp;amp;otherBookHistory)
{
    currentLimit = otherBookHistory.currentLimit;
    people = new Person[currentLimit];
    currentCounter = otherBookHistory.currentCounter;
    order[0] = "first.";
    order[1] = "second.";
    order[2] = "third.";

    for (int i = 0; i &amp;lt; currentCounter; i++)
        people[i] = otherBookHistory.people[i];
}

// Destructor which only destroys our people pointer
~BookHistory()
{
    if (people != NULL)
        delete [] people;
}

// How people are added to this books history. 
void AddHistory(Person person)
{
    // If the currentcounter hasn't yet reached the limit, then set the people pointer inside our history to the incoming person. Basically adds it inside the array
    if (currentCounter &amp;lt; currentLimit)
    {
        people[currentCounter] = person;
        currentCounter++;                   // finally increase the currentCounter
    }
    else
        cout &amp;lt;&amp;lt; "Cannot update this books history at this time" &amp;lt;&amp;lt; endl;
}

// Prints the histoy of this book based on the currentCounter which increases when people check out this book
void PrintHistory()
{
    if (currentCounter &amp;gt;= 1)
    {
        // Will print the persons Info assuming the people pointer isn't NULL and it's name isn't == Empty
        for (int i = 0; i &amp;lt; currentCounter; i++)
        {
            if (people != NULL)
                if (people[i].name != "Empty")
                    cout &amp;lt;&amp;lt; people[i].name &amp;lt;&amp;lt; " ID: " &amp;lt;&amp;lt; people[i].GuestID &amp;lt;&amp;lt; " checked out '" &amp;lt;&amp;lt; bookName &amp;lt;&amp;lt; "' " &amp;lt;&amp;lt; order[i] &amp;lt;&amp;lt; "\n\n";
                else
                    cout &amp;lt;&amp;lt; "No names setup for this book\n";
        }
    }
    else
        cout &amp;lt;&amp;lt; bookName &amp;lt;&amp;lt; " has no check out history yet.\n\n";       // This should print out if the current counter isn't at least equal to 1. Book has no history.
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private:
    Person *people;                         // people pointer which holds references to anyone who checks out this book
    int currentLimit;                       // A max limit variable which is initialized to 3 for this simulation
    int currentCounter;                     // A counter that goes up until it reaches the currentLimit
    string order[3];                        // Simply a string helper which has strings based on the order of an index. So 0 = first, 1 = seconds, 2 = third. 
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next class I’d like to touch on is the Book class. The book class has all public members including the number of pages in a book, its copies, availability, name and a BookHistory class member. Its functions include checking for empty books and removing copies of the book if the number of copies equals 0, which decreases when checked out. The constructor initializes most data with arguments passed in or without them.&lt;/p&gt;

&lt;p&gt;Have a look here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Book class which is used to house all information about a book including its name, number of pages, whether it's avaiable or not, its history, and number of copies
class Book
{
public:
    // Default constructor for this class. Intializes all values. Name of the book is blank (set elsewhere), pages is also reset elsewhere, copies is set to 3,
    // avaialable is set to true, and the the historys bookname is set to empty
    Book()
    {
        name = "Empty";
        pages = 0;
        copies = 3;
        available = true;
        thisBookHistory.bookName = "Empty";
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Book with all parameters setup to copy into this variables
Book(string BookName, int numPages, int copies, BookHistory book)
{
    name = BookName;
    pages = numPages;
    thisBookHistory = book;
    available = true;
    this-&amp;gt;copies = copies;
}

// Destructor of the book class
~Book()
{

}

// If the book is a dummy or a real book
bool emptyBook()
{
    if (name == "" || name == "Empty")
        return true;
    else
        return false;
}

// Removes a copy of the book from the list. Once a copy reaches zero, no one may check out this book
void RemoveCopy()
{
    // Simply decrease the number of copies by 1 and return
    if (copies &amp;gt;= 2)
    {
        copies -= 1;
    }
    // If the copy equals 1, then this is the last copy of the book and available should be set to false for other functions. Copies is also decremented by 1
    else if (copies == 1)
    {
        available = false;
        //cout &amp;lt;&amp;lt; "This is the last copy of " &amp;lt;&amp;lt; name &amp;lt;&amp;lt; endl;
        copies -= 1;
    }
    // This shouldn't occur but is set just in case this function is called by accident
    else
        cout &amp;lt;&amp;lt; "Sorry. " &amp;lt;&amp;lt; "No more copies of: " &amp;lt;&amp;lt; name &amp;lt;&amp;lt; " are avaialable.\n";
}

string name;                    // Name of the book
int pages, copies;              // The number of pages of the book and its copies
bool available;                 // Whether the book is available or not. Used in the bookshelf class
BookHistory thisBookHistory;    //History variable of the book which can be called by the shelf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;};&lt;/p&gt;

&lt;p&gt;The next one is the Bookshelf class. This class is akin to a library bookshelf and its intended design is to have more than one that corresponds to groups of two letters. So in total there are only thirteen of them they are in order by integer. So bookshelf[0] corresponds to books starting with A and B, bookshelf[1] C and D and so on. It has all public members which include a twelve array of Books (matching the shelves), a string which holds the shelfID, a filledboolean for easy access, a fullindex array of size twelve also matching the shelf, and a stockcounter that holds the books available for use. Its functions include a AddBook function which Adds a book and its pages to the class, a PrintAllBooksOnShelf class which prints all the books currently available on this shelf, a printbyindex function which does the same thing but in a limited fashion by first checking if the incoming index is valid, two printbookhistory functions which do the same thing as printindex and printall, a locateBook Boolean helper which returns true or false if a book is found, a getbookID function which tries to find a book by it’s ID instead of name using the locateBook function, a Boolean helper called AllBooksTaken which searches through all books to find one that isn’t false, and finally DualReturnType helper function called ReferenceArrayHelper which uses the StockCounter integer value to manually create a integer pointer reference that can be used in other places, such as the BookGroup which will be covered next.&lt;/p&gt;

&lt;p&gt;Here’s what the Bookshelf looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Bookshelf class that holds all data about a bookshelf instance. 
class Bookshelf
{
public:
    // Default constructor. Sets stockcounter (current books) to 0, then set fullindex incidies to the value in the loop
    Bookshelf()
    {
        StockCounter = 0;
        for (int i = 0; i &amp;lt;= 11; ++i)
            fullindex[i] = i;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Destructor
~Bookshelf()
{

}

// Add a book to this shelf. Parameters include the name of the book and its pages.
void AddBook(string BookName, int pages)
{   
    // If current book couner isn't at its max (12), then proceed
    if (StockCounter &amp;lt;= 11)
    {
        //  If the current name of the book is empty, prepare to replace it with the parameters.
        if (books[StockCounter].name == "Empty")
        {
            books[StockCounter].name = BookName;
            books[StockCounter].pages = pages;
            books[StockCounter].thisBookHistory.bookName = BookName;
            StockCounter++;                                         // Increase the number of books on this instance by 1       
        }
        // if we tried to add a name that wasn't valid. However this won't trigger because of the stockCounter variable after the last add
        else
            cout &amp;lt;&amp;lt; "Somehow, this spot is already taken\n";
    }
    else
    {
        cout &amp;lt;&amp;lt; "No more room on this shelf to add new books\n";        //  Prints if we tried to add a book but the current value exceeds 11
    }
}

// Prints all books data that are currently on the shelf
void PrintAllBooksOnShelf()
{
    string available = "";
    for (int i = 0; i &amp;lt; StockCounter; ++i)
    {
        books[i].available ? available = "Yes" : available = "No";

        cout &amp;lt;&amp;lt; "Shelf ID: " &amp;lt;&amp;lt; shelfID &amp;lt;&amp;lt; " \tBook number: " &amp;lt;&amp;lt; i+1 &amp;lt;&amp;lt; "      Book name: " &amp;lt;&amp;lt; books[i].name 
            &amp;lt;&amp;lt; " \tPages: " &amp;lt;&amp;lt; books[i].pages &amp;lt;&amp;lt; " \tAvailabile: " &amp;lt;&amp;lt; available &amp;lt;&amp;lt; endl;
    }
}

// Print the books general data based on a index parameter assuming it is in bounds
void PrintBookByIndex(int index)
{
    // Temp string to hold the avialability string to print out to the user
    string available = " ";

    // If the book we want is available, set the available string to Yes, otherwise it is set to no
    books[index].available ? available = "Yes" : available = "No";

    // Print the information that we want about this book
    if (index &amp;gt;= 0 &amp;amp;&amp;amp; index &amp;lt;= 11)
        cout &amp;lt;&amp;lt; "Shelf ID: " &amp;lt;&amp;lt; shelfID &amp;lt;&amp;lt; ". Book number: " &amp;lt;&amp;lt; index+1 &amp;lt;&amp;lt; ". Book name: " &amp;lt;&amp;lt; books[index].name
        &amp;lt;&amp;lt; ". Pages: " &amp;lt;&amp;lt; books[index].pages &amp;lt;&amp;lt; ". Available: " &amp;lt;&amp;lt; available &amp;lt;&amp;lt; endl;
}

// Prints the usage history of a specific book assuming its index is in bounds
void PrintBookHistory(int bookID)
{
    if (bookID != -1 &amp;amp;&amp;amp; bookID &amp;lt;= 11)
        books[bookID].thisBookHistory.PrintHistory();
}

// Prints all of the history of all current books on this shelf only
void PrintAllBookHistory()
{
    for (int i = 0; i &amp;lt; StockCounter; ++i)
    {
        books[i].thisBookHistory.PrintHistory();
    }
}

// Attempts to find a single book based on the name.
bool LocateBook(string BookName)
{
    //cout &amp;lt;&amp;lt; endl;
    // Loop through the elements and if the parameter name matches any of the elements name, Simply return true to indicate success.
    for (int i = 0; i &amp;lt;= StockCounter - 1; ++i)
    {
        if (BookName == books[i].name)
            return true;
    }

    // This occurs if we went through all elements and there is no match. In this case print a message and return false to indicate failure.
    cout &amp;lt;&amp;lt; BookName &amp;lt;&amp;lt; " does not exist on shelf " &amp;lt;&amp;lt; shelfID &amp;lt;&amp;lt; "." &amp;lt;&amp;lt; endl;
    return false;
}

// Attempts to grab a booksID based on that books name.
int GetBookID(string BookName)
{
    int bookID = -1;
    if (LocateBook(BookName))
    {
        for (int i = 0; i &amp;lt; StockCounter; ++i)
        {
            // If a match was found, then break the loop and set the id to i.
            if (BookName == books[i].name)
            {
                bookID = i;
                break;
            }
        }
    }
    return bookID;
}

// Boolean return type based on the filled boolean variable. If ANY book is still available, this will return false. Otherwise it will return true.
bool AllBooksTaken()
{
    for (int i = 0; i &amp;lt; 12; ++i)
    {
        // If a book is available, set filled to false and return immediately
        if (books[i].available)
        {
            filled = false;
            return filled;
        }
        // If a book isn't available, then set the fullindex based on that space to -1, used for ReferenceArrayHelper().
        else
            fullindex[i] = -1;
    }

    // If we got here, this shelf really is full and return true.
    filled = true;
    return filled;
}

// DualReturnType reference funcion that will return a pointer and its size together.
DualReturnType ReferenceArrayHelper()
{
    int SizeCounter(0);                         // SizeCounter reference to determine valid books inside the shelf

    // Loop through the active books on the shelf and if the fullindex based on the loop value i is equal to -1, increase the sizecounter variable.
    // This is to intialize another variable later so that it only contains valid indicies from the shelf.
    for (int i = 0; i &amp;lt; StockCounter; ++i)
    {
        if (fullindex[i] != -1)
            SizeCounter += 1;
    }

    // Assuming that at least one of the elements in the above was valid (SizeCounter &amp;gt;=1), proceed.
    if (SizeCounter &amp;gt;= 1)
    {
        int *indexArray = new int[SizeCounter];             // Create a pointer array that is based on the SizeCounter index;
        int indexCounter = 0;                               // new variable reference that tracks the indices of the indexArray. This is so we can set them as we proceed
                                                            // through the loop based on its own counter

        // Loop through the StockCounter again and if the sizecounter is greater than or equal to 1, proceed with the following
        for (int i = 0; i &amp;lt; StockCounter; ++i)
        {
            // If the fullindex element isn't -1, the proceed.
            if (fullindex[i] != -1)
            {
                if (SizeCounter &amp;gt;= 1)
                {
                    indexArray[indexCounter] = i;           // Set the indexArray element based on the current counter equal to i in the loop to indicate a goood value
                    indexCounter++;                         // Increase the index counter by 1 to move to the next element
                    SizeCounter--;                          // Decrease the counter since we hit a successfull element
                }
                else
                {
                    break;                                  // If the sizecounter has gone below 1, stop since there are no other valid elements
                }
            }
        }

        // Finally return this newly created array, along with the index counter, which is indexArray's size
        return DualReturnType(indexArray, indexCounter);
    }
    else
        return DualReturnType();        // IF we got here, return a default or blank DualReturnType
}

Book books[12];                                 // Array of books in that shelf
string shelfID;                                 // String that containts the name of each shelfID
int StockCounter;                               // The number of books that are actually avialable to use, increases when books are added
bool filled;                                    // If the entire structure is taken
int fullindex[12];                              // Useful when checking out a book. This is so this same book isn't looked at again. (Removed from the pool)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;};&lt;/p&gt;

&lt;p&gt;The BookGroup class houses all information containing to books and shelves. After the main setup functions and input class, this is the class that is referencing when adding, looking, finding or removing information pertaining to books, the people, and history. It has one private member which is the bookshelf array which is done to prevent data pertaining to it to be easily modified simply from creating an instance of this class alone. Changing data around it requires using the member functions which calls data and functions inside the class pertaining to the objective required. &lt;br&gt;
It’s members include a constructor, a FindBook Boolean function, a void AddBook function, a void AddBooks function, a getbookshelfID index based on the book name, a GetbookshelfID string function, three printbook variants which prints all of them, one by index, and one by the shelfID, a void CheckoutBook function which takes a person reference and their desired book, a randomBookSelection string helper function which grabs a book without needing to input the name, two bookhistory helper functions which prints book history by shelves, a GetBook Book return type which tries to find a book by its shelfID and spot, and finally a GetBook string function which directly gives the user the name of a book at a certain spot. This one is very long so I won’t be explaining it here.&lt;/p&gt;

&lt;p&gt;I wrote a lot of notes on it though here if you want to go through it yourself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// The main class that controls everything. Operating as the library's database, this class houses all bookshelves and the bookshelves house the books.
class BookGroup
{
public:
    // Default constructor that sets up the bookshelves
    BookGroup()
    {
        // Create a string that has all of the letters of the alphabet
        string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    int stringcounter = 0;          // Counter variable that will be used to pull letters out of the alpabet variable

    // Loop based on the total number of shelves (12 in total).
    for (int i = 0; i &amp;lt; 13; ++i)
    {
        // Make the shelf ID a group of two from the alphabet. So shelf 1 = AB, 2 = CD, 3 = EF etc...
        // Uses the stringcounter as a index from the alphabet in groups of 2. So 0 first then 0 + 1 next. Then simply increase the string counter by 2
        // so when we get here again it references the next set of letters. 
        bookshelf[i].shelfID.append(1, alphabet[stringcounter]);
        bookshelf[i].shelfID.append(1, alphabet[stringcounter + 1]);

        stringcounter += 2;
    }

}

// Default destructor which does nothing
~BookGroup()
{

}

// Find a book based on its name. 
bool FindBook(string book)
{
    // holder boolean which is initialized to false
    bool returnvalue = false;

    // Shelf holder that will be changed based on the first letter of the book (parameter)
    int Shelf = 0;

    // Create a single character variable which references the first character inside the book parameter
    char bookcopy = book[0];

    // Capatitalize this letter to avoid errors and to match the switch case below
    bookcopy = toupper(bookcopy);

    // Switches based on the bookcopy variable
    switch (bookcopy)
    {
    case 'A':
        //cout &amp;lt;&amp;lt; "Letter A \n";
        break;
    case 'B':
        //cout &amp;lt;&amp;lt; "Letter B \n";
        break;
    case 'C':
        //cout &amp;lt;&amp;lt; "Letter C \n";
        Shelf = 1;
        break;
    case 'D':
        //cout &amp;lt;&amp;lt; "Letter D \n";
        Shelf = 1;
        break;
    case 'E':
        //cout &amp;lt;&amp;lt; "Letter E \n";
        Shelf = 2;
        break;
    case 'F':
        //cout &amp;lt;&amp;lt; "Letter F \n";
        Shelf = 2;
        break;
    case 'G':
        //cout &amp;lt;&amp;lt; "Letter G \n";
        Shelf = 3;
        break;
    case 'H':
        //cout &amp;lt;&amp;lt; "Letter H \n";
        Shelf = 3;
        break;
    case 'I':
        //cout &amp;lt;&amp;lt; "Letter I \n";
        Shelf = 4;
        break;
    case 'J':
        //cout &amp;lt;&amp;lt; "Letter J \n";
        Shelf = 4;
        break;
    case 'K':
        //cout &amp;lt;&amp;lt; "Letter K \n";
        Shelf = 5;
        break;
    case 'L':
        //cout &amp;lt;&amp;lt; "Letter L \n";
        Shelf = 5;
        break;
    case 'M':
        //cout &amp;lt;&amp;lt; "Letter M \n";
        Shelf = 6;
        break;
    case 'N':
        //cout &amp;lt;&amp;lt; "Letter N \n";
        Shelf = 6;
        break;
    case 'O':
        //cout &amp;lt;&amp;lt; "Letter O \n";
        Shelf = 7;
        break;
    case 'P':
        //cout &amp;lt;&amp;lt; "Letter P \n";
        Shelf = 7;
        break;
    case 'Q':
        //cout &amp;lt;&amp;lt; "Letter Q \n";
        Shelf = 8;
        break;
    case 'R':
        //cout &amp;lt;&amp;lt; "Letter R \n";
        Shelf = 8;
        break;
    case 'S':
        //cout &amp;lt;&amp;lt; "Letter S \n";
        Shelf = 9;
        break;
    case 'T':
        //cout &amp;lt;&amp;lt; "Letter T \n";
        Shelf = 9;
        break;
    case 'U':
        //cout &amp;lt;&amp;lt; "Letter U \n";
        Shelf = 10;
        break;
    case 'V':
        //cout &amp;lt;&amp;lt; "Letter V \n";
        Shelf = 10;
        break;
    case 'W':
        //cout &amp;lt;&amp;lt; "Letter W \n";
        Shelf = 11;
        break;
    case 'X':
        //cout &amp;lt;&amp;lt; "Letter X \n";
        Shelf = 11;
        break;
    case 'Y':
        //cout &amp;lt;&amp;lt; "Letter Y \n";
        Shelf = 12;
        break;
    case 'Z':
        //cout &amp;lt;&amp;lt; "Letter Z \n";
        Shelf = 12;
        break;
    default:
        cout &amp;lt;&amp;lt; "First letter is not A - Z. Error.\n";
        break;
    }

    // Now that we have our shelf index, then attempt to find the book based on that shelf
    bool FoundBook = bookshelf[Shelf].LocateBook(book);

    // If the FoundBook boolean is equal to true, set the returnvalue to true and the same if its the opposite
    FoundBook ? returnvalue = true: returnvalue = false;
    return returnvalue;
}

// Adds a single book based on a int array value. 
void AddBook(string BookName, int *PagesArray, int PageIndex)
{
    int Shelf = GetBookShelfID_Index(BookName);             // Get the bookID based on the bookName

    // If the shelfID isn't equal to negative one proceed normally, otherwise output a error message
    if (Shelf != -1)
        bookshelf[Shelf].AddBook(BookName, PagesArray[PageIndex]);
    else
        cout &amp;lt;&amp;lt; "Error in AddBook: Impossible to add " &amp;lt;&amp;lt; BookName &amp;lt;&amp;lt; " to the list";
}

// Adds a array of strings to the shelf based size of the array
void AddBooks(string *Books, int BookSize, int *PageArray)
{
    for (int Shelf, i = 0; i &amp;lt; BookSize; ++i)
    {
        Shelf = GetBookShelfID_Index(Books[i]);
        if (Shelf != -1)
        {
            bookshelf[Shelf].AddBook(Books[i], PageArray[i]);
        }
        else
            break;
    }
}

// Get the shelf index based on the first letter of the incoming string. Return that index. If the later cannot be found, return -1
int GetBookShelfID_Index(string Name)
{

    Name[0] = toupper(Name[0]);
    if (Name[0] == 'A' || Name[0] == 'B')
        return 0;
    else if (Name[0] == 'C' || Name[0] == 'D')
        return 1;
    else if (Name[0] == 'E' || Name[0] == 'F')
        return 2;
    else if (Name[0] == 'G' || Name[0] == 'H')
        return 3;
    else if (Name[0] == 'I' || Name[0] == 'J')
        return 4;
    else if (Name[0] == 'K' || Name[0] == 'L')
        return 5;
    else if (Name[0] == 'M' || Name[0] == 'N')
        return 6;
    else if (Name[0] == 'O' || Name[0] == 'P')
        return 7;
    else if (Name[0] == 'Q' || Name[0] == 'R')
        return 8;
    else if (Name[0] == 'S' || Name[0] == 'T')
        return 9;
    else if (Name[0] == 'U' || Name[0] == 'V')
        return 10;
    else if (Name[0] == 'W' || Name[0] == 'X')
        return 11;
    else if (Name[0] == 'Y' || Name[0] == 'Z')
        return 12;
    else
    {
        cout &amp;lt;&amp;lt; "Error in the bookshelfID grabber function" &amp;lt;&amp;lt; endl;
        cout &amp;lt;&amp;lt; Name &amp;lt;&amp;lt; endl;
        return -1;
    }
}

// string return of the bookID based on the Name of a book
string GetBookShelfID(string Name)
{
    // Get and Set the index variable to the index based off the name
    int ShelfID_Index = GetBookShelfID_Index(Name);

    // If index is within bounds then return the ID, otherwise return NULL
    if (ShelfID_Index &amp;gt;= 0 &amp;amp;&amp;amp; ShelfID_Index &amp;lt;= 12)
        return bookshelf[ShelfID_Index].shelfID;
    else
        return "NULL";
}

// Simply prints the books in order by shelves. Calls the shelf variables PrintAllBooksOnShelf 
void PrintAllBooks()
{
    int AllShelves = sizeof(bookshelf) / sizeof(bookshelf[0]);      // Size that we'll loop through
    for (int i = 0; i &amp;lt; AllShelves; ++i)
    {
        bookshelf[i].PrintAllBooksOnShelf();                    // Prints all books per shelf in the array
    }
}

// Print all the books based on a desired shelf
void PrintBooksByShelf(int shelf)
{
    if (shelf &amp;gt;= 0 &amp;amp;&amp;amp; shelf &amp;lt;= 12)
        bookshelf[shelf].PrintAllBooksOnShelf();            // Prints all books on the shelf that we want
}

// Print a specific book with its shelf and slot index
void PrintBookByShelfAndID(int shelf, int bookID)
{
    bookshelf[shelf].PrintBookByIndex(bookID);
}

// The actual function that checks out books from the shelevs. Requires a guest parameter, and that guests desired book to be checked out. 
// This function will continue until a successful book has been removed. The library has been adjusted to accomodate this.
void CheckoutBook(Person &amp;amp;guest, string desiredBook)
{
    // Guest name cannot be blank
    if (guest.name != "Empty")
    {
        // Guest must be able to at least check out one book
        if (guest.BookLimit &amp;gt;= 1)
        {
            // attempts to find the guests desired book
            bool FoundBook = FindBook(desiredBook);

            // If it is found proceed.
            if (FoundBook)
            {
                // Gathers the shelfID and the bookID based on the desiredbook
                int Shelf = GetBookShelfID_Index(desiredBook);
                int bookID = bookshelf[Shelf].GetBookID(desiredBook);

                // If the shelf and bookIDs are -1(failure) then proceed.
                if (Shelf != -1 &amp;amp;&amp;amp; bookID != -1)
                {
                    // Checker to detrmine if all the books on the desired shelf are empty or not
                    bool AllbooksTaken = bookshelf[Shelf].AllBooksTaken();

                    // If its NOT TRUE that all the books are gone, proceed
                    if (!AllbooksTaken)
                    {
                        // If the book that we want is still available, proceed
                        if (bookshelf[Shelf].books[bookID].available)
                        {
                            // Add this person to book they wants history. Reduce this persons booklimit by 1 Add the book to their reference. Finally 
                            // reduce the number of the copies of the book by calling the books removecopy function
                            bookshelf[Shelf].books[bookID].thisBookHistory.AddHistory(guest);
                            guest.BookLimit--;
                            guest.AddBook(desiredBook);
                            bookshelf[Shelf].books[bookID].RemoveCopy();
                        }
                        // This shouldn't execute but is set just in case. Simply recalls this same function again but sets SelectRandomBook() as the second
                        // argument (desiredBook) and keeps the guest reference the same. So the guest is simply searching for another book
                        else
                        {
                            cout &amp;lt;&amp;lt; "Sorry, " &amp;lt;&amp;lt; desiredBook &amp;lt;&amp;lt; " is not currently available" &amp;lt;&amp;lt; endl;
                            return CheckoutBook(guest, SelectRandomBook() );
                        }
                    }
                    else
                        cout &amp;lt;&amp;lt; "Sorry all books have been taken on this shelf. \n";
                }
                else
                    cout &amp;lt;&amp;lt; "Program error. Shelf and or bookID were not initialized properly.\nShelfID: " &amp;lt;&amp;lt; 
                    Shelf &amp;lt;&amp;lt; ". BookID: " &amp;lt;&amp;lt; bookID &amp;lt;&amp;lt; ". Desired book: " &amp;lt;&amp;lt; desiredBook &amp;lt;&amp;lt; endl; // Either there was a failure or something went wrong
            }
            else
                cout &amp;lt;&amp;lt; "Sorry. " &amp;lt;&amp;lt; desiredBook &amp;lt;&amp;lt; " doesn't exist in this library!" &amp;lt;&amp;lt; endl;
        }
        else
            cout &amp;lt;&amp;lt; "Sorry, you can't check out any more books" &amp;lt;&amp;lt; endl;
    }
    else
        cout &amp;lt;&amp;lt; "Error, guest must have a valid name" &amp;lt;&amp;lt; endl;
}

// Attempts to return a random book name on one of the shelves. This function will repeat until a reliable name is found.
string SelectRandomBook()
{
    string bookName = "Empty";                      // Empty bookName holder

    int shelfID(rand() % 13),                       // shelfID picks a random shelf between 0 and 13
    bookID;                                         // bookID variable that will be used for later

    if (shelfID != 13)
    {
        bool TakenBooks = bookshelf[shelfID].AllBooksTaken();       // create a bool to hold whether or not all books on the desired shelf are taken or not
        // If Taken isn't true (or isn't full capacity) then proceed to this branch
        if (!TakenBooks)
        {
            DualReturnType intType = bookshelf[shelfID].ReferenceArrayHelper();     // Uses DualReturnType structure to hold a reference based on the Reference
            // Array Helper function with the shelf id and bookshelf.

            // If the array pointer inside our dualtype variable (intType) isn't NULL, proceedd
            if (intType.int_Array != NULL)
            {
                // Initialize this variable based on size we pased into our intType variable
                bookID = rand() % intType.int_size;

                // Important because we created our own array specifically with its own size and values. We get the value inside at the point of the
                // randomly generated bookID
                int originalBookID = intType.int_Array[bookID];

                // If the bookshelf we want and the book inside it that we want are available, proceed.
                if (bookshelf[shelfID].books[originalBookID].available)
                {
                    bookName = GetBookName(shelfID, originalBookID);
                }
                else
                {
                    // If we get here, delete the array reference we set and call this function again(recursion). This will happen until we get a book that isn't taken.
                    // Note: the TakenBooks variable prevents us from needlessly repeating the search
                    delete intType.int_Array;
                    return SelectRandomBook();
                }
                // This continues if the book we want is avaialable
                delete intType.int_Array;
            }
            // This shouldn't happen but is here just in case. Simply recalls this function again
            else
            {
                cout &amp;lt;&amp;lt; "Retrying book selection. " &amp;lt;&amp;lt; endl;
                return SelectRandomBook();
            }
        }
    }
    return bookName;        // If we got here that means the selection was a success. The function ends normally
}

// Simply outputs the history of a desiredbook if it exists on any of the shelves. Different from PrintBooks() which only prints all books on the shelves
void PrintBookHistoryByBook(string Book)
{
    if (Book != "")
    {
        bool Found = FindBook(Book);                                // Bool reference to hold whether or not the book exists on any of the shelves
        int BookSlot(-1);                                           // Slot reference initialized to -1 error

        // If the book was found continue, if not ouput a error message
        if (Found)
        {
            int ShelfID = GetBookShelfID_Index(Book);               // ShelfID variable class the GetShelfID index function based on the book
            BookSlot = bookshelf[ShelfID].GetBookID(Book);          // BookSlot variable class which uses the bookshelf variable based on shelfID to find a book. 
                                                                    // Basically the shelf is used to quicken search time

            // If the bookslot value isn't negative 1 then, then call PrintBookHistory based on the slot we just received
            if (BookSlot != -1)
                bookshelf[ShelfID].PrintBookHistory(BookSlot);
        }
        else
            cout &amp;lt;&amp;lt; Book &amp;lt;&amp;lt; " can't be found. (PrintBookHistoryByBook)\n";
    }
    else
        cout &amp;lt;&amp;lt; "Sorry, you must insert a valid name into PrintBookHistoryByBook().\n";
}

// Prints the history of the books in order from the first shelf to the last
void PrintAllBookHistory()
{
    for (int i = 0; i &amp;lt;= 12; ++i)
    {
        bookshelf[i].PrintAllBookHistory();
    }
}

// Gets a book based on a shelfID parameter and on spot parameter.
Book GetBook(int ShelfID, int spot)
{
    if (ShelfID &amp;gt;= 0 &amp;amp;&amp;amp; ShelfID &amp;lt;= 12 &amp;amp;&amp;amp; spot &amp;gt;= 0 &amp;amp;&amp;amp; spot &amp;lt;= 11)
    {
        return bookshelf[ShelfID].books[spot];
    }
    // If the parameters are out of bounds, then simply return a empty book
    else
    {
        cout &amp;lt;&amp;lt; "Spot or shelfId inside GetBook() is out of bounds\n";
        return Book();
    }
}

// Does the same as the above but simply gives the name directly instead of the entire book
string GetBookName(int shelfID, int bookspot)
{
    // Simply ensures that the shelfID and bookspot variables are within reasonable bounds (0 - 12) &amp;amp; (0 - 11) respectively
    if (shelfID &amp;gt;= 0 &amp;amp;&amp;amp; shelfID &amp;lt;= 12 &amp;amp;&amp;amp; bookspot &amp;gt;= 0 &amp;amp;&amp;amp; bookspot &amp;lt;= 11)
    {
        return bookshelf[shelfID].books[bookspot].name;
    }
    else
    {
        cout &amp;lt;&amp;lt; "ShelfID or bookspot inside GetBookName() is out of bounds";
        return "NULL";
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private:
    Bookshelf bookshelf[13];                                    // array of shelves A-Z AB, CD, EF, etc. Is private so the user can't do things directly
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next up is the UserInputHelperClass. This class only has two functions, which are the HandlePrintBooks and the HandlePrintBooksHistory functions. The HandlePrintBooks function goes in one of three directions: it will print all books by shelves, allow the user to search for a book using the name of the book as well as its shelfID, and finally will terminate on request. It takes in the BookGroup as a parameter. As for the HandlePrintHistory function, it allows you to see the history of all books or a specific one assuming it exists and also allows the user to go back to the main menu upon request. The function allows this to repeat over and over using a loop until a certain key is pressed.&lt;/p&gt;

&lt;p&gt;Here is the code for this here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class UserInputHelperClass
{
public:
    // Handles the print case 1 from the center. This function will do 1 of 3 actions: 1.) Terminate upon user request 2.) Find a specific book by asking for a
    // shelfID and a bookID 3.) PrintAll books on all shelves
    void HanldePrintingAllBooks(BookGroup mainRef)
    {
        cout &amp;lt;&amp;lt; "Would you like to print all books or just one? A for all, 1 for specific, N to return\n";
        char input(' ');

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    // First ask the user for one of three keys, 1, A or N. If the user doesn't do this this will repeat until then
    while (input != '1' &amp;amp;&amp;amp; input != 'A' &amp;amp;&amp;amp; input != 'N')
    {
        // Asks for only a single key only
        input = _getch();

        // Digit checkers so digits won't proceed through. If the key that the user has entered is a lowercase letter, then simply raise it to uppercase
        if (!isdigit(input) )
            if (islower(input))
                input = toupper(input);

        // Simply repeats the same string as the above but with a error message
        if (input != 'A' &amp;amp;&amp;amp; input != '1' &amp;amp;&amp;amp; input != 'N')
            cout &amp;lt;&amp;lt; "Sorry please try again. A for All books, 1 for specific, N for termination\n";
    }

    // Assuming one of the 3 keys above was given, then proceed to execute based on their action.
    switch (input)
    {
        // The first case if the user wants to manually select a book based on index
        case '1':
        {
            cout &amp;lt;&amp;lt; "Please enter a shelfID between 1 to 13 or N to terminate" &amp;lt;&amp;lt; endl;
            int indexShelf = 0;             // initialized bookshelf ID
            int indexBook = 0;                  // initialized book ID
            bool continueLoop = false;          // Boolean to determine whether or not we need to keep asking the user for information
            string holdervalue("");             // will hold the input of our user

            // This will continue on until the user either quits, or they enter a correct value
            while (!continueLoop)
            {
                // ask for user input
                cin &amp;gt;&amp;gt; holdervalue;

                // If the value the user just entered is less than or equal to 2 in length, i.e a number (0 - 99) or two letters, proceed
                if (holdervalue.size() &amp;lt;= 2)
                {
                    // The case for if the size is only one character long
                    if (holdervalue.size() == 1)
                    {
                        // If the only character is a digit, then set our indexShelfID to what that digit is, if it isn't a digit, then captialize the letter inside
                        if (isdigit(holdervalue[0]))
                        {
                            indexShelf = holdervalue[0] - '0';
                        }
                        else
                            holdervalue[0] = toupper(holdervalue[0]);
                    }

                    // The case for if the size is 2, not 1 and not 0
                    else
                    {
                        // If the first character in the input string is a digit, then set the indexShelf variable to this value. Remove the null character to convert
                        // it to a digit. If we got here then if the second character in the string is also a digit, then mutliply the value that's in the indexShelf
                        // already by ten, and then add this second value to the string. This is ensure that the number is what was originally typed. I.e, 77 Index = 7.
                        // 7 * 10 = 70 + 7 = 77
                        if (isdigit(holdervalue[0]))
                        {
                            indexShelf = holdervalue[0] - '0';

                            if (isdigit(holdervalue[1]))
                            {
                                indexShelf *= 10;
                                indexShelf += holdervalue[1] - '0';
                            }
                        }

                    }

                    // Start with the null termination first to avoid early cancellation by some other value, and include certain types. If this is true, exit the function
                    if (holdervalue == "N" || holdervalue == "NN" || holdervalue == "nn")
                    {
                        cout &amp;lt;&amp;lt; "Terminating" &amp;lt;&amp;lt; endl;
                        return;
                    }
                    // If the indexShelf is greater than or equal to 14, then it is too high. Print a string and continue
                    else if (indexShelf &amp;gt;= 14)
                        cout &amp;lt;&amp;lt; "Number too high. Please enter a shelfID between 1 to 13 or N to terminate" &amp;lt;&amp;lt; endl;
                    // If the indexShelf value is less than or equal to 0, then this value is too low. Print a string and continue
                    else if (indexShelf &amp;lt;= 0)
                        cout &amp;lt;&amp;lt; "Number too low. Please enter a shelfID between 1 to 13 or N to terminate" &amp;lt;&amp;lt; endl;
                    // If all above conditions were not triggered, then the user entered a valid value. Set the continueLoop to true (!false) and stop the loop.
                    // Finally decrease by 1, this is to ensure that the values aren't out of bounds
                    else
                    {
                        cout &amp;lt;&amp;lt; "Valid input." &amp;lt;&amp;lt; endl;
                        continueLoop = !(continueLoop);
                        indexShelf -= 1;
                    }
                }
                // Then the size is too long. Simply print a string and continue like the above conditions
                else
                    cout &amp;lt;&amp;lt; "Value too long. Please enter a valid shelfID between 1 to 13 or N to terminate" &amp;lt;&amp;lt; endl;
            }

            // Reset the basic values again for the bookID
            continueLoop = false;
            holdervalue = " ";

            cout &amp;lt;&amp;lt; "Please enter a bookID between 1 to 12 or N to terminate" &amp;lt;&amp;lt; endl;

            // Repeats the same above while loop but it does this for a bookID, and the max limit is decreased by 1 to match our bookID limit and prevent out of bounds errors
            while (!continueLoop)
            {
                cin &amp;gt;&amp;gt; holdervalue;

                // If the value the user just entered is less than or equal to 2 in length, i.e a number (0 - 99) or two letters, proceed
                if (holdervalue.size() &amp;lt;= 2)
                {
                    // The case for if the size is only one character long
                    if (holdervalue.size() == 1)
                    {
                        // If the only character is a digit, then set our indexBook to what that digit is, if it isn't a digit, then captialize the letter inside
                        if (isdigit(holdervalue[0]))
                        {
                            indexBook = holdervalue[0] - '0';
                        }
                        else
                            holdervalue[0] = toupper(holdervalue[0]);
                    }

                    // The case for if the size is 2, not 1 and not 0
                    else
                    {
                        // If the first character in the input string is a digit, then set the indexBook variable to this value. Remove the null character to convert
                        // it to a digit. If we got here then if the second character in the string is also a digit, then mutliply the value that's in the indexBook
                        // already by ten, and then add this second value to the string. This is ensure that the number is what was originally typed. I.e, 77 Index = 7.
                        // 7 * 10 = 70 + 7 = 77
                        if (isdigit(holdervalue[0]))
                        {
                            indexBook = holdervalue[0] - '0';

                            if (isdigit(holdervalue[1]))
                            {
                                indexBook *= 10;
                                indexBook += holdervalue[1] - '0';
                            }
                        }

                    }

                    // Start with the null termination first to avoid early cancellation by some other value, and include certain types. If this is true, exit the function
                    if (holdervalue == "N" || holdervalue == "NN" || holdervalue == "nn")
                    {
                        cout &amp;lt;&amp;lt; "Terminating" &amp;lt;&amp;lt; endl;
                        return;
                    }
                    // If the indexBook is greater than or equal to 14, then it is too high. Print a string and continue
                    else if (indexBook &amp;gt;= 13)
                        cout &amp;lt;&amp;lt; "BookID too high. Please enter a shelfID between 1 to 13 or N to terminate" &amp;lt;&amp;lt; endl;
                    // If the indexBook value is less than or equal to 0, then this value is too low. Print a string and continue
                    else if (indexBook &amp;lt;= 0)
                        cout &amp;lt;&amp;lt; "BookID too low. Please enter a shelfID between 1 to 13 or N to terminate" &amp;lt;&amp;lt; endl;
                    // If all above conditions were not triggered, then the user entered a valid value. Set the continueLoop to true (!false) and stop the loop. Then 
                    // indexBook is decremented by 1 to fit the loop.
                    else
                    {
                        cout &amp;lt;&amp;lt; "Valid bookID." &amp;lt;&amp;lt; endl;
                        continueLoop = !(continueLoop);
                        indexBook -= 1;
                    }
                }
            }

            // This line is for confirmation only
            cout &amp;lt;&amp;lt; "IndexShelf: " &amp;lt;&amp;lt; indexShelf &amp;lt;&amp;lt; " BookID: " &amp;lt;&amp;lt; indexBook &amp;lt;&amp;lt; endl;

            // Call the PrintBookByShelfAndID helper function to take care of the printing of the book we want
            mainRef.PrintBookByShelfAndID(indexShelf, indexBook);
            break;
        }
        case 'A':
        {
            mainRef.PrintAllBooks();                // In this case simply print all the books in the entire library
            cout &amp;lt;&amp;lt; "Returning to center\n\n";
            break;
        }
        case 'N':
            cout &amp;lt;&amp;lt; "Returning." &amp;lt;&amp;lt; endl;
            break;
    }
}

// Function that prints the books history of either all books or a desired book
void HandlePrintingBookHistory(BookGroup &amp;amp;mainRef)
{
    cout &amp;lt;&amp;lt; "Would you like to enter the name of a book or the ID? 1 for bookID, A for all books, F to search manually , N to return. \n";

    // Initializes basic variables that we will use for this function
    bool continueLoop = false;
    bool innerloop = false;
    string bookName;
    char input = ' ';

    // Initial placement loop to determine the outcome based on user value. If it is valid we will either terminate or proceed deeper into the function
    while (!continueLoop)
    {
        // Asks for only a single key press
        input = _getch();

        // If the input isn't a number that we want, then captialize it. Note: This works because we only gather a single key press, so it is impossible for the user to enter 
        // a number that is greater than 9 or less than 0. Negatives can't be counted as the '-' is a special character
        if (input &amp;lt;= 0 || input &amp;gt;= 10)
            input = toupper(input);

        // Switch statement based on that input value the user just entered
        switch (input)
        {
        // Easiest case scenario. Simply print the history of all books and then return
        case 'A':
        {
            mainRef.PrintAllBookHistory();
            cout &amp;lt;&amp;lt; "\n";
            continueLoop = !continueLoop;
            cout &amp;lt;&amp;lt; "Returning.\n\n";
            return;
        }
        // If this key is pressed, simply proceed forward as this is a main case
        case '1':
            continueLoop = !continueLoop;
            break;
        // This key is also a special case we will proceed again
        case 'F':
            continueLoop = !continueLoop;
            break;
        // This key is a termination key but unlike 'A' we don't print anything and just exist
        case 'N':
            cout &amp;lt;&amp;lt; "Returning. \n\n";
            continueLoop = !continueLoop;
            return;
            break;
        // User didn't print a valid key. Will print a error message and then go back to the top which repeats this entire procees until a valid key is given
        default:
            cout &amp;lt;&amp;lt; "Sorry, you didn't enter a valid character. Please enter 1 to use bookID, A for all books F to search for the bookname, or N to return. \n";
            break;
        }
    }

    continueLoop = !continueLoop;
    // Placeholder values that hold shelfID and bookID values
    int shelfID(-1);
    int bookID(-1);
    // A string that we will use to hold the users input from now on
    string bookdetector("");

    // The main loop or outer loop that will continue to ask for input until user termination or search failure
    while (!continueLoop)
    {
        // Switch statement based on input
        switch (input)
        {
        case '1':
        {
            cout &amp;lt;&amp;lt; "Please enter a shelfID first between 1 to 13.\n";
            cin &amp;gt;&amp;gt; bookdetector;                                        // ask for user input

            innerloop = false;
            // Our loop inside of the main loop. This innerloop is attempting to ask the user for a valid shelfID between 1 to 13 or for N to terminate
            while (!innerloop)
            {
                // Checker for the N key. If pressed then it will break the entire function and return.
                if (bookdetector == "N" || bookdetector == "n")
                {
                    cout &amp;lt;&amp;lt; "Returning.\n\n";
                    innerloop = true;
                    return;
                }

                // If the value the user entered is 2 keys or less continue
                if (bookdetector.size() &amp;lt;= 2)
                {
                    // If the user only entered 1 key
                    if (bookdetector.size() == 1)
                    {
                        // If that key is a digit, then set the shelfID to this value. If it isn't a digit, then set the users input to E for error handling
                        if (isdigit(bookdetector[0]))
                        {
                            shelfID = bookdetector[0] - '0';
                        }
                        else
                            bookdetector = "E";
                    }
                    // The user has entered a size that is equal to 2. 
                    else
                    {
                        // If the first key is a digit, then set shelfID to that digit
                        if (isdigit(bookdetector[0]))
                        {
                            shelfID = bookdetector[0] - '0';

                            // If the second key is a digit, then multiply the shelfID by 10, and then add the second key to the shelfID
                            if (isdigit(bookdetector[1]))
                            {
                                shelfID *= 10;
                                shelfID += bookdetector[1] - '0';
                            }
                            // If the second key isn't a digit, then set the users value to E for error handling
                            else
                                bookdetector = "E";
                        }
                        // If the first key isn't a digit, then set the users value to E for error handling
                        else
                            bookdetector = "E";
                    }

                    // Termination key
                    if (bookdetector == "N" || bookdetector == "n")
                    {
                        cout &amp;lt;&amp;lt; "Returning.\n\n";
                        return;
                    }
                    // Error handling key. Will simply print a error message and let the flow proceed normally thus resulting in a repeat
                    else if (bookdetector == "E")
                    {
                        cout &amp;lt;&amp;lt; "Invalid value. ShelfID must be between 1 and 13. Retry or press N to terminate.\n";
                    }

                    // Another error case. This happens if the user entered a value that doesn't corresspond to the program. Prints 2 sepearte message depending on the case
                    // and lets the program flow normally resulting in a repeat
                    else if (shelfID &amp;lt;= 0 || shelfID &amp;gt;= 14)
                    {
                        if (shelfID == 0)
                            cout &amp;lt;&amp;lt; "Error, shelfID is too low. Please enter a value between 1 to 13 or N to terminate.\n";
                        else
                            cout &amp;lt;&amp;lt; "Error, shelfID is too high. Please enter a value between 1 to 13 or N to terminate\n";
                    }

                    // If the user got here they successflly entered a valid shelfID. Decrease it by 1 to fit our loop, since value must be between 1 to 13,
                    // set the innerloop to true now, and then break the flow of the innerLoop which stops repetition
                    else
                    {
                        cout &amp;lt;&amp;lt; "Success!! " &amp;lt;&amp;lt; shelfID &amp;lt;&amp;lt; endl;
                        shelfID -= 1;
                        innerloop = !innerloop;
                        break;
                    }
                }
                // User entered a value of 3 or above. These are not accepted
                else
                {
                    cout &amp;lt;&amp;lt; "Value entered is too long.\nPlease enter a shelfID between 1 to 13 or N to trminate.\n";
                }

                // Asks the user for input again at the end if this loop isn't broken
                cin &amp;gt;&amp;gt; bookdetector;
            }

            // reset the innerloop so we will use it again
            innerloop = false;
            cout &amp;lt;&amp;lt; "Please print a bookID between 1 to 12 or press N to terminate\n";
            // Exactly the same as the above innerloop but with the book condition instead. So values are between 1 to 12
            while (!innerloop)
            {
                cin &amp;gt;&amp;gt; bookdetector;

                if (bookdetector == "N" || bookdetector == "n")
                {
                    cout &amp;lt;&amp;lt; "Returning.\n\n";
                    innerloop,continueLoop = true;
                    return;
                }

                if (bookdetector.size() &amp;lt;= 2)
                {
                    if (bookdetector.size() == 1)
                    {
                        if (isdigit(bookdetector[0]))
                        {
                            bookID = bookdetector[0] - '0';
                        }
                        else
                            bookdetector = "E";
                    }
                    else
                    {
                        if (isdigit(bookdetector[0]))
                        {
                            bookID = bookdetector[0] - '0';

                            if (isdigit(bookdetector[1]))
                            {
                                bookID *= 10;
                                bookID += bookdetector[1] - '0';
                            }
                            else
                                bookdetector = "E";
                        }
                        else
                            bookdetector = "E";
                    }

                    if (bookdetector == "N" || bookdetector == "n")
                    {
                        cout &amp;lt;&amp;lt; "Returning.\n\n";
                        innerloop = true;
                        continueLoop = true;
                        return;
                    }

                    else if (bookdetector == "E")
                    {
                        cout &amp;lt;&amp;lt; "Invalid value. bookID must be between 1 and 12. Retry or press N to terminate.\n";
                    }

                    else if (bookID &amp;lt;= 0 || bookID &amp;gt;= 13)
                    {
                        if (bookID == 0)
                            cout &amp;lt;&amp;lt; "Error, bookID is too low. Please enter a value between 1 to 12 or N to terminate.\n";
                        else
                            cout &amp;lt;&amp;lt; "Error, bookID is too high. Please enter a value between 1 to 12 or N to terminate\n";
                    }

                    else
                    {
                        cout &amp;lt;&amp;lt; "Success!! " &amp;lt;&amp;lt; shelfID &amp;lt;&amp;lt; endl;
                        bookID -= 1;
                        innerloop = !innerloop;
                        break;
                    }
                }
                else
                {
                    cout &amp;lt;&amp;lt; "Value entered is too long.\nPlease enter a bookID between 1 to 12 or N to trminate.\n";
                }

            }

            // Create a book reference so we can check if the shelfID and bookID found a valid book
            Book myBook = mainRef.GetBook(shelfID, bookID);

            // If the book we just created isn't empty, then print that books history, otherwise print a error message. Regardless of outcome, terminate this function
            if (!myBook.emptyBook() )
                mainRef.PrintBookHistoryByBook(myBook.name);
            else
                cout &amp;lt;&amp;lt; "Sorry, but that book doesn't exist. Returning.\n\n";

            continueLoop = true;
            break;
        }
        // The case when the user presses the F key. Allows them to find the book by its name
        case 'F':
        {
            cout &amp;lt;&amp;lt; "Please enter the name of the desired book.\n";
            std::getline(std::cin, bookName);

            // If the bookName the user entered exists inside the main structre, then print that books history and terminate this loop
            if (mainRef.FindBook(bookName))
            {
                mainRef.PrintBookHistoryByBook(bookName);
                continueLoop = !continueLoop;
            }
            // If the bookname isn't valid, basically ask them if they'd like to try again. If the input they entered isn't a number between the values we want, captialize it.
            else
            {
                cout &amp;lt;&amp;lt; "Would you like to try again (F) or terminate(N)?\n";
                input = _getch();
                if (input &amp;lt; 0 || input &amp;gt;= 10)
                    input = toupper(input);
            }

            break;
        }
        case 'N':
            cout &amp;lt;&amp;lt; "Returning.\n\n";
            continueLoop = !continueLoop; 
            return;
        default:
        {
            cout &amp;lt;&amp;lt; "Sorry, invalid character entered. Please type 1 to search by 1, F to search by name, or N to terminate.\n";
            input = _getch();
            if (input &amp;lt; 0 || input &amp;gt;= 10)
                input = toupper(input);
        }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;};&lt;/p&gt;

&lt;p&gt;The next function is the setUpBookNames function. This is a really quick and simple one. It takes a parameter reference to an active BookGroup instance, and adds a list of random video game names as book names and a random set of pages by calling the AddBooks function inside the BookGroup parameter. &lt;/p&gt;

&lt;p&gt;It looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ref.AddBooks(Alphabet, books_Ref, Pages);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Alphabet variable a string array of names like “Crash Bandicoot”, “Jack and Daxter”, “Horizon Zero Dawn” and the books_Ref being an array of integers that have random values between 20 and 1020. Here is one index of that, although all of them look exactly the same:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rand() % 1000 + 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next up is the InitializeLibraryGuests function which takes a Person pointer type as its only argument. I use this space to set up two array strings, both being considerable sizes; one of only first names, the other only as last names. At the end of this function, I combine them into one name by passing them both together as a argument in the Person pointer argument and also increasing the static integer ID by one for every successful name and passing that in as well. The FirstNames and LastNames string arrays are based on the LibaryGuestSize variable which remember is a global one. By generating a random index between that range, I can easily get a index which I used to directly plug into both respective string arrays.&lt;/p&gt;

&lt;p&gt;It looks a bit like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Go through a loop based on the guest size and setup the guests values
    for (int i = 0; i &amp;lt; LibraryGuestSize; ++i)
    {
        randomFirstIndex = rand() % LibraryGuestSize;       // Generate a random number between 0 and LibraryGuestSize(156)
        randomLastIndex = rand() % LibraryGuestSize;        // Same as the above but inside lastindex

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    // Make the guests name a full value based on random selections between the first name and last names. The indicies we made are used as selectors
    Guests[i].name = FirstNames[randomFirstIndex] + " " + LastNames[randomLastIndex];

    // Increase the static integer value by 1 so every guests has a incremeting ID value
    ID += 1;
    Guests[i].GuestID = ID;         // Set the guests' ID to the static ID.
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;The final piece that needs to be discussed is the one that puts everything together and that is the main function. The main function first creates the array of individuals for the simulation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Person *LibraryGuests = new Person[LibraryGuestSize];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then it setups them up for use by calling the InitializeLibraryGuest function like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;InitializeLibraryGuests(LibraryGuests);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then creating a BookGroup reference and calling the setUpBookNames using that handler.&lt;/p&gt;

&lt;p&gt;Following this, the LibraryGuests variable that was just made is added to the BookGroup handler along with a random book in a for loop for easy access. That code looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;string myBook;
myBook = mainHandle.SelectRandomBook();                     // Selects a random book from somewhere on the shelf and returns its value
            mainHandle.CheckoutBook(LibraryGuests[i], myBook);          // Makes it so that every user checks out a book
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, a while loop is used for different selection cases of numbers by checking input with a character holder variable and the UserInputHelperClass which handles all additional cases and returns here when completed or desired. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Postmortem&lt;/strong&gt;&lt;br&gt;
The biggest thing that I would do differently if doing this again is change the way that data is pulled out in terms of books. While its fine the way that it is now, I think things would have been better if I’d just used a hash table for keys and indices which I somewhat did but not in the way I liked. I chose not to use the LinkedList that I added because it didn’t make sense to me at the time, constantly deleting and removing nodes since they are always static anyway. However, I could have simply cleared the data inside the node until it was active. Not disappointed in what I did, just wondering if I could have done this differently. Originally, I wanted to take the books printed by the BookHistory and add them to a file that could be easily seen. Unfortunately, I didn’t end up doing this and I wish I would have. Would have been cool to see because the results aren’t static. Another thing I wanted to do was make this so that the data is a bit more flexible. By flexible I simply mean that users can add books and or names to the database instead of it being hard coded like it is now. Despite these drawbacks, I’m still satisfied with the way it turned out and it can definitely be improved upon.&lt;br&gt;
This was quite a long-detailed explanation and I hope that it wasn’t too bad in terms of length. You can visit my GitHub page if you’d like to try this program out for yourself &lt;a href="https://github.com/CBanks901/LibrarySimulation"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Thank you for reading if you made it this far and feel free to check out some of my other coding work.&lt;/p&gt;

&lt;p&gt;Sincerely,&lt;/p&gt;

&lt;p&gt;Christian Banks&lt;/p&gt;

</description>
      <category>visualstudio</category>
      <category>cpp</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
