SpinShot Devlog

Performance optimization
I've called time on this for now. After getting frustrated by the animated sprite difficulty (the SDK needs easier to use animation functions in future IMO), I tried an experiment just implementing static sprites for coins, to see whether it had a positive performance impact. While I saw some improvement from these, ultimately there were still spikes happening on the level change. Given it was not impacting gameplay much, I decided to move on to the other things below (but I'll circle back on this at the end).

Lives
I worked on adding a bit of animation to getting or losing a life. Initially I wanted something much flashier, where the lives would be physical balls that would kind of curve into position in front of the paddle after losing one, but I ended up settling for some simple animation that drew the eye a little more instead. I'm not totally happy with these but they're good enough for now.

CleanShot 2023-05-10 at 09.40.52

Visual effects
Something I've been wanting to do for a while is for the destructable bricks to have some kind of effect in addition to the displacement that sold the impact better. I finally implemented a simple effects function that I can pass the name of an animated image, and an x/y position, and it'll add it to a table, draw it to screen, and then remove it. I can spin up a bunch of these on hit events etc and it ended up being pretty straightforward. Currently there isn't much variation, but again it's good enough for now that I can move on.

CleanShot 2023-05-10 at 09.58.23

CleanShot 2023-05-10 at 10.33.31
(Ignore the FPS here, for some reason Mirror nearly halves the framerate)

I also experimented with animating the coins in using another animated image. I was having some issues applying the animation offset, but with all the coins animating in at once, I discovered the performance had increased massively. I think initially I assumed that having bricks and coins animate in over multiple frames would sort of spread the per-frame performance cost, but actually it seems like the opposite is true. I put a placeholder animation that was just a reverse of the explosion for now, but it actually looks alright. I'm going to experiment with animations for the other object types as well, maybe a simple dither fade to start, and remove all the offset adding code.

Next: Levels & Tutorials
So now that I'm happier with some of these basic systems, I'm going to shift my focus to two areas. Firstly building up to around 50 multi-phase levels (I have about 17 at the moment), and adding some sort of tutorial to the game.

I'll probably approach the tutorial in different ways, first with a basic slideshow with some animated gifs and text that can be viewed at any time. That'll be MVP, then I can look at ways of adding in tutorials in-game. Ideally I'd like as much as possible to be just encouraged by the level design, and not have to resort to popups and things, but spinning the ball well is a tricky thing that I've seen isn't easy to discover, so we'll see. Should be ready for a little playtesting after those two things are in place. :wink:

3 Likes

I really love your visual effects. Your game really feels lively and fun to play.

1 Like

Just a quick update before the weekend!

Tutorials
I actually skipped the static tutorial slideshow I thought would be easier to implement, and actually just went straight to an inline system. I can call these tutorial bubbles (which are just an animatedImage) from anywhere, the game pauses, and the box will move out of the way of the paddle so you can see when you're doing for when you continue. I think they look great, but I'll get some playtesting feedback from some friends next week.

Bonus is in order to get these working when someone picks up a coin, I've now added a generic function to be able to trigger events on pickUp of coins. I'll use this for ability pickups and stuff probably.

CleanShot 2023-05-12 at 11.16.12

New levels
These will take a bit longer, but I've tried to speed up my iteration a little bit by loading up Figma (UI design tool) and being able to rapidly place stuff on a grid there to visualize level ideas better. Can't playtest them there of course, but it's definitely helping. Doesn't feel worth it to build an in-game level editor at this stage.

Once I have my ~50ish levels, I'll playtest them obviously, but I'm also thinking about how to break them up into chapters or something, to allow people to practice more advanced levels (even though for high-score chasing, starting from the start will be of most benefit).

I'm thinking different themes for each chapter, changing the background graphics and making them more rich and interesting (as there's quite a bit of unused real estate to either side of the play area).

Also been making an Itch.io page, which makes this whole thing feel way more real! I appreciate everyone's encouragement and support :slight_smile:

Making your first game part-time, solo, is a weird and kind of lonely thing :smiley: Enjoying it though.

6 Likes

This is wonderful!
I'm joining the others that encouraged you to keep it up!

2 Likes

I'm slowly building things which facilitate removing other things I've built (which I guess is good, feels like refinement.). Dark mode is being killed. It was a hacky XOR rectangle over the entire screen, served its purpose of being a setting while I built settings, but as I develop new features it makes less and less sense.

Game Speed
When I migrated my game to use Delta Time, I'd stupidly baked game speed into the delta time calculation. In my brain I was like "Hey cool, I can slow down time by modifying a multiplier!" and implemented that in a bunch of places, but eventually had a gnarly bug where my game would never actually slow to a stop. I finally realised it was because my speed ramping was based on DT also, and it would effectively elongate forever as it's animation tried to get to the end, but time kept on lengthening.

So I refactored it again to have two speeds, a gameSpeed and a dt that I could use for timings regardless of game speed. Cool. I THEN spotted a duplicate sprite update being called in my draw code. I realised this meant I'd been calling sprite updates twice per frame, which was not only doubling my game speed, but halving my performance. It was a fairly easy fix, but I had to re-tweak all my speeds and stuff that were based around the game 'feeling' a certain way at a certain speed. There was a stopwatch, and simulator/device triggering things at the same time involved :slight_smile:

Chapters
I've been tugging at the thread I mentioned last post about theming chapters of the game. I've built out a version of this that is working, but is a little brittle, and needs some additional polish. I've got some proof of concept art in there for a tutorial space theme, a desert planet, an ice planet, and an industrial factory, all of which will tie into new mechanics being layered into the levels.

CleanShot 2023-05-17 at 13.55.28

CleanShot 2023-05-17 at 13.56.01

CleanShot 2023-05-17 at 13.56.29

CleanShot 2023-05-17 at 13.57.09

The thing I learned from my background swap code, was put that stuff in an object! I had a bunch of attempts here to try and get the screen clearing effectively on swap. Tried gfx.clear() in the callback, outside the callback, and they either didn't work, or had huge performance hits due to being called every frame. The approach below seems to have ticked all the boxes though, and is working nicely.

function setBackground(background)
  if bgSprite then
    bgSprite:remove()
  end
  bgSprite = gfx.sprite.setBackgroundDrawingCallback(
    function( x, y, width, height )
      gfx.setImageDrawMode(gfx.kDrawModeCopy)
      background:draw( 0, 0 )
    end
  )
end

Dark backgrounds
The space level being a dark background has uncovered a huge number of headaches in terms of visual design of the objects that I'm slowly plugging away at solving. For now, I've settled on variants of the coins, ball, and paddle, because with the current design, the space levels only include coins. I'll solve the blocks later once I have a more scalable approach I think.

Sitting at around 29 levels at this point. Still motivated and feeling good!

4 Likes

Great progress! New screens look great, I'm intrigued at the scenarios and what will come to level design.

See playdate.display.setInverted(flag)
https://sdk.play.date/inside-playdate/#f-display.setInverted

1 Like

Good to know for future, thanks! The addition of black backgrounds made it make no real sense now anyway, so maybe a future project :slight_smile:

At the moment the chapters are themed around the types of blocks I already have. Sand for desert, ice for ice, and moving blocks for factory.

Depending how ambitious I'm feeling I have some other ideas I want to prototype though, let's see what happens!

So this is what the pit of dispair feels like :smiling_face_with_tear:

I'm at a point in development where I really want to be building and refining content, but to expand on the content I have there, requires getting moving blocks colliding with the ball well, and this is where I've been stuck for the last 21 days.

I've posted asking for help here, but without much success:

I've probably attempted to rewrite the collision detection 10+ times at this point, with no luck. I suspect there are parts of my code that hold up really nicely under the conditions they were created, but in trying to extend them a little, are falling to bits.

So if anyone thinks they might be able to help out, please do hit me up on discord or via a DM or something (does this place support DMs?)

Hopefully my next update will be more positive, and not as far between :slight_smile:

Added a few thoughts over there Steve. I remember thinking when you posted this that having a curved bat might remove some nuance from the perspective of player skill. If it's curved, the surface the ball impacts is always the same angle - perpendicular to the radius of the arena. If you give the player a straight bat then the angle of the surface changes depending on how close to the middle of the bat they land the ball. They'd be able to deflect the ball at different angles depending on where on the bat they land it. And vice versa, having the bat at the wrong angle will send the ball in an undesired direction.

1 Like

I'm back. That pit of despair is real :smiley:

The general feedback on the paddle shape is noted for sure, but accounted for already (kind of unrelated to the problem I was having). I do offset the angle a little depending on how far from the centre of the paddle the ball hits, but the more skillful parts of the game come down to adding spin by moving the paddle during a hit (hence the game name). The problem I'm still having is with moving block collision, though at this point I think I'm just going to design around it, and remove moving blocks entirely.

Hoping to start making some progress again :slight_smile: Watch this space.

2 Likes

Hop on the playdate squad discord, it's been great for my own motivation.

So fresh eyes have helped.

I've decided to design around the moving block collision problem, and just drop moving blocks from the game's design for now. I'm focussing that batch of levels on moving coins, which have to detect collision, but not adjust the ball trajectory at all. There's some balancing to do here, and I'm thinking about reversing the ice levels and factory (moving coin) levels, as the moving coin ones seem to be a lot faster to get through.

CleanShot 2023-12-07 at 11.27.44

One of the design problems I was having with the levels previously, was when you picked up the last coin in a level, the geometry would change to the next level. To ensure the ball didn't end up in the middle of a block, I implemented a time slow-down on level change, that ramped the speed down, chaged the level, and then ramped back up. Even with that, I had to ensure the 8 squares around coin were empty to account for nicking the edge of a coin. With moving coins, and not knowing where the coin would be on the path when it was picked up, this became too much of a constraint. So I've changed the behaviour entirely, removed the slowdown, and the level changes when you hit the paddle the first time after picking up the final coin. This also means the speed of the ball is a lot more consistent, and it's easier to get into a flow state.

Once I've got through the moving coin levels, I have ideas for two new block types I want to prototype, so hopefully the next update will be progress there.

I also want to implement a difficulty slider (game speed), which I'm hoping will be straightforward, but I never know with this codebase :smiley:

2 Likes

My playdate is now in the post, awaiting RMA for a broken handle. In the meantime, I've been playing with other objects one might be able to pick up for abilities and such. It's a little wobbly around the edges but I don't mind it considering the constraints. Have a good weekend everyone :slight_smile:

CleanShot 2023-12-15 at 14.29.05

1 Like

Playdate successfully replaced due to the crank handle falling off so I'm back with some more updates :slight_smile:

I want to give a better sense of progression to the game, by allowing people to show which worlds they've unlocked, and allowing them to jump straight to those worlds to practice. If they're score-chasing they'll likely want to start from the start of course. This UI is likely to be placeholder, replaced by something a bit more modular/granular in future, but it does the job for now and only took about 45 mins.

CleanShot 2024-01-14 at 15.14.55

I also added a request from way back, and have a trail to the ball. I experimented with this a little, and have opted to add the trail only when the ball has angular velocity from a spin or magnet, to make the "curve" of the ball feel more tangible. I quite like it, but having that many animated images is making my previously solid 50fps dip to the low 40's on device. I'll look at how I might be able to optimize this later.

CleanShot 2024-01-14 at 15.23.08

I've also added a game speed setting, so you can start slower if you're having difficulty, or speed it up if you're just a deeply impatient person :wink:

CleanShot 2024-01-14 at 15.27.50

I've also put in some temp music tracks (currently far too repetitive), but what I was trying to figure out was how to have very slightly dynamic music tracks synced so I could fade between them. Right now I'm keeping it simple, with a slightly chiller track for menus and tutorial/cutscenes, and more of a beat when you're in game (might do it when the ball is moving vs stationary instead). I mostly got it working using the file player and setvolume, however when I go back to the main menu, the two tracks go way out of sync. I assume this is because I have a file write operation when returning to the menu, that writes high scores to a file, so it's maybe messing with the stream somehow. I'm going to try and mess with the buffer and see if that fixes it, but if anyone else has any other suggestions, I'm open to them! In the meantime, I'm just forcing the tracks to restart on the main menu.

1 Like

I've been making a ton of progress in a relatively short time, it's really motivating and feels closer to the pace of the first couple of months. While there's still a lot of work and polish to do, it feels like the end is in sight now!

First up, I 'finished' the Factory level set, bringing me to 35 levels across 3 worlds so far. I started timing a full playthrough (which I'm expecting will take most people quite a while to build up to), and playing reasonably well it's about 29 mins or so. I've decided on definitely adding another 10 levels with an additional world/mechanic, and hopefully the additional level difficulty will bring that up to 38-40 mins for a full playthrough.

Score overhaul
One thing I had been struggling with was how to go about making the scoring fun. For a game primarily about trying to score-chase, I wanted there to be the ability to have scores much higher than I personally could likely ever achieve, and plenty of room in between a good run and a great run.

My previous implementation of score multipliers, I'd increase the multiplier for picking up a coin with between each paddle hit, and resetting it if you had a paddle hit where you didn't pick up any coins. I was trying to incentivise precision, however this became really complicated when levels started containing the ice brick types, where it took a couple of bounces to get a pickupable coin. So I scrapped it, replaced it with 10 points for a coin, and -1 for a paddle hit, to more subtly try and implement a push/pull. This was fine but led to low scores, and not much of a dynamic between good play and great play.

Ultimately, @Ebs had proposed the seed of the new system ages ago.

In the new system, if you pick up more than one coin between paddle hits, you get a multiplier increase (only one increase per paddle hit at the moment, max ×8), and multiplier resets on death, or in one other instance. To further highlight these and make them more satisfying, I've added score numbers on coin pickup, and a new multiplier graphic near the score. I also just increased the base scores, so the coins can be worth between 50 to 400 points each depending on multiplier.

CleanShot 2024-01-20 at 21.43.28

This approach has worked way better than I thought it would. You can safely ignore it, play how you want, and have a great time, or think really strategically about which sand or ice blocks you need to break first, and the position you'd need to get in to get a straight shot at two coins in one go, AND incentivises using the magnet to curve the ball to collect multiple coins. Perfect. It's also surprisingly tricky in a way that I no longer expect to be able to hold a top score once this is released :slight_smile:

I'm now going to go back and iterate on the previous levels with this mechanic in mind. I also think there should probably be something else that resets your multiplier. Either time without picking up a coin, or number of paddle hits without picking up a coin (but more lenient, like 8 hits or something).

New block types
For the new world, I quickly prototyped and added two new block types:

Spikes
These reset your multiplier, and remove 50 points from your score when you hit them. I actually did these before refactoring the multiplier system, and then found they worked super well with it. I'm considering whether to introduce them earlier in the game actually, or possibly have a 'hard mode' in future which adds a bunch through the early levels. For now I'll probably leave them as is.

CleanShot 2024-01-20 at 21.40.54

I didn't want to make them too punishing, so they have a much smaller hitbox than anything else in the game, a touch smaller than their visual size. A new visual effect highlights the hit, which I'm pretty happy with.

Doors
These open when you hit them, and close after 2 paddle hits. This is the easiest implementation dev wise, as I never need to worry about a door closing on the ball, and handling that complexity. That gives me flashbacks of my moving block experiments, so I'm designing around it! After a little testing, I'm thinking I might count hitting a second door as a hit that will close previously opened doors also. I'll see how the level design process goes.

CleanShot 2024-01-20 at 21.34.21

Next up:

  • Re-balance how the player earns extra lives
  • Build up 10-15 levels around the new block mechanics
  • Prototype cutscenes between levels
  • Make future worlds locked until you play them
  • Music!
5 Likes

This looks absolutely awesome. Personally was not hooked from the season 1 game of this genre – your game seems to achieve a much more easy, fun and creative gameplay! I'm very happy to see this as I spent many years of my childhood playing the awesome "Vortex" brick crusher game of a very similar style on my iPod Nano (with the scroll wheel)!
Excited to see progress and to try some demos! Will definitely buy the real game :wink:

1 Like

The encouragement means a lot, thank you :slight_smile: Can't wait to get it out there!

1 Like

Multiplier iteration
The multiplier system seems to be working quite well, but once you got a multiplier, the pressure came off a little, and it made you play super cautious, so I've added a little friction back into the mix. Now you have about 8 paddle hits, and if you don't collect a coin in that time, your multiplier decreases by 1. I added a little indicator to make this more obvious which you can see in the top right here.

CleanShot 2024-01-24 at 21.06.48

World unlocks
I set aside a few hours and finished off the system for unlocking worlds as you play through them. This state now saves to a file, and is visually indicated on the level selection screen. Once you complete a world, you unlock the next one, and can warp directly to that world to practice it (obviously your score will be less if you start half way into the game though).

CleanShot 2024-01-24 at 21.06.15

Launch sequence
I started playing around with the launch sequence images, dipping a toe back into Blender and Aftereffects to come up with something a bit more dynamic. I made something a bit longer, as I thought the launch images were designed to play while the app loaded in the background, however that's not the case, so I'll probably go back and tighten it up a bit again, as there's still a second or two before the menu draws.

CleanShot 2024-02-08 at 10.05.17

Not happy with the first "ball bounce" part of the animation, but I was more interested in figuring out the pipeline from Blender > AE > Photoshop > Playdate, which this helped me do.

Content complete?
I've fleshed out the levels to a point where I'm happy enough with the amount of content. Some will still need iteration and balancing, but I feel like this amount of content provides plenty of value for $4-6ish. I've not yet been able to complete an entire run start to finish, but I'm working on it :smiley:

I'm considering adding user-created levels, but it may be something post-itch-release if I'm waiting on catalog submission or something.

3 Likes

Hey folks, I've migrated the dev-log to the Playdate community discord. I'll leave the detail up here for posterity, but I'll post any future updates over there. Discord

Reveal trailer is up, and the itch page is live. :slight_smile:

4 Likes