{"id":633,"date":"2023-07-07T17:13:00","date_gmt":"2023-07-07T17:13:00","guid":{"rendered":"https:\/\/codewithpiri.com\/?p=633"},"modified":"2023-07-08T20:51:59","modified_gmt":"2023-07-08T20:51:59","slug":"code-practicelets-see-how-to-setup-timers-in-networking-games","status":"publish","type":"post","link":"https:\/\/codewithpiri.com\/index.php\/2023\/07\/07\/code-practicelets-see-how-to-setup-timers-in-networking-games\/","title":{"rendered":"Code Practice(Let`s see how to setup timers in networking games)"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"633\" class=\"elementor elementor-633\" data-elementor-post-type=\"post\">\n\t\t\t\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-8443789 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"8443789\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-3f63fddb\" data-id=\"3f63fddb\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-element elementor-element-3d63a930 elementor-widget elementor-widget-text-editor\" data-id=\"3d63a930\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<style>\/*! elementor - v3.14.0 - 26-06-2023 *\/\n.elementor-widget-text-editor.elementor-drop-cap-view-stacked .elementor-drop-cap{background-color:#69727d;color:#fff}.elementor-widget-text-editor.elementor-drop-cap-view-framed .elementor-drop-cap{color:#69727d;border:3px solid;background-color:transparent}.elementor-widget-text-editor:not(.elementor-drop-cap-view-default) .elementor-drop-cap{margin-top:8px}.elementor-widget-text-editor:not(.elementor-drop-cap-view-default) .elementor-drop-cap-letter{width:1em;height:1em}.elementor-widget-text-editor .elementor-drop-cap{float:left;text-align:center;line-height:1;font-size:50px}.elementor-widget-text-editor .elementor-drop-cap-letter{display:inline-block}<\/style>\t\t\t\t<h4><span style=\"font-family: var(--fontFamily); font-size: var(--fontSize); font-style: var(--fontStyle, inherit); font-weight: var(--fontWeight); letter-spacing: var(--letterSpacing); text-transform: var(--textTransform); color: var(--color); text-align: inherit;\">Let`s discuss how to setup timers in network based games and what are the challenges. Lastly we will inspect my ChangeTurn method together!<\/span><\/h4><p>\u00a0<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1494f83 elementor-widget elementor-widget-text-editor\" data-id=\"1494f83\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>Title: Mastering Network-Based Timers in Unity: A Deep Dive into High-Performance Solutions<\/p><p>Introduction: Timers are a fundamental part of game development, enabling developers to schedule events, control gameplay mechanics, and manage various game systems. However, when it comes to network-based timers in Unity, additional challenges arise. In this blog post, we&#8217;ll explore the intricacies of network-based timers and discuss professional concepts and code examples to overcome these challenges effectively.<\/p><p>Understanding Network-Based Timers: Network-based timers are essential for synchronizing game events across multiple networked players or clients. They ensure that specific actions occur simultaneously for all players, preserving the integrity of the game state.<\/p><p><strong>C<\/strong><b>hallenge 1:<\/b> Network Latency: The first challenge in network-based timers stems from network latency, which can introduce inconsistencies in the timing of events between clients.<\/p><p>we start the timer on the server and notify all clients using the <code>[ClientRpc]<\/code> attribute. Each client starts their local timer using <code>StartCoroutine<\/code>, but network latency can cause variations in the countdown duration, resulting in inconsistent timer finishes.<\/p><p><strong>Fi<\/strong><b>x 1<\/b>: Server Authority and Synchronization: To overcome network latency challenges, it&#8217;s crucial to maintain server authority over timers.<\/p><p><strong>Challenge 2:<\/strong> Timer Drift: Another challenge with network-based timers is timer drift, which occurs when the timer on one client falls out of sync with other clients due to variations in frame rates, network hiccups, or processing delays.<\/p><p><strong>Fix 2:<\/strong> Time Synchronization: To address timer drift, we needto synchronize time across all clients. Here&#8217;s an example a code that includes time synchronization:<\/p><p>\u00a0<\/p><p>But let`s see if we wanted to do a simpler turn change what could it look like:<\/p><h4><strong>Explanation of the method:<\/strong><\/h4><p>First of all we determine if the change of turn happens by the timer or we are forcing turn change in case we want to add penalty to the want who misses his turns or stays idle for the timer to pass.<\/p><p>The same approach has been implemented in GodsUnchanged Timer code in which making no moves will add some penalty to you and your timer will decrease faster.<\/p><p>Since the character skills which are some async methods take some time we wait for those animations to finish and the animaitons will fire an event on their completion.<\/p><p><strong>Trust me on this:<\/strong><\/p><p>Firing events of animations utilising the signal invokation of timelines in unity is much simpler approach for even complex skill setup of characters.<\/p><p>We have many pools that could affect the gameplay like being stunned(isses the turn) or bleeding or being poisoned,&#8230; which take time so we should process pool effects before changing the turns and nothing is much sweet setup that utilising Reflection\u00a0 for our abstract skill\u00a0 pool types.<\/p><p>As you can see we go through each pool for the characters that could be in.<\/p><p>THen we decide to forgive the player`s penalty by rewarding them for their appropriate behaviour!<\/p><p>So we reduce their timer speed and then change the turn and toggle the events and do some UI stuff.<\/p><p>Remember all we discussed before about netowrking parts can be integrated easily to this method.<\/p><p>I hope you enjoyed this post.<\/p><p>Feel free to ask me if anything occludes your minds.<\/p><p>Happy Coding!<\/p><p>\u00a0<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1c646bd elementor-widget elementor-widget-code-highlight\" data-id=\"1c646bd\" data-element_type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-csharp line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-csharp\">\n\t\t\t\t\t<xmp>using System;\r\nusing UnityEngine;\r\nusing UnityEngine.Networking;\r\n\r\npublic class NetworkedTimer : NetworkBehaviour\r\n{\r\n    [SerializeField]\r\n    private float timerDuration = 5.0f;\r\n\r\n    private float timerCountdown;\r\n    private float serverStartTime;\r\n\r\n    private event Action TimerFinished;\r\n\r\n    private void Start()\r\n    {\r\n        if (isServer)\r\n        {\r\n            StartServerTimer();\r\n        }\r\n        else\r\n        {\r\n            CmdStartTimer(timerDuration);\r\n        }\r\n    }\r\n\r\n    [Command]\r\n    private void CmdStartTimer(float duration)\r\n    {\r\n        RpcStartTimer(duration);\r\n    }\r\n\r\n    [ClientRpc]\r\n    private void RpcStartTimer(float duration)\r\n    {\r\n        if (isLocalPlayer)\r\n        {\r\n            StartClientTimer(duration);\r\n        }\r\n    }\r\n\r\n    private void StartServerTimer()\r\n    {\r\n        serverStartTime = Time.time;\r\n        RpcStartTimer(timerDuration);\r\n    }\r\n\r\n    private void StartClientTimer(float duration)\r\n    {\r\n        timerCountdown = duration - (Time.time - serverStartTime);\r\n        StartCoroutine(CountdownTimer());\r\n    }\r\n\r\n    private System.Collections.IEnumerator CountdownTimer()\r\n    {\r\n        while (timerCountdown > 0.0f)\r\n        {\r\n            yield return null;\r\n            timerCountdown -= Time.deltaTime;\r\n        }\r\n\r\n        if (isServer)\r\n        {\r\n            RpcTimerFinished();\r\n        }\r\n    }\r\n\r\n    [ClientRpc]\r\n    private void RpcTimerFinished()\r\n    {\r\n        HandleTimerFinishedEvent();\r\n    }\r\n\r\n    private void HandleTimerFinishedEvent()\r\n    {\r\n        TimerFinished?.Invoke();\r\n        Debug.Log(\"Timer finished!\");\r\n    }\r\n\r\n    public void RegisterTimerFinishedCallback(Action callback)\r\n    {\r\n        TimerFinished += callback;\r\n    }\r\n\r\n    public void UnregisterTimerFinishedCallback(Action callback)\r\n    {\r\n        TimerFinished -= callback;\r\n    }\r\n}\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-689bf67 elementor-widget elementor-widget-code-highlight\" data-id=\"689bf67\" data-element_type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-csharp line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-csharp\">\n\t\t\t\t\t<xmp> public async  Task ChangeTurn( bool  byTimer)\r\n    {\r\n        List<Task> tasks = new List<Task>();\r\n        if (IsMyTurn())\r\n        {\r\n            for (int i = 0; i < Grid.Instance.myAgents.Length; i++)\r\n            {\r\n                if (!Grid.Instance.myAgents[i].isDead)\r\n                {\r\n                    for (int j = 0; j < Grid.Instance.myAgents[i].effectedPoolsDictionary.Keys.Count; j++)\r\n                    {\r\n                        if (Grid.Instance.myAgents[i].effectedPoolsDictionary[(AbilityEnumPool)j])\r\n                        {\r\n                            await Grid.Instance.myAgents[i].abstractPoolTypesDict[(AbilityEnumPool)j]\r\n                                .ProcessPoolEffect();\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        }\r\n        else\r\n        {\r\n            for (int i = 0; i < Grid.Instance.enemyAgents.Length; i++)\r\n            {\r\n                if (!Grid.Instance.enemyAgents[i].isDead)\r\n                {\r\n                    for (int j = 0; j < Grid.Instance.enemyAgents[i].effectedPoolsDictionary.Keys.Count; j++)\r\n                    {\r\n                        if (Grid.Instance.enemyAgents[i].effectedPoolsDictionary[(AbilityEnumPool)j])\r\n                        {\r\n                            await Grid.Instance.enemyAgents[i].abstractPoolTypesDict[(AbilityEnumPool)j]\r\n                                .ProcessPoolEffect();\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        if (!byTimer)\r\n        {\r\n            ForgivePlayerPartially();\r\n\r\n        }\r\n      \r\n        \r\n        ResetTimerForOther();\r\n        gridRef.ToggleTurn();\r\n        ToggleTurnPrefabs();\r\n        ResetSliderValue();\r\n        SetTimerSprite();\r\n        \r\n        gridRef.OnTurnChanged?.Invoke();\r\n        \/\/ await Task.CompletedTask;\r\n\r\n    }<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Let`s discuss how to setup timers in network based games and what are the challenges. Lastly we will inspect my ChangeTurn method together! \u00a0 Title: Mastering Network-Based Timers in Unity: A Deep Dive into High-Performance Solutions Introduction: Timers are a fundamental part of game development, enabling developers to schedule events, control gameplay mechanics, and manage various game systems. However, when it comes to network-based timers in Unity, additional challenges arise. In this blog post, we&#8217;ll explore the intricacies of network-based timers and discuss professional concepts and code examples to overcome these challenges effectively. Understanding Network-Based Timers: Network-based timers are essential\u2026<\/p>\n","protected":false},"author":1,"featured_media":640,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-633","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"blocksy_meta":"","_links":{"self":[{"href":"https:\/\/codewithpiri.com\/index.php\/wp-json\/wp\/v2\/posts\/633","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/codewithpiri.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codewithpiri.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codewithpiri.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/codewithpiri.com\/index.php\/wp-json\/wp\/v2\/comments?post=633"}],"version-history":[{"count":7,"href":"https:\/\/codewithpiri.com\/index.php\/wp-json\/wp\/v2\/posts\/633\/revisions"}],"predecessor-version":[{"id":688,"href":"https:\/\/codewithpiri.com\/index.php\/wp-json\/wp\/v2\/posts\/633\/revisions\/688"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/codewithpiri.com\/index.php\/wp-json\/wp\/v2\/media\/640"}],"wp:attachment":[{"href":"https:\/\/codewithpiri.com\/index.php\/wp-json\/wp\/v2\/media?parent=633"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codewithpiri.com\/index.php\/wp-json\/wp\/v2\/categories?post=633"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codewithpiri.com\/index.php\/wp-json\/wp\/v2\/tags?post=633"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}