Today had me studying less design patterns than I thought, but that was no worry since I was a bit busier today and needed to level out my extracurricular studies. I found a great example of a repeated terrain use of the Flyweight pattern and went over the Proxy, Chain of Responsibility, and Interpreter patterns.
As for more flash work, I managed to create a helpful (and not global!) sound manager class, along with an extended subclass of Sound that I created to load itself, create only when called, and not have any unnecessary access while it was loading. This also required the subclass to contain its channel, which worked nicely. I also found out that traditionally, Flash plays mp3 files but not wav files. I will have to keep my eye on that.
Hm, as for something visual? I added a quick and neat portion to the enemy's movement where they would take the direction of the player and move toward it. This was a simple distance calculation and moving the x and y by the direction vector (playerPosition - enemyPosition) and dividing it by magnitude; this can also be manipulated by speed to give an extra hunting movement to the lizards as they fall down, fairly increasing the difficulty for less enemies on the screen (cheaper for the rest of the program!) :
What onto next? Welp, there's still three more tutorial portions to go before I can be sure I'm ready to tackle Flash, but these classes I'm making will help immensely when the time comes to crank out some prototypes.
An account of pain, struggle, and amusing discoveries found in a man's quest for game programming style and finesse.
Monday, August 31, 2015
Sunday, August 30, 2015
Day 7: The Saga of the Command Pattern
Today was a busy day at work, got nothing done.
Just kidding. I was fortuitous enough to be able to study while I was at my post, allowing me to dive in and study as much as I could today. I was concerned about my lack of skill with the Gang of Four's design pattern list, so I went over as thoroughly as I could to understand each pattern. So far I managed the Command, Strategy, Factory/Abstract Factory, Builder, Prototype, Singleton (the good, thread-safe kinds), Adapter, Bridge, Composite, Decorator, Facade, and Flyweight patterns. Implementing them properly and knowing when might need a bit of practice, but I managed the Command design pattern today.
Luckily enough, AS3 allows functions as parameters (of class Function), and allows any function to be passed into a Command object (self-made) without any need for a receiver. Luckily enough, that's about as generic as it can get, allowing a single Command class to be used for any function I need to use for something like the Input Manager. Speaking of, I managed to switch between mouse and keyboard input for Penty in Lizard Rain (elegantly stuck in a static class turned enumeration) and had some difficulty with moving the character properly; it seems that the keyDown event is fired continuously but at long intervals, and movement needed to be smooth by using booleans (isMovingInDirectionSpecified, but that's just generic) and checking it. Thankfully enough, the command to execute managed despite that bug. I also cut the movement of Penty so that it doesn't move off the screen; that also led into another bug where the playScreen (player's parent; should share width and height with stage but) expanded during game. By saving initial values, the player managed just fine (shown below).
Before getting too tired and headed to bed, I looked into the next part of development, which involved actually using the timeline frames (gasp!) for a single frame for loading screens and another frame to load assets, which were placed into an AssetHolder.
This means that in order for the code to stop at frame 1 instead of violently switching between frames, one must use the stop(); command. This is usually done in the actions tab, but a little birdy told me addFrameScript ( 0, function(){stop();} ) did the trick, and now everything's loaded and stopped at frame 1. Except... wait. There was supposed to be an error involving mismatches, according to the tutorial I followed, but nothing's wrong. Strange; I'll have to look into that when I tackle the pre-loader tomorrow.
Saturday, August 29, 2015
Day 6: Raining Lizards and Houdini: (Can't) Try This at Home
Phew! Now that I found a better tutorial for AS3 development (here), I've decided to make a simple game utilizing the better practices of the language (programming everything outside of the scene) and managing a small avoiding game where a friendly pentagon (Penty the Pent-Up Protagonist? Perhaps) avoids a rain of menacing lizard heads.
Although simple, I covered a lot of important things for Flash development. I separated the states of gameplay from the main class (most of em'), set an array of enemies that moved at random speeds (in a range of numbers, for better effect) and that used an inverse tangent method to see exactly where the angle of rotation needed to be for the lizards to look at Penty the entire time. There was a bit of a fix where the lizards were rotated backwards (for effortless shunning) but a quick addition of 180 degrees helped fix that up, along with properly translating from radians to degrees since the rotation member in DisplayObjects was in degrees.
For actual colliding, the bounding box was an unfortunately rigid routine, so I went with the next best thing (the enemies and player being circular n' all): circular collision. There is no specific circular class, but a quick distance check calculation and a radius (made slightly smaller than the actual drawn object for close calls) is all Penty and the lizards need for non-frustrating collision. I also stuck in a score with a dynamic text instance and a clock with eight frames (inside the symbol! Not the scene!) of animation; these two were very similar in number accumulation, so they both went under a parent class for counting numbers. And voila! A simple game of life and death:
On top of that, I also became quite used to the buttons and setting frames with different text and color for unclicked, clicked, hovering, and general hitbox frames. This produces the lovely button below:
I also looked a bit into Houdini; as unfortunate as it may seem, the software is linked directly to the local campus server (to the point where one cannot work on it off-campus), so the work I've done on the side (holding off the lengthy workshop, mind ye) is mainly becoming familiar with its components as modeling software and animation frames in preparation for procedural effects, motion along curves, and other such things that separate Houdini from the lot. It's unlikely I'll be working on it specifically, but a couple of these tricks could save development some time in the long run.
Although simple, I covered a lot of important things for Flash development. I separated the states of gameplay from the main class (most of em'), set an array of enemies that moved at random speeds (in a range of numbers, for better effect) and that used an inverse tangent method to see exactly where the angle of rotation needed to be for the lizards to look at Penty the entire time. There was a bit of a fix where the lizards were rotated backwards (for effortless shunning) but a quick addition of 180 degrees helped fix that up, along with properly translating from radians to degrees since the rotation member in DisplayObjects was in degrees.
For actual colliding, the bounding box was an unfortunately rigid routine, so I went with the next best thing (the enemies and player being circular n' all): circular collision. There is no specific circular class, but a quick distance check calculation and a radius (made slightly smaller than the actual drawn object for close calls) is all Penty and the lizards need for non-frustrating collision. I also stuck in a score with a dynamic text instance and a clock with eight frames (inside the symbol! Not the scene!) of animation; these two were very similar in number accumulation, so they both went under a parent class for counting numbers. And voila! A simple game of life and death:
On top of that, I also became quite used to the buttons and setting frames with different text and color for unclicked, clicked, hovering, and general hitbox frames. This produces the lovely button below:
I also looked a bit into Houdini; as unfortunate as it may seem, the software is linked directly to the local campus server (to the point where one cannot work on it off-campus), so the work I've done on the side (holding off the lengthy workshop, mind ye) is mainly becoming familiar with its components as modeling software and animation frames in preparation for procedural effects, motion along curves, and other such things that separate Houdini from the lot. It's unlikely I'll be working on it specifically, but a couple of these tricks could save development some time in the long run.
Friday, August 28, 2015
Day 5: FastBox, SlowBox, and Flash Netherscapes
Today was quite the busy day; I managed to get the fast and slow boxes in the game properly populated, with switching the main audio actor from the editor over to the player in C++ code for better access. By setting the pitch modulation, one can actually slow and speed music while it's playing; quite the upside. Now the maze looks quite complete:
As for Flash, I followed an interesting little platforming tutorial that went downhill fast, embracing some horrible AS3 coding practices like having multiple frames and layers for programmed objects, keeping code in the Actions tab, etc. I did manage a neat little netherscape from my crappy vector illustration skills, though:
I covered the simple bits like parallax scrolling, collision (incredibly simple and perhaps not the best, with a set of points versus a rectangle), and gravity/jumping. I will definitely need to go to a better example with better practices for AS3 though; luckily, I found just the one.
As for Flash, I followed an interesting little platforming tutorial that went downhill fast, embracing some horrible AS3 coding practices like having multiple frames and layers for programmed objects, keeping code in the Actions tab, etc. I did manage a neat little netherscape from my crappy vector illustration skills, though:
I covered the simple bits like parallax scrolling, collision (incredibly simple and perhaps not the best, with a set of points versus a rectangle), and gravity/jumping. I will definitely need to go to a better example with better practices for AS3 though; luckily, I found just the one.
Thursday, August 27, 2015
Day 4: Flash Collision and its Limits
Today was another day to get my hands dirty with Flash and working with ActionScript 3. Unfortunately, the professor was a bit quick with going over Flash, and I felt I may have only skimmed over very important aspects; however, I did manage to figure out how to save a drawn image as a class and make a movement animation using that image. This led to this horrendous-looking figure here, which I refer to as "QuestionOnion":
The figure in question, once drawn, also has a peculiar shape; in previous collisions involving 2D sprites, it was sufficient to use rectangles and circles for proper and quick collision. For such an object like this, such complexity required not just a convex hull (mind you, impossible with a sprite without set point information) but a bitmap pixel collision test. How this is done is that the figure's transform matrix, along with its bounds is used to setup a bitmap, which is then compared with a hitTest function to the other figure. If the pixel overlap is a color other than a clear nothingness, then spot-on collision is achieved. This is problematic due to the inefficiency of checking each pixel, but EXTREMELY problematic that no other collision actually works in that regard for drawn sprites like this. If I ever use any prototyping involving complex hulls, I must make it clear that the figure's points must be taken into account, if at all. That, or subdivided simple collision sprites (circle for the body, box for the stem).
On the bright side, it was made very clear to us that a manager class would be best for checking inputs (in the case of changing mapping of values), and I created an InputManager class in case such use would be required in later projects involving Flash.
The figure in question, once drawn, also has a peculiar shape; in previous collisions involving 2D sprites, it was sufficient to use rectangles and circles for proper and quick collision. For such an object like this, such complexity required not just a convex hull (mind you, impossible with a sprite without set point information) but a bitmap pixel collision test. How this is done is that the figure's transform matrix, along with its bounds is used to setup a bitmap, which is then compared with a hitTest function to the other figure. If the pixel overlap is a color other than a clear nothingness, then spot-on collision is achieved. This is problematic due to the inefficiency of checking each pixel, but EXTREMELY problematic that no other collision actually works in that regard for drawn sprites like this. If I ever use any prototyping involving complex hulls, I must make it clear that the figure's points must be taken into account, if at all. That, or subdivided simple collision sprites (circle for the body, box for the stem).
On the bright side, it was made very clear to us that a manager class would be best for checking inputs (in the case of changing mapping of values), and I created an InputManager class in case such use would be required in later projects involving Flash.
Wednesday, August 26, 2015
Day 3: Industry Statistics and Creeping Back to the Maze
Today was a slow day again. Apart from a production lecture on industry statistics, there wasn't too much that actually went on today in terms of programming. In anticipation of something to actually happen, I went back to working with the maze project in Unreal Engine 4. I'm quite glad I kept to my side project despite the advice to completely let go of it during the actual coursework, especially with constructing the boxes that will speed and slow down time globally. There are a few things I have to consider when setting time dilation, though.
The function that affects deltaTime is the SetGlobalTimeDilation method, which is set in UGameplayStatics. I also have to track down every moving actor in the game and set CustomTimeDilation for each of them (public members); so far only the player and spikes need set, so I'll have to not get all actors and instead use UGameplayStatics's GetActorsOfClass method as well. The last thing to look into was the audio; by modulating pitch, I could get that slow and speed effect I was looking for. However, I have to work on it further to see if I can change the actual music's pitch while it is playing. Hopefully once I get time to test out the collision box (FastBox!) I'll be able to bring these speed changes together. I also used delegates for both the OnOverlapBegin and OnOverlapEnd functions, so there won't be a boolean constantly checked during Tick. That will keep the maze from becoming too slow.
Here's to school giving me more programming to do, too! My work won't be side projects for long.
Tuesday, August 25, 2015
Day 2: Beginning Anew is Not Always a Bore
Today was a bit of a step forward than the previous class. In response to a lack of programming, I was bombarded with a large aptitude test regarding my programming knowledge of C++, revealing to me that there have been many things I have learned how to do without knowing what (not necessarily why). For example, the bit shift macro and bitmask collision I employed for collision in Bullet with my DirectX assignment I understood perfectly, but unfortunately did not understand when faced with its actual definitions (i.e. what is a macro?). The same went for the use of the template, as I used it as a generic way to spawn a Blueprint class in Unreal Engine 4. Afterwards, we had a refresher on what hexadecimal and octal systems are, which fortunately reminded me of the quick multiplication and division with bit-shifting.
As for the other classes, I was introduced to the Rapid Prototype Production course, which led me to doodle a couple of ideas (instead of cutting my teeth on programming) in anticipation for working in a group. Marine adventures and peril? 2D Katamari fuzzballs? Going deeper in a cave via foreground to background jumps? Only time will tell if these quick and small flights of fancy will be built upon. Afterward, we had a programming workshop where I was quickly introduced to the use of ActionScript 3 in Adobe Flash; I must say, regardless of having experience with multiple engines and coding IDEs, a new one is always a doozy to get used to at first. Thankfully it did not take as long as other complex engines did, and I responded to the usual Hello World code with a lovely rotating picture of a baby red panda that took advantage of the Event.ENTER_FRAME event that called every time the frame continues, resulting in a smooth rotation (as opposed to using the Timer onTick event, which is another possibility).
My hopes continue that I will be able to quickly employ complex matrix translations and rotations in all types of prototypes that we work with; that, and pictures of baby red pandas as the new "Hello, World" standard.
As for the other classes, I was introduced to the Rapid Prototype Production course, which led me to doodle a couple of ideas (instead of cutting my teeth on programming) in anticipation for working in a group. Marine adventures and peril? 2D Katamari fuzzballs? Going deeper in a cave via foreground to background jumps? Only time will tell if these quick and small flights of fancy will be built upon. Afterward, we had a programming workshop where I was quickly introduced to the use of ActionScript 3 in Adobe Flash; I must say, regardless of having experience with multiple engines and coding IDEs, a new one is always a doozy to get used to at first. Thankfully it did not take as long as other complex engines did, and I responded to the usual Hello World code with a lovely rotating picture of a baby red panda that took advantage of the Event.ENTER_FRAME event that called every time the frame continues, resulting in a smooth rotation (as opposed to using the Timer onTick event, which is another possibility).
My hopes continue that I will be able to quickly employ complex matrix translations and rotations in all types of prototypes that we work with; that, and pictures of baby red pandas as the new "Hello, World" standard.
Monday, August 24, 2015
Day 1: ...Not Much Programming
And now that first day of school has started, I have had... no programming classes. Shock! Instead, we have had a production for media class, where I compared Pac-Man to Gabriel Wilson in terms of what consists of an iconic character. (Pac-Man won)
What to do with programming, though? The past day or two was spent uploading a lot of my projects to Github, so if there's anything from my previous work you'd like to take a gander at (with the right libraries), look em up here. I did get to run the maze on the new laptop and am surprisingly pleased by its capabilities; I can now successfully work on a lovely looking maze here:
What to do next? Well, I am still twiddling my fingers until SOMETHING programming related comes my way that I can screenshot, so I will work with those time dilation squares and see if I can manage slow or fast motion for the whole game for a neat effect. So far I'm looking into UGameplayStatics's SetGlobalTimeDilation to affect the run of deltaTime.
What to do with programming, though? The past day or two was spent uploading a lot of my projects to Github, so if there's anything from my previous work you'd like to take a gander at (with the right libraries), look em up here. I did get to run the maze on the new laptop and am surprisingly pleased by its capabilities; I can now successfully work on a lovely looking maze here:
What to do next? Well, I am still twiddling my fingers until SOMETHING programming related comes my way that I can screenshot, so I will work with those time dilation squares and see if I can manage slow or fast motion for the whole game for a neat effect. So far I'm looking into UGameplayStatics's SetGlobalTimeDilation to affect the run of deltaTime.
Saturday, August 22, 2015
Biding Time Until School Starts
Seeing as I only have two days until my schooling officially starts, I am currently figuring out what I should learn for the upcoming few semesters. The maze is complete for now, with a new font that can be more easily read. I could add on a couple more elements, but they may not be implemented in time for class to start.
Until then, I've decided to go back to a 68K program I had been working on and study some portions of Unreal that I am unfamiliar with, such as the specific workings of a quaternion (the vector/scalar, and translating to axis/angle and a rotation matrix for easier understanding) and inverse kinematics in Unreal's examples, in which a figure does jumping jacks on stairs by calculating the offset of the foot from the object via a (costly) Tick-based trace to the ground, and using the offset to displace the joint at that point.
As for 68K, I fixed a simple program involving playing a sound and moving a square by setting eight more sections of code (each to change the current direction and move in that direction) before halting and shutting off the sound properly so it wouldn't keep playing after SIMHALT. Luckily, a faculty member pointed out the existence of a help section in Easy68K that actually listed all the trap tasks, so I was able to utilize trap task 73 (controlling a standard sound player and stopping all sounds by putting the number 3 in register d2) and understand how the rectangle was created (d1 = lowerX bound, d2 = lowerY bound, d3 = upperX bound, d4 = upperY bound) for moving in specific directions. The only thing I'd have to get more comfortable with is pushing things on the stack more often; I push the rectangle coordinates on the stack whenever I utilize another trap task (such as clearing the screen with #11), so by pushing more on the stack I can add more variables for more complex programs. Who knows? Down the line when school starts, I can even draw a sprite in due time. That will wait until Monday...
Until then, I've decided to go back to a 68K program I had been working on and study some portions of Unreal that I am unfamiliar with, such as the specific workings of a quaternion (the vector/scalar, and translating to axis/angle and a rotation matrix for easier understanding) and inverse kinematics in Unreal's examples, in which a figure does jumping jacks on stairs by calculating the offset of the foot from the object via a (costly) Tick-based trace to the ground, and using the offset to displace the joint at that point.
As for 68K, I fixed a simple program involving playing a sound and moving a square by setting eight more sections of code (each to change the current direction and move in that direction) before halting and shutting off the sound properly so it wouldn't keep playing after SIMHALT. Luckily, a faculty member pointed out the existence of a help section in Easy68K that actually listed all the trap tasks, so I was able to utilize trap task 73 (controlling a standard sound player and stopping all sounds by putting the number 3 in register d2) and understand how the rectangle was created (d1 = lowerX bound, d2 = lowerY bound, d3 = upperX bound, d4 = upperY bound) for moving in specific directions. The only thing I'd have to get more comfortable with is pushing things on the stack more often; I push the rectangle coordinates on the stack whenever I utilize another trap task (such as clearing the screen with #11), so by pushing more on the stack I can add more variables for more complex programs. Who knows? Down the line when school starts, I can even draw a sprite in due time. That will wait until Monday...
Friday, August 21, 2015
Letting it Snow
After inserting a snowy-sounding music into the game, I decided to give a shot at making the game look somewhat snow-covered. The first step was to make a dynamic snow material; the way that that is created in the Material Editor in Unreal involves taking the brighter portions of a material and amping them to white. This, unfortunately, was not too well explained in the tutorial I looked at, but did involve clamping values to ensure no negatives either. After applying the snow material, there was another section involving tessellation to make it look as if snow was covering the actual mesh in large clumps. This, however, did not work too well, as the way from 4.3 must differ immensely from what I actually got:
Ditching the tessellation, I decided a more particle-based approach would definitely work out instead of a brushing post-processing effect. The Unreal Engine 4 particle effect example's blizzard effect was similar enough to what I was looking for, brushing the snow particles quickly with different speeds along a vector field. However, I was also trying to figure out how to cover snow on the entire maze (at any size) all while actually showing particles. I tried attaching the emitter to the player, but barely any particles showed up. After awhile, I just decided to populate the entire area with particles and increase the initial location. This almost worked, but not a lot of particles still showed up until I amped up the graphics setting; it may not look it too much below, but snow fairly blows along the whole maze without too much of a drop in frame rate:
Also not shown are the spikes; due to the white area making the chrome hard to see, I gave the general color of the dangers a dark red. Next up? Not sure; school starts up in a couple of days and will probably take over this site (also explains why I haven't been able to post in the past couple of days). Perhaps areas that slow or speed the ball?
Ditching the tessellation, I decided a more particle-based approach would definitely work out instead of a brushing post-processing effect. The Unreal Engine 4 particle effect example's blizzard effect was similar enough to what I was looking for, brushing the snow particles quickly with different speeds along a vector field. However, I was also trying to figure out how to cover snow on the entire maze (at any size) all while actually showing particles. I tried attaching the emitter to the player, but barely any particles showed up. After awhile, I just decided to populate the entire area with particles and increase the initial location. This almost worked, but not a lot of particles still showed up until I amped up the graphics setting; it may not look it too much below, but snow fairly blows along the whole maze without too much of a drop in frame rate:
Also not shown are the spikes; due to the white area making the chrome hard to see, I gave the general color of the dangers a dark red. Next up? Not sure; school starts up in a couple of days and will probably take over this site (also explains why I haven't been able to post in the past couple of days). Perhaps areas that slow or speed the ball?
Tuesday, August 18, 2015
Music, Fading to Red, and Other Miscellany
Today was a short day, as I was experimenting with another one of the FMath methods, mainly the CInterp method. Whereas VInterpTo interpolates between vectors (good for locations!) the FLinearColor structure uses uints for the RGBA format. By accessing the Camera's PostProcessSettings's FilmWhitePoint (a god-AWFUL name for tint), one can fade the screen to red over a few seconds.
Afterwards, I set a small class for the collision box for the end, the WinBox. This one is fairly cheap, as it merely kills the player and restarts without the fading to red. The timer works as well, and is setup with a Top Score for any level that, once completed, sets it under the timer.
To top it off, a musical score was added as a sound actor; the music sounds rather snowy, so once I finish polishing the Top Score mechanic, I'll begin to look into the use of dynamic snow material for an interesting frosty-looking scene.
Afterwards, I set a small class for the collision box for the end, the WinBox. This one is fairly cheap, as it merely kills the player and restarts without the fading to red. The timer works as well, and is setup with a Top Score for any level that, once completed, sets it under the timer.
To top it off, a musical score was added as a sound actor; the music sounds rather snowy, so once I finish polishing the Top Score mechanic, I'll begin to look into the use of dynamic snow material for an interesting frosty-looking scene.
Monday, August 17, 2015
Setting a Timer for Incentive
Once the maze has been setup as a challenge, why go through it? A quick solution is to create a timer. By setting an AHUD class called AMazeHUD, I can draw a quick rectangle, font title, and time to the screen. The answer is anything but simple, however. Unfortunately, due to the heinously slow nature of C++ compilation and the C++ only interaction of the GameMode, I can set the HUD to the GameMode via code, but can only change HUD values in code. Need to move the rectangle by a small offset? That'll take 2-3 minutes at the least.
FText::AsNumber also is a strangely more complex method than the %.2f format that a lot of people are familiar with in printf; the precision and other details is set in a numerical format structure used to to create an actual string with the proper (2 decimal points) precision I am looking for. That said, a simple timer is now set for the ball, which listens to the pawn's death boolean to know when to reset. Apart from spending an hour to properly set the rectangle, I may also interpolate the color to red in the few seconds upon player death for a more interesting effect.
FText::AsNumber also is a strangely more complex method than the %.2f format that a lot of people are familiar with in printf; the precision and other details is set in a numerical format structure used to to create an actual string with the proper (2 decimal points) precision I am looking for. That said, a simple timer is now set for the ball, which listens to the pawn's death boolean to know when to reset. Apart from spending an hour to properly set the rectangle, I may also interpolate the color to red in the few seconds upon player death for a more interesting effect.
Sunday, August 16, 2015
Spawning Spikes in Walls and Making Sure They Aren't Hiding
In order for the spikes to spawn properly in walls, there needed to be something to store data for each block. Sure, the grid stored the StaticMeshActors, but they themselves had no extra portion for info, nor a map structure. What to do? A struct did the job nicely, and only needed to hold data on whether the spot was a ground piece and if it was a start/end piece. Once the spikes were up and running, I was rather confused, though; they were being pushed into locations where they definitely would just jut out into another block and become utterly useless. Reading into the grid structure I made for the maze, it turns out that the x coordinate actually was responsible for height and the y for width. Peculiar, but the multi-dimensional array had that constraint.
Afterwards, I needed to adjust the camera boom (arm to hold camera)'s relative rotation to the ball. The arm was set so that it would not change rotation as the ball rotated, but for some odd reason changing the relative rotation did not change a thing. After deleting the pawn from the editor, the game magically puts in its own pawn according to the GameMode, so I did not need to worry past that point as long as I set the location of the pawn in code at the beginning of gameplay.
I also setup a couple of sound effects using the PlaySoundAtLocation method from UGameplayStatics (the class responsible for all those convenient blueprint methods nobody could ever find in C++ code). Since I was not looking for anything particularly complex, I ditched the attenuation settings initialization and decided to do a quick distance check for the spike extension sounds.
And now, a very terrifying maze:
What's up next? A HUD for properly getting the time of the maze. One has to have something to work toward to make this gauntlet worthwhile.
Afterwards, I needed to adjust the camera boom (arm to hold camera)'s relative rotation to the ball. The arm was set so that it would not change rotation as the ball rotated, but for some odd reason changing the relative rotation did not change a thing. After deleting the pawn from the editor, the game magically puts in its own pawn according to the GameMode, so I did not need to worry past that point as long as I set the location of the pawn in code at the beginning of gameplay.
I also setup a couple of sound effects using the PlaySoundAtLocation method from UGameplayStatics (the class responsible for all those convenient blueprint methods nobody could ever find in C++ code). Since I was not looking for anything particularly complex, I ditched the attenuation settings initialization and decided to do a quick distance check for the spike extension sounds.
And now, a very terrifying maze:
What's up next? A HUD for properly getting the time of the maze. One has to have something to work toward to make this gauntlet worthwhile.
Saturday, August 15, 2015
In Which Our Protagonist Needs to Explode
Today was a small day in terms of programming; once the spike from yesterday was created, I needed to take the step forward and populate the maze with these dangers, so I set the class in the Maze to spawn upon creation of a ground tile; in the case of a block, the block must be aware of other tiles around it to spawn a proper spike jutting out of the wall, so I might create an array that holds cell information as well as the array that holds StaticMeshActors. So far the spikes populate fairly well, with a function that covers a set percent of the ground with them.
Once the danger is released, the ball must interact with it. By using delegates from a previous project, I was able to take the OnComponentBeginOverlap event of the spike mesh and use AddDynamic to attach a delegate method for extra behavior upon collision. By separating the death behavior to the ball, the spike need only grab the first player pawn and call its public Die method, to which the ball is no longer visible and no longer simulates physics, spawning a convincing explosion (preset Starter Content explosion, but can be tailor-made in case) upon its disappearance to make it look dead without actually destroying the object. Boom.
What's next? Spawning the spikes out of the wall and finding out how to attach these objects to the root maze actor; it'll be difficult to keep track of them if they're all over the place during gameplay.
Once the danger is released, the ball must interact with it. By using delegates from a previous project, I was able to take the OnComponentBeginOverlap event of the spike mesh and use AddDynamic to attach a delegate method for extra behavior upon collision. By separating the death behavior to the ball, the spike need only grab the first player pawn and call its public Die method, to which the ball is no longer visible and no longer simulates physics, spawning a convincing explosion (preset Starter Content explosion, but can be tailor-made in case) upon its disappearance to make it look dead without actually destroying the object. Boom.
What's next? Spawning the spikes out of the wall and finding out how to attach these objects to the root maze actor; it'll be difficult to keep track of them if they're all over the place during gameplay.
Friday, August 14, 2015
The Difficulties of Rendering a Lovely Hedge Maze and...Spikes.
After getting the maze to properly function in the previous post, I figured something a little more visually comfortable would work well with the actual maze construction, rather than stone blocks. I had scoured online for foliage meshes for hedges, but the one available to suit my needs was unfortunately VERY expensive for the GPU to render properly. Actually, at this point, my laptop can barely render anything in Unreal Engine 4, which is why I hope to use a more powerful system when I actually start more serious development. As a result, I managed a hedge texture bumped outward by way of a normal map on the regular cube, but only by a slight bit. Still, it looks a bit more lovely than a bunch of bricks.
As for the spike, I mainly put together the framework for a repetitive spike in place that overlaps with all objects to make it look as if it was peeking out of the actual hedge itself. The UENUM structure actually worked out better than expected, allowing me to actually use the enum in blueprints as well. I used an enumeration for the behavior of the spike, allowing it to switch between its resting periods along with extension and retraction.
By using an interpolation method (VInterpTo) that starts out strong and eases out over a set time, I was able to get a natural looking movement of the spike with random ranges on things such as resting time to keep the spikes from being too uniform.
I also tried to figure out how to get it to move in a direction based on rotation, instead of cutting the spike movement to basic directions; the mesh initially started in an upright position, so getting the up vector of the rotation helped for setting a movement direction that would change as the mesh was rotated.
Next up? Getting it to kill the player and populating the maze with spawns of the actor.
As for the spike, I mainly put together the framework for a repetitive spike in place that overlaps with all objects to make it look as if it was peeking out of the actual hedge itself. The UENUM structure actually worked out better than expected, allowing me to actually use the enum in blueprints as well. I used an enumeration for the behavior of the spike, allowing it to switch between its resting periods along with extension and retraction.
By using an interpolation method (VInterpTo) that starts out strong and eases out over a set time, I was able to get a natural looking movement of the spike with random ranges on things such as resting time to keep the spikes from being too uniform.
I also tried to figure out how to get it to move in a direction based on rotation, instead of cutting the spike movement to basic directions; the mesh initially started in an upright position, so getting the up vector of the rotation helped for setting a movement direction that would change as the mesh was rotated.
Next up? Getting it to kill the player and populating the maze with spawns of the actor.
Thursday, August 13, 2015
Maze Restrictions? No Problem!
Apart from the peril of excessive compilation time, I've finally figured out how to get the maze to not produce any dead ends. By way of setting up the walls on an odd numbered square for example, 11x11, there is a 9x9 square in the middle, which yields a 7x7 set of squares that are set comfortably in the middle (4x4 pillars, to be specific). However, if one goes with 10x10, the algorithm still tries to produce 4x4 pillars, with the last row and column set firmly against the wall instead of properly stranded. This makes it very easy for certain seed values to yield unwinnable results. Solution? Restrict the values upon maze generation. A simple modulo does nicely.
Another restriction I found in the code was the declaration of a multi-dimensional array with set boundaries based on a max. It would be simple to break the code by placing something larger than the max in editor, so I also placed a quick check. Now we have a robust maze generation system that procedurally generates a simple yet complex and winnable maze that can be scaled in size (no squares needed). Now to just place the ball in the start spot and perhaps a bit of fancier visuals?
Another restriction I found in the code was the declaration of a multi-dimensional array with set boundaries based on a max. It would be simple to break the code by placing something larger than the max in editor, so I also placed a quick check. Now we have a robust maze generation system that procedurally generates a simple yet complex and winnable maze that can be scaled in size (no squares needed). Now to just place the ball in the start spot and perhaps a bit of fancier visuals?
Wednesday, August 12, 2015
Maze Generation - Working With Blocks, Not Walls
In implementing a maze, I figured a simple thing will help creation. That, and anything sought in Prim's and Kruskal's algorithm seem to only go for walls over using actual blocks as stopping points for walls. Luckily, a generous person by the name of SaxonRahs posted this tutorial on simple maze generation. The way it goes starts with walling off the perimeter, then taking each space after every other in the middle and setting it to a block. That way, one has a set of pillars. With each pillar, one takes a random value and sets an empty space to a block.
It works surprisingly well for the regular rand() function and a set square, but when one goes outside of that set range, ESPECIALLY using seed values...not so much. I've asked them about how to go about working with seeding random values, but the actual application was made about 0.3 versions ago, so there's not too much hope. I also had to add an offset of their owner actor when spawning it in code; luckily there's a function provided that actually spawns a Blueprint class that you can attach as a property in the parent object, but they're not attached upon spawn. As a quick fix, I added the original location of the parent as an offset, but I'm still wondering how to attach the tiles properly on runtime.
Here is a shot of the seeded maze; note the lack of escape.
It works surprisingly well for the regular rand() function and a set square, but when one goes outside of that set range, ESPECIALLY using seed values...not so much. I've asked them about how to go about working with seeding random values, but the actual application was made about 0.3 versions ago, so there's not too much hope. I also had to add an offset of their owner actor when spawning it in code; luckily there's a function provided that actually spawns a Blueprint class that you can attach as a property in the parent object, but they're not attached upon spawn. As a quick fix, I added the original location of the parent as an offset, but I'm still wondering how to attach the tiles properly on runtime.
Here is a shot of the seeded maze; note the lack of escape.
Tuesday, August 11, 2015
Starting up UE4 with Excessively Long Compiling and generated.h errors
Due to the wishes of some of my fellow students for our upcoming semester, I've been tasked with working with Unreal Engine 4 again, as I did for a capstone earlier this year. Unreal Engine 4 definitely pushes the limits of my system, so much that compile time takes much too long and strange and random errors will break and then not cause any problems. Case in point, the generated.h files will be reported as not being found, which in some cases will actually stop compilation. However, if you exit and return, building and running again, it will strangely not give any problems.
It's an example of something involving the UCLASS and USTRUCT macro, which when included require a header generation that is generated upon runtime. It does not work well with Visual Studio's compiling, especially Intellisense. It's a messy problem that never gets fixed from version to version, so make sure to build and run anyways if you run into the error, or restart Visual Studio and try again.
I'm also tasked with building a maze, which is far more difficult for me than most people for some reason; I'm not the best with understanding how a maze is created in a visual perspective, and especially from code.
It's an example of something involving the UCLASS and USTRUCT macro, which when included require a header generation that is generated upon runtime. It does not work well with Visual Studio's compiling, especially Intellisense. It's a messy problem that never gets fixed from version to version, so make sure to build and run anyways if you run into the error, or restart Visual Studio and try again.
I'm also tasked with building a maze, which is far more difficult for me than most people for some reason; I'm not the best with understanding how a maze is created in a visual perspective, and especially from code.
Monday, August 10, 2015
Currently Attempting Snow For Particles
This will be a relatively short post, as particle system creation is in the works. I am currently working on a particle system for a bit of snow to go with the snowy farm scene. Right now I am rendering a snowflake texture to a number of quads and randomizing their location, velocity, and other such aspects. Unfortunately, this doesn't translate to the screen at all; a quick HLSL debugging check reveals an actual issue in tracing the shader itself, so I'm wondering what the problem is with that. Tomorrow I'll see if I can try different textures or scaling the texture to see what the problem is. I also anticipate having to use billboarding techniques to rotate each particle toward the camera so the camera can see it.
Sunday, August 9, 2015
Sacrificing Optimization for...Something That Works
In the previous post, I mentioned that I finally got the terrain (300K+ points and all) rendered onto the screen. Unfortunately, only a slice of the terrain was rendered, and I was still to put collision on the land. For the slice problem, the example I was following from Microsoft for loading index buffers did not foresee indices that went above the 65536 range, so I fixed the index buffer to allow 32 bit integers.
As for the actual shape, I had a choice between the btBvhTriangleMeshShape and the btHeightfieldTerrainShape. The latter was, according to performance and the name, definitely the one preferred. However! I found out that the heightfield centers based on the bounding box, meaning there was little to no hope of me being able to match the terrain rigidbody with the actual terrain. Bullet has little to no explanation or help on the matter online (as usual), so I'm sticking with the btBvhTriangleMeshShape regardless of the insane amount of performance loss during initialization. At least until something works.
And luckily enough, the terrain works and does not slow down during the actual rendering cycle, along with a great reaction to the fog shown below:
As for the actual shape, I had a choice between the btBvhTriangleMeshShape and the btHeightfieldTerrainShape. The latter was, according to performance and the name, definitely the one preferred. However! I found out that the heightfield centers based on the bounding box, meaning there was little to no hope of me being able to match the terrain rigidbody with the actual terrain. Bullet has little to no explanation or help on the matter online (as usual), so I'm sticking with the btBvhTriangleMeshShape regardless of the insane amount of performance loss during initialization. At least until something works.
And luckily enough, the terrain works and does not slow down during the actual rendering cycle, along with a great reaction to the fog shown below:
Seems perfect for a bit of snow. I'm thinking a post-processing effect will be ideal for the situation.
Saturday, August 8, 2015
A Lovelier Farmhouse and the Key to the Fog Problem: Terrain
Back to fixing up the btBvhTriangleMeshShape! Luckily enough, it was a strange but quick fix: ensure that the btTriangleMesh was a pointer to an object instead of an actual object initialized. Now that the mesh farmhouse worked, the ball could run and correctly collide into a mesh surface. The next issue was how the farmhouse looked; the texture coordinates looked as if they were all over the place instead of following the texture map. Solution? It turns out the Assimp code I was using to load models was flipping the UVs for OpenGL use; DirectX does not require UV flipping, so I disabled that when the importer was calling importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs); by removing the flag. And thus, the farmhouse looked quite beautiful.
As a short fix, the balls also lacked a bouncyness to them, so I quickly added restitution to the world to generate a proper bouncing reaction between the player/enemy and the farmhouse and general world.
Next up was to figure out the ground; I could not work with terrain that did not obey the laws of fog factors, so I had to generate my own. Luckily there was a set of tutorials here that I could utilize to load a heightmap based on a bitmap file created in a 2D art program such as Gimp. The only setback was properly setting the vertices and indices of the model to render properly and separately from the rest of the models. Currently the terrain has no collision body, so I made the world transparent to show the terrain properly adjusting to the fog below:
Was there still a problem? Yes, unfortunately; the terrain looked as if it was a long rectangle instead of being the square generation I was looking for. Later on after I load the collision, I will see what is wrong with loading the heightmap.
As a short fix, the balls also lacked a bouncyness to them, so I quickly added restitution to the world to generate a proper bouncing reaction between the player/enemy and the farmhouse and general world.
Next up was to figure out the ground; I could not work with terrain that did not obey the laws of fog factors, so I had to generate my own. Luckily there was a set of tutorials here that I could utilize to load a heightmap based on a bitmap file created in a 2D art program such as Gimp. The only setback was properly setting the vertices and indices of the model to render properly and separately from the rest of the models. Currently the terrain has no collision body, so I made the world transparent to show the terrain properly adjusting to the fog below:
Was there still a problem? Yes, unfortunately; the terrain looked as if it was a long rectangle instead of being the square generation I was looking for. Later on after I load the collision, I will see what is wrong with loading the heightmap.
Friday, August 7, 2015
A Real Object Needs Real Collision
Finally got a real looking object into my application! It's a lovely farmhouse with two steps and no interior, but an actual object nonetheless that works very well with fog. Problem is, I'm no longer working with a simple box nor sphere for collision; I need a full on mesh collider. Luckily, bullet has one in the form of a btBvhTriangleMeshShape, but I'm currently working out the details on what the mesh needs exactly in order not to give 0x00000000 exceptions. I'll have more details and a full picture once I get the thing working.
Thursday, August 6, 2015
Depth Based Fog, For When Linear Doesn't Cut It
Phew! Managed a passable fog. After figuring out that subtracting the viewpoint distance from the start of the fog instead of the beginning was the cause of my previous issue (and thanks to some HLSL debugging that I discovered), a problem still existed: The fog seemed to rely too much on the placement of the object itself rather than the per-pixel fog I was looking for. DX9 and DX10 seemed to have that type of thing built in, but DX11 required it to be built from scratch and NOTHING on the Internet had it. It was quite disappointing and I was stuck with calculating vertex values with some very odd results where the floor wasn't nearly as foggy as the wall I was right next to.
However, I managed a bit of a small step in the right direction with depth values. By taking the depth value and forming it to a linear set of values between 0.0f and 1.0f (transform to NDC coordinates, then work backwards according to the (1/z - 1/near / 1/far - 1/near) for depth calculation, I finally got the values I was looking for (with a bit of clamping). By multiplying said fog by a set constant value, the objects would fade into grey based on their depth values in the scene. This worked well, even with the vertices that weren't well spread out on the plane. I'm thinking with a floor or terrain with more vertices, such a problem won't be present. The skybox is still there, but is also interpolated with the foggy color to seem more natural compared to the rest of the objects.
However, I managed a bit of a small step in the right direction with depth values. By taking the depth value and forming it to a linear set of values between 0.0f and 1.0f (transform to NDC coordinates, then work backwards according to the (1/z - 1/near / 1/far - 1/near) for depth calculation, I finally got the values I was looking for (with a bit of clamping). By multiplying said fog by a set constant value, the objects would fade into grey based on their depth values in the scene. This worked well, even with the vertices that weren't well spread out on the plane. I'm thinking with a floor or terrain with more vertices, such a problem won't be present. The skybox is still there, but is also interpolated with the foggy color to seem more natural compared to the rest of the objects.
Before I start working on something snow related, I may want to replace the gigantic wall with something more realistic like a building. That will be the next step.
Wednesday, August 5, 2015
Fog is Infuriatingly Difficult to Figure Out
Yeah, that's what it now looks like. This is actually supposed to be a linear interpolation of fog, where the distance is set between 0 and 400. There should be a lot more to be seen by this. It was working a little while back when I took the data and directly put it in the shader, instead of a constant buffer, but now nothing's working. I have no idea what is going on nor how to fix it, but I'll do my best for tomorrow.
Tuesday, August 4, 2015
Optimization, Multithreading, and KillZ
While I would like to tackle something much fancier, I noticed a severe performance drop when implementing Recast. Thus, it was time to hit the profiler in Visual Studio! (Debug/Performance and Diagnostics, start profiling in the Performance Explorer) There was a bit of a problem where the application directly needed D3DCOMPILER_47.dll, but that was as simple as taking the actual dll out of the Windows Kits 8.1 bin folder and placing it in the application for extra packaging.
When noticing the profiler, I noticed a single function that ate up most of the profiling time: navMesh.GenerateNavMap(). When jumping into those functions, I unfortunately came across a profiling nightmare; API being responsible for the performance drop. What to do? Luckily enough, there were a few settings I adjusted before running it a second time. When running rcBuildPolyMeshDetail, the function can take up a lot of processing time unless you allow for a little more error. 0.1 was a bit much for this simple function, so I raised a bit higher. Similarly enough, the rcRasterizeTriangles method also took up a lot of space, so by reducing the triangles (increasing maxEdgeLength for the navigation mesh) definitely helped.
For one last shot at fanciness, though, I did indeed take a look into multithreading and set the world geometry setup/navMesh setup into a thread that was run separately from the rest of the function. Luckily enough, there was a high enough performance raise to warrant its creation.
So far, I think that's the most I'll get optimized for now. The bottlenecks lie strictly in third-party API zone at this point, with Bullet's stepSimulation taking up Render()'s time and the rest of the init code being taken up by Assimp's file reading. If anyone has any other recommendations for optimization, I would most certainly love to hear it. Onto fog for our next round...
Oh wait, forgot to mention; I setup a KillZ point to restart enemies and players upon falling too far.
When noticing the profiler, I noticed a single function that ate up most of the profiling time: navMesh.GenerateNavMap(). When jumping into those functions, I unfortunately came across a profiling nightmare; API being responsible for the performance drop. What to do? Luckily enough, there were a few settings I adjusted before running it a second time. When running rcBuildPolyMeshDetail, the function can take up a lot of processing time unless you allow for a little more error. 0.1 was a bit much for this simple function, so I raised a bit higher. Similarly enough, the rcRasterizeTriangles method also took up a lot of space, so by reducing the triangles (increasing maxEdgeLength for the navigation mesh) definitely helped.
For one last shot at fanciness, though, I did indeed take a look into multithreading and set the world geometry setup/navMesh setup into a thread that was run separately from the rest of the function. Luckily enough, there was a high enough performance raise to warrant its creation.
So far, I think that's the most I'll get optimized for now. The bottlenecks lie strictly in third-party API zone at this point, with Bullet's stepSimulation taking up Render()'s time and the rest of the init code being taken up by Assimp's file reading. If anyone has any other recommendations for optimization, I would most certainly love to hear it. Onto fog for our next round...
Oh wait, forgot to mention; I setup a KillZ point to restart enemies and players upon falling too far.
Monday, August 3, 2015
Skybox Works! Added Lighting and Noticed Needed Optimization
Good to know the skybox works! That was fixed by applying the same model I loaded for the player spheres and texturing that with the skybox shader instead of creating a sphere from scratch. Worked like a charm.
However, if I wanted anything fancy in the way of visuals, I would need to create some lighting first. Today was just a simple implementation of direction-based ambient/diffuse/specular lighting, though I opted out the specular since the balls weren't that shiny nor had specific materials to guide their lighting components. If it's necessary, I'll certainly add it down the line.
I did notice another problem, though; the Recast navigation mesh is taking an awful long while to create in the initialization. Perhaps it's good to spend tomorrow working out the profiler and see what the matter is with it.
All in all, it's looking a bit nicer than before!
However, if I wanted anything fancy in the way of visuals, I would need to create some lighting first. Today was just a simple implementation of direction-based ambient/diffuse/specular lighting, though I opted out the specular since the balls weren't that shiny nor had specific materials to guide their lighting components. If it's necessary, I'll certainly add it down the line.
I did notice another problem, though; the Recast navigation mesh is taking an awful long while to create in the initialization. Perhaps it's good to spend tomorrow working out the profiler and see what the matter is with it.
All in all, it's looking a bit nicer than before!
Sunday, August 2, 2015
Skyboxes: So far, the Sphere-From-Scratch trick isn't working
I decided to give skyboxes a shot for this application. For OpenGL, the cubemapping process is fortunately simple and manageable, but regarding DirectX's DDSTexture loading code (Currently using a large cpp file that automatically loads from a file), it's difficult to figure out whether it's loading the cubemap properly. A certain set of tutorials I'm following detail a sphere automatically created on the fly, and I managed to get the skybox settings properly set with setting culling to none and making the skybox the furthest object away by swizzling (xyww) and setting the Depth Stencil state, but the product...eh.
There's a sky showing in a large, jagged half sphere that doesn't cover the entire set. In all honesty, tomorrow I'll probably create a sphere or cube from Blender and load it this way; it'll limit the variables of this situation. If it's the texture...ugh. Let's hope it's not the texture loading code.
I have Jockum Skoglund to thank for the lovely skybox from Open Game Art. Thank you!
Saturday, August 1, 2015
Always Get Your Bounding Conditions Correct!
Today was another trial in adapting simple straight path measurement code for the pathfinder class. So far, managed a proper framework that would detail the correct path and a straight line for that path (with a max up to three steps) and follow to the point of that path. Unfortunately, there was a problem in loading the vertices correctly which led to no contours being developed, stemming from no spans in the heightfield and god knows what else. Turns out the points being loaded when creating the heightfield were constantly being compared to a set of bounds that firmly did not exist; the ymin and ymax were reversed. Luckily enough, a heavy set of debugging skills led to solve that matter and get a little more in depth understanding of this nauseatingly complex open source library.
Next up is figuring out why the dtNavMesh is not initializing properly; that seems to be the more pertinent problem, now that the Recast mesh is created properly. Ah! It seems that dtNavQuery needs its own allocation before initialization.
Now that that's all set, Detour seems to be working surprisingly well! Perhaps even better than consistently locking onto the player's position. Now the AI will be locking on to the player's movement and taking obstacles into account.
Next up is figuring out why the dtNavMesh is not initializing properly; that seems to be the more pertinent problem, now that the Recast mesh is created properly. Ah! It seems that dtNavQuery needs its own allocation before initialization.
Now that that's all set, Detour seems to be working surprisingly well! Perhaps even better than consistently locking onto the player's position. Now the AI will be locking on to the player's movement and taking obstacles into account.
Subscribe to:
Posts (Atom)