<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Daniel</title>
    <description>The latest articles on DEV Community by Daniel (@danieltanfh95).</description>
    <link>https://dev.to/danieltanfh95</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F453368%2F2f9a75c9-3d0f-4748-abdf-db0cd1a4e1e7.jpeg</url>
      <title>DEV Community: Daniel</title>
      <link>https://dev.to/danieltanfh95</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/danieltanfh95"/>
    <language>en</language>
    <item>
      <title>Pragmatic Programming Understanding</title>
      <dc:creator>Daniel</dc:creator>
      <pubDate>Fri, 18 Sep 2020 10:28:33 +0000</pubDate>
      <link>https://dev.to/danieltanfh95/pragmatic-programming-understanding-2dm7</link>
      <guid>https://dev.to/danieltanfh95/pragmatic-programming-understanding-2dm7</guid>
      <description>&lt;p&gt;I’m taking a break from my usual articles to write something for beginners starting to program: Brief, simple explanations of various concepts and programming terms. These came from explaining some concepts to my friend who was completing a curriculum in computer science.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features vs Design vs Implementation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Features: What the program can do&lt;/li&gt;
&lt;li&gt;Implementation: How the program does it&lt;/li&gt;
&lt;li&gt;Design: Planning features and implementations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Programming paradigms
&lt;/h2&gt;

&lt;p&gt;In programming we have logic (how), and data (what). Do note that these paradigms can be mixed.&lt;/p&gt;

&lt;p&gt;Functional paradigm: It’s when you pass in data into logic, and have a new data as a result. E.g. Clojure.&lt;/p&gt;

&lt;p&gt;Object Oriented paradigm: It’s when you place logic in data, and data uses signals to communicate between each other on what logic to trigger. E.g. Ruby&lt;/p&gt;

&lt;p&gt;There are also paradigms that focus on what to control, the logical command or the logical result.&lt;/p&gt;

&lt;p&gt;Imperative paradigm: You make logical commands that describe logic to change your data. E.g. C.&lt;/p&gt;

&lt;p&gt;Declarative paradigm: You explain the final data result to program and it solves the commands to do it for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Types
&lt;/h2&gt;

&lt;p&gt;Untyped languages are like maths. You focus on getting the algorithms right. Here we use schemas to restrict the range of data that can be correct. E.g. square root, but following schema of positive integers. This includes Python and Ruby.&lt;/p&gt;

&lt;p&gt;Typed languages are like physics, you focus on getting the results right. Here types perform basic checking on intermixed values. For more complex checking to the level of schemas you need dependent types. This includes C and Haskell.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mutability
&lt;/h2&gt;

&lt;p&gt;Mutable means “can be changed. Immutability, the opposite, can prevent more human errors by making sure data can only be copied, but not changed. However, the trade off is that your program takes more space and is slower.&lt;/p&gt;

&lt;p&gt;On the other hand, programs using mutable data structures can be very fast and use less memory but programmers will make more mistakes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project management
&lt;/h2&gt;

&lt;p&gt;Scope: How much will you complete&lt;/p&gt;

&lt;p&gt;Resources: How much can you use (including human resources)&lt;/p&gt;

&lt;p&gt;Time: How long will you take&lt;/p&gt;

&lt;p&gt;This brings us to the development styles:&lt;/p&gt;

&lt;p&gt;Waterfall: Fixed scope, but flexible resources and time.&lt;/p&gt;

&lt;p&gt;Agile: Fixed resources and time but flexible scope.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spectrum of development
&lt;/h2&gt;

&lt;p&gt;All of these require algorithm and data structure knowledge.&lt;/p&gt;

&lt;p&gt;Front-end: User-facing application where you have less control over the environment. Can be web based, like HTML/JS/CSS, or native, like C++ or Java.&lt;/p&gt;

&lt;p&gt;Back-end: Non-user-facing application where you have more control over the environment. Any language can be a backend language.&lt;/p&gt;

&lt;p&gt;Infrastructure and Operations: Applications that host the front-end or back-end applications, and how to transfer the front-end application to the user etc&lt;/p&gt;

&lt;p&gt;Data engineering: Applications that gather and clean data for use in other applications like AI applications.&lt;/p&gt;

</description>
      <category>programming</category>
    </item>
    <item>
      <title>Awesome Unity3D: State Machines — Effective State Management</title>
      <dc:creator>Daniel</dc:creator>
      <pubDate>Thu, 27 Aug 2020 15:08:50 +0000</pubDate>
      <link>https://dev.to/danieltanfh95/awesome-unity3d-state-machines-effective-state-management-3gdm</link>
      <guid>https://dev.to/danieltanfh95/awesome-unity3d-state-machines-effective-state-management-3gdm</guid>
      <description>&lt;p&gt;This article assumes you know what are Finite State Machines (FSM). If not, I would recommend reading this article that &lt;a href="https://gameprogrammingpatterns.com/state.html"&gt;shows common pitfalls when writing code handling character state and why we use FSMs&lt;/a&gt;. If you prefer a "TL;DR", the gist is that without FSMs you need to use plenty of flags in your program, which can lead to many nested "if-else" statements everywhere, leading to a terrifying debugging experience. You do not want to waste your time in this self-made hell.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Example of self-made hell&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handleInput&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetKeyDown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KeyCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Space&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;isJumping&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isDucking&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Jump...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetKeyDown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KeyCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;isJumping&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;isDucking&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nf"&gt;setGraphics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IMAGE_DUCK&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetKeyUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KeyCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isDucking&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;isDucking&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nf"&gt;setGraphics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IMAGE_STAND&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;FSMs are the kind of pattern that most people I know have a love/hate relationship with. Love it for it's ability to encapsulate dynamic application state, hate it for additional complexity. Personally I did not enjoy using code-only FSMs since juggling state transitions can be quite a handful especially in games with complex interactions between units but including a GUI solution for FSM like Playmaker can be pretty heavy. &lt;/p&gt;

&lt;p&gt;On that note, what if there is a lightweight FSM system that we can use (or hijack) within Unity? &lt;/p&gt;

&lt;h2&gt;
  
  
  Using the &lt;code&gt;AnimationController&lt;/code&gt; as FSM
&lt;/h2&gt;

&lt;p&gt;Unity already contains a state machine for animations that we can use, with some modification.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UBCiz4M9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/696/0%2Axis_tqpYGqI2LuMJ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UBCiz4M9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/696/0%2Axis_tqpYGqI2LuMJ" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create an empty GameObject in the scene with an Animator attached.&lt;/li&gt;
&lt;li&gt;Create a new AnimatorController asset somewhere in your project folder. Attach this to the Animator you've created.&lt;/li&gt;
&lt;li&gt;Open Window→Animator→Parameters and create a trigger called "Next".&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j6ayyQ9g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/0%2Ag-wsnFt3ztW-8wU-" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j6ayyQ9g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/0%2Ag-wsnFt3ztW-8wU-" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Customization
&lt;/h3&gt;

&lt;p&gt;Create a class that inherits  &lt;code&gt;StateMachineBehaviour&lt;/code&gt; so we can create custom states, provide a cleaner interface for the state machine, and enable debugging. We can call our custom class &lt;code&gt;LogicalStateMachine&lt;/code&gt; . &lt;code&gt;StateMachineBehaviour&lt;/code&gt; already provides methods such as &lt;code&gt;OnStateEnter&lt;/code&gt; , &lt;code&gt;OnStateUpdate&lt;/code&gt; , &lt;code&gt;OnStateExit&lt;/code&gt; , which we can use to provide interfaces such as these.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnLogicalStateEnter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GameObject&lt;/span&gt; &lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnLogicalStateUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GameObject&lt;/span&gt; &lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnLogicalStateExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GameObject&lt;/span&gt; &lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ResetState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GameObject&lt;/span&gt; &lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnStateEnter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Animator&lt;/span&gt; &lt;span class="n"&gt;animator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AnimatorStateInfo&lt;/span&gt; &lt;span class="n"&gt;stateInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;layerIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;ResetState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ActiveAnimator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;OnLogicalStateEnter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ActiveAnimator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnStateUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Animator&lt;/span&gt; &lt;span class="n"&gt;animator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AnimatorStateInfo&lt;/span&gt; &lt;span class="n"&gt;stateInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;layerIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;OnLogicalStateUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ActiveAnimator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnStateExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Animator&lt;/span&gt; &lt;span class="n"&gt;animator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AnimatorStateInfo&lt;/span&gt; &lt;span class="n"&gt;stateInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;layerIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;OnLogicalStateExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ActiveAnimator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To make it easier to debug, we'll use the trigger we've created before to create a &lt;code&gt;Continue&lt;/code&gt; method that can force the next state to occur.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="n"&gt;Animator&lt;/span&gt; &lt;span class="n"&gt;ActiveAnimator&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Continue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;ActiveAnimator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ActiveAnimator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Animator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StringToHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnStateEnter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Animator&lt;/span&gt; &lt;span class="n"&gt;animator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AnimatorStateInfo&lt;/span&gt; &lt;span class="n"&gt;stateInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;layerIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ActiveAnimator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;animator&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;ResetState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ActiveAnimator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;ActiveAnimator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ResetTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Animator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StringToHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="nf"&gt;OnLogicalStateEnter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ActiveAnimator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can make this even better by creating an Inspector Button for it in the editor. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3C292SFz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1388/0%2ANzNajE5m_SJyIjdo" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3C292SFz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1388/0%2ANzNajE5m_SJyIjdo" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Personally I just use the Odin Inspector to create one but if you'd prefer a native solution there's one &lt;a href="https://raw.githubusercontent.com/zaikman/UnityPublic/master/InspectorButton.cs"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Voila! A simple state machine you can use in your project. You can find the code here as well: &lt;a href="https://gitlab.com/glassblade/unityfsm"&gt;https://gitlab.com/glassblade/unityfsm&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Effective State Management in Games
&lt;/h2&gt;

&lt;p&gt;This advice applies to most complex applications, but game is a good example. Games typically contain two types of state : persistent state and dynamic state. For example, in the game, "Enter the Gungeon", the persistent state would contain the unlocked pool of guns, while the dynamic state would contain the gun picked up by the player.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iGPiXHMm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/0%2AwyZvd2vCDP2GevEo" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iGPiXHMm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/0%2AwyZvd2vCDP2GevEo" alt="Enter the Gungeon gameplay"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;FSMs contain two basic components, state and transitions and I would recommend the following to make it easier to debug your state in FSM:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If you need to use a flag, don't. Use a state instead.&lt;/li&gt;
&lt;li&gt;Spending some time before you code to identify what would be persistent state and dynamic state in your game relative to the FSM. Dynamic state should be reset each time you enter a state while persistent state will not.&lt;/li&gt;
&lt;li&gt;Make an immutable copy of your persistent state on entering a state, only set persistent state on exiting a state. You can optimize this later on, but it makes it alot easier for debugging points of error.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>unity3d</category>
    </item>
    <item>
      <title>Pragmatic K8s Understanding</title>
      <dc:creator>Daniel</dc:creator>
      <pubDate>Sun, 16 Aug 2020 03:19:50 +0000</pubDate>
      <link>https://dev.to/danieltanfh95/pragmatic-k8s-understanding-fm1</link>
      <guid>https://dev.to/danieltanfh95/pragmatic-k8s-understanding-fm1</guid>
      <description>&lt;p&gt;This article simplifies k8s as a magical tool to simplify deployment. By the end of the article you should have enough basic knowledge to discuss k8s with others, and to use it as well.&lt;/p&gt;

&lt;p&gt;This article is also part of a Machine Learning Ops (MLOps) series.&lt;/p&gt;

&lt;p&gt;But before we start, an image describing the experience of learning k8s right now in spite of the resources widely available in the web, which prompted me to write an article that follows the &lt;a href="https://en.wikipedia.org/wiki/KISS_principle"&gt;KISS principle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IR_xuEOf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.redd.it/3pdbnh698pu41.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IR_xuEOf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.redd.it/3pdbnh698pu41.jpg" alt="https://i.redd.it/3pdbnh698pu41.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Why kubernetes (k8s)?
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UIeoJKvh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/0%2Amcn_dC3qSZ5mkFX7" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UIeoJKvh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/0%2Amcn_dC3qSZ5mkFX7" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember when during development you only have one machine to deploy with, and you're asked to scale your application without much budget? Naturally. you set up a load balancer and create two instances with different ports to handle the extra load. Later on, you're given more computers, and you do the same thing on those computers as well. This becomes a tedious task as more and more computers are required, and it's still not an easy task even with tools like Ansible.&lt;/p&gt;

&lt;p&gt;What k8s does is automating away all of this, so most of the times after you set up k8s, all you need to do is register your new computer with labels of apps that are allowed on it, and k8s takes care of the rest. On a single computer, it handles load balancing and ports automatically for your applications when scaling up, all without bundles of bash/Ansible scripts, which brings us to the next great feature of k8s.&lt;/p&gt;

&lt;p&gt;Writing k8s configuration files are pretty much like writing SQL code whereas tools like Ansible are similar to writing Python code. You just describe what you want, and k8s finds the best way to do it. Since the config are just YAML files, you can keep it with your repository as well. Updating the deployment is as easy as updating the configuration files and applying it to the cluster.&lt;/p&gt;

&lt;p&gt;This means you can bring your application to multiple different clusters in different environment and expect more or less similar behaviour, which makes it very attractive for a lot of companies.&lt;/p&gt;

&lt;p&gt;However, k8s requires containers to do its magic, so before I proceed to provide a simple guide to k8s, I have to explain containers.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why containers?
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HU_GZz2L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/850/0%2AQXZveqr1zRs5Zo1Z" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HU_GZz2L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/850/0%2AQXZveqr1zRs5Zo1Z" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nuff' said.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Actual Guide
&lt;/h1&gt;

&lt;h2&gt;
  
  
  K8s terms translator
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Node: Computer that is not a container.&lt;/li&gt;
&lt;li&gt;Cluster: Group of nodes.&lt;/li&gt;
&lt;li&gt;Control plane: Node that controls other nodes.&lt;/li&gt;
&lt;li&gt;Persistent Volumes: A description of what storage is available.&lt;/li&gt;
&lt;li&gt;Persistent Volume Claims: A description of what storage you need.&lt;/li&gt;
&lt;li&gt;Pods: A description for how containers are run and how they use persistent volumes.&lt;/li&gt;
&lt;li&gt;Deployment: A group of pods.&lt;/li&gt;
&lt;li&gt;Service: A description for how deployments communicate through the internet.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Using k8s
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://minikube.sigs.k8s.io/docs/start/"&gt;Minikube&lt;/a&gt; has, by far, the easiest way to start with k8s on a single computer. &lt;/li&gt;
&lt;li&gt;Otherwise, the second easiest is to get one from Azure, AWS or GKE.&lt;/li&gt;
&lt;li&gt;Finally it would be setting up a cluster manually using kops, kubeadm or kubespray. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  K8s essentials for developers
&lt;/h2&gt;

&lt;p&gt;There's really four basic concepts you need to know before using k8s: containers, persistent storage, deployments, services.&lt;/p&gt;

&lt;p&gt;We'll use Nginx for this example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Containers (Docker)
&lt;/h3&gt;

&lt;p&gt;You'll have to be able to create a docker image. I wrote an article on how to &lt;a href="https://medium.com/glassblade/strategies-for-reducing-docker-image-size-with-python-flask-feef86a63349?source=your_stories_page---------------------------"&gt;reduce docker container size&lt;/a&gt; that would be useful as well, which also contains a sample docker file used to build the image.&lt;/p&gt;

&lt;p&gt;Do note that containers can be restarted or destroyed often, for example when your container crashes k8s will automatically restart it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Persistent Storage
&lt;/h3&gt;

&lt;p&gt;The easiest to start with local data, but there are &lt;a href="https://kubernetes.io/docs/concepts/storage/storage-classes/"&gt;many other types as well&lt;/a&gt;. This type of storage will not be destroyed when the container is destroyed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PersistentVolume&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-pv&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;local&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;storageClassName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;manual&lt;/span&gt;
  &lt;span class="na"&gt;capacity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10Gi&lt;/span&gt;
  &lt;span class="na"&gt;accessModes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ReadWriteMany&lt;/span&gt;
  &lt;span class="na"&gt;hostPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/var/lib/path-in-node"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;A persistent volume only describe what storage is available, it does not actually allocate the storage or block it off. &lt;/p&gt;

&lt;p&gt;You can use access modes to describe the behaviour of pods when dealing with this storage (i.e. mounting). &lt;em&gt;This is irrespective of the actual file system&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;There are three modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ReadWriteOnce : the volume can be mounted as read-write by a single node&lt;/li&gt;
&lt;li&gt;ReadOnlyMany : the volume can be mounted read-only by many nodes&lt;/li&gt;
&lt;li&gt;ReadWriteMany : the volume can be mounted as read-write by many nodes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Deployments
&lt;/h3&gt;

&lt;p&gt;This describes an actual "application". It uses containers and persistent storage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-deployment&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-vol&lt;/span&gt;
        &lt;span class="na"&gt;persistentVolumeClaim&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;claimName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-pvc&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:latest&lt;/span&gt;
        &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-vol&lt;/span&gt;
          &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/lib/path-in-nginx-container&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As noted, you can start with multiple replicas of your application. The deployment will create multiple copies of your pods using the template. &lt;/p&gt;

&lt;h3&gt;
  
  
  Services
&lt;/h3&gt;

&lt;p&gt;You can expose your app to the internet using services. You can choose a load balancer between multiple nodes or just use a port on a node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-service&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;nodePort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30080&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NodePort&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The service automatically load balances between pods created by a deployment.&lt;/p&gt;

&lt;p&gt;The service selects deployment based on the app label specified in the deployment (i.e. the selector). &lt;/p&gt;

&lt;p&gt;Services, by default are only allowed to use ports 30000-32767. You can use another reverse proxy or ingress to do port forwarding, common options are Nginx and HAProxy.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;And that's basically most of what you need to actually be productive in k8s.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>containers</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
