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?
Subscribe to:
Posts (Atom)