<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Ing. Jan Jileček]]></title>
  <link href="https://blog.jilecek.cz/atom.xml" rel="self"/>
  <link href="https://blog.jilecek.cz/"/>
  <updated>2026-04-05T22:13:24+00:00</updated>
  <id>https://blog.jilecek.cz/</id>
  <author>
    <name><![CDATA[Ing. Jan Jileček]]></name>
    <email><![CDATA[your@email.com]]></email>
  </author>
  <generator uri="https://jekyllrb.com/">Jekyll</generator>

  
  <entry>
    <title type="html"><![CDATA[Backrooms Break: Two Years, 20,000 Copies, and Everything It Cost Me]]></title>
    <link href="https://blog.jilecek.cz/blog/2026/04/05/backrooms-break-devlog/"/>
    <updated>2026-04-05T12:00:00+00:00</updated>
    <id>https://blog.jilecek.cz/blog/2026/04/05/backrooms-break-devlog/</id>
    <content type="html"><![CDATA[<p>Twenty thousand copies sold on Steam. That’s <a href="https://store.steampowered.com/app/2248330/Backrooms_Break/">Backrooms Break</a> - my third indie game, and by far my most successful. My name is Jan Jileček, and I built it as a solo developer over two years of nights and weekends.</p>

<p>But this isn’t just a devlog. This is the story of what it actually takes to ship a successful indie game.</p>

<p><img src="https://blog.jilecek.cz/images/backrooms/1.jpg" alt="header image" /></p>

<!-- more -->

<hr />

<p>Those two years meant, in the most literal sense, nothing but work. A full-time programming job during the week, then another shift at home every evening and weekend. Sometimes 16 hours a day in Unreal Engine on weekdays - more on weekends. My social life took a serious hit. Every free minute was consumed by the project. I sacrificed a lot for it, including my health. I stopped going to jiu-jitsu. I cut back on family visits. I started meal-prepping just to save time for programming. Taking care of my body became an afterthought. The project had absolute priority.</p>

<p>Then came the paradox. The moment I discovered people had <em>real</em> interest in the game, everything got more complicated - not less. The project suddenly carried far greater weight, and with it came responsibility. Every mistake, every bug, could translate into serious financial losses.</p>

<p>And one design mistake ended up doing exactly that.</p>

<p>In this devlog, I’ll walk you through the entire process - from game design and hundreds of hours of programming, through testing and marketing, to the personal sacrifices, the problems that nearly derailed everything, and finally, the launch.</p>

<p><img src="https://blog.jilecek.cz/images/backrooms/23.jpg" alt="timeline" /></p>

<p>In case you prefer the video version, I made this <a href="https://youtu.be/jkuAN08PVlM">devlog on youtube</a>, but chose to narrate it in my native Czech language.</p>

<hr />

<h2 id="where-it-all-started">Where It All Started</h2>

<p>Back in 2019, I’d been working at a software company for several years - a job that felt utterly hollow. The office sat in the middle of an industrial wasteland on the edge of the city. In that remote location the sense of emptiness hit me hard enough that I actually made a 16-minute short film about it. By then I’d already shipped a few games, but I didn’t consider any of them commercially successful. They were experiments, made for fun.</p>

<p>The real turning point came during COVID.</p>

<p>In 2020, I made a game inspired by Jungian psychology called <a href="https://store.steampowered.com/app/709710/Jungs_Labyrinth/"><em>Jung’s Labyrinth</em></a>. The procedural labyrinth generation algorithm I built for it would later become the foundation for Backrooms Break.</p>

<p><img src="https://blog.jilecek.cz/images/backrooms/22.jpg" alt="maze" /></p>

<p>The first concept for Backrooms Break came together on a single Saturday - May 21, 2022. At the time I was working as an Unreal Engine developer at a another Czech gamedev studio. I was frustrated with my weak grasp of the Chaos physics system, so I cooked up a small side project to learn it properly. I modeled a Backrooms pillar in Blender, sliced it into destructible pieces using Chaos physics, and started experimenting with Unreal’s physics fields. I spent a few hours studying the physics in Battlefield 4, went through their GDC talks, then wrote out theoretical game mechanics I’d want - things like hacking minigames inspired by Fallout. I pulled references from Call of Duty: Cold War too. Even so, I still didn’t see Backrooms Break as a full game - more of a demo. I gave it another day on Sunday, then shelved the project.</p>

<p><img src="https://blog.jilecek.cz/images/backrooms/24.jpg" alt="concept" /></p>

<hr />

<h2 id="the-jam-that-started-everything">The Jam That Started Everything</h2>

<p>I came back to it in September when I heard about the Ludum Dare game jam happening in October. I’d entered it before with small games - the standard format is making something from scratch in 72 hours. I already had a foundation, and I wasn’t in it for the ranking anyway. I used Ludum Dare as a playtesting venue. It’s the same approach I used with my previous game: <strong>test the idea as a demo first, and if the response is positive, push forward.</strong></p>

<p>That first version of Backrooms Break was played by hundreds of people. I got valuable feedback, watched multiple streamers play it live, and saw their genuine, unfiltered reactions.</p>

<p><img src="https://blog.jilecek.cz/images/backrooms/33.jpg" alt="game design" /></p>

<p>After Ludum Dare I was energized - but I wanted to use the Christmas break to actually rest. My game design process always involves letting the Unconscious work for a few months. I collect dreams, shower thoughts, random ideas - jot them down, and after some time revisit them with Occam’s Razor: cut anything that adds complexity without meaningfully improving fun or gameplay. Every project I make is a form of shadow work. It’s not just a game, but an expression of who I am.</p>

<p>With Backrooms Break, that approach had some unexpected consequences. More on that later.</p>

<p><img src="https://blog.jilecek.cz/images/backrooms/25.jpg" alt="collision" /></p>

<hr />

<h2 id="building-in-public-from-day-one">Building in Public from Day One</h2>

<p>In December 2022, I registered a Steam page - because <strong>starting your marketing the moment you have a working product is absolutely critical.</strong> A lot of studios skip this out of fear someone will steal their idea. But even just having a STeam page with a few screenshots starts generating wishlists. A few days after launching the page, I posted a single screenshot to Reddit. That one post got 54,000 views, 1,400 upvotes, and generated hundreds of wishlists overnight. After that, dozens more wishlists rolled in organically every day - a signal that real interest existed.</p>

<p><img src="https://blog.jilecek.cz/images/backrooms/9.jpg" alt="first screenshot" /></p>

<p>I never build a game without first knowing who my audience is and where I’ll reach them. For my previous game about Jungian psychology, I targeted psychology subreddits. For Backrooms, I went to Backrooms communities, horror fans, and liminal spaces enthusiasts. Those communities also gave me invaluable feedback and let me ask directly what they wanted to see in the game.</p>

<p><img src="https://blog.jilecek.cz/images/backrooms/2.jpg" alt="backrooms" /></p>

<p>On January 12, 2023, I released the first teaser trailer - hundreds more wishlists. Two days later, Japanese gaming sites noticed it and wrote an article, posting a screenshot tweet that racked up <strong>6 million views and 55,000 likes</strong>. That tweet linked to my Steam page. If the page hadn’t existed, I would have lost all of that momentum.</p>

<p><strong>Make your Steam page as early as possible.</strong></p>

<p>The day after that, Chinese outlets picked it up. I also started posting to TikTok - my girlfriend handled that campaign since I had no idea what I was doing there.</p>

<p>At this point, nearly everything shown in the trailer was a facade. The only actual gameplay was what I’d built in two days for Ludum Dare. I naively listed a Q2 2023 release date and planned on making just one level - the classic yellow Backrooms. But the response blew that plan apart. I was getting <strong>480 wishlists a day</strong>, and the wave kept going for about four weeks. I had to rethink everything.</p>

<p><img src="https://blog.jilecek.cz/images/backrooms/3.jpg" alt="wishlists" /></p>

<p>Around this time I watched a lecture by Dr. Huberman recommending nicotine as a nootropic. Despite being a non-smoker, I bought Nicorette and started taking one a day. My productivity shot up immediately. The consequences came later. More on that too.</p>

<p>By late April, I’d finished the complete game design. I also created a Discord community - something I’d recommend to every indie developer. By launch day, I had hundreds of fans waiting. Some helped with localization. Others kept me going during the moments I wanted to quit.</p>

<p><img src="https://blog.jilecek.cz/images/backrooms/27.jpg" alt="board" /></p>

<hr />

<h2 id="gathering-steam-literally">Gathering Steam (Literally)</h2>

<p>By May 2023, I was posting development progress videos to Reddit. I was at 7,000 wishlists - a meaningful number on Steam. Theoretically, hitting that threshold earns your game a “visibility wheel” in the Trending section for a week before launch, which can bring in tens of thousands of additional wishlists. That’s why releasing before reaching 7,000 is generally a bad idea. Backrooms Break ultimately reached <strong>35,000 wishlists before launch</strong>, and gained another 11,000 on release day alone.</p>

<p>In June, the prestigious games publication 80.lv noticed my May posts and tweeted about the game.</p>

<p><img src="https://blog.jilecek.cz/images/backrooms/6.jpg" alt="twitter post 80 LEVEL" /></p>

<p>In early July, I came up with one of the game’s defining features: a telekinetic hammer. The original demo only had a basic demolition hammer. I honestly can’t believe it took me that long to add the ability to call it back like a boomerang. People started calling the game “Thor in the Backrooms.” The inspiration came from an old childhood game, <em>Psi-Ops</em>, where telekinesis was the standout ability. I’ve always felt that what matters isn’t the telekinesis itself - it’s what you can <em>do</em> with it. It felt flat in <em>Control</em>. It was brilliant in <em>Half-Life 2</em> because of the Gravity Gun. In Backrooms Break, the magic was environmental destruction. Fans also drew comparisons to <em>Red Faction: Armageddon</em>, one of the first games to feature large-scale destruction.</p>

<p>I built multiple versions of the hammer throw and ran a vote in the Discord community. Fans chose their preferred throw style and force. I used the same community input for naming items and mechanics. That Discord was invaluable throughout the entire process.</p>

<p>Mid-July, I released another trailer and ran a Reddit campaign - good feedback, but less wishlist impact than the Japanese article had generated. I used the opportunity to refocus on optimization. Getting the game to run smoothly with thousands of lights and destructible walls at a playable framerate took roughly three months of daily work.</p>

<p><img src="https://blog.jilecek.cz/images/backrooms/28.jpg" alt="article" /></p>

<p>In August, I collaborated with my girlfriend - a professional 3D modeler and character artist - on a new enemy type. She built the entire creature in about two days based on my design. I then spent weeks experimenting with Unreal’s Physical Constraints system for its claw mechanics. Originally inspired by <em>Dead Space</em>’s necromorphs, I designed the enemy (which I named “Skullscythe”) so that players could only kill it by shooting off its claws. I built the mechanic, added tutorial text on the walls explaining it - and watched playtesters completely ignore it. In hundreds of Twitch sessions, only <em>one</em> player ever aimed at the claws. Everyone else shot the body and complained it was too hard to kill. Game design lesson: players don’t behave the way designers expect. I removed the mechanic and buffed body damage.</p>

<p><img src="https://blog.jilecek.cz/images/backrooms/30.jpg" alt="skullscythe" /></p>

<p>Also in August, I playtested with my little cousins using the Valve methodology: never guide, never hint, just observe. The cleanest feedback comes from players who don’t have a developer whispering over their shoulder.</p>

<h2><img src="https://blog.jilecek.cz/images/backrooms/5.jpg" alt="valve" /></h2>

<h2 id="steam-next-fest-the-turning-point">Steam Next Fest: The Turning Point</h2>

<p>October brought Steam Next Fest - arguably the single most important event in the lifecycle of a modern indie Steam game. I spent all of September preparing a demo build and a new trailer.</p>

<p>One major design pivot I made around this time: I had originally planned to use procedural generation for all levels, but quickly realized it creates a fundamental problem - <strong>boredom</strong>. You can see this with big-budget games like Starfield. I locked everything to a single seed, keeping level structure static while randomizing enemy spawns and loot. That made iteration dramatically faster.</p>

<p>I also started sending press kits. Both <a href="https://games.tiscali.cz/bleskovka/ceska-backrooms-break-adaptuje-znamy-mestsky-mytus-do-akcniho-roguelite-565450">Games.cz</a> and <a href="https://indian-tv.cz/clanek/probourejte-se-bludistem-v-ceske-akci-backrooms-break-mypk2q">Indian-TV.cz</a> covered Backrooms Break. Good momentum.</p>

<p>Steam Next Fest started on October 9th. Thousands of players tried the demo, including YouTubers and streamers, pulling in 800–1,100 new wishlists per day throughout the festival. The data was invaluable - I could see how the game performed across every hardware configuration and exactly where players got stuck.</p>

<p>One of the biggest complaints: players didn’t know where to go. That’s intentional in Backrooms lore - the disorientation is part of the experience - but I had to add at least a few navigation markers before frustration tipped into abandonment.</p>

<p>On the first day of the festival, Japanese outlet <a href="https://news.denfaminicogamer.jp/news/231009b">Denfaminicogamer</a> published another article. Japanese players immediately stood out as a core audience - roughly 30% of my total wishlists came from Japan. Later, they’d prove to have the lowest refund rate, the longest playtimes, and the most positive reviews of any country.</p>

<p>Some players tried to destroy every single wall in the demo. I turned their determination into a Steam achievement.</p>

<hr />

<h2 id="building-more-levels">Building More Levels</h2>

<p>In November I started modeling Level 4, heavily inspired by the TV series <em>Severance</em>. I wanted CRT monitors that felt authentic - the hacking minigame is modeled on basic Linux terminal commands. The whole CRT system had to be built using in-scene cameras rendering to render targets.</p>

<p>December was dedicated to the Poolrooms level. I’d originally planned 10 levels, but each one took one to two months to build properly - mechanics, puzzles, loot, enemies, testing, fun factor, all of it. I cut the game to five levels. Otherwise I’d have needed another full year.</p>

<p>Over Christmas, my girlfriend and I photographed a local abandoned pool, which she then modeled for the game. I also used photos from a trip I’d taken to Pripyat, Ukraine - the Chernobyl pool is in the game too.</p>

<p><img src="https://blog.jilecek.cz/images/backrooms/32.jpg" alt="chernobyl" /></p>

<p>Then came the first serious crashes: loot box collision models were misconfigured, triggering infinite collision loops with certain static meshes, draining memory and crashing the whole application.</p>

<p><img src="https://blog.jilecek.cz/images/backrooms/7.jpg" alt="pool inspiration" /></p>

<hr />

<h2 id="the-worst-month">The Worst Month</h2>

<p>On January 4, 2024 - two months before launch - I got <strong>bronchopneumonia</strong>. My own fault: I got cold coming home from jiu-jitsu one evening. I was overworked, tired and those nicotine patches I mentioned? By this point I was taking several a day. Nicotine is a significant immunosuppressant - something I only discovered through research later. It’s one of the primary mechanisms through which it promotes cancer: it suppresses immune response, leaving the body unable to fight abnormal cell growth. My immune system was compromised enough that the pneumonia knocked me out for a month. I hadn’t rested over Christmas either - just kept working. My body forced the issue. I pushed the launch date to late April.</p>

<p>All of February went into building the final boss fight. The Backrooms lore includes a level called “The End,” set in a library - so that’s where the bossfight lives. Lots of destructible wooden furniture. It works.</p>

<h2 id="-1"><img src="https://blog.jilecek.cz/images/backrooms/17.jpg" alt="light" /></h2>

<h2 id="the-last-stretch">The Last Stretch</h2>

<p>March was the new trailer, plus implementing Steam leaderboards and achievements. The leaderboards were designed for speedrunning - borrowing from Hotline Miami’s structure, where players are rewarded for speed and, in Backrooms Break’s case, destruction. At the end of each level, an elevator info screen breaks down the player’s performance, scores it, and shows their global ranking. I designed the scoreboard display based on a LED wall-panel menu at a local café I liked.</p>

<p><img src="https://blog.jilecek.cz/images/backrooms/15.jpg" alt="cafe" /></p>

<p>The new launch date: <strong>April 24, 2024</strong>. Chosen carefully - releasing any later would land in Steam’s spring sale, which is financial suicide for a small indie game. Players who just spent money on AAA titles aren’t going to buy yours. And April 26th was when my biggest direct competitor, <strong>POOLS</strong>, was planning to launch - a walking simulator focused purely on the Poolrooms aesthetic.</p>

<p>I’d actually built Backrooms Break partly as a reaction to walking simulators. The genre strips players of any agency, making them passive victims of atmosphere. I wanted players to be able to <em>fight back</em>. That was a risky bet. It turned out POOLS sold roughly <strong>8x more copies</strong> than Backrooms Break - despite (or maybe because of) being yet another entry in a genre with a hundred near-identical competitors. I’d underestimated how deep the demand for that experience ran. That said, Backrooms Break is distinct enough that people are still buying it and praising it for what it is.</p>

<p>Pricing and timing decisions are genuinely their own science. I use <a href="https://steamdb.info">steamdb.info</a> and <a href="https://gamalytic.com">gamalytic.com</a> obsessively - tracking follower counts, wishlist growth, and post-trailer spikes to model expected sales.</p>

<p>On March 12th, I discovered that a Polish Backrooms game was also planning to launch on April 24. A nightmare scenario. I tracked their Discord, noticed they were badly underestimating their own development timeline - and sure enough, by March they’d pushed their date to “TBD.” As of April 2026, they still haven’t launched.</p>

<hr />

<h2 id="the-vtuber-army">The Vtuber Army</h2>

<p>On March 25, a month before launch, I got a message on Discord that seemed almost too good to be true. It was from the CEO of a major Japanese Vtuber agency.</p>

<p>After years of receiving hundreds of fake “I’m a famous YouTuber, can I have keys?” emails, I was skeptical. I asked to move the conversation to LinkedIn. He responded there, which confirmed he is legit. I generated dozens of keys and asked him to hold off until the day before launch.</p>

<p>A month later, I had an army of Vtubers - each with millions of subscribers - streaming Backrooms Break for hours. Every single one of them played for multiple hours. Their videos pulled in tens and hundreds of thousands of views each. Best investment I made on the entire project. It cost me nothing but product keys.</p>

<p><img src="https://blog.jilecek.cz/images/backrooms/34.jpg" alt="vtubers" /></p>

<hr />

<h2 id="launch-week">Launch Week</h2>

<p>In the final weeks, I finished translations into Japanese, Chinese, Russian, and German. Chinese is tricky - you gain access to a massive market, but also receive disproportionately higher refund rates and negative reviews compared to other regions It’s not just my experience - Czech gaming magazine LEVEL has written about this pattern too. As of now, I am aware why that is happening. Chinese market has disabled Steam community centre, so the only way to complain is through the actual Steam reviews.</p>

<p>A week out, I was blasting trailers and screenshots across every social channel. I also hired 10 paid playtesters - a few dollars each to complete the game. Some sent back PDF reports mapping exactly what they liked and didn’t. I also integrated BugSplat crash tracking so every crash post-launch would be logged.</p>

<p><img src="https://blog.jilecek.cz/images/backrooms/13.jpg" alt="pc" /></p>

<p>The days before launch: no sleep. Working through the night. The morning of release I sent keys to YouTubers and streamers I’d been in contact with over the previous years.</p>

<p>My biggest Western content creator was <a href="https://youtu.be/eZrkGIZIgKQ">Broogli</a> - the #1 content creator in the Backrooms community, who normally just maps the lore but made an exception to play my game live. <a href="https://youtu.be/npsHhaGqqJQ">8BitRyan (4M subscribers)</a> was another surprise. The Japanese and Chinese markets were a chapter unto themselves.</p>

<p>I published on Epic Game Store as well - and I wouldn’t recommend it to anyone. Non-responsive support, endless bureaucratic friction, and I ended up launching there 10 days after my Steam date, just because the achievements on Epic did not match those I created on Steam, and they demanded I fix it, and then failed to approve it before release. And then they noticed my trailer contains blood, and demanded I release another trailer without blood/red paint. The result: a few dozen copies sold. On Steam: 20,000. Epic might only make sense for a 6-month exclusivity deal where you can work out the bugs before a Steam launch. But 2 years after release, Epic store generated in sum about as many sales as the weakest week on Steam.</p>

<p><img src="https://blog.jilecek.cz/images/backrooms/12.jpg" alt="boom" /></p>

<hr />

<h2 id="after-launch">After Launch</h2>

<p>Post-launch, I patched the most critical bugs. In May I added an Endless Mode - for players who finished the game and want to roam freely, spawn anything, no enemies. In June, I contacted Valve about receiving a Steam Deck for porting. By July, I’d hit the sales threshold to unlock Steam Trading Cards.</p>

<p><img src="https://blog.jilecek.cz/images/backrooms/35.jpg" alt="deck" /></p>

<hr />

<h2 id="what-i-learned">What I Learned</h2>

<p>And here we are - two years from a Blender pillar to 20,000 copies sold.</p>

<p>There was the Steam Next Fest chaos, the pneumonia that nearly derailed everything, the Japanese articles that changed the trajectory of the whole project, the Vtuber campaign that cost nothing and paid off enormously, and one expensive design mistake - a level ordering decision based on lore fidelity rather than player experience.</p>

<p>I was obsessive about following canonical Backrooms level numbers. Level 0, then 1, then 4, then 37. The elevator goes in order, so the game goes in order. Backrooms fans will appreciate the lore consistency, I told myself. It makes sense, right?</p>

<p>Problem is, I made the Garage (Level 1) a flooded level. Like the Amnesia invisible monster level. The level was fundamentally different from the first level (not that much destruction, a lot of psychological pressure and actual horror, running from the invisible monster, occasionally breaking some pillars, jumping onto parked cars, having to rotate a valve to open a gate while the monster heads toward the last spot where you touched the water… etc.)</p>

<p>And I put this level second in the game.</p>

<p>A lot of players quit there. I spotted the drop in playtime data a few days after launch, switched the level to later in the sequence where it actually belongs difficulty-wise - and sales and refunds went back to normal almost immediately. I estimate that ordering decision cost me somewhere between $13-15k.</p>

<p>The numerical level order is now wrong by lore standards. Nobody noticed. Nobody cared. But they sure noticed the feeling - or rather, they stopped noticing it in a bad way. Levels go from easy to hard now, as they should have from the start.</p>

<p><img src="https://blog.jilecek.cz/images/backrooms/29.jpg" alt="github" /></p>

<p>The deepest lesson, though, is this: be very careful which game you choose to make - because in my experience, you eventually <em>become</em> the project. I thought I was making a game about the feeling I had in 2019, in a job that left me empty, searching for a way back to myself.</p>

<p>Instead, my own life during development started to look a lot like the Backrooms - full of pressure, isolation, and unexpected dead ends.</p>

<p>Next time, I want to make something that feels as genuinely meaningful as my first Steam game, <em>Jung’s Labyrinth</em>. Nothing less.</p>

<p>But even so - the journey was worth it. Mainly because of the people who were part of it: my girlfriend, my family, the Discord community, and all the players who kept showing up.</p>

<p>Thanks for reading this all the way to the end.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The Power of Buttons in World of Tanks: My notes from the UX talk at Game Access Conference 2025]]></title>
    <link href="https://blog.jilecek.cz/blog/2025/06/18/the-power-of-buttons-in-world-of-tanks-my-notes-fr/"/>
    <updated>2025-06-18T12:00:00+00:00</updated>
    <id>https://blog.jilecek.cz/blog/2025/06/18/the-power-of-buttons-in-world-of-tanks-my-notes-fr/</id>
    <content type="html"><![CDATA[<p><img src="https://blog.jilecek.cz/images/the-power-of-buttons-in-world-of-tanks-my-notes-fr-02.png" alt="" /></p>

<!-- more -->

<p>One of the few talks at this year’s GA conference that I was really interested in was by Lucia Magáthová, a UX designer with three years of experience at Wargaming Studios.
As a long-time World of Tanks (WoT) player, I was curious about how this well-oiled, money-making machine of a game keeps me psychologically hooked. It turns out it starts with the buttons — the main interface between the player and the game.
I documented this primarily for my own game development goals. While the games I’ve <a href="https://store.steampowered.com/app/2248330/Backrooms_Break/">released</a> have been successful, their UI has always been a weak point.
Here are my notes! During the presentation, Lucia showed examples directly from the game, so I took in-game screenshots to replicate what she presented. Unfortunately, they’re in Czech, as that’s the version of WoT I play.</p>
<h2 id="3-button-concepts-directing-obscuring-evoking">3 button concepts: Directing, Obscuring, Evoking</h2>
<p><img src="https://blog.jilecek.cz/images/the-power-of-buttons-in-world-of-tanks-my-notes-fr-03.png" alt="" /></p>
<h2 id="directing">Directing</h2>
<h3 id="prioritization">Prioritization</h3>
<ul>
  <li>prioritize the button with an interesting color
<img src="https://blog.jilecek.cz/images/the-power-of-buttons-in-world-of-tanks-my-notes-fr-04.png" alt="" />
Vyměnit — Exchange
    <h3 id="direction-of-intention">Direction of intention</h3>
  </li>
  <li>arrows in the campaing map, show the direction of the progress through the missions
<img src="https://blog.jilecek.cz/images/the-power-of-buttons-in-world-of-tanks-my-notes-fr-05.png" alt="" />
    <h3 id="direction-questions-order">Direction questions, order</h3>
  </li>
  <li>suitable in the military setting. Affirmative. Purchase.</li>
  <li>(yes, the talk made absolutely clear that Wargaming’s main focus is money making. I don’t blame them, I admire how good of a money making machine the game is.)
<img src="https://blog.jilecek.cz/images/the-power-of-buttons-in-world-of-tanks-my-notes-fr-06.png" alt="" />
Koupit — Purchase
    <h3 id="timer">Timer</h3>
  </li>
  <li>in-game “thank you” button</li>
  <li>You have 10 seconds to send a thank you back to the player that thanked you. I asked Lucia about this, why I cannot send a thank you after the battle, she said it is due the context of the battle — this way it is always clear what the player is thanking you for, it is always situation-based.
<img src="https://blog.jilecek.cz/images/the-power-of-buttons-in-world-of-tanks-my-notes-fr-07.png" alt="" />
    <h2 id="obscuring">Obscuring</h2>
    <p><img src="https://blog.jilecek.cz/images/the-power-of-buttons-in-world-of-tanks-my-notes-fr-08.png" alt="" /></p>
    <h3 id="mystery">Mystery</h3>
  </li>
  <li>transparent FOMO</li>
  <li>don’t remember this one, that’s my only note. Transparent fear of missing out? Could be the assembly shop tank menu.
    <h3 id="paywall">Paywall</h3>
  </li>
  <li>animated raumfalte</li>
  <li>no screenshot here, but she shown the Raumfalte lootbox and their different stages. Pay more &gt; the 3D lootbox gets nicer to represent higher value.</li>
  <li>I am pretty sure the paywall also applies to regular paywalls like this:
<img src="https://blog.jilecek.cz/images/the-power-of-buttons-in-world-of-tanks-my-notes-fr-09.png" alt="" />
    <h3 id="concealment">Concealment</h3>
  </li>
  <li>research disabled
<img src="https://blog.jilecek.cz/images/the-power-of-buttons-in-world-of-tanks-my-notes-fr-10.png" alt="" />
Nelze vyzkoumat — Research disabled
    <h3 id="omission">Omission</h3>
  </li>
  <li>notification tells the user what he got for daily reward</li>
  <li>apparently they experimented with daily login rewards, and the notification at bottom right shown the rewards automatically. User did not have to click any button. So that is why “omission”.
    <h2 id="evoking">Evoking</h2>
    <h3 id="personalisation">Personalisation</h3>
  </li>
  <li>ribbon rearrangement</li>
  <li>showcase
<img src="https://blog.jilecek.cz/images/the-power-of-buttons-in-world-of-tanks-my-notes-fr-11.png" alt="" />
    <h3 id="adaptivity">Adaptivity</h3>
  </li>
  <li>buttons with memory — game remembers what you used</li>
  <li>demounting choice (kit, gold or bonds)</li>
  <li>WoT plus privillege
<img src="https://blog.jilecek.cz/images/the-power-of-buttons-in-world-of-tanks-my-notes-fr-12.png" alt="" />
    <h3 id="second-hand-trigger">Second-hand trigger</h3>
  </li>
  <li>Christmas streams</li>
  <li>She got an entire segment about the twitch people watching streamers open lootboxes. Therefore “Second-hand trigger”. They enjoy watching other people have joy of opening lootboxes? I think that was her point.
    <h3 id="slice-of-life">Slice of life</h3>
  </li>
  <li>Diegetic buttons</li>
  <li>This segment was about diegetic (that is — integrated into the world, game) buttons. Shown in the Clan battle UI.
<img src="https://blog.jilecek.cz/images/the-power-of-buttons-in-world-of-tanks-my-notes-fr-13.png" alt="" />
The talk was generally interesting, but she spent too much time at the beginning discussing irrelevant literary topics from her degree. Additionally, she took 5–10 minutes to explain the concept of “immersion” to a room full of game developers, which felt unnecessary.
Then it started being informative with concrete examples, I enjoyed that.
After that there was a fireside chat with Oleksii Sytianov, main game designer of Stalker: Shadow of Chernobyl. I left early, he was talking about general stuff of how he entered game development in 2005–2007. It was aimed mainly at people trying to get into game development. The rest of the information I already knew in greater detail than he could provide — in 2022 I extracted an article from the AI programmer of Stalker, <a href="https://blog.jilecek.cz/@janjilecek/a-life-emergent-ai-and-s-t-a-l-k-e-r-70a9cdde3fac">you can read it here</a>.
And here is a photo of the fireside chat. Game Access has a great atmosphere each year, but it is more of a networking event, than a place to learn.
<img src="https://blog.jilecek.cz/images/the-power-of-buttons-in-world-of-tanks-my-notes-fr-14.png" alt="" /></li>
</ul>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Quantum entanglement could use love as the substrate material for communication]]></title>
    <link href="https://blog.jilecek.cz/blog/2025/01/25/quantum-entanglement-could-use-love-as-the-substra/"/>
    <updated>2025-01-25T12:00:00+00:00</updated>
    <id>https://blog.jilecek.cz/blog/2025/01/25/quantum-entanglement-could-use-love-as-the-substra/</id>
    <content type="html"><![CDATA[<p>This is my personal view, based on years of following the happenings in the scientific world, connected with my (ex-) eastern philosophy views, personal psychedelic experiences and personal theory, one that I cannot prove. Yet, I felt this way for years and wanted to express it, somewhere.
I have been a Jungian since 2017. That is when my journey really began. Back then I wrote my first <a href="https://janjilecek.blogspot.com/2017/02/we-can-shape-reality-with-our-mind.html">article</a>, and also bought a book about the Tao. Later I discovered Jungian psychology, and what Tao Te Ting only outlined as something that could not be explained or named, Jung explained in DEPTH as the Collective Unconscious.</p>

<p>Collective Unconscious was real, concrete thing, according to Jung. He considered it a living entity, that exists outside ourselves, living in the Universe. In my pantheistic view, the concept is the same as God. I cannot go into depth about the Collective Unconscious, for that are my other articles, but I want to focus on one concept from it — <strong>Synchronicity</strong>.</p>

<!-- more -->

<p>Synchronicty is, as many of you know, a meaningful coincidence. But it is <em>not</em> that kind of basic coincidence where you learn a new concept (like the name of a song) and then you hear it everywhere — that is simply the Reticular activating system (RAS), part of the brain that is responsible for filtering reality down to bits that your being finds relevant and useful. It is an optimization method to only see useful context. It is also not that kind of coincidence where your meet your next door neighbour on your vacation in Rome.</p>
<h3 id="living-a-symbolic-life">Living a symbolic life</h3>
<p>Meaningful coincidence is a borderline impossible thing to happen. An event that you feel in your soul is about to happen, and it happens in reality. <strong>It is also an event that is a marker of a correct progress through your life, a marker of a good path</strong>. People not inclined towards this way of thinking will disregard these events. They will consider them an esoteric bullshit. Jung was a mystic, after all, and there is no such thing as a soul (sarcasm).
I had multiple of those borderline impossible events happen in my life. For example — I went for a job interview in my dream firm, <strong>30. June 2017</strong>. They said yes, but had problems with their budget. Due to various circumstanes I did not get hired in the end. This was my dream job, working as a game developer. For financial reasons, I had to go back to being a software developer. I forgot about my dream. Then covid came in 2020, I finally quit software development, <a href="https://store.steampowered.com/app/709710/Jungv_Labyrint/">made a game about Jungian psychology</a> on my own, and used it as portfolio piece. Then, by random chance, an email offer comes from head hunters. I could get into a game development firm of an uknown name. I pass the interview process. And I get hired, on <strong>30. June 2021</strong>. Later I find out that this firm is the same one I failed to get into, <strong>exactly 4 years ago, TO THE DAY.</strong> In this firm, I would find my future girlfriend.
In 2019, I was finishing my master’s degree. First attempt I failed, due to exhaustion. My second, and last attempt, I ate clean, exercised, I was my best version. I ate bio food, most expensive bio eggs I could find for breakfast. They sold in pack of 6 eggs. For months I would make the same breakfast. 5 eggs and bacon. Yes, this bit of the story will be about eggs, but bear with me!
On the morning of my final exam for my degree, <strong>30. August 2019</strong>, I decided to eat light. I crack 3 eggs out of the pack of 6. All of them have DOUBLE EGG YOLKS. This did not happen once (not once!) in the year before, or the whole year after. Believe me, I watched. I interpreted this sign as getting a 6 on a throwing dice. Sign of good luck. Then before my exam I pick a random theme out of 64 possible themes we had to pick out from, and it is exactly the one that I memorized for half an hour before I went to the exam. Luck was on my side. I passed. Then, the second morning I use the remaining 3 eggs — none had double yolk. And no egg had double yolk for a year after. It may sound funny. But in Jungian psychology, egg signifies potential.
I told you about the game I released, right? I finished development of the game at 29. August 2020. Then at midnight, I am hungry. I do not know yet it is “tomorrow”, I was working late into the night. I go to have a snack, and eggs sound like a good choice. I crack a few onto the pan. I get 3 double yolks. I look at the clock. It is <strong>30. August 2020</strong>. <strong>Exactly a year later, to the day</strong>. In a few days I release the game. It is a success. And of course, I see no double yolks for months after.
Those events are not a mere chance. They are an expression of your Unconscious, that triggers an event in “the real world”. It works both ways. I did not call this sign. I did not wish for it. It materialized in front of me. And I was careful enough to listen.
These synchronicities tie closely with your dreams, which use symbolic language to express important warnings and predictions about your life. I wrote about this in my <a href="https://blog.jilecek.cz/how-to-analyze-your-dreams-and-why-is-it-crucial-for-self-development-4089d46dc046">other articles</a>.</p>
<h3 id="okay-but-how-does-this-relate-to-quantum-entanglement">Okay, but how does this relate to quantum entanglement?</h3>
<p>I would demonstrate on an experiment, that quantum scientist (and buddhist) Dr. Dean Radin made years ago. He proved that telepathy exists. He took a long time married couple, placed them in a lab in different countries (in USA and Europe), gave both the husband and wife an EEG headset, <a href="https://youtu.be/8eJkFh1-5Yw?t=748">covered the eyes of the wife</a>, and began shining light into the eyes of the husband. This neural activity would show in the brain of the wife, halfway around the globe! The information traveled there through an unknown substrate.</p>
<blockquote>
  <p>His own theory is that brains are just receivers of cosmic energy and that each brain has a gravitational field.</p>
</blockquote>

<!-- more -->

<p><a href="https://www.goodreads.com/quotes/753175-my-brain-is-only-a-receiver-in-the-universe-there">Nikola Tesla</a> said the same thing hundreds of years ago.</p>
<blockquote>
  <p>“My brain is only a receiver, in the Universe there is a core from which we obtain knowledge, strength and inspiration. I have not penetrated into the secrets of this core, but I know that it exists.”</p>
</blockquote>

<p>Christopher Langan is still <a href="https://www.youtube.com/watch?v=d8IZ0L5596s">saying this</a>.</p>

<p>And the frequencies on which our brains resonate attract or repulse other people (and events). If you spend a long enough time with somebody in a loving relationship, you begin to FEEL THEM through space. Your girlfriend, or wife, could be at her work, yet you begin to feel like she does not feel OK. Or you have a desire to write her, and in exactly that moment, she writes you.</p>
<blockquote>
  <p>People who took the most potent psychedelic drug — <a href="https://www.youtube.com/watch?v=awpK2KdQMCE">Bufo Alvarius</a> — report that they become something greater than the Universe, that they became Love.</p>
</blockquote>

<p>I cannot prove these things. I feel them.
My father was working construction, in the month my mother was expecting me. One day he is at the site, reconstructing a castle. Suddenly a feeling hits him, he drops everything, runs to the payphone, and calls the hospital. He felt I was born. The nurse told him I was born 10 minutes prior to the call.
My aunt was creating a clay statue in her shop. She had a candle lit nearby. Her husband is in the hospital, sick. She works on the statue, and suddenly, the candle goes out. At that moment, she knew her husband died. Later she confirms the sad news.
In 2021 I travel to Switzerland with a friend, to Jung’s secret tower in Bollingen. There is not a chance in hell that we will get to visit the <a href="https://youtu.be/hdRTFD2e1f8">Lapis Philosophorum</a> (a stone that Jung carved when he was 75 years old), because it is on private property. I come in anyway, knock on the door of this abandoned tower, and two women open the door. They are Jung’s grand-grand-daughters. They ask about me, I tell them about the game I made about their grandfather. They allow me to touch the stone.
The quantum entanglement is a mechanism that works faster than the speed of light. Information gets propagated through some unknown substrate. The energy of the Universe. It could be called Love.
Taoists call it Tao.
Gnostics call it Pleroma.
Jung calls it the Collective Unconscious.
Christians call it God.
From the examples I provided you can see that you personally can experience this phenomenon only through love. It is always the case that love is involved in some shape or form. Otherwise, you are not connected strongly enough to the other person. You do not resonate on the same frequency. Quantum Communication is not possible otherwise.
<img src="https://blog.jilecek.cz/images/quantum-entanglement-could-use-love-as-the-substra-02.jpg" alt="" /></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Designing Games — 21 best pieces of advice taken from the book]]></title>
    <link href="https://blog.jilecek.cz/blog/2024/03/08/designing-games-21-best-pieces-of-advice-taken-fro/"/>
    <updated>2024-03-08T12:00:00+00:00</updated>
    <id>https://blog.jilecek.cz/blog/2024/03/08/designing-games-21-best-pieces-of-advice-taken-fro/</id>
    <content type="html"><![CDATA[<p>When I read a book, I often underline useful passages. Later when I am finished reading the book, I compile a summary of these important lines.</p>

<!-- more -->

<p>I am an Unreal Engine 5 game developer and this is 21 quotes from the book written by Tynan Sylvester, an INTP millionaire gamedev. I searched for INTP gamedev writers and this book was appraised by many. I used the money that my dying grandfather gave me as a Christmas gift to buy this book. My memento of his soul lives in my copy of the book. Let his will flow through my future gamedev ideas.</p>
<ol>
  <li>These situations can be kept more interesting by not telling players everything, and instead rationing out information in a structured way to create suspense.</li>
  <li>The true parts of these statements (feedback from testers) are the raw emotions behind “I liked it” and “It wasn’t fun”</li>
  <li>So games that teach players to build, socialize, and fight will always have the broadest impact (values that shift loneliness to togetherness and poverty to wealth)</li>
  <li>To achieve sustained success, a game must use its new technology to unlock interactions and situations that could not have been experienced before (example: Doom)</li>
  <li>Games narratives are laden with clichés. The player character is an amnesiac. Or a super-soldier. One of the worst clichés is the crate (loot crate, they use the <em>Start to crate</em> metric as metric for bad games)</li>
  <li>… it is the reason most limitless games are multiplayer — because a person can learn nearly any game system, but he can never fully understand another human mind (timeless game example: Chess, multiplayer games in general)</li>
  <li>In a mechanics-driven experience, this is healthy, since <strong>exploring systems is a major driver of meaning</strong>.</li>
  <li>Ignoring is, where possible, often better than disallowing or punishing because the player feels less controlled, and the behaviour stops quickly when the player gets no interesting reaction. Players understand the game mechanics have limits; it’s often better to make those limits simple, obvious, and dull than it is to try to camouflage them (example: jumping on boss’s table, NPC does not react)</li>
  <li>Understanding decisions is critical in game design because decisions are the only emotional trigger that is unique to games</li>
  <li>The heart of games is in interactivity and the heart of interactivity is the moment of decision.</li>
  <li>We can avoid such shelf moments (nothing to look forward to in the game, players shelves it) by superimposing several fixed ration schedules.</li>
  <li>The key to superimposing reward schedules is that the player must not be allowed to concentrate his efforts on just one reward schedule.</li>
  <li>They mean that we should not just toss rewards willy-nilly into every game experience, hoping for a free motivation boost. Used haphazardly, extrinsic rewards degrade, distort and destroy the core experience of play. The player may be motivated, but the motivations is a shell of action without a core of feeling (money, credits rewards for a previously fun activity)</li>
  <li>Redundancy — we can do this sneakily so that players don’t notice. For example, we place the same audio log in five different places, but once player listens to one of them, we have the others silently disappear.</li>
  <li>Most players will never understand why a game feels the way it does. They will credit the graphics or balance for successes that were actually won in the <strong>input system</strong>.</li>
  <li>Fine-tuning Half-Life: Toward the middle of the project, once the major elements were in place, it became mostly a matter of fine-tuning. We automatically recorded player’s position, health, weapons, time and any major activities such as saving the game, dying, being hurt, solving puzzles, fighting monsters etc. We then graphed the results to find places where player spent too long without any encounters (boring), too long with too much health (too easy) or the opposite (too hard). This gave us a good idea where to add the goodies.</li>
  <li>Start at the bottom of the dependency stack and work upward through iteration loop (about dependency stacks).</li>
  <li>“You are trying to get to the moon. You should be aiming for Jupiter. If you aim for Jupiter, you will definitely get to the moon” — Jim Henson</li>
  <li>“A soldier will fight long and hard for a bit of colored ribbon” — Napoleon</li>
  <li>Games are mental models for pieces of life.</li>
  <li><strong>A game is not a chain of events like a story. It’s a system. It crystallizes some part of the world into a set of mechanics and packages them up for us to play with</strong>
<img src="https://blog.jilecek.cz/images/designing-games-21-best-pieces-of-advice-taken-fro-02.png" alt="" /></li>
</ol>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Jak vytvořit Pacmana v Pythonu - 2. část]]></title>
    <link href="https://blog.jilecek.cz/blog/2023/01/10/Pacman2/"/>
    <updated>2023-01-10T12:00:00+00:00</updated>
    <id>https://blog.jilecek.cz/blog/2023/01/10/Pacman2/</id>
    <content type="html"><![CDATA[<p><img src="https://create-it.cz/Blog/PublishingImages/Titulni/2023/2pacman.JPG" alt="" /></p>

<p>Vítejte ve druhé části seriálu o tom, jak vytvořit hru Pac-Man v Pythonu. V <a href="https://create-it.cz/Blog/Stranky/Pacman1.aspx">minulém díle</a>jsme si představili základní principy hry Pac-Man a navrhli si její datovou strukturu. V tomto díle se budeme zabývat implementací několika důležitých prvků hry, jako je například kolize s duchy, počítání score, umělá inteligence duchů, power-upy, koncové stavy hry, animace a textury.</p>

<!-- more -->

<p>Nejprve si ale připomeneme, jakým způsobem bude hra fungovat. Hráč ovládá Pacmana a snaží se získat co nejvíce bodů za snězení všech cookies na mapě. Pacman je ale pronásledován duchy, kteří se po mapě pohybují podle určitých pravidel. Hra končí, pokud Pacmana chytí jeden z duchů, nebo pokud Pacman sní všechna cookies.</p>

<p>V tomto finálním díle se zaměříme na implementaci kolizí s duchy, které jsou pro hru důležité, jelikož jejich kontakt s Pacmanem může vést k jeho zničení. Dále se podíváme na to, jak můžeme počítat skóre hráče a jak implementovat umělou inteligenci duchů, aby se po mapě pohybovali realističtěji.</p>

<p>Power-upy jsou speciální prvky, které mohou hráči pomoci zvýšit jeho šance na vítězství. V našem případě to mohou být například různé druhy cookies, které mohou Pacmanovi dodat speciální schopnosti nebo ho ochránit před duchy.</p>

<p>Koncové stavy hry jsou důležité, abychom mohli oznámit hráči, zda vyhrál nebo prohrál. V našem případě budeme mít dva možné koncové stavy: vítězství, pokud Pacman sní všechna cookies, a prohru, pokud ho chytí jeden z duchů.</p>

<p>Animace a textury postav duchů a Pacmana zase zajistí, aby hra vypadala živěji a realističtěji. V našem případě budeme animovat pohyb Pacmana a duchů po mapě.</p>

<p>Pokud budete následovat tento článek až do konce, tak výsledná hra bude vypadat takhle:</p>

<p><img src="https://create-it.cz/Blog/PublishingImages/Stranky/Pacman2/pacman4.gif" alt="" /> </p>

<h2 id="kolize-s-duchy-a-počítání-životů">Kolize s duchy a počítání životů</h2>

<p>Počítání životů je spojeno se systémem kolizí hráče s duchy. V minulém díle jsme však pořádně neodlišili duchy od ostatních herních objektů, proto pro ducha založíme samostatnou funkcionalitu pro jeho ukládání, získávání a kontrolu kolize s hráčem. Logika je totožná s kolizí s cookie z prvního dílu. Také připravíme proměnné pro powerupy (schopnost podle originálního jména “kokoro”), životy, skóre a časovače událostí. Pro počítání životů jsem přidal jednoduchou funkci <em>kill_pacman</em> - pokud se ho dotkne duch, odeberu mu jeden život a umístím ho znovu na startovní pozici. Pokud mu dojdou životy, tak zničím jeho objekt.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#class GameRenderer:
def __init__ (self, in_width: int, in_height: int):
	self._won = False
	self._powerups = []
	self._ghosts = []
	self._hero: Hero = None
	self._lives = 3
	self._score = 0
	self._score_cookie_pickup = 10
	self._score_ghost_eaten = 400
	self._score_powerup_pickup = 50
	self._kokoro_active = False
	self._current_mode = GhostBehaviour.SCATTER
	self._mode_switch_event = pygame.USEREVENT + 1 # custom event
	self._kokoro_end_event = pygame.USEREVENT + 2
	self._pakupaku_event = pygame.USEREVENT + 3
	self._modes = [
    	(7, 20),
    	(7, 20),
    	(5, 20),
    	(5, 999999) # infinite chase
	]
	self._current_phase = 0

def add_ghost(self, obj: GameObject):
	self._game_objects.append(obj)
	self._ghosts.append(obj)

def get_ghosts(self):
	return self._ghosts

def end_game(self):
    	if self._hero in self._game_objects:
        	self._game_objects.remove(self._hero)
    	self._hero = None

def kill_pacman(self):
    self._lives -= 1
    self._hero.set_position(32, 32)
    self._hero.set_direction(Direction.NONE)
    if self._lives == 0: self.end_game()


#class Hero
def tick():
	self.handle_cookie_pickup()
	self.handle_ghosts()

 def handle_ghosts(self):
    	collision_rect = pygame.Rect(self.x, self.y, self._size, self._size)
    	ghosts = self._renderer.get_ghosts()
    	game_objects = self._renderer.get_game_objects()
    	for ghost in ghosts:
        	collides = collision_rect.colliderect(ghost.get_shape())
        	if collides and ghost in game_objects:
            	if self._renderer.is_kokoro_active():
                	game_objects.remove(ghost)
                	self._renderer.add_score(ScoreType.GHOST)
            	else:
                	if not self._renderer.get_won():
                    	self._renderer.kill_pacman()
</code></pre></div></div>

<p>Power-upy a počítání skóre</p>

<p>Skóre je v Pacmanovi udělování za snězení cookie, power-upu nebo ducha. Hodnoty se pro každý ze zmíněných objektů liší. Specifikujeme si je proto do enumu <em>ScoreType</em>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class ScoreType(Enum):
	COOKIE = 10
	POWERUP = 50
	GHOST = 400
</code></pre></div></div>

<p>V Pacmanovi existují speciální cookies, které mu udělí schopnost požírání duchů. V prvním díle jsme schopnost popsali původním japonským slovem “kokoro”, proto ji tak referencuji i v kódu. Vytvoříme novou třídu <em>Powerup</em> - v podstatě totožné s <em>Cookie</em>, jen o něco větší. Do ASCII bludiště použijeme pro power-up písmeno “O” a ve funkci <em>main</em> lehce modifikujeme kód pro zpracování volných míst v bludišti. Také upravíme funkci pro kolizi s cookies  <em>handle_cookie_pickup</em>, a zahrneme i novou třídu <em>Powerup</em>. Když Pacman sebere power-up, aktivujeme tuto schopnost na 15 sekund. Po sebrání cookie i powerupu ještě zavoláme funkci <em>add_score</em> s odpovídajícím typem skóre. Přidáme taky <em>set_won</em> pro konec hry, kdy hráč (Pacman) sebral všechny cookies.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Powerup(GameObject):
	def __init__ (self, in_surface, x, y):
    	super(). __init__ (in_surface, x, y, 8, (255, 255, 255), True)


# class GameRenderer
def add_powerup(self, obj: GameObject):
	self._game_objects.append(obj)
	self._powerups.append(obj)

def start_kokoro_timeout(self):
	pygame.time.set_timer(self._kokoro_end_event, 15000) # 15s

def activate_kokoro(self):
	self._kokoro_active = True
	self.set_current_mode(GhostBehaviour.SCATTER)
	self.start_kokoro_timeout()

 def _handle_events(self):
	for event in pygame.event.get():
    	if event.type == self._kokoro_end_event:
        	self._kokoro_active = False


# class Hero
def handle_cookie_pickup(self):
	collision_rect = pygame.Rect(self.x, self.y, self._size, self._size)
	cookies = self._renderer.get_cookies()
	powerups = self._renderer.get_powerups()
	game_objects = self._renderer.get_game_objects()
	cookie_to_remove = None
	for cookie in cookies:
    	collides = collision_rect.colliderect(cookie.get_shape())
    	if collides and cookie in game_objects:
        	game_objects.remove(cookie)
        	self._renderer.add_score(ScoreType.COOKIE)
        	cookie_to_remove = cookie

	if cookie_to_remove is not None:
    	    cookies.remove(cookie_to_remove)

	if len(self._renderer.get_cookies()) == 0:
    	    self._renderer.set_won()

	for powerup in powerups:
    	    collides = collision_rect.colliderect(powerup.get_shape())
    	    if collides and powerup in game_objects:
        	    if not self._renderer.is_kokoro_active():
            	    game_objects.remove(powerup)
            	    self._renderer.add_score(ScoreType.POWERUP)
            	    self._renderer.activate_kokoro()

# main
for powerup_space in pacman_game.powerup_spaces:
	translated = translate_maze_to_screen(powerup_space)
	powerup = Powerup(game_renderer, translated[0] + unified_size / 2, translated[1] + unified_size / 2)
	game_renderer.add_powerup(powerup)
</code></pre></div></div>

<h2 id="umělá-inteligence-duchů">Umělá inteligence duchů</h2>

<p>V originální hře se duchové chovají podle následujícího vzorce:</p>

<ol>
  <li>vlna - SCATTER 7 sekund, pak CHASE 20 sekund</li>
  <li>vlna - SCATTER 7 sekund, pak CHASE 20 sekund</li>
  <li>vlna - SCATTER 5 sekund, pak CHASE 20 sekund</li>
  <li>vlna - SCATTER 5 sekund, pak permanentně CHASE</li>
</ol>

<p>SCATTER je režim, ve kterém se duchové chovají náhodně a vybírají si náhodná místa v bludišti (ve skutečnosti mají ještě další specifičtější vzorce pro pohyb okolo překážek, ale do tyto složitější vzorce zde řešit nebudeme). CHASE je režim, ve kterém si duchové dají za cíl pozici hráče - využijeme pro to kód z prvního dílu a jen upravíme cílovou lokaci z náhodné na danou pozici hráče <em>get_hero_position</em>.</p>

<p>Tyto časovače máme v kódu od začátku článku, teď jen musíme přidat přepínání mezi režimy CHASE a SCATTER a kód pro zjištění trasy na pozici hráče.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># class GameRenderer
def tick(self, in_fps: int):
	self.handle_mode_switch()

 def handle_mode_switch(self):
	current_phase_timings = self._modes[self._current_phase]
	print(f"Current phase: {str(self._current_phase)}, current_phase_timings: {str(current_phase_timings)}")
	scatter_timing = current_phase_timings[0]
	chase_timing = current_phase_timings[1]

	if self._current_mode == GhostBehaviour.CHASE:
    	self._current_phase += 1
    	self.set_current_mode(GhostBehaviour.SCATTER)
	else:
    	self.set_current_mode(GhostBehaviour.CHASE)

	used_timing = scatter_timing if self._current_mode == GhostBehaviour.SCATTER else chase_timing
	pygame.time.set_timer(self._mode_switch_event, used_timing * 1000)

def get_hero_position(self):
	return self._hero.get_position() if self._hero != None else (0, 0)

def set_current_mode(self, in_mode: GhostBehaviour):
	self._current_mode = in_mode

def get_current_mode(self):
	return self._current_mode

def _handle_events(self):
	for event in pygame.event.get():
    	if event.type == self._mode_switch_event:
        	self.handle_mode_switch()

# class Ghost
 def request_path_to_player(self, in_ghost):
	player_position = translate_screen_to_maze(in_ghost._renderer.get_hero_position())
	current_maze_coord = translate_screen_to_maze(in_ghost.get_position())
	path = self.game_controller.p.get_path(current_maze_coord[1], current_maze_coord[0], player_position[1],player_position[0])

	new_path = [translate_maze_to_screen(item) for item in path]
	in_ghost.set_new_path(new_path)

def calculate_direction_to_next_target(self) -&gt; Direction:
	if self.next_target is None:
    	if self._renderer.get_current_mode() == GhostBehaviour.CHASE and not self._renderer.is_kokoro_active():
        	self.request_path_to_player(self)
    	else:
        	self.game_controller.request_new_random_path(self)
    	return Direction.NONE

	diff_x = self.next_target[0] - self.x
	diff_y = self.next_target[1] - self.y
	if diff_x == 0:
    	return Direction.DOWN if diff_y &gt; 0 else Direction.UP
	if diff_y == 0:
    	return Direction.LEFT if diff_x &lt; 0 else Direction.RIGHT

	if self._renderer.get_current_mode() == GhostBehaviour.CHASE and not self._renderer.is_kokoro_active():
    	self.request_path_to_player(self)
	else:
    	self.game_controller.request_new_random_path(self)
	return Direction.NONE
</code></pre></div></div>

<h2 id="animace-a-textury">Animace a textury</h2>

<p>Duchy a Pacmana upravíme tak, aby se místo dosavadních základních geometrických tvarů zobrazovali jako textury, respektive “sprites”. Do <em>MovableObject</em> třídy přidáme proměnnou image a upravíme funkci draw následovně:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># class MovableObject
def __init__ (self, in_surface, x, y, in_size: int, in_color=(255, 0, 0), is_circle: bool = False):
	self.image = pygame.image.load('images/ghost.png')

def draw(self):
	self.image = pygame.transform.scale(self.image, (32, 32))
	self._surface.blit(self.image, self.get_shape())
</code></pre></div></div>

<p>Referencované obrázky jsou dostupné na mém <a href="https://github.com/janjilecek/pacman_python_pygame">githubu</a>.</p>

<p>Každý duch bude mít jiný obrázek (specifikujeme ve funkci main) a když hráč aktivuje powerup, přepnou se duchové na texturu <em>fright</em>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># class Ghost
def __init__ (self, in_surface, x, y, in_size: int, in_game_controller, sprite_path="images/ghost_fright.png"):
	super(). __init__ (in_surface, x, y, in_size)
	self.game_controller = in_game_controller
	self.sprite_normal = pygame.image.load(sprite_path)
	self.sprite_fright = pygame.image.load("images/ghost_fright.png")

def draw(self):
	self.image = self.sprite_fright if self._renderer.is_kokoro_active() else self.sprite_normal
	super(Ghost, self).draw()
</code></pre></div></div>

<p><img src="https://create-it.cz/Blog/PublishingImages/Stranky/Pacman2/pacman1.gif" alt="" /></p>

<p>Animace otevírání a zavírání pusy Pacmana uděláme přes časovanou událost <em>_pakupaku_event</em>, která se volá každých 200ms (implementujeme v kapitole níže). Ta zneguje binární hodnotu mouth_open a podle toho se vykreslí jeden nebo druhý sprite Pacmana.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># class Hero
def __init__ (self, in_surface, x, y, in_size: int):
	super(). __init__ (in_surface, x, y, in_size, (255, 255, 0), False)
	self.last_non_colliding_position = (0, 0)
	self.open = pygame.image.load("images/paku.png")
	self.closed = pygame.image.load("images/man.png")
	self.image = self.open
	self.mouth_open = True

def draw(self):
	half_size = self._size / 2
	self.image = self.open if self.mouth_open else self.closed
	self.image = pygame.transform.rotate(self.image, self.current_direction.value)
	super(Hero, self).draw()


# class GameRenderer
def _handle_events(self):   
	if event.type == self._pakupaku_event:
    	    if self._hero is None: break
    	    self._hero.mouth_open = not self._hero.mouth_open
</code></pre></div></div>

<h2 id="koncové-stavy-hry-a-textové-ui">Koncové stavy hry a textové UI</h2>

<p>Zobrazení stavu hry je na konec jednoduché. Funkcí <em>display_text</em> vykreslíme text o dané velikosti na danou pozici. V hlavní tick funkci zobrazíme na základě výsledku <em>get_won</em> text pro výhru “YOU WON”. Pokud neexistuje objekt hráče - což mohlo nastat jen při “smrti”, když objekt zničíme - tak zobrazíme text “YOU DIED”.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># class GameRenderer
def display_text(self, text, in_position=(32, 0), in_size=30):
	font = pygame.font.SysFont('Arial', in_size)
	text_surface = font.render(text, False, (255, 255, 255))
	self._screen.blit(text_surface, in_position)

def set_won(self):
	self._won = True

def get_won(self):
	return self._won


def tick(self, in_fps: int):
	black = (0, 0, 0)

	self.handle_mode_switch()
	pygame.time.set_timer(self._pakupaku_event, 200) # open close mouth
	while not self._done:
    	for game_object in self._game_objects:
        	game_object.tick()
        	game_object.draw()

    	self.display_text(
        	f"[Score: {self._score}] [Lives: {self._lives}]")

    	if self._hero is None: self.display_text("YOU DIED", (self._width / 2 - 256, self._height / 2 - 256), 100)
    	if self.get_won(): self.display_text("YOU WON", (self._width / 2 - 256, self._height / 2 - 256), 100)
    	pygame.display.flip()
    	self._clock.tick(in_fps)
    	self._screen.fill(black)
    	self._handle_events()
</code></pre></div></div>

<p><img src="https://create-it.cz/Blog/PublishingImages/Stranky/Pacman2/pacman2.gif" alt="" /></p>
<h2 id="závěrem">Závěrem</h2>

<p>Ve finální části seriálu o vývoji hry Pac-Man v Pythonu jsme se zaměřili na implementaci několika důležitých prvků hry.</p>

<p>Nejprve jsme si ukázali, jak můžeme implementovat kolize s duchy a počítat skóre hráče. Poté jsme se zaměřili na umělou inteligenci duchů, která je důležitá pro realistický pohyb těchto objektů po mapě. Dále jsme se věnovali implementaci power-upů, které mohou hráčům pomoci zvýšit šance na vítězství.</p>

<p>V závěru jsme se podívali na koncové stavy hry a implementovali jsme animace a textury objektů hry. Díky těmto prvkům se nám podařilo vytvořit kompletní prototyp legendární hry Pac-Man. V případě nejasností je můj kód k dispozici na <a href="https://github.com/janjilecek/pacman_python_pygame/blob/main/pacman_final.py">githubu</a>.</p>

<p>Doufám, že vám tento seriál pomohl pochopit, jak vytvořit hru Pac-Man v Pythonu, a že jste se při implementaci dozvěděli něco nového. Pokud máte zájem o další informace o vývoji her v Pythonu, neváhejte se podívat na další <a href="https://create-it.cz/Blog/Stranky/hra-v-pythonu.aspx">články</a> na našem webu.</p>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Creating Pac-Man clone in Python in 300 lines of code or less— Part 1]]></title>
    <link href="https://blog.jilecek.cz/blog/2022/12/21/creating-pac-man-clone-in-python-in-300-lines-of-c/"/>
    <updated>2022-12-21T12:00:00+00:00</updated>
    <id>https://blog.jilecek.cz/blog/2022/12/21/creating-pac-man-clone-in-python-in-300-lines-of-c/</id>
    <content type="html"><![CDATA[<p>Pac-Man is a classic platform game that is probably known by everyone today. The name “Pac-Man” comes from the Japanese word “paku,” which means opening and closing the mouth. The creator, Toru Iwatani, was inspired by a Japanese story about a creature that protects children from monsters by eating them. In creating the game, he used key words from the story as a springboard, and the verb “eat” became the foundation of everything.</p>

<!-- more -->

<p><img src="https://blog.jilecek.cz/images/creating-pac-man-clone-in-python-in-300-lines-of-c-02.jpg" alt="" />
You will have created this with me by the end of this article!
The monsters are represented as four ghosts that attack the player in successive waves, similar to Space Invaders. Each ghost also has a unique personality. In the story, there is one more important element, the concept of life force “kokoro,” which allowed the creatures to eat monsters. In the game, this energy is represented as power-up cookies that give Pac-Man a short-term ability to eat monsters.
In the tutorial, I will first guide you through basic setup, then we will create game objects for the maze wall, Pac-Man and ghosts, ensure pathfinding through the maze, give the ghosts random movement, implement arrow controls for the player, and finally, place food in the form of cookies throughout the maze. I will accompany everything with images and GIFs for better representation.</p>
<h2 id="-basic_settings">» basic_settings</h2>
<p>The resulting game has approximately 300 lines of code, so I am only listing the most important parts here. The full code is available <a href="https://github.com/janjilecek/pacman_python_pygame/blob/main/pacman.py">on my GitHub repository</a>. The first step is to install the necessary packages. We will need pygame, numpy, and tcod. Install all of them using the pip tool (you can find out how to do this in the article about Python applications). If you are using an IDE like PyCharm (I recommend it), the installation will occur after clicking on the missing package error message.
First, we will create a game window, in a similar way to the previous <a href="https://medium.com/itnext/creating-space-invaders-clone-in-pygame-ea0f5336c677">tutorial on the Space Invaders game</a> (which had only 100 lines). Here, I will prepare the parameters for specifying the window size, game name, refresh rate, and several data fields that will hold references to game objects and the player. The tick function iteratively goes through all the game objects and calls their internal logic and rendering. Then all that remains is to redraw the entire game area and handle input events such as mouse clicks and keyboard input. The _handle_events function will serve this purpose.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import pygame # import packages (install with "pip install pygame" in cmd)  
import numpy as np  
import tcod  
class GameRenderer:  
    def __init__(self, in_width: int, in_height: int):  
        pygame.init()  
        self._width = in_width  
        self._height = in_height  
        self._screen = pygame.display.set_mode((in_width, in_height))  
        pygame.display.set_caption('Pacman')  
        self._clock = pygame.time.Clock()  
        self._done = False  
        self._game_objects = []  
        self._walls = []  
        self._cookies = []  
        self._hero: Hero = None  
    def tick(self, in_fps: int):  
        black = (0, 0, 0)  
        while not self._done:  
            for game_object in self._game_objects:  
                game_object.tick()  
                game_object.draw()  
            pygame.display.flip()  
            self._clock.tick(in_fps)  
            self._screen.fill(black)  
            self._handle_events()  
         print("Game over")  
    def add_game_object(self, obj: GameObject):  
        self._game_objects.append(obj)  
    def add_wall(self, obj: Wall):  
        self.add_game_object(obj)  
        self._walls.append(obj)  
    def _handle_events(self):  
        pass # we'll implement this later
</code></pre></div></div>
<h2 id="-parent_game_object">» parent_game_object</h2>
<p>Next, I am creating a parent game object called GameObject, from which other classes will inherit functionality. In the game, we will have objects for the wall (Wall), Pac-Man (Hero), ghosts (Ghost), and cookies (Cookie). For the movable game entities mentioned above, I will later create a class called MovableObject, which will be an extension of the GameObject class with movement functions.
During object initialization, I specify its color, shape, and position. Each object also has a reference to the rendering surface _surface, so that it can take care of its own rendering on the main surface. We have a function called draw for this purpose, which is called by the previously created GameRenderer for each game object. Depending on the is_circle parameter, the object is either rendered as a circle or as a rectangle (in our case, I am using a square with slightly rounded corners for the walls and a circle for Pac-Man and cookies).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class GameObject:  
    def __init__(self, in_surface, x, y,  
                 in_size: int, in_color=(255, 0, 0),  
                 is_circle: bool = False):  
        self._size = in_size  
        self._renderer: GameRenderer = in_surface  
        self._surface = in_surface._screen  
        self.y = y  
        self.x = x  
        self._color = in_color  
        self._circle = is_circle  
        self._shape = pygame.Rect(self.x, self.y, in_size, in_size)  
    def draw(self):  
        if self._circle:  
            pygame.draw.circle(self._surface,  
                               self._color,  
                               (self.x, self.y),  
                               self._size)  
        else:  
            rect_object = pygame.Rect(self.x, self.y, self._size, self._size)  
            pygame.draw.rect(self._surface,  
                             self._color,  
                             rect_object,  
                             border_radius=4)  
    def tick(self):  
        pass
</code></pre></div></div>
<p>Creating the wall class will be simple. I choose the color blue for the walls according to the original Pac-Man (color parameter — Blue 255, rest 0).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Wall(GameObject):  
    def __init__(self, in_surface, x, y, in_size: int, in_color=(0, 0, 255)):  
        super().__init__(in_surface, x * in_size, y * in_size, in_size, in_color)
</code></pre></div></div>
<p>The code for rendering and the object for the walls is prepared. When writing, make sure that the Wall and GameObject classes are above the GameRenderer class so that the class “sees” them. The next step is to render the maze on the screen. But before that, we have to create one helper class.</p>
<h2 id="-the_game_controller_class">» the_game_controller_class</h2>
<p>I will save the maze in ASCII characters in a variable in the new PacmanGameController class. I will use the original maze size — 28x31 tiles. Later, I will have to ensure that the ghosts can correctly find their way through the maze and potentially find the player. First, I will read the maze as characters and convert it to a matrix of ones and zeros, where the wall is zero and the passable space is one. These values serve the pathfinding algorithm as a so-called cost function. Zero signifies an infinite cost of passage, so items in the array marked this way will not be considered passable. Note the reachable_spaces array, which holds the passable parts of the maze. But more on that later, first I have to prepare the class structures. You can copy the maze in ASCII form from <a href="https://github.com/janjilecek/pacman_python_pygame/blob/main/pacman.py">my GitHub</a>. In the character notation, I used “X” for the wall, “P” for Pac-Man, and “G” for the ghost.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class PacmanGameController:  
    def __init__(self):  
        self.ascii_maze = [  
            "XXXXXXXXXXXXXXXXXXXXXXXXXXXX",  
            "XP           XX            X",  
            "X XXXX XXXXX XX XXXXX XXXX X",  
            "X XXXX XXXXX XX XXXXX XXXX X",  
            "X XXXX XXXXX XX XXXXX XXXX X",  
            "X                          X",  
            "X XXXX XX XXXXXXXX XX XXXX X",  
            "X XXXX XX XXXXXXXX XX XXXX X",  
            "X      XX    XX    XX      X",  
            "XXXXXX XXXXX XX XXXXX XXXXXX",  
            "XXXXXX XXXXX XX XXXXX XXXXXX",  
            "XXXXXX XX          XX XXXXXX",  
            "XXXXXX XX XXXXXXXX XX XXXXXX",  
            "XXXXXX XX X   G  X XX XXXXXX",  
            "          X G    X          ",  
            "XXXXXX XX X   G  X XX XXXXXX",  
            # shortened for article, full ascii on my github  
            "XXXXXXXXXXXXXXXXXXXXXXXXXXXX",  
        ]  
        self.numpy_maze = []  
        self.cookie_spaces = []  
        self.reachable_spaces = []  
        self.ghost_spawns = []  
        self.size = (0, 0)  
        self.convert_maze_to_numpy()  
        #self.p = Pathfinder(self.numpy_maze) # use later  
    def convert_maze_to_numpy(self):  
        for x, row in enumerate(self.ascii_maze):  
            self.size = (len(row), x + 1)  
            binary_row = []  
            for y, column in enumerate(row):  
                if column == "G":  
                    self.ghost_spawns.append((y, x))  
                if column == "X":  
                    binary_row.append(0)  
                else:  
                    binary_row.append(1)  
                    self.cookie_spaces.append((y, x))  
                    self.reachable_spaces.append((y, x))  
            self.numpy_maze.append(binary_row)
</code></pre></div></div>
<h2 id="-rendering_the_maze">» rendering_the_maze</h2>
<p>Everything necessary for rendering the maze is prepared, so all that remains is to create instances of our PacmanGameController classes, go through the 2D array with wall positions, and create a Wall object at these locations (I am using the add_wall function, which is not shown here, again, take a look at the full code <a href="https://github.com/janjilecek/pacman_python_pygame/blob/main/pacman.py">on my GitHub</a>). I set the refresh rate to 120 frames per second.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>if __name__ == "__main__":  
    unified_size = 32  
    pacman_game = PacmanGameController()  
    size = pacman_game.size  
    game_renderer = GameRenderer(size[0] * unified_size, size[1] * unified_size)  
    for y, row in enumerate(pacman_game.numpy_maze):  
        for x, column in enumerate(row):  
            if column == 0:  
                game_renderer.add_wall(Wall(game_renderer, x, y, unified_size))  
    game_renderer.tick(120)
</code></pre></div></div>
<p><img src="https://blog.jilecek.cz/images/creating-pac-man-clone-in-python-in-300-lines-of-c-03.jpg" alt="" /></p>
<h2 id="-lets_add_ghosts">» let’s_add_ghosts!</h2>
<p>In the original Pac-Man, there were four ghosts named Blinky, Pinky, Inky, and Clyde, each with their own individual character and abilities. The concept of the game is based on a Japanese fairy tale (more <a href="https://www.gamedeveloper.com/design/the-pac-man-dossier">here</a> and <a href="https://gameinternals.com/understanding-pac-man-ghost-behavior">here</a>) and the original names in Japanese also suggest their abilities (e.g. Pinky has the Japanese name Thief, Blinky is Shadow). However, for our game, we will not go into such detail and each ghost will use only the basic behavioral loop like in the original — i.e. the Chase, Scatter, and Frightened modes. We will describe and process these AI modes in the second part.
The ghost class will be simple, inheriting most of its behavior from the parent MovableObject class (check my <a href="https://github.com/janjilecek/pacman_python_pygame/blob/main/pacman.py">GitHub</a>, that class is slightly more complex and includes logic for movement in four directions, following a route, and checking for collisions with walls).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Ghost(MovableObject):  
    def __init__(self, in_surface, x, y, in_size: int, in_game_controller, in_color=(255, 0, 0)):  
        super().__init__(in_surface, x, y, in_size, in_color, False)  
        self.game_controller = in_game_controller
</code></pre></div></div>
<p>I will add RGB values for the colors of each ghost to the PacmanGameController class and generate four colorful ghosts in the main function. I will also prepare a static function for coordinate conversion, which simply converts maze coordinates (e.g. x=16 y=16 is approximately the center of the maze, and multiplying by the size of the cell, or tile, gives me a coordinate on the game surface in pixels).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># inPacmanGameController  
self.ghost_colors = [  
        (255, 184, 255),  
        (255, 0, 20),  
        (0, 255, 255),  
        (255, 184, 82)  
    ]  
# in main  
for i, ghost_spawn in enumerate(pacman_game.ghost_spawns):  
    translated = translate_maze_to_screen(ghost_spawn)  
    ghost = Ghost(game_renderer, translated[0], translated[1], unified_size, pacman_game,  
                  pacman_game.ghost_colors[i % 4])  
    game_renderer.add_game_object(ghost)  
# General functions for coordinate conversion, place at the beginning of the code  
def translate_screen_to_maze(in_coords, in_size=32):  
    return int(in_coords[0] / in_size), int(in_coords[1] / in_size)  
def translate_maze_to_screen(in_coords, in_size=32):  
    return in_coords[0] * in_size, in_coords[1] * in_size
</code></pre></div></div>
<p>At this stage, the four ghosts will be rendered in the maze upon launching the game. We now want to make them move.</p>
<h2 id="-maze_pathfinding">» maze_pathfinding</h2>
<p>Now comes the possibly most complex part. Finding a path in a 2D space or graph is a difficult problem. Implementing an algorithm to solve such a problem would take another article, so we will use a ready-made solution. The most efficient algorithm for pathfinding is the A* algorithm. This is provided by the tcod package that we installed at the beginning.
In order to move the ghosts, I will create a class called <code class="language-plaintext highlighter-rouge">Pathfinder</code>. In the constructor, I will initialize a numpy array with the cost of passing through (an array of ones and zeros described earlier) and create a class variable <code class="language-plaintext highlighter-rouge">pf</code> which will hold an instance of the A* pathfinder. The <code class="language-plaintext highlighter-rouge">get_path</code> function will then calculate and return the path as a series of steps in an array when called with coordinates in the maze (from where, to where).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Pathfinder:  
    def __init__(self, in_arr):  
        cost = np.array(in_arr, dtype=np.bool_).tolist()  
        self.pf = tcod.path.AStar(cost=cost, diagonal=0)  
    def get_path(self, from_x, from_y, to_x, to_y) -&gt; object:  
        res = self.pf.get_path(from_x, from_y, to_x, to_y)  
        return [(sub[1], sub[0]) for sub in res]
</code></pre></div></div>
<p>I will now add a section to the main function to demonstrate pathfinding. I choose the starting coordinates [1,1] and the destination of the route [24,24]. This is optional code.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># draw path - optional  
red = (255, 0, 0)  
green = (0, 255, 0)  
_from = (1, 1)  
_to = (24, 24)  
path_array = pacman_game.p.get_path(_from[1], _from[0], _to[1], _to[0])  
print(path_array)  
# [(1, 2), (1, 3), (1, 4), (1, 5), (2, 5), (3, 5), (4, 5), (5, 5), (6, 5), (6, 6), (6, 7) ...  
white = (255, 255, 255)  
for path in path_array:  
    game_renderer.add_game_object(Wall(game_renderer, path[0], path[1], unified_size, white))  
from_translated = translate_maze_to_screen(_from)  
game_renderer.add_game_object(  
    GameObject(game_renderer, from_translated[0], from_translated[1], unified_size, red))  
to_translated = translate_maze_to_screen(_to)  
game_renderer.add_game_object(  
    GameObject(game_renderer, to_translated[0], to_translated[1], unified_size, green))
</code></pre></div></div>
<p>In the game, rendering the shortest route looks like this:
<img src="https://blog.jilecek.cz/images/creating-pac-man-clone-in-python-in-300-lines-of-c-04.jpg" alt="" /></p>
<h2 id="-randomized_ghost_movement">» randomized_ghost_movement</h2>
<p>Now, we are going to create a new function in the PacmanGameController class for selecting a random point from the reachable_spaces array. Each ghost will use this function after it reaches its destination. This way, the ghosts will simply choose a path from their current position in the maze to a random destination indefinitely. We will implement more complex behavior, such as chasing and fleeing the player, in the next part.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def request_new_random_path(self, in_ghost: Ghost):  
    random_space = random.choice(self.reachable_spaces)  
    current_maze_coord = translate_screen_to_maze(in_ghost.get_position())  
    path = self.p.get_path(current_maze_coord[1], current_maze_coord[0], random_space[1],  
                           random_space[0])  
    test_path = [translate_maze_to_screen(item) for item in path]  
    in_ghost.set_new_path(test_path)
</code></pre></div></div>
<p>In the Ghost class, we add new logic for following a path. The function reached_target is called every frame and checks whether the ghost has already reached its target. If it has, it determines in which direction the next step of the path through the maze is and starts changing its position either up, down, left, or right (the logic for movement is called in the parent MovableObject class).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def reached_target(self):  
    if (self.x, self.y) == self.next_target:  
        self.next_target = self.get_next_location()  
    self.current_direction = self.calculate_direction_to_next_target()  
def set_new_path(self, in_path):  
    for item in in_path:  
        self.location_queue.append(item)  
    self.next_target = self.get_next_location()  
def calculate_direction_to_next_target(self) -&gt; Direction:  
    if self.next_target is None:  
        self.game_controller.request_new_random_path(self)  
        return Direction.NONE  
    diff_x = self.next_target[0] - self.x  
    diff_y = self.next_target[1] - self.y  
    if diff_x == 0:  
        return Direction.DOWN if diff_y &gt; 0 else Direction.UP  
    if diff_y == 0:  
        return Direction.LEFT if diff_x &lt; 0 else Direction.RIGHT  
    self.game_controller.request_new_random_path(self)  
    return Direction.NONE  
def automatic_move(self, in_direction: Direction):  
    if in_direction == Direction.UP:  
        self.set_position(self.x, self.y - 1)  
    elif in_direction == Direction.DOWN:  
        self.set_position(self.x, self.y + 1)  
    elif in_direction == Direction.LEFT:  
        self.set_position(self.x - 1, self.y)  
    elif in_direction == Direction.RIGHT:  
        self.set_position(self.x + 1, self.y)
</code></pre></div></div>
<p>The ghosts are now created at the positions indicated by the letter “G” in the original ASCII maze and begin to search for a random path. I have locked three ghosts in the cage — as in the original Pacman, they will be released one by one — and one is wandering through the maze:
<img src="https://blog.jilecek.cz/images/creating-pac-man-clone-in-python-in-300-lines-of-c-05.jpg" alt="" /></p>
<h2 id="-player_controls">» player_controls</h2>
<p>To add player functionality, I will create a class called Hero. Most of the logic for controlling both the player and the ghosts is handled in the MovableObject class, so we only need a few functions to specify the behavior of the player. In the original Pacman, the player can move in four directions, controlled by the arrow keys. If no arrow key is pressed, the player will continue in the last valid direction. If a key is pressed in a direction that the player cannot move, the direction is saved and used at the next available turn. I will replicate this behavior in our game and also added Pacman’s ability to teleport from one end of the maze to the other — I will just check if the player is outside the game area on the left or right side and set their position to the opposite side of the maze accordingly. Pacman also has a modified rendering function, we need to render it with half the size it would normally take up as a square (using pygame.rect).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Hero(MovableObject):  
    def __init__(self, in_surface, x, y, in_size: int):  
        super().__init__(in_surface, x, y, in_size, (255, 255, 0), False)  
        self.last_non_colliding_position = (0, 0)  
    def tick(self):  
        # TELEPORT  
        if self.x &lt; 0:  
            self.x = self._renderer._width  
        if self.x &gt; self._renderer._width:  
            self.x = 0  
        self.last_non_colliding_position = self.get_position()  
        if self.check_collision_in_direction(self.direction_buffer)[0]:  
            self.automatic_move(self.current_direction)  
        else:  
            self.automatic_move(self.direction_buffer)  
            self.current_direction = self.direction_buffer  
        if self.collides_with_wall((self.x, self.y)):  
            self.set_position(self.last_non_colliding_position[0], self.last_non_colliding_position[1])  
        self.handle_cookie_pickup()  
    def automatic_move(self, in_direction: Direction):  
        collision_result = self.check_collision_in_direction(in_direction)  
        desired_position_collides = collision_result[0]  
        if not desired_position_collides:  
            self.last_working_direction = self.current_direction  
            desired_position = collision_result[1]  
            self.set_position(desired_position[0], desired_position[1])  
        else:  
            self.current_direction = self.last_working_direction  
    def handle_cookie_pickup(self):  
        collision_rect = pygame.Rect(self.x, self.y, self._size, self._size)  
        cookies = self._renderer.get_cookies()  
        game_objects = self._renderer.get_game_objects()  
        for cookie in cookies:  
            collides = collision_rect.colliderect(cookie.get_shape())  
            if collides and cookie in game_objects:  
                game_objects.remove(cookie)  
    def draw(self):  
        half_size = self._size / 2  
        pygame.draw.circle(self._surface, self._color, (self.x + half_size, self.y + half_size), half_size)
</code></pre></div></div>
<p>I instantiate the Hero class at the end of the main function. I set the position to the coordinates [1,1] — unified_size is the size of one tile. We also need to add processing of input events to the GameRenderer class so that we can control the game character.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># in GameRenderer class  
def add_hero(self, in_hero):  
        self.add_game_object(in_hero)  
        self._hero = in_hero  
def _handle_events(self):  
    for event in pygame.event.get():  
        if event.type == pygame.QUIT:  
            self._done = True  
    pressed = pygame.key.get_pressed()  
    if pressed[pygame.K_UP]:  
        self._hero.set_direction(Direction.UP)  
    elif pressed[pygame.K_LEFT]:  
        self._hero.set_direction(Direction.LEFT)  
    elif pressed[pygame.K_DOWN]:  
        self._hero.set_direction(Direction.DOWN)  
    elif pressed[pygame.K_RIGHT]:  
        self._hero.set_direction(Direction.RIGHT)  
# at the end of main function  
pacman = Hero(game_renderer, unified_size, unified_size, unified_size)  
game_renderer.add_hero(pacman)  
game_renderer.tick(120)
</code></pre></div></div>
<p>After launching the game now, we can control the player — Pacman!
<img src="https://blog.jilecek.cz/images/creating-pac-man-clone-in-python-in-300-lines-of-c-06.jpg" alt="" /></p>
<h2 id="-adding_cookies">» adding_cookies</h2>
<p>It wouldn’t be Pacman without cookies in the maze. From a gameplay perspective, they determine the degree of exploration of the world and some cookies even reverse the abilities of ghosts and Pacman. <strong>They are therefore the ultimate reward for players and the main indicator of their progress through levels. In today’s games, behavior that the game designer wants to encourage in the player is usually rewarded. A beautiful example is this year’s Elden Ring, where anyone who explores every corner of the world is rewarded. The more dangerous and remote, the greater the reward.</strong> On the other hand, games like the modern Assassin’s Creed support task completion, so you have the feeling while playing that you are working, not playing.
Adding cookies will be the easiest thing in the entire tutorial, and that’s why I saved it for the end, as the cherry on top. I will create a class called Cookie. Its instance will always be four pixels in size, yellow in color, and circular in shape. In the main function, I will create cookies on all tiles that we saved in the cookie_spaces array (the same as reachable_spaces) at the beginning. I will add a function called handle_cookie_pickup to the player, in which I constantly check whether the player is colliding with any cookie. If that is the case, I will remove the cookie from the array and it will no longer be rendered.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Cookie(GameObject):  
    def __init__(self, in_surface, x, y):  
        super().__init__(in_surface, x, y, 4, (255, 255, 0), True)  
# in GameRenderer class   
def add_cookie(self, obj: GameObject):  
        self._game_objects.append(obj)  
        self._cookies.append(obj)  
# in Hero class  
def handle_cookie_pickup(self):  
    collision_rect = pygame.Rect(self.x, self.y, self._size, self._size)  
    cookies = self._renderer.get_cookies()  
    game_objects = self._renderer.get_game_objects()  
    for cookie in cookies:  
        collides = collision_rect.colliderect(cookie.get_shape())  
        if collides and cookie in game_objects:  
            game_objects.remove(cookie)  
# in main function:  
for cookie_space in pacman_game.cookie_spaces:  
    translated = translate_maze_to_screen(cookie_space)  
    cookie = Cookie(game_renderer, translated[0] + unified_size / 2, translated[1] + unified_size / 2)  
    game_renderer.add_cookie(cookie)
</code></pre></div></div>
<p>And now for the result of our efforts:
<img src="https://blog.jilecek.cz/images/creating-pac-man-clone-in-python-in-300-lines-of-c-07.jpg" alt="" />
A little interesting fact for the end — in the original game, Pacman stops for one frame after eating each cookie, so the ghosts can more easily catch him at the beginning of the game when the field is still full. In the next part, we will implement similar game mechanics and you can also look forward to artificial intelligence for the ghosts, score tracking, sounds, animations, textures, power-ups, screen-shake effects, lives, and end game states.
If you’ve found my article interesting, you may be also interested in my game development course for beginners:
<a href="https://www.udemy.com/course/make-a-3d-game-in-unity-2020-from-scratch-with-free-assets/?referralCode=8B96F6C67527AEEA39D9">https://www.udemy.com/course/make-a-3d-game-in-unity-2020-from-scratch-with-free-assets/?referralCode=8B96F6C67527AEEA39D9</a>
<img src="https://blog.jilecek.cz/images/creating-pac-man-clone-in-python-in-300-lines-of-c-08.jpg" alt="" /></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Jak vytvořit Pacmana v Pythonu - 1. část]]></title>
    <link href="https://blog.jilecek.cz/blog/2022/11/30/Pacman1/"/>
    <updated>2022-11-30T12:00:00+00:00</updated>
    <id>https://blog.jilecek.cz/blog/2022/11/30/Pacman1/</id>
    <content type="html"><![CDATA[<p><img src="https://create-it.cz/Blog/PublishingImages/Titulni/2022/1pacman.jpg" alt="" /></p>

<p>Pacman je kultovní plošinovka, kterou zná pravděpodobně každý. Jméno “Pac-man” pochází z japonského slova “paku”, které označuje otevírání a zavírání úst. Tvůrce Toru Iwatani se inspiroval u japonské pohádky o bytosti, která ochraňuje děti před monstry tím, že monstra požírá. Při tvorbě hry použil jako odrazový můstek klíčová slova z příběhu, a sloveso “jíst” se stalo základem všeho.</p>

<!-- more -->

<p>Monstra jsou znázorněna jako čtyři duchové, kteří na hráče útočí v postupných vlnách, podobně jako ve Space Invaders. Každý z duchů má také unikátní osobnost. V pohádce je ještě jeden důležitý element, totiž koncept životní síly “kokoro”, která bytosti umožňovala požírat monstra. Ve hře je tato energie znázorněna jako power-up cookiesky, které Pacmanovi uděluji krátkodobou schopnost požírat monstra.</p>

<p>V návodu vás nejprve provedu základním nastavením, pak vytvoříme herní objekty pro zeď bludiště, Pacmana a duchy, zajistíme hledání cesty bludištěm, duchům přidáme náhodný pohyb, u hráče implementujeme ovládání šipkami a nakonec do bludiště rozmístíme jídlo ve formě cookies. Vše budu doprovázet obrázky a gify pro lepší znázornění.</p>

<h2 id="základní-nastavení">Základní nastavení</h2>

<p>Výsledná hra má přibližně 300 řádků kódu, proto zde uvádím pouze nejdůležitější části. Kód v úplné podobě je dostupný na <a href="https://github.com/janjilecek/pacman_python_pygame/blob/main/pacman.py">mém github repozitáři</a>. Prvním krokem je instalace potřebných balíčků. Budeme potřebovat <em>pygame, numpy</em> a <em>tcod</em>. Nainstalujte si všechny přes nástroj pip (jak na to najdete <a href="https://create-it.cz/Blog/Stranky/Python-aplikace.aspx">v článku o Python aplikacích</a>). Pokud používáte vývojové prostředí jako např. PyCharm (doporučuji), instalace proběhne po kliknutí na hlášku o chybějícím balíčku.</p>

<p>Nejprve si vytvoříme herní okno, podobným způsobem jako v <a href="https://create-it.cz/Blog/Stranky/hra-v-pythonu.aspx">předchozím návodu na hru Space Invaders</a> (ta měla pouhých 100 řádků). Zde připravím parametry pro specifikaci velikosti okna, název hry, obnovovací frekvenci a několik datových polí, které budou držet reference na herní objekty a hráče. Funkce <em>tick</em> všechny herní objekty opakovaně prochází a volá jejich vnitřní logiku a vykreslování. Pak zbývá už jen překreslit celou herní plochu a zajistit zpracování vstupních událostí, jako jsou kliknutí myši a vstup z klávesnice. K tomu bude sloužit funkce <em>_handle_events</em>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import pygame # importy balíků
import numpy as np
import tcod

class GameRenderer:
    def __init__ (self, in_width: int, in_height: int):
        pygame.init()
        self._width = in_width
        self._height = in_height
        self._screen = pygame.display.set_mode((in_width, in_height))
        pygame.display.set_caption('Pacman')
        self._clock = pygame.time.Clock()
        self._done = False
        self._game_objects = []
        self._walls = []
        self._cookies = []
        self._hero: Hero = None

    def tick(self, in_fps: int):
        black = (0, 0, 0)
        while not self._done:
            for game_object in self._game_objects:
                game_object.tick()
                game_object.draw()

            pygame.display.flip()
            self._clock.tick(in_fps)
            self._screen.fill(black)
            self._handle_events()
        print("Game over")

    def add_game_object(self, obj: GameObject):
        self._game_objects.append(obj)


    def add_wall(self, obj: Wall):
        self.add_game_object(obj)
        self._walls.append(obj)

    def _handle_events(self):
        pass # dodelame
</code></pre></div></div>

<p>Vytvoření třídy pro zeď pak bude vypadat jednoduše. Barvu pro zdi volím modrou podle originálního Pacmana (parametr color - Blue 255, zbytek 0). </p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Wall(GameObject):
	def __init__ (self, in_surface, x, y, in_size: int, in_color=(0, 0, 255)):
		super(). __init__ (in_surface, x * in_size, y * in_size, in_size, in_color)
</code></pre></div></div>

<p>Kód pro vykreslování a objekt pro zdi máme připraven. Při psaní se ujistěte, že třídy <em>Wall</em> a <em>GameObject</em> jsou nad třídou <em>GameRenderer</em>, aby je třída “viděla”. Dalším krokem je vykreslení bludiště na obrazovku. Ale ještě předtím musíme vytvořit jednu pomocnou třídu.</p>

<h2 id="třída-game-controller">Třída game controller</h2>

<p>Bludiště ve formě ASCII znaků uložím do proměnné v nové třídě <em>PacmanGameController</em>. Použiju velikost bludiště jako v originále - 28x31 dlaždic. Později budu muset zajistit, aby duchové mohli správně hledat cestu v bludišti a případně i najít hráče. Bludiště nejprve načtu jako znaky a převedu ho na pole jedniček a nul, kde zeď bude nula a průchodný prostor bude jedna. Tyto hodnoty slouží algoritmu hledání cesty jako tzv. cost funkce. Nula značí nekonečnou cenu průchodu, proto nebudou takto označené položky pole považovány za průchodné. Všimněte si pole <em>reachable_spaces</em>, které drží průchozí části bludiště. K tomu ale až později, jako první musím připravit struktury třídy. Bludiště v ASCII podobě můžete zkopírovat z mého <a href="https://github.com/janjilecek/pacman_python_pygame/blob/main/pacman.py">githubu</a>. Ve znakovém zápisu jsem použil “X” pro zeď, “P” pro Pacmana a “G” pro ducha. </p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class PacmanGameController:
    def __init__ (self):
        self.ascii_maze = [
            "XXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            "XP XX X",
            "X XXXX XXXXX XX XXXXX XXXX X",
            "X XXXX XXXXX XX XXXXX XXXX X",
            "X XXXX XXXXX XX XXXXX XXXX X",
            "X X",
            "X XXXX XX XXXXXXXX XX XXXX X",
            "X XXXX XX XXXXXXXX XX XXXX X",
            "X XX XX XX X",
            "XXXXXX XXXXX XX XXXXX XXXXXX",
            "XXXXXX XXXXX XX XXXXX XXXXXX",
            "XXXXXX XX XX XXXXXX",
            "XXXXXX XX XXXXXXXX XX XXXXXX",
            "XXXXXX XX X G X XX XXXXXX",
            " X G X ",
            "XXXXXX XX X G X XX XXXXXX",
            # zkraceno pro clanek
            "XXXXXXXXXXXXXXXXXXXXXXXXXXXX",
        ]

        self.numpy_maze = []
        self.cookie_spaces = []
        self.reachable_spaces = []
        self.ghost_spawns = []

        self.size = (0, 0)
        self.convert_maze_to_numpy()
        #self.p = Pathfinder(self.numpy_maze) # pouzijeme pozdeji


    def convert_maze_to_numpy(self):
        for x, row in enumerate(self.ascii_maze):
            self.size = (len(row), x + 1)
            binary_row = []
            for y, column in enumerate(row):
                if column == "G":
                    self.ghost_spawns.append((y, x))

                if column == "X":
                    binary_row.append(0)
                else:
                    binary_row.append(1)
                    self.cookie_spaces.append((y, x))
                    self.reachable_spaces.append((y, x))
            self.numpy_maze.append(binary_row)
</code></pre></div></div>

<h2 id="vykreslení-bludiště">Vykreslení bludiště</h2>

<p>Vše nutné pro vykreslení bludiště je připraveno, takže už jen stačí vytvořit instance našich tříd <em>PacmanGameController,</em> projít 2D pole s pozicemi zdí a na těchto místech vytvořit objekt <em>Wall</em> (používám neuvedenou funkci <em>add_wall</em>, opět nahlédněte do úplného kódu na mém <a href="https://github.com/janjilecek/pacman_python_pygame/blob/main/pacman.py">githubu</a>). Obnovovací frekvenci nastavuji na 120 snímků za vteřinu. </p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>if __name__ == " __main__":
    unified_size = 32
    pacman_game = PacmanGameController()
    size = pacman_game.size
    game_renderer = GameRenderer(size[0] * unified_size, size[1] * unified_size)

    for y, row in enumerate(pacman_game.numpy_maze):
        for x, column in enumerate(row):
            if column == 0:
                game_renderer.add_wall(Wall(game_renderer, x, y, unified_size))

    game_renderer.tick(120)
</code></pre></div></div>

<p>  <img src="https://create-it.cz/Blog/PublishingImages/Stranky/Pacman1/unnamed-3.png" alt="pacman" /></p>

<h2 id="přidání-duchů">Přidání duchů</h2>

<p>V originálním Pacmanovi byli čtyři duchové jmény Blinky, Pinky, Inky a Clyde, každý s individuálním charakterem a schopnostmi. Koncept hry je založen na japonské pohádce (více <a href="https://www.gamedeveloper.com/design/the-pac-man-dossier">zde</a> a <a href="https://gameinternals.com/understanding-pac-man-ghost-behavior">zde</a>) a originální jména v japonštině i naznačují jejich schopnosti (např. Pinky má japonské jméno Lupič, Blinky je zase Stín). Pro naši hru ale nebudeme zacházet do takových detailů a každý z duchů bude používat jen základní behaviorální smyčku jako v originále - tzn. módy <em>Chase</em>, <em>Scatter</em> a <em>Frightened.</em> Tyto AI módy si popíšeme a zpracujeme ve druhém díle.</p>

<p>Třída pro ducha bude jednoduchá, většinu chování zdědí od rodičovské třídy <em>MovableObject</em> (nahlédněte na <a href="https://github.com/janjilecek/pacman_python_pygame/blob/main/pacman.py">github</a>, ta třída je o něco složitější a obsahuje logiku pro pohyb ve čtyřech směrech, následování trasy a ověřování kolize se zdí). </p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Ghost(MovableObject):
    def __init__ (self, in_surface, x, y, in_size: int, in_game_controller, in_color=(255, 0, 0)):
        super(). __init__ (in_surface, x, y, in_size, in_color, False)
        self.game_controller = in_game_controller
</code></pre></div></div>

<p> </p>

<p>Do třídy <em>PacmanGameController</em> přidám hodnoty RGB barev jednotlivých duchů a ve funkci <em>main</em> vygeneruji čtyři barevné duchy. Připravím si také statickou funkci pro převod souřadnic, která jednoduše převede souřadnice bludiště (např. x=16 y=16 je přibližně střed bludiště, a pronásobením s velikostí buňky, neboli tile, dostanu souřadnici na herní ploše v pixelech). </p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># v PacmanGameController
self.ghost_colors = [
        (255, 184, 255),
        (255, 0, 20),
        (0, 255, 255),
        (255, 184, 82)
    ]

# ve funkci main
for i, ghost_spawn in enumerate(pacman_game.ghost_spawns):
    translated = translate_maze_to_screen(ghost_spawn)
    ghost = Ghost(game_renderer, translated[0], translated[1], unified_size, pacman_game,
                  pacman_game.ghost_colors[i % 4])
    game_renderer.add_game_object(ghost)

# obecné funkce pro převod souřadnic, umístěte na začátek kódu
def translate_screen_to_maze(in_coords, in_size=32):
    return int(in_coords[0] / in_size), int(in_coords[1] / in_size)

def translate_maze_to_screen(in_coords, in_size=32):
    return in_coords[0] * in_size, in_coords[1] * in_size
</code></pre></div></div>

<p>V této fázi se již budou po spuštění hry vykreslovat čtyři duchové v bludišti. Dále je chceme rozpohybovat. </p>

<h2 id="hledání-cesty-bludištěm">Hledání cesty bludištěm</h2>

<p>Nyní přichází možná nejsložitější část. Hledání cesty ve 2D prostoru, nebo grafu, je obtížný problém. Implementovat algoritmus pro vyřešení takového problému by dalo na další článek, proto použijeme hotové řešení. Nejefektivnějším algoritmem pro hledání cesty je <a href="https://cs.wikipedia.org/wiki/A%2a">A* algoritmus</a>. Ten nám poskytne balíček <em>tcod</em>, který jsme instalovali na začátku.</p>

<p>Vytvořím teď třídu Pathfinder. V konstruktoru inicializuji <em>numpy</em> pole s cenou průchodu (pole jedniček a nul, popsané výše) a vytvořím třídní proměnnou <em>pf,</em> která bude držet instanci A* pathfinderu. Funkce <em>get_path</em> nám pak po zavolání se souřadnicemi v bludišti (odkud, kam) vypočítá a vrátí trasu ve formě jednotlivých kroků polem. </p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Pathfinder:
    def __init__ (self, in_arr):
        cost = np.array(in_arr, dtype=np.bool_).tolist()
        self.pf = tcod.path.AStar(cost=cost, diagonal=0)

    def get_path(self, from_x, from_y, to_x, to_y) -&gt; object:
        res = self.pf.get_path(from_x, from_y, to_x, to_y)
        return [(sub[1], sub[0]) for sub in res]
</code></pre></div></div>

<p>Do funkce <em>main</em> přidám úsek pro demonstraci vyhledání trasy. Volím souřadnice začátku trasy [1,1] a cíle trasy [24,24].</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Vykreslení cesty
red = (255, 0, 0)
green = (0, 255, 0)
_from = (1, 1)
_to = (24, 24)
path_array = pacman_game.p.get_path(_from[1], _from[0], _to[1], _to[0])
#
print(path_array)
# [(1, 2), (1, 3), (1, 4), (1, 5), (2, 5), (3, 5), (4, 5), (5, 5), (6, 5), (6, 6), (6, 7) ...
#
white = (255, 255, 255)
for path in path_array:
    game_renderer.add_game_object(Wall(game_renderer, path[0], path[1], unified_size, white))
#
from_translated = translate_maze_to_screen(_from)
game_renderer.add_game_object(
    GameObject(game_renderer, from_translated[0], from_translated[1], unified_size, red))
#
to_translated = translate_maze_to_screen(_to)
game_renderer.add_game_object(
    GameObject(game_renderer, to_translated[0], to_translated[1], unified_size, green))
</code></pre></div></div>

<p>Ve hře vypadá vykreslení nejkratší trasy takto:</p>

<p><img src="https://create-it.cz/Blog/PublishingImages/Stranky/Pacman1/unnamed.gif" alt="pacman" />  </p>

<h2 id="náhodný-pohyb-duchů">Náhodný pohyb duchů</h2>

<p>Ve třídě <em>PacmanGameController</em> vytvářím novou funkci pro zvolení náhodného bodu z pole dosažitelných míst <em>reachable_spaces</em>. Každý duch tuto funkci použije po tom, co dorazí do cíle. Jednoduše si tak duchové donekonečna volí cestu ze své aktuální pozice v bludišti do náhodného cíle. Složitější chování, jako útěk a honění hráče, implementujeme v dalším díle. </p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def request_new_random_path(self, in_ghost: Ghost):
    random_space = random.choice(self.reachable_spaces)
    current_maze_coord = translate_screen_to_maze(in_ghost.get_position())

    path = self.p.get_path(current_maze_coord[1], current_maze_coord[0], random_space[1],
                           random_space[0])
    test_path = [translate_maze_to_screen(item) for item in path]
    in_ghost.set_new_path(test_path)
</code></pre></div></div>

<p>Duchovi přidáme ve třídě <em>Ghost</em> novou logiku pro následování trasy. Funkce <em>reached_target</em> je volaná každý snímek a kontroluje, zda duch již dorazil do cíle. Pokud ano, zjistí jakým směrem je další krok cesty bludištěm a podle toho začne měnit svoji pozici buď nahoru, dolů, doleva nebo doprava (logika pro pohyb je volaná v rodičovské třídě <em>MovableObject</em>). </p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def reached_target(self):
    if (self.x, self.y) == self.next_target:
        self.next_target = self.get_next_location()
    self.current_direction = self.calculate_direction_to_next_target()

def set_new_path(self, in_path):
    for item in in_path:
        self.location_queue.append(item)
    self.next_target = self.get_next_location()

def calculate_direction_to_next_target(self) -&gt; Direction:
    if self.next_target is None:
        self.game_controller.request_new_random_path(self)
        return Direction.NONE
    diff_x = self.next_target[0] - self.x
    diff_y = self.next_target[1] - self.y
    if diff_x == 0:
        return Direction.DOWN if diff_y &gt; 0 else Direction.UP
    if diff_y == 0:
        return Direction.LEFT if diff_x &lt; 0 else Direction.RIGHT
    self.game_controller.request_new_random_path(self)
    return Direction.NONE

def automatic_move(self, in_direction: Direction):
    if in_direction == Direction.UP:
        self.set_position(self.x, self.y - 1)
    elif in_direction == Direction.DOWN:
        self.set_position(self.x, self.y + 1)
    elif in_direction == Direction.LEFT:
        self.set_position(self.x - 1, self.y)
    elif in_direction == Direction.RIGHT:
        self.set_position(self.x + 1, self.y)
</code></pre></div></div>

<p>Duchové se teď vytvoří na pozicích určených písmenem “G” v původním ASCII bludišti a začnou si hledat náhodnou cestu. Já jsem zavřel tři duchy do klece - jako v původním Pacmanovi budou vypouštěni postupně - a jeden bloudí bludištěm:</p>

<p><img src="https://create-it.cz/Blog/PublishingImages/Stranky/Pacman1/unnamed-2.gif" alt="pacman" /></p>

<h2 id="přidání-hráče-a-jeho-ovládání">Přidání hráče a jeho ovládání</h2>

<p>Pro hráče dělám třídu Hero. Většina logiky pro ovládání hráče i duchů je řešena ve funkci <em>MovableObject</em>, proto stačí pouze pár funkcí pro upřesnění chování. V originále se Pacman hýbe ve čtyřech směrech, šipkami ovládáme jeho chůzi bludištěm. Pokud nezmáčkneme žádnou směrovou klávesu, bude pokračovat posledním validním směrem. Pokud zmáčkneme klávesu ve směru, kterým ještě nelze jít, směr se uloží a použije se při příští dostupné zatáčce. Stejné chování replikuji do naší hry a přidal jsem i Pacmanovu schopnost teleportovat se z jednoho konce bludiště na druhý - prostě zkontroluji, jestli je mimo herní plochu zleva nebo zprava, a podle toho nastavím jeho pozici na opačnou stranu bludiště. Pacman má taky upravenou funkci pro vykreslování, musíme ho vykreslit s poloviční velikostí, kterou by normálně zabíral jako čtverec (<em>pygame.rect</em>).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Hero(MovableObject):
    def __init__ (self, in_surface, x, y, in_size: int):
        super(). __init__ (in_surface, x, y, in_size, (255, 255, 0), False)
        self.last_non_colliding_position = (0, 0)

    def tick(self):
        # TELEPORT
        if self.x &lt; 0:
            self.x = self._renderer._width

        if self.x &gt; self._renderer._width:
            self.x = 0

        self.last_non_colliding_position = self.get_position()

        if self.check_collision_in_direction(self.direction_buffer)[0]:
            self.automatic_move(self.current_direction)
        else:
            self.automatic_move(self.direction_buffer)
            self.current_direction = self.direction_buffer

        if self.collides_with_wall((self.x, self.y)):
            self.set_position(self.last_non_colliding_position[0], self.last_non_colliding_position[1])

        self.handle_cookie_pickup()

    def automatic_move(self, in_direction: Direction):
        collision_result = self.check_collision_in_direction(in_direction)

        desired_position_collides = collision_result[0]
        if not desired_position_collides:
            self.last_working_direction = self.current_direction
            desired_position = collision_result[1]
            self.set_position(desired_position[0], desired_position[1])
        else:
            self.current_direction = self.last_working_direction

    def handle_cookie_pickup(self):
        collision_rect = pygame.Rect(self.x, self.y, self._size, self._size)
        cookies = self._renderer.get_cookies()
        game_objects = self._renderer.get_game_objects()
        for cookie in cookies:
            collides = collision_rect.colliderect(cookie.get_shape())
            if collides and cookie in game_objects:
                game_objects.remove(cookie)

    def draw(self):
        half_size = self._size / 2
        pygame.draw.circle(self._surface, self._color, (self.x + half_size, self.y + half_size), half_size)
</code></pre></div></div>

<p>Třídu <em>Hero</em> instancuji na konci funkce main. Pozice nastavuji na souřadnici [1,1] - <em>unified_size</em> je velikost jedné dlaždice. Do <em>GameRenderer</em> třídy ještě musíme přidat zpracování vstupních události, abychom mohli herní postavu ovládat.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># ve třídě GameRenderer
def add_hero(self, in_hero):
        self.add_game_object(in_hero)
        self._hero = in_hero

def _handle_events(self):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            self._done = True

    pressed = pygame.key.get_pressed()
    if pressed[pygame.K_UP]:
        self._hero.set_direction(Direction.UP)
    elif pressed[pygame.K_LEFT]:
        self._hero.set_direction(Direction.LEFT)
    elif pressed[pygame.K_DOWN]:
        self._hero.set_direction(Direction.DOWN)
    elif pressed[pygame.K_RIGHT]:
        self._hero.set_direction(Direction.RIGHT)


# na konci funkce main
pacman = Hero(game_renderer, unified_size, unified_size, unified_size)
game_renderer.add_hero(pacman)
game_renderer.tick(120)
</code></pre></div></div>

<p>Po spuštění můžeme Pacmana vodit bludištěm!</p>

<p>  <img src="https://create-it.cz/Blog/PublishingImages/Stranky/Pacman1/unnamed-3.gif" alt="pacman" /></p>

<h2 id="přidání-cookies">Přidání cookies</h2>

<p>Nebyl by to Pacman bez cookies v bludišti. Z herního hlediska určují míru prozkoumanosti světa a některé cookies i obrací schopnosti duchů a Pacmana. Jsou tedy ultimátní odměnou pro hráče a hlavním ukazatelem jeho postupu úrovní. V dnešních hrách se běžně odměňuje chování, které chce herní designér podporovat ve hráči. Krásným příkladem je např. letošní <em>Elden Ring</em>, kde dostane odměnu každý, kdo prozkoumává všechny kouty světa. Čím nebezpečnější a odlehlejší, tím větší odměna. Naopak hry jako novodobý <em>Assassin’s Creed</em> podporují plnění úkolů, takže máte při hraní pocit, že jste v práci, a ne ve hře.</p>

<p>Přidání cookies bude nejsnadnější věcí celého návodu, a proto jsem ji nechal na konec, jako třešničku na dortu. Vytvořím třídu <em>Cookie</em>. Její instance bude mít vždy velikost čtyři pixely, žlutou barvu a kruhový tvar. Ve funkci main vytvořím cookies na všech dlaždicích, které jsme na začátku uložili do pole <em>cookie_spaces</em> (totožné s <em>reachable_spaces</em>). Hráčovi přidám funkci <em>handle_cookie_pickup</em>, ve které si neustále ověřuji, jestli nedochází ke kolizi hráče s nějakou cookie. Pokud tomu tak je, cookie odstraním z pole a ta se přestane vykreslovat.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Cookie(GameObject):
    def __init__ (self, in_surface, x, y):
        super(). __init__ (in_surface, x, y, 4, (255, 255, 0), True)

# ve třídě GameRenderer přidat:
def add_cookie(self, obj: GameObject):
        self._game_objects.append(obj)
        self._cookies.append(obj)

# ve třídě Hero přidat:
def handle_cookie_pickup(self):
    collision_rect = pygame.Rect(self.x, self.y, self._size, self._size)
    cookies = self._renderer.get_cookies()
    game_objects = self._renderer.get_game_objects()
    for cookie in cookies:
        collides = collision_rect.colliderect(cookie.get_shape())
        if collides and cookie in game_objects:
            game_objects.remove(cookie)

# ve funkci main:
for cookie_space in pacman_game.cookie_spaces:
    translated = translate_maze_to_screen(cookie_space)
    cookie = Cookie(game_renderer, translated[0] + unified_size / 2, translated[1] + unified_size / 2)
    game_renderer.add_cookie(cookie)
</code></pre></div></div>

<p>Výsledek našeho snažení:</p>

<p><img src="https://create-it.cz/Blog/PublishingImages/Stranky/Pacman1/unnamed-4.gif" alt="pacman" />  </p>

<p>Malá zajímavost za závěr - v originální hře se Pacman zastaví na dobu jednoho snímku po každém požití cookie, takže ho duchové snáze dohoní v počátku hry, když je ještě pole zaplněné. V příštím díle zpracujeme podobnou herní mechaniku a můžete se těšit i na umělou inteligenci duchů, počítání score, zvuky, animace, textury, power-upy, screen-shake efekty, životy a koncové stavy hry.</p>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[5 kognitivních zkreslení při vývoji softwaru a jak se jim vyhnout]]></title>
    <link href="https://blog.jilecek.cz/blog/2022/04/13/kognitivni-zkresleni/"/>
    <updated>2022-04-13T12:00:00+00:00</updated>
    <id>https://blog.jilecek.cz/blog/2022/04/13/kognitivni-zkresleni/</id>
    <content type="html"><![CDATA[<p><img src="https://create-it.cz/Blog/PublishingImages/Titulni/2022/kognitivni_zkresleni.jpg" alt="" /></p>

<p>Kognitivní zkreslení jsou naučená pravidla vnímání a chování. V podstatě jsou to mentální zkratky, které nevědomě používáme. Při práci nás tyto skryté předsudky mohou nemile překvapit, proto je nutné si uvědomovat, jak fungují, a vědomě jim předcházet. V tomto článku se podíváme na 5 hlavních zkreslení a na užitečné techniky, které lze použít pro jejich minimalizaci.</p>

<!-- more -->

<h2 id="optimistické-zkreslení">Optimistické zkreslení</h2>

<p>Optimistické zkreslení (nebo také zaujatost) je tendence k přehnané optimističnosti ohledně okolních událostí. V softwarovém světě se vyskytuje hlavně při odhadech náročnosti úkolů, kdy můžeme přeceňovat vlastní dovednosti.</p>

<p>Běžně se může při poradě stát, že váš kolega prohlásí, že daný náhodný úkol zvládne lehce udělat a nezabere mu to skoro žádný čas. Přitom nemá žádnou předchozí znalost o úkolu a vše zakládá na přehnaném optimismu. Jak jste určitě ve světě software už viděli, tyto odhady se často ukážou jako těžce podceněné. A malou třešničkou na dortu je tzv. snadné-obtížné zkreslení, kdy lidé odhadují obtížné úkoly optimisticky a ty snadné zase pesimisticky.</p>

<p>Tomuto kognitivnímu zkreslení se dá vyhnout pomocí těchto přímých otázek:</p>

<ol>
  <li>Vidíš na úkolu něco, co by mohlo způsobit problémy?</li>
  <li>Vidíš nějaký důvod, proč by tvoje řešení mohlo být nesprávné?</li>
  <li>Zamyslel ses nad závislostmi, které budou ovlivněny změnou tohoto kódu? </li>
</ol>

<h2 id="konfirmační-zkreslení">Konfirmační zkreslení</h2>

<p>Konfirmační zkreslení je dalším dobře známým zkreslením. Značí, že máme tendenci věnovat pozornost pouze těm informacím, které potvrzují naše existující přesvědčení a názory a naopak ignorovat ty informace, které našim názorům protiřečí. V podstatě je to stejné jako mít hlavu v oblacích a utíkat před realitou. Bystrost našeho myšlení se pod vlivem tohoto zkreslení nijak nezlepšuje, právě naopak.</p>

<p>Řekněme, že jeden z programátorů v týmu pevně věří, že dědičnost byla vždy základem <a href="https://cs.wikipedia.org/wiki/OOP">OOP</a>. Jiný kolega předloží argument, že tomu tak není. Dědičnost nebyla přijata jen tak a je stále zdrojem debat. Aby první programátor dokázal svoji pravdu, vygooglí třeba “dědičnost základem OOP” a hned první výsledek mu potvrdí jeho názor. Avšak jeho kolega má pravdu. Ani Alan Key, jeden ze zakladatelů OOP,  nechtěl implementovat dědičnost v první verzi jazyku Smalltalk.</p>

<p>Konfirmačnímu zkreslení se dá vyhnout následujícími způsoby</p>

<ol>
  <li>Pokusit se nalézt problémy, které mohou vzniknout, a nehledat jen pozitivní případy. V případě příkladu s Googlem tedy hledat i opačný názor.</li>
  <li>Hledat logické opodstatnění každého předsudku (a nejlépe i zjistit, že jde o předsudek) a hledat i případy, při kterých může být logicky neplatný.</li>
</ol>

<h2 id="kotvení">Kotvení</h2>

<p>Kotvení popisuje skutečnost, kdy je přirozenou lidskou tendencí spoléhat se při rozhodovacím procesu na jednu informaci či skutečnost, od níž jsou poté odvozována další rozhodnutí. Tato informace však mnohdy vůbec nemusí být relevantní a může náš úsudek ovlivňovat negativním způsobem.</p>

<p>Toto zkreslení se může vyskytnout např. v následující situaci. Scrum master se zeptá týmu při odhadu pracnosti: “Jak dlouho zabere tenhle task? 2 týdny?”. Díky efektu kotvení pak nebude záležet, jak je ten úkol ve skutečnosti obtížný, většina týmu se shodne na 2 týdnech. Byli ovlivněni první informací, kterou obdrželi. Stejná technika se využívá i při pohovorech, kdy je pro uchazeče klíčové navrhnout platové ohodnocení jako první.</p>

<p>A jak se kotvení zbavit?</p>

<ol>
  <li>Neptat se přímo na odhad, ale na úkol samotný: “Kolik toho zvládnete udělat za 2 týdny?”</li>
  <li><a href="https://en.wikipedia.org/wiki/Planning_poker">Planning poker</a> - všechny názory jsou dány anonymně ve stejný moment. Je to skvělá technika při scrumových odhadech! </li>
</ol>

<h2 id="stádový-efekt">Stádový efekt</h2>

<p>Stádový efekt je jev, který jedince nutí jít s davem a spíše přistupovat na názory, které viděl u ostatních. Může také označovat oblibu módních trendů - stačí se podívat na dnešní instagramovou kulturu bezcharakterních lidí. Pokud je myšlenka sdílena většinou populace, nabývá na důvěryhodnosti nezávisle na pravdivosti. Sociální sítě jako Twitter a Reddit jsou na to také velice náchylné. Na Twitteru je to ještě podpořeno omezeným počtem znaků, který podporuje povrchní názory a myšlenky.</p>

<p>Z hlediska softwarového vývoje se podívejme opět na příklad s poradou. Charismatická team leaderka argumentuje, proč by celý tým měl přejít z REST API na GraphQL. V prezentaci demonstruje technické výhody nové technologie pro celou firmu. Kolegové také vypadají, že novou technologii chtějí. Bohužel jde o stádový efekt. Team leaderka ve skutečnosti jen způsobila rozruch okolo nové technologie, ale nedokázala hodnotu svého nápadu. Bude to zajímat zákazníka? Uvidí nějaký rozdíl při používání? Přinese to více času, zákazníků nebo peněz firmě? Když jde o novou technologii, jsou pochopitelně všichni nadšení.</p>

<p>Jak se zbavit tohoto kognitivního zkreslení? Těmito otázkami:</p>

<ol>
  <li>Software vyvíjíme hlavně pro podporu firmy. Nemá smysl používat novou barevnou technologii, pokud nepřinese žádnou extra hodnotu</li>
  <li>Jaká je hodnota toho nápadu?</li>
  <li>Jak přinese nové zákazníky, čas nebo nějakou jinou výhodu?</li>
  <li>Převažují výhody nad cenou implementace?</li>
</ol>

<h2 id="atribuční-chyba">Atribuční chyba</h2>

<p>Atribuční chyba je zkreslení procesů přisuzování. Projevuje se tím, že při vysvětlování chování ostatních lidí má člověk sklon nadsazovat charakterové vlastnosti člověka a podceňovat kontext jeho životní situace nebo náhodnosti okolního prostředí.</p>

<p>Pro poslední zkreslení tohoto článku už vylezeme ze zasedačky a raději si sedneme zpět k práci. Při programování si však všimnete ošklivého bloku kódu. Pomocí <em>git blame</em> zjistíte, kdo je jeho autorem. Je to Lukáš. Samozřejmě. Lukáš je neopatrný, nezodpovědný a impulsivní. Nepřemýšlí nad tím co dělá. Vy byste to udělali lépe!</p>

<p>Ale uklidníte se a pokračujete v implementaci svojí feature. Za chvíli však narazíte na další blok otřesného kódu. Zase Lukáš, to je jasné! Avšak <em>git blame</em> tentokrát řekne jiný příběh - autorem jste vy. Všemožné otázky najednou naplní vaši  mysl. Jsem špatný vývojář? Jsem jako Lukáš? Ale tyto pochyby ihned zahodíte a začnou přicházet výmluvy. Samozřejmě, že nejste špatný vývojář, byla zrovna deadline, nebylo dost času, měli jste zrovna rýmu, a psa jste měli u veterináře. To je ve zktrace atribuční chyba - podceňování kontextu životní situace při souzení jiných lidí.</p>

<p>Jak se vyhnout atribuční chybě?</p>

<ol>
  <li>Obviňování autora nepomůže. Zkuste zjistit příčinu toho špatného kódu.</li>
  <li>Má Lukáš málo zkušeností v tomto segmentu vědění o programovacím jazyku/projektu?</li>
  <li>Byl zrovna pod stresem? Blížil se deadline? Byl přepracovaný? Byl víkendový crunch?</li>
</ol>

<h2 id="pozvěte-ďáblova-advokáta"> Pozvěte ďáblova advokáta</h2>

<p>A to tedy bylo 5 hlavních kognitivních zkreslení. Co jsme se naučili? Kognitivní zkreslení se stávají nám všem. Co proti tomu můžeme dělat je naučit se všímat si jich a umět se jim vyhnout. Nejčastější zkreslení v softwarovém vývoji jsou optimistické, konfirmační a kotvící. Také je velice častý stádový efekt a atribuční chyba. Na softwarové projekty mohou mít katastrofální vliv. Hlavní metodou vyhnutí je vždy pečlivé zamyšlení se nad problémem a hraní si na “ďáblova advokáta” při jeho analýze, tedy snaha hledat nejen pozitivní případy, ale i ty opačné a negativní. Pro více informací o kognitivních zkresleních v softwarovém vývoji doporučují tuto <a href="https://www.researchgate.net/publication/328410759_Cognitive_Biases_in_Software_Engineering_A_Systematic_Mapping_Study">studii</a>, kterou jsem použil jako zdroj pro tento článek. Doufám, že jste si článek užili, a zase příště!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[A-Life, Emergent AI and S.T.A.L.K.E.R.:  An Interview with Dmitriy Iassenev (article restored from defunct AiGamedev.com)]]></title>
    <link href="https://blog.jilecek.cz/blog/2022/04/13/a-life-emergent-ai-and-s-t-a-l-k-e-r-an-interview/"/>
    <updated>2022-04-13T12:00:00+00:00</updated>
    <id>https://blog.jilecek.cz/blog/2022/04/13/a-life-emergent-ai-and-s-t-a-l-k-e-r-an-interview/</id>
    <content type="html"><![CDATA[<blockquote>
  <p>article restored from defunct AiGamedev.com (February 25th, 2008)</p>
</blockquote>

<!-- more -->

<p>Ever since it was first announced, the game S.T.A.L.K.E.R. has captured the imagination of avid gamers fascinated by the idea of a massive world populated by an A-Life system. The game also piqued the interest of AI developers here at AiGameDev.com, making it into the finalists for best AI and runner up for technical innovation in the Game AI Awards for 2007.
It’s therefore a pleasure to announce this exclusive interview with <em>Dmitriy Iassenev</em>, the mastermind behind the AI and A-Life system in S.T.A.L.K.E.R., who agreed to answer some questions about the engine and its implementation. As it turns out, there’s some pretty amazing technology under the hood to — and not only on the surface!
<img src="https://blog.jilecek.cz/images/a-life-emergent-ai-and-s-t-a-l-k-e-r-an-interview--02.jpg" alt="" />
Non-player characters grouped around a campfire in S.T.A.L.K.E.R.
<strong>Alex Champandard: Hi, Dmitriy. Thanks for taking the time to answer these questions. Could you introduce yourself briefly and tell us about your background in AI and game development?</strong>
Dmitriy Iassenev: Hi, Alex. I am the lead programmer at GSC Game World on S.T.A.L.K.E.R.: Clear Sky.
The first thing I got acquainted with in this matter was the intelligence for the board game filler at the AI…
<strong>AC: One of the key features of S.T.A.L.K.E.R. is the A-Life system. Could you describe what you think is the essence of A-life, and how it can be applied?</strong>
DI: The gist of the A-life is that the characters in the game live their own lives and exist all the time, not only when they are in the player’s field of view. It eventually runs counter to the customary optimization processes used in games development (why perform operations invisible to the player). Thus, such a scheme is reasonable to be used only when you know exactly what you want to have in the end. We had the game designers’ requirements to have the characters that could not only live inside a certain level, but move between the levels, memorizing the information they obtained during their existence. Consequently, we have decided that each character should come with only one logical essence regardless of the level he is at; whereas we could try to implement that with various tricks involved.
<strong>AC: There’s a fine line between a game and a simulation. How far does your implementation in S.T.A.L.K.E.R. take these ideas of A-Life?</strong>
DI: Our A-life implementation does not claim to be full and pure. The concept of a living world, where each character has his own goal is vast and complicated, indeed. Therefore, its realization to the fullest extent is a large and difficult task. Especially, when the matter concerns shooters, with their detailed elaboration of the actions, and when good-looking animations can be more significant than the high-level character actions. (This is much spoken about; the question of why the AI methods of RTS cannot be carried over to FPS has been discussed at your web-site, for example. I would also like to ask the AI developers in FPS games, how much time they devote to low level and how much to the high. I’d say that it would be great if the ratio is 10 to 1.)
<img src="https://blog.jilecek.cz/images/a-life-emergent-ai-and-s-t-a-l-k-e-r-an-interview--03.jpg" alt="" />
Artificial life populating the area around Chernobyl.
<strong>AC: Could you tell us more about how you implemented the A-Life?</strong>
DI: Our A-life implementation is quite simple. We have introduced two terms that characterize 2 patterns of character’s behaviour, different in implementation details: offline and online. The offline behaviour is very simple: the character does not play animations or sounds, does not manage his inventory actively, does not build detailed and smooth paths (although he does build paths according to the global navigation graph, but more on that later), etc. In contrast, online behaviour is fully detailed. Thus, offline behaviour can be considered the LoD (level of detail) of the online.
In our system the player acts in a level, other characters live in other levels, i.e. they are offline, i.e. they are using the offline behaviour. Moreover, considering the high density of characters in a level, not all characters in the player’s level have the online behaviour, but only those who are in a predefined radius from the player (can vary from level to level, but usually it is about 150 meters), or what the game designer sets it to. To achieve this, the A-life system follows the player’s and offline characters’ movements, and switches the latter to online/offline as necessary.
Next, navigation of objects in online and offline should be mentioned. Our game has levels, for each of which a separate navigation graph is build and is used by characters for movement in online mode. We call it the detailed graph. For each graph a less detailed version is created, the vertices of which can be connected with vertices of graphs from other levels. This is the graph used by characters for navigation in offline. It is also used by online characters for carrying out strategic objectives. For example, if an online character decides to move to the location on another level, he searches for the path on the global graph, then uses the current level’s detailed graph to create the path from his current position to a vertex of the global graph. If that point is already on another level, the character teleports there and switches to offline mode. To prevent the player from seeing this, we have placed these points further than the player’s transition points, somewhere “around the corner.”
<img src="https://blog.jilecek.cz/images/a-life-emergent-ai-and-s-t-a-l-k-e-r-an-interview--04.jpg" alt="" />
A stalker getting into trouble with the army!
<strong>AC: What were the other important parts of the system for developing the A-Life in S.T.A.L.K.E.R.?</strong>
DI: Every character in the game always has a goal: to uncover the mystery of the Zone. In early versions of the simulator, a character knew one or several dealers, which had sets of quests that they generated based on the map of anomalous activity and requests from organizations, which wanted to get rich from artefacts found in the Zone. Completion of a quest brought the character closer to his goal. There was only one type of quest at the time — “bring an artefact”. The character would take on a quest to search for the artefact, go to the approximate area in which it could be found, if able to find the artefact, brought it back to the dealer, traded it, then picked a new quest. Along the way he could encounter enemies and fight them. In offline mode this was simulated as a TBS: the opponents took turns making moves, the result calculated based on a formula and the random factor. The effect was that one opponent could run away from another, sometimes characters got killed, sometimes they did not even notice each other or decided to avoid confrontation. If the character was a stalker and met a neutral or a friend, they traded with each other, guided by a developed trading scheme. All of this worked both in offline and in online modes. To notify player about the offline activity, we used news, which were generated if some character could see an event or its consequences.
It was planned that the number of types of quests would later increase, and character behaviour would diversify due to introduction of requirements of food and sleep. We also planned that our characters would be able to uncover the mystery of the Zone before the player, or at least collect a certain amount of information.
Then we changed the way quests were generated. Characters would now get quests not from dealers, but from the so-called smart terrains (not the same as in Sims). A character’s life now worked in such a way, that he took the quest generated by some smart terrain, then walked to the destination it had set for him. After getting there, he would get points, and the smart terrain would take him under control for some time. Under the control of a smart terrain, the character prioritized and carried out the available tasks. This is how the game got faction bases, stalkers by campfires, and such.
That is, migration of characters from place to place, their movement between levels, all was caused by changing goals.
<img src="https://blog.jilecek.cz/images/a-life-emergent-ai-and-s-t-a-l-k-e-r-an-interview--05.jpg" alt="" />
The camp of an AI faction in the zone.
<strong>AC: How do these ideas tie in to the character AI at the lower level?</strong>
DI: Regarding AI at the single character level, we should look at the two models: offline and online, separately, even though they have some things in common.
Offline character AI is very simple: if there is no goal, try to get one. If a goal cannot be found, wonder about aimlessly. If there is a goal, go to the place at which it can be achieved. When a character is under smart terrain control, he can get additional commands for movement, but performs no other actions.
Online character AI consists of three layers:</p>
<ul>
  <li>collection and processing of information</li>
  <li>making decisions</li>
  <li>a set of low-level controllers
A character has three types of receptors: visual, sound, and damage. Out of the information received from receptors, the character picks the interesting bits — enemies, threats, objects that can be picked up.
<strong>AC: How do characters make decisions in S.T.A.L.K.E.R.?</strong>
DI: The decision-making model has undergone many changes during the course of its development. There have been four iterations in total. First, we used hand written stack-based FSM. Then we switched to a hierarchical FSM, then I read the remarkable GOAP (Goal Oriented Action Planning) article by Jeff Orkin in Game Programing Wisdom II, then an article about motivational graphs, and we started using motivational graphs for goal selection and GOAP for action selection.
There are several nuances here, which I have discussed in correspondence with Jeff Orkin. We have decided to use planning exclusively for action selection. That is, we only needed a plan for selecting the first action. All the other parts of the plan were ignored. The value of the first action is in the fact that it is chosen not arbitrarily, but in the context of some plan. This is very good for debugging — you always know what your character is doing and, more importantly, why. This also makes it easier to tell if a plan is still valid, since our plan is always valid.
To keep the plan valid, our implementation of GOAP kept querying those properties of the world that it needed to create the plan of least weight. We did not keep rebuilding plans, but only queried the properties of the world that the planner used to create the current plan. If any one of them changed value, then the whole plan was rebuilt.
On the other hand, a character must always have some non-empty plan. An empty plan meant that the character did not know what to do, since there was no sequence of actions that could transfer current world state to the target one using a set of available operators (or its attainment required too many vertices to visit, which happened, though rarely. In 99% of cases it meant that there was no such sequence, but the planner could not prove it, due to the limit on the number of visited vertices). The condition of existence of a non-empty plan demanded that we make a property of the world that always had a single value, which is probably not very elegant.
<img src="https://blog.jilecek.cz/images/a-life-emergent-ai-and-s-t-a-l-k-e-r-an-interview--06.jpg" alt="" />
Armed soldiers patrolling in S.T.A.L.K.E.R.
To set a character’s (stalker’s) behaviour we used several dozens of operators (about 70). To easily control such a number of operators, we used hierarchies of planners. That is, an operator could itself be a planner. Interaction of planners of different levels was carried out like this: if the top-level planner changed plan, with which the current state also changed, then the previous planner was informed that it should finish. If the operator was itself a planner, it informed its own current planner, and so on. It should be noted that finishing was an instantaneous action, i.e. if the action could not be stopped at once, this had to be taken into account not only at its level, but also at others, which introduces additional complexity.
That is why we decided not to use GOAP for the monsters behaviours, since monsters rely extremely on animations which cannot be interrupted or blended. Therefore we used hierarchical FSM for them, but, actually, it did not solve non-instantaneous action issue. In prequel we get solution to this complexity by transferring part of the logic into the low level controllers: high level logic selects goals for the low-level controllers. Therefore instantaneous action change in the high level doesn’t mean instantaneous action change in the low level.
There is also a nuance in combining two methods for manipulating logic. At first, we introduced motivational graphs for taking some load off the GOAP planner. Eventually it was found that the planner coped with its task well, and the search never exceeded 200 vertices. Besides, determining the logic for traversing targets consisted of the topology graph author taking some of the work onto himself. Eventually, we stopped using motivational graphs at all, since it became easier to set all logic in a single place. Different goals were used only for live and dead characters (for clutching the trigger while dying).
Low-level controllers were responsible for animation, movement, controlling objects, sound, character orientation. Implementation of these controllers is not particularly interesting, except that we also used GOAP for controlling objects (and quite successfully, at that). In my view, it would be interesting to see an approach using a controller manager that would perform some partially ordered planning on operators of low-level controllers. Here, of course, the speed aspect of its performance is very important, since low-level controllers are typically updated each frame. On the other hand, it could also take up many issues with implicit interaction between the controllers. Maybe it could even be used not only for logic of low-level controllers, but for all of a character’s logic, as has been discussed on your site (Rethinking the AI/Animation Interface).
<strong>AC: Since the final game had a story element to it, you also had certain areas in the game that were “scripted” in a more traditional way. Could you tell us more about how you integrated the A-Life system with the scripts?</strong>
DI: As has been mentioned above, quests in the game are generated by smart terrains. This also applies to the storyline. Story quests have higher priority. Moreover, storyline areas are surrounded by so-called space restrictors. Their purpose consists of keeping the storyline characters from running too far away, and non-storyline characters from interfering with storyline elements. That is, there a significant amount of control over simulation. On the other hand, after the player completes the storyline scene, storyline characters become regular and follow regular rules, i.e. choose quests and go carry them out in the appropriate smart terrain locations. At the same time, the area is freed from all limitations.
<img src="https://blog.jilecek.cz/images/a-life-emergent-ai-and-s-t-a-l-k-e-r-an-interview--07.jpg" alt="" />
The danger zone around the power plant itself.
<strong>AC: Was the process of integrating these scripted areas with A-Life a difficult process for the designers? How did they approach the process?</strong>
DI: It was difficult without space restrictors. Then, any “outsider” character would either break the storyline scene by distracting other characters, or, if they were not permitted to pay attention, stupid situations would occur, like having a character be bitten by a dog, not pay it any attention and finally die fully armed.
To generalize, one could say that space restrictors, along with careful management of information coming from receptors, solved this problem practically completely, in time.
<strong>AC: In retrospect, what parts of the system and/or development process were you particularly happy with?</strong>
DI: I was very happy with the work done when I followed a stalker from one level to another, saw how he searched for artefacts, found them, returned to the dealer, approached him, traded, picked a new quest, went on — too bad this did not make it into the original game. It was very interesting to witness.
When we were just implementing GOAP, it was very interesting to watch two hostile unarmed characters that knew were to get weapons and ammo: they first run to the weapons, find that they have no ammo, then run to the ammo, the first one to get there causes the other to panic if he is still far away from weapons and ammo, the panickier gets wounded and falls, the other approaches to finish him (this did not make it into the original game, since all characters received unlimited ammo, and such situations could not take place).
It was very interesting to watch a fight of several dogs and one stalker — it was breathtaking to see this sight, as he flees the dogs, switching covers. Sometimes he died quickly, sometimes managed to take down 4–5 dogs, and sometimes all 6.
<img src="https://blog.jilecek.cz/images/a-life-emergent-ai-and-s-t-a-l-k-e-r-an-interview--08.jpg" alt="" />
Soldiers using the environment to take cover and return fire.
<strong>AC: How about disappointments? Was there anything in particular about the system or its development that you would have done differently?</strong>
Dmitriy Iassenev:
In simulation: I would very much like to play a game in which characters would live their own lives, each would have his own goal in the game, each would have human-like (or some specific for monsters) needs that the character would have to satisfy. Now, instead of creation of an algorithm for choice of current needs and their satisfaction, a simpler model has been used, which offloaded this work to the smart terrains, responsible for change of tasks by characters, able to assign tasks like “sleeping”, which, of course, is not the same thing.
In visuals: much can be done to improve fights, teamwork, efficiency of combat and efficiency of characters’ actions. I really want to switch from imitation of team actions, to real team AI, even if it means only a few actions.
In intellect: adaptation and teaching characters the player’s game style. The emotional part would also be very interesting.
Miscellaneous: I would really like to teach characters to adequately react to the surrounding world: walk around dynamic obstacles, each other, use the terrain (path and smart objects) in various ways, be able to drive vehicles, fly the helicopter, etc. There are many things they cannot do for various reasons, but in the future iterations of our game we will try to gradually add the missing elements.
<strong>AC: What about the lessons learned? If you had thirty seconds to give advice to other game developers out there, what would it be?</strong>
Dmitriy Iassenev:
    <ol>
      <li>Do not reinvent the wheel. Use the Internet to find solutions to your problems.</li>
      <li>Have a clear idea of the game you are making, of which features it will have and which it will not, use prototyping to avoid implementing features that do not make it into the release.</li>
      <li>Debug characters with comfortable tools: each component should have its debug draw/mode/screen. Draw paths (all the iterations, all the smooth stages and so on), draw visibility checks to find out why character doesn’t see, draw covers information and so on. To debug characters behaviour we created their debug screen with all the data from all the layers, so we can easily pick the character and find out what is wrong with him. Pause and time factor are invaluable for the animation/movement/orientation debug.</li>
      <li>Let programmers do programmer work and designers design. Designer is a bad programmer, programmer is a bad designer. This could become a problem when using scripts. Let people do things in which they are strong. Instead of advancing designers in programming, create WYSIWYP editor with many options to tune.</li>
      <li>Be aware of all the new developments in your area, read Internet resources, like AiGameDev.com :)</li>
      <li>Implement something new in your game. Maybe it is only one thing (since several can be too much for a single project), but necessarily new. We see an excellent implementation of decision trees in Black &amp; White, Jeff Orkin has created an exceptional implementation of a GOAP planner in F.E.A.R., we have tried to make a kind of approximated A-Life in a shooter, maybe someone will make something new tomorrow — this will benefit the players, who will get diverse games, and developers themselves, who will set an example of a good method or approach.
<img src="https://blog.jilecek.cz/images/a-life-emergent-ai-and-s-t-a-l-k-e-r-an-interview--09.jpg" alt="" />
<strong>AC: Can you tell us about the S.T.A.L.K.E.R. prequel you are working on? Where would you like to take the A-Life technology?</strong>
DI: Information from our site:
        <blockquote>
          <p><em>“The story of S.T.A.L.K.E.R.: Clear Sky brings the players one year prior to the events of the original S.T.A.L.K.E.R. game in 2011.</em></p>

          <p><em>A group of stalkers has for the first time reached the very heart of the Zone — Chernobyl Nuclear Power Plant, and brings about a cataclysm on the brink of a catastrophe. An immense blowout of anomalous energy changes the Zone. There are no more reliable and relatively safe roads. The entire levels vanish in the outbursts of anomalies. Stalkers and even expeditions die or end up sealed on the lost territories. New areas, which remained unknown since the time of the Zone emergence, appear on the Zone map. The Zone continues to shake with blowouts. The Zone is unstable. The anomalous activity is at its maximum.</em></p>

          <p><em>Changes of the Zone map known to stalkers shake the fragile balance of forces in the Zone. Among the groupings, there flare up hostilities for the new territories, artefact fields and spheres of influence. There are no more old enemies or friends — now everyone is for himself. The Factions War has started between the groupings.</em></p>

          <p><em>The protagonist is a mercenary who appeared at the edge of the opposition between stalker factions, Strelok and even the Zone itself. The main character will have to play the key role in the events, which led to creation of the Zone up to the point from which the original S.T.A.L.K.E.R. game begins.”</em></p>
        </blockquote>
      </li>
    </ol>
  </li>
</ul>

<p>We changed the role of factions in simulations. i.e it used to be some smart terrain, one of a hundred, that generated quests with the precondition that they could only be taken by members of certain factions, but now the faction itself is a game entity, it has its own goals within the simulation, fights other factions, while the player can assist this and immediately see the result of his actions.
Also, we made several changes to the character’s combat behaviour. Now they fight more efficiently and became more believable.
<strong>AC: Many thanks for your time Dmitriy, and best of luck with the upcoming project!</strong></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Novinky v Unreal Engine 5]]></title>
    <link href="https://blog.jilecek.cz/blog/2022/02/09/Unreal-engine-5/"/>
    <updated>2022-02-09T12:00:00+00:00</updated>
    <id>https://blog.jilecek.cz/blog/2022/02/09/Unreal-engine-5/</id>
    <content type="html"><![CDATA[<p><img src="https://create-it.cz/Blog/PublishingImages/Titulni/2022/unreal-engine-5.jpg" alt="" /></p>

<p>Firma Epic Games se na herním trhu objevila v roce 1998 s legendární hrou <a href="https://en.wikipedia.org/wiki/Unreal_%281998_video_game%29">Unreal</a>. Od té doby se jejich <a href="https://en.wikipedia.org/wiki/Unreal_Engine">Unreal Engine</a> stal hlavním konkurentem <a href="https://en.wikipedia.org/wiki/Quake_engine">Quake</a> technologie ve světě FPS her. Pak přišel Unreal Engine 2, který se stal základem pro hru <a href="https://en.wikipedia.org/wiki/Unreal_Tournament_2004">Unreal Tournament 2004</a>. Dalším krokem pak byl v roce 2014 Unreal Engine 4 („UE4“), který tu s námi byl 7 produktivních let a během té doby se na scéně chlubil těmi nejlepšími nástroji pro herní vývojáře vůbec. UE4 se proslavil zejména svou rozsáhlou škálou nástrojů, které jsou zároveň jednoduché na používání. Jeho blueprint systém, který umožňuje grafické programování a tím ulehčuje práci umělcům a komunikaci programátorů se zbytkem týmu, je také ideálním nástrojem pro rychlé prototypování nápadů. UE4 se používá i ve filmovém průmyslu, jak lze vidět např. u seriálu Mandalorian. Byly zde použity CGI scenérie vytvořené UE4 a promítané na obří LED obrazovky, které byly synchronizované s kamerou a nahradily tak “klasické” zelené plátno.</p>

<!-- more -->

<p>Posledním evolučním krokem je Unreal Engine 5 („UE5“), který se naposledy ohlásil v prosinci svojí dechberoucí prezentací nového dema Matrix Awakens. O něm a o dalších pokročilých funkcích nového UE5 vám řeknu níže.</p>

<h2 id="jak-revoluční-je-unreal-engine-5">Jak revoluční je Unreal Engine 5?</h2>

<p>V původním <a href="https://youtu.be/qC5KtatMcUw">demu</a> vydaném v květnu roku 2021 ukázal světu Unreal Engine svoje nové technologie, jmenovitě Lumen a Nanite. Lumen je nový plně dynamický systém globálního osvětlení a odrazů a Nanite je geometrický systém, který umožňuje vykreslovat extrémně detailní modely v reálném čase. Jednou z metod, kterou Nanite používá, je víceméně klasické LOD, Level of Detail - načítání  těch detailnějších modelů blíže kameře a těch horších daleko od kamery. Hlavním tahákem je zpracování milionů trojúhelníků na 3D meshi.</p>

<p><a href="https://youtu.be/xfpXN6mgfew?t=533"><img src="https://create-it.cz/Blog/PublishingImages/Stranky/Unreal-engine-5/ue3.png" alt="unreal engine" /></a>  </p>

<p>Jak již bylo řečeno, <strong>Lumen</strong> je nový osvětlovací systém v UE5. Byl navržen pro next-gen konzole a dokáže vykreslovat diffusní (rozptýlené) odrazy s nekonečným počtem odražení a nepřímé spekulární (zrcadlové) odrazy v rozsáhlých prostředích, a to v měřítku milimetrů i kilometrů. Běžně se musí tzv. “zapékat” lightmap textury po každé změně statických světel ve scéně. S Lumenem tato nutnost odpadá, vše je řešeno automaticky a v reálném čase.</p>

<p>Lumen spoléhá na LOD v Nanite systému, protože vypočítává světla hlavně poblíž kamery a viditelného světa, pro optimální výkon. Lumen přímo nepotřebuje Nanite systém k činnosti, ale pokud je ve scéně komplexní geometrie s mnoho-polygonovými mesh objekty bez zapnutého Nanite, tak bude výpočet osvětlení značně zpomalený. To je obzvlášť znatelné u scén plných objektů bez nastaveného LOD. Jak celý osvětlovací systém vypadá v reálné scéně a v reálném čase se můžete kouknout na videu výše. Ložnice se po otevření okna přirozeně zaplaví světlem.</p>

<p><a href="https://www.youtube.com/watch?v=qC5KtatMcUw"><img src="https://create-it.cz/Blog/PublishingImages/Stranky/Unreal-engine-5/ue2.png" alt="" /></a>  </p>

<p>Už od vzniku komerčního 3D herního vývoje byli vývojáři utlačováni a omezování počtem polygonů, které mohou vykreslit bez dopadu na výkon hry. Metody optimalizace počtu polygonů ve scéně zůstaly po řadu let v podstatě nezměněny - 3D modely se vymodelují v několika úrovních detailů, neboli LOD a detaily se simulují kombinací textur a shaderů (opět, blíž = detailnější).</p>

<p><strong>Nanite</strong> v Unreal Engine 5 je schopný vykreslovat scény s miliardami trojúhelníků zdrojové geometrie. V podstatě to znamená, že engine má přístup ke geometrii v plném rozlišení a v reálném čase optimalizuje vykreslování na obrazovku.</p>

<p>Při použití klasických vykreslovacích technik by se hodil 3D model do scény a vykreslil by se každý jeho polygon, bez ohledu na to, zda je viditelný kamerou (každá herní scéna má hlavní kameru) a nebo jestli sdílí stejné pixely s jinými polygony. S Nanitem jsou všechny tyto věci zpracovány automaticky.</p>

<p><a href="https://youtu.be/WU0gvPcc3jQ"><img src="https://create-it.cz/Blog/PublishingImages/Stranky/Unreal-engine-5/ue1.png" alt="ue1.png" /></a>  </p>

<p>Na závěr bych ještě rád zmínil Matrix Awakens, poslední vydané demo prezentující novinky v Unreal Engine 5. Popravdě řečeno bylo dechberoucí, alespoň pro mě. Na začátku videa skoro nelze poznat, který Keanu Reeves je ten reálný, a kterého vytvořil počítač. Možná jen podle vrásek okolo očí. Vše je zásluhou Nanite a Lumen systémů, které dokáží zpracovat extrémní detaily a vypočítat realistické osvětlení. Potenciál, který má UE5 pro filmový a herní průmysl, je masivní. Už teď jsou ve vývoji hry využívající UE5, jako např. Stalker 2, takže se určitě máme na co těšit!</p>

<p> <em>Jan Jileček</em></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Proč je Jiu Jitsu ideálním sportem pro IT profesionály]]></title>
    <link href="https://blog.jilecek.cz/blog/2021/12/01/BJJ/"/>
    <updated>2021-12-01T12:00:00+00:00</updated>
    <id>https://blog.jilecek.cz/blog/2021/12/01/BJJ/</id>
    <content type="html"><![CDATA[<p><img src="https://www.create-it.cz/Blog/PublishingImages/Titulni/2021/brazilian-jiu-jitsu.jpg" alt="" /></p>

<p>Brazilské jiu jitsu, zkratkou BJJ, je jedním z nejkomplexnějších bojových umění všech dob. Zahrnuje nepřeberné množství technik a jejich kombinací, přičemž se tyto techniky neustále vyvíjejí a zdokonalují. Mnoho technik je zaměřeno na překonání silnějšího a většího oponenta. BJJ se primárně zaměřuje na boj na zemi, a obsahuje judo techniky a wrestlingové takedown techniky (je samozřejmě důležité dostat oponenta na zem). Poté, co se oponent dostává na zem, ztrácí téměř všechny silové páky, které by jinak mohl využít. Takto lze překonat i oponenta třeba o 40 kg těžšího (zde je <a href="https://www.youtube.com/watch?v=N9LRH6qj7j0">video</a>, kde se žena ubrání násilníkovi na ulici pomocí BJJ). V moderním MMA tvoří BJJ velkou část dovedností nutných pro šanci uspět, obzvlášť když se boj přesune na zem. V tomto článku se dozvíte, proč je právě BJJ tak skvělé fitness pro IT profesionály, a to jak muže, tak ženy.</p>

<!-- more -->

<p>Jak jiu jitsu vlastně vypadá? Pokud jste zhlédli jakýkoliv díl Johna Wicka, tak už jste BJJ už viděli.</p>

<p>V tomto <a href="https://youtu.be/_aOpGPQFpPM">videu</a> se můžete podívat, jak BJJ kouč rozebírá pár scén z filmu. Pro začátek je důležité podotknout, že BJJ je hlavně o pákách, škrcení a lámání, a díky absenci úderů či kopů lze BJJ cvičit i ve stáří. Na konci článku pak uvedu několik dalších zajímavých BJJ videí. </p>

<p>Předtím, než rozeberu BJJ jako takové, bych měl sdílet, jak jsem se k BJJ dostal já. Začal jsem ho trénovat v roce 2019, dnes jsem v něm tedy aktivní již přes dva roky. V té době jsem pracoval jako linuxový sysadmin a dokončoval inženýrská studia IT bezpečnosti. Měl jsem za sebou už několik kurzů bojových umění, ale vždy to byly jen techniky bez sparringu (tzn. procvičování nově naučených technik ihned v boji naživo s reálným oponentem, tak důležité pro nějakou reálnou retenci informací). Zkoušel jsem karate a krav magu v půlročních kurzech, ale vždy to byly jen izolované techniky bez testování v “reálném provozu”. Tím pádem to byly bezcenné informace, které mi dodaly pouze psychologický Dunning-Krugerův efekt falešné kompetence. Při reálném konfliktu bezcenné, a možná až nebezpečné. Každé bojové umění, které za něco stojí, potřebuje sparring. Pokud si totiž člověk techniku ihned neotestuje, je mu k ničemu. K tomu se váže i úderné rčení - “Při souboji nedosáhneš svých očekávání, klesneš na úroveň svého tréninku”. Při souboji není čas myslet. Proto je důležité mít zaryté techniky v Nevědomí a dělat je automaticky - a toho je možné dosáhnout jen díky procvičování technik naživo při sparringu.</p>

<p>V té době jsem začal hodně slýchat o BJJ ze všech koutů internetu, ale nikdy jsem si nepomyslel, že bych já, introvertní programátor, do něčeho takového šel. Souhra náhod mě však dovedla právě k BJJ.</p>

<p>Zprvu mě nenapadlo, že by se moje nedostatečná znalost sebeobrany přenesla do jiných aspektů života, ale začal jsem si toho všímat. Např. v tehdejší práci jsem měl zavolat jednomu CEO velké české firmy, když jsem řešil migraci jejich serverů k nám. Prokrastinoval jsem asi hodinu, než jsem se k tomuto jednoduchému hovoru odhodlal. Zní to jako banalita, ale právě proto jsem to chtěl začít řešit. Prokrastinoval jsem kvůli nervozitě, které jsem se chtěl zbavit. V práci sysadmina je velice potřeba určitá údernost a odolnost, kterou jsem v té době postrádal. Nabalily se na sebe i další věci, související s odolností vůči stresu a nátlaku (o spojitosti s BJJ dále). Zkrátka jsem se při konfliktu nedokázal v reálném čase efektivně bránit. Posledním impulsem pro mě pak byla skoro vzniklá hospodská rvačka, kde jsem si uvědomil, že bych neměl žádnou šanci proti 120-kilovému oponentovi se svými tehdejšími fyzickými (ne)dovednostmi. A s tím jsem chtěl něco udělat.</p>

<p>Takže jsem se zapsal na jiu jitsu lekce v Brně. Přijít mezi 30 lidí v kimonu (gi) bylo na počátku hodně mimo moji komfortní zónu, ale ukázalo se, že mnoho z nich byli stejní začátečníci jako já. Navíc jsem se dozvěděl, že někteří z mých sparring partnerů pracují s neuronkami, jsou to sysadmini, datoví analytici nebo weboví vývojáři. Kouč mi pak řekl, že z nějakého důvodu má na lekcích hodně lidí z IT. A takové nadšení jako po první lekci BJJ jsem dlouho necítil. Po pár lekcích jsem si uvědomil, že to je pravděpodobně jediný sport, jediná fitness aktivita, která mě opravdu baví. Nebyl jsem nikdy fyzicky zaměřený. Běh mi vždy přišel jako utrpení. Nikdy jsem se nedostal do “endorfinového opojení”. Do fitka jsem chodil v kuse několik měsíců a dostal se na obstojnou úroveň, ale ve výsledku jsem v tom neviděl žádný smysl. To se právě změnilo s BJJ. Není repetitivní jako fitko. A není to nudné utrpení jako běhání. Ale to mluvím z pozice člověka, který potřebuje hodně stimulace a hodně smyslu v tom, co dělá.</p>

<p>Po pár lekcích jsem se do BJJ opravdu ponořil a rozhodl se, že dosáhnu modrého pásku (druhý pásek po bílém, což je cíl na cca 3 roky). Z každé lekce jsem si odnášel krvavé prsty a klouby s oděrkami o kimona ostatních - v BJJ jsou totiž klíčové úchopy. Pravidelně mě doprovázela bolest paží, ramen a loktů z lámání v armbarech (lámání paže) a namožené krční svalstvo ze škrcení - až do bodu, kdy jsem nemohl polykat bez bolesti. To mě ale nezastavilo, naopak. Konečně jsem zažil reálný boj. Cítil jsem se jako Tyler Durden.</p>

<p>V každé lekci se učíte něco nového, studnice technik a jejich kombinací je v BJJ nevyčerpatelná, což je zároveň intelektuálně velice stimulující. Každá nová lekce je nová výzva. Proto se myslím někdy přezdívá BJJ “lidské šachy”. S šachy však nemá BJJ, kromě množství kombinací, nic společného. Trefnější přezdívkou BJJ je “Umění praní prádla, zatímco je stále nošeno”. Každá nová hodina přináší nový cíl. A proces dosahování cílů se pojí s uvolňováním dopaminu. Takže každá tato minivýzva přináší pozitivní emoce. Toto vše je umocněno tím, že si nacvičenou techniku ihned vyzkoušíte ve sparringu. Máte tak ihned možnost ovládnout oponenta a vyhrát nad ním. A nebo prohrát a fyzicky procítit, jaké chyby jste udělali a jaké už nedělat. Plno technik se vám do těla zaryje na emocionální úrovni. BJJ je proto pro mě jakási aktivní meditace. U BJJ se cvičíte nemyslet a používat svoje tělo co nejefektivněji.</p>

<p>Pak je zde sociální aspekt. Myslím, že ve 30 letech se přátelé nehledají vůbec snadno. Sociální okruhy jsou teď hlavně rodina a kolegové. BJJ je pro introvertního programátora, který tráví většinu času u PC, jako požehnání. Automaticky se zde seznámí s velkým množstvím lidí, které pak vídá pravidelně více jak 2x týdně. A veškerý sociální tlak je smazaný kontextem. Všichni jsme na matu (mat - “žíněnka”, pojem označující podlahu BJJ gymu) a přátelsky spolu bojujeme a učíme se.</p>

<p><img src="https://www.create-it.cz/Blog/PublishingImages/Stranky/BJJ/bjj.png" alt="bjj.png" /></p>

<p>Intelektuální a psychologický aspekt jiu jitsu jsem již zmínil. Jsou zde neustále nové techniky na naučení a zdokonalení. V BJJ se člověk nepřestane nikdy učit, stejně jako je tomu ve všech IT oborech. Je potřeba se neustále překonávat. Váš charakter se projeví i ve stylu, jakým bojujete. Vaše předsudky se projeví ihned. V začátcích BJJ vás dokáže porazit i 17letá holka s modrým páskem. To člověku rychle srazí ego a donutí ho uvědomit si realitu situace. Pro mentální rozvoj je každý bojový sport skvělý. A schopnost fyzicky se bránit i proti většímu oponentovi dodá člověku vnitřní pocit sebevědomí a stability. Když vás zalehne 120-kilový modrý pásek tak, že sotva můžete dýchat (side-control pozice), tak se z toho musíte umět rychle dostat. Bench-press na něco takového nepomůže, je potřeba umět techniku. A i tehdy je to náročné. Je to enormní nátlak, který je třeba vydržet a správně provést únik do lepší pozice. Při sparringu za hodinu bojujete třeba i s 15 lidmi, po 3 až 5minutových kolech, takže si vyzkoušíte všechny možné formy boje. A postupně si takhle budujete mentální houževnatost, která se pak promítne do všech částí života, ať už jde o obchodní vyjednávání nebo sociální vztahy. Cvičíte si také sílu vůle a pro další postup v BJJ je samozřejmě potřebná silná disciplína.</p>

<p>Poslední aspekt, který je pro IT profesionály dobrý (a dost možná nejdůležitější), je fitness. Tělu je nutné kompenzovat ochabování způsobené sezením u PC 8-14 hodin denně. Nemít v životě žádnou pravidelnou fitness aktivitu není dlouhodobě udržitelná strategie u někoho, kdo prosedí tolik času u PC. Někdo to řeší chozením do fitka, někdo běháním, někdo lezením po stěnách, a pak je tu právě BJJ. Zaručeně protáhne celé tělo a je to skvělé kardio, které bude vždy stimulující. Navíc je zde problém sebedisciplíny outsourcován do skupiny ostatních bojovníků. Stačí nepřijít dva týdny na lekce a všichni ostatní jsou znatelně lepší, než vy, takže jste nuceni chodit i když se vám zrovna “nechce”.</p>

<p>Jak jsem slíbil, zde jsou další zajímavá videa z BJJ. Tohle <a href="https://youtu.be/1JipHH72DSw">video</a> z UFC ukazuje bojovníka Ryana Halla, držitele černého pásku, který při boji využívá hlavně BJJ, čímž získává značnou výhodu nad mnoha oponenty. A v tomto krásném souboji Nurmagomedova a Poiriera o vítězi zápasu rozhodlo právě BJJ <a href="https://youtu.be/8Iy6t0Zt6is?t=719">video</a>. Toto <a href="https://youtu.be/nAEWx5bsv0g">video</a>, kde učitel cvičí se svojí ženou, zase ukazuje zajímavé detaily, které vám pomohou dostat se z closed guard základní pozice.</p>

<p>Po 2 letech cvičení BJJ mohu říci, že jsem díky němu posílil svoji vůli, disciplínu a jsem více sebevědomý. Naučil jsem se být více ve svém těle, než v hlavě, takže se i prohloubilo moje cítění. Moje fitness je na nejvyšší úrovni, kterou jsem kdy měl - do té doby jsem totiž neměl sportovní aktivitu, která by mě opravdu bavila. Z perspektivy mé oblíbené Jungiánské psychologie toto vše spadá pod archetyp Bojovníka. Cvičení bojového umění ho posiluje.</p>

<p>Komplexita BJJ zajistí, že vám nikdy nedojdou nové věci na naučení. Pokud zvažujete vyzkoušet si BJJ, není nic snazšího než zavolat do místního BJJ gymu a zeptat se na detaily. Učitelé, u kterých jsem byl, nabízí první lekci zdarma a nově příchozím dokonce zapůjčí kimono. Plno BJJ technik navíc naleznete na YouTube, takže si můžete předem ověřit, jestli by to bylo něco pro vás. Já sám budu v BJJ pokračovat dlouhé roky. Jak říká jedno moudré rčení “Černí pásci jsou jen bílí pásci, kteří se na to nevykašlali”.</p>

<p> </p>

<p> </p>

<p> </p>

<p> </p>

<p> </p>

<p> </p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Story analysis of my top 3 favorite dystopian games]]></title>
    <link href="https://blog.jilecek.cz/blog/2021/11/27/story-analysis-of-my-top-3-favorite-dystopian-game/"/>
    <updated>2021-11-27T12:00:00+00:00</updated>
    <id>https://blog.jilecek.cz/blog/2021/11/27/story-analysis-of-my-top-3-favorite-dystopian-game/</id>
    <content type="html"><![CDATA[<p>Okay, I am gonna tell you about my top 3 favorite games. All of them share similar characteristics, like the hero fighting against tyranny or nihilism. All of them are existentialist, dystopian and partly post-apocalyptic. I am going to analyze the story, setting and philosophy behind these games. Let’s do it!</p>

<!-- more -->

<h2 id="half-life-2">Half Life 2</h2>
<p><img src="https://blog.jilecek.cz/images/story-analysis-of-my-top-3-favorite-dystopian-game-02.jpg" alt="" />
The first game is Half Life 2. The best thing about it is the story. I am a big fan of George Orwell’s 1984 and dystopian stories in general, so I appreciate the dystopian elements in Half Life 2.
I come from a post-communist country, so I got a real feel of how it was to live in a totalitarian regime. You know, the post-communist countries like the Czech Republic, Slovakia, Ukraine, Belarus, Latvia.. they share a similar feel. A lot of Half Life 2 looks like it takes place in Eastern Europe, and you can see this even more in Half Life: Alyx.
In Half Life 2, there is a massive tyrannical alien race in the Universe, called Combine. They are like Reapers in Mass Effect, but in HL2, these Combine aliens are classic tyrants. And they are so great and efficient at what they do.
They invade the world they want to overtake and they use its resources for their benefit, but in a way that there is no friction or resistance at all. So they manipulate the political leaders, and they use minimal effort in this.
They are very efficient, they use the resources of the victim. So, in HL2, these aliens manipulate the political leader — Dr. Breen, and they use all sorts of very clever things to control the citizens.
At the beginning of HL2 when you, Dr. Gordon Freeman, arrive at City 17, you can see the other confused people, and if you listen to them, one guy tells you “Don’t drink the water, they put something in it to make you forget”. Another guy on the train tells you “I hate it when they relocate us, I never get used to it”. And these are very subtle hints at what’s going on.
The Combine wants to keep people separated, so they move all the people to various cities, so they can never form any friendship, any family, any resistance. They are all alone and afraid because they have no power. And when they are afraid and they have no friends, they can’t form any sort of resistance. So that’s a clever thing to do for a tyrant. And that’s one of many subtle things that you may not notice when playing Half Life games.
Another thing is that they use this constructed language, similar to newspeak in 1984. They use medical and biological terms to hide the atrocious acts they do. To cauterize the wound means killing everybody in the area. Non-mechanical sexual stimulation rewards means being allowed to have real sex (there is a suppression field in Half Life, preventing the sexual urge). More in the video below.
The guards, the Combine, the Civil Protection (CP) units, if you listen to their radio comms, you can infer from that that they are manipulated by fear. Because the CP are still human. They are collaborators, traitors of humankind, and they collaborate with Combine because they are afraid. They have reasons to be, because when they fail to capture you, Gordon Freeman, not only them, but their whole family is gonna be wiped out. And the same thing happens if they die capturing you. Their whole family is gonna be wiped out. So, in a way, you, Gordon Freeman, the silent protagonist, the hero of HL2, when you kill a CP guard, you also kill his family. So you, Gordon Freeman, killed hundreds, thousands of people from the families of the collaborators, innocent people.
This is very similar to the social status system North Korea has. If you fuck up in a major way, it’s over for your whole family, your grandparents, and your children. Your DNA will be erased.
If they find that someone is collaborating with the resistance, they (the Combine Overwatch AI) deduct food rations from the whole bloc, which is how it happens in communist countries and communist regimes. The closest thing to it is North Korea. And if you watch the documentaries about North Korea (e.g. <a href="https://www.imdb.com/title/tt13243898/?ref_=nv_sr_srsg_3">The Mole: Undercover in North Korea</a>), they are stuck like in the 1960s, and they live in fear, they can’t even fucking smile. They can smile only about the things the leader has done. If you do anything wrong, and you live in the bloc, and if you do something that is against the leader, against the regime, if somebody tells on you, you are in big trouble, but so it the whole bloc of people, because they are associated with you. This of course breeds fear, this is a thing that happens in communist countries. I know because this was happening in Czechoslovakia. Your neighbours would tell on you. If you had more cash than you should’ve, they told on you and the authorities came and took it away. They will be guarded against the unforeseen consequences this might have on the whole block. So they will be protected, as collaborators.
The people behave like tyrannical leaders, and this is something I got from Dr. Jordan Peterson — because he studied totalitarian regimes for 40 years, so he knows his stuff — the individual in a tyrannical country behaves like the tyrannical state. That’s why it works. Because every single individual in these countries behaves in congruence with the tyrannical regime. Everybody is a tyrant. Every single individual in that country is a tyrant. All you have to do is to look at North Korea. People there are so afraid they tell on each other.. the point is, that’s why it’s often enough that one free man, like Gordon Freeman, takes action, and people follow.
<strong>Václav Havel</strong>, the revolutionary behind the fall of communism in Czechoslovakia, and the first Czech president writes in his book “<strong>Power of the powerless</strong>” about the “substance” of a post-totalitarian regime like we had. The substance of the wall of tyranny surrounding the people is seemingly hard as steel, but it is enough for one man to start speaking Truth, and the substance becomes fragile and soft as paper.</p>
<h2 id="dark-souls-prepare-to-die-edition">Dark Souls: Prepare to die edition</h2>
<p><img src="https://blog.jilecek.cz/images/story-analysis-of-my-top-3-favorite-dystopian-game-03.jpg" alt="" />
Let’s move on to Dark Souls. My second most favorite game. I’ve already made a video about this — <a href="https://youtu.be/x5OtJOk3Vik?t=61">link</a>. I talk more about the mythology of Dark Souls than replayability.
Dark Souls is mythological and existentialist- the Universe is nihilistic, nothing matters of course, BUT — you have to create your own meaning. That’s what Dark Souls is about. Against all odds, you, a nobody, can turn around the nihilism, the inevitable doom of humanity, you can turn that around, just by having some hope for the future.
my Dark Souls analysis starts at 1:00
In Dark Souls, you begin in a cell, locked in a prison with some other people who lost all hope. And this guy, Oscar of Astora, throws you a key (he actually throws you a corpse with a key), through the roof. He frees you from the prison. He isn’t sure that you are the Chosen One, so hee frees everybody from the prison. This is of course metaphorical, symbolical, element of the story. If you think let’s say to the Matrix — that is the same story. Matrix is the prison, Neo is the nobody, but he’s actually the Chosen One, but Morpheus doesn’t know this, so Morpheus saves everybody he can from the prison, from the Matrix.
He’s the archetype of Senex, which is a Jungian archetype, he’s the Wise Old Man, you can see it in all good movies and games. The hero is being shown how to do things by the old and experienced mentor — by a Senex, which is a detail-oriented wise old man. In the Lord of the Rings it’s the Gandalf, in Star Wars it’s Obi-Wan, in Matrix it’s Morpheus, in Dark Souls it’s Oscar of Astora, in Fight Club it’s Tyler, in Mr. Robot it’s Mr. Robot and in Fallout New Vegas, which I am gonna talk about next, you start with being killed, and this old doctor saves you.
So, Dark Souls begins in prison, Oscar frees you, and you kill bosses on your way to the Kiln of the first flame. And you sacrifice yourself the same way as Jesus because all of these stories are analogical to Jesus’ journey. Same as Matrix, it’s the same story. Jesus Christ had to sacrifice himself for the good of humanity. Same as Neo, he had to die and be resurrected, same as the guy in Dark Souls, in the end, he burns himself — or you can choose not to do it and let the darkness come. But if you sacrifice yourself, you will use your Soul, your Dark Soul, to prolong the Age of fire (Light) by 1000 years, and then somebody else, some brave individual, must come and burn his Soul again. That same concept exists in Buddhism. Buddha has the same life path and story as Jesus Christ. Avoid temptation, walk the narrow path, attain Enlightenment… and then come back. Story of Dark Souls is analogical.</p>
<h2 id="fallout-new-vegas">Fallout: New Vegas</h2>
<p><img src="https://blog.jilecek.cz/images/story-analysis-of-my-top-3-favorite-dystopian-game-04.jpg" alt="" />
The third favorite game of mine is Fallout: New Vegas.
As I said, you start with being shot in the face. You are a courier, a nobody. And you are carrying a platinum chip for another Senex archetype, Mr. House. You are a regular guy. This is often the case in mythology and stories in general, you are just a guy. Every-man archetype eventually becomes the Hero. Because a member of the herd can always rise above, through Truth. You have to be willing to learn new things, you can’t be arrogant. You can’t become arrogant, otherwise you will stagnate. So to progress in the story (of your life), you need to start as the Every-man.
The story of Fallout: New Vegas is dystopian and post-apocalyptic. It’s again about saving humanity, humankind. There are multiple factions in FN:V, there is Caesar’s Legion. They are tyrannical, they use slaves and murder people by crucifixion.
<img src="https://blog.jilecek.cz/images/story-analysis-of-my-top-3-favorite-dystopian-game-05.jpg" alt="" />
Tyrannical Caesar’s Legion
Then there is NCR, the New California Republic. The story of FN:V is that America caused the nuclear apocalypse, and these NCR guys are trying to keep the old ways because they think they are good without realizing that the “American way of thinking” is what caused the nuclear apocalypse in the first place.
<img src="https://blog.jilecek.cz/images/story-analysis-of-my-top-3-favorite-dystopian-game-06.jpg" alt="" />
NCR
Those are the main two sides, factions.. and there is this Mr. House, who is the Senex in this story, a visionary. He is a pacifist I would say, but he’s that kind of pacifist who understands how things really are.
<img src="https://blog.jilecek.cz/images/story-analysis-of-my-top-3-favorite-dystopian-game-07.jpg" alt="" />
He’s not like Albert Einstein, who used to be a pacifist in a wrong naive way. Einstein thought it would be good if countries had such a system that it would be impossible to have a war against each other. This is of course nonsense, because if you want peace, you need to prepare for war. That’s it. Even in normal real-life social interactions between men, if you are weak, you can’t be a real pacifist. In that case everybody knows you can’t defend yourself, so if you say you are a pacifist, everybody sees you are just saying that because you are harmless. You have to be strong and be able to cause mayhem, and then choose not to. That’s what being a pacifist is really about. You need to be able to defend yourself and then choose not to attack. If you have this ability people will just not fuck with you. And that’s what America has been doing for a long time. They constantly need to stay on top, the arms race. The danger of negative consequences of attacking them needs to be so big, that the attacker chooses not to do it. So that somebody chooses not to do anything stupid. Mr. House is that kind of guy. He has an army of military robots and he wants to avoid another war.
I think this is a good time to stop. So, that’s it about my 3 favorite games, I hope you enjoyed this read, and don’t forget to follow me for more stories!
<img src="https://blog.jilecek.cz/images/story-analysis-of-my-top-3-favorite-dystopian-game-08.jpg" alt="" />
<a href="https://www.artstation.com/artwork/gJrOym">Dr. Gordon Freeman,</a> Solaire of Astora, NCR veteran ranger</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[NFTs, DeFi, chytré kontrakty a jaká je jejich budoucnost]]></title>
    <link href="https://blog.jilecek.cz/blog/2021/10/20/NFT/"/>
    <updated>2021-10-20T12:00:00+00:00</updated>
    <id>https://blog.jilecek.cz/blog/2021/10/20/NFT/</id>
    <content type="html"><![CDATA[<p><img src="https://create-it.cz/Blog/PublishingImages/Titulni/2021/NFT.jpg" alt="" /></p>

<p>Hlavními trendy ve světě kryptoměn jsou teď decentralizované finance, DeFi, a non-fungible tokens, NFT. Obě technologie mohou využívat tzv. chytré kontrakty. V tomto článku se podíváme na všechny 3 zmíněné pojmy, popíšeme si, co znamenají pro vývoj kryptoměn a kde se používají, a také zvážíme jejich výhody a nevýhody. Všechny 3 technologie se točí hlavně okolo Etherea, platformy, na které dnes stojí hodně altcoinů. Doporučuji přečíst si také moje starší články o tom, jak funguje <a href="https://create-it.cz/Blog/Stranky/Blockchain.aspx">blockchain</a>, a dva díly (<a href="https://create-it.cz/Blog/Stranky/altcoiny1.aspx">I.</a>, <a href="https://create-it.cz/Blog/Stranky/altcoiny2.aspx">II.</a>) o alternativních kryptoměnách.</p>

<!-- more -->

<h2 id="defi">DeFi</h2>

<p>DeFi je zkratka pro decentralizované finance. Tento pojem pod sebou zastřešuje různé finanční a blockchainové aplikace, které mají za cíl zbavit se prostředníků v transakcích.</p>

<p>DeFi se inspiruje zejména blockchainem, tedy technologií, na které stojí většina dnešních kryptoměn. Jen pro zopakování, blockchain umožňuje více entitám držet kopii historie transakcí, takže není pod kontrolou jednoho centralizovaného zdroje. To je důležité, jelikož centralizované systémy mohou omezovat rychlost a sofistikovanost transakcí, a zároveň omezit uživateli kontrolu nad vlastními penězi. DeFi rozšiřuje funkcionalitu blockchainu z jednotlivých transakcí na komplexnější finanční systémy.</p>

<p>Přímé prodeje nejsou jediným typem transakce nebo kontraktu mezi velkými společnostmi; finanční aplikace jako půjčky, pojištění, crowdfunding nebo sázení jsou také pod jejich kontrolou. Zbavení se prostředníka v těchto transakcích je jednou z hlavních výhod DeFi.</p>

<p><strong>Podívejme se na pro a proti DeFi ve srovnání s klasickým bankovním systémem:</strong></p>

<h2 id="ty-držíš-svoje-peníze-vs-banka-drží-tvoje-peníze">Ty držíš svoje peníze VS banka drží tvoje peníze</h2>

<p>Ano, člověk má absolutní moc nad svými penězi. Je tu ale nebezpečí, že ztratí nebo zapomene svůj seed, a všechny kryptoměny jsou navždy ztraceny. U bank je určitá jistota, že se o klientovy peníze postarají v případě nějakého hacku. Pak je tu samozřejmě inflace, ale ta existuje v obou případech. Kryptoměny jsou v bezpečí alespoň do příchodu dostatečně výkonných kvantových počítačů (což zabere minimálně dalších 50 let), schopných <a href="https://en.wikipedia.org/wiki/Post-quantum_cryptography">překonat</a> asymetrické šifrování. Až se to stane, tak bude mít problém celý technologický svět, nejen kryptoměny, u kterých najednou půjde odvodit seed z veřejné adresy peněženky. (více o seedech v <a href="https://create-it.cz/Blog/Stranky/Blockchain.aspx">prvním článku</a>).</p>

<h2 id="transakce-zabírají-minuty-vs-transakce-mohou-zabrat-dny">Transakce zabírají minuty VS transakce mohou zabrat dny</h2>

<p>U kryptoměn jsou transakce velice rychlé. Tedy v případě, že není zahlcena síť, jak tomu bylo např. na konci roku 2017, kdy průměrný poplatek za transakci dosahoval 42 dolarů. Pokud jste zaplatili méně, na transakci jste mohli čekat hodiny až dny. Vše je ovlivněno transakčními poplatky. Čím vyšší poplatek za transakci, tím dříve se uskuteční. Ethereum 1.0 podporuje až 30 transakcí za sekundu, Ethereum 2.0 bude zvládat až 100 tisíc transakcí za sekundu a Bitcoin zvládá 7 transakcí za sekundu.</p>

<h2 id="transakce-jsou-pseudo-anonymní-vs-transakce-jsou-svázané-s-identitou">Transakce jsou pseudo-anonymní VS transakce jsou svázané s identitou</h2>

<p>Kryptoměny nejsou svázané s identitou, jako je tomu u bank, takže se často používají pro vyhnutí se daním a pro nelegální činnosti. Pokud by byly kryptoměny dále neregulované a opravdu by nahradily klasické peníze ve velkém měřítku, tak by mohly vést k rozpadu států, protože by do státní kasy neproudily daně od občanů. Kryptoměny jsou ve své podstatě anarchistické, a toto jejich jádro by se manifestovalo v reálném světě. Na druhou stranu, ve státech s utlačujícím totalitním režimem jsou kryptoměny cestou ke svobodě.</p>

<p>Potenciálně nebezpečné následky lze vidět i u novinky ze Severní Korei. Virgil Griffith, jeden ze zakladatelů Etherea, se tento týden <a href="https://www.bleepingcomputer.com/news/security/ethereum-dev-admits-to-helping-north-korea-evade-crypto-sanctions/">u soudu přiznal</a>, že v roce 2019 pomáhal Severní Koreji, aby se za použití Etherea vyhnula sankcím USA a učil je jak prát peníze. Griffith byl v minulosti vyhozen z týmu Tor vývojářů za prodávání de-anonymizovaných dat, takže je zřejmé, že není naivní a Koreji pomáhal vědomě. Severní Korea <a href="https://www.csfd.cz/film/923232-krtek-spionem-v-severni-koreji/recenze/">nemá finanční zdroje</a> a anonymita kryptoměn by jim mohla velice pomoci ve zbrojení a rozšíření svého vražedného totalitního režimu za hranice. Takových příkladů je možné použít více, např. ze světa organizovaného zločinu. Bude také zajímavé sledovat, jak dopadne pokus v <a href="https://www.nbcnews.com/news/latino/el-salvador-hits-snags-adopts-bitcoin-official-currency-first-country-rcna1910">El Salvadoru</a>, kde tamní prezident uzákonil Bitcoin jako hlavní měnu.</p>

<h2 id="nfts">NFTs</h2>

<p>NFTs, non-fungible tokens, jsou nenahraditelné nebo nezaměnitelné tokeny. Například jedna mince je zaměnitelná, protože představuje to stejné jako další mince stejné hodnoty.</p>

<p>Většina kryptoměn je také zaměnitelná. Jeden Bitcoin se rovná jednomu Bitcoinu. Nezaměnitelné tokeny však, jak název napovídá, nelze zaměnit. Tyto digitální soubory, vyražené (“<a href="https://coinmarketcap.com/alexandria/article/how-to-mint-an-nft#header-6">minted</a>”) do blockchainu, představují majetek, který je jedinečný a vzácný.</p>

<p>Záznam vytvořený na blockchainu dokáže ověřit kdo je kdo a hlavně kdo jej vlastní. Při převodu vlastnictví dochází také k záznamu. Lze si snadno představit, jak tento systém může změnit způsob, jakým zaznamenáváme a přenášíme digitální vlastnictví. Soubory dnes běžně posíláme online, ale NFT přidává další vrstvu ověřování dat, tudíž lepší zabezpečení.</p>

<p>Existují i chytré kontrakty (o těch si povíme níže), kdy tvůrce může kódovat licenční poplatky do svých NFT, takže kdykoliv bude aktivum znovu prodáno na trhu, bude mu připsán výdělek za přeprodej díla. Tento záznam je na blockchainu uložen na věčnost, takže tvůrce může obdržovat legální výdělky z díla po celý zbytek života.</p>

<p>Umělec Beeple <a href="https://www.theverge.com/2021/3/11/22325054/beeple-christies-nft-sale-cost-everydays-69-million">prodal</a> v březnu svoje NFT za 69 milionů dolarů. NFTs se však netýkají jen umění, mohou držet jakýkoliv druh dat. Jsou skoro jako nový formát souboru.  NFTs jsou jen pár kroků od toho, aby byly použity pro jízdenky, prodej pozemků a možná i cenných papírů. Je tu však stále možnost, že NFTs jsou jen další bublinou, dalším výstřelkem, který rychle pomine. Zatím to vypadá, že NFT využívají hlavně influenceři, kteří jsou schopni díky svému rozsáhlému publiku prodat i umělecké kýče.</p>

<p>Některé altcoiny se také snaží spojit NFT s herním světem. Pak by herní předměty, jako např. meče ve WoW nebo lodě v EVE Online, byly navždy majetkem hráče. Podle mého názoru jsou však tyto snahy až přehnaně ambiciózní a neskončí úspěšně. U umění mají NFT smysl, ale hráčům je víceméně jedno, jakým způsobem vlastní herní virtuální předměty. Záleží hlavně na herní ekonomice a trhu (jak tomu je u Team Fortress 2 klobouků nebo CS:GO skinů, trhů, které mají <a href="https://www.youtube.com/watch?v=t8QEOBgLBQU">větší kapitalizaci než některé reálné státy</a>). Přechod na blockchain by vyžadoval masivní předělání základů hry, a u starých her jako WoW je toto skoro vyloučeno. Většina her má jen omezenou podporu ze strany vývojářů a i u fenoménů jako je CS:GO se po čase přejde hlavně na kosmetické změny. Proto by tyto altcoinové projekty musely vyvinout i svoje AAA herní tituly nebo doufat, že jejich systém využijí vývojáři pracující na nové hře velikosti Fortnite.</p>

<p>Velké herní distribuční platformy jako je <a href="https://www.nme.com/news/gaming-news/steam-is-removing-nft-games-from-the-platform-3071694">Steam už dnes banují NFT hry</a> ze svého obchodu. Určitě totiž nebudou podporovat něco, co je může ochudit o výdělky. Jak Valve, tak Apple i Google si berou 30% z příjmů z vnitřní herní ekonomiky. Takže těmto NFT projektům nebude stačit vyvinout AAA herní tituly, ale dokonce budou muset vybudovat distribuční systémy a jejich reputaci, aby byli schopni konkurovat platformám Epic Store a Steam. Zkrátka, adopce blockchainu bude pomalá, a je dost možné, že tento výstřelek NFT gamingu rychle pomine. Ale možná se mýlím.</p>

<h2 id="smart-contracts">Smart Contracts</h2>

<p>Smart contracts, neboli chytré kontrakty, jsou jednoduché programy, které běží na blockchainu. Je to sbírka funkcí a stavů, které jsou spojeny s určitou blockchainovou adresou. Nejpopulárnější implementací tohoto protokolu je měna Ethereum, proto se budeme věnovat hlavně jí. Dají se využít jak v DeFi, tak v NFT.</p>

<p>Chytré kontrakty jsou typem Ethereového účtu, tzn. že mají nějaký zůstatek a mohou posílat transakce přes síť. Nejsou nicméně pod kontrolou uživatele, ale jsou nasazeny do sítě a běží podle svého programu. Uživatelské účty pak mohou s těmito kontrakty komunikovat zasíláním transakcí, které provedou funkci definovanou v kontraktu. Chytré kontrakty mohou určovat pravidla, stejně jako běžný kontrakt, a automaticky vynucovat jejich dodržení. Interakci, která s kontraktem proběhne, už nelze vzít zpět.</p>

<p><a href="https://en.wikipedia.org/wiki/Nick_Szabo">Nick Szabo</a>, který v 90. letech přišel s konceptem chytrých kontraktů, tedy dlouho před vznikem Bitcoinu, popisuje tyto kontrakty jednoduchou metaforou - jako automat na kávu. Pokud kontrakt obdrží správný vstup, vygeneruje určený výstup. Níže uvádím příklad kódu takového chytrého kontraktu, v jazyce Solidity.</p>

<p><img src="https://create-it.cz/Blog/PublishingImages/Stranky/NFT/eTe7.png" alt="eTe7.png" /></p>

<p>Stejně jako reálné automaty na kávu nevyžadují zaměstnance pro prodej kávy, chytré kontrakty mohou nahradit prostředníky v mnoha oborech.</p>

<hr />

<p>To je o dnešních trendech vše. Původně jsem chtěl psát další článek o alternativních kryptoměnách, jako je Solana nebo Polkadot, jimž se přezdívá “Ethereum-killers”, ale zvolil jsem abstraktnější přístup. U Solany totiž nedávno nastalo masivní fiasko, kdy se ukázalo, že je naprosto centralizovaná (vývojáři byli schopni vypnout celou transakční síť). Tyto přehnaně ambiciózní projekty skoro vždy vedou k nezdaru, jak se za roky ukázalo u měn jako byla např. IOTA. Proto při investicích doporučuji staré známé a ověřené coiny, které tu zaručeně budou i za 10 let, tzn. Bitcoin, Ethereum a Cardano. </p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Build a simple CRUD todo app with Python Flask in 100 lines of code or less]]></title>
    <link href="https://blog.jilecek.cz/blog/2021/06/10/build-a-simple-crud-todo-app-with-python-flask-in/"/>
    <updated>2021-06-10T12:00:00+00:00</updated>
    <id>https://blog.jilecek.cz/blog/2021/06/10/build-a-simple-crud-todo-app-with-python-flask-in/</id>
    <content type="html"><![CDATA[<p><img src="https://blog.jilecek.cz/images/build-a-simple-crud-todo-app-with-python-flask-in--02.png" alt="" /></p>

<!-- more -->

<p>In this tutorial we are gonna build a simple CRUD app (<em>Create, Read, Update, Delete</em>) for keeping a “TODO” list. We will use Python 3 and two external libraries. The first one is the Flask web framework and the second in SqlAlchemy, ORM mapper for easier database manipulation. We’ll use Bootstrap as the frontend. Python code will fit into 50 lines of code and the HTML too.</p>
<h2 id="install-the-dependencies-and-prepare-the-environment">Install the dependencies and prepare the environment</h2>
<p>First, we will use the pip dependency manager to install flask and SQLAlchemy (pip is shipped with every Python installation).
<img src="https://blog.jilecek.cz/images/build-a-simple-crud-todo-app-with-python-flask-in--03.png" alt="" />
Let’s create a template folder in the root folder. Flask uses it to load HTML templates. Create a new index.html file.
<img src="https://blog.jilecek.cz/images/build-a-simple-crud-todo-app-with-python-flask-in--04.png" alt="" /></p>
<h2 id="imports-and-app-initialization">Imports and app initialization</h2>
<p><img src="https://blog.jilecek.cz/images/build-a-simple-crud-todo-app-with-python-flask-in--05.png" alt="" />
First, we need to import the required dependencies. Then we initialize the Flask app (we use the active module name, <em>__name__</em>, as the argument). Then we create the database connection. I am using a basic file database, SQLite. If you have a more complex database running as a separate process (MariaDB, Postgres), use that. You only need to change the connection string. We then pass this string as a URI db address and run SQLAlchemy. An important step is to define the database model.
For that we create the <em>Note</em> table, with automatic <em>id</em>, the <em>text</em> of the todo task, boolean holding the <em>done</em> value, and an automatic date <em>dateAdded</em>, holding the creation time. Later we will initialize the database with this model.</p>
<h2 id="crud-api">CRUD API</h2>
<p>Let’s create 4 methods, that will ensure that our app will be a CRUD app — it will be able to create, read, update and delete records.
<img src="https://blog.jilecek.cz/images/build-a-simple-crud-todo-app-with-python-flask-in--06.png" alt="" />
The <em>create_note</em> method has only the task <em>text</em> as a parameter. First, we create a new <em>Note</em>, pass this parameter as text and save it in the database. For <em>read_notes</em>, we only list all <em>Note</em> records from the database. The <em>update_note</em> method has 2 parameters, <em>text</em> and <em>done</em>. The <em>text</em> is again the text of the task and <em>done</em> is the value of the checkbox of the form that we will create. If the value of this checkbox is “on” (ie. it is checked), then the stored boolean value <em>done</em> will be <em>True</em>, otherwise <em>False</em>. Now only the method for deleting, <em>delete_note</em>, remains.</p>
<h2 id="home-page-adding-and-displaying-records">Home page, adding and displaying records</h2>
<p><img src="https://blog.jilecek.cz/images/build-a-simple-crud-todo-app-with-python-flask-in--07.png" alt="" />
In the Flask framework, endpoints are defined using the <em>@ app.route</em> decorator. The first parameter is the relative URL. Another optional parameter holds the allowed request methods, in our case <em>POST</em> and <em>GET</em> for form processing. The <em>POST</em> method means that we are sending a form with a newly created task. But whether it is <em>POST or GET</em>, we will display the <em>index.html</em> template and pass to the <em>Jinja</em> template system all the tasks we have stored in the database (<em>read_notes</em>) to draw them into the template.
<img src="https://blog.jilecek.cz/images/build-a-simple-crud-todo-app-with-python-flask-in--08.png" alt="" />
The first form will be connected to the “/” endpoint, ie. to the home page. It will only have one input field for the text and a submit button. Then we will go through all the records we passed to the template in the notes variable and display them all. Later we will add a form to each record — so it will be possible to edit and delete individual records from the frontend. For now, the page looks like this. We can add and display, but not edit and delete.
<img src="https://blog.jilecek.cz/images/build-a-simple-crud-todo-app-with-python-flask-in--09.png" alt="" /></p>
<h2 id="editing-deleting-and-better-frontend">Editing, deleting, and better frontend</h2>
<p><img src="https://blog.jilecek.cz/images/build-a-simple-crud-todo-app-with-python-flask-in--10.png" alt="" />
The method for editing and deleting is a bit more complicated. We specify the relative address of the endpoint as <em>/edit/note_id</em>, ie. that we will pass a parameter to the URL, which we named <em>note_id</em>. We pass it to the <em>edit_note</em> method. If the input request is made via <em>POST</em>, we pass the input form to the <em>update_note</em> function to modify the task. If as a <em>GET</em> request, then we delete the given task. When done, we will redirect everything to the original page.
In the Python code, we call <em>db.create_all</em>, which creates a database with all the tables we specified (in our case, only <em>Note</em>) and then runs the entire Flask application.
Finally, we adjust the template to make it look good. This requires a significant modification of the existing HTML code (for the whole application, visit my <a href="https://github.com/janjilecek/simple_python_flask_crud_todo_app">Github</a>).
<img src="https://blog.jilecek.cz/images/build-a-simple-crud-todo-app-with-python-flask-in--11.png" alt="" />
First, we will import bootstrap CSS styles. We will edit all forms into bootstrap styles and change each listed task to a form that will have a checkbox on the left and a button on the right to confirm the text editing. If the checkbox is checked, we call the redirect function via <em>onChange</em> javascript, which sends a <em>GET</em> request to the address <em>/edit/note_id</em>. If the update button is clicked, it will be sent to the same <em>POST</em> request address. We will also add small details such as displaying the creation time of the task on mouse hover. The rendered template now looks like this:
<img src="https://blog.jilecek.cz/images/build-a-simple-crud-todo-app-with-python-flask-in--12.png" alt="" />
And this is our final application! We looked at how to create endpoints for creating, editing, reading, and deleting records, connected the frontend to them, and wrapped everything in bootstrap styles to make our application look good, and we did it all in less than 100 lines of code. The whole application is available on my <a href="https://github.com/janjilecek/simple_python_flask_crud_todo_app">Github</a>. I hope you have learned something new and see you next time!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[How could Hitler influence whole nations to such an extent?]]></title>
    <link href="https://blog.jilecek.cz/blog/2021/05/01/how-could-hitler-influence-whole-nations-to-such-a/"/>
    <updated>2021-05-01T12:00:00+00:00</updated>
    <id>https://blog.jilecek.cz/blog/2021/05/01/how-could-hitler-influence-whole-nations-to-such-a/</id>
    <content type="html"><![CDATA[<p><img src="https://blog.jilecek.cz/images/how-could-hitler-influence-whole-nations-to-such-a-02.png" alt="" />
One of the “rehearsing photos” that Hitler wanted to be destroyed
First, we will take a look at the political circumstances of Hitler‘s time that made his rise to power possible. Then we will assess the crucial events from his personal history and his psychological profile. And finally in chapter 7, we will analyze how a schizophrenic psychopath like him could influence whole nations.</p>
<h2 id="1-what-were-the-primary-political-and-economic-issues-of-his-time"><strong>1. What were the primary political and economic issues of his time?</strong></h2>
<p>Put yourself in the shoes of an average German in 1921. Your country just lost the Great War (WW1), you have to pay reparations to certain countries (roughly equivalent to $442 billion in 2021) and your military is severely restricted. Germany is forced to accept the sole responsibility for all the loss and damage of the war. Your national pride is shattered. You feel humiliated on the international stage.
Then in 1929, the Great Depression strikes. The German economy begins to collapse. You cannot feed your family. Everyone around you is suffering. Then comes Adolf Hitler, the leader of the NSDAP party, and promises to restore national pride, take back the land lost in the war, and create more jobs. He has an enchanting charisma and it seems like he can vocalize every feeling of the crowd. He says everything the people want to hear — and then he does exactly what he promises. Everybody loves what he is saying. You believe this visionary leader will take you to a better future.</p>
<h2 id="2-what-were-the-crucial-events-of-his-childhood"><strong>2. What were the crucial events of his childhood?</strong></h2>
<p>4 out of 5 of Hitler’s siblings died, which left a sense of him being exceptional in his mind. At the age of six, his father, Alois Hitler, retired on a pension from the Austrian civil service. He was an alcoholic and a brute and he often beat him. Little Adolf did well in the monastery school and considered becoming a priest. He was always bossy and even when playing with other children, he told them what to do. He is quick to anger and spoiled by his mother, Klara.
His father was 22 years older than his mother. The whole family rented a cheap flat, but the mother kept everything shiny clean, as would later note the family’s doctor Eduard Bloch. Hitler’s obsession with cleanliness was fed since the beginning.
At the age of 9, he discovered his hidden talent for drawing, especially buildings. He wanted to go to a classical school, but his father insisted on a technical secondary school.
Hitler was deeply affected by the death of his younger brother Edmund, who died in 1900 from measles. Hitler changed from a confident, outgoing, conscientious student to a morose and detached boy.</p>
<h2 id="3-of-his-adolescence"><strong>3. Of his adolescence?</strong></h2>
<p>Hitler did very poorly in his first year of technical school and became very detached. There were many arguments with his father about his career choice. In Mein Kampf he states that he intentionally did poorly in school, hoping that once his father saw “what little progress I was making at the technical school he would let me devote myself to my dream”. Young Adolf found the idea of spending his life in an office job horrible, whereas his father saw the idea of him becoming an artist ridiculous.
In high school, Hitler became interested in history and the idea of Pan-Germanism (unifying all the German-speaking people). His father died in January of 1903, ending their constant battles and allowing him to pursue his dream of becoming an artist.
In 1906 he met a new friend, August Kubíček (Kubiczek), who had Czech parents. They shared a passion for the operas of Richard Wagner and became best friends and later roommates in Vienna. Hitler was fascinated with the mythological content of the operas, later using some of the themes in his ideology.
Hitler was very close to his mother, so when she developed breast cancer, he didn’t cope very well. The doctor taking care of her was Czech Jew <a href="https://spartacus-educational.com/Eduard_Bloch.htm">Eduard Bloch</a>. After the war he shared his very interesting notes on the Hitler family:</p>
<blockquote>
  <p>“While Hitler was not a mother’s boy in the usual sense, I never witnessed a closer attachment. Their love had been mutual. Klara Hitler adored her son. She allowed him his own way whenever possible. For example, she admired his watercolor paintings and drawings and supported his artistic ambitions in opposition to his father at what cost to herself one may guess.”</p>
</blockquote>

<!-- more -->

<p>After Klara Hitler died of breast cancer in 1907, the doctor has another important note:</p>
<blockquote>
  <p>“I sat with the family for a while, trying to ease their grief. I explained that in this case death had been a savior. They understood. In the practice of my profession it is natural that I should have witnessed many scenes such as this one, yet none of them left me with quite the same impression. <strong>In all my career I have never seen anyone so prostrate with grief as Adolf Hitler.</strong> “</p>
</blockquote>

<p>As the doctor recalls, the mother’s death devastated Hitler, confirming he had an extreme emotional bond to her, unlike anybody else. That points to a strong Oedipal complex, as we will discuss in the psychology section, and to his inability to cope with life’s tragedies.
Some critics claim that his mother’s death under the hands of a Jewish doctor triggered Hitler’s antisemitism. The fact that 18 years old Hitler granted the doctor his “everlasting gratitude” for not charging any treatment fees refutes that. In 1908 Hitler even wrote Bloch a postcard assuring him of his gratitude which he expressed with handmade gifts and a large wall painting. Later in 1937, Hitler called him a “noble Jew”.</p>
<h2 id="4-of-his-young-adulthood"><strong>4. Of his young adulthood?</strong></h2>
<p>When his mother died he left Linz to live and study fine art in Vienna, financed by orphan’s benefits. He applied to the Academy of Fine Arts (twice) and was rejected both times. The professors told him he would make a fine architect, not a painter. His friend Kubíček got in.
Hitler expected the university will accept him, so the failure demolished his self-esteem and sent him into a downward spiral. He ended up homeless. He focused his hate on the middle-class bourgeoisie, which rejected him and couldn’t understand his “genius”.
He probably left Vienna to evade conscription into the Austrian Army, and in 1914 he enlisted into the Bavarian Army. Because of his Austrian citizenship, he had to request permission to serve in the Bavarian army. It was most likely a clerical error because as an Austrian citizen he should not be allowed to join the German ranks.</p>
<h2 id="5-what-happened-to-him-during-ww1"><strong>5. What happened to him during WW1?</strong></h2>
<p><img src="https://blog.jilecek.cz/images/how-could-hitler-influence-whole-nations-to-such-a-03.jpg" alt="" />
In October 1918, at Werwicq in Belgium, he fell victim to a British gas attack, or so he claimed. He was taken to a Bavarian field hospital at Qudenaarde, unable to see. All the men who had been exposed to gas were treated, but the doctors refused to treat Hitler. They diagnosed him as a “war neurotic” and transported him to the hospital in Pasewalk. His temporal blindness was not from the gas, but a form of “hysterical blindness”.
This incident is one of the key events in Hitler’s early life and could have been a huge factor in shaping Hitler’s future personality. On his hospital admission, Hitler was examined by psychiatrist Dr. Edmund Foster. The diagnosis? A psychopath with hysterical symptoms. During his hospital stay he “miraculously” recovered from the blindness. That convinced him he is the Messiah and his life’s mission was to “save” Germany.
In Mein Kampf, he says that his eyes “turned into glowing coals”. He probably convinced himself he was a victim of the gas attack. Unfortunately, witnesses of the event either committed suicide or disappeared. The event had a deep psychological influence on Hitler. His own “exceptionality” was now confirmed by surviving a deadly attack. Hitler would later cover all his tracks, so he could be politically invincible. On September 11, 1933, Dr. Forster was found dead in his bathroom after an interrogation by the Gestapo.</p>
<h2 id="5-what-was-the-start-of-his-political-career-like"><strong>5.</strong> What was the start of his political career like?</h2>
<p>On November 8, 1923, Hitler marched with around 2500 of his supporters through Munich. He planned to seize the city and use it as a base for a march against Germany’s national government. This event would later be called “Beer Hall Putsch”.
During the putsch, 16 members of the Nazi group and 4 policemen were killed. The attempt at a coup failed. Hitler fled to the house of his press spokesman, Ernst Hanfstaengl, where he almost committed suicide. Hanfstaengl’s wife Helena stopped him by taking his gun. This behaviour was not unusual. Hitler frequently threatened suicide if events did not go his way. Hitler was later found and arrested on November 11, 1923.
He was accused of treason and sentenced to 5 years in Landsberg Prison. Here he would go on and formulate and write Mein Kampf. He was also treated by a psychologist, Alois Maria Ott. During his trial preparation, he constructed a set of arguments for a speech he would later use during the trial — and he succeeded. His speech was printed in the daily journal.
In prison, he went on a hunger strike. In 1924 he was treated by a psychologist Alois Maria Ott. Ott shared his experiences after many years when he was 98 years old (more on that in the next section).</p>
<h2 id="6-what-was-his-psychological-profile"><strong>6. What was his psychological profile?</strong></h2>
<h3 id="jungian-theory">Jungian theory</h3>
<p>According to Carl Jung, who has also seen one of Hitler’s speeches in person, Hitler was primarily a hysteric. He probably had a sub-form of hysteria — pseudologia phantastica. That means he was a pathological liar who absolutely believed everything he said. That could grant the person possessed by the illness a few productive months of positive public attention.
At the same time, it’s also a form of idealism, where the visions are considered to be a noble aim and have to be attained no matter the cost. The possessed believes he is doing everything for the benefit of the whole of humanity and is blind to the fact that his aim is purely egoistic. The psychopathy of such behaviour is not easily recognizable by a layman.
But how could such a hysteric psychopath influence whole nations like that? All we have to do is to look at the character of an average German at the moment in time. German people were full of resentment born from their national inferiority complex, fed by the loss of WW1 (by the time referred to as the Great War, as WW2 hasn’t happened yet) and the Versailles treaty consequences.
By far the most interesting insight of master Jung is about Hitler’s rise to power. “Suggestion works only when there is a secret wish to fulfill it”, he says. By that, he points to Hitler’s followers and helpers. His words and ideas worked on them because of their inferiority complex and secret dreams of power. As a result, he gathered an army of psychopaths and criminals around him (Goebbels, Goering). At the same time, he grabbed the collective unconscious of normal people, who are always naive and consider themselves “innocent and right”.
Jung saw that Hitler’s hysterical mind puts on all of his gesticulations, intent on making an impression. Jung says that the majority of normal people are ridiculously unconscious and naive and are open to any suggestion. That is normal mass psychology. “The more people live together in heaps, the stupider and more suggestible the individual becomes”.</p>
<h3 id="jungs-wotan-theory">Jung’s Wotan theory</h3>
<p><img src="https://blog.jilecek.cz/images/how-could-hitler-influence-whole-nations-to-such-a-04.jpg" alt="" />
In 1889, the year of Adolf Hitler’s birth, Franz von Stuck painted “The Wild Chase”, depicting Wotan. Look closely.
Another interesting insight is about the Pan-Germanic pagan god Wotan (equivalent to Odin). Jung thought that Hitler and the German nation were possessed by him.</p>
<blockquote>
  <p><strong>Carl Jung:</strong> But what is more than curious — indeed, piquant to a degree — is that an ancient god of storm and frenzy, the long quiescent Wotan, should awake, like an extinct volcano, to new activity, in a civilized country that had long been supposed to have outgrown the Middle Ages. We have seen him come to life in the German Youth Movement, and right at the beginning the blood of several sheep was shed in honour of his resurrection. Armed with rucksack and lute, blond youths, and sometimes girls as well, were to be seen as restless wanderers on every road from the North Cape to Sicily, faithful votaries of the roving god. Later, towards the end of the Weimar Republic, the wandering role was taken over by the thousands of unemployed, who were to be met with everywhere on their aimless journeys. By 1933 they wandered no longer, but marched in their hundreds of thousands. The Hitler movement literally brought the whole of Germany to its feet, from five-year-olds to veterans, and produced the spectacle of a nation migrating from one place to another. Wotan the wanderer was on the move. He could be seen, looking rather shamefaced, in the meeting-house of a sect of simple folk in North Germany, disguised as Christ sitting on a white horse. I do not know if these people were aware of Wotan’s ancient connection with the figures of Christ and Dionysus, but it is not very probable.
Perhaps we may sum up this general phenomenon as Ergriffenheit — a state of being seized or possessed. The term postulates not only an Ergriffener (one who is seized) but also an Ergreifer (one who seizes). Wotan is an Ergreifer of men, and, unless one wishes to deify Hitler — which has indeed actually happened — he is really the only explanation. It is true that Wotan shares this quality with his cousin Dionysus, but Dionysus seems to have exercised his influence mainly on women. The maenads were a species of female storm-troopers, and, according to mythical reports, were dangerous enough. Wotan confined himself to the berserkers, who found their vocation as the Blackshirts of mythical kings.
With Hitler you do not feel that you are with a man. You are with a medicine man, a form of spiritual vessel, a demi-deity, or even better, a myth. <strong>With Hitler you are scared. You know you would never be able to talk to that man; because there is nobody there.</strong> He is not a man, but a collective. He is not an individual, but a whole nation. I take it to be literally true that he has no personal friend. How can you talk intimately with a nation?
“All these pathological features — <strong>complete lack of insight into his own character, auto-erotic self-admiration and self-extentuation, denigration and terrorization of one’s fellow men</strong> (how contemptuously Hitler spoke of his own people!), <strong>projection of the shadow, lying, falsification of reality, determination to impress by fair means or foul, bluffing and double-crossing</strong> — all these were united in the man who was <strong>diagnosed clinically as an hysteric</strong>, and whom a strange fate chose to be the political, moral, and religious spokesman of Germany for twelve years. Is this pure chance? “</p>
</blockquote>

<h3 id="general-personality-assessment-and-neo-freudian-theory"><strong>General personality assessment and Neo-Freudian theory</strong></h3>
<p>The main hypothesis, according to the <a href="https://www.google.com/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;cd=&amp;cad=rja&amp;uact=8&amp;ved=2ahUKEwjs77yOm6nwAhUtmIsKHa5_AjYQFjAAegQIAhAD&amp;url=https%3A%2F%2Fuccs.edu%2FDocuments%2Ffcoolidg%2FDSM-Assessment-of-Hitler-%2520Final%2520Copy%25202007.pdf&amp;usg=AOvVaw0PI_S6MozNBYn2xQifZ3Ya">DSM-IV Assessment of Adolf Hitler,</a> was that Hitler would have been diagnosed with paranoid schizophrenia today.
5 psychologists got together and retrospectively rated Hitler’s personality on multiple scales. The consensus was that Hitler was very strong on the PTSD scale, had psychotic thinking, schizophrenia, and major depressive disorder. Personality disorders-wise he was paranoid, antisocial, narcissistic, sadistic, and schizoid.
According to the study, the borderline scale did not reach clinical significance, but the descriptions from Hitler’s life appear to meet many of the borderline criteria including unstable and intense interpersonal relationships, identity and sexual identity issues, and anger. The borderline criteria also include suicidal gestures. There are 3 known suicidal events — one in the press spokesman’s house after the failed Beer Hall putsch, another in prison, and the third and final in 1945.
Finally, all five raters saw him as a strong introvert. This is consistent with the fact that Hitler was socially awkward and often unable to converse with others, and preferred to talk at them.
Neo-Freudian psychologist Erich From proposed that Hitler suffered from an Oedipal conflict. He believed he transferred these Oedipal feelings for his mother into allegiance to the German nation and corresponding conflict with “her” prosecutors. Hitler unconsciously wished to kill his rejecting father, and projected this wish into Jewish Marxist intellectuals, and by association, all other Jews.</p>
<h3 id="hitlers-psychologist-diagnosis"><strong>Hitler‘s psychologist diagnosis</strong></h3>
<p>While in Landsberg prison in 1924, Hitler was rehabilitated by a prison psychologist, <a href="https://www.psychiatrictimes.com/view/alois-maria-ott-i-was-hitler-s-psychologist">Alois Maria Ott</a>. He disclosed his experiences with Hitler at the age of 98.
On arrival at the prison, Hitler was “of moderate strength,” 5 feet 9 inches tall, and weighed 76 kilograms. In this examination, it was also found that Hitler had “right-side cryptorchidism” or an undescended right testicle. This rumor was thus confirmed in 2015 thanks to the prison report.
Hitler would either remain silent, “acted fresh, or broke out into crying fits.” His shouts and screams could be heard all over the building. After a few sessions with Hitler, Ott made his assessment of the prisoner<strong>:</strong> a hysteric and pathological psychopath.</p>
<h2 id="7-how-could-hitler-influence-whole-nations-to-such-an-extent"><strong>7. How could Hitler influence whole nations to such an extent?</strong></h2>
<p><img src="https://blog.jilecek.cz/images/how-could-hitler-influence-whole-nations-to-such-a-05.png" alt="" />
Another of the “rehearsing photos”
The whole nation of Germany was feeling depressed and then the financial crisis came. Jung argues that the climate of Germans was almost that of a “psychological inferiority”. Hitler simply embodied the feeling of the majority of people.
An interesting insight comes from the book “Ordinary men”, which is about a squad of Nazi executioners in the concentration camps. It would be simple to explain their behaviour as driven by fear of punishment if they don’t do their job (that is, executing camp prisoners). But as comes to light from the book, there were almost no consequences if they didn’t obey orders.
They were not forced at all but were told that they can leave whenever they want without any consequences. At first, the executioners had tremendous difficulties with carrying out the executions (symptoms like vomiting after the act and psychological trauma). Eventually, they adapted and started having no difficulties with executing Jew prisoners.
The book “Hitler’s willing executioners” goes to greater lengths describing this squad of soldiers. The soldiers executed Jew prisoners in greater numbers than others. That points to the hypothesis that the members of the working-class (the executioners were “normal” people, construction workers before the war, etc.) had inherent hate towards Jews and the antisemitism was not a symptom of Hitler’s propaganda but was already inside the general public. Hitler came and only awoken it from the collective unconscious of the German public.</p>
<blockquote>
  <p><strong>Carl Jung:</strong> Now, the secret of Hitler’s power is not that Hitler has an unconscious more plentifully stored than yours or mine. Hitler’s secret is twofold: first, that his unconscious has exceptional access to his consciousness, and second, that he allows himself to be , moved by it. <strong>He is like a man who listens intently to a stream of suggestions in a whispered voice from a mysterious source and then acts upon them.</strong> In our case, even if occasionally our unconscious does reach us as through dreams, we have too much rationality, too much cerebrum to obey it. This is doubtless the case with Chamberlain, but Hitler listens and obeys. The true leader is always led. We can see it work in him. <strong>He himself has referred to his Voice. His Voice is nothing other than his own unconscious, into which the German people have projected their own selves; that is, the unconscious of seventy-eight million Germans. That is what makes him powerful.</strong></p>
</blockquote>

<h2 id="8-other-interesting-facts-about-hitler-to-conclude"><strong>8. Other interesting facts about Hitler to conclude</strong></h2>
<p>His father was very dominant and his mother very submissive. He mirrored this in his sexual relationships. His girlfriends were always naive, childish, and submissive. This points to his under-developed Anima and her projection into real women. All his girlfriends either tried or succeeded at committing suicide, either to gain his attention or from realizing what kind of man he is. Including Eva Braun, who tried to commit suicide after he didn’t pay enough attention to her.
He was vegetarian and loved animals, especially dogs. He didn’t drink any alcohol, probably because his father was an alcoholic and he hated him. He often worked late into the night, like a nighttime artist. He was extremely obsessed with cleanliness and was a mysophobe (fear of filth). He bathed multiple times a day. His extremely elevated disgust sensitivity also explains why he often referred to Jews as a virus, infection, and cancer. He saw Germany as “One body” and Jews as a virus or cancer that was destroying it. He often openly refers to Jews as viruses and infection in his public speeches.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Create Flappy Bird clone in Unity Bolt visual language in 10 minutes or less]]></title>
    <link href="https://blog.jilecek.cz/blog/2021/03/23/create-flappy-bird-clone-in-unity-bolt-visual-lang/"/>
    <updated>2021-03-23T12:00:00+00:00</updated>
    <id>https://blog.jilecek.cz/blog/2021/03/23/create-flappy-bird-clone-in-unity-bolt-visual-lang/</id>
    <content type="html"><![CDATA[<p><img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-02.png" alt="" /></p>

<!-- more -->

<p>If you want to become a game developer, but were always afraid of learning a programming language, Bolt visual scripting language might be the right starting point for your gamedev journey!
Two main game engines in the industry, Unreal Engine 4 and Unity now both have the option to use a visual scripting language, instead of the classic programming languages. In the case of UE4 it’s has always been the blueprint system (used primarily instead of C++) and in the case of Unity it’s Bolt.
In this tutorial we will make a clone of the popular game Flappy Bird and we will replicate the original controls and obstacle generator. The obstacles will be infinitely generated off-screen and move to the left (common trick to create the illusion of movement of the main character that the infinite-scroller games use). Let’s do it!
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-40.gif" alt="" />
The final game + the player controller Bolt graph</p>
<h2 id="installing-bolt">Installing Bolt</h2>
<p>First we create a new 2D project in Unity 2020 and we install Bolt (<a href="https://assetstore.unity.com/packages/tools/visual-scripting/bolt-163802">link</a>). If you are not sure how to create a new project or install a new package, check the first part of my game development <a href="https://blog.jilecek.cz/basics-of-3d-animation-in-unity-tutorial-d2d6ff3bc6b7">series</a>.
Select 2D as the type of the new project. After importing Bolt from the Asset Store, download it in Unity via the <em>Package Manager → My Assets → Download</em>.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-04.jpg" alt="" />
And then install it via <em>Tool → Install Bolt</em>. Follow the setup wizard (<em>Next → programmer naming → next → generate</em>).
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-05.jpg" alt="" /></p>
<h2 id="player-character">Player character</h2>
<p>We will use an alien as the main player character. You can choose whatever sprite you like, I found the alien on <a href="https://kenney.nl/assets/alien-ufo-pack">Kenney’s game assets page</a>.
But first we need to create a new game object for it. Click in the hierarchy window and select <em>2D Object</em> → <em>Sprite.</em>
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-06.jpg" alt="" />
Rename the new object to <em>Alien</em>.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-07.jpg" alt="" />
In the <em>Sprite Renderer</em> component change the Sprite to <em>shipGreen_manned</em> (you can also download the asset from my github repo with the complete project solution. Links below).
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-08.jpg" alt="" />
Press the <em>Add Component</em> button and add a <em>Polygon Collider 2D.</em> This way we will make sure to use perfect collision detection with the obstacles. Next we add <em>RigidBody2D</em> for gravity simulation. Change the <em>Mass</em> and <em>Drag</em> parameters to 0.1 and 1 respectively, so the player movement matches that of the original Flappy Bird.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-09.jpg" alt="" />
In the scene view move (W shortcut) the object to the left of the screen viewport.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-10.jpg" alt="" />
Next we add the most important component, <em>Flow Machine</em>. It will control the logic for controlling the character.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-11.jpg" alt="" />
Let’s change the <em>Source</em> to <em>Embed.</em> Rename it to <em>Alien</em> and add description.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-12.jpg" alt="" />
After you click the <em>Edit graph</em> button a new interface appears. We will use this graph editor for the visual scripting.
The graph has <em>Start</em> and <em>Update</em> method, just as any new script implementing the <em>MonoBehavior</em> interface.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-13.jpg" alt="" />
You can add new function with the output arrow or clicking into the empty space. Dragging the node output arrow will load a dialogue for searching the existing methods. So let’s find a method for the keyboard input (<em>Input.GetKeyDown</em>), so we can control our character.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-14.jpg" alt="" />
Let’s use the Space key for flying. Pick <em>Space</em> as the <em>key</em> parameter.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-15.jpg" alt="" />
Continue with <em>Control → Branch</em> (if condition equivalent).
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-16.jpg" alt="" />
Next we will need the reference for the RigidBody2D component of the player object.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-17.jpg" alt="" />
Pick the <em>RigidBody2D</em> as the <em>type</em>.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-18.jpg" alt="" />
Let’s add a kinetic impulse via the <em>RigidBody2D.AddForce</em> function. That will emulate the Flappy Bird movement — each press “kicks” the bird upwards.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-19.jpg" alt="" />
We want the Alien to “jump” up, so let’s change the <em>y coordinate</em> to 1 and <em>mode</em> to <em>Impulse</em>.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-20.jpg" alt="" />
Complete logic for the player character looks like this:
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-21.jpg" alt="" />
Now when we run the game, we can control the alien by using the spacebar.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-22.gif" alt="" />
If you like this tutorial, check out my udemy course where I can teach you how to make an 3D action horror game in Unity! Below is a coupon code for a 50% OFF, it will be available for the next 30 days.</p>
<h3 id="hi-my-name-is-jan-jileček-and-i-am-a-professional-game-developer-with-masters-degree-in-computer-science-and-ive">Hi, my name is Jan Jileček and I am a professional game developer with master’s degree in computer science and I’ve…</h3>
<p><a href="https://www.udemy.com/course/make-a-3d-game-in-unity-2020-from-scratch-with-free-assets/?couponCode=9F7413B32A5AC0DC7973">www.udemy.com</a></p>
<h2 id="obstacles">Obstacles</h2>
<p>Same as with the Alien, we add a new Sprite via the <em>2D Object → Sprite</em> menu and rename it to Obstacle. In the <em>Sprite Renderer</em> component we pick the <em>elementMetal055</em> sprite (also from kenney.nl or my github).
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-23.jpg" alt="" />
And we add a <em>Box Collider 2D</em>.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-24.jpg" alt="" />
Using the <em>Rect</em> tool we change the dimensions of the obstacle object to match the original obstacles of Flappy Bird. We move the obstacle slightly outside the viewport (we will manipulate the position of the generated instance of a new obstacle via the flow graph).
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-25.jpg" alt="" />
Rect tool
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-26.jpg" alt="" />
Now we duplicate the object (click it in the hierarchy window → <em>Duplicate</em>) and move it to the upper side of the screen, so we create a gap between the two panels.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-27.jpg" alt="" />
Next we create a new “parent” object, rename it to <em>ObstacleHolder</em> and associate the previous 2 <em>Obstacle</em> objects with it by dragging them onto the <em>ObstacleHolder</em>.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-28.jpg" alt="" />
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-29.jpg" alt="" />
We also have to create a so called “prefab” of the <em>ObstacleHolder</em> object. All you need to do it drag the ObstacleHolder object from the <em>hierarchy</em> window into the <em>Assets</em> window.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-30.jpg" alt="" />
This way we will be able to create instances of the object from the generator script. Now, when we have the prefab ready, we can delete the original <em>ObstacleHolder</em>. From now on we will be using only the prefab.</p>
<h2 id="obstacle-generator">Obstacle Generator</h2>
<p>Let’s create an empty object (<em>Create Empty</em>) for the obstacle generator. Rename it to <em>Generator.</em> Next add a <em>Flow Machine</em> component the same way as with the Alien, and open the graph editor.
In the left sub-window of the editor we can see the variable manager. Here we create a new scene variable of type <em>GameObject</em>, which will hold a reference to the <em>ObstacleHolder</em> prefab. After naming the new variable just drag the prefab from the <em>Assets</em> into the <em>value</em> field.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-31.jpg" alt="" />
Next we add a new graph node, <em>Timer</em>. It will be responsible for periodic obstacle generation. we need the Timer to start counting immediately after creating the generator, that is why we call it from the <em>Start</em> method. Let’s set the <em>duration</em> to 4 seconds.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-32.jpg" alt="" />
Each obstacle instance will be generated with a random offset on the <em>y</em> axis. For that we use the <em>Random.Range</em> function, which we set to generate a random number from 0.2 to 0.7 (I’ve tested these values, they are the best fit to common screen resolutions).
We will then pass the value to a new <em>Vector3</em> node, where we edit the x value to 1.4 (we need to spawn the obstacles outside the visible screen space, in this case it will tell the next method to spawn it 40% of the width to the right).
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-33.jpg" alt="" />
Next we pass this <em>Vector3</em> to the <em>ViewportToWorldPoint</em> function, which translates the provided values to screen coordinates. We also need to edit the camera parameter to <em>Main Camera</em>.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-34.jpg" alt="" />
Now we have the actual screen coordinate where we can generate a new obstacle. For that we will use the Instantiate function. We pass it the previously created reference to the <em>ObstacleHolder</em> (by using the <em>Get Variable → Graph → obstacle</em>), the calculated Vector3 position and a default rotation (<em>get Quaternion identity</em>).
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-35.jpg" alt="" />
Next we add a RigidBody2D component to the instantiated <em>ObstacleHolder</em> and set it to kinematic (<em>set RigidBody2D.bodyType</em>) and set the speed on x axis to -2 (<em>set RigidBody2D.velocity</em>). That will ensure a proper collision handling and movement to the left of the screen.
One more thing we need to do here is to connect all of this to the <em>Destroy</em> method, which will automatically delete the object after 20 seconds — when the object is already outside of the view and not needed. We need to pass to it an object instance that we created a few steps back.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-36.jpg" alt="" />
Last step is to connect the flow back to the <em>Timer</em>, so the whole sequence we just created repeats in a cycle (4 second timer = 4 second cycle).
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-37.jpg" alt="" />
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-38.gif" alt="" />
Let’s also add a collision detection of the player with the obstacle. Once that happens, the whole scene reloads, effectively restarting the game. We don’t need to worry about the details of the object we are colliding with, because we can collide literally only with 2 objects in this game.
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-39.jpg" alt="" />
<img src="https://blog.jilecek.cz/images/create-flappy-bird-clone-in-unity-bolt-visual-lang-40.gif" alt="" />
The final game!
This whole game project is available on my <a href="https://github.com/janjilecek/flappy_bird_clone_in_unity_bolt/tree/master">github</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Červená kniha - recenze]]></title>
    <link href="https://blog.jilecek.cz/blog/2021/01/26/redbook/"/>
    <updated>2021-01-26T12:00:00+00:00</updated>
    <id>https://blog.jilecek.cz/blog/2021/01/26/redbook/</id>
    <content type="html"><![CDATA[<p><img src="https://blog.jilecek.cz/images/port/redbook.jpg" alt="" /></p>

<p>V lednu jsem v rámci digitálního detoxu vypnul internet a místo toho jsem četl. Níže krátce recenzuji první z knih, které byly součástí mého experimentu.</p>

<!-- more -->

<p>Kniha, ve které mistr Carl Gustav Jung zachytil vize, které mu vyvstávaly z nevědomí v letech 1913-1917. Tyto vize potom dalších 16 let zpracovával a ručně zapisoval do kaligrafické Červené Knihy, která byla zveřejněna až po jeho smrti v roce 1961. Jung nezamýšlel, aby knihu četl kdokoliv, kdo nerozumí jeho snažení, proto ji dal za svého života dal číst pouze svým nejbližším přátelům a kolegům. Obsahy nevědomí, které do knihy zachytil, potom daly vzniknout jeho dalším životním dílům. Na jejich základě pak zformuloval definice kolektivního nevědomí, synchronistických událostí a archetypů.</p>

<p>Hlavní z těchto vizí byla záplava Evropy krví a tisíce smrtí. Těchto vizí měl několik, a dokonce se obával, že pochází z jeho osobního nevědomí (v té době ještě neměl rozpracovanou definici kolektivního nevědomí), a proto si myslel, že se stává schizofrenikem. Za pár měsíců se ale vize vyplnily, a nastala První světová válka. Pochopil, že vize pocházely z hlubší vrstvy nevědomí. Pak zjistil, že někteří umělci měli ve stejném období jako on podobné sny. To mu dalo další motivaci zabývat se kolektivním nevědomím a jeho funkcí.</p>

<p>Čtenářská edice obsahuje pouze text a cca 3 černobílé kopie ilustrací z původní Red Book, kterou Jung psal ručně 16 let. Psal ji variací jakéhosi švabachu v němčině, a snažil se o stejnou stylizaci, jakou měly staré texty psané mnichy. Hlavně jsou v původní verzi jeho nádherné kresby, ve kterých Jung zachycuje svoje vize, které mu doslova chrlily z nevědomí.</p>

<p><img src="https://blog.jilecek.cz/images/port/rb1.jpg" alt="Některé z jeho vizí" /></p>

<p>Přesto, že jsem velký Jungův fanboy, tak byly některé pasáže extrémně nudné - nakonec, jsou to analýzy aktivních imaginací dalšího člověka. Jung zde přibližně třetinu knihy promlouvá se svojí Duší, v další třetině s Elijášem a Salomé (jeho Senex a Anima, Logos a Eros, myšlení a cítění) a dále pak s Filemónem (kapitola Kouzelník, diferencovaný Senex). Jazyk je často dvojznačný, a Jung dlouho pracoval na tom, aby dokázal mluvit dvojznačně, jako jeho Duše. Mně trvalo první 2/3 knihy, než jsem porozuměl, co touto dvojznačností myslí. Některé pasáže totiž jsou zároveň absolutní pravda i absolutní nesmysl. Jung tím vyjadřuje paradoxní Boží podstatu, jak popisuji níže. Ale taková je povaha Duše. (pozn. - po dočtení další knihy s jeho esejemi, Výbor z díla III., chápu navíc tuto dvojznačnost jako nutný vyjadřovací prostředek pro sdělení paradoxní reality Duše. Alchymisté neúmyslně používali dvojznačné pojmy a volně zaměňovali symboly jako voda, vodní pára nebo oheň. To je ale vstupní požadavek při čtení alchymických textů, jímž vlastně je i Červená kniha. Člověk musí číst tyto texty s vědomím jejich hluboké symboliky.)</p>

<p>Jung probírá i další postavy a koncepty, jako je Pléróma (gnostický ekvivalent Tao) nebo Abraxas (Bůh zastupující podobný koncept). To je pro mě asi nejzajímavější obsah, který je přímo spojen s kvantovou mechanikou a panpsychismem (Vesmír je jedno s Bohem, nic není externím objektem a vše “objektivní” je pouze aspektem vědomí). Jung na dokázání této teze v pozdějších letech 1932-1934 pracoval s Wolgangem Paulim, jedním z prvních průkopníků kvantové mechaniky (Jung se začal zajímat o fyziku po řadě večeří s Albertem Einsteinem mezi lety 1909-1912). Dále zde Jung probírá počátky rozlišení dobra a zla v Bohu, jak to rozvinul ve svém Aionu, kde dokazuje, že Bůh je absolutní dobro i zlo zároveň, což moderní Křesťanství chybně rozštěpilo do dualismu.</p>

<p>Kniha má velice hluboké pasáže, nad kterými budu ještě dlouho přemýšlet. Knihu jako takovou však nemohu doporučit nikomu, kdo není již do nějaké míry obeznámen s dílem mistra Junga. Nebudu uvádět citace z knihy, jelikož by byly vytrženy z masivního kontextu, který je nutný k jejich plnému pochopení.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Everything you do leaves a debt.]]></title>
    <link href="https://blog.jilecek.cz/blog/2020/09/21/everything-you-do-leaves-a-debt/"/>
    <updated>2020-09-21T12:00:00+00:00</updated>
    <id>https://blog.jilecek.cz/blog/2020/09/21/everything-you-do-leaves-a-debt/</id>
    <content type="html"><![CDATA[<p><img src="https://blog.jilecek.cz/images/everything-you-do-leaves-a-debt-02.jpg" alt="" />
The basic law of the Universe is that of karma. Everything you do leaves a debt, be it good or bad.
I use this philosophy for my everyday life. I know that when I will partake in hedonistic pleasures, it will incur a debt, I will have to pay for later.
So, when I have a day that is full of easy things, then I know the second day will be full of difficult things. Thus I try to do very difficult things, so I can have an easy time later.
The same goes for any kind of project. Be it your college project or a work project. When I go for the easy way out, and I make some short-sighted decision, it ALWAYS comes back, sooner or later, and kicks me in the butt.
I can’t say how many times I used a “hacky” solution in a programming project, only for it to bring bugs or other implementation difficulties later on.
Thus, I now I try to go for long-term decisions, that are often hard to make and implement but are the only right thing to do, compared to short-term solutions that will need a rework later.
This concept even has a name in programming - it’s called “<a href="https://en.wikipedia.org/wiki/Technical_debt">technical debt</a>”.
I realized the same thing about my college years. I used to do a lot of college projects at the last minute, and often create them so it worked so-so. I used to study for exams in the last 2 days and have cram sessions, often on some kind of a stimulant.
Now, years later, I am not so confident in my knowledge, even though I have a master’s degree on the subject. Now I wish I paid more ATTENTION in my college years and put a deeper effort into my projects. But I was young and I had other things on my mind.
I read somewhere that the “opposite of love is not hate, but indifference”. Or one could also say “lack of attention”. Paying attention is really what I feel is the most important thing. I regret not paying attention more. It’s the most valuable thing we have.</p>
<h2 id="for-every-action-there-is-an-equal-and-opposite-reaction"><strong>For every action, there is an equal and opposite reaction.</strong></h2>
<p>This 3rd Newton’s law could also be described in one word: <strong>enantiodromia</strong>. It’s a psychological term introduced by Swiss psychiatrist Carl G. Jung, the founder of analytical psychology</p>
<blockquote>
  <p>“<strong>Enantiodromia</strong> is the emergence of the unconscious opposite in the course of time. This characteristic phenomenon practically always occurs when an extreme, one-sided tendency dominates conscious life; in time an equally powerful counterposition is built up which first inhibits the conscious performance and subsequently breaks through the conscious control.”</p>
</blockquote>

<!-- more -->

<p>It’s implicit in various complexes, for example the superiority complex. People with superiority complex consciously feel superior to others as a defense mechanism that covers their unconscious feeling of inferiority.
Taoists described this thousands of years ago. In Tao Te Ting, this phenomenon is described in 24th verse:</p>
<blockquote>
  <p><em>Those who stand on their toes are not steady.<br />
Those who take long steps cannot keep the pace.<br />
Those who show off do not shine.<br />
Those who are self-righteous are not prominent.<br />
Those who boast are not respected.<br />
Those who praise themselves do not prevail.</em></p>
</blockquote>

<p>Showing off has the exact opposite reaction to what the person expects and wants — his social status decreases. It’s rather fundamental knowledge, that is easy to talk about, but very hard to implement in real life.
This law is incredibly paradoxical, but fundamental, and I feel the whole Universe stands on it. However you call it, it’s here. And it’s important to know about it. Everything you do leaves a debt.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Jung's Labyrinth, moje psychologická explorační hra]]></title>
    <link href="https://blog.jilecek.cz/blog/2020/09/05/jungslabyrinth/"/>
    <updated>2020-09-05T12:00:00+00:00</updated>
    <id>https://blog.jilecek.cz/blog/2020/09/05/jungslabyrinth/</id>
    <content type="html"><![CDATA[<p><img src="https://blog.jilecek.cz/images/port/JL.jpg" alt="" /></p>

<p>Během koronavirové izolace mi moje nevědomí poslalo nápad na hru, který jsem naštěstí zachytil a zapsal.
Již nějakou dobu jsem koketoval s pár nápady na hororovu hru, která by používala mytologické koncepty, ve které bych mohl vyjádřit sebe a hlavně věci, které považuji za důležité a smysluplné a chtěl jsem je sdělit dalším lidem.</p>

<!-- more -->

<div class="embed-youtube">
<iframe width="560" height="315" src="https://www.youtube.com/embed/GjX9cSc2BLw" title="YouTube" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
</div>

<p>Nápad jsem dostal 22.5.2020 během dvoudenní spánkové deprivace. Nápad jsem ihned sepsal na několik papírů A4. Ihned mi došlo, že jsem pravděpodobně jediný, kdo tento nápad dostal, ale zůstaval jsem skeptický.</p>

<p>Navrhnul jsem si rigidní 3 měsíční vývojový cyklus, kde jsem si zkrátka předsevzal, že VŠE dokončím přesně za 3 měsíce. Vím, jak se gamedev (a všeobecně softwarové) projekty mohou roztáhnout i na roky, pokud jsou špatně naplánovány. Použil jsem strategii “Marketing first”.</p>

<p>Moje pochyby o jedinečnosti nápadu se rozplynuly, když jsem po měsíci každodenní práce na prvním alfa konceptu hry vydal Announcement Trailer. Tisíce lidí měly kladné reakce a několik komentářů se dotklo přímo i mé pochyby - potvrdili mi, že tento nápad je unikátní a nechápou, jak to ještě nikoho nenapadlo.</p>

<p>To na mě ale uložilo velkou zodpovědnost, kterou jsem nečekal - teď jsem měl tisíce fanoušků, kteří dychtivě očekávali, že hru dokončím. Proto jsem šel do sebe a další 2 měsíce nedělal nic jiného, než práci na hře a marketing.</p>

<p><img src="https://blog.jilecek.cz/images/port/gitimg.png" alt="Commity Jungova labyrintu. Prázdné dny jsou marketing a práce na archetypálním testu" /></p>

<p>Skrz mailovou kampaň jsem sehnal dobrovolníky pro dabing - velká část z nich jsou poloprofesionální dabéři a všichni z nich Jungiáni. Přesně ten typ lidí, který jsem potřeboval. Ozvali se i dva umělci, skladatel klasické hudby a malíř. Oba dva také Jungiáni, kteří jsou ve svých dílech přímo inspirováni Jungovou Červenou knihou a jejich díla jsem použil v Jungově Labyrintu.</p>

<p>Za marketing jsem neplatil ani korunu, vše jsem získal organicky přes reddit, facebook skupiny, twitter a imgur. Navíc jsem vytvořil i web, kde se lidi mohou otestovat na svůj archetyp - <a href="https://archetypes.jilecek.cz">https://archetypes.jilecek.cz</a>. Tento web jsem použil jako gateway na Steam store. Během 7 dnů přilákal cca 200 000 shlédnutí, jelikož se stal virální na twitteru. Nejvíc traficcu ale přišlo jednoznačně se subredditů jako /r/alchemy a /r/jung. Na redditu je také skvělý průnik Jungiání/gameři, kteří tvořili nejvíc konverzí. Jako metriku úspěšnosti mých strategií jsem používal počet Steam wishlistů. Také jsem budoval mailing list, jak pro uživatele archetypového testu, tak přímo fanoušky hry. Ten jsem použil pro pravidelné rozesílání updatů o hře a nakonec oznámení o vydání.</p>

<p>Vývoj jsem začal 1.6.2020 a hru vydal 5.9.2020 03:00 GMT+1 (4.9.2020 18:00 PDT) - tento den pro mě totiž má speciální význam, stalo se mi během něj několik synchronicit. K vývoji jsem použil engine Unity 2020.1.</p>

<p>Hru jsem první dva měsíce testoval sám, poslední měsíc pak s pomocí přátel na různě výkonných konfiguracích (včetně integrovaných GPU karet na Macu atd.). Hře jsem také přidal podporu pro Virtuální Realitu (testoval jsem na Oculus Rift S).</p>

<p>Stránka obchodu - <a href="https://store.steampowered.com/app/709710/Jungs_Labyrinth">https://store.steampowered.com/app/709710/Jungs_Labyrinth</a></p>

<p>Více o vývojovém procesu Jungova labyrintu se dočtete v mém anglickém <a href="https://medium.com/@janjilecek/analytical-psychology-driven-game-design-in-jungs-labyrinth-117184189097">článku</a> na medium.com</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Analytical psychology driven game design in Jung’s Labyrinth]]></title>
    <link href="https://blog.jilecek.cz/blog/2020/08/28/analytical-psychology-driven-game-design-in-jungs/"/>
    <updated>2020-08-28T12:00:00+00:00</updated>
    <id>https://blog.jilecek.cz/blog/2020/08/28/analytical-psychology-driven-game-design-in-jungs/</id>
    <content type="html"><![CDATA[<p><img src="https://blog.jilecek.cz/images/analytical-psychology-driven-game-design-in-jungs--02.png" alt="" /></p>

<!-- more -->

<p>Jung’s Labyrinth is a psychological exploration game I made in 3 months. The game is unlike any other. I noticed a niche on the market, for games that would utilize Jungian psychology. There are literally no games (or movies) that would go in-depth into archetypal/analytical psychology and use its concepts literally.
The official trailer for Jung’s Labyrinth
I compare Jung to Einstein, but unlike Jung, you can understand how Einstein came up with his theories. As he himself says, he just thought about a problem longer than normal people. But Jung… he was sort of an archeologist for the mind and the roots of consciousness. The depths of his understanding of the mind are scary. Each time I read his books I feel like reading something out of a Lovecraftian story, except it’s almost always scientific and provable.
But Jung’s opponents often claim that Jungian psychology is pseudo-scientific. Reading 10 pages of any of his books would prove them wrong, if only they tried it.
Jung came up with the concept of the Collective Unconsciousness, and he proved it. It means that there is a sort of a collective basis of our minds, from which everything stems. That means that a newborn’s mind is NOT a clean slate, but it’s already full of predetermined neural structures that form its character. Kind of like instinct in animals. Those things are shared among people and are called archetypes.
Archetypes exist in everyone, and each person has his own activated version of the archetype, a personal complex. The archetypes that are activated the most in you are shaped by the circumstances of your life.
Those archetypes include the Shadow, Anima and Animus (contrasexual identity), Wise Old Man and the Self.
The Shadow consists of repressed parts of your conscious personality, and are both good and bad. The Shadow holds your untapped potential, both negative and positive. Hitler was controlled by the vicious Shadow of everything he ever repressed and what his father Alois did to him. All that creative energy he had turned against him and eventually against the world. He projected his inferiority onto others.
<img src="https://blog.jilecek.cz/images/analytical-psychology-driven-game-design-in-jungs--03.png" alt="" />
The Anima and Animus are contra-sexual identities. Anima means “soul” (and Animus too). Anima is female and Animus is male. Everyone has a part of the opposite sex in himself. Yin Yang is THE representation of this concept.
In men it’s Anima, emotional, non-rational and spiritual personality. It also holds the image of the ideal partner, that you often project on a new sexual partner before you start to differentiate between the ideal and the reality.<br />
In women the situation is reversed. Animus is a manly spirit, rational and rather aggressive. The problem with Anima and Animus is that they are often low-resolution. For men it’s low resolution feeling and for women low resolution rationality. You can sometimes hear them in arguments, when the woman says “You always do this and this”, it’s the Animus talking. In these cases your Anima often reacts.
In mythology Anima takes many forms. Her shadow form is represented by Witches, Lamias, Nymphs, Naiads, Succubae etc.
<img src="https://blog.jilecek.cz/images/analytical-psychology-driven-game-design-in-jungs--04.png" alt="" />
And there is the Wise Old Man, or Senex. Detail-oriented old man who seeks the truth above all else. Without going into detail — imagine Dumbledore, Gandalf, the Architect from Matrix or any other Old Master (Lao Tzu).
These are the main 3 archetypes that are a part of the individuation process. Individuation is a psychological process of becoming who you are, or reaching your Self. As Buddhism describes the same process as Individuation, the state of reaching the Self could be described as attaining Nirvana.
There are many concepts and details I would like to talk about, but I want to talk about the game too, before I lose your attention.
The process of becoming who you really are happens unconsciously throughout your life. For example — your contra-sexual identity becomes activated in the later years, around 50 years of age. Men start to get more feminine and soft and women more masculine and hard.
The point of Individuation is to make this process conscious. Two main methods are by dream analysis, as dream symbols are a great source of information about your unconscious processes; and active imagination, which is a conversation with your inner archetypes.. self-induced dream state, similar to lucid dreaming.
I noticed there are no games or movies that would utilize this. For me, it’s the most important thing in life. Kindling the light of my consciousness. But studying this and really investing into it means you will inevitably become alone. Most people feel aversion to looking at their Shadow in the face and accepting it as part of themselves. Who would want to admit that they could become a guard in the concentration camps in the ‘40s? Most people would say they would never do it, but those people need Shadow work the most. Accepting that one is capable of immense atrocities is the first step to becoming your full Self. And most people can never do even this first step. Knowing your personal Shadow is crucial for this process. You have to notice your personal projections, face your fears and most importantly integrate your capacity for mayhem.
No games use this. One movie that I know of uses this —Christopher Nolan’s Inception. He also mentions Jung’s ideas in Batman Begins (Scarecrow). But that’s only shallow touch. EVERY major story uses mythological concepts and it becomes successful BECAUSE it uses mythology. Mythology is embedded in us. There is a field called comparative mythology that tracks the parallels among world mythologies. Jung noticed this too.
And I wanted to create a game about the whole process. Utilizing things I know about mythology, dream analysis, analytical psychology and alchemy. Yes, alchemy. That was Jung’s major contribution. He noticed, mapped and proved that alchemists were using symbolic language to map the process of Individuation. But try to explain that to a person who knows nothing about alchemy, mythology, dream analysis or analytical psychology. Impossible.
So I made this game.
I came up with the idea (or rather the idea came to me from my Unconscious and I happened to catch it) when I was consciously sleep depriving myself for 2 days. I wanted to reset my sleep cycles. But it backfired and I couldn’t sleep the second day I planned to go to sleep. I had this beautiful feeling on my brain, that I get only a few times a year. It’s sort of a tingling sensation. Like if you drank 4 cups of coffee, but didn’t have any negative effects. Only positive.
And in this state of mind, an idea came. A great idea.
I wanted to make a horror game for some time. I quit my job of 3 years about a month prior so I had all the time in the world. I wanted to have a shot at making my own business.
I also wanted to make a game about my ideas and my character. As Jonathan Blow says “<em>Take your deepest feelings and desires, and put them in the game</em>”.
Suddenly it was obvious that I should make a game about the thing that I consider to be perhaps the deepest concept I know, and the most important thing on my mind for the past 2 years. <strong>Individuation.</strong> Finally finding who I truly am. A way to have a deeply meaningful life. Never having to do anything that I consider to be useless and NOT meaningful EVER again (I captured that feeling into a movie I made, <a href="https://www.youtube.com/watch?v=4B9Ev6fLfqY">Button Pusher</a>).
So I frantically written down the idea and drawn concept art on 3 pages of paper, and then recorded a personal VLOG. When I watch it now I see I was obviously losing my mind. The idea was too great. I couldn’t express the feeling. One of the things I said was “I cannot die now. I am perhaps the only person who can do this game”.
At first I thought I am delusional, but no, people proved me RIGHT. I worked for a month on the game and released an <a href="https://www.youtube.com/watch?v=Y4-01YjDbgI">announcement trailer</a>. Thousands of people saw it and praised me. The gifted me reddit gold on reddit and I gained patrons. And a few people confirmed, in disbelief, that I was indeed the only person who thought of this.
<img src="https://blog.jilecek.cz/images/analytical-psychology-driven-game-design-in-jungs--05.png" alt="" />
It was confirmed. I wasn’t crazy. My idea was seriously substantial.
In the beginning I knew that I have to estimate this well. I am (or used to be) a software engineer and we are known to have horrible estimation skills. But I had some games behind me, so I knew what I am capable of.
I set 3 MONTHS for myself to make this game.<br />
I got the idea on 05/22/20, started working on it 06/01 and released the official trailer today, 08/27. Planned release date on 09/04.
I surprised myself. I worked every day, even weekends, anywhere between 4 to 18 hours a day. I got into flow states every day. I LOVE THIS.
<img src="https://blog.jilecek.cz/images/analytical-psychology-driven-game-design-in-jungs--06.png" alt="" />
my gihub commit history
I came up with a marketing idea. I knew how to do marketing already, and I began after a month of development, giving me 2 months. Each week I would do big post on reddit. I found subreddits that absolutely LOVE the game, like /r/jung, /r/occult,/r/dreaminterpretation,/r/alanwatts,/r/rationalpsychonatus and more. But I instinctively knew these kind of people would be interested in the game. I knew because I am like them. I made the game for myself. For the type of person like me.
I was tired of modern games. I recently bought a new gaming laptop and couldn’t wait to finally be able to play Witcher 3 and Metro Exodus. But I stopped playing each of these after an hour or two. I absolutely hated the games. Witcher holds your hand whole time (in the middle of the Griff fight it was still TEACHING ME how to use the inventory) and Metro Exodus has an absolutely DUMB story (and I am a fan of Metro 2033, read the books, played the first two games. Love Stalker and Fallout).
It all comes down to this — I am a DARK SOULS fan. I can’t play anything else now. Only a few chosen indie games I love — like Limbo, Inside, SMB or Short Hike.
<strong>I also wanted to make a game for myself.</strong>
Back to the marketing idea. I created a website, where you can <a href="https://archetypes.jilecek.cz/">test your archetype</a>. Sort of like MBTI or Big Five, you answer 72 questions and it calculates what archetype is strongest in you. I made the site in 2 days in GatsbyJS and I used Netlify for CI. I absolutely love that stack. I couldn’t be more efficient.
The strategy: Most of these online tests want you to pay via premium SMS or give them your email. I did none of this — instead I put a link to my Steam page and trailer on each results page.
It worked flawlessly. And a sort of a miracle happened. After two days, for some reason, Koreans and Filipinos made a god damn VIRAL MEME out of my site on twitter! It went like this “Share your archetype and your ult”. I had to google what ult means, but apparently it’s your “ultimate obsession in K-pop”. That’s right. K-pop….. I do not understand why they connected these two things, but when I searched for my name on twitter, I got new results linking to the test every 5 seconds, for 2 days. Each screen of the results page had the name of my game in it. In 2 days, without any paid marketing, I got 200,000 views of the test page. 1% of these clicked on Steam page, and a 1% of these added to wishlist. K-pop loving teenage girls (most of the twitter horde) are perhaps the polar opposite of my target group (men with interest in depth psychology), so the low conversion rate was understandable. But even today, the website draws around 500 people.
I hired voice actors on fiverr and did e-mail campaigns with my mailing list to find voice actors for the game. A few people signed up, and one guy, Daniel M. was especially helpful. His passion to be in the project helped the development greatly. Sped it up. He’s the main voice actor and he made the development so much easier. A real professional. Thanks Daniel. There is also Daniel W., who was a tremendous help. Both guys from Texas.
The game features a soundtrack by MJDorian, a classical music composer who is also a Jungian. And a small anecdote — I wanted to buy a license for Zack Hemsey’s “Nice to meet me” for the end credits, but his PR responded with something like “We don’t do licenses for games, sorry”. The song would fit the end perfectly. Reaching your true Self. Attaining your true potential.
That is all about the development process of Jung’s Labyrinth, I hope you enjoyed the read.
Here are the social links:</p>
<h3 id="psychological-exploration-game-based-on-teachings-of-carl-g-jung-this-game-explores-the-themes-of-so-called">Psychological exploration game. Based on teachings of Carl G. Jung, this game explores the themes of so called…</h3>
<p><a href="https://store.steampowered.com/app/709710/Jungs_Labyrinth">store.steampowered.com</a>
<a href="https://twitter.com/janjilecek">https://twitter.com/janjilecek</a></p>
]]></content>
  </entry>
  
</feed>
