Bop The Bad Elf - Mobile Game

Bop The Bad Elf Preview

HTML5 and Android Mobile Game - Bop The Bad Elf

Back in 2015/2016, I released my first-ever mobile game on the Google Play Store: Bop The Bad Elf. It was built using AGK (App Game Kit) and inspired by the classic whack-a-mole mechanic, but with a fun Christmas twist.

The aim? Simple: bop as many mischievous elves as you can before you run out of lives. As the score climbs, the game speeds up, making it increasingly chaotic and addictive.

Unfortunately, like many early projects, the game eventually vanished from the Play Store, and over the years, I lost the original source code after a backup drive failure. For a long time, I thought the project was gone for good.

Fast forward almost a decade later, while digging through an old USB stick, I stumbled upon a directory called 'Elf Game Design'. Inside it was an early, cut-down version of the game's original source code and the full set of image assets. It wasn't the final build, but it was enough to recreate the game from scratch, mostly from memory.

Using that as a starting point, I rebuilt the game in 2025, fixing a few old bugs and finally exporting a new HTML5 version so it could live on once more.

Play the Game (HTML5)

You can play the rebuilt HTML5 version directly in your browser here:

Game Aim

Bop The Bad Elf is a festive whack-a-mole-style game. Your goal is to score as many points as possible by tapping the elves as they pop out of their holes. The faster you score, the quicker they appear, making it progressively more challenging.

Controls

  • Tap/Click: on an elf to bop it and score points.
  • Missed Taps: cost you a life, so aim carefully!

Scoring & Extra Lives

  • +25 points for every elf you hit.
  • -1 life for every missed tap.
  • Extra life every 1000 points, but you can't exceed 5 lives total.
  • If you drop below 5 lives, you can regain them by pushing your score higher.

How to Play

  1. Tap the Play button to start.
  2. Bop as many elves as possible before running out of lives.
  3. When your lives hit zero, it's Game Over.
  4. Beat your personal high score and keep climbing!

The fullscreen toggle works best on desktop browsers. Mobile devices may still experience issues due to differences in how fullscreen APIs behave in modern mobile browsers.

Original Android APK

Although it's no longer officially on the Google Play Store for download, you can still grab the original .apk on apkpure:

Development Timeline

YearMilestoneDetails
2015Initial DevelopmentStarted building the game in AGK (App Game Kit) as a small Christmas-themed project.
2016Play Store ReleasePublished Bop The Bad Elf on the Google Play Store, my first-ever released game.
2017Game RemovedThe app was delisted as I moved on to other projects and stopped maintaining it.
2018 - 2024Source LostA failed backup drive meant the final project files were gone, only an HTML5 export remained, locked in AGK bytecode.
2025Rebuild & RevivalFound an early source code version on an old USB, rebuilt the game from memory, and released a new HTML5 version.

Behind the Scenes

When I built Bop The Bad Elf back in 2015, I had almost no real game dev experience. It was my first time working with AGK (App Game Kit), and I was figuring everything out as I went.

Rebuilding the game in 2025 gave me a chance to revisit some of that original logic, and it's fun to look back at how things were put together.

Here's a peek behind the curtain at some of the mechanics that make the game tick:

Elf Spawning

Each elf is anchored to one of nine fixed holes. Instead of choosing a random hole each time, the game seeds a wake-up time for every elf (Random(1200,4000)/1000 seconds). When Timer() passes that time, that elf switches from ELF_HIDDEN to ELF_RISING and starts to pop up. The unpredictability comes from these per-elf timers, not from moving elves between holes.

  • There are nine fixed holes; each elf stays with its own hole.
  • Per-elf wake-up timers provide the randomness (not random positions).
  • This keeps pops unpredictable without sprites teleporting around.
Elf timing (seeding spawn times)
Function SeedElves(mode, spr)
	Select mode
		Case 0
			For i=0 to 8
				temp#=random(1200,4000)
				temp#=temp#/1000
				Elves[i].time=timer()+temp#
				Elves[i].flag=0
			Next i
		EndCase
' This is the same as above, except we only apply it to one sprite
		Case 1
			temp#=random(1200,4000)
			temp#=temp#/1000
			Elves[spr].time=timer()+temp#
			Elves[spr].flag=0
		EndCase
	EndSelect
EndFunction

And the check that flips an elf from hidden→rising when its time hits:

Elf State Update
Function CheckElves()
    For i=0 to 8
        If Elves[i].time < Timer() AND Elves[i].flag=ELF_HIDDEN
            Elves[i].flag=ELF_RISING
        EndIf
    Next i
EndFunction

Increasing Difficulty

There isn't a global "spawn delay." Difficulty scales per elf: every successful hit makes that specific elf a little faster (capped), and shortens the cooldown before it can be hit again. Fast elves become hittable again sooner, which increases pressure as you keep landing hits.

  • Hits speed up that elf (capped between MIN_ELF_SPEED and MAX_ELF_SPEED).
  • Cooldown shortens as that elf gets faster (SLOW_COOLDOWN → FAST_COOLDOWN).
  • Floor/ceiling values keep things challenging but not impossible.
Spawn Delay (speed up per hit and set a cooldown)
' CONSTANTS
MIN_ELF_SPEED as float = 0.15
MAX_ELF_SPEED as float = 0.50
SLOW_COOLDOWN as float = 0.35
FAST_COOLDOWN as float = 0.12
 
' Inside TapElves, on a successful hit:
Elves[i].flag=ELF_HIT
 
' Increase elf speed but cap it
Elves[i].spd=Elves[i].spd+0.025
If Elves[i].spd>MAX_ELF_SPEED Then Elves[i].spd=MAX_ELF_SPEED
 
' Dynamic anti-mash cooldown based on current speed
speedRatio#=(Elves[i].spd-MIN_ELF_SPEED)/(MAX_ELF_SPEED-MIN_ELF_SPEED)
cooldownTime#=SLOW_COOLDOWN+(FAST_COOLDOWN-SLOW_COOLDOWN)*speedRatio#
Elves[i].nextHit=Timer()+cooldownTime#

That's the real mechanic: each hit speeds that elf up a little and sets a per-elf cooldown before it can be hit again.

Lives & Game Over Logic

You start with 3 lives, gain +1 life every 1000 points (up to 5), and the game ends at zero. You only lose a life on a true miss: if at least one elf was hittable and you didn't hit any.

  • Start with 3 lives.
  • Earn extra lives every 1000 points, capped at 5 lives.
  • Once your lives hit zero, the game switches to Game Over mode and shows your high score.

(StartLives=3 on reset, with MaxLives=5 and NextExtraLife=1000.)

Taps, scoring, extra lives, and 'true miss' life loss
Function TapElves()
    If GetPointerPressed()=1
        lflag=0
        anyElfHittable=0
        tappedOnAnyElf=0
 
        For i=0 to 8
            If GetSpriteHitTest(Elves[i].spr, GetPointerX(), GetPointerY())=1
                tappedOnAnyElf=1
            EndIf
 
            ' A hittable elf (rising or visible) that's not on cooldown
            If (Elves[i].flag=ELF_RISING OR Elves[i].flag=ELF_VISIBLE) AND Timer() >= Elves[i].nextHit
                anyElfHittable=1
            EndIf
 
            ' If we actually hit a valid, ready elf...
            If GetSpriteHitTest(Elves[i].spr, GetPointerX(), GetPointerY())=1 AND (Elves[i].flag=ELF_RISING OR Elves[i].flag=ELF_VISIBLE) AND Timer() >= Elves[i].nextHit
 
                ' (FX/anim trimmed)
                Elves[i].flag=ELF_HIT
 
                ' Per-hit speed-up + cooldown (see previous snippet)
                ' ...
 
                ' Score & extra life
                Score=Score+25
                If Score >= NextExtraLife AND Lives < MaxLives
                    Inc Lives
                    NextExtraLife=NextExtraLife+1000
                    SetTextString(Text[4], "LIVES"+CHR(10)+str(Lives))
                EndIf
 
                SetTextString(Text[2], "SCORE"+CHR(10)+str(Score))
                lflag=1
            EndIf
        Next i
 
        ' Only lose a life on a TRUE miss (there was something hittable, but you didn't hit it)
        If lflag=0 AND anyElfHittable=1
            Dec Lives
            SetTextString(Text[4], "LIVES"+CHR(10)+str(Lives))
            PlaySound(7)
        EndIf
    EndIf
EndFunction

Things That Didn't Make It

Back in 2015, I had big ideas for the game that didn't make it into the original release, partly because I was learning as I went, and partly due to time constraints. Revisiting the project in 2025 made me rethink a few of these and consider potential future updates:

  • Power-Ups: Originally, I wanted temporary boosts like "Freeze All Elves" or "Double Points" for a short time. It didn't make it into the final release, but could be fun to add.

  • Boss Elf Mode: I toyed with the idea of a mischievous Boss Elf that appears occasionally, harder to hit but worth big points. Still might add this in a future version.

  • Leaderboard Integration: Back then, I didn't have the know-how to add Google Play leaderboards. It's something I'd like to explore now.

  • Sound & Music Enhancements: The original sound design was extremely basic, just a few "bop" effects. I'd love to revisit this with a fuller festive soundtrack.

Lessons Learned

  • Bytecode Export: AGK's HTML5 export compiles to bytecode, which meant I couldn't recover the final Play Store build, it had to be rebuilt manually.
  • Game Feel Matters: Tiny tweaks like spawn timing and tap detection make or break this style of game.
  • Backups are important: Seriously… keep them. If I could have backed up my project files more effectively using a cloud service or version control, it would have saved me a lot of headaches.

Bytecode is a compact, low-level set of instructions designed for a virtual machine rather than a physical CPU. It encodes behaviour as data, each instruction is typically a single byte, executed sequentially by the VM.

This approach offers a balance between performance and safety: it's faster and denser than interpreting high-level structures but safer and more portable than running raw machine code.

Commonly used in scripting systems and languages like Lua and Java, bytecode allows developers and even end-users to define flexible behaviour without recompiling the core application.

Technical Notes

  • Engine: AGK (App Game Kit)
  • Original Release: 2015/2016 (Android)
  • Rebuilt Version: 2025 (HTML5 export)
  • Source Recovery: An early .agc file + original image assets found on an old USB stick
  • Known Issues: On mobile, the Enter Fullscreen button may fail due to browser restrictions, works fine in a desktop environment (the HTML5 export is built for the browser)

This project is a small but meaningful time capsule for me, my first ever released game, now resurrected nearly a decade later. If you played the original back in the day or try the HTML5 version now, I'd love to hear what you think!

Roadmap: Feature Comparison

  • HTML5 build, playable in-browser
  • Random elf spawning logic
  • Difficulty scaling with score
  • Lives system with recovery
  • Score tracking and high-score saving
  • Power-ups (Freeze, Double Points)
  • Improved sound and festive soundtrack
  • Fullscreen API fixes for mobile
  • Optimisations for smoother HTML5 performance
  • Boss Elf mode, rare, harder to hit, big rewards
  • Online leaderboards and score sharing
  • Seasonal updates with new elf designs
  • Touch feedback effects and animations
Author

About the Author

David Gunner (Jnr) is an SEO executive, digital marketer, and hobbyist developer with years of experience. I even hold a Full Stack Software Development Diploma. You can learn more about my journey in this blog post and you can view my diploma certificate here.

Passionate about helping beginners learn to code and sharing practical insights, knowledge, and resources.