<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: KorigamiK</title>
    <description>The latest articles on DEV Community by KorigamiK (@korigamik).</description>
    <link>https://dev.to/korigamik</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F909263%2Fa0ab12df-2201-48f0-a301-73c8619a7207.png</url>
      <title>DEV Community: KorigamiK</title>
      <link>https://dev.to/korigamik</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/korigamik"/>
    <language>en</language>
    <item>
      <title>Raycasting Adventures</title>
      <dc:creator>KorigamiK</dc:creator>
      <pubDate>Sat, 05 Nov 2022 19:49:11 +0000</pubDate>
      <link>https://dev.to/korigamik/raycasting-adventures-1j7n</link>
      <guid>https://dev.to/korigamik/raycasting-adventures-1j7n</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Read the (better) &lt;em&gt;PDF&lt;/em&gt; version of this blog &lt;a href="https://korigamik.ml/assets/raycasting.pdf" rel="noopener noreferrer"&gt;here&lt;/a&gt;!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, this is going to be more of a summary and some implementation details of&lt;br&gt;
my first ever experience with computer graphics and making games.&lt;/p&gt;

&lt;p&gt;You can find the &lt;a href="https://korigamik.itch.io/untitled-psp" rel="noopener noreferrer"&gt;itch-io page&lt;/a&gt;&lt;br&gt;
with all the instructions and links to download and play the game (maybe&lt;br&gt;
even give me a follow)&lt;/p&gt;

&lt;p&gt;Two weeks ago, not knowing anything about computer graphics and game&lt;br&gt;
development, I embarked on a journey down the rabbit hole of creating&lt;br&gt;
one of the pioneering games of video game history, such as the OG &lt;em&gt;Doom&lt;/em&gt;&lt;br&gt;
and &lt;em&gt;Wolfenstein 3D&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I decided to create a raycasting engine in &lt;em&gt;C++&lt;/em&gt; using the &lt;em&gt;Simple&lt;br&gt;
DirectMedia Layer&lt;/em&gt; graphics library. And for a beginner like me, it was&lt;br&gt;
quite the challenge.&lt;/p&gt;

&lt;p&gt;The whole idea of making this in a very bare-bones library and language&lt;br&gt;
like &lt;em&gt;SDL2&lt;/em&gt; and &lt;em&gt;C++&lt;/em&gt; was because I wanted to create something that&lt;br&gt;
would be truly cross-platform from the start. And by cross-platform I&lt;br&gt;
mean &lt;strong&gt;cross-platform&lt;/strong&gt;. The game would run on all desktop operating&lt;br&gt;
systems (Linux, Windows, Apple) and all mobile operating systems&lt;br&gt;
(Android, iOS, Raspberry Pi, Chrome)! And of course the&lt;br&gt;
&lt;em&gt;PSP&lt;/em&gt;. I could talk a lot about why the PSP, but I'll save&lt;br&gt;
that for another time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Now you must be asking - \"Bruh, what even is a Raycaster\".&lt;/p&gt;

&lt;p&gt;The simplest way to explain it is that it's a rendering technique to&lt;br&gt;
create a 3D perspective from a 2D map, what we like to call as 2.5D.&lt;/p&gt;

&lt;p&gt;Although this is about the making of a raycasting game engine, I had to&lt;br&gt;
give a lot of thought on how game engines are structured in the first&lt;br&gt;
place.&lt;/p&gt;

&lt;p&gt;I wanted my project to follow the &lt;em&gt;Object-Oriented&lt;/em&gt; design pattern as&lt;br&gt;
well so that it would be easy to extend and plug in components without&lt;br&gt;
touching a lot of code, enabling a deeper level of abstraction. I taught&lt;br&gt;
me a lot about inheritance and composition in C++.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Game Engine
&lt;/h2&gt;

&lt;p&gt;I'll talk about the game architecture in this section.&lt;/p&gt;

&lt;p&gt;The engine was written in C++ and then compiled using the &lt;em&gt;CMake&lt;/em&gt; build&lt;br&gt;
system, which enables me to go completely cross-platform.&lt;/p&gt;

&lt;p&gt;The high level architecture of the engine looks something like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--N6zQh3x5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/img/game_design.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--N6zQh3x5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/img/game_design.png" alt="Design" width="514" height="215"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I would've gone more into the design but TikZ is such a huge pain to&lt;br&gt;
learn. Though, I might come back to this in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Raycasting
&lt;/h2&gt;

&lt;p&gt;What actually distinguishes my project from any other implementation&lt;br&gt;
that you may find on the web is the fact that instead of dividing the&lt;br&gt;
whole world into square grids, it defines all the objects and texture&lt;br&gt;
rendering using their actual coordinates.&lt;/p&gt;

&lt;p&gt;Looking back, using the 2D grid approach while being a lot easier to&lt;br&gt;
implement, it's also quite a bit more efficient and accurate.&lt;/p&gt;

&lt;p&gt;Having said that, it also restricts a lot of what can be actually&lt;br&gt;
created in the game.&lt;/p&gt;

&lt;p&gt;The biggest leap of faith I took for this engine was to create the&lt;br&gt;
raycasting logic. So, here's how raycasting actually works.&lt;/p&gt;

&lt;p&gt;We first need to define these terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Player direction&lt;/strong&gt;  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wREUJHKI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/edJH4OEEPn.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wREUJHKI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/edJH4OEEPn.svg" width="9" height="6"&gt;&lt;/a&gt; : The direction that the player is currently facing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Maximum view distance&lt;/strong&gt;  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CZBMhagY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/iB5cma2PPp.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CZBMhagY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/iB5cma2PPp.svg" width="7" height="10"&gt;&lt;/a&gt; : The position of the player in the world.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Horizontal field of view&lt;/strong&gt;  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IeuDTsGR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/RZWtFQKtpj.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IeuDTsGR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/RZWtFQKtpj.svg" width="10" height="10"&gt;&lt;/a&gt; : The visible field of view&lt;br&gt;
the player sees in the horizontal direction. I assumed this to be,&lt;br&gt;
100°.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Vertical field of view&lt;/strong&gt; : This gives an idea of how high or low&lt;br&gt;
can the person see. I assume this to be, 60°.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Number of rays&lt;/strong&gt; : This is the number of rays that we cast from&lt;br&gt;
the player's position. You can set this number a lot of ways, and&lt;br&gt;
how high you set this will determine how accurate the raycasting&lt;br&gt;
will be.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we are ready to tackle the actual casting of rays. What our aim is&lt;br&gt;
to cast a ray from the player's position in the direction of the&lt;br&gt;
player's direction  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TFDnagUB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/Mi0j5nQvvr.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TFDnagUB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/Mi0j5nQvvr.svg" width="9" height="6"&gt;&lt;/a&gt; and then check if it intersects with any of&lt;br&gt;
the walls in the map. If it does, then we need to calculate the distance&lt;br&gt;
between the player and the wall and then draw a slice of the player's&lt;br&gt;
view corresponding to that ray.&lt;/p&gt;

&lt;p&gt;So, consider this diagram of the player's situation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pp29_nax--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/img/raycasting.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pp29_nax--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/img/raycasting.png" alt="Raycasting" width="800" height="535"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This circle corresponds to the player's maximum view distance ( &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gAADHsV_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/A6d68g1dlj.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gAADHsV_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/A6d68g1dlj.svg" width="7" height="10"&gt;&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;It should be noted that half of the cast rays would be on the left side&lt;br&gt;
of the player's field of view ( &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OdnjWTd5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/0mROBlb6PV.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OdnjWTd5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/0mROBlb6PV.svg" width="13" height="17"&gt;&lt;/a&gt;) and the other half&lt;br&gt;
would be on the right side.&lt;/p&gt;

&lt;p&gt;Now, we can define the angle between each ray as:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---XhTHelV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/LqPyuCwYSx.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---XhTHelV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/LqPyuCwYSx.svg" width="150" height="31"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are going to construct the view of the player by drawing a slice of&lt;br&gt;
the view for each ray. The rays would be equally spaced (suspending the&lt;br&gt;
angle  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZURVoVuP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/XojCZ1vov8.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZURVoVuP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/XojCZ1vov8.svg" width="7" height="9"&gt;&lt;/a&gt; at the player) starting from point  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ruy74h5B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/KzUjUjCLNR.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ruy74h5B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/KzUjUjCLNR.svg" width="10" height="10"&gt;&lt;/a&gt; till  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ON1jbe9b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/vRSi1UTzJu.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ON1jbe9b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/vRSi1UTzJu.svg" width="31" height="11"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We'll calculate  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ON1jbe9b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/vRSi1UTzJu.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ON1jbe9b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/vRSi1UTzJu.svg" width="31" height="11"&gt;&lt;/a&gt; (distance taken from  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ruy74h5B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/KzUjUjCLNR.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ruy74h5B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/KzUjUjCLNR.svg" width="10" height="10"&gt;&lt;/a&gt;) by using the&lt;br&gt;
following formula:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V7j3fuQw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/vdsxWw29HS.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V7j3fuQw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/vdsxWw29HS.svg" width="100" height="28"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, the distance  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fLa9hPS8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/Aibb1JUkgP.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fLa9hPS8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/Aibb1JUkgP.svg" width="12" height="9"&gt;&lt;/a&gt; for any ray at angle  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GcqIxxW2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/qdxm14ZrTJ.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GcqIxxW2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/qdxm14ZrTJ.svg" width="8" height="12"&gt;&lt;/a&gt; would be:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9LxagBWB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/RFtxHz5oQj.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9LxagBWB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/RFtxHz5oQj.svg" width="105" height="28"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, we can calculate the width of the slice ( &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4YFNZaG_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/brSYRl5LQL.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4YFNZaG_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/brSYRl5LQL.svg" width="14" height="10"&gt;&lt;/a&gt;) for each ray as:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t3dkTQup--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/gQwnpxYOLw.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t3dkTQup--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/gQwnpxYOLw.svg" width="249" height="28"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But, we cannot calculate the vertical height of the slice by using the&lt;br&gt;
distance of the ray's end point from the player  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uG2-LSvL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/PdrG3CIhcj.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uG2-LSvL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/PdrG3CIhcj.svg" width="80" height="14"&gt;&lt;/a&gt;&lt;br&gt;
directly.&lt;/p&gt;

&lt;p&gt;This is the exact cause of the fish eye effect that you might have seen&lt;br&gt;
from some cameras that looks very alien to your eyes. It looks something&lt;br&gt;
like&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IZHUJ1cF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/img/fish-eye.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IZHUJ1cF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/img/fish-eye.png" alt="Fish-eye effect" width="477" height="268"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can correct for the fish eye effect by taking the length of the ray&lt;br&gt;
from the plane of the camera.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1HfewAG8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/2yz5VIH8B2.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1HfewAG8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/2yz5VIH8B2.svg" width="260" height="14"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thus, we calculate the height of the slice based on this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kQSaAfQb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/lVYegxFEYf.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kQSaAfQb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/lVYegxFEYf.svg" width="256" height="28"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nice! The fish-eye effect is no more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x03CAEL0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/img/no-fish-eye.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x03CAEL0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/img/no-fish-eye.png" alt="Fish-eye effect corrected" width="479" height="269"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Phew! That was a lot of math. But, we are almost done.  &lt;/p&gt;

&lt;p&gt;Another thing that we can calculate is the brightness of an individual&lt;br&gt;
slice:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Vbap0xmr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/vHyM7UXP89.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Vbap0xmr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/vHyM7UXP89.svg" width="321" height="28"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This means that farther objects will appear darker than when they're&lt;br&gt;
closer. You could probably play around here and find a way to do fog or&lt;br&gt;
mist, but I'll leave that up to you.&lt;/p&gt;

&lt;p&gt;The last thing left for us to do (at least on this blog) is to figure&lt;br&gt;
out a way to map the image textures onto the actual walls.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The method is pretty simple,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The width and height of the textures remain the same.&lt;/li&gt;
&lt;li&gt;The start of the texture can be calculated by taking into account
the distance of the ray along the line.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f2hJYGra--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/JeQRHO5l1h.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f2hJYGra--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/JeQRHO5l1h.svg" alt="Texture X" width="394" height="14"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The remainder operator will repeat the texture when the length of the&lt;br&gt;
wall is greater than the texture itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;That's it, Congrats, you made it to the end. The raycasting is working,&lt;br&gt;
and you're now a game developer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6GTTOhNy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/gAx0rCca5B.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6GTTOhNy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/gAx0rCca5B.svg" width="223" height="14"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope you enjoyed the journey with me as much as I did making and&lt;br&gt;
writing this. Maybe you'll even feel inclined to contribute and fix the&lt;br&gt;
inevitably many bugs I have &lt;a href="https://github.com//korigamik/untitledpsp" rel="noopener noreferrer"&gt;in my code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thank you Kueeing! (king + queen let's &lt;a href="https://www.urbandictionary.com/define.php?term=kueeing" rel="noopener noreferrer"&gt;make this go mainstream&lt;/a&gt;)&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>writing</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Bags with Balls</title>
      <dc:creator>KorigamiK</dc:creator>
      <pubDate>Tue, 16 Aug 2022 10:50:00 +0000</pubDate>
      <link>https://dev.to/korigamik/bags-with-balls-27f6</link>
      <guid>https://dev.to/korigamik/bags-with-balls-27f6</guid>
      <description>&lt;p&gt;This post is my first experience in solving a "hard" problem on CodeForces.&lt;/p&gt;

&lt;p&gt;As I logged in to CodeForces for the first time, I went to the &lt;code&gt;Problemset&lt;/code&gt;&lt;br&gt;
section hoping to solve some question. I was blissfully unaware how the&lt;br&gt;
difficulty rating system worked. I picked the first problem in the list and&lt;br&gt;
tried to have a go.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://codeforces.com/problemset/problem/1716/F" rel="noopener noreferrer"&gt;The question&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;There are n bags, each bag contains m balls with numbers from 1 to m. For&lt;br&gt;
every &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MUn1mMWA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/OMgnbTsUR2.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MUn1mMWA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/OMgnbTsUR2.svg" alt="I" width="5" height="9"&gt;&lt;/a&gt;&lt;br&gt;
∈[1, m], there is exactly one ball with number &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sfDmajuX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/UFmFt1ZjgB.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sfDmajuX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/UFmFt1ZjgB.svg" alt="I" width="5" height="9"&gt;&lt;/a&gt;&lt;br&gt;
in each bag.&lt;/p&gt;

&lt;p&gt;You have to take exactly one ball from each bag (all bags are different, so, for&lt;br&gt;
example, taking the ball 1 from the first bag and the ball 2 from the second bag&lt;br&gt;
is not the same as taking the ball 2 from the first bag and the ball 1 from the&lt;br&gt;
second bag). After that, you calculate the number of balls with odd numbers&lt;br&gt;
among the ones you have taken. Let the number of these balls be &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cL1RGrvF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/hvYeBwkG4O.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cL1RGrvF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/hvYeBwkG4O.svg" width="10" height="9"&gt;&lt;/a&gt;&lt;br&gt;
Your task is to calculate the sum of &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--D5B6MOkp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/W1OEcmaIfA.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D5B6MOkp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/W1OEcmaIfA.svg" width="17" height="12"&gt;&lt;/a&gt;&lt;br&gt;
over all possible ways to take n balls, one from each bag.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initial Thoughts
&lt;/h2&gt;

&lt;p&gt;So when I saw the notation for &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yZhNXDjG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/TIQXfeo8b0.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yZhNXDjG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/TIQXfeo8b0.svg" width="17" height="12"&gt;&lt;/a&gt;&lt;br&gt;
I thought this supposed to refer to a&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Multi-index_notation" rel="noopener noreferrer"&gt;Multi-index n-tuple&lt;/a&gt;&lt;br&gt;
where&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5D0bLtue--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/AOFI9TpXon.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5D0bLtue--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/AOFI9TpXon.svg" width="10" height="9"&gt;&lt;/a&gt;&lt;br&gt;
was a tuple of all the odd index selected balls.&lt;/p&gt;

&lt;p&gt;But that was stupid, it's just the regular exponent. Still it was pretty&lt;br&gt;
interesting of them to ask the sum of the number of balls to&lt;br&gt;
the&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4Vrgtd_m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/PudsU5TNrh.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4Vrgtd_m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/PudsU5TNrh.svg" width="17" height="12"&gt;&lt;/a&gt;&lt;br&gt;
 power.&lt;/p&gt;

&lt;h2&gt;
  
  
  The working
&lt;/h2&gt;

&lt;p&gt;I was definitely stuck on this. There weren't even any solutions on the internet&lt;br&gt;
either. But I was able to find some similar problems and that's where&lt;br&gt;
WolframAlpha gave me the key to solve this problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Formulating the solution
&lt;/h3&gt;

&lt;p&gt;We can consider the number of was to pick &lt;code&gt;i&lt;/code&gt; odd balls from &lt;code&gt;n&lt;/code&gt; bags each&lt;br&gt;
containing &lt;code&gt;m&lt;/code&gt; balls. This can be found out by:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Wxgand6g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/UBIx2N9Ctv.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Wxgand6g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/UBIx2N9Ctv.svg" width="195" height="55"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We basically choose &lt;code&gt;i&lt;/code&gt; boxes which we want the odd balls from and each of the&lt;br&gt;
&lt;code&gt;i&lt;/code&gt; boxes has m+1/2 choices, and then we want to choose even balls from the&lt;br&gt;
&lt;code&gt;n-i&lt;/code&gt; remaining bags which have m/2 choices each.&lt;/p&gt;

&lt;p&gt;To make the expressions easier to maintain we will&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gOJWNnq8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/GL2RFkmAov.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gOJWNnq8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/GL2RFkmAov.svg" width="193" height="33"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So the final answer can be formulated as&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qQ-EzzYK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/g4Wb0nv3ux.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qQ-EzzYK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/g4Wb0nv3ux.svg" width="140" height="16"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Where we sum through all the number of odd balls which can be selected (from 0&lt;br&gt;
to n) each contributes &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pgW1AOOP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/gJzwNsRmB1.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pgW1AOOP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/gJzwNsRmB1.svg" width="10" height="12"&gt;&lt;/a&gt;&lt;br&gt;
to answer.&lt;/p&gt;

&lt;p&gt;Now the challenge was the simplify this expression, as it is now it will be way&lt;br&gt;
over the O(n) complexity that is required to solve these "hard" problems.&lt;/p&gt;

&lt;p&gt;It seems awfully close to the well known binomial formula but the pesky&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pgW1AOOP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/gJzwNsRmB1.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pgW1AOOP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/gJzwNsRmB1.svg" width="10" height="12"&gt;&lt;/a&gt;&lt;br&gt;
makes it almost impossible to simplify further.&lt;/p&gt;

&lt;p&gt;Luckily after research on this a little, WolframAlpha taught me about the&lt;br&gt;
existense of the&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Stirling_number" rel="noopener noreferrer"&gt;Stirling numbers&lt;/a&gt; which are&lt;br&gt;
denoted by the { a b } bracketes like the binomial coefficient.&lt;/p&gt;

&lt;p&gt;They have the interesting property that:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oP12y4Jy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/DUTdoX60zc.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oP12y4Jy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/DUTdoX60zc.svg" width="128" height="38"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Which will help us to do something about the the exponent. I present to you the&lt;br&gt;
steps to the simplification:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XqRYKYYq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/dPt76zSz5m.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XqRYKYYq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/dPt76zSz5m.svg" width="332" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Therefore, the answer can be simplified into&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1ES1QL43--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/5YGRBmc3dW.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1ES1QL43--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://korigamik.deno.dev/svg/5YGRBmc3dW.svg" width="189" height="42"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first term can be precomputed into a 2-D dp array. The final complexity of&lt;br&gt;
the program should be ~ O(n + c)&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope you found this thread interesting. I still don't think I will be able to&lt;br&gt;
give much time to the competitive coding side of things. For me, it's similar to&lt;br&gt;
a Sudoku or a puzzle that I would solve once in a while but not spend all my&lt;br&gt;
brain power on just doing them.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Hello world!</title>
      <dc:creator>KorigamiK</dc:creator>
      <pubDate>Mon, 15 Aug 2022 19:15:18 +0000</pubDate>
      <link>https://dev.to/korigamik/hello-world-66n</link>
      <guid>https://dev.to/korigamik/hello-world-66n</guid>
      <description>&lt;p&gt;This is my first blog post!&lt;/p&gt;

&lt;p&gt;$$ x_1 = 54 $$&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;hello&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x_2 = 21 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>init</category>
      <category>test</category>
    </item>
  </channel>
</rss>
