@MoviusC soooo unreal tournament definitely tried terrain maps with their twitch-fps weapons and they were god damned awful lol (Today)

@MoviusC well if it were like a quake map there'd probably be less giant open spaces, or if there were they'd be in… t.co/0LK7FJCbVs (Today)

if PUBG was just like the same concept but a giant quake map and played like quake then I would be dead from playing it for 999999 hours (Today)

@TeddyDief ancient me: "my bloodline will carry out this task for me sometime before the sun consumes our home plan… t.co/T27Mb6a93W (Today)

RT @fell_martins: 💰💎✨ Boys and girls, I'm open for business ✨💎💰 Resposting artwork because most of my stuff is under very secretive NDAs.… (Today)

@RYStorm actually now that I think about it when I get really excited "dude" is one of the first things out of my m… t.co/xjxRg7aZtf (Today)

@dkoontz the brite side (Today)

@MOOMANiBE I grew up in ultra rural upstate new york and somehow I still got it (Today)

when i spend hours on a bug caused by typing x twice instead of x and y t.co/nOkvbJ2XQg (Today)

@NoelFB @RobClemmonsJr coffee totally kills my appetite and I may lean into that more than I should *passes out fro… t.co/QEri4qx8On (Today)

@NoelFB this is a "bad" habit, you say? hmm... interesting... heh heh... *totally not sweating nervously*... (Today)

I've accepted the fact that I'm just going to say "like" 500 times per minute when I'm talking, and that's just, like, how it is. (Today)

@raiganburns yeah something really frustrating about watching a term's meaning totally erode, especially when a ter… t.co/LnabpYVyJQ (Today)

@floatvoid holy poop I havent heard this one yet!! (Today)

@raiganburns seems folks have been using rogue-whatever when they just mean procedural generation for awhile now. (… t.co/yYGOokKJUu (Today)

when are these so called major "esports" teams going to pick up players for link to the past randomizer races?? t.co/mxXI5JRG2X (Yesterday)

@AshBlueWD @ESAdevlog this is legit one of my favorite games of the past couple years. amazingly executed metroidva… t.co/WAQq7r3MQs (2 days ago)

@dannyBstyle Yeah it was an insane disaster and I'm amazed everyone signed on and was like yeah cool this sounds good let's do this (2 days ago)

RT @ESAdevlog: Btw, ESA is 60% off (and OST 30%) this weekend on Steam & Humble Store!! Completely forgot to announce that, whoops https://… (2 days ago)

@dannyBstyle Haha too late. It was... a thing. The original trailer for it was amazing though so I'll just keep watching that. (2 days ago)

follow
search
posts tagged with: starforger

2014 - 11 - 2 / 4:22 pm / general

Index Palette Shader

Index Palette Shader

A few months ago I made and released a game jam game that featured a cool shader based off of Dan Fessler's HD Index Painting tutorial. The idea is to take a normal image and render it with an extremely limited palette. Essentially it's like a game boy shader, and with the help of a dither map texture it actually creates the illusion that there are more colors than there actually are.

Image

The game jam version of the shader was rather clunky, and required the game to manually render a dither texture over the entire screen. Yesterday I spent some time figuring out how to apply the dither directly in the shader itself to make it more general purposed. Here's the entire shader:

#version 130
uniform sampler2D texture; // The main input texture (the screen.)
uniform sampler2D palette; // The palette texture.
uniform float shift; // The shift amount on the palette texture.
uniform float offset; // The offset for the random noise generation.
uniform float screenScale; // The current scale of the screen. (1x, 2x, etc)
uniform vec2 screenSize; // The size of the core game screen (320 x 240)
uniform float noiseAlpha; // The amount of alpha the noise should have.

// A weird way to generate a random number with a vec2 seed.
float rand(vec2 co){
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

void main() {
// The size of the game window.
vec2 screenSizeScaled = screenScale * screenSize;
// The pixel coordinate being operated on.
vec2 pixpos = gl_TexCoord[0].xy;

// Get dither pixel
vec2 overlayCoord = floor(gl_FragCoord.xy / screenScale);
// Get 1 or 0 based on the pixel location.
float overlayPixelColor = mod(overlayCoord.x + overlayCoord.y, 2);
// Dither is black and white every other pixel.
vec4 overlayPixel = vec4(overlayPixelColor, overlayPixelColor, overlayPixelColor, 1);

// Scale the frag position to match the screen scale
vec2 scaledpos = floor(pixpos * screenSizeScaled);
// Adjust the position based on the scale of the screen.
scaledpos -= mod(scaledpos, screenScale);
// Convert back to 0 - 1 coordinate space.
scaledpos /= screenSizeScaled;

// Get base color.
vec4 pixcol = texture2D(texture, pixpos);

// Mix dither texture.
pixcol = mix(pixcol, overlayPixel, 0.1);

// Determine the brightness of the pixel in a dumb way.
float gray = (pixcol.r + pixcol.g + pixcol.b) / 3;

// Round it to the nearest 0.25.
gray = round(gray / 0.25) * 0.25;

// Add some noise.
gray += (rand(scaledpos + offset) * 2 - 1) * noiseAlpha;

// Map the palette to the pixel based on the brightness and shift.
pixcol = texture2D(palette, vec2(gray, shift));

// Multiply through the gl_Color for final output.
gl_FragColor = pixcol * gl_Color;
}


The shader does require a 2d texture for the palette itself. For this game the palette I used was this:

Image

The "shift" uniform in the shader determines the Y coordinate to sample the palette on. A shift of 0 will sample the top most Y, and a shift of 1 will sample the bottom most. You can use this to dynamically change the palette during the game.

The shader needs to have the "screenScale" uniform set to the current scale of the screen. This will make sure that the pixel size is corrected for the dither and the noise. The shader also needs to know the "screenSize" in order for the noise pixels to be the correct size. You can also just set the "noiseAlpha" to 0 if you don't want any of that stuff to show up.

To make the noise change every update the "offset" value should be set to a random float 0 - 1 every update.

Here's what the game looks like without the shader:

Image

And turning on the shader:

Image

Neat!

No Comments

2014 - 9 - 18 / 4:08 pm / general

Game Jam Procedural Generation Part IV

Game Jam Procedural Generation Part IV

The final part of this series about procedural generation for Starforger II will conclude with the last of the level generation code. In the last episode I talked about some of the details in generating rooms, tunnels, and other details in the level. In this final part I'll wrap it up by talking about how I place enemies, breakable blocks, and some final touches on the treasure room.

Image

The next thing in the generation of the level is the breakable blocks. These are blocks that the player can blow up using their bombs. I added these sort of at the last minute of the jam just to give some more interaction with the world, and it felt kinda fun to forge your own path through a big section of breakable blocks.

// put breakable blocks in random places I dunno
for (var yy = 10; yy < grid.TileRows; yy++) {
for (var xx = 0; xx < grid.TileColumns; xx++) {
if (CheckRect(xx, yy, 2, 2)) {
continue;
}
if (Rand.Chance(config.BreakableChance)) {
if (breakables < breakablesMax) {
Scene.Add(new BreakableBlock(xx * 16, yy * 16));
gridBreakable.SetRect(xx, yy, 2, 2);
breakables++;
}
if (config.Width > 1500) {
xx++;
}
if (config.Width > 1000) {
xx++;
}
}
}
}


I actually use a separate grid "gridBreakable" to keep track of where I've already placed blocks. This is less expensive in Otter. The alternative would be to do a collision check against all other breakable blocks which would take longer and longer if there are more breakable blocks being added. Whenever a block is added I add a 2 x 2 rectangle to the gridBreakable grid, and the function CheckRect() will check against the breakable grid and the ground grid, so I can't accidentally place a breakable block in the ground, or overlapping another breakable block. read more

No Comments

2014 - 9 - 12 / 12:49 pm / general

Game Jam Procedural Generation Part III

Game Jam Procedural Generation Part III

In the last episode of Game Jam Procedural Generation I talked a lot about generating the base of the platforming level in Starforger II, and carving out rooms into the ground of the level.

Image

So now we have a basic level that with a bunch of empty rooms below the ground. The next step is going to be connecting those rooms together. To do this I built a quick class called a TunnelSnake (tunnel snakes rule) to dig tunnels from any point on the map to any other point. Here's the full source of that class:

class TunnelSnake {
public int X;
public int Y;
public int Width = 1;
public int Height = 2;

public int EndX;
public int EndY;

int verticalSteps;
int verticalStepMax = 4;
int forceHorizontal = 0;
int forceHDirection = 1;

public TunnelSnake(int x, int y, int endX, int endY) {
X = x;
Y = y;
EndX = endX;
EndY = endY;
}

public void Dig(GridCollider grid) {
while (X != EndX || Y != EndY) {
grid.SetRect(X, Y, Width, Height, false);

if (Rand.Chance(50) || forceHorizontal > 0) {

if (forceHorizontal > 0) {
X += forceHDirection;
Height = 2;
X = (int)Util.Clamp(X, 2, grid.TileColumns - 2);
}
else {
X += Math.Sign(EndX - X);
}

forceHorizontal--;
if (forceHorizontal == 0) {
verticalSteps = 0;
}
}
else {
verticalSteps++;

Y += Math.Sign(EndY - Y);

if (verticalSteps == verticalStepMax) {
forceHorizontal = Rand.Int(3, 15);
forceHDirection = Rand.Sign;
}
}

if (Rand.Chance(50)) {
if (Rand.Chance(50)) {
Width += Rand.Sign;
Width = (int)Util.Clamp(Width, 1, 5);
}
if (Rand.Chance(50)) {
Height += Rand.Sign;
Height = (int)Util.Clamp(Height, 2, 6);
}
}
}
}
}

read more

No Comments

2014 - 9 - 9 / 12:45 am / games

Starforger II

Starforger II

A few weeks ago I went to a local game jam in Phoenix! The them was discovery and I set out to make some kind of space exploration procedural thing. The final result was a game I named Starforger II. There is no Starforger I, but maybe I can make a prequel someday.

Download
Starforger II v1.0 - Windows (92mb)

Whoa what's with the file size? Well this game has a lot of weird sounds in it, and maybe I can figure out how to get them more compressed, but right now they take up a lot of space.

The game uses Enter, X, C, and the arrow keys, or a USB game controller (although the game is designed around the 360 controller, so using one of those would be ideal.)

Screenshots
Image

Image

Image

Image

6 Comments

about

About

Hi! My name's Kyle, and I make video games most of the time in Denver, Colorado. Here you will find my thoughts, games, websites, doodles, and other stuff like that. I worked on Snapshot, Offspring Fling, and a whole bunch of other games. I also created and maintain Otter, a 2d game making framework. If you want to get a hold of me use the form on the bottom of the page, leave a comment, or just tweet at me. I try to post three times a week. Thanks for stoppin' by! You're the coolest.

blog stuff

categories

tags

archives

facebook

videos

Do you want to make a Let's Play of one of my games, or a just a video featuring footage of my games? You have my full permission to do so! Even if you are monetizing your videos, you still have my full permission to use any footage from any of my games. Go for it!

contact

Your message has been sent! Thanks :)
SEND MESSAGE