Happy New Year!
...almost. Today was mainly a work day in which I responded to feedback and tried (unsuccessfully, yet again) to build the python build that a former employee left behind. After reinstalling the Python libraries after Tcl/Tk wasn't being resolved properly and doing the proper conversions of the build document from DOS to Unix (dos2Unix, oddly enough did not work, so I had to remove the characters manually (sed -i 's/\r$//' insert-file-here) ), PyInstaller seemed to not support a certain type of replace it was attempting. Whether this is because the latest version of PyInstaller is too new or not, I am uncertain. Honestly, there's a lot of things to be uncertain about regarding what proper Python tools to use.
Going back to the actual Unity work, I managed a couple of tweaks here and there. By employing the motion blur provided by Unity's standard assets, I did a convincing speed blur effect upon hyper speed. It's not the official camera motion blur script, but taking a render texture and applying the offsets to the main scene, one can get a pretty cool effect:
On top of that, I also put in some background assets and a script that repeats them over time to fit the looping nature of the scene. I don't know if it was entirely necessary, but I exercised taking messy for-loops out and mainly worked with recursive programming. After learning about template metaprogramming. I could also put in some template overloads if I really wanted to follow that route.
As for the floating ball scene, I applied some tweaks with a gently swaying motion to reward objects. Coroutines came to the rescue (don't they always) and applied a back-and-forth constant force (doing away with external gravity entirely). The tricky part, however, was reversing velocity; an instant change was too jarring, but reversing the velocity applied by a constant force caused an unequal distribution on one end, causing the objects to fly veeeeery far into the air.
The solution for that was a quick but gentle velocity decrease function; if the velocity sign did not match the force sign, the function would move the velocity toward 0, giving the force a fighting chance and getting a gentle back-and-forth motion:
What next? Another application in the works is calling for weather. Can I make clouds without referring to a paid package? I better hope so.
An account of pain, struggle, and amusing discoveries found in a man's quest for game programming style and finesse.
Thursday, December 31, 2015
Wednesday, December 30, 2015
Studying Is Done! For Now
Today marks the end of my traveling through Scott Meyers's Effective C++ books.
Step 1: With lambda expressions, they offer plenty of flexibility in relation to std::bind calls.
Step 2: Thread-based programming? Eh, if you want to deal with oversubscription and system_thread exceptions. And also optimize the thread programming, but most of the time put the trust in async.
Step 3: And when you do, feel free to work with the default launch policy (sync or async), but avoiding checks associated with deferred synchronous futures (fancy objects created from async) can be done by getting a little more specific with std::launch::async.
Step 4: Making the std::thread class unjoinable on all threads prevents premature termination if anything goes wrong during a joinable thread.
Step 5: However, destruction behavior varies on thread handles, especially with futures. With a future (usually the last in a line of shared_futures) referring to a shared state (the line between a promise and a future - almost sounds lovely), it will do an odd exceptional behavior by blocking until the task completes. Otherwise it destroys all data members.
Step 6: For one-shot event communication, promises and futures can work quite well! Just remember to keep their parameters void since they won't be used.
Step 7: For concurrency, std::atomics are quite useful. However, for unpredictable memory like peripheral memory, just using atomics could be painful. Mark those special spots with volatile to prevent unnecessary optimizations on unpredictable data.
Step 8: It's a small case (copyable parameters that are cheap to move and always copied), but passing by value makes a difference where it's usually avoided.
Step 9: Emplace! It constructs and inserts in the same breath! Under the right circumstances, it can work well when running different types into a list insertion.
I didn't have too much work to do on the EEG work today; it was mainly composed of setting a coroutine of negation protection, in the case that an interval for negation fired right after a reward. The negation protection is another time that gives a bit of padding to the negation firing event.
What next? Who knows? Maybe I can get back to my capstone code and post screenshots again.
Step 1: With lambda expressions, they offer plenty of flexibility in relation to std::bind calls.
Step 2: Thread-based programming? Eh, if you want to deal with oversubscription and system_thread exceptions. And also optimize the thread programming, but most of the time put the trust in async.
Step 3: And when you do, feel free to work with the default launch policy (sync or async), but avoiding checks associated with deferred synchronous futures (fancy objects created from async) can be done by getting a little more specific with std::launch::async.
Step 4: Making the std::thread class unjoinable on all threads prevents premature termination if anything goes wrong during a joinable thread.
Step 5: However, destruction behavior varies on thread handles, especially with futures. With a future (usually the last in a line of shared_futures) referring to a shared state (the line between a promise and a future - almost sounds lovely), it will do an odd exceptional behavior by blocking until the task completes. Otherwise it destroys all data members.
Step 6: For one-shot event communication, promises and futures can work quite well! Just remember to keep their parameters void since they won't be used.
Step 7: For concurrency, std::atomics are quite useful. However, for unpredictable memory like peripheral memory, just using atomics could be painful. Mark those special spots with volatile to prevent unnecessary optimizations on unpredictable data.
Step 8: It's a small case (copyable parameters that are cheap to move and always copied), but passing by value makes a difference where it's usually avoided.
Step 9: Emplace! It constructs and inserts in the same breath! Under the right circumstances, it can work well when running different types into a list insertion.
I didn't have too much work to do on the EEG work today; it was mainly composed of setting a coroutine of negation protection, in the case that an interval for negation fired right after a reward. The negation protection is another time that gives a bit of padding to the negation firing event.
What next? Who knows? Maybe I can get back to my capstone code and post screenshots again.
Tuesday, December 29, 2015
Leaning and Hyper Speed
Today was a day for me to get a little more work done with the Unity EEG project. The next step in input was to set a Hyper Speed (or a fairly fast speedy force) on the ball if enough rewards were given. Luckily, the negate reward coroutine was perfect for tallying up the amount of reward events and applying the necessary force. I just had to be careful not to make it look like a jump; the direction had to be the direction the ramp was following, not just a simple Vector3.forward.
As for another portion of the Infinite Ball roll, I was also tasked with creating a leaning object. This required a force to be applied to the ball at a certain threshold, waggling around without exactly falling off.
Along with that, I was also asked to see if the Unreal HTML5 projects can be used similarly like we are using the Unity Web Player now. Can it be done? I'll have to find out.
Almost done with studying as well! Went over plenty of move semantics, perfect forwarding fallacies, and universal references before making a start on lambda expressions.
As for another portion of the Infinite Ball roll, I was also tasked with creating a leaning object. This required a force to be applied to the ball at a certain threshold, waggling around without exactly falling off.
Along with that, I was also asked to see if the Unreal HTML5 projects can be used similarly like we are using the Unity Web Player now. Can it be done? I'll have to find out.
Almost done with studying as well! Went over plenty of move semantics, perfect forwarding fallacies, and universal references before making a start on lambda expressions.
Monday, December 28, 2015
Smart-Alec Pointers
Ah, another round with learning about smart pointers! Luckily, this study revealed that much progress has been made in C++11 and C++14 since the previous text that told me I had to make my own shared_ptr.
Step 1: Unique_ptr is good for exclusive ownership, and great for pointer-to-implementation (Pimpl, heh) idioms!
Step 2: Shared_ptr is now a legitimate part of the standard. Just be careful that the shared_ptr keeps track and doesn't leave dangling pointers (by way of cycled references and what not)
Step 3: And in the case of said cyclical references, use weak_ptr for its keen ability to detect whether it dangles!
Step 4: Use make_shared and make_unique over duplicate code and allocation by constructing based off a new constructed object. It's just more efficient that way (except for weak_ptrs that get destroyed after shared_ptrs)
Step 5: When using the Pimpl idiom, make sure to declare special member functions BUT put them implemented in the implementation file.
Step 6: std::move and std::forward actually do nothing like it says; it just makes something that could be eligible for moving by unconditional and conditional rvalue casting. Move is simpler, but forward is more correct for rvalue casting.
Step 7: Keep const member functions thread safe! Use atomics for singular values/memory locations, but for anything else, nothing works better than a mutex.
Step 8: Constexpr is a good way to keep values const and known during compilation, while it allows functions to produce constexpr return values and function regularly with normal values
Step 9: Declaring noexcept is a good idea for things that don't emit exceptions (std::pow, swap, moves) to help optimize the calls for those functions.
Nearly done! Just a couple more days.
Step 1: Unique_ptr is good for exclusive ownership, and great for pointer-to-implementation (Pimpl, heh) idioms!
Step 2: Shared_ptr is now a legitimate part of the standard. Just be careful that the shared_ptr keeps track and doesn't leave dangling pointers (by way of cycled references and what not)
Step 3: And in the case of said cyclical references, use weak_ptr for its keen ability to detect whether it dangles!
Step 4: Use make_shared and make_unique over duplicate code and allocation by constructing based off a new constructed object. It's just more efficient that way (except for weak_ptrs that get destroyed after shared_ptrs)
Step 5: When using the Pimpl idiom, make sure to declare special member functions BUT put them implemented in the implementation file.
Step 6: std::move and std::forward actually do nothing like it says; it just makes something that could be eligible for moving by unconditional and conditional rvalue casting. Move is simpler, but forward is more correct for rvalue casting.
Step 7: Keep const member functions thread safe! Use atomics for singular values/memory locations, but for anything else, nothing works better than a mutex.
Step 8: Constexpr is a good way to keep values const and known during compilation, while it allows functions to produce constexpr return values and function regularly with normal values
Step 9: Declaring noexcept is a good idea for things that don't emit exceptions (std::pow, swap, moves) to help optimize the calls for those functions.
Nearly done! Just a couple more days.
Sunday, December 27, 2015
Preferring This Modern, Newfangled Keyword
Today was mainly a study day due to my busy schedule today. Not busy enough to keep from learning!
Step 1: auto may produce undesired types in the case of proxy classes. Explicitly cast that type when declaring auto variables to prevent this!
Step 2: {} can produce different construction behavior when working with numeric vectors ({10, 20}, what does it make?) and has preference for initializer_list. However, it prevents some nasty things like the parse that makes default constructors look like normal functions.
Step 3: Prefer nullptr to 0 and NULL. One is a pointer (or all types) type, and the others are integral types. This can turn into some nasty overloading when trying to call functions on each different null type, so stick to nullptr.
Step 4: Prefer alias declarations to typedefs. Using blah = tends to be a little better than putting typedefs in structs, along with reducing dependent types while programming.
Step 5: Prefer enum class to enum; scoped enums help strongly type enumerated values and prevents comparing a Color to a number.
Step 6: Prefer deleted functions to private, undefined functions. Some member or friend might try.
Step 7: Declare overriding functions with override, so the compiler can check whether the function properly overrides something.
Step 8: Prefer noexcept for functions like move operations and swap that do not emit exceptions; this provides more efficient code that helps to optimize the stack during possible preparation for exceptions.
Step 1: auto may produce undesired types in the case of proxy classes. Explicitly cast that type when declaring auto variables to prevent this!
Step 2: {} can produce different construction behavior when working with numeric vectors ({10, 20}, what does it make?) and has preference for initializer_list. However, it prevents some nasty things like the parse that makes default constructors look like normal functions.
Step 3: Prefer nullptr to 0 and NULL. One is a pointer (or all types) type, and the others are integral types. This can turn into some nasty overloading when trying to call functions on each different null type, so stick to nullptr.
Step 4: Prefer alias declarations to typedefs. Using blah = tends to be a little better than putting typedefs in structs, along with reducing dependent types while programming.
Step 5: Prefer enum class to enum; scoped enums help strongly type enumerated values and prevents comparing a Color to a number.
Step 6: Prefer deleted functions to private, undefined functions. Some member or friend might try.
Step 7: Declare overriding functions with override, so the compiler can check whether the function properly overrides something.
Step 8: Prefer noexcept for functions like move operations and swap that do not emit exceptions; this provides more efficient code that helps to optimize the stack during possible preparation for exceptions.
Saturday, December 26, 2015
Web Player Doesn't Want Your Dirty IO
Today was definitely a busy day, but a good day to tackle a bug and learn an interesting thing about the (soon-to-be-deprecated) Unity Web Player build.
The problem in question was the pause state; the pause state was relayed from the EEG software, but whenever an application is loaded, there's no way for the HTML player to grab the state; it's a one-way street, so the pause has to be saved for a rainy day.
What to do? Well, common sense says that one can just use a BinaryFormatter to serialize and write data to a file, which Unity supports with a persistent data path on whatever device it's running on. The Web Player, however, does not support this traditional IO styling of saving data. No reading or writing serializable data allowed?
Do not fret! I only needed to save a boolean value, so the way to go was PlayerPrefs, which is a small preferences class actually stored in the Unity build. This allows the setting and getting of values such as ints and floats in a key-value type system, where the key is a string name. However, there was also no Get/Set Bool, so I had to default to wonky static functions that, for better or for worse, translate to value ? 1 : 0. Ternary operators are not the most readable, but it's quick and gets the job done.
What next? I finished the STL C++ book and am moving onto C++ 11 and C++ 14, letting me know how type deduction works and how auto and template based type deduction are essentially like each other except for bracketed definition of values. Yeuch.
The problem in question was the pause state; the pause state was relayed from the EEG software, but whenever an application is loaded, there's no way for the HTML player to grab the state; it's a one-way street, so the pause has to be saved for a rainy day.
What to do? Well, common sense says that one can just use a BinaryFormatter to serialize and write data to a file, which Unity supports with a persistent data path on whatever device it's running on. The Web Player, however, does not support this traditional IO styling of saving data. No reading or writing serializable data allowed?
Do not fret! I only needed to save a boolean value, so the way to go was PlayerPrefs, which is a small preferences class actually stored in the Unity build. This allows the setting and getting of values such as ints and floats in a key-value type system, where the key is a string name. However, there was also no Get/Set Bool, so I had to default to wonky static functions that, for better or for worse, translate to value ? 1 : 0. Ternary operators are not the most readable, but it's quick and gets the job done.
What next? I finished the STL C++ book and am moving onto C++ 11 and C++ 14, letting me know how type deduction works and how auto and template based type deduction are essentially like each other except for bracketed definition of values. Yeuch.
Friday, December 25, 2015
Christmas Is No Excuse to Not Program
Happy Holidays! Time to program.
Both yesterday and today I brainstormed over what to do with creating a "curved path", like my supervisors wanted. Ideally, there'd be some elegant, free spline mesh deformation tool already available with Unity to make my dreams come true.
Nah. I brushed up on procedural mesh generation and am currently in the midst of building sides of a mesh for a possible wrap-around repeated square generation to produce a track along a specific spline:
(I promise you, that's not the default Unity cube)
As for the tessellator work, I was tasked with also creating a reverse behavior on the tessellator, so that it would start spinning and crazy and displaced and slowly come back into orderly place. This required the use of Unity's Constant Force modules, with a negative-reward-based subscriber that increased and decreased a constant spinning torque on the module.
I also looked into the various uses and pitfalls of function objects, including an interesting fact: usually, the act of abstracting code leads to extra costs, but function objects actually save more time than actual functions being sent into algorithms. Who knew?
Both yesterday and today I brainstormed over what to do with creating a "curved path", like my supervisors wanted. Ideally, there'd be some elegant, free spline mesh deformation tool already available with Unity to make my dreams come true.
Nah. I brushed up on procedural mesh generation and am currently in the midst of building sides of a mesh for a possible wrap-around repeated square generation to produce a track along a specific spline:
(I promise you, that's not the default Unity cube)
As for the tessellator work, I was tasked with also creating a reverse behavior on the tessellator, so that it would start spinning and crazy and displaced and slowly come back into orderly place. This required the use of Unity's Constant Force modules, with a negative-reward-based subscriber that increased and decreased a constant spinning torque on the module.
I also looked into the various uses and pitfalls of function objects, including an interesting fact: usually, the act of abstracting code leads to extra costs, but function objects actually save more time than actual functions being sent into algorithms. Who knew?
Wednesday, December 23, 2015
Point and Spin
Today was a day to perfect and make sure pausing and tessellation worked the way it should. Thankfully I fixed it before committing the most recent work, since I was putting the commands for resuming the work in the Scale change command, instead of the actual run command. Been a long day...
As for the tessellation, I figured a sharp change in tessellation would not do, so I incorporated a smooth linear interpolation from the current displacement to a target displacement. I also figured a more interesting movement (like a spinning motion) would be more interesting to show off the tessellation, so I put in a torque force that was applied, with angular drag doing the work for negating rewards for me. Lo and behold, a spinny-spiky-crystal thing!
As for studies today, I mainly went over associative containers and iterators (and ran out of notebook space). For example, casting from const_iterators to iterators is impossible, but by constructing a new iterator and moving it to the current const_iterator position is feasible using advance and distance. Problem is....is it a random access iterator, or a bidirectional iterator?
Also, maps have a very interesting "add and update" logic associated with their [ ] operators, so one can balance between using [ ] and inserts to make faster updating and adding, respectively.
Also, the age-old question that confuses many new to associative containers (me): What is the difference between equality and equivalence?
Equality? Just equal values. Equivalence? Neither precedes the other in a sort order. Think of it as !(x < y) && !(y < x). All strange sort orders (ignoring case, <=) applies, although it's wise to return false on an equal operator.
What next? If artists don't come to my rescue, I might just work on procedural mesh creation.
As for the tessellation, I figured a sharp change in tessellation would not do, so I incorporated a smooth linear interpolation from the current displacement to a target displacement. I also figured a more interesting movement (like a spinning motion) would be more interesting to show off the tessellation, so I put in a torque force that was applied, with angular drag doing the work for negating rewards for me. Lo and behold, a spinny-spiky-crystal thing!
As for studies today, I mainly went over associative containers and iterators (and ran out of notebook space). For example, casting from const_iterators to iterators is impossible, but by constructing a new iterator and moving it to the current const_iterator position is feasible using advance and distance. Problem is....is it a random access iterator, or a bidirectional iterator?
Also, maps have a very interesting "add and update" logic associated with their [ ] operators, so one can balance between using [ ] and inserts to make faster updating and adding, respectively.
Also, the age-old question that confuses many new to associative containers (me): What is the difference between equality and equivalence?
Equality? Just equal values. Equivalence? Neither precedes the other in a sort order. Think of it as !(x < y) && !(y < x). All strange sort orders (ignoring case, <=) applies, although it's wise to return false on an equal operator.
What next? If artists don't come to my rescue, I might just work on procedural mesh creation.
Tuesday, December 22, 2015
Extra Pointy Pausing
Today was a day to further some interesting progress on the negative side of the EEG software input; instead of representing a specific amplitude and threshold of inhibitor wavelengths, I was tasked with creating a negative reward system; if the rewards aren't coming fast enough, negative rewards (i.e. reversal of reward effects) start happening. In that case, I came back to my old friend (the coroutine) and set a timer to negate rewards after a set time. If the rewards come fast enough, the scene works nicely. I even repurposed some classes like the color changer of the sky to go towards a negative color upon negation of rewards.
I also starting fitting some of the other EEG software events with the Unity game, including a pause screen that only unpauses when the EEG software unpauses its system:
As for another step in the next application, I also looked into setting a displacement shader with tessellation values. By extruding the vertex in the direction of a specified normal displacement map (with extra vertices from tessellation!), one will be able to achieve an interesting effect over time with the reward system soon:
And as for studies? Never think that a vector<bool> is anything that actually contains bool objects. Nay, it contains bitfields. Try a deque<bool> instead.
I also starting fitting some of the other EEG software events with the Unity game, including a pause screen that only unpauses when the EEG software unpauses its system:
As for another step in the next application, I also looked into setting a displacement shader with tessellation values. By extruding the vertex in the direction of a specified normal displacement map (with extra vertices from tessellation!), one will be able to achieve an interesting effect over time with the reward system soon:
And as for studies? Never think that a vector<bool> is anything that actually contains bool objects. Nay, it contains bitfields. Try a deque<bool> instead.
Monday, December 21, 2015
Choose Your Own Reward Adventure
Phew! Today's been quite the busy day and studying isn't done just yet (although I see the algorithmic difference now from using empty() as opposed to size()). My task in my EEG work today was to separate rewards from each other on an activated menu.
How that works is that the subscribers attaching and detaching from the reward event controller are now controlled by a toggled UI interface. That said, that allows me to separate the pieces and parts of each reward effect even further (sound cues separated from bouncing and floating) to create a more customized experience.
That, and bright green explosions! Just what a reward state needs.
How that works is that the subscribers attaching and detaching from the reward event controller are now controlled by a toggled UI interface. That said, that allows me to separate the pieces and parts of each reward effect even further (sound cues separated from bouncing and floating) to create a more customized experience.
That, and bright green explosions! Just what a reward state needs.
Sunday, December 20, 2015
Finishing More Effective C++
Today was a bit of a break day with the family, but I managed to roll in some lessons and wrap up the sequel to the Effective C++ book, More Effective C++.
Step 1: Smart pointers are ideal - a lot has to be done by oneself, overloading dereferencing, constructors, deconstructors, and deciding whether the raw data needs access. It is ideal, though.
Step 2: Reference counting is also a very important thing when considering extensions for smart pointers (shared_ptr from TR1?), and helping a Flyweight-style pattern when object creation is expensive.
Step 3: Proxy classes can help when doing things like multidimensional dynamic arrays (Array2D of Array1Ds) but can effectively betray the assumptions of the main class, especially with implicit type conversions.
Step 4: Making functions virtual with respect to multiple parameters? Double dispatching? Either submit to a terrifying if-else loop or attempt a set of many functions that emulate pointers to a virtual table.
Step 5: Program in the future tense. Focus on prevention over documentation and make complete classes. Take advantage of paranoia.
Step 6: Non-leaf classes can lead to problems when transferring data by way of things like the copy assignment operator. It's best to keep non-leaf classes abstract and keep the fringe classes the ones that are used in instantiation.
Step 7: Combining C++ with C may be inevitable, so make use of extern, keep memory management to their specific methods (malloc-free, new-delete), put the main in C++, and keep OOP-related functions and objects out of C-compatible programming.
Step 8: Start STL.
Which is what I'll be doing. Onto studying the Standard Template Libraries!
Step 1: Smart pointers are ideal - a lot has to be done by oneself, overloading dereferencing, constructors, deconstructors, and deciding whether the raw data needs access. It is ideal, though.
Step 2: Reference counting is also a very important thing when considering extensions for smart pointers (shared_ptr from TR1?), and helping a Flyweight-style pattern when object creation is expensive.
Step 3: Proxy classes can help when doing things like multidimensional dynamic arrays (Array2D of Array1Ds) but can effectively betray the assumptions of the main class, especially with implicit type conversions.
Step 4: Making functions virtual with respect to multiple parameters? Double dispatching? Either submit to a terrifying if-else loop or attempt a set of many functions that emulate pointers to a virtual table.
Step 5: Program in the future tense. Focus on prevention over documentation and make complete classes. Take advantage of paranoia.
Step 6: Non-leaf classes can lead to problems when transferring data by way of things like the copy assignment operator. It's best to keep non-leaf classes abstract and keep the fringe classes the ones that are used in instantiation.
Step 7: Combining C++ with C may be inevitable, so make use of extern, keep memory management to their specific methods (malloc-free, new-delete), put the main in C++, and keep OOP-related functions and objects out of C-compatible programming.
Step 8: Start STL.
Which is what I'll be doing. Onto studying the Standard Template Libraries!
Saturday, December 19, 2015
Bringing It Together
Today was a small step forward for the EEG work; since I was busy moving back to Ohio for Winter Break, I decided a good idea would be to set the two applications I was working on to a simple set of loading levels. The current selection in the software is just a single HTML game with a single Unity file, so a build that would allow both applications (and more) at once would be necessary.
As for studying progress, more interesting and complex things abound!
Step 1: Where do REAL temporary objects come from? Implicit conversions and return values from functions, and that can be fixed!
Step 2: By returning constructor arguments instead of returning a temporary value, we can optimize a program and use a relatively standard optimization.
Step 3: Overloading functions (Add(int, MadeUp) instead of implicit conversion) can prevent the temporary objects that are created during implicit type conversions.
Step 4: Using += instead of = (and using the += inside a + operator) can help reduce implicit type conversions as well!
Step 5: Use alternative libraries. This is a small section, but helps illuminate the pros and cons of libraries such as <iostream> (type safe, portable) and <stdio> (small and fast executables)
Step 6: Virtual functions cost plenty! Virtual base tables and pointers to those tables keep in mind how important it is to determine where to produce those tables. A heuristic helps put them in place only where needed, but that can be subverted by inlining. (So don't inline)
Step 7: Virtualizing constructors and non-member functions can be tricky, but possible.
Step 8: Limiting the amount of objects of a class can be done by extending the Singleton to include a max set of references and an exception to throw in case it goes over that amount. It all depends on how "exceptional" those references are though...
Step 9: It's difficult, nay impossible to determine whether an object is on the heap or not, but actually quite simple to determine whether it's alright to delete itself. Do the latter.
Next? More techniques and miscellany!
As for studying progress, more interesting and complex things abound!
Step 1: Where do REAL temporary objects come from? Implicit conversions and return values from functions, and that can be fixed!
Step 2: By returning constructor arguments instead of returning a temporary value, we can optimize a program and use a relatively standard optimization.
Step 3: Overloading functions (Add(int, MadeUp) instead of implicit conversion) can prevent the temporary objects that are created during implicit type conversions.
Step 4: Using += instead of = (and using the += inside a + operator) can help reduce implicit type conversions as well!
Step 5: Use alternative libraries. This is a small section, but helps illuminate the pros and cons of libraries such as <iostream> (type safe, portable) and <stdio> (small and fast executables)
Step 6: Virtual functions cost plenty! Virtual base tables and pointers to those tables keep in mind how important it is to determine where to produce those tables. A heuristic helps put them in place only where needed, but that can be subverted by inlining. (So don't inline)
Step 7: Virtualizing constructors and non-member functions can be tricky, but possible.
Step 8: Limiting the amount of objects of a class can be done by extending the Singleton to include a max set of references and an exception to throw in case it goes over that amount. It all depends on how "exceptional" those references are though...
Step 9: It's difficult, nay impossible to determine whether an object is on the heap or not, but actually quite simple to determine whether it's alright to delete itself. Do the latter.
Next? More techniques and miscellany!
Friday, December 18, 2015
Continuously Rolling
Phew! Today was certainly a difficult day. I nearly lost an important scene file when trying to work on changing levels; looks as if the command receiver and controller did not want to be turned into a prefab, and a backup copy thankfully saved me.
As for progress today, I was tasked with working on a rolling ball application. The main portion of this application is to impose infinite rolling (I would think for now) with effects from rewards that would benefit the ball (keeping on the path? Bouncing?). Oddly enough, I'm experiencing odd issues and a delay on how long it takes for the program to receive JSON commands; this might be attributed to odd issues I'm experiencing with random Python errors (greenlet.py) that I run into.
As for the infinite rolling, I decided to setup a set of three strips of land (similar to a scrolling background) and had the ball roll along those strips. By placing the strips in the exact right locations and using a trigger teleportation script, the ball now rolls infinitely along the same three strips of land without making it look as if it's interrupting its movement.
Due to the odd issues involving trying to get the program to actually receive commands, I decided a simple reward output that didn't necessarily approach an end state with such peril would be necessary, so I put in a simple bounce. Like the CharacterController in Unity, the ball requires a raycast to consistently detect a ground area; I figured that raycast would only be necessary when a reward is thrown, reducing the amount of possibly costly calls.
What next? I'll have to get ahold of my supervisor and see what else I can work on.
As for progress today, I was tasked with working on a rolling ball application. The main portion of this application is to impose infinite rolling (I would think for now) with effects from rewards that would benefit the ball (keeping on the path? Bouncing?). Oddly enough, I'm experiencing odd issues and a delay on how long it takes for the program to receive JSON commands; this might be attributed to odd issues I'm experiencing with random Python errors (greenlet.py) that I run into.
As for the infinite rolling, I decided to setup a set of three strips of land (similar to a scrolling background) and had the ball roll along those strips. By placing the strips in the exact right locations and using a trigger teleportation script, the ball now rolls infinitely along the same three strips of land without making it look as if it's interrupting its movement.
Due to the odd issues involving trying to get the program to actually receive commands, I decided a simple reward output that didn't necessarily approach an end state with such peril would be necessary, so I put in a simple bounce. Like the CharacterController in Unity, the ball requires a raycast to consistently detect a ground area; I figured that raycast would only be necessary when a reward is thrown, reducing the amount of possibly costly calls.
What next? I'll have to get ahold of my supervisor and see what else I can work on.
Thursday, December 17, 2015
Actual Screenshots
Good news today! I made some actual progress on the EEG project! From what I found out yesterday, there is a specific class that acts as an event handler for anticipating each event that the EEG device sends to the application. The main events I look for are the ones in which threshold changes, amplitude changes, and rewards are given.
The rewards weren't exactly implemented yet, so I pulled in a series of objects that would begin glowing and floating upon reception of an award. The rewards (and the amplitude/threshold ratios for the sky and pitch) are subscribers to the event handler (Observer Pattern!) that activate these derived classes of the subscribers when the events are fired.
Luckily this leads to actual visuals and screenshots that can now be described as a "game":
As for studies, I looked ahead to figure out the amount of items I need to study and found out that the rough average is 9 items per day. Phew! I definitely have a ways ahead of me. A lot of what I'm now studying is a bit of a retread in certain spots (C++ style casts, the difference between reference and pointer) but I did learn some interesting bits, including the reason why people lean towards prefixes instead of postfixes for incrementing and decrementing. The return then increment style of postfix requires an extra object to be made, which is not too bad for built in types. However, if the object is a large object iterator, prefixes are definitely recommended to increment then return, not requiring a temporary copy.
As for the work I'm doing on the prototype, the other facets of AI other than the controller are proving to be extra tricky. It's particularly archaic in how the Receive Tick as well as Receive Execute events even have C++ counterparts. I'll find it somehow.
The rewards weren't exactly implemented yet, so I pulled in a series of objects that would begin glowing and floating upon reception of an award. The rewards (and the amplitude/threshold ratios for the sky and pitch) are subscribers to the event handler (Observer Pattern!) that activate these derived classes of the subscribers when the events are fired.
Luckily this leads to actual visuals and screenshots that can now be described as a "game":
As for studies, I looked ahead to figure out the amount of items I need to study and found out that the rough average is 9 items per day. Phew! I definitely have a ways ahead of me. A lot of what I'm now studying is a bit of a retread in certain spots (C++ style casts, the difference between reference and pointer) but I did learn some interesting bits, including the reason why people lean towards prefixes instead of postfixes for incrementing and decrementing. The return then increment style of postfix requires an extra object to be made, which is not too bad for built in types. However, if the object is a large object iterator, prefixes are definitely recommended to increment then return, not requiring a temporary copy.
As for the work I'm doing on the prototype, the other facets of AI other than the controller are proving to be extra tricky. It's particularly archaic in how the Receive Tick as well as Receive Execute events even have C++ counterparts. I'll find it somehow.
Subscribing For More Rewards
Phew! Finally made some progress on the EEG programming. Looks like a specific event is responsible for handling events by way of lambda expressions from commands sent through JSON. For the update events, I'll be specifically looking at amplitude and threshold events that are subscribed to by my applications via an Observer pattern.
C++ transforming the AI in my prototype is in the works! I'm still not sure how Event Receive Execute translates in C++, so I focused primarily on the AI controller and how to get an OnPossess Event going like in Blueprints. Looks as if the Possess() function can operate as an OnPossessEvent in itself.
I have also finished with Effective C++! Now onto More Effective C++, though I'm not sure if it was intentional to start with something so basic as "learn the difference between pointers and references". It shall ramp up eventually!
C++ transforming the AI in my prototype is in the works! I'm still not sure how Event Receive Execute translates in C++, so I focused primarily on the AI controller and how to get an OnPossess Event going like in Blueprints. Looks as if the Possess() function can operate as an OnPossessEvent in itself.
I have also finished with Effective C++! Now onto More Effective C++, though I'm not sure if it was intentional to start with something so basic as "learn the difference between pointers and references". It shall ramp up eventually!
Tuesday, December 15, 2015
All New Way of Making New
Today marked part two of my quest to document all of my prototype code! Don't forget to mark all your functions and data members with proper comments, kids!
Today was also mainly a day off, but I managed a few lessons in, one of which had me really interested!
Step 1: Member functions can have their own templates, including pesky constructor templates - however, when declaring the general function, the compiler will still try to make one in the case of copy constructor/assignment, so make sure to make normal "dummy" versions.
Step 2: When supporting implicit type conversions in templates (operator*, for example), be sure to use non-member functions. In this entire book I'm reading, the author never once recommends friend functions, but they steal the spotlight here.
Step 3: Trait classes help provide info about a class during compilation. Heck, with overloading functions based on it as a type, it can even do if-elses during compilation!
Step 4: Template metaprogramming is a strange beast (using enums to recursively calculate data for loops?!) but if I dare look into it, the possibilities of policy-based programming (combining independent behaviors) for generative applications are interesting, if not compile-time intensive (but hey! The more you put in the compiler, the less you have to worry about it during run-time!)
Step 5: It's possible to use set_new_handler to provide your own error function during errors regarding new - heck, you can even override and put in the old nothrow (return null) example from 1993!
All this is still a barrage of info that I may not be applying to game programming anytime soon, but it all provides me with quite the arsenal to proceed.
Today was also mainly a day off, but I managed a few lessons in, one of which had me really interested!
Step 1: Member functions can have their own templates, including pesky constructor templates - however, when declaring the general function, the compiler will still try to make one in the case of copy constructor/assignment, so make sure to make normal "dummy" versions.
Step 2: When supporting implicit type conversions in templates (operator*, for example), be sure to use non-member functions. In this entire book I'm reading, the author never once recommends friend functions, but they steal the spotlight here.
Step 3: Trait classes help provide info about a class during compilation. Heck, with overloading functions based on it as a type, it can even do if-elses during compilation!
Step 4: Template metaprogramming is a strange beast (using enums to recursively calculate data for loops?!) but if I dare look into it, the possibilities of policy-based programming (combining independent behaviors) for generative applications are interesting, if not compile-time intensive (but hey! The more you put in the compiler, the less you have to worry about it during run-time!)
Step 5: It's possible to use set_new_handler to provide your own error function during errors regarding new - heck, you can even override and put in the old nothrow (return null) example from 1993!
All this is still a barrage of info that I may not be applying to game programming anytime soon, but it all provides me with quite the arsenal to proceed.
Monday, December 14, 2015
In Which Documenting in Hindsight is Probably Important
Today was a big(ish) meeting for the capstone group. Namely, it gives me a little more to do, as I need to document my code a little bit. Ideally we'll be setting up an actual wiki for documentation, but I figured it'd be necessary to note and document data members and function prototypes.
I'm also in the midst of figuring out the translation from Blueprints to C++ in AI navigation, but I'm a little confused as to what "Event Receive Execute" (when an event is executed in a task) translates to in C++. I'll experiment with it tomorrow.
I also did a little bit of pitch-based programming to prepare for (when I actually know how to interpret the EEG data). The data is best represented as a ratio of signal versus threshold, so I represented that signal as a pitch on a soothing sound of ocean waves.
I also learned some more things in studying C++, including the fun of learning a bit how templates work.
Step 1: Private inheritance is good, but denotes more of a "has-a" relationship of composition, in which the inheritor only has access to some bits, as opposed to the publicly inheriting "is-a" relationship.
Step 2: Multiple inheritance is tricky, as virtual base classes may be necessary to prevent replication of base class data. That said, the same thing can probably be done with singular inheritance anyways.
Step 3: Templates imply an interface and do compile-time inherited objects in the case of !=, >, and other such operators that produce a family of related functions around logically valid statements.
Step 4: Use the "typename" command for nested dependent type names (T::iterator, for example) but make sure to keep it out of base class identifiers.
Step 5: How does one access names in template base classes? Using directives and accessing the base class via this-> usually does the trick.
Step 6: Template code usually depends on a parameter - keep the non-template parameters out of the typename specifier and create separate functions to reduce unneeded replication
Whew! What a day - I do enjoy balancing a bunch of different tasks though!
I'm also in the midst of figuring out the translation from Blueprints to C++ in AI navigation, but I'm a little confused as to what "Event Receive Execute" (when an event is executed in a task) translates to in C++. I'll experiment with it tomorrow.
I also did a little bit of pitch-based programming to prepare for (when I actually know how to interpret the EEG data). The data is best represented as a ratio of signal versus threshold, so I represented that signal as a pitch on a soothing sound of ocean waves.
I also learned some more things in studying C++, including the fun of learning a bit how templates work.
Step 1: Private inheritance is good, but denotes more of a "has-a" relationship of composition, in which the inheritor only has access to some bits, as opposed to the publicly inheriting "is-a" relationship.
Step 2: Multiple inheritance is tricky, as virtual base classes may be necessary to prevent replication of base class data. That said, the same thing can probably be done with singular inheritance anyways.
Step 3: Templates imply an interface and do compile-time inherited objects in the case of !=, >, and other such operators that produce a family of related functions around logically valid statements.
Step 4: Use the "typename" command for nested dependent type names (T::iterator, for example) but make sure to keep it out of base class identifiers.
Step 5: How does one access names in template base classes? Using directives and accessing the base class via this-> usually does the trick.
Step 6: Template code usually depends on a parameter - keep the non-template parameters out of the typename specifier and create separate functions to reduce unneeded replication
Whew! What a day - I do enjoy balancing a bunch of different tasks though!
Sunday, December 13, 2015
Need Me Some Rosetta JSON
Today was yet another day without knowing what the JSON data was or how to access it, so I went back to the studying drawing board for today.
Step 1: Try to use includes as little as possible. Separate definition from declaration and use forward declarations.
Step 2: Public inheritance is a "is-a" model. Don't have objects inherit unless they are specifically types of their base class.
Step 3: With that, avoid hiding inherited names (use using declarations to get ahold of functions or even inline functions in the case of private inheritance)
Step 4: Interface and Implementation inheritance? Pure virtual is interface only, virtual is interface and a default implementation, and non-virtual is a mandatory implementation.
Step 5: Instead of virtual functions, try a strategy pattern using tr1::function, function pointers, or even a separate object, but note the lack of access to private members.
Step 6: NEVER redefine an inherited non-virtual function - it gives strange behavior and masks the original.
Step 7: NEVER redefine a function's inherited default parameters. Try non-virtual functions with default parameters that contain virtual functions if that is the case.
Step 8: Composition is the "has-a" equivalent in object oriented programming. If a set isn't a list due to unique objects, put a list in the set for specific, non "is-a" behavior while keeping list functionality.
More steps tomorrow!
Step 1: Try to use includes as little as possible. Separate definition from declaration and use forward declarations.
Step 2: Public inheritance is a "is-a" model. Don't have objects inherit unless they are specifically types of their base class.
Step 3: With that, avoid hiding inherited names (use using declarations to get ahold of functions or even inline functions in the case of private inheritance)
Step 4: Interface and Implementation inheritance? Pure virtual is interface only, virtual is interface and a default implementation, and non-virtual is a mandatory implementation.
Step 5: Instead of virtual functions, try a strategy pattern using tr1::function, function pointers, or even a separate object, but note the lack of access to private members.
Step 6: NEVER redefine an inherited non-virtual function - it gives strange behavior and masks the original.
Step 7: NEVER redefine a function's inherited default parameters. Try non-virtual functions with default parameters that contain virtual functions if that is the case.
Step 8: Composition is the "has-a" equivalent in object oriented programming. If a set isn't a list due to unique objects, put a list in the set for specific, non "is-a" behavior while keeping list functionality.
More steps tomorrow!
Saturday, December 12, 2015
Praise Be The New Cast
Today's studying day focused primarily on various implementation choices and how they affect performance and that exception safety that usually destroys most C++ programs.
Step 1: Like a lazily instantiated Singleton, if an exception is going to stop your code before you can use a variable, define it after the problem section for a little optimization.
Step 2: It's preferential to stick with casting (of the hot, new, and not-C-like C++ cast!). Whether it be the casting away of constness (const_cast), determining an object in an inheritance hierarchy (dynamic_cast, but due to the cost of calling 4-5 strcmps if the level is deep enough, save a smart pointer to derived classes or use a virtual function for access), unportable casting (pointer to int? Well, there's reinterpret_cast...) and implicit conversion forcing (static_cast). Despite the costliness of dynamic_cast, the C++ casts are simpler to identify and are definitely preferred. Praise be.
Step 3: Avoid returning things like pointers that may be const and protected from being changed, but that reaaaally private data member can be accessed from the const reference.
Step 4: Exceptions are bad. Either don't throw one, or ensure that if an exception is thrown, the data remains in a valid or otherwise unchanged state. A neat way to do this (cost aside) is the copy and swap method, in which a copy of data is made and changes are applied to it. If the exception is thrown, the copy is ditched and the original is clean. Else, swap it!
Step 5: Inlines can be very useful, especially in templates. Both are in header files, so it makes sense to combine the two wherever appropriate? Nope. If one has to change implementation on inlines, that requires recompilation (instead of relinking or even swapping dll files). Best off if the function is short, frequently used, and trivial enough to not require extra implementation changes down the road.
As for the EEG software that I've been working with, I finally found where the Unity file is so I can change files! Oddly enough, everything was lowercase so nothing worked (Unity being all case-sensitive about its classes matching its files) so I worked through that and no errors are found. Now I just have a pile of JSON gobblegook that I can't read, so I'll have to speak to the person in charge.
Step 1: Like a lazily instantiated Singleton, if an exception is going to stop your code before you can use a variable, define it after the problem section for a little optimization.
Step 2: It's preferential to stick with casting (of the hot, new, and not-C-like C++ cast!). Whether it be the casting away of constness (const_cast), determining an object in an inheritance hierarchy (dynamic_cast, but due to the cost of calling 4-5 strcmps if the level is deep enough, save a smart pointer to derived classes or use a virtual function for access), unportable casting (pointer to int? Well, there's reinterpret_cast...) and implicit conversion forcing (static_cast). Despite the costliness of dynamic_cast, the C++ casts are simpler to identify and are definitely preferred. Praise be.
Step 3: Avoid returning things like pointers that may be const and protected from being changed, but that reaaaally private data member can be accessed from the const reference.
Step 4: Exceptions are bad. Either don't throw one, or ensure that if an exception is thrown, the data remains in a valid or otherwise unchanged state. A neat way to do this (cost aside) is the copy and swap method, in which a copy of data is made and changes are applied to it. If the exception is thrown, the copy is ditched and the original is clean. Else, swap it!
Step 5: Inlines can be very useful, especially in templates. Both are in header files, so it makes sense to combine the two wherever appropriate? Nope. If one has to change implementation on inlines, that requires recompilation (instead of relinking or even swapping dll files). Best off if the function is short, frequently used, and trivial enough to not require extra implementation changes down the road.
As for the EEG software that I've been working with, I finally found where the Unity file is so I can change files! Oddly enough, everything was lowercase so nothing worked (Unity being all case-sensitive about its classes matching its files) so I worked through that and no errors are found. Now I just have a pile of JSON gobblegook that I can't read, so I'll have to speak to the person in charge.
Friday, December 11, 2015
Because a Red Sky is Too Boring
Today was the beginning of what would be my dual pronged effort during winter break; to manage EEG reading applications on Unity and study more effective C++.
For the EEG readings, I mainly familiarized myself with the information. Unfortunately, the readings seem to be in large blocks of text instead of anything specifically corresponding to positive/negative readings, and the reward system seems not to be reading either. I've gotten the procedural skybox to change color on command, so the visuals seem to be all set for the upcoming data.
As for Effective c++ learning, I've learned to store resource allocation in standalone statements (since we can't trust the order that compilers will work them out) and went through some vague atrocity regarding interface design. Passing by constant reference instead of value definitely helps, especially with the hidden overhead involving copying data. However, especially with the tricky nature of deleting local objects, it was best to return a value. I also thought through the section on the importance of private members, and have always felt off regarding encapsulation only as a means to hide data. (So many times when I wish I would access data but can't) Instead, encapsulation involves the ability to update an implementation (a function) across an entire project, and can put more in a get/set than just getting and setting.
Privatizing data is OK (and actually fairly annoying from a client standpoint), but I can see where encapsulation is a lot more than privatizing data.
For the EEG readings, I mainly familiarized myself with the information. Unfortunately, the readings seem to be in large blocks of text instead of anything specifically corresponding to positive/negative readings, and the reward system seems not to be reading either. I've gotten the procedural skybox to change color on command, so the visuals seem to be all set for the upcoming data.
As for Effective c++ learning, I've learned to store resource allocation in standalone statements (since we can't trust the order that compilers will work them out) and went through some vague atrocity regarding interface design. Passing by constant reference instead of value definitely helps, especially with the hidden overhead involving copying data. However, especially with the tricky nature of deleting local objects, it was best to return a value. I also thought through the section on the importance of private members, and have always felt off regarding encapsulation only as a means to hide data. (So many times when I wish I would access data but can't) Instead, encapsulation involves the ability to update an implementation (a function) across an entire project, and can put more in a get/set than just getting and setting.
Privatizing data is OK (and actually fairly annoying from a client standpoint), but I can see where encapsulation is a lot more than privatizing data.
Wednesday, December 9, 2015
Effectively Studying
Today (and yesterday, nothing like forgetting a post!) marks the first day of winter break for me! I mean, I did have some quick things I had to fix up regarding our capstone demo (two-sided gravity bubble meshes and a post-processing effect that appeared whenever the camera was in range), but I can be definitely sure that I don't have to worry about it.
What I can worry about now is studying for next semester! I'm currently traveling my way through the tomes of Scott Meyers and am learning plenty along the way that may sound simple, but can foolproof C++ code to suitable levels. This mainly seems like a link between the tenets of game design patterns but also extends C++ specific terminology. I'm not the biggest fan of the way the work is presented (must read the entire book before fully understanding Chapter 1) but it's the best I've got.
Got a problem with #defines? Use consts, and make sure you stick to conceptual constness with the help of mutables! Got a problem with protecting the address of constants? Use an enum instead! Make sure to initialize objects before they're used (member constructors) and know when to cheat by privately declaring functions in a base class so the C++ compiler won't try to generate faulty stand-ins! That's some of the stuff I have so far. We'll not have too much in the way of screenshots for now, so hopefully the written word is just as satisfying.
What I can worry about now is studying for next semester! I'm currently traveling my way through the tomes of Scott Meyers and am learning plenty along the way that may sound simple, but can foolproof C++ code to suitable levels. This mainly seems like a link between the tenets of game design patterns but also extends C++ specific terminology. I'm not the biggest fan of the way the work is presented (must read the entire book before fully understanding Chapter 1) but it's the best I've got.
Got a problem with #defines? Use consts, and make sure you stick to conceptual constness with the help of mutables! Got a problem with protecting the address of constants? Use an enum instead! Make sure to initialize objects before they're used (member constructors) and know when to cheat by privately declaring functions in a base class so the C++ compiler won't try to generate faulty stand-ins! That's some of the stuff I have so far. We'll not have too much in the way of screenshots for now, so hopefully the written word is just as satisfying.
Monday, December 7, 2015
Day 106: The Last Day...For Now
Today is the final day before my work is done with the capstone prototype. (That, and the rest of the semester but there's a final exam coming tomorrow soooo)
Today was mainly a day to put in bug fixes. The gravity well, when attached to the insects tended to exert force on its parent objects despite being attached, so I decided to give the gravity wells a reference to their attached actors to make it detectable in both C++ and blueprints.
The little guys also had a tendency to run into each other, but I found out that Unreal Engine 4 fortunately uses an updated version of Recast (well well... we meet again) and had a controller for Detour crowding, so I updated the insect AI controllers.
As for tomorrow? Here's hoping for the best! I'll have to brainstorm on what I want to look into for my down time.
Oh yeah, forgot to mention that we emergently found the ability for two gravity wells to form a bridge of blocks with two counteracting forces. Neat!
Today was mainly a day to put in bug fixes. The gravity well, when attached to the insects tended to exert force on its parent objects despite being attached, so I decided to give the gravity wells a reference to their attached actors to make it detectable in both C++ and blueprints.
The little guys also had a tendency to run into each other, but I found out that Unreal Engine 4 fortunately uses an updated version of Recast (well well... we meet again) and had a controller for Detour crowding, so I updated the insect AI controllers.
As for tomorrow? Here's hoping for the best! I'll have to brainstorm on what I want to look into for my down time.
Oh yeah, forgot to mention that we emergently found the ability for two gravity wells to form a bridge of blocks with two counteracting forces. Neat!
Sunday, December 6, 2015
Day 105: Logical Corruptions and Wiggly Insect
Today was a day to start up polishing and thinking of any extra additions that we may need for the capstone pitch. In order to logically extend and help further the plot and mechanics, we came up with the idea for the opposite of a gravity well (a gravity geyser?). Essentially, it negatively reacts with the ley energy that forms a gravity well and uses repelling energy instead. I imposed some dark effects and negative tessellation for a nasty little piece:
As for the insect, we finally got a skeletal mesh in, which required me to make a couple of changes (remove the static mesh) that I'm still working the kinks out of. The main kink is getting a skeletal mesh to fly through the air properly:
I shall persist! When I am less tired. XP
As for the insect, we finally got a skeletal mesh in, which required me to make a couple of changes (remove the static mesh) that I'm still working the kinks out of. The main kink is getting a skeletal mesh to fly through the air properly:
I shall persist! When I am less tired. XP
Saturday, December 5, 2015
Day 104: No Longer Blocked By Blockage
Phew! The Xbox cross-platform project is finally through. After managing all the collision boxes (to follow the rules of DirectX's flipped y coordinates) and properly setting the fade value (0xFFFFFFFF was how colors are stored, with the most significant bits holding the alpha. Therefore, I couldn't just overflow the values by adding past 0xFF. Bit shifting helped fix that up rather nicely!
As for the extremely hard part, that involved working XACT audio in the sound. The playing sound part was straightforward once the sound bank was set up, but actually setting up the audio is the hard part. When setting up a project in XACT, one starts with a wave bank, which holds wave files. Wave files can be stored (one or more) as sounds in a sound bank, which also have cues to play those sounds. That all together, I also didn't know a very important aspect to our testing; the music media was loaded in the hard drive memory of the XDK, so the bank had to be setup as streaming from the hard drive instead of in-memory. After that? Well, things fell into place from there.
Now back to capstone, I was also surprised to see how much I had finished up once I tackled the LeyBlocker. That object had some odd logic attached to it, or that the actors I was assigning the laser block point to kept switching places with the next pedestal as a target point, causing a nasty flicker (which I assumed was bad line tracing). Now with that and adding in some art for the insect AI, things are slowly coming together:
As for the extremely hard part, that involved working XACT audio in the sound. The playing sound part was straightforward once the sound bank was set up, but actually setting up the audio is the hard part. When setting up a project in XACT, one starts with a wave bank, which holds wave files. Wave files can be stored (one or more) as sounds in a sound bank, which also have cues to play those sounds. That all together, I also didn't know a very important aspect to our testing; the music media was loaded in the hard drive memory of the XDK, so the bank had to be setup as streaming from the hard drive instead of in-memory. After that? Well, things fell into place from there.
Now back to capstone, I was also surprised to see how much I had finished up once I tackled the LeyBlocker. That object had some odd logic attached to it, or that the actors I was assigning the laser block point to kept switching places with the next pedestal as a target point, causing a nasty flicker (which I assumed was bad line tracing). Now with that and adding in some art for the insect AI, things are slowly coming together:
Friday, December 4, 2015
Day 103: Experiencing Quite the Blockage
Today's a day where I should be less tired when writing these blog posts. The Xbox project has the starting screen rendered (whew!) despite the flipped coordinates, but we're unsure whether that'll translate to movement and collision as well.
For the Unreal Engine project, I focused a little time on blocking objects for the ley lines; however, it's got me stumped. The ray trace (SingleLineTrace, MultiLineTrace, etc) is not functioning on specific frames; despite the fact that there's an object blocking the way, it flickers constantly to its original orientation. I'm wondering if this is the right solution...
For the Unreal Engine project, I focused a little time on blocking objects for the ley lines; however, it's got me stumped. The ray trace (SingleLineTrace, MultiLineTrace, etc) is not functioning on specific frames; despite the fact that there's an object blocking the way, it flickers constantly to its original orientation. I'm wondering if this is the right solution...
Thursday, December 3, 2015
Day 102: Ley Nodes From The Ground Up
Today was a pretty busy day; after some grueling work in #defining all the OpenGL code from Robotron, my partner and I finally figured out how wave files are stored in wave banks which are stored in sound banks. Fun stuff, that XACT audio.
As for the prototype work, I worked an endlessly moving object that can be slowed by time dilation. The interpolation of locations can get a bit slow when they get close enough, so I put in a minimum distance until it immediately switched to the next position for smoother movement:
After speaking with my producers, I also had to rework plenty of the nodes. Instead of always being connected, we've decided to set pedestals as snap-to locations for nodes, only updating their connections after attaching or detaching from the pedestal group. Thankfully, the use of forward declarations made keeping references of objects much simpler, as long as it came before the generated header:
What next? To be honest, this recent rework knocked most of my to-dos out of the ballpark. I think I'll focus plenty on the Xbox project now.
As for the prototype work, I worked an endlessly moving object that can be slowed by time dilation. The interpolation of locations can get a bit slow when they get close enough, so I put in a minimum distance until it immediately switched to the next position for smoother movement:
After speaking with my producers, I also had to rework plenty of the nodes. Instead of always being connected, we've decided to set pedestals as snap-to locations for nodes, only updating their connections after attaching or detaching from the pedestal group. Thankfully, the use of forward declarations made keeping references of objects much simpler, as long as it came before the generated header:
What next? To be honest, this recent rework knocked most of my to-dos out of the ballpark. I think I'll focus plenty on the Xbox project now.
Wednesday, December 2, 2015
Day 101: Weightless Ants in Space
Today was the final finishing touches on the feedback for Robotron. That start screen now includes the family members and player all showing off for a neat intro:
As for RPP work, today was an especially tricky day. The new character animation and mesh was finally in, so I had to connect all previous casting to a third person character to this new blueprint. Luckily enough, I updated the AI to now spawn and get distracted by said new character's arrows. This was a similar aggravation check with a lower priority and a higher radius to track down player projectiles:
The last trick with AI was ensuring weightlessness without interfering with the character control. What ended up was a complex set of disabling and re-enabling colliders that never got the ant mesh to appear in the right place. This required the dirty fix of respawning another ant in the exact same spot, but it works:
What next? Non-AI things. (Thank goodness)
As for RPP work, today was an especially tricky day. The new character animation and mesh was finally in, so I had to connect all previous casting to a third person character to this new blueprint. Luckily enough, I updated the AI to now spawn and get distracted by said new character's arrows. This was a similar aggravation check with a lower priority and a higher radius to track down player projectiles:
The last trick with AI was ensuring weightlessness without interfering with the character control. What ended up was a complex set of disabling and re-enabling colliders that never got the ant mesh to appear in the right place. This required the dirty fix of respawning another ant in the exact same spot, but it works:
What next? Non-AI things. (Thank goodness)
Tuesday, December 1, 2015
Day 100: Somethingtron 2084
Today was a big day to wrap up the basic PC build of Robotron and respond to feedback. Today, the feedback was relatively positive; we just need a start/game over screen, lives, a wave counter, a no-spawn rectangle, and an effect to begin the level in a non-abrupt fashion.
The tricky part came when we had to come up with a substitution effect for the scanline blast that was so prevalent in the predecessor. The arcade itself had a custom graphics processor that allowed the lines of a sprite to split apart in a dramatic fashion, but that would require an insane amount of overhead from us when the project (in Xbox form) is due in a week. What to do? A fade-in effect, employing the transparency that the original game lacked, helped us immensely.
There was little I did for capstone today, but firmly established that since MoveTo for locations is not functioning for my enemy character, using waypoint actors in lieu of locations is a much more intuitive and better scheme for proper patrolling.
The tricky part came when we had to come up with a substitution effect for the scanline blast that was so prevalent in the predecessor. The arcade itself had a custom graphics processor that allowed the lines of a sprite to split apart in a dramatic fashion, but that would require an insane amount of overhead from us when the project (in Xbox form) is due in a week. What to do? A fade-in effect, employing the transparency that the original game lacked, helped us immensely.
There was little I did for capstone today, but firmly established that since MoveTo for locations is not functioning for my enemy character, using waypoint actors in lieu of locations is a much more intuitive and better scheme for proper patrolling.
Subscribe to:
Posts (Atom)