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ā¦?
I had also wanted at the time some sort of good vs evil system with npcs, which was pretty much cut entirely due to complexity.
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.
(edit: added a few more)
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 itself than the execution.
Progress is definitely 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 cast)
- 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 B. 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 but Iāll do my best)
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. Which is very useful.
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:
Item pick up magnetic/gravity effect prototype.
need to tune the forces a little based on distance.
Using collision filtering to differentiate between inner and outer circles:
Bug while implementing where i used the opposite angle and they were pushed away instead of sucked in:
Welp, here we are. I didnāt quite get everything I wanted in for this demo, but I am pretty happy with progress made the last 2 sprints.
I will keep working on this obviously, but as far as Devanuary goes Iāll cut it off here. This is my official submission:
spaceproject_devember_enginedemo_20230131
There is a requirement to install Java (sorry). I will look into packaging a jvm the with build: Deploying your application - libGDX
If you donāt feel like running unsigned jars from strangers on the internet, source code here: GitHub - 0XDE57/SpaceProject at spaceproject_devember_enginedemo_20230131
Will sort out some better devops stuff later for future builds.
I put a lot of energy into fixing bugs and crashes instead of pushing more features in for this build.
Things that have not made it into this demo that I hoped for:
- space station and docking
- basic lighting / post-processing
- laser and asteroid slicing
- better destruction rules for asteroids
- AI (AI spawning is currently disabled)
Known issues:
- lack of gameplay: this is a basic engine demo
- asteroids make extra pieces sometimes or spawn funny: #2
- drops do not spawn correctly, this is a direct side effect broken origin caused by #2
- magnet/gravity effect for sucking in drops needs tuning as I implemented this only just last night (they just get stuck in orbit around player or whip out passed the player when higher velocity)
- thereās nothing to do with collected drops yet (you will find a count below the health bar of how many you picked up. eventually to be sold at a space station)
- missing sounds
- camera needs work (disabled lerping due to running into some stuttering issues and framing, need to lead target, etc)
- options UI for changing keybindings is really bad and broken
- no in-game tutorial or explanation for controls
- many more: see issues first
- many other things in todo not in issues yet
I currently master everything in a plain text todo file, but its about ~1000 items long and only somewhat organized. So Iām going to experiment with githubās project organizing workspace thingy, and Iām migrating items from my todo into that. Hopefully this tool gives me better organization and planning.
Anywho, here are the controls:
Notes and tips:
- Some controls disabled; features not ready. Will break down in future post.
- frame of reference and sense of scale can be confusing, zoom in and out to get your bearings
- If you are going too fast to stop your ship before ramming into an asteroid, you can activate the shield to safely bounce off.
- If you fly into a star, you can use the shield to protect your ship from burning up.
- Minimap is off by default, M to toggle between [off, corner, full] and supports its own zoom level when mouse over.
- all debug controls and rendering is left in because I think that stuff is interesting so feel free to poke around the debug menu options and have fun.
- NOT LISTED IN CONTROLS: I left a very specific debug control in intentionally: Right-Click will spawn a new asteroid at mouse position. This is for you to play with / abuse / test and wont be part of regular gameplay.
Let me know what you think!
Java gets a lot of undeserved hate. Yes, I am biased.
All of the cool kidz do it thoughā¦ thanks for providing the source code.
Java was one of the first languages I learned after gml and visual basic. I liked that I never had to to care about what operating system the user is running. Which seems to be true of more languages and engines these days but not so much 10 years ago.
I have been tempted to port to c++ ābecause performanceā, but Iām not going to worry about ājava is slowā until I actually hit that wall (if I even do for a simple 2D game like this).
Different tools for different jobs. Iād like to try Rust or Go Jai at some point.
Fixed some bugs. Been pretty busy with work, will try to release update this weekend.