[Devember 2022] a space project | open source space game

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.

1 Like

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.

2 Likes

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 RGBA8888RGBA4444

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:

3 Likes

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.

4 Likes

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. :sweat_smile:

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.

2 Likes

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.

3 Likes

I love the sound idea. I would say that I like the dissonant sound better than the dirty sound ratio.

2 Likes

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.

1 Like

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:

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!

2 Likes

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.

2 Likes

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! :stuck_out_tongue:

1 Like

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: