Bugs Exist In All Code Bases

June 19, 2026

 

Logo

Bugs Exist In All Code Bases

One of the most common misconceptions among new programmers is that experienced developers write bug-free code. Spend enough time programming, however, and you'll discover an important truth:

Bugs exist in all code bases.

It doesn't matter if the project is a weekend hobby, an indie game, a commercial application, or software used by millions of people. Given enough complexity, enough features, and enough time, bugs will find their way into the code.

Perfection Is an Impossible Target

Programming isn't simply writing instructions for a computer. It's about solving problems, and those problems often change over time. New features are added, old systems are updated, and user expectations evolve.

Every change introduces the possibility of unintended side effects.

A fix for one problem might expose another. An optimisation could create an edge case that nobody anticipated. A new feature might interact with older code in unexpected ways.

This isn't necessarily bad programming. It's simply the nature of software development.

Complexity Is the Real Enemy

A program might start out as a few hundred lines of code. Years later, it could have hundreds of thousands of lines spread across countless functions and modules.

The more moving parts a project has, the more interactions exist between those parts.

Even if each individual function works perfectly, combining them can produce behaviours that weren't expected.

The challenge isn't eliminating every possible bug. It's managing complexity so that bugs are easier to find and fix.

Every Programmer Writes Bugs

Beginners often think they're making mistakes because they aren't good enough.

Professionals know that mistakes are part of the job.

Experienced programmers don't magically avoid bugs. They simply develop better habits:

* Breaking problems into smaller pieces.
* Testing code frequently.
* Writing clear, readable functions.
* Using debugging tools effectively.
* Accepting that the first version probably won't be the final version.

The difference between a beginner and an experienced developer isn't the number of bugs they create.

It's how quickly they can track them down and fix them.

Finding Bugs Is Progress

It's easy to become frustrated when a bug appears after hours of coding.

In reality, discovering a bug is often a success.

You found something that wasn't working correctly before your users did. You learned something about your program. You made the code a little more robust than it was yesterday.

Every bug fixed improves the quality of the project.

Even Famous Software Has Bugs

* Operating systems have bugs.

* Games have bugs.

* Web browsers have bugs.

* Programming languages have bugs.

The tools we use every day receive updates and patches because developers continually discover issues and improve their software.

If some of the largest software projects in the world can't eliminate every bug, it's unrealistic to expect our own projects to be perfect.

The Goal Is Better Software

Good software development isn't about creating bug-free code.

It's about creating code that can be understood, maintained, tested, and improved over time.

A healthy code base isn't one without bugs.

It's one where bugs can be identified, fixed, and prevented from causing bigger problems in the future.

Final Thoughts

Bugs exist in all code bases.

That's not a sign that a project has failed or that a programmer lacks skill. It's a natural consequence of building increasingly complex systems to solve increasingly complex problems.

The next time you encounter a bug, remember that you're participating in a process shared by every programmer, from hobbyists writing their first game to engineers maintaining software used around the world.

The goal isn't perfection.

The goal is to make today's code a little better than yesterday's.


PS3D - Polygon Subdivision PS3D - PlayBASIC Devlog

May 20, 2026

 

PS3D - Polygon Subdivision PS3D - PlayBASIC Devlog

In this PlayBASIC development update, we take a deep dive into the latest polygon subdivision experiments inside the PS3D software rendering engine. This tech demo showcases adaptive quad subdivision, near-plane clipping improvements, affine texture mapping, filtered triangles, and transparent rendering running entirely in software.

The new subdivision system dynamically increases polygon detail based on camera distance and face orientation, dramatically improving image quality for close-up geometry without requiring full perspective-correct texture mapping. Instead of relying purely on traditional affine textured triangles, PS3D subdivides quads into smaller faces to better approximate perspective, reducing the heavy distortion commonly seen near the camera.

This video also explores:

  • Adaptive polygon subdivision in a software renderer
  • Quad vs triangle clipping behavior
  • Near Z-plane clipping and projection artifacts
  • Backface culling and object-level visibility rejection
  • Transparent alpha blended rendering
  • Triangle fan generation after clipping
  • Performance tradeoffs between image quality and rendering speed
  • Screen-space clipping limitations
  • Software 3D rendering techniques in PlayBASIC
  • Retro-style rendering pipelines and engine experimentation
  • The demo scene renders thousands of transparent objects while visualizing subdivision levels and clipping behavior in real time. The green wireframe overlays reveal how faces are broken down and processed internally by the renderer.

    PS3D remains a fully software-driven 3D engine written in PlayBASIC, focused on experimentation with classic rendering techniques, optimization strategies, and retro-inspired graphics programming.

    Mini Golf Demo – Conceptual Overview

    February 21, 2026

     

    Mini Golf Demo – Conceptual Overview

    This demo shows a simple but powerful way to build a top-down mini-golf style simulation in PlayBASIC.

    Rather than focusing on complex physics, the code demonstrates how to combine a few clean ideas to create believable behaviour using fast, data-driven techniques.


    1. Separating visuals from gameplay logic

    The program uses two images of the same size, each with a different purpose:

    • Visible Screen

    This is what you actually see: grass, shapes, and moving balls.

    • Zone Screen

    This image is never shown to the player. Each pixel stores a zone value that tells the code what type of surface the ball is currently rolling over.

    This is a very common game-dev trick:

    images aren’t just for graphics – they can also be fast lookup maps for gameplay data.


    2. Zone-based friction using lookup tables

    Each terrain type (short grass, medium grass, long grass) is assigned:

    • A zone ID

    • A friction value

    • A display colour

    When a ball moves, the code reads the pixel value from the zone screen at the ball’s position and uses that value as an index into a friction array.

    This avoids large blocks of conditionals and makes it easy to add or tweak terrain types later.


    3. Direction-based movement

    Each ball stores its:

    • Position

    • Angle

    • Speed

    Movement is calculated using basic trigonometry (sin and cos) to convert angle and speed into X and Y motion.

    The friction value from the current zone scales the speed, giving the impression of different grass lengths slowing the ball down.


    4. Ray-based collision and reflection

    Instead of moving the ball first and checking overlaps later, the code uses ray intersection:

    • A ray is cast from the current position to the next position

    • If it hits geometry, the surface normal is used to calculate a reflection angle

    • The ball bounces naturally off walls and obstacles

    This method is robust, avoids tunnelling, and works well even at higher speeds.


    5. Vector-based world geometry

    The course is built from vector lines and convex shapes, not tiles.

    • Borders are simple line segments

    • Obstacles are procedurally generated convex polygons

    • The world is partitioned to improve collision performance

    This keeps the layout flexible and easy to expand or randomise.


    6. Data-driven design

    One of the key ideas in this demo is data-driven gameplay:

    • Terrain behaviour is defined by data, not hard-coded logic

    • Friction, colour, and movement all come from lookup tables

    • New terrain types can be added with minimal code changes

    This approach scales well and is widely used in real game engines.


    Summary

    At its core, this demo demonstrates how to:

    • Separate visuals from logic

    • Use images as gameplay data

    • Apply simple physics with believable results

    • Handle collision using raycasting

    • Build systems that are easy to extend

    It’s a compact example of practical game programming techniques, written in a way that new coders can understand and build upon.



      Constant Zone_ShortGrass    =ac(1)
      Constant Zone_MedGrass        =ac(1)
      Constant Zone_LongGrass        =ac(1)
    
    
      Dim Palette(100)
      Palette(Zone_ShortGrass)      = rgb(55,200,80)
      Palette(Zone_MedGrass)          = rgbfade(Palette(Zone_ShortGrass),50)
      Palette(Zone_LongGrass)          = rgbfade(Palette(Zone_ShortGrass),25)
     
      dim Friction#(100)
      Friction#(Zone_ShortGrass)    =1
      Friction#(Zone_MedGrass)      =1.5
      Friction#(Zone_LongGrass)      =2
     
     
      ; get the screen size 
      sw=GetScreenWidth()
      sh=GetScreenHeight()
    
      ; create the visible screen
      DisplayScreen      =NewIMage(sw,sh,true)
    
      ; create the zone screen.
      ; the zone screen is the same size as the 'visible'
      ; but is just used to tell what zone the ball is currently over
      ZoneScreen        =GetFreeimage()
      createfximageex ZoneScreen,sw,sh,32
     
    
      // Draw the Visible scene..
      rendertoimage Displayscreen
      c=Palette(Zone_ShortGrass)
      shadebox 0,0,sw,sh,c,rgbfade(c,80),c,rgbfade(c,80)
    
      inkmode 1+32 
      ellipsec sw*0.7,sh*0.5,200,100,true,Palette(Zone_MedGrass)     
      ellipsec sw*0.7,sh*0.5,100,50,true,Palette(Zone_LongGrass)     
      inkmode 1
    
    
      // draw the collision (zone) scene. 
      rendertoimage Zonescreen
      Cls Zone_ShortGrass
      ellipsec sw*0.7,sh*0.5,200,100,true,Zone_MedGrass     
      ellipsec sw*0.7,sh*0.5,100,50,true,Zone_LongGrass     
     
    
    
      // create collision world
      CollisionWorld=CreateVectorWorld()
     
    
     
      rendertoscreen
    
    
      camera=newcamera()
      cameracls camera,off
    
      setfps 60
    
    
    
      Type tBall
            x#,y#,angle#,speed#
      endType
    
      Dim Ball as tball List
    
        AddNewBallTime=0
    
      Do
    
            CT = Timer() and $7fffffff
          if CT>AddNewBallTime
                ball = new Tball
                ball.x#=rnd(sw)
                ball.y#=rnd(sh)
                Ball.Angle#=rnd(360)
                Ball.speed#=rndrange(2,10)
                AddNewBallTime=CT+1000
          endif
    
           
           
    
          capturetoscene
          clsscene
         
          CaptureDepth 100
    
          CameraGrabWorld Camera,CollisionWorld
    
          DrawImage DisplayScreen,0,0,false
    
          CaptureDepth 10
    
          rendertoimage ZoneScreen
    
          for each Ball()
    
            ; check what zone the ball is currently over.       
            ZoneType=Point(Ball.x#,Ball.y#) and 255
    
            ; get the amount of friction this zone has
            Friction#=Friction#(ZoneType)
     
            ; move the ball 
            Speed#=Ball.Speed#*1/Friction#
    
            newx#=ball.x#+(cos(Ball.angle#)*speed#*1)
            newy#=ball.y#+(sin(Ball.angle#)*speed#*1)
    
            if RayIntersectWOrld(CollisionWorld,Ball.x#,Ball.y#,NewX#,NewY#)=true
                  x2#  =getintersectx#(0)
                  y2#  =getintersecty#(0)
                  ; Calc reflection Direction
                  WallAngle#=AtanFull(getnormaly#(0),getnormalx#(0))
                  RayAngle#=GetAngle2d(x2#,y2#,ball.x#,ball.y#)
                  Ball.Angle#=WrapAngle(WallAngle#,WallAngle#-RayAngle#)
    
                  ball.x#=x2#
                  ball.y#=y2#
               
            else
                  ball.x#=newx#
                  ball.y#=newy#
            endif
    
            ; draw the circle to represent the ball
            circle ball.x#,ball.y#,10,true
          next
    
          drawcamera camera
          Sync
      loop
    
    
    
    
    
    Function CreateVectorWorld()
      WorldWidth=GetScreenWidth()
      WorldHeight=GetScreenHeight()
    
    
    ; Create world
      World=NewWorld()
      CaptureToWorld World
    
    ; draw a series of boarder line for this world
      line 0,0,worldwidth,0
      line worldwidth,0,worldwidth,worldheight
      line worldwidth,worldheight,0,worldheight
      line 0,worldheight,0,0
    
      for lp=0 to 7
          x=100+lp*80
          y=100+lp*80
          Make_Convex(4,x,y,50,90+lp*20)
      next
    
      Make_Convex(6,700,100,90,70)
    
      PartitionWorld World,32
      DrawGFXImmediate
    
    EndFunction World
    
    
    
      ; This function creates a convex polygon shape
    
    Function Make_Convex(edges,xpos#,ypos#,Size,angle)
          sa#=360.0/edges
          c=rndrgb()
          for lp=0 to edges-1
            a#=angle+(lp*sa#)
            x1#=xpos#+cosRadius(a#,size)
            y1#=ypos#+SinRadius(a#,size)
            if lp<(edges-1)
                a#=angle+((lp+1)*sa#)
            else
                a#=angle
            endif
            x2#=xpos#+cosRadius(a#,size)
            y2#=ypos#+SinRadius(a#,size)
            line x2#,y2#,x1#,y1#
          next lp
    endfunction i