Creating a responsive Single Page Web App can be daunting, but using a good CSS framework can help. I like Bulma for its easy to read syntax, and because its column layout is familiar to me as someone who usually uses Bootstrap. By wrapping your Vue elements in Bulma classes, you can easily perform complicated conditional rendering and not worry about the app breaking, as all the elements will sort to the proper positions within the container.
For this example I am using @vue/cli 4.5.13, which you can install through Yarn or NPM. I am using NPM for this example.
npm install -g @vue/cli
With @vue/cli we can use the create-app feature to build our scaffolding:
vue create my-app-name
This will open a menu that prompts you to select the features you want for your app
Vue CLI v4.5.13
? Please pick a preset: Manually select features
? Check the features needed for your project:
(*) Choose Vue version (*) Babel
( ) TypeScript
( ) Progressive Web App (PWA) Support
( ) Router
(*) Vuex (*) CSS Pre-processors
(*) Linter / Formatter () Unit Testing
( ) E2E Testing
Use space to select CSS Pre-Processors and Babel any other features you may want. Also make sure to select Vue 3. Press enter to move on. Continue answering the questions, but make sure to select Dart-SASS as your preprocessor
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default):
>Sass/SCSS (with dart-sass)
Sass/SCSS (with node-sass)
Less
Stylus
Finish selecting your features and allow the app to scaffold. Navigate to the app and you should be able to run:
cd ./my-app-name
npm run serve
And see your app running. Now we need to install Bulma:
npm install bulma --save-dev
Next create a folder in /src/ called styles and then create /src/styles/main-styles.scss
and insert the following code:
@charset "utf-8";
//styles will go here
@import "~bulma";
Then we need to reference this style in main.js
require('./styles/main-styles.scss');
And thats it! Let’s test it by adding a button to our home page. Navigate to the HelloWorld.vue component and add a button with Bulma styling
<template>
//code
<button class="button is-primary">Bulma Button</button>
// more code
</template>
When you run your app the styling should apply:
Great! Now let’s add our own custom styling. Back in src/styles/main-styles.scss We should define a new primary color:
@charset "utf-8";
//styles will go here
$pink: #eb909f;
$primary: $pink;
@import "~bulma";
And now your App should look like this:
It’s that easy! For a full list of Bulma variables, check out the Bulma docs
BeatMaster is a music RPG designed and programmed by myself with art and other assets from Miko-Koro and music by MidiGogblin . In it players will take on the role of a young DJ as she fights the demons that have begun to pour out of an astral tear in the local club. Players will explore dungeons based on different genres of music, fight monsters with rhythm-based combat, and explore the city to find allies and equipment.
I hope to have a playable demo of this game completed by the spring of 2021. This series of blog entries will be my free form devlog. It will contain both anecdotes of development as well as more in depths explanations of my design and code.
I have never written a devlog before so this may be scattershot at times, however I do intend to post regular updates as development progresses. This first entry will give a general overview of some of the systems I have begun to develop, and future posts will contain more in depth explorations of these systems and solutions.
Design Pillars
Before I started any work on this project I had a few core concepts I know I wanted to build a game around:
Rhythm based combat
RPG style stat development
catchy original music
Light hearted and surreal story
Player dialogue choice
I have experimented with many of these concepts previously so I already had in mind how I would tackle the dialogue system and the RPG elements. I have also attempted to make a rhythm game in unity before as well so I was aware how challenging the musical elements would be. Because of this I started experimenting with the audio/rhythm elements first
How To Rhythm in Unity?
It is very important to me that the player is able to get into “the groove” of the combat, and I would like to see players bobbing their heads as they fight. The feeling of being in the groove is a such a core joyful feeling that musicians get to experience often and that is something I want the combat to express. However, because of the fickle nature of computer timing, making combat that relies on musical timing can be difficult. If the player is running even a single fps too fast or slow, over the course of the song the input timing can become offset enough to make the game unplayable and completely destroy the groove.
In earlier projects I have tackled this problem by syncing events to the time sample of a given audio clip, but I have never found an elegant way to make this scalable. I quickly decided to find a premade solution to save time on the audio-syncing and events. After some searching I decided Koreographer by SonicBloom was a good fit for my project. I got the base version as it seemed to have all the features I need.
Using Koreographer
Koreographer allows me to quickly add events with payloads to any audio clip. For example:
Koreographer plugin for Unity
I have added an event on every bar of the master track with the bar count of the audio. I can then register any script to listen to this event easily:
void Start()
{
text = GetComponent<Text>();
//Registers the method onNewBar with the Koreographer
Koreographer.Instance.RegisterForEvents(
"master_bar_count", onNewBar);
}
//Called by my custom event
void onNewBar(KoreographyEvent evt){
int barNum = evt.GetIntValue();
text.text = "BAR: " + barNum;
}
Powerful.
Unfortunately Koreographer does not supply an adequate solution to triggering and syncing multiple audio tracks at once. It provides a multiTrackPlayer however this requires all the audio tracks to be playing from the start. I will go more in depth on my solution to this later.
I had enough of an idea to start on art and combat.
Art Design
After discussing the project with Miko, we decided on a isometric 2d pixel art style with fairly large sprites (62×62 although this may get normalized to 64×64) which would allow for more detailed character design while still allowing for simple animations.
Miko also began working on some character design for the dialogue sprites as well as some environmental design. The story needs to be developed more before we are able to make much more progress on the characters.
We are going for a retrowave/occult mashup for the design of the game.
Rendering Animations
We are using Martin Hodler’s Aseprite Importer for Unity. Which is a great little tool. It’s only available through his github, but it’s very useful. It auto converts aseprite files into separate animations named after the tags in the aseprite files.
The walk animations are labeled and taggedWhen saved in the project, the aseprite file is split into animations
I then set each animation to a state in the Hero Animator
Which are accessed and set by the IsometricPlayerRenderer script
dir in this case is set by a method that splits a circle into a number of slices (in this case four) and returns the slice based on the Vector2 from the player input.
Speaking of player input….
Unity’s Input System
I decided to switch to Unity’s Input System from the defaults. I really like the design of the new system because it means I can reduce clutter in my Updates and it just feels more intuitive to me to use input callbacks.
ISSUES: I had initially built the project in Unity ver 2020.1.1f1 however after installing the Input System I was having issues with some of the callbacks not firing as expected. I had problems similar to a few other people posting on the Unity forums where no one had a very clear solution. However after updating to ver 2020.2 the problem seemed to resolve itself and the input system is working as expected. Phew.
I then added the Player Input component to my Hero prefab, and set the Behavior to Send Messages which allows me to use callbacks named after the Input Actions
public void OnGreen()
{
Hero.active.playerStateMachine.InputGreen();
}
public void OnYellow()
{
Hero.active.playerStateMachine.InputYellow();
}
public void OnRed()
{
Hero.active.playerStateMachine.InputRed();
}
public void OnBlue(){
Hero.active.playerStateMachine.InputBlue();
}
//Callback from Player Move Input
public void OnMove(InputValue value){
Hero.active.playerStateMachine.InputStick(value);
}
As you can see I am using a Finite State Machine to decide what to do with the inputs. So if the player is in CombatState the east button will attack an enemy, but if the player is in RoamState the east button will open the menu.
As I write this I can see some inconsistency with my naming pattern. While Blue Yellow Red etc… makes sense for the Xbox gamepad I am using it is not great for other controllers. I may refactor this to read East North West etc…
Combat
Designing the combat has taken most of my attention thus far. I will do a separate blog on the evolution of the combat system when I am more certain of what it will be like.
Right now, the enemies are each tied to a different stem in the music. For example:
This enemy is connected to the SNARE hits of the song. It is targeted with the BLUE button. There are two separate Koreography events it listens for: snare_hit, which is when it is vulnerable, and snare_atk, which determines when it attacks. The Damageable Time is the window of error to be able to damage it.
When in combat the player uses the face buttons to attack different enemies. Each enemy is vulnerable on the various drum hits and beats of the master track. To damage the enemies the player must input the attacks in time with the song. The player also has the ability to block attacks.
I am still deciding if I want more of a turn based combat or something more like popular top-down action games like hades. I will go more in depth into this code once it is cleaner.
Next Steps…
Making games is hard, especially with such a small team. As I am still relatively novice, it is hard for me to have a super clear roadmap of what needs to happen, especially while we are still in a prototype phase. I know for sure that the combat needs to be fun and relatively simple. Most of my time will be focused on finalizing the combat system.
I will also be spending some time writing as well, as I think the story may inform the combat and gameplay in some places. I plan on writing some character breakdowns for the major characters. This will allow Miko to do more sprite work. I also hope to have a broad-strokes onesheet completed soon.
If you found any of these topics interesting I will be happy to elaborate more and share more code so please comment here or on my twitter.