Have been testing what Microsofts XNA framework can do and am toying with the idea of making some sort of Worms style game. Spent a few minutes today googling on how one can generate the terrain for such a game and found a few pages which explained parts of it but no place really contained any good working examples.
So after spending a few hours with the examples I could find I came up with an algorithm which works pretty well.

Here is an example of what the code generates:

wormsstyleterraininxna

This is example terrain was generated in about 2 second.


Here is the code:

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace TankersTD.Tankers.Tools
{
    class TerrainGenerator
    {
        private double initFrequency, initAmplitude, persistance;
        private int octaves, seed;

        public Texture2D generateTerrain(GraphicsDevice gd,
                int width, int height, double ammountofearth,
                double initFrequency, double initAmplitude, double persistance, int octaves )
		{
			this.initFrequency	= initFrequency;
			this.initAmplitude	= initAmplitude;
			this.persistance	= persistance;
			this.octaves		= octaves;

            seed = System.DateTime.Now.Millisecond;

            Texture2D result = new Texture2D(gd, width, height);
            Color[] cData = new Color[width * height];

            int t_he = 1, t_wi = 1;
            for (int x = 1; x < width*height; x++)
            {
                if (t_wi > width)
                {
                    t_he++;
                    t_wi = 1;
                }
                double val = Function2D((double)t_wi, (double)t_he);
                if (val > (ammountofearth*-1))
                    cData[x] = Color.Black;
                t_wi++;
            }

            result.SetData(cData);
            return result;
        }

        // returns the Perlin Noise value for the given coordinate
        private double Function2D(double x, double y)
		{
			double	frequency = initFrequency;
			double	amplitude = initAmplitude;
			double	sum = 0;
			for ( int i = 0; i < octaves; i++ )
			{
				sum += SmoothedNoise( x * frequency, y * frequency ) * amplitude;

				frequency *= 2;
				amplitude *= persistance;
			}
			return sum;
		}

		private double Noise( int x, int y )
		{
			int n = x + y * 57;
			n = ( n << 13 ) ^ n ;
            return (1.0 - ((n * (n * n * (15731 + seed) + 789221- seed) + 1376312589) &amp;amp;amp; 0x7fffffff) / 1073741824.0);
		}

		private double SmoothedNoise( double x, double y )
		{
			int		xInt = (int) x;
			int		yInt = (int) y;
			double	xFrac = x - xInt;
			double	yFrac = y - yInt;
			double	x0y0 = Noise( xInt    , yInt );
			double	x1y0 = Noise( xInt + 1, yInt );
			double	x0y1 = Noise( xInt    , yInt + 1 );
			double	x1y1 = Noise( xInt + 1, yInt + 1) ;
			double	v1 = CosineInterpolate( x0y0, x1y0, xFrac );
			double	v2 = CosineInterpolate( x0y1, x1y1, xFrac );
			return CosineInterpolate( v1, v2, yFrac );
		}

		private double CosineInterpolate( double x1, double x2, double a )
		{
			double f = ( 1 - Math.Cos( a * Math.PI ) ) * 0.5;
			return x1 * ( 1 - f ) + x2 * f;
		}
    }
}

The code is used like this (the picture above was generated using these input variables):

TerrainGenerator terraingenerator = new TerrainGenerator();
Texture2D ter = terraingenerator.generateTerrain(
        graphics.GraphicsDevice, 2048, 1024, -0.1, 0.0225, .5, 0.05, 1);



Here are a couple of related pages that may interest you:

  1. Project: Blinky – Sound Level Warning
    My office recently moved from a building in which the  rooms were were quite small and only...

Tagged with:
 

2 Responses to Generate Worms Style Terrain, Perlin Noise in XNA

  1. fredrick says:

    I’m also looking for somtehing like this for a upcomming “project”, have yout thought about just generating random circles to make the terrain? Wouldent that be faster?

    • JensB says:

      The thought actually crossed my mind for the exact reason you mention, performance, but after testing it a bit I still went for the Perlin Noise method. When I tried it I actually used ellipses instead of circles and placed them randomly on the texture. Every second ellipse i placed generated terrain and the other removed whatever terrain was under it. It dident look very natural though and you could very much see that it was a bunch of ellipses added and subtracted to get the result.

      This method may take a bit longer but I think its worth it.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>