<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Valentin Simonov on Programming]]></title><description><![CDATA[Thoughts, stories and ideas.]]></description><link>https://va.lent.in/</link><image><url>https://va.lent.in/favicon.png</url><title>Valentin Simonov on Programming</title><link>https://va.lent.in/</link></image><generator>Ghost 2.28</generator><lastBuildDate>Mon, 06 Oct 2025 16:21:13 GMT</lastBuildDate><atom:link href="https://va.lent.in/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Delivering a great tech talk]]></title><description><![CDATA[Tech talks at conferences are usually done to share experience, show a product or explain a hard topic to the audience. Unfortunately, most people can't present their knowledge in systematic, understandable and entertaining way]]></description><link>https://va.lent.in/delivering-a-great-tech-talk/</link><guid isPermaLink="false">5d55840be6bd4808e40e5a9b</guid><category><![CDATA[Public Speaking]]></category><category><![CDATA[Conference]]></category><dc:creator><![CDATA[Valentin Simonov]]></dc:creator><pubDate>Tue, 08 Aug 2017 09:00:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>I visit tens of game development conferences every year, I listen to hundreds of talks and <a href="http://va.lent.in/about/">I deliver talks myself</a>. I am by far not the greatest public speaker, I know my flaws and I don't like watching recordings of my sessions.</p>
<p>In this post I want to focus on meaningful tech talks, not marketing bullshit talks which sneak into conference schedules no matter what. Tech talks at conferences are usually done to share experience, show a product or explain a hard topic to the audience. In any case, there's a speaker who has some kind of knowledge and wants to share this knowledge with the audience.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><blockquote>
<p>The problem is that most people can't present their knowledge in systematic, understandable and entertaining way.</p>
</blockquote>
<p>Which leads to disappointment and low ratings. It is always frustrating to watch how the author of a decent framework struggles to explain why it is useful, so at the end the only question the audience has is <strong>&quot;why did we waste an hour on this?&quot;</strong>.</p>
<p>There are many articles on public speaking in the internet, most of them give general advice about presentation structure, rehearsing and engaging the audience. I don't want to copy these articles. Instead, I'd like to focus on mistakes I see a lot at IT and Game Development conferences.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/08/2017-08-08_01-00-06.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><h1 id="commonmistakes">Common mistakes</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Most of the failed talks share the same mistakes. It is crucial to know them and be able to catch yourself on making them. This is a list of common mistakes I found particularly bad and capable of destroying any talk no matter how good the presenter knows the topic and how experienced public speaker he or she is.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="1beawarethatyouhaveafixedtimeslot">1. Be aware that you have a fixed time slot</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Let's start with an obvious advice which for some reason is frequently ignored in tech talks. It is understandable that we want to share as much valuable information as we can, but time slots at conferences are usually limited to 25 or 45 minutes, and what is more important, the audience can digest new information only that fast.</p>
<p>This means that you must carefully choose what you want to talk about. I've seen so many failed talks because the speakers tried to fit 5 hours of content into 25 minutes.</p>
<p>But the mistake is not about having too much content, it is about not understanding your time slot. Here are a few examples:</p>
<ol>
<li>The speaker doesn't have too much content, but spends too much time on part 1, so he has to rush through part 2 and skip part 3.</li>
<li>There was an issue with video capture, so the talk started 10 minutes late but the speaker failed to take this into account and started rushing at the last moment.</li>
<li>The speaker was aware that he had much content and limited time, so he ran through it extra fast, finishing in 10 minutes and confusing the hell out of the audience.</li>
</ol>
<p>So, you get the idea.</p>
<p>The best way not to make this mistake is to rehearse your speech at home or the hotel you are staying at and write down how much time you need for specific parts of the speech. At this point you will have a rough estimate like so:</p>
<blockquote>
<p>I have 4 parts. The first one is about 20 minutes, the other ones are 10 minutes each. Summed up, this is 50 minutes which fits the 45 minute slot I've been given. Unfortunately, no time for questions... <s>Which is good, since I don't know what I am talking about anyway.</s></p>
</blockquote>
<p>During the talk you will need to try to stick to the budgeted time. If you are within the budget, you speak at the normal speed, add jokes and ask the audience questions; if you are running late, you speak faster and start skipping slides.</p>
<p>This practice is going to take a lot of time and at some point you will learn how to budget the time without rehearsing and skip the slides in such a way that nobody suspects a thing. But this will happen only if you fully understand the next section.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="2theaudiencedoesntknowhowyourpresentationissupposedtogo">2. The audience doesn't know how your presentation is supposed to go</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>You probably don't think about it, but the only living creatures who know what your slides are and how your presentation is supposed to go are you and your cat who's been intensely staring at you the whole time you were rehearsing your speech at home.</p>
<p>In other words...</p>
<blockquote>
<p>The audience doesn't know what is supposed to be on your slides and how your presentation is supposed to go.</p>
</blockquote>
<p>This is extremely important and for some reason is not really obvious. Think about it for a few seconds.</p>
<blockquote>
<p>Never tell the audience that what is happening is not a part of the plan.</p>
</blockquote>
<p>Don't panic and be ready to continue if something is not working. Here are a few examples.</p>
<h3 id="thepresenterseesthatheisrunningoutoftimeanddecidestoskiponeofthetworemainingtopicswhatshouldhedo">The presenter sees that he is running out of time and decides to skip one of the two remaining topics. What should he do?</h3>
<p><strong>Wrong</strong>: He quickly switches to the next slides one by one explaining that there's no time and apologising until he reaches the last topic.<br>
<strong>Right</strong>: In Presenter mode on his display he switches manually to the last topic and starts from there.</p>
<p>The thing is that the audience doesn't know about the topic he was about to skip. Nobody is going to stand up and demand to show the skipped topic. On the contrary, manually skipping through the slide deck and apologising clearly shows that the presenter is unable to plan his time and the audience will feel cheated in some way because a part of the valuable information was taken away.</p>
<h3 id="thepresentersuddenlyrealizesthatthisisnotthelatestversionoftheslidesandthatoneimportantslideismissingwhatshouldhedo">The presenter suddenly realizes that this is not the latest version of the slides, and that one important slide is missing. What should he do?</h3>
<p><strong>Wrong:</strong> He starts apologising and explaining that there was this great slide, that he spent an hour googling for appropriate memes for it, that it was so important and there might be a possibility that he can find it on his thumb drive...<br>
<strong>Right:</strong> Realized that the slide is missing, he switches to the previous slide and tells the part of the story without ever mentioning the missing slide.</p>
<p>The audience doesn't care about your slides. As long as what you are saying makes sense, the slides are not needed at all. Most of the time slides are there just for you to remember what you are going to say next.</p>
<h3 id="allanimatedgifsandvideosarebrokenanddontplaywhatshouldthepresenterdo">All animated GIFs and videos are broken and don't play. What should the presenter do?</h3>
<p><strong>Wrong:</strong> Every slide he apologizes that the video is not playing and pauses the presentation trying to make it play.<br>
<strong>Right:</strong> He doesn't say anything about the GIFs — nobody knows that these are not just static images. He has videos on the thumb drive, one of which is important, so he tries to plug the thumb drive and play the video from there. VLC seems to play the file fine.</p>
<blockquote>
<p>Don't let the audience know that something is not right, and don't apologize for this. It doesn't look well, believe me.</p>
</blockquote>
<p>Many times I had to use the conference default PC which messed all the fonts, but there was no point in apologizing for ugly slides: many people understood this, some didn't care, others thought this was intended since I am a programmer and can't design shit.</p>
<p>A few times I had to manually increase the font size on all slides on stage while waiting for people to come because the conference used 320x240 LED displays ¯\_(ツ)_/¯ Nobody suspected this wasn't planned.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="3findoutwhathardwaretheconferenceisusingandtestitbeforethetalk">3. Find out what hardware the conference is using and test it before the talk</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Speaking of 320x240 LED displays, this was an unpleasant surprise for me since I was going to do a live demo (which obviously I had to skip). Since then I added &quot;projector type and resolution&quot; to my usual questions to the organizers.</p>
<p>Not knowing what hardware the conference uses is a very common mistake, and it is rather painful for tech talks because we tend to do live demos. Hell, half of my presentations are just live demos without slides at all. So, it is usually quite disappointing when you figure out that you can't run the demo from your machine for whatever reason.</p>
<p>But even if I am not running a demo I always prefer to present from my MacBook Pro with all the right fonts, correct video playback and familiar keyboard. So I usually ask to provide the following information:</p>
<ol>
<li><strong>Is it possible to present from my laptop?</strong><br>
Usually it is, even if the organizers say no the first time. At this point I try to play the NDA card, that I can't present from their machine because I can't copy files there. It tends to work, but don't tell anyone!</li>
<li><strong>What video cable are you using?</strong><br>
I always have all the adapters in my backpack, but it is good to know this in advance.</li>
<li><strong>What video capture device are you using?</strong><br>
Video capture is usually done by a contractor and here you can have surprises. Especially if you are on Mac, because there are many cheap devices which don't like Macs... or Macs don't like them — anyway, video capture doesn't work.</li>
<li><strong>Is audio available?</strong></li>
<li><strong>What projector are you using and what resolution does it have?</strong></li>
<li><strong>Will my talk be recorded?</strong></li>
</ol>
<blockquote>
<p>Unfortunately, having all the answers is not enough. You never know if this particular video capture setup will work with your PC, so you have to go and test it.</p>
</blockquote>
<p>Try to go to the hall where your presentation will be as early as possible before the talk and ask to test your laptop. Connect the video capture, run the slides, play videos — usually everything works. If not, talk to the A/V guys and the organizers about possible solutions.</p>
<p>Don't be that guy who is unable to play videos in his presentation. Don't be that guy who tries to show a networked game connected to the conference network (which obviously doesn't work). Don't be that guy who was going to show the live demo, but his software doesn't run with resolution lower than 1280x720 (true story).</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="4makesurethatpeoplecanactuallyseewhatyouaretryingtoshow">4. Make sure that people can actually see what you are trying to show</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Continuing the topic about hardware, you must take into account how people will be looking at your slides or live demos. It is not a good presentation if the audience can't see what's going on on the screen.</p>
<p>There are several common issues:</p>
<ol>
<li><strong>Text (especially code) is too small.</strong><br>
If you are showing code in an IDE, make sure that you increase font size to an optimal value when people can actually read it.</li>
<li><strong>Interface is tot small.</strong><br>
Learn to use built-in zoom on Mac and Windows. Make sure that you zoom on important parts of your live demo during the talk.</li>
<li><strong>IDE theme is too dark.</strong><br>
You might have your favourite dark IDE theme enabled which looks great on screen, but doesn't have enough contrast on projector. You should definitely think about changing it to a light contrast theme at least for the presentation.</li>
<li><strong>Video is too dark.</strong><br>
Unfortunately, if you are showing a horror game which is simply too dark for the projector, the audience will not be able to see much. In this case you can try to edit the video to add more contrast to it, and ask the conference organizers to dim the lights during the video. But you must discuss this moment in advance, because most of the time nobody knows where the light controls are ¯\_(ツ)_/¯</li>
</ol>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="5reversethefloworderofyourpresentation">5. Reverse the flow order of your presentation</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>How many times have you seen (or personally delivered) a talk with the structure like this?</p>
<ol>
<li>This is <strong>the thing</strong>,</li>
<li>This is what it can do,</li>
<li>This is an example of how to use it.</li>
</ol>
<blockquote>
<p>This is the most common presentation structure but it is fundamentally wrong.</p>
</blockquote>
<p>Do you know why TED talks are 18 minutes long? <a href="https://www.linkedin.com/pulse/20140313205730-5711504-the-science-behind-ted-s-18-minute-rule">Science says</a> that this is an optimal time interval in which humans can still keep their attention on the speaker. But it gets much shorter if the audience is bored.</p>
<p>This structure is bad because:</p>
<ol>
<li>Most of the time till the very end of the presentation people still have no clue about what <strong>the thing</strong> is for. For the presenter it might be obvious from the first two parts, but without a concrete example people usually still have no idea if this thing might be useful for them or not.</li>
<li>The first part of a presentation following this structure tends to be rather boring because its role essentially is to list axioms, describe the problem space and have a 5 minute story on how <strong>the thing</strong> was conceived.</li>
<li>Even experienced presenters can't always budget their time correctly, so the last part is usually rushed through, or even worse — the audience is directed &quot;to watch videos online after the presentation&quot;. Of course, this leads to huge confusion.</li>
</ol>
<p>So you will end up with the following attention curve.</p>
<blockquote>
<p>The biggest issue with attention curves is that less attention the listener pays to what the speaker says, it's harder for the curve to go up — so, if attention gets close to zero, it will always remain there. Or, scientifically speaking — congratulations, you have bored the hell out of the audience!</p>
</blockquote>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/08/graph2.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>The presentation structure to keep attention must be reversed:</p>
<ol>
<li>This is an example of how to use <strong>the thing</strong>,</li>
<li>This is what it can do,</li>
<li>This is <strong>the thing</strong>.</li>
</ol>
<p>In this case, the audience will most likely be interested from the very beginning. Of course, this structure is rather controversial because, it seems odd to show an example of using a <a href="https://en.wikipedia.org/wiki/Surface_integral">Surface Integral</a> without describing what this is first. But in practice showing an example first triggers active questions in the audience: <em>What is it? How is it done? Can I use it?</em> Exactly these questions you are going to answer in the next parts of the presentation.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/08/graph1.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>The totally reversed flow is not applicable to every presentation, but...</p>
<blockquote>
<p>You should ask yourself, is the flow of your presentation supporting attention in the audience or is it just making everyone fall asleep?</p>
</blockquote>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="6dontassumethateverybodyhasplayedoratleastknowsyourgame">6. Don't assume that everybody has played or at least knows your game</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>I know people in game development industry who haven't played <a href="https://en.wikipedia.org/wiki/Diablo_(video_game)">Diablo</a> or <a href="https://en.wikipedia.org/wiki/The_Witcher_3:_Wild_Hunt">The Witcher 3</a>, I know people who don't follow mobile top charts and <em>&quot;this is like <a href="https://en.wikipedia.org/wiki/Clash_of_Clans">Clash of Clans</a>&quot;</em> tells them nothing.</p>
<blockquote>
<p>Why do you assume that people know YOUR game?</p>
</blockquote>
<p>Even if you are <a href="http://en.cdprojektred.com/">CD Projekt Red</a> and you are going to talk about <a href="https://en.wikipedia.org/wiki/The_Witcher_3:_Wild_Hunt">The Witcher 3</a>, you absolutely must show a trailer or a gameplay clip at the beginning of your talk. Don't think that you are saving precious time by not doing this. What you are really doing is adding more confusion which immediately converts into lack of attention.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="7showdonttell">7. Show, don't tell</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>There's nothing more boring than a wall of text on a large screen. Don't do this.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/08/2017-08-07_23-53-39.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>If you are talking about your game and how you created 50 characters, 20 levels and 10 weapons — show the weapons, show animated characters, add screenshots of the levels! If you are describing an algorithm, show a visual representation of how it works.</p>
<blockquote>
<p>Don't make the audience read, especially don't make people read code from the slides!</p>
</blockquote>
<p>If you have to show code, highlight important parts.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/08/2017-08-07_23-59-50.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="8everythingisimportantinyourpresentation">8. Everything is important in your presentation</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>One thing I really hate is when I am sitting in the audience trying to figure out what the speaker is showing, but he keeps switching through slides saying that <strong>this is not important</strong>. WHY HAVE YOU INCLUDED THESE SLIDES THEN???!!1</p>
<p>I can tell you why, because I tend to do the same thing. Good that I know this and I am able to correct myself right away. But most of the time it is hard to fix the voice I'm using while talking about these things. People tend to notice this.</p>
<blockquote>
<p>People tend to see when you think that what you are saying is not important, and they project this on you. Now you are not important.</p>
</blockquote>
<p>If you look like what you are saying is important, people will give more attention to what you are saying, they will tend to agree with you and will more likely think that you are smart (do you think those public speakers are smart? well, at least they look smart). Unfortunately, this is a difficult skill to master</p>
<p>You should start with believing that <strong>if you included this slide in the presentation, it is important</strong>. It was important when you were making this slide deck, why is it suddenly not important on stage?</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h1 id="generaladvice">General advice</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>And the last, I want to list a few things which help me deliver better presentations.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="1donteatbeforethepresentation">1. Don't eat before the presentation</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>This one is my personal choice. I usually feel like having a nap after getting a good meal, which is not the best state to be when you need to stand on stage and talk for an hour.</p>
<p>Look at your own experience — do you feel more active after having a meal? Does drinking coffee before a presentation make you more active or you just feel more awake while your brain seems to be lagging?</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="2findapersonintheaudienceandtalktohimorher">2. Find a person in the audience and talk to him or her</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>It is hard to speak in front of a large audience, you see people swiping their phones, people randomly stand up and leave, or people just keep staring at you with a distinct sceptical look on their faces. The later doesn't mean that the person is judging you, he or she is most likely suffers from <a href="https://en.wikipedia.org/wiki/Resting_bitch_face">Resting Bitch Face Syndrome</a>.</p>
<p>So the best strategy to keep calm is to find one or more people in the hall who look genuinely interested and talk to them. In this case it doesn't matter if you are speaking in front of 10 people or 10 000 people.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="3whenaskingwhoisherexquestionsraiseyourhand">3. When asking &quot;who is here [X]?&quot; questions, raise your hand</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>It is a good practice to spice up your presentation with questions to the audience. By doing this you may be able to change your presentation on the fly or just break the ice in the room.</p>
<p>The question might be the following: <em>&quot;Who is a programmer here? Raise your hand.&quot;</em></p>
<p>I found, that a good thing to do when asking such questions is to raise your hand too. This shows the audience that this is OK to raise a hand and someone has already done this. Otherwise, you know, people are shy to actively participate.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="4dontletapersonintheaudiencehijackyourtalk">4. Don't let a person in the audience hijack your talk</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Sometimes I want the audience to ask questions during the presentation, so it is more like a lecture, not a one way information transfer. But I know that I have this bug, that if interrupted I completely lose track of what I was saying. So, I usually try to enforce one of the following rules:</p>
<ul>
<li>If you have a question, raise your hand.</li>
<li>I ask if there are questions during transitions between logical sections of my presentation. No questions while I am speaking.</li>
</ul>
<p>This helps me to structure the presentation and make sure that I budget the time correctly. The biggest problem here is when a person from the audience tries to hijack your talk by masking his own opinion within a question. Such &quot;questions&quot; tend to be long and distracting, and what's more important they benefit nobody except the person asking them.</p>
<p>It is very important to identify such &quot;questions&quot; in time and try to get rid of them as fast as possible. This is what I usually try to do:</p>
<ol>
<li>If the story before the question is getting quite long, I usually interrupt the person and explicitly ask &quot;so, what's the question?&quot;. This works sometimes.</li>
<li>Tell the person to talk to me after the presentation.</li>
<li>Say that I can't answer this now, but if the person sends [the project] to me by email, I might be able to look at it further. (hint: nobody has ever sent me anything, so this is safe)</li>
</ol>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h1 id>*************</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>I hope that with the help of articles like this there will be fewer mediocre talks at IT and Game Development conferences. Remember, that sharing knowledge is a unique skill which requires hard work. Just knowing something is not enough to be able to teach people what you know.</p>
<p>Practice, look at other speakers, read articles like this, and soon people will line up for your talks and give you 5 star rating all the time!</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Unity 2017.1 — when small things count]]></title><description><![CDATA[We've just released Unity 2017.1! Nobody reads Release Notes — so, I compiled a list of little fixes and features which are probably too small but I find them really important]]></description><link>https://va.lent.in/unity-2017-1-when-small-things-count/</link><guid isPermaLink="false">5dc99c7f56953d7286f4d4ff</guid><dc:creator><![CDATA[Valentin Simonov]]></dc:creator><pubDate>Tue, 11 Jul 2017 11:50:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>We've just released Unity 2017.1 which while being just a next Unity update begins the new era of the Engine. If you are as excited as me, don't forget to read about new amazing features on <a href="https://blogs.unity3d.com/2017/07/11/introducing-unity-2017/">our Blog</a>.</p>
<p>Unity 2017.1 <a href="https://unity3d.com/unity/whats-new/unity-2017.1.0">has more features and fixes</a> than that blog post had space for, but unfortunately nobody reads Release Notes. So, I compiled a list of little fixes and features which are probably too small but I find them really important.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="editornewprojectsnowdefaulttotextbasedserialization">Editor: New projects now default to text-based serialization.</h4>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/Screen-Shot-2017-07-11-at-6.14.34-PM.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>When you are creating a new project, do you also go to <em>Edit &gt; Project Settings &gt; Editor</em> and set <em>Asset Serialization Mode</em> to <em><strong>Force Text</strong></em> every damn time?</p>
<p>This is the best feature of Unity 2017.1! Hands down! Saving millions of man hours.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="uiprofiler">UI Profiler</h4>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/2017-07-11_22-53-07.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>This is not a small thing, but was not included into the main blog post for some reason. The UI team made an amazing UI Profiler which shows how much CPU time UI rendering takes and also tells why UI objects were split into many batches.</p>
<p>This is a great tool to profile UI in your game!</p>
<p><em><strong>Update:</strong> UI Profiler was added to the oficial post.</em></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="uiaddedsupportforselectingmultiplefilesintheassetsimportnewassetdialogonallplatforms">UI: Added support for selecting multiple files in the &quot;Assets/Import New Asset...&quot; dialog, on all platforms.</h4>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>I have never used this dialog specifically for this reason. It is much easier to select and drag a bunch of assets to the Project Window. It is too late for me to change, but you might consider using this dialog instead.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="il2cppimprovedil2cppcodeconversiontimeonosxconversiontimesmayimprovebyasmuchas2x">IL2CPP: Improved IL2CPP code conversion time on OSX. Conversion times may improve by as much as 2x.</h4>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Yey! Faster iOS builds!</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="editorlogmessagesfromconnectedplayerswillnowshowineditorconsoleforeasierdebugging">Editor: Log messages from connected players will now show in Editor console for easier debugging.</h4>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/2017-07-11_18-49-00.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>This is really cool! Now you can use Profiler connection to see logs from a game running on device in the Editor Console window. I randomly noticed this during a 2017.1 beta and was very excited!</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="physicsaddabilitytomanuallysimulate2dphysicsusingphysics2dsimulatetimeandturnautosimulationonoffwithphysics2dautosimulationtruefalse">Physics: Add ability to manually simulate 2D physics using &quot;Physics2D.Simulate(time)&quot; and turn auto simulation on/off with &quot;Physics2D.autoSimulation=true/false&quot;.</h4>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Also the same for 3D physics:<br>
<em>Physics: Expose Physics.Simulate and Physics.autoSimulation. This allows stepping the physics simulation manually, from scripts. Useful for customising the server-side physics, in-editor simulation, and more.</em></p>
<p>This change gives you control over when you want to simulate physics. The ability to simulate physics in the editor is really powerful.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="assetpipelineaddedmethodsassetbundlegetallloadedassetbundlesandassetbundleunloadallassetbundles">Asset Pipeline: Added methods AssetBundle.GetAllLoadedAssetBundles and AssetBundle.UnloadAllAssetBundles.</h4>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>If you really need to unload everything! This is really helpful in the editor when you load a bundle but a link to it is lost during an assembly reload.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="editoraddedcallbacksforassemblyreloadeventstwoeventsaredispatchedonebeforeandoneafterreloadingallassembliesseeclassassemblyreloadevents">Editor: Added callbacks for assembly reload events: two events are dispatched: one before and one after reloading all assemblies. See: class AssemblyReloadEvents.</h4>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>before and one after reloading all assemblies. See: class AssemblyReloadEvents.<br>
If you have ever developed a non-trivial Editor extension you remember the pain for figuring out how to handle assembly reloads changes properly. Especially when transitioning into Play Mode.</p>
<p>We used to have <code>EditorApplication.playmodeStateChanged</code> callback with some code checking <code>EditorApplication.isPlaying</code> and <code>EditorApplication.isPlayingOrWillChangePlaymode</code> properties to figure out why the assemblies were reloaded.</p>
<p>Now we have <code>AssemblyReloadEvents.beforeAssemblyReload</code> and <code>AssemblyReloadEvents.afterAssemblyReload</code>.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="editorexperimentalfeatureretainedmodeuisystemfortheeditoruielements">Editor: Experimental feature : retained-mode UI system for the Editor (UI Elements).</h4>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Have you ever done any Editor scripting? Unity uses this unfamiliar to most of the people concept of <em>Immediate Mode GUI</em> for its interface. It is not easy to start writing your own Editor extensions and takes some time to learn how to do it right.</p>
<p>This is why we are working on a more convenient system to write Editor extensions which is based on a more traditional paradigm — Retained Mode UI.</p>
<p>This system even supports CSS to style elements.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/2017-07-11_18-17-11.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>UL Elements is an experimental feature right now, expect many changes in 2017.2. If you are interested, <a href="https://github.com/Unity-Technologies/UIElementsExamples">read more at our Github account</a>.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="buildpipelineaddeddelegatestobuildplayerwindowthatallowoverridingthedefaultbuildbuttonbehavior">Build Pipeline: Added delegates to BuildPlayerWindow that allow overriding the default Build button behavior.</h4>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Many of you write your own build logic and execute it from the top menu. <code>BuildPlayerWindow.RegisterBuildPlayerHandler</code> allows you to override default behavior of the <em>Build</em> button.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="graphicsincreasedbatchinglimitsto65000vertices810600">Graphics: Increased batching limits to 65,000 vertices. (810600).</h4>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>There was a limit not only for the number of vertices, but also for the number of indices, resulting in less optimal batching. Now static batching can combine more stuff!</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="shadersoptimizedgamedatabuildtimeforshaderswithmassivemillionsorbillionspotentialvariantcountsfixedshaderinspectorpopupmenutodisplayvariantcountslargerthan2billionproperly">Shaders: Optimized game data build time for shaders with massive (&quot;millions or billions&quot;) potential variant counts. Fixed shader inspector popup menu to display variant counts larger than 2 billion properly.</h4>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>For those who have massive shaders q:</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="scriptingrenametodebugloggertodebugunitylogger852000">Scripting: Rename to Debug.logger to Debug.unityLogger (852000).</h4>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>This thing was just a bit annoying. Basically, when typing <code>Debug.lo</code> in a code editor you'd get <code>Debug.logger</code> autocompletion while you needed <code>Debug.Log</code>. I guess, thousands Unity developers have already learned to just type <code>Debug.Log</code>...</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="editorfixfocusedgameviewnotalwaysreceivinginputmacos895460">Editor: Fix focused Game View not always receiving input (macOS) (895460).</h4>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>This one was reported by me and broke one of my pet projects. Basically, a big detached Game View on Mac wasn't receiving input at all ¯\_(ツ)_/¯</p>
<p>I guess, I was the only one trying this on Mac. Glad this was fixed.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="editorassetserverversioncontrolsupporthasbeenremovedfromtheeditor">Editor: AssetServer version control support has been removed from the editor.</h4>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>This last one is kinda sad. To move the Engine forward we unfortunately have to remove old code and features some people might still be using.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="thatsallfolks">That's all, folks!</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>So, this is my quick list.<br>
What is the small feature <strong>YOU</strong> are most excited about?</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Is Vector3.one slow in Unity?]]></title><description><![CDATA[These days you can find a lot of articles giving advice on performance and optimisation. I like testing these little bits of knowledge with little Unity projects on various platforms. Sometimes I get interesting results. This post is about one of them, and I still don't understand the results I got]]></description><link>https://va.lent.in/is-vector3-one-slow/</link><guid isPermaLink="false">5dc9a0ca56953d7286f4d564</guid><dc:creator><![CDATA[Valentin Simonov]]></dc:creator><pubDate>Mon, 30 Jan 2017 17:56:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>These days you can find a lot of articles about Unity over the net which tell you <em>to do this</em> or <em>not to do that</em>, especially when it comes to performance and optimization.</p>
<p>I like testing these little bits of knowledge with little Unity projects on various platforms. Sometimes I get interesting results. This post is about one of them, and I still don't understand the results I got.</p>
<p><strong>TL;DR:</strong> Shit's complicated, yo!</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h1 id="thequestion">The question</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Look at <a href="https://docs.unity3d.com/ScriptReference/Vector3-one.html">Vector3.one</a>. You might have heard that since this is a Property, it is a method call which is not inlined by IL2CPP in any way. So, your little <code>for (var i = 0; i &lt; 100000; i++) v += Vector3.one;</code> in <code>Update()</code> might be costly.</p>
<p><strong>But is it?</strong></p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h1 id="thetest">The test</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>So, I made a test to compare performance of the following:</p>
<ol>
<li>Vector3.one</li>
<li>new Vector3(1, 1, 1)</li>
<li>local variable</li>
<li>static variable</li>
</ol>
<p>The test is measuring timings of 5 loops:</p>
<pre><code class="language-language-csharp">static Vector3 Vector3Zero = new Vector3(1, 1, 1); 
var v3z = new Vector3(1, 1, 1);

// empty
for (var i = 0; i &lt; n; i++) {}
// Vector3.one
for (var i = 0; i &lt; n; i++) { arr[i] = Vector3.one * i; }
// new Vector(1, 1, 1)
for (var i = 0; i &lt; n; i++) { arr[i] = new Vector3(1, 1, 1) * i; }
// static variable
for (var i = 0; i &lt; n; i++) { arr[i] = Vector3Zero * i; }
// local variable
for (var i = 0; i &lt; n; i++) { arr[i] = v3z * i; }
</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h1 id="results">Results</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="osxmonomacbookpro">OS X (Mono) — MacBook Pro</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Running on my MBP with a standalone non-development build I got the following timings:</p>
<ol>
<li>empty: <strong>18 ms</strong>,</li>
<li>Vector3.one: <strong>345 ms</strong>,</li>
<li>new: <strong>325 ms</strong>,</li>
<li>local: <strong>226 ms</strong>,</li>
<li>static: <strong>239 ms</strong>.</li>
</ol>
<p>This seems to be expected, though I am more interested in IL2CPP right now.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="androidgalaxys7il2cpp32bit">Android Galaxy S7 IL2CPP 32 bit</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Next, I published the test to my Android test device:</p>
<ol>
<li>empty: <strong>0 ms</strong>,</li>
<li>Vector3.one: <strong>387 ms</strong>,</li>
<li>new: <strong>177 ms</strong>,</li>
<li>local: <strong>147 ms</strong>,</li>
<li>static: <strong>150 ms</strong>.</li>
</ol>
<p>As you see, the empty loop was optimized by the compiler. I iterated on the test a few times to make sure that it doesn't optimize anything else. As for <code>Vector3.one</code>, here we see that it is more than twice as slow as a local variable, which is still the fastest.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="iosiphone6il2cpp64bit">iOS iPhone 6 IL2CPP 64 bit</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Next, I ran the test on my iOS test device (Android results after /):</p>
<ol>
<li>empty: <strong>0 ms</strong> / <em>0 ms</em>,</li>
<li>Vector3.one: <strong>47 ms</strong> / <em>387 ms</em>,</li>
<li>new: <strong>56 ms</strong> / <em>177 ms</em>,</li>
<li>local: <strong>35 ms</strong> / <em>147 ms</em>,</li>
<li>static: <strong>54 ms</strong> / <em>150 ms</em>.</li>
</ol>
<p><strong>Wait, what?!</strong></p>
<p>I ran this test a lot of times with slight modifications here and there. I'd appreciate if anybody would give me a hint what I did wrong.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="iosiphone6il2cpp32bit">iOS iPhone 6 IL2CPP 32 bit</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Is this a difference in hardware or 32bit vs. 64bit? Samsung S7 should be a bit faster than iPhone 6. Let's see how 32bit code performs (64bit results after /):</p>
<ol>
<li>empty: <strong>0 ms</strong> / <em>0 ms</em>,</li>
<li>Vector3.one: <strong>170 ms</strong> / <em>47 ms</em>,</li>
<li>new: <strong>175 ms</strong> / <em>56 ms</em>,</li>
<li>local: <strong>174 ms</strong> / <em>35 ms</em>,</li>
<li>static: <strong>170 ms</strong> / <em>54 ms</em>.</li>
</ol>
<p>OK, this looks more like timings I got on Android.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h1 id="generatedcode">Generated code</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>So far the only result is that you'd better use a local variable. But let's dig deeper into IL2CPP generated code.</p>
<p>IL2CPP takes your C# code and emits C++ code instead. This C++ code is easy to find in Xcode project but is not that easy to read. If you are interested, I recommend reading <a href="https://blogs.unity3d.com/2015/05/06/an-introduction-to-ilcpp-internals/">the series of blog posts about IL2CPP</a> at Unity Blog.</p>
<p>Let's look at the code generated from our C# test.</p>
<p>Here's <code>Vector3.one</code> C++ code:</p>
<pre><code class="language-language-c">extern &quot;C&quot;  Vector3_t4282066566 Vector3_get_one_m2017759730(…) {
	Vector3_t4282066566 L_0;
	memset(&amp;L_0, 0, sizeof(L_0));
	Vector3__ctor_m2926210380(&amp;L_0, (1.0f), (1.0f), (1.0f), …);
	return L_0;
}
</code></pre>
<p>And this is how this method is called from our code:</p>
<pre><code class="language-language-c">Vector3_t4282066566  L_14 = Vector3_get_one_m2017759730(…);
</code></pre>
<p>Here's <code>new Vector3(1, 1, 1)</code> C++ code:</p>
<pre><code class="language-language-c">Vector3_t4282066566  L_50;
memset(&amp;L_50, 0, sizeof(L_50));
Vector3__ctor_m2926210380(&amp;L_50, (1.0f), (1.0f), (1.0f), …);
</code></pre>
<p><strong>BUT...</strong></p>
<p>Since <code>Vector3_get_one_m2017759730</code> and <code>Vector3__ctor_m2926210380</code> are in the same compilation unit, the constructor is actually inlined in  <code>Vector3_get_one_m2017759730</code> method. It is compiled to the following bytecode:</p>
<pre><code>fmov		s0, #1.00000000
mov.16b	 v1, v0
mov.16b	 v2, v0
ret
</code></pre>
<p><strong>Is this why Vector3.one is not slow here?</strong></p>
<p>But as our code is in another compilation unit, it is correct to say that <code>Vector3_get_one_m2017759730</code> will not be inlined to <strong>our</strong> code.</p>
<p>If you look to any code using static variables, you will see that in IL2CPP it follows the same pattern. For example, this is the call to the static variable in my test:</p>
<pre><code class="language-language-c">IL2CPP_RUNTIME_CLASS_INIT(Test_t2603186_il2cpp_TypeInfo_var);
Vector3_t4282066566 L_26 = 
   ((Test_t2603186_StaticFields*)Test_t2603186_il2cpp_TypeInfo_var	
	-&gt;static_fields)-&gt;get_staticOne_2();
</code></pre>
<p>Luckily, the whole second line is inlined. But, the <code>IL2CPP_RUNTIME_CLASS_INIT</code> macro has to check if the class is initialized every time. <strong>Is this why static variables are slow(er)?</strong></p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h1 id="safetychecks">Safety checks</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Let's look at a snippet of generated IL2CPP code:</p>
<pre><code class="language-language-c">Vector3U5BU5D_t215400611* L_25 = __this-&gt;get_arr_5();
NullCheck(L_25);
IL2CPP_ARRAY_BOUNDS_CHECK(L_25, L_26);
Vector3_t4282066566  L_27 = Vector3_get_one_m886467710(…);
int32_t L_28 = V_3;
Vector3_t4282066566  L_29 = Vector3_op_Multiply_m973638459(…);
(*(Vector3_t4282066566 *)((L_25)
   -&gt;GetAddressAt(static_cast&lt;il2cpp_array_size_t&gt;(L_26)))) = L_29;
</code></pre>
<p>Notice lines two and three:</p>
<pre><code class="language-language-c">NullCheck(L_25);
IL2CPP_ARRAY_BOUNDS_CHECK(L_25, L_26);
</code></pre>
<p>Unity and IL2CPP add a few safety checks to generated code to make sure that you don't accidentally shoot yourself in the foot. This is usually a good thing. But does it add overhead? Yes, it does.</p>
<p>You can turn these safety checks off using <code>Il2CppSetOption</code> attribute (<a href="https://docs.unity3d.com/Manual/IL2CPP.html">read more</a>) like so:</p>
<pre><code class="language-language-c">[Il2CppSetOption(Option.NullChecks, false)]
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
[Il2CppSetOption(Option.DivideByZeroChecks, false)]
public class Test : MonoBehaviour {}
</code></pre>
<p>Of course, you must be absolutely sure that your code is perfect before doing this. Let's see how much performance I got in my test on iPhone 6 by turning these things off:</p>
<ol>
<li>empty: <strong>0 ms</strong> / <em>0 ms</em>,</li>
<li>Vector3.one: <strong>40 ms</strong> / <em>47 ms</em>,</li>
<li>new: <strong>56 ms</strong> / <em>56 ms</em>,</li>
<li>local: <strong>31 ms</strong> / <em>35 ms</em>,</li>
<li>static: <strong>51 ms</strong> / <em>54 ms</em>.</li>
</ol>
<p>Well, this is definitely good.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h1 id="whatwefoundout">What we found out</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="64bit">64-bit</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Does the fact that I build for a 64-bit platform give such speed boost?</p>
<p>Here I'm entering the realm where I don't really have much expertise. From a lot of googling and chatting with more experienced colleagues I got the following:</p>
<ol>
<li>It's not SIMD. Generated ARM instructions are definitely not SIMD.</li>
<li>The 64-bit bytecode seems to be using registers instead of stack to pass function parameters.</li>
</ol>
<p>This might be just an edge case. So, the question is still open.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h1 id="results">Results</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><ol>
<li>It is really important to test things on your platform and target device.</li>
<li>Compilers are smart.</li>
<li>Use a local variable.</li>
<li>You learn a lot while making tests.</li>
</ol>
<p>... and (sadly) I still don't understand what's going on.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Opening links in a Unity WebGL project]]></title><description><![CDATA[The heart of HTML pages are links which can be opened either in the same window/tab or in a popup window/tab. Turns out that it's not that simple with a Unity WebGL project precisely because of one of the browser's security mechanisms]]></description><link>https://va.lent.in/opening-links-in-a-unity-webgl-project/</link><guid isPermaLink="false">5dc9a3c156953d7286f4d5a8</guid><dc:creator><![CDATA[Valentin Simonov]]></dc:creator><pubDate>Sat, 07 Nov 2015 18:08:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<p>A <a href="http://docs.unity3d.com/Manual/webgl-gettingstarted.html">WebGL</a> Unity project is just a normal HTML page running a 3 000 000 lines of code JavaScript file.</p>
</blockquote>
<p>The heart of HTML pages are <a href="http://va.lent.in">links</a> which can be opened either in the same window/tab or in a popup window/tab. Turns out that it's not that simple with a Unity WebGL project precisely because of one of the browser's security mechanisms.</p>
<p>Modern browsers open links in new tabs/windows only when they clearly see that this action resulted from a user input event, like mouse click for example. If not, Firefox displays this when a JavaScript uses <code>window.open()</code> code to open a new window:</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/ffnewwindow.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>This is fine in a context of a normal web page when you click links. But in Unity actual input is processed within <em>Player Loop</em> in a moment after you clicked an object which is too late for a browser to consider this action to be originated from a user event.</p>
<p>So, if you use <code>Application.ExternalEval(&quot;window.open('http://google.com');&quot;);</code> in Unity when a mouse button is pressed this will be already too late and your window will be blocked by default.</p>
<p>A proper solution here would be the same described in <a href="http://docs.unity3d.com/Manual/webgl-cursorfullscreen.html">Unity WebGL Docs</a> — send a message to JavaScript from Unity when a button is pressed so JavaScript would execute actual window opening code when user releases the button.</p>
<p>This can be done in a few ways described in Unity WebGL Docs: <a href="http://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html">Interacting With Browser Scripting</a>. But let's see how one can write a WebGL JS Plugin to do this.</p>
<p>A WebGL plugin is a <strong>.jslib</strong> file placed anywhere in your project. It's a good idea to store plugins somewhere like <strong>/Assets/Plugins/WebGL</strong> but it's not required anymore. New <em>Plugin Inspector</em> in Unity 5 makes life much easier:</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/plugin.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>The contents of OpenWindow.jslib file is the following:</p>
<pre><code>var OpenWindowPlugin = {
    openWindow: function(link)
    {
    	var url = Pointer_stringify(link);
        document.onmouseup = function()
        {
        	window.open(url);
        	document.onmouseup = null;
        }
    }
};

mergeInto(LibraryManager.library, OpenWindowPlugin);
</code></pre>
<p>It's a JS file with an object containing one function — <strong>openWindow</strong>. This function receives an URL from Unity and set's up <strong>onmouseup</strong> event for entire web page which when opens this URL. <em>Notice: this is just the most simple example code.</em></p>
<p>Then, the simplest script to use this plugin would be the following:</p>
<pre><code>using UnityEngine;
using System.Runtime.InteropServices;

public class Link : MonoBehaviour {
	public void OpenLinkJSPlugin() {
		#if !UNITY_EDITOR
		openWindow(&quot;http://unity3d.com&quot;);
		#endif
	}

	[DllImport(&quot;__Internal&quot;)]
	private static extern void openWindow(string url);
}
</code></pre>
<p>Notice <code>#if !UNITY_EDITOR</code> in the script — this is a preprocessor define to include this code only when executed not in Unity Editor, because this code will not work there.</p>
<p>The next thing is we need to code another small script to  actually execute this code on <strong>mouseDown</strong> event when we click an UI Button for example. The issue with Buttons is that they fire <strong>onClick</strong> event only when mouse button is released, which is too late for us. This means that we need another script and we need to put it on our Button element in UI hierarchy:</p>
<pre><code>using UnityEngine;
using UnityEngine.EventSystems;
using System;
using UnityEngine.Events;

public class PressHandler : MonoBehaviour, IPointerDownHandler {
	[Serializable]
	public class ButtonPressEvent : UnityEvent { } 

	public ButtonPressEvent OnPress = new ButtonPressEvent();

	public void OnPointerDown(PointerEventData eventData) 	{
		OnPress.Invoke();
	}
}
</code></pre>
<p>Put this script on your UI Button and set <strong>OnPress</strong> event to call our <strong>OpenLinkJSPlugin</strong> function.</p>
<p>For an example Unity project you can refer to <a href="https://github.com/valyard/UnityWebGLOpenLink">this GitHub page</a>.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Optimize for readability first]]></title><description><![CDATA[Developers spend most of their productive time reading code, not writing it: debugging, checking commits, etc. While doing this developers essentially work as (not so good actually) interpreters — executing code in their head while trying to keep in mind the current state of execution.]]></description><link>https://va.lent.in/optimize-for-readability-first/</link><guid isPermaLink="false">5dc9a53b56953d7286f4d5c9</guid><dc:creator><![CDATA[Valentin Simonov]]></dc:creator><pubDate>Tue, 08 Jul 2014 17:15:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Nowadays when someone uses the word <strong>optimization</strong> they usually mean <strong>optimization for execution time</strong>, unless they've explicitly stated that they are going to optimize for GPU memory consumption, network traffic, etc.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h1 id="knowwhatyouareoptimizingfor">Know what you are optimizing for</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>When I started programming we not only had slow processors, we also had very limited memory — sometimes measured in kilobytes. So we had to think about memory and optimize memory consumption wisely. University taught us about two extremes in optimization:</p>
<ul>
<li>You either optimize for execution speed sacrificing memory,</li>
<li>Or you optimize for memory consumption by calculating stuff over and over again.</li>
</ul>
<p>These days nobody cares about memory much (except demosceners, embedded systems engineers and sometimes mobile games developers); I mean not only RAM but hard drive space too. <em>Just look at the Watch Dogs install which is about 25Gb on disk. In addition, I'm writing this in a Chrome tab which ate 130Mb of RAM.</em></p>
<p>But there are more optimization types:</p>
<ul>
<li>Optimization for power consumption, which is getting more attention with growth of smartphones market</li>
<li>Optimization for readability to make reading and debugging code easier, thus reducing development time and cost</li>
<li><em>I'll just stop here...</em></li>
</ul>
<blockquote>
<p>Optimization for readability — making code easier to read, follow and understand.</p>
</blockquote>
<p>You should understand that you can't optimize everything at once. For example, while working on performance optimization you will likely make your app consume more memory and make your code less readable.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h1 id="whyreadability">Why readability</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><blockquote>
<p>Developers spend most of their productive time reading code, not writing it: debugging, checking commits done by others, learning new libraries, etc.</p>
</blockquote>
<p>While doing this developers essentially work as (not so good actually) interpreters — executing code in their head while trying to keep in mind the current state of execution. This is why programmers tend to be particularly grumpy when interrupted during this process.</p>
<blockquote>
<p><strong>Time == money</strong></p>
</blockquote>
<p>The most important thing to understand is that your and your coworkers' time costs a lot. And even if a developer works hard they can still waste time by:</p>
<ul>
<li>Working on things which are not needed now and might be never used.</li>
<li>Working on something which doesn't add perceivable value.<br>
<em>For example, wasting a week to optimize execution time of a function which is called once an hour by 10ms.</em></li>
<li>Writing hard-to-debug code and trying to find bugs in it.</li>
<li>Writing code which slows down other people.<br>
<em>Remember that &quot;other people&quot; might as well be YOU in just a week.</em></li>
</ul>
<p>This is provided that the developer in question is an experienced one and knows how to write efficient algorithms and clean code. Otherwise this list would be too long.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h1 id="optimizeforreadability">Optimize for readability</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>There's a well-known quote by Donald Knuth. I bet you've heard it numerous times.</p>
<blockquote>
<p>&quot;Premature optimization is the root of all evil (or at least most of it) in programming.&quot; by D.Knuth, 1974.</p>
</blockquote>
<p>I have seen a lot of people who memorized it but didn't understand what this quote really means. The most common mistake looks like this:</p>
<p>— Why the code for this simple task is so complicated?<br>
— I optimized X and Y because in the future...<br>
— Haven't you heard that <em>Premature optimization is the root of all evil</em>?<br>
— Sure, but this is not <em>premature optimization</em>, <strong>I know that this way it will work faster</strong>.</p>
<p>I assume this is because the term <em>premature optimization</em> is not well-defined. This is why the person in the example doesn't consider what he has done to be a <em>premature optimization</em> at all. How can we define this term?</p>
<blockquote>
<p>Premature optimization — everything one tries to optimize before profiling and running tests on a working system.</p>
</blockquote>
<p>Everything except readability. So instead of what one <em>shouldn't do</em> we'd better say what one <em>should do</em>. And the quote will look like this:</p>
<blockquote>
<p>Optimize for readability first.</p>
</blockquote>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h1 id="whatslowsdowndeveloperswhenreadingcode">What slows down developers when reading code</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Well, we agreed that we should make our code easier to read to spend less time doing it, wasting less money, right? But what does it really mean?</p>
<p>There are two fundamental things that immensely slow down a developer while reading code:</p>
<ol>
<li>The code is hard to understand,</li>
<li>The code is hard to follow.</li>
</ol>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h1 id="thecodeishardtounderstand">The code is hard to understand</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Unfortunately people are not like software interpreters which don't bother to know what the code means to add two numbers and call a function (while it still compiles, of course).</p>
<p>To find why the code doesn't work a programmer needs to understand exactly what it does as typed in a source file, and what its original purpose was.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="whatmakescodehardtounderstand">What makes code hard to understand?</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>From here I'll be writing about an experienced developer who knows the language the code is written in and algorithms used in the application's domain (<em>i.e. he has enough knowledge to understand this code</em>).</p>
<ol>
<li>The code stinks. Monstrosities of one letter variables and 1000 lines long functions.</li>
<li>It is not properly or consistently formatted.</li>
<li>It has unnecessary one-liners.</li>
<li>There are undocumented low-level optimizations.</li>
<li>The code is too clever.</li>
</ol>
<p>I'll skip the first two because you shouldn't be reading bad code anyway. If someone in your company writes it, teach them or get rid of them. And of course you need to enforce strict coding style for your entire code base.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="3ithasunnecessaryoneliners">3. It has unnecessary one-liners</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Or so-called <strong>number of lines optimizations</strong>. Long lines with nested function calls and <strong>?:</strong> operators are harder to parse. Of course, you may say that this argument is subjective. But some people just feel that they must leave in source code as few lines as possible, sacrificing readability.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="4undocumentedlowleveloptimizations">4. Undocumented low-level optimizations</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Long time ago the code was readable and worked fine, but someone decided to optimize it at some point. It might be a good optimization after serious profiling, but now the code looks like a combination of arrays, bitwise operators and magic numbers. Nobody knows what exactly it does or even what it was supposed to do because the guy who made the optimization didn't leave any comments.</p>
<p>You probably heard that good code doesn't need comments. But optimized code (<s>even</s>especially if it's good) DOES need them.</p>
<p>Most harmless consequences of such optimizations might be <a href="http://jacksondunstan.com/articles/983">undocumented lines like this</a> in your code base:</p>
<pre><code class="language-language-csharp">if (val != val) { ... }
</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="5thecodeistooclever">5. The code is too clever</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>As software developers we learn more and more <em>academic</em> tricks which we then use in production code. We are <em>Computer Scientists</em> after all, not just mere coders!</p>
<p>Some languages even encourage developers to use bleeding edge techniques, making code more expressive and <em>academic</em>. You get the same feeling of accomplishment when you build a perfectly robust system in code as when you prove a hard theorem in math using methods 99.997% of educated individuals don't understand.</p>
<p>Even if code is well-organized into modules/classes/functions and each of these blocks contains perfectly readable imperative code, for someone else to read this code they will need a broader view of its architecture and they must know all the techniques and patterns used.</p>
<blockquote>
<p>Once again remember that &quot;someone else&quot; might as well be YOU in a week.</p>
</blockquote>
<p>This is most likely why I know only 2 people who use Scala in production. Personally I like Scala a lot. <em>For me it has been an academic playground where I could build glass castles in vacuum.</em> But the more you know about it and the more you use its features, the more you understand that <em>it's essentially a write-only language</em> (please don't quote me on this!); not as write-only as Perl, but even the most beautiful code base will require changes and updates.</p>
<p>Not as write-only as <em>Perl</em> but even the most beautiful code base will require changes and updates. And now you are stuck looking for a person who can understand this <em>beautiful code</em>...</p>
<p>This seems controversial that clean clever code is harder to read.</p>
<blockquote>
<p>&quot;Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.&quot; by Brian Kernighan</p>
</blockquote>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h1 id="thecodeishardtofollow">The code is hard to follow</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>When reading code a developer jumps frequently from one method or class to another. This is where knowing your IDE of choice will save you a lot of time. By using <strong>Go to Declaration</strong>, <strong>Find Usages</strong>, <strong>Navigate to</strong>, <strong>Inspect</strong> and other features of an IDE <em>(Visual Studio for example)</em> you will be able to think about code as a <strong>connected graph</strong>.</p>
<blockquote>
<p>It's fine to write code in Notepad but if you want to read code efficiently you will have to master a good IDE.</p>
</blockquote>
<p>Well, what is a <strong>connected graph</strong> exactly?</p>
<blockquote>
<p>A graph which is connected in the sense of a topological space, i.e., there is a path from any point to any other point in the graph. <a href="http://mathworld.wolfram.com/ConnectedGraph.html">(source)</a></p>
</blockquote>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/graph.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>In other words in <em>&quot;connected&quot;</em> code you can easily follow from one method to another making a model in your mind of what this code does.</p>
<p>If somewhere in code a connection is broken (in a sense that IDE can't assist you jumping from one method to another) you usually have to spend some time looking for this connection yourself. More broken connections in code —&gt; harder it is to follow —&gt; harder it is to read.</p>
<p>So, why might the code graph be disconnected? There are many reasons; I'll list the ones I see most often:</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="1methodsorpropertiesarereferencedasstrings">1. Methods or properties are referenced as strings</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Some frameworks just love doing this. They pass <em>&quot;callbacks&quot;</em> as strings and use reflection when needed. Here you just have to use good old <strong>CMD+F</strong>.</p>
<p>Most evil ones make these strings dynamic... in dynamic languages. <em>All hail JavaScript! Or AS3 for that matter.</em></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="2codeisseparatedintodisconnectedparts">2. Code is separated into disconnected parts</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>For example, half of your code is written in C# and the other half is assembled in a visual node editor. You will have a hard time jumping between these two worlds.</p>
<p>The same stands for <em>Dependency Injection frameworks</em> and other XML-configured bullshit. They don't say it loud but writing XML configs is coding too. It's called declarative programming <em>(not mentioning those insane people who build imperative languages over XML)</em>.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="3hugegraphnodes">3. Huge graph nodes</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>20 links jump to this 1000 lines long method?.. ouch. You have no use for a graph which contains such nodes.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="4everythingistooabstract">4. Everything is too abstract</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>When by <strong>Go to Declaration</strong> you get to an interface or an abstract class and have to figure out which implementation there might be. It gets worse with <em>Dependency Injection</em>, <em>abstract factories</em> and all the other methods which fight dependencies. Connections between nodes in code graph become too abstract.</p>
<p>It might seem that I hate <strong>DI</strong> and <strong>XML</strong>. DI is a great tool to avoid <em>spaghetti code</em> and make your architecture more modular and testable. But as many other good things it gets ugly when abused.</p>
<blockquote>
<p>I was completely discouraged once when I was inspecting an app and I realised that I couldn't figure out where it starts... Like where the entry point is. It all was just automagically assembled from a huge XML config on start.</p>
</blockquote>
<p>I do hate <em>XML configs</em> though.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h1 id>***</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>So, here's what you should have learned:</p>
<ul>
<li>Master your IDE,</li>
<li>Keep code graphs as connected as possible,</li>
<li>Write simple code first,</li>
<li>By writing unnecessary code you are wasting a lot of money.</li>
</ul>
<p>It will take time and forcing yourself to write simple code, and resisting optimizations on early stages will definitely be hard.</p>
<p><strong>But 2 hours before the deadline, having been awake for 48 hours straight, you will say &quot;thank you&quot; to yourself in the past if the code you are working with is debuggable with a half asleep brain.</strong></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="ps">P.S.</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Don't miss great discussions on <a href="http://www.reddit.com/r/programming/comments/2a5sqp/optimize_for_readability_first_what_slows_down/">reddit</a> and <a href="https://news.ycombinator.com/item?id=8008634">hackernews</a>.<br>
Thanks to <a href="http://www.reddit.com/user/Arandur">/u/Arandur</a> for correcting numerous grammatical errors!</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[When someone on the internet is a greater authority than you]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Last week I stumbled upon <a href="http://fragmentbuffer.com/docs/PerformanceProgramming.pdf">Slides of Keith O'Conor's talk</a> about performance optimizations and it reminded me of a topic I wanted to write a blog post about for several months.</p>
<p>So this is <strong>the post</strong>.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="informationsponges">Information sponges</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>I have a huge list of RSS subscriptions and usually scroll through</p>]]></description><link>https://va.lent.in/when-someone-on-the-internet-is-greater-authority-than-you/</link><guid isPermaLink="false">5dcbd17556953d7286f4d630</guid><dc:creator><![CDATA[Valentin Simonov]]></dc:creator><pubDate>Mon, 07 Jul 2014 08:48:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Last week I stumbled upon <a href="http://fragmentbuffer.com/docs/PerformanceProgramming.pdf">Slides of Keith O'Conor's talk</a> about performance optimizations and it reminded me of a topic I wanted to write a blog post about for several months.</p>
<p>So this is <strong>the post</strong>.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="informationsponges">Information sponges</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>I have a huge list of RSS subscriptions and usually scroll through ~500 articles a day adding 10-30 of them to <a href="http://getpocket.com/a/queue/">Pocket</a> to read later. <em>Which I rarely do.</em> Most likely that you do the same. Because there's just too much information on the internet even if you read only blogs about software development.</p>
<p>I call people as myself <strong>&quot;information sponges&quot;</strong> because we try to absorb as much information as possible on a daily basis. Maybe some day this data will be useful...</p>
<p>And there's nothing bad about it... Nothing bad as long as you reflect on this information and don't catch yourself into a trap of partial filtering.</p>
<p>And this is what <strong>junior developers</strong> never do. Let me explain...</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="partialfiltering">Partial filtering</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>All good talks and articles on the internet which give you insights on new technologies, methods, patterns and algorithms always specifically point out WHEN these algorithms should be used and what problems these new technologies are trying to solve.</p>
<blockquote>
<p>The thing is that being overwhelmed by awesomeness of these new methods it's easy to filter out the information about when they should be used.</p>
</blockquote>
<p>For example you might watch a video from a conference where a well-known speaker tells you how awesome MVC is. Of course explicitly or implicitly he will mention the problem which MVC solves. Because it's not just abstractly good, <strong>MVC is a solution to the specific problem</strong> (try to test yourself and say out load what this problem is).</p>
<blockquote>
<p>Partial filtering is when you remember only that &quot;MVC is awesome&quot; instead of &quot;MVC is a great solution to this specific problem&quot;.</p>
</blockquote>
<p>Another good example is optimization. There are tons of great articles and talks about how to optimize stuff.</p>
<p>All of them usually mention that <strong>these are solutions to specific performance problems</strong>. If you don't have these problems don't try to optimize your code. You will just waste a lot of time and make it unreadable. Unfortunately this part is usually ignored.</p>
<p>The paper I started from has a slide on this topic.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/optimize.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>This slide should have been in the beginning. With bold red text and images of dead programmers who didn't profile before optimizing.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="someoneontheinternetsaidtodoso">Someone on the internet said to do so</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>And here's where it gets interesting.</p>
<p>Imagine a junior developer who is an information sponge <em>(nothing bad so far)</em>, who unwittingly applies a partial filter to all information he absorbs <em>(not so bad either)</em>, who thinks that because he absorbed all this information he is an uber developer now <em>(not that fatal)</em> and <strong>who doubts every single word from you contradicting to this filtered information especially when the information was presented by some authoritative person from Microsoft, Adobe, Oracle, you name it</strong>. Not just questions your opinion but he is totally sure that if that person on the internet said something you must be a total fool if you say something opposite.</p>
<p>Most of the time it goes like this:</p>
<p>— Damn, why did you code this monstrosity? Why didn't you use this easy built-in mechanism this framework gives you?<br>
— The guys from Adobe say it's more performant.<br>
— It might be faster on shitty mobile devices, we are running the app on Intel i7.<br>
— But the guys from Adobe say...<br>
— They say it for mobile devices.<br>
— Whatever... (meaning &quot;you don't know shit and you are no authority for me&quot;)</p>
<p>Once I even had this conversation which completely pissed me off:</p>
<p>— The library was not made to be used like you are using it. But now we have to do this because you ignored this easy mechanism provided by the framework and we don't have time to rebuild the whole thing.<br>
— Who said that this library shouldn't be used this way? (meaning &quot;give me a link to a video where someone from Microsoft says not to use the library this way&quot;)<br>
— Me, the freaking author of the freaking library said that for fuck's sake.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="reflectingonyourself">Reflecting on yourself</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Long time ago I was building a simple messaging system and was taken away by that object pooling strategy I learned from some blog. Of course I implemented it straight away just to be asked by my coworker:</p>
<p>— Why the hell did you do this?<br>
— For performance, it caches message objects.<br>
— Right... how many messages are you going to receive per second?<br>
— Like... 1...<br>
— Do you understand now?</p>
<p>Of course there was no point implementing message pooling system here. And I wasted half a day on this simple task trying to optimize the problem we didn't have.</p>
<blockquote>
<p>This is a part of your learning curve — making mistakes and reflecting on them later.</p>
</blockquote>
<p>I obviously had a mental filter which dropped the information on what problem this technique is solving. <strong>From that day I'm aware that while consuming information I might unwittingly activate such filter, so after reading a blog post or watching a talk I try to reflect on the information i received and how I understood it.</strong></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="dealingwithsuchpeople">Dealing with such people</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Personally I don't know how to deal with juniors for whom you aren't authoritative enough. It might be a coincidence but lately I'm meeting such people more often. Is it the new generation which can't handle information overload? I don't know.</p>
<p>I think that a junior developer must first <strong>accept that he is junior</strong> (though there's no definition here and a programmer with 5 years of experience may be as junior as a college graduate after all) and then <strong>learn hard from practical tasks and experienced colleagues</strong>.</p>
<p>The person described is unable to do both.</p>
<p>Another thing is that unfortunately I don't know anything about you as a reader of this blog. And this person might as well be you. Even if it's true you won't be able to accept it.</p>
<blockquote>
<p>Think about it, reflect on yourself and don't ever blindly beleive what someone from Microsoft, Adobe, Oracle, you name it, said on the internet... or YOU think you remember what they said.</p>
</blockquote>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Unity: make your lists functional with ReorderableList]]></title><description><![CDATA[In Unity 4.5 we got a nice (undocumented) built-in tool to visualize lists in IDE. It's called ReorderableList. Let's see how to code beautiful interfaces in Unity IDE using ReorderableList]]></description><link>https://va.lent.in/unity-make-your-lists-functional-with-reorderablelist/</link><guid isPermaLink="false">5dc9265f56953d7286f4d428</guid><dc:creator><![CDATA[Valentin Simonov]]></dc:creator><pubDate>Fri, 27 Jun 2014 14:47:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>In Unity 4.5 we got a nice <em>(undocumented)</em> built-in tool to visualize lists in IDE. It's called <code>ReorderableList</code>, it's located in <code>UnityEditorInternal</code> namespace and looks like this:</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/result_edited.gif" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>Let's see how to code this beautiful interface in Unity IDE using <strong>ReorderableList</strong>.</p>
<blockquote>
<p><strong>Note:</strong> Though <em>UnityEditorInternal</em> namespace is public, it seems to be intended for Unity Team internal use <em>(hence the name)</em>, it is not documented and might change in future versions of Unity. If you notice an API change please post it in <em>comments section</em> below.</p>
</blockquote>
<p><strong>Sources:</strong> <a href="https://github.com/valyard/ReorderableListExample">Project sources are on GitHub</a>.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="settinguptheproject">Setting up the project</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Let's pretend that we are making a Tower Defense-like game and need a decent interface for our game-designer to set up waves of monsters for a particular level.</p>
<p>First, create a new Unity project.</p>
<p>We will need some test assets: <em>mobs</em> and <em>bosses</em>. We'll be placing them in <code>Prefabs/Mobs</code> and <code>Prefabs/Bosses</code> folders. Create several prefabs and put them in these folders. Right now these can be just default cubes and spheres. Give them descriptive names. This is what I came up with:</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/prefabs.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="storingdata">Storing data</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Create <code>Scripts</code> folder where we will store our <strong>C#</strong> scripts. Create two scripts in this folder: <code>LevelData.cs</code> and <code>MobWave.cs</code>.</p>
<p>Add this code to <code>MobWave.cs</code>. This is our value object for storing data for a wave of monsters.</p>
<pre><code class="language-language-csharp">using UnityEngine;
using System;

[Serializable]
public struct MobWave {
	public enum WaveType {
		Mobs,
		Boss
	}

	public WaveType Type;
	public GameObject Prefab;
	public int Count;
}
</code></pre>
<p>As you see, every wave can be either a wave of <em>Mobs</em> or one or more <em>Bosses</em>. Every wave has a link to a prefab to clone and a number of copies.</p>
<blockquote>
<p><strong>Note:</strong> Unity can serialize custom structs since version 4.5.</p>
</blockquote>
<p>Add this code to <code>LevelData.cs</code>. This is just a container for our <code>MobWave</code> objects.</p>
<pre><code class="language-language-csharp">using UnityEngine;
using System.Collections.Generic;

public class LevelData : MonoBehaviour {
	public List&lt;MobWave&gt; Waves = new List&lt;MobWave&gt;();
}
</code></pre>
<p>Add a <code>GameObject</code> to your scene and call it <code>Data</code>. Add <code>LevelData</code> component to this game object and set it up as shown in the GIF animation below.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/setting_up.gif" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>This is basically how lists in Unity IDE look by default. Of course they are not bad, but they become a major pain very quickly when you have many items in a list and want to move them around and add some in the middle.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="buildingacustominspector">Building a custom inspector</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>For every <em>Component</em> in Unity IDE you can create a custom inspector which will change how the component is shown in <em>Inspector</em> tab. Right now we will do this for our <code>LevelData.cs</code> script to change Unity's default list rendering to more functional <strong>ReorderableList</strong>.</p>
<p>Create <code>Editor</code> folder and a new script inside. Call it <code>LevelDataEditor.cs</code>.</p>
<blockquote>
<p><strong>Note:</strong> All custom inspectors must be in <strong>Editor</strong> folder and inherit from <code>Editor</code> class.</p>
</blockquote>
<p>Add this code to the new script:</p>
<pre><code class="language-language-csharp">using UnityEngine;
using UnityEditor;
using UnityEditorInternal;

[CustomEditor(typeof(LevelData))]
public class LevelDataEditor : Editor {
	private ReorderableList list;
	
	private void OnEnable() {
		list = new ReorderableList(serializedObject, 
        		serializedObject.FindProperty(&quot;Waves&quot;), 
        		true, true, true, true);
	}
	
	public override void OnInspectorGUI() {
		serializedObject.Update();
		list.DoLayoutList();
		serializedObject.ApplyModifiedProperties();
	}
}
</code></pre>
<p>All custom inspector classes have the same important parts:</p>
<ol>
<li>A custom inspector must inherit from <code>Editor</code> class,</li>
<li>To tell Unity that this is an inspector for <code>LevelData</code> component we must add <code>[CustomEditor(typeof(LevelData))]</code> attribute,</li>
<li><code>private void OnEnable()</code> method is used for initialization,</li>
<li><code>public override void OnInspectorGUI()</code> method is called when inspector is redrawn.</li>
</ol>
<p>In our case in <code>OnEnable</code> we are creating an instance of <code>ReorderableList</code> to draw our <code>Waves</code> property. Don't forget to import <strong>UnityEditorInternal</strong> namespace:</p>
<pre><code class="language-language-csharp">using UnityEditorInternal;
</code></pre>
<p><strong>ReorderableList</strong> works with standard <strong>C#</strong> lists as well as with <em>SerializedProperties</em>. It has two constructors and their more general variants:</p>
<ol>
<li><code>public ReorderableList(IList elements, Type elementType)</code>,</li>
<li><code>public ReorderableList(SerializedObject serializedObject, SerializedProperty elements)</code>.</li>
</ol>
<p>In this example we are using <strong>SerializedProperty</strong> because this is the recommended way of working with properties in custom inspectors. This makes the code smaller and works nicely with Unity and Undo system.</p>
<pre><code class="language-language-csharp">public ReorderableList(
	SerializedObject serializedObject, 
	SerializedProperty elements, 
    bool draggable, 
    bool displayHeader, 
    bool displayAddButton, 
    bool displayRemoveButton);
</code></pre>
<p>As you see just by using right parameters we can restrict adding, removing and reordering of items in our list.</p>
<p>Later in the code we just call <code>list.DoLayoutList()</code> to draw the interface.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/list_1.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>Right now you are probably saying: &quot;Wait, this looks even worse!&quot;. But wait a minute, our data structure is complex so Unity doesn't know how to draw it properly. Let's fix this.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="drawinglistitems">Drawing list items</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p><strong>ReorderableList</strong> exposes several delegates we can use to customize our lists. The first one is <code>drawElementCallback</code>. It's called when a list item is drawn.</p>
<p>Add this code in <code>OnEnable</code> after the list is created:</p>
<pre><code class="language-language-csharp">list.drawElementCallback = 
	(Rect rect, int index, bool isActive, bool isFocused) =&gt; {
	var element = list.serializedProperty.GetArrayElementAtIndex(index);
	rect.y += 2;
	EditorGUI.PropertyField(
    	new Rect(rect.x, rect.y, 60, EditorGUIUtility.singleLineHeight),
        element.FindPropertyRelative(&quot;Type&quot;), GUIContent.none);
	EditorGUI.PropertyField(
    	new Rect(rect.x + 60, rect.y, rect.width - 60 - 30, EditorGUIUtility.singleLineHeight),
        element.FindPropertyRelative(&quot;Prefab&quot;), GUIContent.none);
	EditorGUI.PropertyField(
    	new Rect(rect.x + rect.width - 30, rect.y, 30, EditorGUIUtility.singleLineHeight),
        element.FindPropertyRelative(&quot;Count&quot;), GUIContent.none);
};
</code></pre>
<p>Return to Unity. Now all the list items are pretty and functional. Try adding new ones and dragging them around. This is much better, right?</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/list_2.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>If you are not familiar with the syntax and APIs in the code you just pasted, this is a standard <strong>C#</strong> <em>lambda-expression</em> with <em>Editor GUI methods</em>.</p>
<blockquote>
<p><strong>Note:</strong> It's important to have a semicolon at the end of a lambda };</p>
</blockquote>
<p>Here we are getting the list item being drawn:</p>
<pre><code class="language-language-csharp">var element = list.serializedProperty.GetArrayElementAtIndex(index);
</code></pre>
<p>We are using <code>FindPropertyRelative</code> method to find properties of the wave:</p>
<pre><code class="language-language-csharp">element.FindPropertyRelative(&quot;Type&quot;)
</code></pre>
<p>And after that we are drawing 3 properties in one line: <code>Type</code>, <code>Prefab</code> and <code>Count</code>:</p>
<pre><code class="language-language-csharp">EditorGUI.PropertyField(
	new Rect(rect.x, rect.y, 60, EditorGUIUtility.singleLineHeight),
    element.FindPropertyRelative(&quot;Type&quot;), GUIContent.none);
</code></pre>
<p>Note that list header says <em>&quot;Serialized Property&quot;</em>. Let's change it to something more informative. To do this we need to use <code>drawHeaderCallback</code>.</p>
<p>Paste this code in <code>OnEnable</code> method:</p>
<pre><code class="language-language-csharp">list.drawHeaderCallback = (Rect rect) =&gt; {
	EditorGUI.LabelField(rect, &quot;Monster Waves&quot;);
};
</code></pre>
<p>Now it feels right.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/list_3.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>At this stage the list is fully functional but I want to show you how we can extend it even further. Let's see what other callbacks <strong>ReorderableList</strong> has to offer.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="callbacks">Callbacks</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Here are all the callbacks exposed by an instance of <strong>ReorderableList</strong>:</p>
<ul>
<li>drawElementCallback</li>
<li>drawHeaderCallback</li>
<li>onReorderCallback</li>
<li>onSelectCallback</li>
<li>onAddCallback</li>
<li>onAddDropdownCallback</li>
<li>onRemoveCallback</li>
<li>onCanRemoveCallback</li>
<li>onChangedCallback</li>
</ul>
<h4 id="drawelementcallback">drawElementCallback</h4>
<blockquote>
<p>Signature: <em>(Rect rect, int index, bool isActive, bool isFocused)</em></p>
</blockquote>
<p>Here you can specify exactly how your list elements must be drawn. Because if you don't this code is used to draw list elements:</p>
<pre><code class="language-language-csharp">EditorGUI.LabelField(rect,
	EditorGUIUtility.TempContent((element == null) ? listItem.ToString() : element.displayName));
</code></pre>
<h4 id="drawheadercallback">drawHeaderCallback</h4>
<blockquote>
<p>Signature: <em>(Rect rect)</em></p>
</blockquote>
<p>Is used to draw list header.</p>
<h4 id="onreordercallback">onReorderCallback</h4>
<blockquote>
<p>Signature: <em>(ReorderableList list)</em></p>
</blockquote>
<p>Called when an element is moved in the list.</p>
<h4 id="onselectcallback">onSelectCallback</h4>
<blockquote>
<p>Signature: <em>(ReorderableList list)</em></p>
</blockquote>
<p>Called when an element is selected in the list.</p>
<h4 id="onaddcallback">onAddCallback</h4>
<blockquote>
<p>Signature: <em>(ReorderableList list)</em></p>
</blockquote>
<p>Called when the <strong>+</strong> button is pressed. If this callback is assigned it must create an item itself, in this case default logic is disabled.</p>
<h4 id="onadddropdowncallback">onAddDropdownCallback</h4>
<blockquote>
<p>Signature: <em>(Rect buttonRect, ReorderableList list)</em></p>
</blockquote>
<p>Called when the <strong>+</strong> button is pressed. If this callback is assigned <strong>+</strong> button changes to <strong>Add more</strong> button and <code>onAddCallback</code> is ignored. As with <code>onAddCallback</code> you must create a new list element yourself.</p>
<h4 id="onremovecallback">onRemoveCallback</h4>
<blockquote>
<p>Signature: <em>(ReorderableList list)</em></p>
</blockquote>
<p>Called to remove selected element from the list. If this callback is defined default logic is disabled.</p>
<h4 id="oncanremovecallback">onCanRemoveCallback</h4>
<blockquote>
<p>Signature: <em>bool (ReorderableList list)</em></p>
</blockquote>
<p>Called when <strong>—</strong> button is drawn to determine if it should be active or disabled.</p>
<h4 id="onchangedcallback">onChangedCallback</h4>
<blockquote>
<p>Signature: <em>(ReorderableList list)</em></p>
</blockquote>
<p>Called when the list is changed, i.e. an item added, removed or rearranged. If data within an item is changed this callback is not called.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="addingselectionhelper">Adding selection helper</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>You can add <code>Debug.Log()</code> to all these callbacks to see when they are called. But now let's make something useful with some of them.</p>
<p>The first one will be <code>onSelectCallback</code>. We'll make that when you select an element the corresponding mob prefab is highlighted in <em>Project</em> panel.</p>
<p>Add this code to <code>OnEnable</code> method:</p>
<pre><code class="language-language-csharp">list.onSelectCallback = (ReorderableList l) =&gt; {
	var prefab = l.serializedProperty.GetArrayElementAtIndex(l.index).FindPropertyRelative(&quot;Prefab&quot;).objectReferenceValue as GameObject;
	if (prefab)
    	EditorGUIUtility.PingObject(prefab.gameObject);
};
</code></pre>
<p>The code is pretty simple. We are looking for <code>Prefab</code> property of selected wave and if it's defined we are calling <code>EditorGUIUtility.PingObject</code> method to highlight it in <em>Project</em> panel.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="checkinghowmanywaveshaveleft">Checking how many waves have left</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Let's say that we want to have at least one wave in our list at all times. In other words we want to disable <strong>—</strong> button if there's only one element in the list. We can do this using <code>onCanRemoveCallback</code>.</p>
<p>Add this code to <code>OnEnable</code> method:</p>
<pre><code class="language-language-csharp">list.onCanRemoveCallback = (ReorderableList l) =&gt; {
	return l.count &gt; 1;
};
</code></pre>
<p>Now try deleting all elements from the list. You will see that if there's only one element the <strong>—</strong> button is disabled.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="addingawarning">Adding a warning</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>We don't really want to accidentally delete an item in our list. Using <code>onRemoveCallback</code> we can display a warning and make a user press <strong>Yes</strong> button if he really wants to delete an element.</p>
<pre><code class="language-language-csharp">list.onRemoveCallback = (ReorderableList l) =&gt; {
	if (EditorUtility.DisplayDialog(&quot;Warning!&quot;, 
    	&quot;Are you sure you want to delete the wave?&quot;, &quot;Yes&quot;, &quot;No&quot;)) {
		ReorderableList.defaultBehaviours.DoRemoveButton(l);
	}
};
</code></pre>
<p>Note how we used <code>ReorderableList.defaultBehaviours.DoRemoveButton</code> method here. <code>ReorderableList.defaultBehaviours</code> contains all default implementations for various functions which sometimes can be handy if you don't want to reinvent the wheel.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/warning.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="initializinganewlycreatedelement">Initializing a newly created element</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>What if we wanted to add a preconfigured element when a user presses <strong>+</strong> button instead of copying the last one in the list? We can intercept the logic of adding elements using <code>onAddCallback</code>.</p>
<p>Add the following code to <code>OnEnable</code> method:</p>
<pre><code class="language-language-csharp">list.onAddCallback = (ReorderableList l) =&gt; {
	var index = l.serializedProperty.arraySize;
	l.serializedProperty.arraySize++;
	l.index = index;
	var element = l.serializedProperty.GetArrayElementAtIndex(index);
	element.FindPropertyRelative(&quot;Type&quot;).enumValueIndex = 0;
	element.FindPropertyRelative(&quot;Count&quot;).intValue = 20;
	element.FindPropertyRelative(&quot;Prefab&quot;).objectReferenceValue = 
    		AssetDatabase.LoadAssetAtPath(&quot;Assets/Prefabs/Mobs/Cube.prefab&quot;, 
            typeof(GameObject)) as GameObject;
};
</code></pre>
<p>Here we are adding an empty wave to the end of the list and with the help of <code>element.FindPropertyRelative</code> method we are setting its properties to predefined values. In case of <code>Prefab</code> property we are looking for the specific prefab at path <code>Assets/Prefabs/Mobs/Cube.prefab</code>. Make sure that you created the folder structure accordingly.</p>
<p>Now return to Unity and try adding new elements to the list. You will see that new elements are always added as Cubes with Count equal to <em>20</em>.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="addingdropdownmenu">Adding drop-down menu</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>The last example will be the most interesting. We will make a dynamic drop-down menu activated by <strong>+</strong> button using <code>onAddDropdownCallback</code>.</p>
<p>In <code>Prefabs</code> folder we have 3 <em>mobs</em> and 3 <em>bosses</em>, so it would be natural to be able to add a specific one from a menu instead of manually dragging prefabs in the list.</p>
<p>Let's first add a new data type which we will later use in our menu system. Add this code at the end of the file before the last <strong>}</strong>.</p>
<pre><code class="language-language-csharp">private struct WaveCreationParams {
	public MobWave.WaveType Type;
	public string Path;
}
</code></pre>
<p>Next, define a callback which will be called by built-in Unity menu system. Right now it's empty but we'll fix this later. Add the following code after <code>OnInspectorGUI</code> method.</p>
<pre><code class="language-language-csharp">private void clickHandler(object target) {}
</code></pre>
<p>And now is the time to define our <code>onAddDropdownCallback</code>. Add this code in <code>OnEnable</code> method:</p>
<pre><code class="language-language-csharp">list.onAddDropdownCallback = (Rect buttonRect, ReorderableList l) =&gt; {
	var menu = new GenericMenu();
	var guids = AssetDatabase.FindAssets(&quot;&quot;, new[]{&quot;Assets/Prefabs/Mobs&quot;});
	foreach (var guid in guids) {
		var path = AssetDatabase.GUIDToAssetPath(guid);
		menu.AddItem(new GUIContent(&quot;Mobs/&quot; + Path.GetFileNameWithoutExtension(path)), 
        false, clickHandler, 
        new WaveCreationParams() {Type = MobWave.WaveType.Mobs, Path = path});
	}
	guids = AssetDatabase.FindAssets(&quot;&quot;, new[]{&quot;Assets/Prefabs/Bosses&quot;});
	foreach (var guid in guids) {
		var path = AssetDatabase.GUIDToAssetPath(guid);
		menu.AddItem(new GUIContent(&quot;Bosses/&quot; + Path.GetFileNameWithoutExtension(path)), 
        false, clickHandler, 
        new WaveCreationParams() {Type = MobWave.WaveType.Boss, Path = path});
	}
	menu.ShowAsContext();
};
</code></pre>
<p>Here we are building dynamic drop-down menu from the files in <em>Mobs</em> and <em>Bosses</em> folders, assigning instances of <code>WaveCreationParams</code> to them to be able to find out what menu element was clicked later in <code>clickHandler</code>.</p>
<p>If you set up your folder structure right and didn't forget to add <code>using System.IO;</code> in the beginning of the file, you can now return to Unity and try pressing <strong>+</strong> button (which is now <em>Plus More</em>) to see how it works.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/menu.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>Now all what's left is to add actual wave creation logic to <code>clickHandler</code>:</p>
<pre><code class="language-language-csharp">private void clickHandler(object target) {
	var data = (WaveCreationParams)target;
	var index = list.serializedProperty.arraySize;
	list.serializedProperty.arraySize++;
	list.index = index;
	var element = list.serializedProperty.GetArrayElementAtIndex(index);
	element.FindPropertyRelative(&quot;Type&quot;).enumValueIndex = (int)data.Type;
	element.FindPropertyRelative(&quot;Count&quot;).intValue = 
    	data.Type == MobWave.WaveType.Boss ? 1 : 20;
	element.FindPropertyRelative(&quot;Prefab&quot;).objectReferenceValue = 
    	AssetDatabase.LoadAssetAtPath(data.Path, typeof(GameObject)) as GameObject;
	serializedObject.ApplyModifiedProperties();
}
</code></pre>
<p>When a menu item is clicked this method is called with the <em>value object</em> we specified earlier. This <em>value object</em> containing in <code>data</code> variable is used to set up properties of the newly created wave. To assing the right <em>Prefab</em> to the wave we are using <code>AssetDatabase.LoadAssetAtPath(data.Path, typeof(GameObject))</code> method with the path we found in <code>onAddDropdownCallback</code>.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><!--kg-card-begin: markdown--><h2 id="inconclusion">In conclusion</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Of the all available callbacks we haven't touched only <code>onChangedCallback</code> and <code>onReorderCallback</code> because they are not really interesting. But you must know that they exist.</p>
<p>If you've been working with Unity for a long time you should know how hard it is to make a proper interface for a collection of things in Unity IDE. Especially when this wasn't in your time budget from the beginning. I've been using another implementation of <strong>ReorderableList</strong> by <a href="https://bitbucket.org/rotorz/reorderable-list-editor-field-for-unity">rotorz</a> for a while. But now when we have an implementation from Unity Team there's no excuse not to use it.</p>
<p>If you want to find out how this list is implemented you can use <a href="http://ilspy.net/">ILSpy</a> to decompile <strong>UnityEditor.dll</strong> which is <em>(thankfully)</em> not obfuscated or otherwise protected.</p>
<blockquote>
<p>May the pretty lists be with you!</p>
</blockquote>
<p>P.S. Alexei in comments proposed a solution to list item height problem which is described here: <a href="https://feedback.unity3d.com/suggestions/custom-element-size-in-reorderable-list">https://feedback.unity3d.com/suggestions/custom-element-size-in-reorderable-list</a><br>
Code: <a href="http://pastebin.com/WhfRgcdC">http://pastebin.com/WhfRgcdC</a></p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/fIbBorr---Imgur.gif" class="kg-image"></figure><!--kg-card-end: image-->]]></content:encoded></item><item><title><![CDATA[Interesting things in Unity 4.5 you probably didn't know about]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Well, as you all know Unity team has recently released <a href="http://unity3d.com/unity/whats-new">Unity version 4.5</a> which brought us (according to Unity's web site):</p>
<ul>
<li>Over 450 bug fixes,</li>
<li>OpenGL ES 3.0,</li>
<li>Shader workflow boost,</li>
<li>Smooth and natural 2D physics and</li>
<li>Sparse Textures.</li>
</ul>
<p>While <em>450 bugs fixed</em> sounds amazing, shaders compilation was</p>]]></description><link>https://va.lent.in/interesting-things-in-unity-4-5-you-probably-didnt-know-about/</link><guid isPermaLink="false">5dcbd39356953d7286f4d655</guid><dc:creator><![CDATA[Valentin Simonov]]></dc:creator><pubDate>Mon, 02 Jun 2014 08:57:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Well, as you all know Unity team has recently released <a href="http://unity3d.com/unity/whats-new">Unity version 4.5</a> which brought us (according to Unity's web site):</p>
<ul>
<li>Over 450 bug fixes,</li>
<li>OpenGL ES 3.0,</li>
<li>Shader workflow boost,</li>
<li>Smooth and natural 2D physics and</li>
<li>Sparse Textures.</li>
</ul>
<p>While <em>450 bugs fixed</em> sounds amazing, shaders compilation was indeed terribly slow, I don't really care about OpenGL ES 3.0 (since I got an old iPhone 4s) and <em>Sparse Textures</em> is a good feature to explore on modern desktop GPUs, what I want to tell you about are those features and bug fixes buried in the massive <a href="http://unity3d.com/unity/whats-new/unity-4.5">Release Notes</a> which you have probably missed but they are indeed very important.</p>
<p><em>In no particular order.</em></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="hierarchywindowsorting">Hierarchy Window sorting</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><blockquote>
<p>New Hierarchy Window sorting - sorting of elements is now based on transform order instead of name.</p>
</blockquote>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/sorting.gif" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>This change alone breaks the naming convention of millions of developers. I myself used to name the empty object with controllers <strong>$</strong> to make sure that it's always on the top of <em>Hierarchy Panel</em>. Now you can just drag <em>GameObjects</em> up and down manually.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="selectionbaseattribute">SelectionBase attribute</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><blockquote>
<p>Editor: Created SelectionBase attribute. When applied to a script, GameObjects with that script on will work the same as prefab roots for Scene View picking.</p>
</blockquote>
<p>If you have an hierarchy of objects with geometry attached usually when you click one of them it gets selected.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/select_child.gif" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>If you remember <strong>Prefabs</strong> behave differently. If you click an object in prefab's hierarchy the root of this prefab is be selected instead. And now you can manually force this behavior using <strong>SelectionBase</strong> attribute.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/select_child2.gif" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><pre><code class="language-language-csharp">[SelectionBase]
public class TheBase : MonoBehaviour {}
</code></pre>
<p>This may be useful when you think of an hierarchy of objects as single object and don't want to control its child objects. For example you have an object and a plane inside and it's important to move this root object instead of its child plane. This feature might help you always select the right object.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="decoratordrawers">DecoratorDrawers</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><blockquote>
<p>Editor: PropertyDrawers are now supplemented with DecoratorDrawers, which can be used for decorative elements in the Inspector such as spacing, headers, or notes.<br>
Editor: Improved inspector customisation with [Tooltip] and [ContextMenuItem] script attributes.</p>
</blockquote>
<p><a href="http://docs.unity3d.com/ScriptReference/PropertyDrawer.html">PropertyDrawers</a> are used to make your fields more pretty in the Editor. They are extremely easy to use. For example using just one <em>annotation</em> you can convert a float field into a smart range property.</p>
<pre><code class="language-language-csharp">[Range(0, 100)]
public float MyValue;
</code></pre>
<p>While <em>PropertyDrawers</em> modify the appearence of fields in the Editor, new <em>DecoratorDrawers</em> augment them with visual elements. Check out this code:</p>
<pre><code class="language-language-csharp">[Header(&quot;Hi there!&quot;)]
public string TheHeader = &quot;Header!&quot;;
[Tooltip(&quot;This is THE VALUE!&quot;)]
[ContextMenuItem(&quot;Reset&quot;, &quot;resetTheValue&quot;)]
public float TheValue = 42.0f;
[Space(50)]
public string TheString = &quot;THE STRING&quot;;

private void resetTheValue()
{
    TheValue = 42;
}
</code></pre>
<p>And the animation where you can see what these <em>annotations</em> do.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/decorators.gif" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>Just a little trick to make your Editor interfaces better.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="scriptsindlls">Scripts in DLLs</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><blockquote>
<p>Scripting: Improved resolution of types that inherit from types in different user assemblies.</p>
</blockquote>
<p>This is probably one of my favorites.</p>
<p>You see, prior to <em>4.5</em> if you had <code>MyBaseClass : MonoBehaviour</code> in <strong>MyBaseClass.dll</strong> and <code>MyDerivedClass : MyBaseClass</code> in <strong>MyDerivedClass.dll</strong> you couldn't use <em>MyDerivedClass</em> in your projects because <em>Unity</em> was unable to follow this <em>MASSIVE</em> inheritance chain and figure out that <em>MyDerivedClass</em> was a <em>MonoBehaviour</em>.</p>
<p>Thanks God this is now fixed.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="defaultparameters">Default parameters</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><blockquote>
<p>Scripting: Fixed namespace detection for MonoBehaviors containing methods with default parameters.</p>
</blockquote>
<p>This bug was one of those bugs stopping people from using specific language features. Now we can breath freely.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="savingtojpeg">Saving to JPEG</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><blockquote>
<p>Graphics: Added Texture2D.EncodeToJPG.</p>
</blockquote>
<p>Many developers have been asking for a function to save to JPEG. Yes we had <a href="http://docs.unity3d.com/ScriptReference/Texture2D.EncodeToPNG.html">Texture2D.EncodeToPNG</a> for a long time, but you know...</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/jpg_vs_png.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>Anyway, the new method is also terribly slow. Encoding a 2048x2048 texture:</p>
<ul>
<li>Encoded to PNG in 0.4529677 seconds,</li>
<li>Encoded to JPG in 0.1349338 seconds.</li>
</ul>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="nowweknowifwehaveprolicense">Now we know if we have Pro license</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><blockquote>
<p>Scripting: Added UNITY_PRO_LICENSE define.</p>
</blockquote>
<p>This will be useful for fellow plugin developers. Now we have an easy way to be sure that code we are writing targets right Editor version.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="serialization">Serialization</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><blockquote>
<p>Scripting: Add UnityEngine.ISerializationCallbackReceiver interface, to get a callback right before serialisation and right after deserialization.<br>
Scripting: Structs with System.Serializable attribute can now be serialized. Also, fields of AnimationCurve[] and double[] now get serialised.</p>
</blockquote>
<p>People have been asking for years for the ability to serialize <em>structs</em>. Now this code works and shows a list of structs:</p>
<pre><code class="language-language-csharp">public List&lt;MyStruct&gt; list = new List&lt;MyStruct&gt;();

[Serializable]
public struct MyStruct
{
    public int Value;
}
</code></pre>
<p>Being able to serialize arrays of <em>AnimationCurve</em> sometimes may be handy too.</p>
<p>But what really interesting is <a href="http://docs.unity3d.com/ScriptReference/ISerializationCallbackReceiver.html">ISerializationCallbackReceiver</a> interface. The docs say:</p>
<blockquote>
<p><em>Interface to receive callbacks upon serialization and deserialization.</em></p>
</blockquote>
<p>It seems that instead of wasting man-years on figuring out how to serialize <em>Dictionaries</em> they gave us an ability to manually specify what and how we want to be serialized. <a href="http://docs.unity3d.com/ScriptReference/ISerializationCallbackReceiver.OnBeforeSerialize.html">The example</a> in the docs shows just that.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="gameobjectgetcomponentsinparent">GameObject.GetComponentsInParent()</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><blockquote>
<p>Scripting: Added GetComponentsInParent function.</p>
</blockquote>
<p>It's good to know that now we have <a href="http://docs.unity3d.com/ScriptReference/GameObject.GetComponentsInParent.html">this</a>. I haven't tested it yet but it must be a lot faster than enumerating manually through the parent chain.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="debuggingdirectx11shaders">Debugging DirectX 11 shaders</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><blockquote>
<p>Documentation: Added docs on how to debug DirectX11 shaders with Visual Studio, look for 'SL-Debugging DirectX 11 Shaders with Visual Studio'.</p>
</blockquote>
<p>The method described is not new but now we got <a href="http://docs.unity3d.com/Manual/SL-DebuggingD3D11ShadersWithVS.html">a decent tutorial on how to debug dx11 shaders in Unity</a>.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="windowsphoneapps">Windows Phone apps</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>I understand that nobody gives a damn about WP apps but I had to develop a couple simple ones for <em>Nokia Lumia</em> and I'm glad that <em>Unity</em> is evolving and I hope that it will be able to make this platform better.</p>
<p>There are a lot of added features and fixed bugs for <em>Windows Phone</em> target and it's good to know that I helped fixing some of them:</p>
<blockquote>
<p>Start, Update and similar methods in scripts derived from generic base class are now properly invoked.<br>
WP: Resolution will now be correctly detected on phones than have larger screen than 768x1280.<br>
WP: Screen.dpi now returns physical device DPI, rather than 0.</p>
</blockquote>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="oo">o.O</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><blockquote>
<p>Active scenes count properly displayed when more than 100 scenes are added to Build Settings window.</p>
</blockquote>
<p>Damn, some people have huge projects...</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="nicelists">Nice lists</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>And the last one is not even in the <em>Release Notes</em>. It's a little Editor class hiding in <code>UnityEditorInternal</code> namespace. It's called <code>ReorderableList</code> and it makes drawing lists in custom inspectors such an easy task. If you ever tried to make a pretty inspector for a <em>List&lt;&gt;</em> or <em>Array</em> field in <em>Unity</em> you know what a massive pain it is.</p>
<p>Here's a demo of <em>ReorderableList</em> class:</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/list.gif" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>This is the code from the custom inspector used:</p>
<pre><code class="language-language-csharp">private ReorderableList list;

list = new ReorderableList(property.serializedObject, property.FindPropertyRelative(&quot;tagList&quot;), true, true, true, true);
list.drawHeaderCallback += rect =&gt; GUI.Label(rect, label);
list.drawElementCallback += (rect, index, active, focused) =&gt;
{
    rect.height = 16;
    rect.y += 2;
    EditorGUI.PropertyField(rect, 
        list.serializedProperty.GetArrayElementAtIndex(index), 
        GUIContent.none);
};

list.DoList(position);
</code></pre>
<p>This is the full example: <a href="https://github.com/TouchScript/TouchScript/blob/master/TouchScript.Editor/TouchManagerEditor.cs">TouchManagerEditor.cs</a></p>
<p>Interesting fact: there was already practically identical list implementation called <a href="https://bitbucket.org/rotorz/reorderable-list-editor-field-for-unity">ReorderableList</a> which I've been using from time to time.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id>***</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>These are the features I found particularly interesting while browsing through <em>Unity 4.5 Release Notes</em>. It's always like a treasure hunt... you  never know what you will find.</p>
<p>If for some reason you think that some other features/fixes deserve more attention feel free to post them in comments.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Prolog for Mac]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Let's assume that you need to set up <a href="http://en.wikipedia.org/wiki/Prolog">Prolog</a> for OS X. If you are still here let's continue.</p>
<p>After reading some book from 80s about Prolog I found that language to be interesting and I decided to write some simple things in it. But I had to install it</p>]]></description><link>https://va.lent.in/prolog-for-mac/</link><guid isPermaLink="false">5dcbda8056953d7286f4d70d</guid><dc:creator><![CDATA[Valentin Simonov]]></dc:creator><pubDate>Sun, 09 Mar 2014 09:27:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Let's assume that you need to set up <a href="http://en.wikipedia.org/wiki/Prolog">Prolog</a> for OS X. If you are still here let's continue.</p>
<p>After reading some book from 80s about Prolog I found that language to be interesting and I decided to write some simple things in it. But I had to install it somehow on my Mac preferably without any stupid virtual machines. So here's what I ended with.</p>
<ul>
<li>All crossplatform solutions are based on <a href="http://eclipse.org/">Eclipse</a>, so first of all you need Eclipse. There are a lot of versions, but I chose the one with less stuff I don't need because I won't use anything related to Java development.</li>
<li>The first plugin I tested was <a href="http://roots.iai.uni-bonn.de/research/pdt/download">PDT</a> which is too old and doesn't work with Eclipse 3.5, I downloaded 3.1 but haven't tested it because I got another plugin which works — <a href="http://prodevtools.sourceforge.net/index.html">ProDT</a>. This is just what I need. From Downloads you should choose the smallest file.</li>
<li>For ProDT to work you need <a href="http://www.swi-prolog.org/download/stable">SWI-Prolog</a> — some kind of opensource Prolog.</li>
<li>I'm not sure if SWI-Prolog requires <a href="http://www.macports.org/">MacPorts</a>, but anyway I recommend you to install it. It's useful.</li>
<li>Extract ProDT to eclipse/dropins/prodt/eclipse/plugins, run eclipse which installs it automatically.</li>
<li>After that in ProDT preferences (<em>Eclipse -&gt; Preferences -&gt; Prolog -&gt; Compilers -&gt; Swi Compiler</em>) set compiler path which is at <code>/opt/local/bin/swipl.</code></li>
<li>Switch to Prolog view <em>Window -&gt; Show Perspective -&gt; Other... -&gt; Prolog</em>.</li>
</ul>
<p>That's it. Now you can test if it actually works:</p>
<pre><code>yes(one).
yes(two).
</code></pre>
<p>Run and write in console:</p>
<pre><code>yes(X).
x = one;
x = two.
</code></pre>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Should you use Playmaker in production?]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>So, should you use Playmaker in production? Short answer is:</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/ShockingSardonicDalmatian.gif" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>Long answer follows.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="playmaker">Playmaker</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p><a href="http://www.hutonggames.com/">Playmaker</a> is a visual scripting tool for Unity. It has been a top-selling asset in the Asset Store for a couple of years.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/playmaker.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><h1 id="learningenvironment">Learning environment</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>I get invited to host Unity workshops from time to time.</p>]]></description><link>https://va.lent.in/should-you-use-playmaker-in-production/</link><guid isPermaLink="false">5dcbd63f56953d7286f4d6b7</guid><dc:creator><![CDATA[Valentin Simonov]]></dc:creator><pubDate>Sun, 09 Mar 2014 09:09:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>So, should you use Playmaker in production? Short answer is:</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/ShockingSardonicDalmatian.gif" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>Long answer follows.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="playmaker">Playmaker</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p><a href="http://www.hutonggames.com/">Playmaker</a> is a visual scripting tool for Unity. It has been a top-selling asset in the Asset Store for a couple of years.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/playmaker.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><h1 id="learningenvironment">Learning environment</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>I get invited to host Unity workshops from time to time. One of these workshops consisted of 6 lessons and the audience didn't know anything about programming. That's where I finally decided to try to build an entire game using Playmaker.</p>
<p>The game was really small with Unity physics doing most of the work, but anyway many small scripts to handle interactivity were needed. And here Playmaker worked really great.</p>
<blockquote>
<p>The concept of states and actions appears to be very intuitive, so even people with near to no programming experience could &quot;script&quot; simple interactions very fast.</p>
</blockquote>
<p>So, for teaching Unity I will definitely use Playmaker again.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="statemachines">State machines</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Well, I'm a huge fan of state machines. I usually structure my code so I know exactly in which states all the modules of my application are. And every action is controlled from top to bottom in a hierarchy of simple state machines. This apporach keeps the code very simple and easy to follow and debug.</p>
<p>It seemed that Playmaker being a visual state machine framework would fit fine in my pipeline. But, oh God, how I was wrong.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="codeoopandsoftwarearchitecture">Code, OOP and software architecture</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><blockquote>
<p>If you are an experienced software engineer you know how important it is to structure your code right.</p>
</blockquote>
<p>We all remember those days spent trying to debug a spaghetti mess of interlinked code promising to God to never be so lazy again if he helps us find why this monstrosity doesn't work.</p>
<p>Sooner or later you inevitably come to a set of good practices of software architecture and code structuring. If you do everything right and use a good IDE like Visual Studio which allows you to easily browse code and jump to lines where a function is defined or called, it's really easy to follow what's going on in your code and usually is not hard to figure out why something is not working.</p>
<p>The critical features here are:</p>
<ul>
<li>Ability to see where methods are called from,</li>
<li>Transparent control hierarchy (i.e. a chain of command with no global events or variables),</li>
<li>Right encapsulation with no external state exposed.</li>
</ul>
<blockquote>
<p>Playmaker violates all these statemens and adds even more ugly stuff.</p>
</blockquote>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="playmakerinproduction">Playmaker in production</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Now I'm going to list all the problems I found in Playmaker I could remember while working on a real project. In no particular order.</p>
<p>If you know a good workaround for any of these problems feel free to post them in comments at the end of the article.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="1playmakerbreaksencapsulation">1. Playmaker breaks encapsulation</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><blockquote>
<p>If you don't want to shoot yourself in a foot you absolutely shouldn't expose object's internal state to the world.</p>
</blockquote>
<p>Well, Playmaker does just that. It completely breaks encapsulation.</p>
<p>Most likely you would have a script on the same object with Playmaker FSM which exposes API to control the object. This script does some work and makes the FSM to change state. It's a normal behavior but here you have <strong>state</strong> moved outside of the object, visible to everyone, state which can be modified by anything any time.</p>
<p>Even if you are an experieced developer and you understand possible consequences of this decision, believe me, you WILL be tempted to do the wrong thing and modify this state bypassing proper API calls. <strong>Young programmers will do this immediately if you give them any chance at all.</strong></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="2playmakermakesitimpossibletoseecontrolflow">2. Playmaker makes it impossible to see control flow</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Any action in any state can call any method or change a local or global variable. There's no way to find out what changes what except going through every state and every action by hand.</p>
<p>There's no <code>Find Usages</code> or <code>Go to Definition</code> like in any good IDE, <strong>if someone decides to bypass the API (and they will) you will have a very hard time trying to find out what really is happening there.</strong></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="3playmakerisincompatiblewithgit">3. Playmaker is incompatible with git</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Seriously, we had so much pain in the ass because of how Playmaker saves its graphs into Unity scene. <strong>It seems that it does this the most unmergeable way possible</strong>. And you don't even know that something was damaged during a merge right away. Beleive me or not it was happening a lot even if someone just moved some states around to make them look better...</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="4playmakermakesscriptsmorecomplicated">4. Playmaker makes scripts more complicated</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Playmaker was created to make coding simpler, right? Not really.</p>
<blockquote>
<p>Playmaker makes <em>small</em> &quot;code&quot; simpler to write but <em>large</em> complicated code becomes a complete mess.</p>
</blockquote>
<p>This is actually a problem of all visual languages. Believe me, I worked a lot with visual scripting environments.</p>
<p>In a visual language you connect nodes which do simple tasks, like adding two numbers or calling a method. And there's a threshold where you have to delete all your &quot;visual&quot; code and reimplement this logic as a <strong>node</strong> or an <strong>action</strong> in Playmaker terminology. Because visual &quot;code&quot; becomes too complicated very quickly.</p>
<p>Sooner or later you'll end up with this.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="https://va.lent.in/content/images/2019/11/max2.jpg" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>Which is <strong>MUCH</strong> harder to follow than code.</p>
<p>Of course, you can develop common practices to try to fix this mess. Like, having one action with major logic per state or design your action in some modular fashion. But you can't get rid of this problem completely especially when you have a set of actions which you probably can combine into a Frankenstein's monster to do what you want. <strong>Because the cost of making a new action (multiplied by laziness) is higher.</strong></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="41passingdata">4.1 Passing data</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Unlike <a href="http://en.wikipedia.org/wiki/Dataflow_programming">dataflow visual languages</a> where you pass modified data around, to pass something from one action to another you have to use variables. Which is <strong>(a)</strong> another huge layer of complexity and <strong>(b)</strong> makes one more huge hole in encapsulation.</p>
<p>So, instead of doing <code>action2(action1(&quot;hi&quot;));</code> in code you have to <strong>(a)</strong> add one or more variables, <strong>(b)</strong> add variable support to both actions, <strong>(c)</strong> configure to use same variables on both instances of these actions. <strong>Which is adding a lot of unnecessary complexity.</strong></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="42eventsonstatechange">4.2 Events on state change</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>It's surprising, but there's no way for a script to be notified when a FSM changes state. If you want to sync a FSM's state with something else you will have to put a special action in every state yourself. Which makes states even bigger.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="5playmakerusesglobalvariablesandevents">5. Playmaker uses global variables and events</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>You probably know or at least heard that global variables and global events are evil. Usually it's wrong to say that something is 100% bad or 100% good because world is not black and white. There are ways to use global variables/singletons and global events/messages without driving yourself crazy.</p>
<blockquote>
<p>But how global events and global variables are implemented in Playmaker is the same as giving you a loaded machine gun and aiming it to your foot.</p>
</blockquote>
<p>Anything can dispatch an event or change a global variable, and any other object can react to this. And due to <strong>(2)</strong> you have no way of debugging this.</p>
<p>And because Playmaker encourages you to use global events and global variables, even if you are aware of the consequences, sooner or later you will start using them. <strong>And you'll regret about this decision at the end...</strong></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="6playmakermakesstatemachinesexcessivelycomplicated">6. Playmaker makes state machines excessively complicated</h2>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>This one might be my personal choice, but anyway these are my personal thoughts so I ought to list it too.</p>
<blockquote>
<p>There are several ways to implement a state machine. Different implementations might be called a <a href="http://en.wikipedia.org/wiki/Mealy_machine">Mealy machine</a>, or a <a href="http://en.wikipedia.org/wiki/Moore_machine">Moore machine</a>, or another way to combine current state and current input into action.</p>
</blockquote>
<p><strong>The thing is that Playmaker forces you to have all the logic in states.</strong> So, to execute something you have to change state. This gets even more complicated considering the <code>execute in every frame</code> flag which many actions have. Because in current system it's either a transition from a state to itself (while during this transition not all the actions get executed) or a piece of logic which executes without a transition. Both of these options break the execution model Playmaker offers.</p>
<p>What's more, if you want to add a constant logic for an event which behaves the same in most of the states you will have to add this logic to all states in Playmaker.</p>
<p>I think you can use several FSMs to deal with this problem but having several FSMs just adds even more complexity.</p>
<p>Another model (which I use in my code) would be to use states as filters what to do with incoming events. In this case you need much less states and all your event handlers will look like this:</p>
<pre><code>private void EventHandler() {
	switch (currentState) {
    	case State.One:
    		// ignore
    		break;
    	case State.Two:
    		doSomeStuff();
    		break;
    	case State.Three:
    		doOtherStuff();
    		break;
	}
}
</code></pre>
<p>I don't have to change states when I want to execute some logic in response to an event. Also, I'm absolutely sure that this event will have no effect if current state is <code>State.One</code>.</p>
<p>Of course, you can have some logic executed right when state changes. Anyway, this abstraction of state machines allows to have less states and is easy to read in code.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="goodstuff">Good stuff</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>But there are some good points. When I was trying to list good sides of Playmaker I came up only with two:</p>
<ol>
<li>Visual representation of states and transitions,</li>
<li>Usually it's easy to see what is being done in a state.</li>
</ol>
<p>I am an experienced software engineer and I can keep in mind most of the nested graphs of state machines in my app. But it's always better to have a visual representation.</p>
<blockquote>
<p>One of my less experienced colleague told me that he really liked working with Playmaker, because he was able to see actual state graphs.</p>
</blockquote>
<p>Of course, guess who was in charge of fixing all the mess Playmaker introduced with these shiny graphs... But he has a point. Visualizing control flow and state graphs does help.</p>
<p>As for individual states, <strong>if you structure and name all the actions right</strong> it's really easier to read what's going on in the state comparing to reading a bunch of unrelated methods in source code. But as I noticed this type of &quot;coding&quot; actively uses another part of your brain and keeps wasting brain power on how &quot;code&quot; looks instead of focusing on how it works.</p>
<p>Not that it's a completely bad thing but it easily drives you from what you need to do into some sort of &quot;playing with fonts&quot; procrastination.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="conclusion">Conclusion</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>First of all, I will never use Playmaker in my app again.</p>
<p>Second, there might be a better paradigm and a better way to use a visual state machine in Unity. The one which doesn't have all the flaws Playmaker has.</p>
<p>This is just another field for me to explore.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[You don't have Flash MX player installed!]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>While making screenshots of old flash sites for <a href="http://thefwa.com/">TheFWA</a> new site I noticed that a lot of them fail to start because of wrong flash player detection. They tell me that I do not have Flash MX player. Of course damn it I don't! Today is almost 2010 and flash</p>]]></description><link>https://va.lent.in/you-dont-have-flash-mx-player-installed/</link><guid isPermaLink="false">5dcbe2f256953d7286f4d715</guid><dc:creator><![CDATA[Valentin Simonov]]></dc:creator><pubDate>Tue, 18 Feb 2014 10:03:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>While making screenshots of old flash sites for <a href="http://thefwa.com/">TheFWA</a> new site I noticed that a lot of them fail to start because of wrong flash player detection. They tell me that I do not have Flash MX player. Of course damn it I don't! Today is almost 2010 and flash player 10 rules the world. I decompiled one of flash detection SWFs and here we go:</p>
<pre><code>if (getVersion().charAt(4) &gt;= 6)
</code></pre>
<p>Do you see the problem here? Today all these SWFs think that I got flash player version 1 which is obviously too old to view the site.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[The importance of reading blogs and attending conferences]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>I just started watching recorded sessions of Flex|360 and Adobe MAX 2008/2009. And it is fantastic how I see people dealing with same problems I was dealing last year and earlier this year. If only I have watched these videos earlier or attended these conferences... This could have</p>]]></description><link>https://va.lent.in/the-importance-of-reading-blogs-and-attending-conferences/</link><guid isPermaLink="false">5dcbe35656953d7286f4d71d</guid><dc:creator><![CDATA[Valentin Simonov]]></dc:creator><pubDate>Sun, 01 Dec 2013 10:04:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>I just started watching recorded sessions of Flex|360 and Adobe MAX 2008/2009. And it is fantastic how I see people dealing with same problems I was dealing last year and earlier this year. If only I have watched these videos earlier or attended these conferences... This could have saved me a lot of time. Yes, I found my own solutions, better or worse, but that was reinventing the wheel once again.</p>
<p>I am an active blogger and read a lot of blog posts on a daily basis. But nobody can read or know everything. Yet a lot of people simultaneously from opposite sides of the world are trying to solve same problems and come up with same brilliant ideas. They just don't know about each other...</p>
<p>That's why it is vitally important to be social. Internet is a great tool we must use. You should read blogs, you should watch recorded sessions from conferences you can't attend. You may not have a personal blog but you must be hungry for new information. I don't care if others find reading blogs a waste of time. Most of them are narrow minded people living in their own sandbox.</p>
<p>You must live on the edge of knowledge in your field, you must know what was done, what obstacles people faced in their projects. Learn on someone else's mistakes.</p>
<p>What's more, reading an article about something you found interesting but is not relevant right now is definitely not a waste of time. If you have a team of people who are information sponges you can do anything in a much more productive way. Any problem during development will be solved much faster, every decision will have much more probability to be right, because someone have read about another team facing same problem or that people say how bad that architecture rendered to be at the end. Someone might have attended a conference where he heard of an interesting framework which is ideal for your current needs.</p>
<p>You might have memorized only 3% of the whole article read or video watched, but you already know about the existence of a solution you might desperately need right now. You'll spend a couple of hours googling instead of weeks of development.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="conclusion">Conclusion</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>I like reading technical books. Last books I read were about human genome, swarm intelligence, artificial intelligence, loosing weight, prolog, plants and branching structures. They don't have much relation to what I am doing right now, I am just hungry for interesting stuff...</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Null, undefined and NaN]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>A newbie in ActionScript3 might wonder why there are 3 different values which mean &quot;nothing&quot;. I'll try to explain the difference.</p>
<p>Something is <strong>null</strong> when it points to nothing. If you remember that by saying</p>
<pre><code>var p: Point = new Point();
</code></pre>
<p>we create a reference (pointer) <code>p</code> to a</p>]]></description><link>https://va.lent.in/null-undefined-and-nan/</link><guid isPermaLink="false">5dcbe3c756953d7286f4d729</guid><dc:creator><![CDATA[Valentin Simonov]]></dc:creator><pubDate>Wed, 16 Oct 2013 10:06:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>A newbie in ActionScript3 might wonder why there are 3 different values which mean &quot;nothing&quot;. I'll try to explain the difference.</p>
<p>Something is <strong>null</strong> when it points to nothing. If you remember that by saying</p>
<pre><code>var p: Point = new Point();
</code></pre>
<p>we create a reference (pointer) <code>p</code> to a position in memory which has the created <code>Point</code> object. This pointer is typed so can reference only objects of type Point. If we write</p>
<pre><code>p = 42 as Point;
</code></pre>
<p>flash can't convert 42 to <code>Point</code> so <code>p</code> just points to nothing in memory thus it is <strong>null</strong>.</p>
<p>If we write something like</p>
<pre><code>var i:int = (new Point()) as int;
</code></pre>
<p><strong>i</strong> will be 0 because int variable is of so-called simple type and contains its value not points to some memory space.</p>
<p>But what about <strong>undefined</strong>? Remember that in ActionScript we can have dynamic classes and untyped variables. For example this is an untyped variable definition:</p>
<pre><code>var untyped: *;
</code></pre>
<p>While it's not set it is <strong>undefined</strong> because it neither points to anything nor it contains a simple value. It is just not defined yet. All typed variables have default values which is usually <strong>null</strong>. Also we get <strong>undefined</strong> when referencing a non-existing property of a dynamic object.</p>
<pre><code>trace({}.x); // empty Object
trace([][1]); // empty Array
</code></pre>
<p>both will trace <strong>undefined</strong>. This is quite interesting, because here if you don't understand the difference between null and undefined you can get unusual results. Let's check an example.</p>
<pre><code>var o: Object = {x: null};
trace(o.x);
trace(!o.x);
trace(o.y);
trace(!o.y);
</code></pre>
<p>This will output:</p>
<p>null<br>
true<br>
undefined<br>
true</p>
<p><strong>x</strong> property exists in object <strong>o</strong> but it points to nothing, but <strong>y</strong> property doesn't exist at all. If you test something for existence using this approach you are missing the point. You should use === instead, because</p>
<pre><code>null == undefined; // true
null === undefined; // false
</code></pre>
<p>Now what is <strong>NaN</strong>. NaN states for Not a Number. It's a value which a variable of type Number can hold meaning that it holds something which is not a number. This is how you can get NaN:</p>
<pre><code>Number(&quot;hello&quot;);
0/0;
Math.sqrt(-1);
</code></pre>
<p>The only way you can check if your variable holds <strong>NaN</strong> is <code>isNaN()</code> global function. You can't say</p>
<pre><code>something == NaN;
</code></pre>
<p>because comparing to NaN always results in false. Even</p>
<pre><code>NaN == NaN
</code></pre>
<p>is false.</p>
<p>There's another value for Numbers you should know — <strong>Infinity</strong>. You can get it if you divide something by 0.</p>
<p>OK, let's do our final test.</p>
<pre><code>private var undef: *;

trace({}.x); // undefined
trace(undef); // undefined
trace([][1]); // undefined
trace(Number(&quot;hello&quot;)); // NaN
trace(0/0); // NaN
trace(Math.sqrt(-1)); // NaN
trace(1/0); // Infinity
trace(NaN == undefined); // false
trace(NaN === undefined); // false
trace(null == undefined); // true
trace(null === undefined); // false
trace(NaN == NaN); // false
trace(NaN === NaN); // false
trace(null == null); // true
trace(null === null); // true
trace(undefined == undefined); // true
trace(undefined === undefined); // true
</code></pre>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[So, how do teams work on a big Unity3D project?]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p><strong>Update:</strong> <em>some of the videos are no longer available, I found some of them on YouTube and added slides. If you know where these videos are now please post in comments.</em></p>
<p>Unity3D is great for indie developers. We have yet to build a large Unity project, but we’ve built</p>]]></description><link>https://va.lent.in/so-how-do-teams-work-on-a-big-unity3d-project/</link><guid isPermaLink="false">5dcbe4ff56953d7286f4d735</guid><dc:creator><![CDATA[Valentin Simonov]]></dc:creator><pubDate>Sun, 15 Jan 2012 10:11:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p><strong>Update:</strong> <em>some of the videos are no longer available, I found some of them on YouTube and added slides. If you know where these videos are now please post in comments.</em></p>
<p>Unity3D is great for indie developers. We have yet to build a large Unity project, but we’ve built a couple of <a href="http://vimeo.com/33590185">small</a> <a href="http://vimeo.com/30006025">projects</a> so far but during this process we did see Unity3D from the ugly side. It seems that the engine can do some things blazingly fast and easy but some other ones were clearly neglected during development. But that’s another post.</p>
<p>So, <a href="http://answers.unity3d.com/questions/186421/how-do-teams-work-on-projects.html">I’ve tried</a> to find out how big teams work on large Unity projects if even we are struggling. But no luck.</p>
<p>Ones were mumbling about source control, separating control over scenes editing etc. That’s kind of obvious and shows that those people don’t have any experience at all.</p>
<p>But recently I watched <a href="http://www.youtube.com/playlist?list=PLX2vGYjWbI0Q7HYmCTbZyMOTmb4R9RYrf">all the videos from Unite 11 conference</a>. I really wish I could visit it and talk to Unity gurus. But anyway, here are the videos I found useful. Videos where speakers share their experience on working in Unity3D as a team. The information which is practical and useful:</p>
<p><strong>Unite 11: Scalable Game Development at Schell Games <a href="http://unite.schellgames.com/">(PPT)</a></strong></p>
<ol>
<li>Unity tends to crash building a large project. That’s why <strong>they split the game into several projects</strong>: entry point project, assets projects, code project.</li>
<li>Entry point project is simple, contains minimum stuff to show loading screen or error screen. Loads asset bundles from asset projects and DLLs from code projects.</li>
<li>Content projects got their copy of DLLs, they are used to export assets to bundles and there are external tools to rebuild assets.</li>
<li><strong>There’s no single source file in Unity projects.</strong></li>
<li>That allows to build custom framework, use namespaces, custom compiler preprocessor and obfuscator (if needed).</li>
<li>But <strong>there are problems</strong> with this approach like some deeply derived from MonoBehavior classes not showing in Unity3D IDE, harder to debug, etc.</li>
<li><strong>#if preprocessor instructions</strong> are used to exclude platform specific code.</li>
<li>Custom GUI with relative sizing and positioning of controls. Saved and loaded using ScriptableObjects.</li>
<li>A lot of external data handled by ScriptableObjects which are serializable, editable like Behaviors and not tied to a GameObject.</li>
</ol>
<p><strong><a href="http://www.youtube.com/watch?v=i9z_-d3C2R4">Unite 11: Postmortem – Smuggle Truck</a></strong></p>
<ol>
<li><strong>ONE</strong> project to build for all platforms. I think the project is not large, so they don’t see Unity crash much.</li>
<li>There’s a <strong>Level Editor</strong> which was used by players to create levels which actually shipped with the release.</li>
<li><strong>Asset Settings tool</strong> to configure assets importing parameters for every platform. For example, background textures could be half-size in iPhone builds to increase performance.</li>
<li><strong>Platform Specific</strong> properties can be configured with special 1. Behaviors attached to objects. For example, you could specify object’s size depending on whether the project is compiled for iOS or PC.</li>
<li>Custom build process allows them to use the data from 3 and 4 to set needed properties and delete unused assets before the actual build. This ensures that assets from PC build will not go to iOS build increasing its size.</li>
<li>At the end of the presentation they advised to have 2 copies of the project for different build targets if you have a lot of assets. Because converting from PC formats to iOS formats takes a lot of time.</li>
</ol>
<p><strong>Update</strong>: recently they released <a href="http://smuggletruck.com/multiplatform/">Multiplatform Toolkit</a> to the Asset Store.</p>
<p><strong><a href="http://www.youtube.com/watch?v=ndt1crp9i7M">Unite 11: Jagged Alliance Online Engineering for Large Web Player Game</a></strong></p>
<ol>
<li>Large games have different problems: automatic builds, light map baking which takes 4 days to complete.</li>
<li>Big monolithic project fails to build. (heh, been there done that)</li>
<li>The project is split in <strong>SEVERAL</strong> small projects: code libraries, asset project(s). This approach allows to share code between client and server. Unity3D .NET project uses 3.5 and can be referenced from 4.0 server code. Asset projects are compiled into assets bundles to be use with code.</li>
<li>Programmers don’t spend an hour a day waiting for assets to be imported.</li>
<li>Code projects are <strong>separate Visual Studio</strong> solutions kept outside of Unity3D Assets folder. It allows using namespaces (not for MonoBehaviors though). Also they use Unit Tests with modified SharpUnit framework. There are problems with built-in Unity3D classes.</li>
<li>Shared code between code projects and assets projects are separated in yet another project which is referenced by them as DLL libraries.</li>
<li>Separate VS projects are configured to build DLLs into Temp folder not to be loaded by Unity3D and causing names conflict with existing source files.</li>
<li>There’s an advanced automatic build system which executes light map baking and asset bundles exporting in parallel reducing average build time.</li>
</ol>
<p><strong><a href="http://www.youtube.com/watch?v=YOY0YD75z3Q">Unite 11: Creating a Browser-ready FPS MMO in Unity</a> <a href="http://www.slideshare.net/amiltondiesel/creating-a-browser-ready-fps-mmo-in-unity-pptmewfinal">Slides</a></strong></p>
<ol>
<li>Yet again, nobody uses built-in Unity GUI system.</li>
<li>The game looks really cool q:</li>
<li>There’s a custom interface to build asset bundles.</li>
<li>They use <strong>ScriptableObjects</strong> which are saved to XML and later loaded from server.</li>
<li><strong>Tools for artists is a key to success</strong>.</li>
</ol>
<p><strong><a href="https://www.youtube.com/watch?v=6dnQX0ChOsA">Unite 11: Intro to Editor Scripting</a></strong>, <strong><a href="http://www.youtube.com/watch?v=itkm-emb5tg">Unite 12: Advanced Editor Scripting</a></strong>, <strong><a href="http://www.youtube.com/watch?v=t-wShOv8c1E">Unite 13: Advanced Editor Scripting</a></strong> — totally must see if you want to create your own editor tools. Describes how to create custom Behaviors inspectors, drawing dummies in 3D scene and even creating custom editor windows.</p>
<p><strong>Unite 11: SHADOWGUN: Rendering Techniques and Optimization Challenges <a href="http://blogs.unity3d.com/wp-content/uploads/2011/09/Shadowgun_Unite2011.pdf">(PDF)</a></strong> — a lot of low-level details if you want to optimize your game for devices.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="conclusion">Conclusion</h1>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Now I have time to think what approach to use: single configurable project, many projects with source inside Unity3D Assets folder or many projects with DLLs in the final Unity3D project. At least this time I got the details.<br>
If you want to improve your team workflow with Unity3D you must spend a day watching these videos one by one. There is a lot of interesting details and what to think about. There’s no silver bullet but there is real world experience which speakers gladly share with you.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Don’t know what to watch next? Download and watch top-ranked TED videos]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Recently I found <a href="http://blog.postrank.com/2010/05/and-the-most-engaging-ted-talk-is/">a great post</a> where the author (using a script) ranked <a href="http://www.ted.com/">TED</a> videos by the number of times they were mentioned in social services. And since TV series are getting more and more stupid I decided to start watching these videos. I’ve seen many great TED talks</p>]]></description><link>https://va.lent.in/top-ted-talks/</link><guid isPermaLink="false">5dcbe5be56953d7286f4d741</guid><dc:creator><![CDATA[Valentin Simonov]]></dc:creator><pubDate>Thu, 08 Jul 2010 10:15:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Recently I found <a href="http://blog.postrank.com/2010/05/and-the-most-engaging-ted-talk-is/">a great post</a> where the author (using a script) ranked <a href="http://www.ted.com/">TED</a> videos by the number of times they were mentioned in social services. And since TV series are getting more and more stupid I decided to start watching these videos. I’ve seen many great TED talks in the past and anyway videos people talk about the most shouldn’t be bad. So I decided to download all of them.</p>
<p>One would open that large XLS file from the site and start clicking links. It might seem easier to just watch one video from the list at a time than to write a script which visits URLs and downloads videos. But I wanted to upload all of them to my iPhone and watch/listen to them while on my way to work. So here’s the final script:</p>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><script src="https://gist.github.com/valyard/693715384453cde3b1e6.js"></script><!--kg-card-end: html--><!--kg-card-begin: markdown--><p>I uploaded the same script with data for TED videos (with rating &gt;=5) and Gemfile to install required gems to <a href="https://github.com/valyard/topTED">GitHub</a>. Some of the videos don’t have links to video files, so you have to watch them online.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>