<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://cslab.quest/feed.xml" rel="self" type="application/atom+xml"/><link href="https://cslab.quest/" rel="alternate" type="text/html" hreflang="en"/><updated>2026-11-02T23:21:15+00:00</updated><id>https://cslab.quest/feed.xml</id><title type="html">blank</title><subtitle></subtitle><entry><title type="html">Ontario Tech Science Day 2026</title><link href="https://cslab.quest/blog/2026/science-day/" rel="alternate" type="text/html" title="Ontario Tech Science Day 2026"/><published>2026-10-26T00:00:00+00:00</published><updated>2026-10-26T00:00:00+00:00</updated><id>https://cslab.quest/blog/2026/science-day</id><content type="html" xml:base="https://cslab.quest/blog/2026/science-day/"><![CDATA[<p>On October 17th, Ontario Tech hosted its annual Science Day event - a STEM gathering hosted in the University’s Science Building.</p> <p>Throughout the day, various keynotes were held. Our lab hosted two keynotes and showcased three projects:</p> <h1 id="does-she-remember-how-you-felt">Does She Remember How You Felt?</h1> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/posts/science-day-2026/al-480.webp 480w,/assets/posts/science-day-2026/al-800.webp 800w,/assets/posts/science-day-2026/al-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/posts/science-day-2026/al.jpg" class="img-fluid rounded z-depth-1" width="50%" height="50%" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> <h5 id="does-she-remember-how-you-felt-1"><em>Does she remember how you felt?</em></h5> <p>In many new video games, characters talk with you through an AI language model. These characters cannot keep every word that you say, so they write short notes about each conversation. When the notes pile up, the AI rewrites them shorter, and then it does this again and again. AFTERSTATE, Al Shifan’s Master’s project, asks what survives all this rewriting: the facts of what happened, or the feelings behind them.</p> <p>We tested 12 open AI models on 219 role-play conversations from a fantasy game, and we checked every fact and every feeling after each rewrite. The first results surprised us. Feelings lasted a little longer than facts: 29% of feelings were kept, against 23% of facts. But the feelings lost their detail. In about 7 of 10 cases, the memory kept that a feeling was there, and whether it was good or bad, but it lost what kind of feeling it was or how strong it was. Feelings that a character only showed, such as a slammed door, were lost more often than feelings put into words. Most of the loss happened at the first rewrite. To show what this means for players, we also built a small demo game, The B Gate 3, where a companion rewrites her notes about you after each night at camp. These are early results, and we will check them with human labels next.</p> <h1 id="peak-testing-levels-with-evolved-players">PEAK: Testing Levels with Evolved Players</h1> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/posts/science-day-2026/peak-480.webp 480w,/assets/posts/science-day-2026/peak-800.webp 800w,/assets/posts/science-day-2026/peak-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/posts/science-day-2026/peak.jpg" class="img-fluid rounded z-depth-1" width="50%" height="50%" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> <h2 id="what-peak-is">What PEAK is</h2> <p>PEAK is a game-balancing tool for 2D platformers. Small neural networks learn to play a level and then report what happened: how often they win, where they die and why. This way, a level can be tested thousands of times without humans.</p> <p>PEAK has 5 game engines: Mario, Mega Man, Sonic, Meat Boy and Bomberman.</p> <h2 id="players-with-different-styles">Players with different styles</h2> <p>The agents imitate 6 types of players:</p> <table> <thead> <tr> <th>Persona</th> <th>How it plays</th> </tr> </thead> <tbody> <tr> <td>Novice</td> <td>Walks only, reacts slowly</td> </tr> <tr> <td>Clumsy</td> <td>Walks only, reacts slowly, often presses the wrong button</td> </tr> <tr> <td>Experienced</td> <td>Sprints, reacts every frame, makes no mistakes</td> </tr> <tr> <td>Speedrunner</td> <td>Like experienced, but tries to finish fast</td> </tr> <tr> <td>Killer</td> <td>Tries to kill every enemy</td> </tr> <tr> <td>Collector</td> <td>Tries to pick up every coin</td> </tr> </tbody> </table> <h2 id="the-experiment">The experiment</h2> <p>The newest work asks one question: <strong>if you make one small change to a level, do the agents notice it?</strong></p> <p>Each game has 1 test level, and each level has 5 changes:</p> <ul> <li><strong>A sealed route:</strong> a wall blocks the way to the exit</li> <li><strong>A harder obstacle:</strong> a wider gap, an extra enemy or a shorter bomb fuse</li> <li><strong>A weaker jump</strong></li> <li><strong>A hidden change:</strong> a tile that no player can reach</li> <li><strong>A cosmetic change:</strong> the level file is different, but the level plays the same</li> </ul> <p>The agents first learn to play the original level. Then they play each changed version, and PEAK compares the two sets of play.</p> <h2 id="the-results">The results</h2> <ul> <li>PEAK caught <strong>11 of 12</strong> changes that make the level harder or impossible to finish.</li> <li>PEAK correctly ignored <strong>4 of 4</strong> changes that do not affect play.</li> <li>The cosmetic changes played exactly the same in all 4 games.</li> <li>The one miss was the weaker jump in Meat Boy.</li> </ul> <p>Novice, experienced and speedrunner players noticed the most changes. Clumsy players noticed none, because they could not finish the original levels.</p> <h1 id="tokyoemerald">TokyoEmerald</h1> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/posts/science-day-2026/tokyoemerald-480.webp 480w,/assets/posts/science-day-2026/tokyoemerald-800.webp 800w,/assets/posts/science-day-2026/tokyoemerald-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/posts/science-day-2026/tokyoemerald.jpg" class="img-fluid rounded z-depth-1" width="50%" height="50%" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> <h5 id="can-pedestrians-in-shinjuku-tokyo-beat-pokemon-emerald"><em>Can pedestrians in Shinjuku, Tokyo beat Pokemon Emerald?</em></h5> <p><span style="color: gray;"> Given enough time, probably! </span></p> <p>TokyoEmerald is a computer vision project I myself worked on during the university’s reading week. The concept is simple: track pedestrians from a 24/7 live stream, mapping their real-time location to a virtual surface containing buttons. There are buttons overlayed on the stream that map to actual inputs in the game. The game feed is positioned in the top-lefthand side of the stream.</p> <p>As of the time of writing, it has been nearly two weeks since the stream started. We have a level 17 Combusken and we haven’t beat the first rival fight.</p> <p>More information can be found in the Twitch channel description: <a href="http://twitch.tv/tokyoemerald">twitch.tv/TokyoEmerald</a>. Feel free to walk on by our lab (SCI-2071) to see the stream on display, as well.</p>]]></content><author><name>sebastian</name></author><category term="news"/><summary type="html"><![CDATA[Recapping our lab's involvement in Ontario Tech's Science Day 2026]]></summary></entry><entry><title type="html">Explaining Our AI Research Paper from Inside Minecraft</title><link href="https://cslab.quest/blog/2026/ridge-minecraft/" rel="alternate" type="text/html" title="Explaining Our AI Research Paper from Inside Minecraft"/><published>2026-09-24T00:00:00+00:00</published><updated>2026-09-24T00:00:00+00:00</updated><id>https://cslab.quest/blog/2026/ridge-minecraft</id><content type="html" xml:base="https://cslab.quest/blog/2026/ridge-minecraft/"><![CDATA[<div class="video-wrapper"> <iframe src="https://www.youtube.com/embed/1eOKtZ-Df9g" frameborder="0" width="560" height="315" allowfullscreen=""> </iframe> </div> <p>We recently went inside Minecraft to explain our new research paper, <em>RIDGE: State-Conditioned Reward Blending for Behavioral Convergence in Deep RL Game Agents</em>. The paper was accepted for an oral presentation at the IEEE Conference on Games (CoG) 2026.</p> <p>Why Minecraft? Our reinforcement learning agent learns in Crafter, a 2D survival game that works very much like Minecraft. In this environment, the agent chops trees, crafts tools, fights zombies, and tries to stay alive. Presenting the paper from inside a similar block-building world felt like the perfect way to demonstrate the agent’s capabilities.</p> <h2 id="the-problem">The Problem</h2> <p>Usually, reinforcement learning agents are trained around a single play style. If you want an explorer, a survivor, a craftsman, and a warrior, you traditionally have to train four separate agents. Simply hard-switching rewards while an agent is learning destabilizes its entire value function.</p> <h2 id="our-idea">Our Idea</h2> <p>Our idea with RIDGE is to train one agent that possesses all four reward profiles and smoothly blends them together based on what is happening in the game. Instead of needing separate specialists, the agent adapts its priorities as the situation changes. When its health is low, it prioritizes playing it safe. When it has sufficient resources, it focuses on building.</p> <h2 id="what-happened">What Happened</h2> <p>The state-conditioned approach led to significant improvements in versatility and performance:</p> <ul> <li><strong>Dual Specialization:</strong> RIDGE was the only agent to successfully reach both the crafting and combat skills. It reached the wood pickaxe about 32% of the time and the wood sword about 26% of the time, whereas each individual specialist only mastered its own designated branch.</li> <li><strong>Survival Mechanics:</strong> It learned to sleep and wake up safely 0.66 of the time. The fixed agents reached 0.15 or less.</li> <li><strong>The Importance of State:</strong> When we removed the state-based blending and simply mixed all four rewards equally, performance dropped by 30–50%.</li> </ul> <p>One agent with many play styles costs less to train, and it plays much more like a human adapting to a dynamic environment. Beyond games, this idea could potentially extend to adaptive autonomous systems.</p> <p>A big thanks to my co-authors Kevin Christopher Chua, Ali Neshati, Loutfouz Zaman, and Cristiano Politowski, and to the Code &amp; Sorcery Lab at Ontario Tech University.</p> <p><strong>Links &amp; Resources:</strong></p> <ul> <li><strong>Full Video:</strong> <a href="https://www.youtube.com/watch?v=1eOKtZ-Df9g">Watch on YouTube</a></li> <li><strong>Code + Paper:</strong> <a href="https://github.com/Code-SorceryLab/RIDGE">GitHub Repository</a></li> </ul>]]></content><author><name></name></author><category term="news"/><category term="publication"/><summary type="html"><![CDATA[Our latest paper, RIDGE, accepted at IEEE CoG 2026, explores how state-conditioned reward blending allows a single deep RL agent to master multiple play styles.]]></summary></entry><entry><title type="html">LLM-Based NPCs in Video Games: A Systematic Mapping Study</title><link href="https://cslab.quest/blog/2026/llm-based-npcs/" rel="alternate" type="text/html" title="LLM-Based NPCs in Video Games: A Systematic Mapping Study"/><published>2026-09-24T00:00:00+00:00</published><updated>2026-09-24T00:00:00+00:00</updated><id>https://cslab.quest/blog/2026/llm-based-npcs</id><content type="html" xml:base="https://cslab.quest/blog/2026/llm-based-npcs/"><![CDATA[<div class="video-wrapper"> <iframe src="https://www.youtube.com/embed/hEYQ04oiRFE" frameborder="0" width="560" height="315" allowfullscreen=""> </iframe> </div> <p>With this review, I wanted to see how far AI has taken the capabilities of NPCs in video games.</p> <p>For many years, I went from being someone who not only enjoyed playing games as a kid, wondering how they magically made the NPCs fight the player or help them in some way, to learning how to program them bit-by-bit in university.</p> <p>Now, with the rapid emergence of AI and LLM-based applications and characters, I constructed this review to explore what researchers have done to potentially enhance the realism of NPCs. The review has been designed to show what can take a simple conversation or encounter and make them feel similar to a true interaction.</p> <p>Can LLMs improve the experience of players? Or do they diminish their enjoyment? Can NPCs be efficiently created with current technology, or do they imply that manually crafted behaviour trees/dialogue are the most optimal?</p> <p>Read the paper <a href="https://ieeexplore.ieee.org/document/11704098">here</a>!</p>]]></content><author><name>Dilan Mian</name></author><category term="news"/><category term="publication"/><category term="gamedev"/><category term="review"/><summary type="html"><![CDATA[Can LLM-Based Video Game NPCs Enhance Player Immersion?]]></summary></entry><entry><title type="html">Research visit and seminar at UFMG</title><link href="https://cslab.quest/blog/2026/seminar-ufmg/" rel="alternate" type="text/html" title="Research visit and seminar at UFMG"/><published>2026-08-10T00:00:00+00:00</published><updated>2026-08-10T00:00:00+00:00</updated><id>https://cslab.quest/blog/2026/seminar-ufmg</id><content type="html" xml:base="https://cslab.quest/blog/2026/seminar-ufmg/"><![CDATA[<p>From 5 to 19 August 2026 I am visiting the <a href="https://dcc.ufmg.br/">Department of Computer Science (DCC)</a> at the Universidade Federal de Minas Gerais (UFMG), in Belo Horizonte, Brazil.</p> <p>The visit is hosted by Prof. <a href="https://dcc.ufmg.br/professor/joao-eduardo-montandon-de-araujo-filho/">João Eduardo Montandon</a>, coordinator of the project <em>Improving Software Development Productivity with Large Language Models</em> (CNPq nº 444507/2024-8), and has three goals: strengthen the research collaboration between our groups, deliver a seminar for graduate students and faculty, and hold focused meetings with faculty members to advance the project’s research lines.</p> <h2 id="the-seminar">The seminar</h2> <p>I gave a talk titled <strong>Games, Software Engineering &amp; AI — What we build, break and measure in our lab</strong>, covering the work we do at Code &amp; Sorcery: how we build games, how we break them, and what we measure along the way.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/posts/seminar-ufmg/first-slide-480.webp 480w,/assets/posts/seminar-ufmg/first-slide-800.webp 800w,/assets/posts/seminar-ufmg/first-slide-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/posts/seminar-ufmg/first-slide.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" alt="Title slide reading 'Games, Software Engineering &amp; AI — What we build, break and measure in our lab'" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/posts/seminar-ufmg/seminar-480.webp 480w,/assets/posts/seminar-ufmg/seminar-800.webp 800w,/assets/posts/seminar-ufmg/seminar-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/posts/seminar-ufmg/seminar.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" alt="Seminar room at DCC/UFMG with attendees seated around a table and the title slide on screen" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Seminar at DCC/UFMG.</figcaption> </figure> <h2 id="meetings">Meetings</h2> <p>Beyond the seminar, the visit is built around individual meetings with faculty. So far I have met:</p> <ul> <li><a href="https://dcc.ufmg.br/professor/andre-cavalcante-hora/">André Hora</a></li> <li><a href="https://dcc.ufmg.br/professor/joao-eduardo-montandon-de-araujo-filho/">João Eduardo Montandon</a></li> <li><a href="https://dcc.ufmg.br/professor/marco-tulio-de-oliveira-valente/">Marco Tulio Valente</a></li> <li><a href="https://dcc.ufmg.br/professor/eduardo-figueiredo/">Eduardo Figueiredo</a></li> <li><a href="https://dcc.ufmg.br/professor/lucas-n-ferreira/">Lucas N. Ferreira</a></li> </ul> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/posts/seminar-ufmg/campus-480.webp 480w,/assets/posts/seminar-ufmg/campus-800.webp 800w,/assets/posts/seminar-ufmg/campus-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/posts/seminar-ufmg/campus.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" alt="Three people standing outdoors on the UFMG campus" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">On the UFMG campus with João Montandon and Fábio Petrillo.</figcaption> </figure> <p>Many thanks to João and the DCC for the invitation and the warm reception.</p>]]></content><author><name></name></author><category term="news"/><summary type="html"><![CDATA[Two weeks at the Department of Computer Science at UFMG in Belo Horizonte, working on LLMs for software development productivity.]]></summary></entry><entry><title type="html">Honours Thesis — Class of 2026</title><link href="https://cslab.quest/blog/2026/honour-thesis-f2025-w2026/" rel="alternate" type="text/html" title="Honours Thesis — Class of 2026"/><published>2026-05-28T00:00:00+00:00</published><updated>2026-05-28T00:00:00+00:00</updated><id>https://cslab.quest/blog/2026/honour-thesis-f2025-w2026</id><content type="html" xml:base="https://cslab.quest/blog/2026/honour-thesis-f2025-w2026/"><![CDATA[<p>Proud to share the work of my undergraduate honours thesis students from the Fall 2025–Winter 2026 cohort. Each of them completed an independent research project, wrote a full thesis, and presented their findings. It was a great group to work with.</p> <hr/> <div class="row mt-4 align-items-center"> <div class="col-sm-2"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/posts/honour-thesis-f2025-w2026/alex-480.webp 480w,/assets/posts/honour-thesis-f2025-w2026/alex-800.webp 800w,/assets/posts/honour-thesis-f2025-w2026/alex-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/posts/honour-thesis-f2025-w2026/alex.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> <div class="col-sm-10"> <strong>Alex Lowe</strong><br/> <em>A 2D-Gaming Benchmark for Deep Reinforcement Learning</em><br/> <small>Can DRL realistically serve as a playtesting tool for indie developers? Alex built a benchmark of three games (Flappy Bird, Pong, Snake) from scratch and trained four algorithms (PPO, A2C, TRPO, RPPO) on a consumer machine without a GPU. The results showed that while trained agents can serve as lightweight balance measurement tools, reward engineering remains the dominant barrier to adoption for small studios.</small><br/><br/> <a href="/assets/posts/honour-thesis-f2025-w2026/alex.pdf" target="_blank">Thesis</a> &nbsp;·&nbsp; <a href="/assets/posts/honour-thesis-f2025-w2026/alex-slides.pdf" target="_blank">Slides</a> </div> </div> <hr/> <div class="row mt-4 align-items-center"> <div class="col-sm-2"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/posts/honour-thesis-f2025-w2026/rabia-480.webp 480w,/assets/posts/honour-thesis-f2025-w2026/rabia-800.webp 800w,/assets/posts/honour-thesis-f2025-w2026/rabia-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/posts/honour-thesis-f2025-w2026/rabia.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> <div class="col-sm-10"> <strong>Rabia Chattha</strong><br/> <em>Evaluating Large Language Models for Docstring-to-Code Alignment</em><br/> <small>How well can LLMs associate documentation with the exact code it describes? Rabia framed this as a structured matching task — replacing docstrings with slot identifiers that models must correctly assign from a candidate list. Evaluating several modern LLMs on real-world repositories, she found that while some models perform strongly, inconsistencies in completeness and reliability remain a challenge.</small><br/><br/> <a href="/assets/posts/honour-thesis-f2025-w2026/rabia.pdf" target="_blank">Thesis</a> </div> </div> <hr/> <div class="row mt-4 align-items-center"> <div class="col-sm-2"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/posts/honour-thesis-f2025-w2026/ryan-480.webp 480w,/assets/posts/honour-thesis-f2025-w2026/ryan-800.webp 800w,/assets/posts/honour-thesis-f2025-w2026/ryan-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/posts/honour-thesis-f2025-w2026/ryan.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> <div class="col-sm-10"> <strong>Ryan Ahlborn</strong><br/> <em>Context-Aware Hint Generation for Serious Games Using Large Language Models in Gidget</em><br/> <small>Traditional hint systems in educational games rely on manually written rules that are hard to scale. Ryan built an LLM-powered hint pipeline for Gidget, a programming education game, that reads the current game state and the player's attempt, and delivers hints directly inside the game interface. User testing across 88 hint requests showed 80.7% were immediately helpful and 93.2% were factually correct.</small><br/><br/> <a href="/assets/posts/honour-thesis-f2025-w2026/ryan.pdf" target="_blank">Thesis</a> &nbsp;·&nbsp; <a href="/assets/posts/honour-thesis-f2025-w2026/ryan-slides.pdf" target="_blank">Slides</a> </div> </div> <hr/> <div class="row mt-4 align-items-center"> <div class="col-sm-2"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/posts/honour-thesis-f2025-w2026/saahir-480.webp 480w,/assets/posts/honour-thesis-f2025-w2026/saahir-800.webp 800w,/assets/posts/honour-thesis-f2025-w2026/saahir-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/posts/honour-thesis-f2025-w2026/saahir.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> <div class="col-sm-10"> <strong>Saahir Dhani</strong><br/> <em>Persona-Based Reward Shaping in Deep Reinforcement Learning</em><br/> <small>Is reward design alone enough to produce agents with distinct, stable personalities? Saahir introduced three personas — Speedrunner, Survivor, and Greedy — in a custom Breakout environment extended with lives, energy, and special abilities, each trained with PPO using only a different reward function. The results showed clear and consistent behavioral separation across all five measured metrics. A notable finding: the Survivor agent discovered reward hacking by refusing to launch the ball to avoid losing lives, which had to be corrected with an auto-launch constraint.</small><br/><br/> <a href="/assets/posts/honour-thesis-f2025-w2026/saahir.pdf" target="_blank">Thesis</a> &nbsp;·&nbsp; <a href="/assets/posts/honour-thesis-f2025-w2026/saahir-slides.pdf" target="_blank">Slides</a> </div> </div> <hr/> <div class="row mt-4 align-items-center"> <div class="col-sm-2"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/posts/honour-thesis-f2025-w2026/saffron-480.webp 480w,/assets/posts/honour-thesis-f2025-w2026/saffron-800.webp 800w,/assets/posts/honour-thesis-f2025-w2026/saffron-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/posts/honour-thesis-f2025-w2026/saffron.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> <div class="col-sm-10"> <strong>Saffron Birch</strong><br/> <em>Can LLM-Driven NPCs Remain in Character? Investigating Challenges in Generative AI-based NPC Development and Testing</em><br/> <small>LLM-powered NPCs can generate dynamic dialogue, but they struggle with hallucination, personality drift, and adversarial prompts. Saffron built a structured evaluation framework combining a cognitive memory system with a persona monitoring layer across four guardrail dimensions: personality alignment, knowledge filtration, bias mitigation, and narrative adherence. Tested on an NPC configured as Geralt of Rivia from <em>The Witcher 3</em>, the guardrail system raised the all-pass rate from 67.6% to 83.8% on a 37-question adversarial test suite.</small><br/><br/> <a href="/assets/posts/honour-thesis-f2025-w2026/saffron.pdf" target="_blank">Thesis</a> &nbsp;·&nbsp; <a href="/assets/posts/honour-thesis-f2025-w2026/saffron-slides.pdf" target="_blank">Slides</a> </div> </div> <hr/> <div class="row mt-4 align-items-center"> <div class="col-sm-2"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/posts/honour-thesis-f2025-w2026/saksham-480.webp 480w,/assets/posts/honour-thesis-f2025-w2026/saksham-800.webp 800w,/assets/posts/honour-thesis-f2025-w2026/saksham-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/posts/honour-thesis-f2025-w2026/saksham.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> <div class="col-sm-10"> <strong>Saksham Tejpal</strong><br/> <em>A Large Dataset of Video Game Patch Notes</em><br/> <small>Patch notes are a rich but messy record of how games evolve — Steam mixes them with sales posts, community updates, and promotional content, making large-scale study impractical. Saksham built a four-stage pipeline that retrieves, filters, classifies, and serves patch notes at scale: starting from 145,622 games and 1.87 million news items, the pipeline uses Gemini 2.5 Flash to confirm 817,765 genuine patch notes across 68,043 games. It then extracts 8.3 million individual change statements tagged as bug fixes (36.2%), feature additions (45.8%), or balance changes (18.0%), served through a searchable web application.</small><br/><br/> <a href="/assets/posts/honour-thesis-f2025-w2026/saksham.pdf" target="_blank">Thesis</a> &nbsp;·&nbsp; <a href="/assets/posts/honour-thesis-f2025-w2026/saksham-slides.pdf" target="_blank">Slides</a> </div> </div>]]></content><author><name></name></author><category term="news"/><summary type="html"><![CDATA[Proud to share the work of my undergraduate honours thesis students from the Fall 2025–Winter 2026 cohort. Each of them completed an independent research project, wrote a full thesis, and presented their findings. It was a great group to work with.]]></summary></entry><entry><title type="html">Invited lecture — Empirical (RETRO) Game Research</title><link href="https://cslab.quest/blog/2026/invited-lecture/" rel="alternate" type="text/html" title="Invited lecture — Empirical (RETRO) Game Research"/><published>2026-03-30T00:00:00+00:00</published><updated>2026-03-30T00:00:00+00:00</updated><id>https://cslab.quest/blog/2026/invited-lecture</id><content type="html" xml:base="https://cslab.quest/blog/2026/invited-lecture/"><![CDATA[<p>I gave a guest lecture titled <strong>Empirical (RETRO) Game Research</strong> in <em>INFR 3375U/CSCI 5550G — Retro Game Development</em>, the course taught by Andrew Hogue at Ontario Tech.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/posts/invited-lecture/first-slide-480.webp 480w,/assets/posts/invited-lecture/first-slide-800.webp 800w,/assets/posts/invited-lecture/first-slide-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/posts/invited-lecture/first-slide.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" alt="Title slide reading 'Empirical (RETRO) Game Research'" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> <h2 id="what-the-lecture-covered">What the lecture covered</h2> <p>The first part set up what empirical research means in this context: building knowledge from observation, measurement, and evidence rather than intuition or advocacy, and what that looks like when applied to games.</p> <p>The hard part is that games have subjective goals. Ordinary software is judged on correctness, reliability, and performance. Games are judged on fun, fairness, immersion, frustration, pacing, and balance — none of which can be measured directly, so empirical game research leans on proxies. That splits the field in two: research on <strong>game development</strong> (bugs, patching practices, testing strategies, engine usage, maintenance) and research on the <strong>game experience</strong> (difficulty, balance, pacing, immersion, engagement).</p> <h2 id="four-case-studies">Four case studies</h2> <p>The rest of the lecture walked through projects from the lab, all of them on retro games:</p> <p><strong>Creativity Beyond Functionality: An Observational Study of Easter Eggs in Video Games</strong> — with Claudio Di Sipio, Benoit Baudry, Michalis Famelis, and Houari Sahraoui, published at the 10th International Workshop on Games and Software Engineering (GAS 2026). Where do easter eggs come from, what counts as the first one, and what does a dataset of them across decades of releases actually show?</p> <p><strong>Iterating a Game Series’ Identity: Mixed-Methods Analysis of the Creative Process Developing Dragon Quest I–VI</strong> — with Aleksander Franiczek, presented at the International Conference on Games and Narrative (ICGaN 2025). A studio iterating on a series wants each entry to be better while reusing assets to keep the work tractable. But what does “better” mean, and how do hardware constraints such as cartridge size shape those creative decisions?</p> <p><strong>Rewriting Nostalgia in Official and Unofficial Iterations of Final Fantasy IV</strong> — with Aleksander Franiczek, accepted at the Canadian Game Studies Association Conference (CGSA 2026). Final Fantasy IV has been ported, remastered, and remade repeatedly, and fans produce ROM hacks that remix features across versions. That makes it a strong case for treating nostalgia as an active process rather than a fixed memory.</p> <p><strong>Decompiling (retro) Pokémon games</strong> — reverse engineering an executable back into human-readable code, and asking whether a feature you see in the game is really the code you think it is.</p> <p>Thanks to Andrew for the invitation.</p>]]></content><author><name></name></author><category term="news"/><summary type="html"><![CDATA[A guest lecture on empirical game research for INFR 3375U/CSCI 5550G Retro Game Development, with four case studies on easter eggs, Dragon Quest, Final Fantasy IV, and Pokémon.]]></summary></entry><entry><title type="html">OTUGuessr - A GeoGuessr-style campus exploration game for Ontario Tech University</title><link href="https://cslab.quest/blog/2026/otuguessr/" rel="alternate" type="text/html" title="OTUGuessr - A GeoGuessr-style campus exploration game for Ontario Tech University"/><published>2026-01-28T00:00:00+00:00</published><updated>2026-01-28T00:00:00+00:00</updated><id>https://cslab.quest/blog/2026/otuguessr</id><content type="html" xml:base="https://cslab.quest/blog/2026/otuguessr/"><![CDATA[<h1 id="otuguessr">OTUGuessr</h1> <p><em>A GeoGuessr-style campus exploration game for Ontario Tech University</em></p> <p><a href="https://www.otuguessr.com/">https://www.otuguessr.com/</a></p> <p><strong>Created by:</strong> Adrian Fudge &amp; Vincent Wong</p> <h2 id="introduction">Introduction</h2> <p>Ontario Tech University has a large and diverse campus with many hidden or lesser-known spots that students may never discover during their time at the school. As students ourselves, we noticed that many people tend to stick to the same few buildings and paths, missing out on some genuinely great areas across campus.</p> <p>We built <strong>OTUGuessr</strong> to help change that.</p> <p>OTUGuessr is a GeoGuessr-style web game designed specifically for the Ontario Tech University campus. The goal of the project was to create something fun and interactive that would encourage students to explore their surroundings, improve campus culture, and give both new and long-time students a new way to engage with the university.</p> <p>This was a personal project between two students, built outside of any course requirements, with the goal of gaining real-world development experience and showcasing our technical skills. After deploying the application, we saw hundreds of users within the first 24 hours, which was incredibly motivating and validated the idea.</p> <h2 id="what-is-otuguessr">What is OTUGuessr?</h2> <p>OTUGuessr is a browser-based guessing game inspired by GeoGuessr, but fully themed around the Ontario Tech University campus.</p> <p>Players are shown an image taken somewhere on campus along with an interactive map. They place a pin where they believe the image was taken. Once submitted, their guess is scored based on how close it is to the real location.</p> <p>After several rounds, players are given a final score and can submit their name to appear on a global leaderboard.</p> <p>The target audience is students — from first-years seeing campus for the first time to postgraduates who may still discover places they’ve never noticed before.</p> <h2 id="how-the-game-works">How the Game Works</h2> <ol> <li>A random campus image is displayed.</li> <li>The player drops a pin on the map.</li> <li>The guess is submitted.</li> <li>The distance between the guess and the actual location is calculated.</li> <li>A score is awarded based on accuracy and speed.</li> <li>After several rounds, the final score is shown and can be submitted to the leaderboard.</li> </ol> <h2 id="tech-stack">Tech Stack</h2> <ul> <li><strong>Frontend:</strong> React TS</li> <li><strong>Mapping:</strong> Leaflet</li> <li><strong>Backend / Cloud:</strong> Firebase</li> <li><strong>Hosting:</strong> Vercel</li> </ul> <h2 id="high-level-system-design">High-Level System Design</h2> <p>Image + Coordinates → User Guess → Distance Calculation → Score Computed → Stored in Firebase → Leaderboard</p> <h2 id="key-challenges--solutions">Key Challenges &amp; Solutions</h2> <h3 id="accurate-distance-calculation">Accurate Distance Calculation</h3> <p>We implemented the <strong>Haversine formula</strong> to calculate the shortest distance between two points on Earth using latitude and longitude.</p> <h3 id="image-performance">Image Performance</h3> <p>Images were resized and compressed before upload to significantly improve load times and responsiveness.</p> <h2 id="what-we-learned">What We Learned</h2> <ul> <li>Full-stack web development</li> <li>React + TypeScript workflows</li> <li>Firebase cloud integration</li> <li>Deployment and performance optimization</li> </ul> <h2 id="future-improvements">Future Improvements</h2> <ul> <li>Monthly resetting leaderboards</li> <li>Larger curated image pool</li> <li>Moderation system for submissions</li> <li>Difficulty modes</li> </ul>]]></content><author><name>Adrian</name></author><category term="tech"/><summary type="html"><![CDATA[OTUGuessr]]></summary></entry><entry><title type="html">Code &amp;amp; Sorcery Students at HackHive 2026</title><link href="https://cslab.quest/blog/2026/hackathon-css/" rel="alternate" type="text/html" title="Code &amp;amp; Sorcery Students at HackHive 2026"/><published>2026-01-25T00:00:00+00:00</published><updated>2026-01-25T00:00:00+00:00</updated><id>https://cslab.quest/blog/2026/hackathon-css</id><content type="html" xml:base="https://cslab.quest/blog/2026/hackathon-css/"><![CDATA[<p>Our lab students did a awesome job during the <a href="https://hackhive-2026.devpost.com/">HackHive 2026</a>.</p> <p>The Team CSS (Code &amp; Sorcery Students) <strong>Kevin christopher Chua, Mohame Al Musqi Mohamed Shifan, Alex Lowe, Adrian Fudge</strong> created this great tool that can identity body parts and facilitate the interaction between medic and pacients, even using multiple languages.</p> <p>More details bellow.</p> <hr/> <p>Bridging the Gap in Telehealth: Introducing Gestura</p> <p>I’m excited to share Gestura, a project built for the 2026 Global Hackathon that aims to revolutionize patient-clinician communication in telehealth.</p> <p>The Problem: Describing pain is hard. Language barriers, physical limitations, and the lack of tactile feedback in video calls often lead to misdiagnoses and frustration. “My arm feels like fire” shouldn’t become a translation error.</p> <p>Our Solution: Gestura is a real-time, AI-powered body mapping tool that translates gestures into structured clinical data. No wearables, no special hardware just a webcam.</p> <p>We believe technology should make healthcare more human, not less. Gestura is our step towards a future where every patient is understood, regardless of language or location.</p> <p>Check out the demo below!</p> <p>Check the details here: <a href="https://devpost.com/software/gestura-23czgh?ref_content=my-projects-tab&amp;ref_feature=my_projects">https://devpost.com/software/gestura-23czgh?ref_content=my-projects-tab&amp;ref_feature=my_projects</a></p>]]></content><author><name>Cristiano Politowski</name></author><category term="tech"/><summary type="html"><![CDATA[Our lab students did a awesome job during the HackHive 2026.]]></summary></entry><entry><title type="html">📢 Call for Submissions - FaSE4Games’26 @ FSE 2026 (Montreal, Canada)</title><link href="https://cslab.quest/blog/2025/call-fase4games26/" rel="alternate" type="text/html" title="📢 Call for Submissions - FaSE4Games’26 @ FSE 2026 (Montreal, Canada)"/><published>2025-12-11T00:00:00+00:00</published><updated>2025-12-11T00:00:00+00:00</updated><id>https://cslab.quest/blog/2025/call-fase4games26</id><content type="html" xml:base="https://cslab.quest/blog/2025/call-fase4games26/"><![CDATA[<p>We are excited to announce the 3rd ACM International Workshop on Foundations of Applied Software Engineering for Games (FaSE4Games’26) and invite contributions from the community!</p> <p>FaSE4Games brings together researchers, practitioners, and educators working on the challenges of software engineering for entertainment games, serious games, and gamified applications. The workshop offers an open and collaborative environment to share new ideas and discuss emerging topics in game development.</p> <p>🔍 We welcome: • Long papers (8 pages, incl. references) • Extended abstracts (5 pages, incl. references)</p> <p>All submissions will be reviewed by three reviewers. Accepted contributions will be presented at the workshop.</p> <p>📅 Important Dates • Submission deadline: February 12, 2025 • Notification: March 19, 2025 • Camera-ready: April 2, 2025</p> <p>🌐 More information: http://fase4games.quest</p> <p>Whether you submit a paper or simply join us for the event, FaSE4Games offers a welcoming space to learn, share, and connect with the community driving software engineering for games.</p> <p>See you in Montreal! 🇨🇦</p>]]></content><author><name></name></author><category term="news"/><summary type="html"><![CDATA[We are excited to announce the 3rd ACM International Workshop on Foundations of Applied Software Engineering for Games (FaSE4Games’26) and invite contributions from the community!]]></summary></entry><entry><title type="html">Optimizing 2D Physics Spatial Hashing</title><link href="https://cslab.quest/blog/2025/spatial-hashing/" rel="alternate" type="text/html" title="Optimizing 2D Physics Spatial Hashing"/><published>2025-11-30T16:40:16+00:00</published><updated>2025-11-30T16:40:16+00:00</updated><id>https://cslab.quest/blog/2025/spatial-hashing</id><content type="html" xml:base="https://cslab.quest/blog/2025/spatial-hashing/"><![CDATA[<p>In 2D platformers, collision detection is the silent killer of performance. Checking every object against every other object results in O<sub>n</sub><sup>2</sup> complexity, which quickly bottlenecks the CPU as the world grows.</p> <p>To solve this in PEAK, we implemented <strong>Spatial Hashing</strong>, a broad-phase optimization technique that partitions the game world into a grid of “buckets.” This post details our implementation and the architectural decision to use a <strong>Dual Hash system</strong>.</p> <h2 id="peak--platform-engine-by-al-and-kevin">PEAK – Platform Engine by Al and Kevin</h2> <p><strong>PEAK</strong> is a small SMB1-style RL/game engine with: A custom Mario-like environment (MarioCore) using Pygame. A modular reward layer (mario.py) that shapes behavior into different “personas”.</p> <p>Clean Gym-style API: reset(), step(action), get_action_space(), get_observation_space().</p> <p><strong>The core loop is:</strong></p> <ol> <li>Env loads a level from ASCII.</li> <li>Player + enemies/coins/powerups are spawned.</li> <li>Each step(action): <ul> <li>Apply input → physics → collisions.</li> <li>Update game objects, anti-stall logic, camera.</li> <li>Compute reward and info.</li> <li>Return (obs, reward, terminated, info).</li> </ul> </li> </ol> <h2 id="the-architecture-why-two-hashes">The Architecture: Why Two Hashes?</h2> <p>When designing the collision system, we evaluated three primary architectures: a single unified hash, separate hashes for static/dynamic objects, and a hybrid approach.</p> <p>We selected <strong>Option 2: Dual Spatial Hashes</strong>. In this architecture, we maintain two distinct instances of the spatial hash:</p> <ol> <li><strong><code class="language-plaintext highlighter-rouge">static_hash</code> (TileHash):</strong> Contains walls, floors, and platforms. Built once at level load and treated as read-only.</li> <li><strong><code class="language-plaintext highlighter-rouge">dynamic_hash</code> (ObjectHash):</strong> Contains enemies, coins, and the player. Cleared and repopulated every single frame.</li> </ol> <h3 id="why-this-approach">Why this approach?</h3> <ul> <li><strong>Performance:</strong> By keeping the static geometry in a read-only hash, we maximize cache efficiency and avoid the overhead of re-inserting thousands of wall tiles every frame.</li> <li><strong>Separation of Concerns:</strong> This mimics industry standards used in engines like Unity and games like <em>Celeste</em> (which separates “Solids” from “Actors”). It prevents accidental modification of level geometry.</li> </ul> <h2 id="implementation-details">Implementation Details</h2> <p>Our <code class="language-plaintext highlighter-rouge">SpatialHash</code> class is a lightweight grid partitioner. It uses a dictionary to map integer cell coordinates to lists of objects.</p> <h3 id="1-the-grid-structure">1. The Grid Structure</h3> <p>We define a <code class="language-plaintext highlighter-rouge">cell_size</code> slightly larger than the average object. This ensures most objects sit in only 1–4 cells, keeping queries fast.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">class</span> <span class="nc">SpatialHash</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">cell_size</span><span class="o">=</span><span class="mi">64</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="n">cell_size</span> <span class="o">=</span> <span class="n">cell_size</span>
        <span class="c1"># Maps (cx, cy) -&gt; List[obj]
</span>        <span class="n">self</span><span class="p">.</span><span class="n">contents</span> <span class="o">=</span> <span class="p">{}</span>
</pre></td></tr></tbody></table></code></pre></div></div> <h3 id="2-cell-addressing">2. Cell Addressing</h3> <p>We convert world-space float coordinates into integer grid indices using floor division.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="k">def</span> <span class="nf">_get_cell_coords</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">position</span><span class="p">:</span> <span class="n">Tuple</span><span class="p">[</span><span class="nb">float</span><span class="p">,</span> <span class="nb">float</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">Tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">]:</span>
    <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">position</span>
    <span class="k">return</span> <span class="nf">int</span><span class="p">(</span><span class="n">math</span><span class="p">.</span><span class="nf">floor</span><span class="p">(</span><span class="n">x</span> <span class="o">/</span> <span class="n">self</span><span class="p">.</span><span class="n">cell_size</span><span class="p">)),</span> <span class="nf">int</span><span class="p">(</span><span class="n">math</span><span class="p">.</span><span class="nf">floor</span><span class="p">(</span><span class="n">y</span> <span class="o">/</span> <span class="n">self</span><span class="p">.</span><span class="n">cell_size</span><span class="p">))</span>
</pre></td></tr></tbody></table></code></pre></div></div> <h3 id="3-insertion">3. Insertion</h3> <p>When an object is inserted, we calculate its Axis-Aligned Bounding Box (AABB) and add the object to every cell that the AABB overlaps.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="k">def</span> <span class="nf">insert</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
    <span class="n">target</span> <span class="o">=</span> <span class="n">obj</span><span class="p">.</span><span class="n">gObj</span> <span class="k">if</span> <span class="nf">hasattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="sh">'</span><span class="s">gObj</span><span class="sh">'</span><span class="p">)</span> <span class="k">else</span> <span class="n">obj</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">target</span><span class="p">.</span><span class="n">active</span><span class="p">:</span>
        <span class="k">return</span>

    <span class="c1"># specific AABB calculation
</span>    <span class="n">start_cx</span><span class="p">,</span> <span class="n">start_cy</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="nf">_get_cell_coords</span><span class="p">((</span><span class="n">target</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="n">target</span><span class="p">.</span><span class="n">y</span><span class="p">))</span>
    <span class="n">end_cx</span><span class="p">,</span> <span class="n">end_cy</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="nf">_get_cell_coords</span><span class="p">((</span><span class="n">target</span><span class="p">.</span><span class="n">x</span> <span class="o">+</span> <span class="n">target</span><span class="p">.</span><span class="n">width</span><span class="p">,</span> <span class="n">target</span><span class="p">.</span><span class="n">y</span> <span class="o">+</span> <span class="n">target</span><span class="p">.</span><span class="n">height</span><span class="p">))</span>

    <span class="k">for</span> <span class="n">cx</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">start_cx</span><span class="p">,</span> <span class="n">end_cx</span> <span class="o">+</span> <span class="mi">1</span><span class="p">):</span>
        <span class="k">for</span> <span class="n">cy</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">start_cy</span><span class="p">,</span> <span class="n">end_cy</span> <span class="o">+</span> <span class="mi">1</span><span class="p">):</span>
            <span class="n">cell</span> <span class="o">=</span> <span class="p">(</span><span class="n">cx</span><span class="p">,</span> <span class="n">cy</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">cell</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">self</span><span class="p">.</span><span class="n">contents</span><span class="p">:</span>
                <span class="n">self</span><span class="p">.</span><span class="n">contents</span><span class="p">[</span><span class="n">cell</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
            <span class="n">self</span><span class="p">.</span><span class="n">contents</span><span class="p">[</span><span class="n">cell</span><span class="p">].</span><span class="nf">append</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div> <h3 id="4-querying">4. Querying</h3> <p>To find nearby objects, we query a specific rectangle. To handle objects that span multiple cells (and therefore appear in multiple buckets), we use a set of <code class="language-plaintext highlighter-rouge">seen_ids</code> to ensure we don’t return duplicates.</p> <h2 id="integration-in-mariocore">Integration in MarioCore</h2> <p>PEAK integrates these instances directly into the core game loop.</p> <h3 id="the-static-pass-level-load">The Static Pass (Level Load)</h3> <p>During <code class="language-plaintext highlighter-rouge">_build_level_from_txt</code>, we populate the <strong><code class="language-plaintext highlighter-rouge">static_hash</code></strong>. This includes ground, platforms, spikes, and goal tiles. Because this data never moves, we never clear this hash. This makes resolving player-environment collisions extremely fast (O(k<sub>tiles</sub>)).</p> <h3 id="the-dynamic-pass-update-loop">The Dynamic Pass (Update Loop)</h3> <p>Every frame, <code class="language-plaintext highlighter-rouge">_rebuild_dynamic_hash()</code> runs:</p> <ol> <li>Clears the <code class="language-plaintext highlighter-rouge">dynamic_hash</code>.</li> <li>Iterates through all active entities (Enemies, Coins, Powerups).</li> <li>Inserts them into the grid based on their new positions.</li> </ol> <p>This allows us to handle Entity-vs-Entity collisions (like a Shell hitting an Enemy) efficiently without checking the entire map.</p> <h2 id="beyond-physics-rendering">Beyond Physics: Rendering</h2> <p>We also leverage the spatial hash for rendering optimization. Instead of sending every object to the GPU, <code class="language-plaintext highlighter-rouge">_draw_entities_from_hash</code> queries the <code class="language-plaintext highlighter-rouge">dynamic_hash</code> using the <strong>Camera’s view rectangle</strong>.</p> <p>This serves as an effective frustum culling mechanism: if an enemy is not in a bucket overlapping the camera view, it is never processed for drawing.</p> <h2 id="conclusion">Conclusion</h2> <p>By adopting the <strong>Dual Spatial Hash</strong> architecture, PEAK achieves a balance of simplicity and performance. We avoid the O<sub>n</sub><sup>2</sup> sorting trap, maintain clean code separation between world geometry and active actors, and gain a rendering culling system for free.</p>]]></content><author><name>Al</name></author><category term="gamedev"/><category term="tech"/><summary type="html"><![CDATA[In 2D platformers, collision detection is the silent killer of performance. Checking every object against every other object results in On2 complexity, which quickly bottlenecks the CPU as the world grows.]]></summary></entry></feed>