Looks simple enough to implement. It would be cool if you could make a swept wing craft that retracts and extends the wings. Does not really make sense in space, too much, but would be cool.
Yeah i like that folding wing design. It really doesnāt make sense in space, but it looks kinda cool. I could hook it up with actual box2D joints so it reacts to the world or you could shoot a wing off. Its just a video game, thereās no law that says it has to make sense.
I have some ideas on paper for customizable ships. But thatās one of the features I have cut for now to reduce scope. Only one ship till I get the rest of the engine working.
Started to add sounds effects.
I played around with some colors for better contrast, and I think I figured out the art style a little bit.
The first move was reducing the background textureās pixmap format from RGBA8888
ā RGBA4444
before: smooth 8888
after: stepped 4444
The noise now has a stepping instead of smooth transition that I think fits the art style a little better. And this reduced color pallet makes it easier to see foreground objects.
I also added a greyscale shader to fade to black and white when zooming out. This helps further with contrast.
To get the grey we calculate the average color for a pixel by sampling the r,g,b and divide by 3.
varying vec4 v_color;
varying vec2 v_texCoords;
uniform sampler2D u_texture;
uniform float u_blend;
void main() {
vec4 color = v_color * texture2D(u_texture, v_texCoords);
float grey = (color.r + color.g + color.b) / 3.0;
gl_FragColor = mix(color, vec4(grey, grey, grey, color.a), u_blend);
}
Then using a uniform to pass in the ratio of how much to u_blend
the mix() between the original color, and black and white. The ratio in this case based on the zoom.
public void update(float delta) {
CameraSystem cam = getEngine().getSystem(CameraSystem.class);
float blend = cam.getZoomLevel() / cam.getMaxZoomLevel();
spaceShader.bind();
spaceShader.setUniformf("u_blend", blend);
//renderStuff()....
}
I tried to avoid drawing a grid. But Iām still struggling with frame of reference so I cracked and drew a grid to help judge movement and velocity.
I also want to keep the UI minimal for now. Thereās a minimap, but Iām hoping by letting the camera zoom out wide it lessens the need for a minimap.
Inverting colors with shaders is crazy easy too by setting the rgb values back to the inverse of themselves (1- value):
varying vec4 v_color;
varying vec2 v_texCoord0;
uniform sampler2D u_sampler2D;
void main() {
vec4 color = texture2D(u_sampler2D, v_texCoord0) * v_color;
color.rgb = 1.0 - color.rgb;
gl_FragColor = color;
}
and looks pretty cool:
Im trying to keep my media small, playing with export settingsā¦
Great resource for learning shaders:
Hmm, running into some trouble recording sound in OBS on Linux. Itās not picking up desktop audio for some reasonā¦
Summary
I double checked settings in pulse audio control panel. Tried killing and restarting the pulseaudio daemon.
Based on a search I ran this to trouble shoot:
$ pactl list | grep -A2 'Source #' | grep 'Name: .*\.monitor$' | cut -d" " -f2
alsa_output.pci-0000_00_1b.0.analog-stereo.monitor
This is what I had selected but it wouldnāt pick up any audio regardless of which app was playing audio.
Nothing is mutedā¦had to look up sinks vs sources, but not really interested in fighting with this rn.
Based on another search I tried:
rm -f ~/.config/pulse/*
sudo killall pulseaudio
Which was supposed to āreset the settings when pulseaudio starts againā? But this ended up making pulseaudio not want to start at all. Luckily I had the foresight to back those files up. Copied them back and pulseaudio started again. Still no desktop audio.
I gave up digging around all the sound settings and panels. So I just screen recorded on a different machine for now. Maybe ill move this question to the linux help thread. Anywhoā¦
Sound FX!
I wasnāt sure what the asteroids should sound like when breaking apart. Given that sound cannot travel in vacuum of space, I figured why not have fun with it and just threw a sample in to get things started. In this case a single random piano note I exported from Ableton, which happened to be an F3.
Sound f3 = Gdx.audio.newSound(Gdx.files.internal("sound/f3.wav"));
The sound API provides control for volume, pitch and pan. So I randomized the pitch just to get an idea of what it sounds like:
public long asteroidShatter() {
float pitch = MathUtils.random(0.5f, 2.0f);
return f3.play(0.25f, pitch, 0);
}
For collision sounds, I wanted to set the volume of the sound based on the how hard the impact is with the other object.
In the Box2D physics contact listener, there is a postSolve()
event:
- This lets you inspect a contact after the solver is finished. This is useful for inspecting impulses.
Note: there can be multiple impulses, we want the strongest one.
@Override
public void postSolve(Contact contact, ContactImpulse impulse) {
// get highest impulse from impulse resolution
float maxImpulse = 0;
for (float normal : impulse.getNormalImpulses()) {
maxImpulse = Math.max(maxImpulse, normal);
}
if (maxImpulse >= 1) {
float damageThreshold = 15.0f; // impulse threshold at which to apply damage to entity
SoundSystem sound = engine.getSystem(SoundSystem.class);
if (maxImpulse < damageThreshold) {
float volume = maxImpulse / damageThreshold;
sound.impactLight(volume); //light impact with that gets louder with harder impacts
} else {
sound.impactHeavy(); // harder hit sound
}
}
}
(NOTE: postSolve()
is also where I calculate damage from impact between bodies too. This is simplified to focus on sound. Also excluded are some other checks like the if playerās shield is activated at time of impact, you take no damage and the impact is a different sound.)
I know sites like freesound exist, I just prefer to messing around in DAWS. And Iāll make some more sounds later, but for now I actually have a friend who is interested in helping contribute some sounds, which is nice and helps me focus on the code.
Hereās some gameplay destroying asteroids and bouncing around them with the physics. Itās kinda like brick breaker in space:
These sounds arenāt the final pass, some are just place holders while figure out what to do with the sound design/implementation.
At first I had no intention originally of making the asteroids musical, but when I heard the randomized pitch in engine I thought it was kinda funny and kinda neat. Reminds me of amethyst blocks in minecraft.
I really like the result so I am goofing around and experimenting with stepping by 12 from 0.5-2.0.
The pitch range is [0.5f - 2.0f]. Which is half to double frequency. So in theory, we should be able get a range of 24 notes from 1 sample.wav
Or +/- one octave from the source frequency:
lower octave = [0.5 - 0.9?] (eg: 440Hz * 0.5 = 220Hz)
upper octave = [1.0 - 2.0] (eg: 440Hz * 2.0 = 880Hz)
int curStep = 0;
public long ascendingTone() {
// upper octave = 1.0 - 2.0 (eg: 440hz * 2.0 = 880)
float step = 1.0f/12.0f; // = 0.08333
float pitch = 1.0f + (step * (curStep-12));
if (curStep < 12) {
//lower octave = 0.5 - 0.9583? (eg: 440hz * 0.5 = 220)
//step 11 -> 0.5f + ((1/12) * 0.5f * 11) = 0.9583
step *= 0.5f;//scale down 1.0 -> 0.5
pitch = 0.5f + (step * curStep);
}
//increase step
if (curStep++ > 24) {
curStep = 0;
}
return f3.play(0.25f, pitch, 0);
}
This was just quick and dirty, the pitch ratios are not āin tuneā:
Step -> pitch
0 -> 0.5
1 -> 0.5416667
2 -> 0.5833333
3 -> 0.625
4 -> 0.6666667
5 -> 0.7083334
6 -> 0.75
7 -> 0.7916667
8 -> 0.8333334
9 -> 0.875
10 -> 0.9166667
11 -> 0.9583334
12 -> 1.0
13 -> 1.0833334
14 -> 1.1666666
15 -> 1.25
16 -> 1.3333334
17 -> 1.4166667
18 -> 1.5
19 -> 1.5833334
20 -> 1.6666667
21 -> 1.75
22 -> 1.8333334
23 -> 1.9166667
24 -> 2.0
If I wanted to be in tune, could do a little 12-tone stepping calculation scaled by frequency ratio 2^(1/12), not linearly⦠but it sounds neat anyways.
Iāll explore panning to give sounds more spacial information. Sounds to the left should play in the left, and sounds in the right should play in the right. Also some sort of attenuation volume scaling so sounds from far away will be quieter than close sounds.
Thereās a new hit effect when bullets collide with asteroids. Can add more particles later.
The trail left behind the player and behind projectiles ābullet tracersā are a temporary debug tool. It shows path of travel, but with some additional information encoded via color: (engine state, shield state, when took damage, when successful block with shield).
Iāll probably replace this trail with some sort of particle effect trails that fade nicely and help convey the change of velocity to illustrate motion.
Also Iāve learned that MP3 is apparently not a good file format for seamless looping. It clips and cant seem to line up the waveform properly.
So most sounds will probably be WAV going forward.
Cool, I always like to see how people tackle sound design in games!
But I think that piano sample would give me a headache after a few minutes.
AFAIK most sound engines will decode MP3s in blocks, so you canāt start at a specific sample point like with WAV files. Maybe you could work around this by converting it to a WAV at runtime if you still need the reduced size.
Haha, yeah maybe itās a little fatiguing. I just dropped these samples in to get things hooked up for now.
I think the default limit for decoded audio is 1MB. I am not too concerned about file size yet but thatās good to consider. Noted.
I love the sound idea. I would say that I like the dissonant sound better than the dirty sound ratio.
I agree the true random pitch sounds better.
I think the amethyst block sounds from minecraft are quite pleasant so maybe Iāll aim in that more āsparkily gemā feeling. Or I could sample some sounds of rocks or big boulders smashing, idk yet.
I have some ideas for what I want to do with the resources that asteroids drop. I could do the standard:
- iron
- gold
- silver
- copper
- etc, just grab some metals off the periodic table
- gems: ruby,sapphire,emerald,etcā¦
- maybe thereās icy asteroids and we need water?
Perhaps the sound of the asteroid can depend on its type or what resources it drops.
Iām open to ideas.
I realized I havenāt talked much about the gameplay itself yet. Which is probably important, given that it is a game. But first a little history.
I like to start on paper before touching code. Here are some of my old design notes:
Looks like at the time I was debating between either libGDX, slick2D, or lwjgl (which I always have fun trying to pronounce). I wonder if I would have chosen Godot if it existed back then�
Why my own engine?
I started this project in ~2013. My previous project was a juiced up breakout clone in gamemaker 8, and by this time I was working almost purely in gml (game makerās scripting language) because I liked having more control through code than the drag nā drop actions/events.
On the side I also had started a simple tile-based engine based of TheChernoās old engine series: https://www.youtube.com/@TheCherno because I was getting more interested in the lower level underlying technology.
When I had the idea for this game, I knew that some of the features I wanted to implement would probably be much harder to do in gamemaker. I didnāt want to limit my design or ideas based on the the constraints of someone elseās engineā¦
Then I stumbled upon some articles about the āmagic of ECSā and the āevils of OOPā, and I was drawn by the flexibility. I ̶w̶a̶s̶t̶e̶d̶ spent a lot of time reading about and stressing over different design patterns and clean code and code quality. Itās easy to have ideas for features, but how to add them all without making a mess? How do I structure my program as it grows in scope and complexity? It certainly doesnāt help if you like to over-engineer things.
I have found that properly planning what I want to build first before touching code is really helpful.
It also allows me to identify certain problems before running into them during implementation or runtime.
For example: these pages are from a time when I was trying to sort out the some architecture issues. I mapped it out the class hierarchy / project structure to wrap my head around around the dependencies and coupling:
This helped me figure out where/how/why I was using certain objects and simplify the project a little.
A couple re-writes later and here we are⦠Now I have a more pragmatic approach of just keep it simple and follow best practices where applicable.
It is interesting to see what I have been able to implement so far compared to what I had originally planned. Some things have changed overtime, features cut because they were too complex, or didnāt make sense. Sometimes there is a technical limitation in the hardware or the software. Or even dealing with limitations in myself and my own abilities. Other times I am more excited by an idea than the execution itself.
Progress is definitely very slow compared to if had decided to use a full engine like Unity or Godot. But ultimately I am glad I took the time to DIY as much as I could because Iāve learned a lot from it.
Thankfully I also have the freedom to walk away from this project to focus on other things when I feel burnt out or overwhelmed. And that Iām stubborn enough to keep coming back to it from time to time.
Right, so back to gameplay. Right now I have a problem of large empty universe, kinda boring and lonely.
Next up is getting the mining gameplay loop:
- asteroids drop loot when destroyed
- player collects loot
- ship can carry X amount of loot in cargo until full.
- player sells loot space station
Space Station:
- space station orbits star, or planet
- ships can dock at station
At the space station the player can:
- sell loot
- repair ship
- upgrade components on ship:
- more health
- better engine
- etc
- buy new components:
- shield
- hyperdrive for faster travel
- different weapons
- maybe a solar panel so you can recharge/heal when near stars or in direct light path of star (ray trace)
- etc
- buy/sell different ships (out of scope for now: I have some ship classes and types on paper)
Once you have loot and items, you need some flavor of UI/inventory. Iāll draft some stuff on paper but I need to sort out some more details. Again, Iād prefer to keep UI simple and minimal for now. I donāt like complex inventory management systems.
AI is partially implemented but disabled spawning to sort out some other stuff. The idea is AI ships will fly from planet to planet.
AI:
- fly between planets or stars
- can dock at space stations
- can mine asteroids
- passive by default, but will return fire when attacked
Some AI miners flying between asteroids mining locations and space stations. In theory you could be a space pirate, attack another miner to take their loot.
In my original design doc I had planned some sort of economy and trading system. Where resource X would be rarer in system A, than in system Y. And with some travel you can profit. This has always felt out of scope till recently itās coming into view, but I am not sure if thatās even what I want to do anymore or how I want to implement it. I donāt want a really complex UI / inventory system.
Planned Content:
- black hole at the center of the galaxy
- worm holes or some sort of warp gate teleport type thing
- AI battles
- space creatures / bosses
- scripted events / quests?
- landing on planets (probably out of scope, will break down in future post)
While far from complete, Iām forcing myself to make a demo build at the end of the January here so at least I can get some feedback on the controls and feel and people can poke at it. I know I said that last year, but it was really too incomplete and broken then. Iāll see what I can get done in this final week (Iāll be gone this weekend for an ice-fishing trip but Iāll do my best lol)
Iām in this awkward stage where I want to show certain things, and other things simply arenāt ready. But I canāt develop in a vacuum anymore and Iāve already refined some controls for the ships based on some feedback people have given me.
Down the road once I have a more complete gameloop and a little more polish Iāll make an itchio page and start putting builds there.
I feel like Iām finally hitting a turning point where I can start working less on the engine, and more on the actual game itself!
Hey, this is part of the creative process. It is better to get feedback early versus send out a viable product that no one wants, right?!
That must be a great feeling.
Itās an interesting transition. Adding new mechanics and building out the world is usually a lot more fun than some of the other stuff.
For example, sometimes you spend a long time working on something internally in the engine thatās important, but not very interesting work on. And often those under the hood tasks donāt have any obvious impact on gameplay or visually, so it can look and feel like your not making much progress. Those periods can feel slow and be difficult to get though. Especially without a clear goal or plan.
Thatās certainly one way to do this, but itās probably not the best.
For another a better approximation of actual luminosity values, try something like this:
float grey = 0.21 * sample.r + 0.71 * sample.g + 0.07 * sample.b;
As you can see, this is a weighted sum(You method is as well, but all the weight are 0.33. I hope this makes sense to you). And intuitively the green should contribute more to the total luminosity, since our eyes are more sensitive to green light.
(I know the weight add up to .99. I think this is intentional since it maps better to 0-255 without clamping)
Other than that, your game looks very cool. Itās certainly ambitious, but you seem to make great progress. Keep it up!
Yep, makes perfect sense. I can see how green being more visible to our eyes than red is reflected in your weights.
How did you arrive on these specific values?
Also here is what the change looks like in engine:
The previous .33 weight:
With the weights you provided:
Itās certainly darker and blacker overall results. Here is less zoom, less dark more mix:
I didnāt though of these values myself.
Itās a well-known formula, but you can search google for it(keywords: luminosity greyscale shader).
Hereās an article from 2009 comparing some methods: