[{"data":1,"prerenderedAt":395},["ShallowReactive",2],{"nav-pages":3,"footer-socials":160,"$nLR9CPt1-i":183,"projects-boids":204},[4,127],{"id":5,"title":6,"body":7,"crumbs":115,"description":119,"extension":120,"icon":117,"meta":121,"navigation":122,"path":123,"seo":124,"stem":125,"__hash__":126},"pages\u002Fpages\u002F1.index.md","Home",{"type":8,"value":9,"toc":109},"minimark",[10,15,19,24,27,61,64,96,99,103],[11,12,14],"h1",{"id":13},"my-portfolio","My Portfolio",[16,17,18],"p",{},"Hi there, welcome to my portfolio website.",[20,21,23],"h2",{"id":22},"who-am-i","Who am I?",[16,25,26],{},"I'm George, a software engineer with an interest in self-hosting, programming, and hardware.",[16,28,29,30,37,38,43,44,49,50,55,56,60],{},"I studied BSC Computer Science at ",[31,32,36],"a",{"href":33,"rel":34},"https:\u002F\u002Fwww.cardiff.ac.uk\u002F",[35],"nofollow","Cardiff University",", the projects I did during my time there can be found on my ",[31,39,42],{"href":40,"rel":41},"https:\u002F\u002Fcode.ggrainger.uk\u002Fggrainger?tab=repositories",[35],"Forgejo"," or ",[31,45,48],{"href":46,"rel":47},"https:\u002F\u002Fgithub.com\u002Frandomman552",[35],"GitHub"," though I have migrated most of these to my self-hosted Forgejo instance. For my dissertation I created a website to show sensor information in Cardiff University's new Abacws building, which you can see the code for ",[31,51,54],{"href":52,"rel":53},"https:\u002F\u002Fcode.ggrainger.uk\u002Fggrainger\u002FAbacws-Data-Vis",[35],"here"," or my deployment of ",[31,57,54],{"href":58,"rel":59},"https:\u002F\u002Fabacws.ggrainger.uk\u002F",[35],".",[16,62,63],{},"In my spare time I maintain a Linux server in my house, on which I self-host a couple of things including:",[65,66,67,76,88],"ul",{},[68,69,70,71],"li",{},"My own personal cloud storage using ",[31,72,75],{"href":73,"rel":74},"https:\u002F\u002Fnextcloud.com\u002F",[35],"NextCloud",[68,77,78,79,83,84],{},"My ",[31,80,82],{"href":40,"rel":81},[35],"code"," using ",[31,85,42],{"href":86,"rel":87},"https:\u002F\u002Fforgejo.org\u002F",[35],[68,89,90,95],{},[31,91,94],{"href":92,"rel":93},"https:\u002F\u002Fheadscale.net\u002Fstable\u002F",[35],"HeadScale"," for easy, self-hosted VPN access",[16,97,98],{},"In my spare time, I also write some code for Arduino's here and there, the connection between software and hardware is always fun to play with. I work for a company based in North Yorkshire that makes robotic automation systems, so I've got to work with some really cool hardware.",[20,100,102],{"id":101},"what-is-this-site-for","What is this site for?",[16,104,105,106,60],{},"I wanted a place to write about interesting projects I've worked on, here it is. You can check them out ",[31,107,54],{"href":108},"\u002Fprojects",{"title":110,"searchDepth":111,"depth":111,"links":112},"",2,[113,114],{"id":22,"depth":111,"text":23},{"id":101,"depth":111,"text":102},[116],{"name":6,"icon":117,"href":118},"material-symbols:home-rounded","\u002F","Welcome to George's portfolio website","md",{},true,"\u002Fpages",{"title":6,"description":119},"pages\u002F1.index","iJZaQtML6AUZWO7oOxOQo8ckoA7ZFdLQwhAci4MVMik",{"id":128,"title":129,"body":130,"crumbs":150,"description":154,"extension":120,"icon":153,"meta":155,"navigation":122,"path":156,"seo":157,"stem":158,"__hash__":159},"pages\u002Fpages\u002F2.projects.md","Projects",{"type":8,"value":131,"toc":148},[132,135,138,145],[11,133,129],{"id":134},"projects",[16,136,137],{},"My recent projects can be found below.",[16,139,140,141,144],{},"Can't find anything that interests you? Check out my ",[31,142,42],{"href":40,"rel":143},[35]," for some other things I've made that didn't make the cut (or that I haven't finished).",[146,147],"card-project-grid",{},{"title":110,"searchDepth":111,"depth":111,"links":149},[],[151,152],{"name":6,"icon":117,"href":118},{"name":129,"icon":153,"href":108},"material-symbols:deployed-code","View my projects here",{},"\u002Fpages\u002Fprojects",{"title":129,"description":154},"pages\u002F2.projects","ZvgQ8iafkO8Vo_2oMkyd_n-BCCp-tAooB16GjR_rLf4",[161,169,175],{"id":162,"extension":163,"icon":164,"link":165,"meta":166,"name":42,"stem":167,"__hash__":168},"socials\u002Fsocials\u002Fforgejo.yml","yml","devicon-plain:forgejo","https:\u002F\u002Fcode.ggrainger.uk\u002Fggrainger",{},"socials\u002Fforgejo","eLo2tedWGBfxJY_VmYmV0uFkIDhRuQvm4fmj_5QD7f0",{"id":170,"extension":163,"icon":171,"link":46,"meta":172,"name":48,"stem":173,"__hash__":174},"socials\u002Fsocials\u002Fgithub.yml","mdi:github-box",{},"socials\u002Fgithub","umA4vGSgNhkainXfqvtesFnwEcchjMuYOaVvJl409do",{"id":176,"extension":163,"icon":177,"link":178,"meta":179,"name":180,"stem":181,"__hash__":182},"socials\u002Fsocials\u002Flinkedin.yml","mdi:linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fgeorge-grainger552\u002F",{},"LinkedIn","socials\u002Flinkedin","bTHOxI-WAMN6H2Ub1ipKl89w3nM34aSFOrB4ziV6Nhc",{"id":128,"title":129,"body":184,"crumbs":199,"description":154,"extension":120,"icon":153,"meta":202,"navigation":122,"path":156,"seo":203,"stem":158,"__hash__":159},{"type":8,"value":185,"toc":197},[186,188,190,195],[11,187,129],{"id":134},[16,189,137],{},[16,191,140,192,144],{},[31,193,42],{"href":40,"rel":194},[35],[146,196],{},{"title":110,"searchDepth":111,"depth":111,"links":198},[],[200,201],{"name":6,"icon":117,"href":118},{"name":129,"icon":153,"href":108},{},{"title":129,"description":154},{"id":205,"title":206,"body":207,"coverImage":385,"description":386,"extension":120,"liveDemo":218,"meta":387,"navigation":122,"ogImage":388,"path":389,"publishedAt":390,"seo":391,"sourceCode":392,"stem":393,"__hash__":394},"projects\u002Fprojects\u002Fboids.md","Boids Simulation",{"type":8,"value":208,"toc":376},[209,213,220,225,229,232,235,262,265,268,276,280,288,291,300,303,309,318,322,325,329,332,366,370,373],[20,210,212],{"id":211},"demo","Demo",[16,214,215,216,60],{},"A video demonstration of the simulation in action can be seen below. To try it out yourself, click ",[31,217,54],{"href":218,"rel":219},"https:\u002F\u002Fggrainger.epicpages.dev\u002Flibgdx-boids\u002F",[35],[221,222],"prose-video",{"alt":223,"src":224},"Demo video of the simulation in action.","\u002Fvideos\u002Fprojects\u002Fboids\u002Fdemo.mp4",[20,226,228],{"id":227},"what-are-boids","What are Boids?",[16,230,231],{},"Boids are an algorithmic approach to simulation of flocking behaviour such as that found in flocks of birds or schools of fish.",[16,233,234],{},"They achieve this by following a series of simple rules which are defined in the report above\nand are as follows:",[236,237,238,246,254],"ol",{},[68,239,240,241],{},"Collision Avoidance\n",[65,242,243],{},[68,244,245],{},"Avoid collisions with nearby flock mates.",[68,247,248,249],{},"Velocity Matching\n",[65,250,251],{},[68,252,253],{},"Attempt to match velocity with nearby flock mates.",[68,255,256,257],{},"Flock Centering\n",[65,258,259],{},[68,260,261],{},"Attempt to stay close to nearby flock mates.",[16,263,264],{},"These are in order of decreasing precedence,\nmeaning that Collision Avoidance is the most important, and Flock Centering is the least important.",[16,266,267],{},"With each of these rules individually, the boids will not exhibit flocking behaviour.\nBut when combined, the result looks very realistic (and mesmerising to watch).",[16,269,270,271,60],{},"The Boids algorithm was originally developed by Craig Reynolds in 1986, for more information see this Wikipedia ",[31,272,275],{"href":273,"rel":274},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FBoids",[35],"article",[20,277,279],{"id":278},"project-goals","Project Goals",[16,281,282,283,60],{},"In this project, I produced a Boids simulation using the libGDX framework.\nThis project was inspired by a similar project developed by Sebastian Lague, which can be found on ",[31,284,287],{"href":285,"rel":286},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=bqtqltqcQhw",[35],"YouTube",[16,289,290],{},"In addition to the basic Boids algorithm, this simulation also implements a simple obstacle avoidance system using raycasting to detect and avoid obstacles.",[16,292,293,294,299],{},"I selected ",[31,295,298],{"href":296,"rel":297},"https:\u002F\u002Flibgdx.com\u002F",[35],"libGDX"," as the framework for this project, as I was familiar with it at the time from a previous project.\nI have recently made some extensions to the simulation to allow for additional boids to be spawned, and obstacles to be added dynamically to the simulation.",[20,301,298],{"id":302},"libgdx",[16,304,305,308],{},[31,306,298],{"href":296,"rel":307},[35]," is a cross-platform Java game development framework that works cross platform on Windows, Linux, macOS, Android, iOS, and browsers.\nUnlike game engines such as Unity, libGDX is only a framework. It doesn't force you to adhere to a particular structure, but it also leaves it up to you to build your own structure.\nIt handles rendering, input, audio, and includes Box2D for physics.",[16,310,311,312,317],{},"I used libGDX on a ",[31,313,316],{"href":314,"rel":315},"https:\u002F\u002Fcode.ggrainger.uk\u002Fggrainger\u002Fcm2305-group-11",[35],"previous group project"," at university and was familiar with it at the time I made this project, which made it the obvious choice.",[20,319,321],{"id":320},"spatial-partitioning","Spatial partitioning",[16,323,324],{},"In an attempt to improve performance of this boid implementation, we make use of spatial partitioning\nto prevent us from looping over every other boid for each frame, this implementation uses the\nunderlying Box2D physics engine so that boids can only \"perceive\" other boids that are within a\ncertain radius of them.",[20,326,328],{"id":327},"configuration","Configuration",[16,330,331],{},"The simulation can be dynamically configured using a series of tools built into the simulation UI, the following tools are integrated:",[65,333,334,342,350,358],{},[68,335,336,337],{},"Force Configuration\n",[65,338,339],{},[68,340,341],{},"Configure the force scalar for each of the three boid rules.",[68,343,344,345],{},"Debug Overlay\n",[65,346,347],{},[68,348,349],{},"Includes overlays to view the underlying physics engine, and forces acting on each boid.",[68,351,352,353],{},"Boid Spawner\n",[65,354,355],{},[68,356,357],{},"Create and remove boids from the simulation dynamically.",[68,359,360,361],{},"Obstacle Spawner\n",[65,362,363],{},[68,364,365],{},"Create and remove obstacles from the simulation dynamically.",[20,367,369],{"id":368},"results","Results",[16,371,372],{},"The simulation works well for a few hundred boids, but performance with large number of boids could be improved.\nThere are a couple of ways performance could be improved, we could offload the boid calculations to separate threads, or even create a GPU compute shader to handle the calculations for us (which would be significantly faster).",[16,374,375],{},"LibGDX is a great framework, but it's not as widely used as other engines such as Unity, Unreal, or Godot.\nIt's also comparatively very simple and doesn't force a particular structure on you which is nice, but I may look at these other engines in a future project as I'd like to see how they compare.",{"title":110,"searchDepth":111,"depth":111,"links":377},[378,379,380,381,382,383,384],{"id":211,"depth":111,"text":212},{"id":227,"depth":111,"text":228},{"id":278,"depth":111,"text":279},{"id":302,"depth":111,"text":298},{"id":320,"depth":111,"text":321},{"id":327,"depth":111,"text":328},{"id":368,"depth":111,"text":369},"\u002Fimages\u002Fprojects\u002Fboids\u002Fcover.png","Implementing a Boids simulation to model flocking behavior using LibGDX.",{},null,"\u002Fprojects\u002Fboids","2026-08-02 15:56:00",{"title":206,"description":386},"https:\u002F\u002Fcode.ggrainger.uk\u002Fggrainger\u002Flibgdx-boids","projects\u002Fboids","m0rNVB9GdHyPGP2K9Y_U604QZu25e8z9Nw1SfSS8Q6Q",1785686925256]