Jump to content
  • entries
    13
  • comments
    2
  • views
    1353

Dev Blog #02 – Smoothing a path for Terrator

Sign in to follow this  
RoKabium Games

534 views

The last week we’ve been implementing a new enemy in “Something Ate My Alien” called “Terrator”.

He’s much larger than the other enemies, and he’s a worm like creature that we wanted to randomly appear, work its way across the screen and ‘Eat’ our alien if he gets in the way.

Kat created the art, and split it up into sprites for each of the ‘worm’ sections, head, body and tail.

Game-SAMA-Something-Ate-My-Alien-Rokabiu

We didn’t want to create a random path as it was moving, because we wanted more control over him. So we decide to plan out a batch of paths that he should follow and then just pick one at random during spawn. To mix things up a bit, the path should be offset by a random number of pixels, and his start position relative to the path should also change. We also allowed it to be ‘flipped’ randomly to create more variation.

We planned out a path with about 15 or so points, and then used a smoothing algorithm called “Chaikin’s Algorithm” to create a smooth path.

Chaikin is nice and quick, not 100% accurate though, because of the way it works, the result doesn’t pass through the original points, but its good enough for what we needed it for.

Game-SAMA-Something-Ate-My-Alien-Rokabiu

It works by ‘cutting corners’ off each point to create a more smoothed curve, and then repeating 3 or 4 times makes it get smoother and smoother. We found 4 times was good enough to make Terrator animate smoothly in the game.

I found a C# example which helped, here: C# Smoothing Path

Although it was a quick algorithm, the implementation I found actually created quite a bit of C# Garbage, so I looked into re-writing it to remove any Garbage.

Now, rather than creating a new array on every smooth pass, you can pre-create an big array, and then it fills in that one array.

So now it was generating zero Garbage during game play. Yay!!

Game-SAMA-Something-Ate-My-Alien-Rokabiu

And as a bonus, with a bit of extra tweaking, I got it to process faster also. For 15 original points and smoothing 4 times, the original routine took about 1.22ms and allocated 3.3kb of Garbage. My new one took 1.05ms and allocated none.

Here is a video clip of it in game:

Here is the barebones C# code I wrote for Unity, to generate the smooth curve if anyone else might find it useful:

// Setup smooth info
int smoothness = 4;
int NumMainPoints = 15;
Vector2[] smoothPoints = new Vector2[(NumMainPoints - 2) * (int)Mathf.Pow(2,smoothness) + 2];

Vector2 startpoint = new Vector2(25,50);
Vector2 centerPoint = new Vector2(50,50);

smoothPoints[0] = startpoint;
smoothPoints[1] = startpoint + new Vector2(8,0);
smoothPoints[2] = startpoint + new Vector2((8 + 2),0);
smoothPoints[3] = centerPoint + new Vector2(-6.0f, 0.5f);
smoothPoints[4] = centerPoint + new Vector2(-2.0f, -1.5f);
smoothPoints[5] = centerPoint + new Vector2(1.5f, 0.5f);
smoothPoints[6] = centerPoint + new Vector2(5.0f, -2.5f);
smoothPoints[7] = centerPoint + new Vector2(2.5f, -5.5f);
smoothPoints[8] = centerPoint + new Vector2(-3.0f, -3.0f);
smoothPoints[9] = centerPoint + new Vector2(-4.5f, -0.5f);
smoothPoints[10] = centerPoint + new Vector2(-2.5f, 2.0f);
smoothPoints[11] = centerPoint + new Vector2(1.5f, 2.5f);
smoothPoints[12] = centerPoint + new Vector2(5.0f, 2.0f);
smoothPoints[13] = centerPoint + new Vector2(9.0f, 2.5f);
smoothPoints[14] = centerPoint + new Vector2(150, -0.5f);

ChaikinFast(ref smoothPoints, smoothness, NumMainPoints);

private void ChaikinFast(ref Vector2[] smoothPoints, int smoothness, int NumMainPoints) {
    Vector2 lastVector = smoothPoints[NumMainPoints - 1]; // Save last point
    int p = NumMainPoints - 2;
    int factor = 2;
    int lastPoint;
    Vector2 offsetRight, offsetLeft;

    // Loop through mulitple times to smooth
    for (int s=1; s<=smoothness; s++) {
        lastPoint = (NumMainPoints - 2) * factor;
        offsetRight = (smoothPoints[p+1] - smoothPoints[p]) * 0.25f;

        // For each point, replace with 2,
        // with each one being 25% more towards the left and right points
        for (int n=lastPoint; n>1; n-=2) {
            offsetLeft = (smoothPoints[p] - smoothPoints[p-1]) * 0.25f;
            smoothPoints[n] = smoothPoints[p] + offsetRight;
            smoothPoints[n-1] = smoothPoints[p] - offsetLeft;
            offsetRight = offsetLeft;
            p--;
        }

        // Prepare for next loop
        p = lastPoint;
        smoothPoints[p+1] = lastVector; // Copy the end point to the end
        factor *= 2;
    }
}

 

View the full article

 

Sign in to follow this  


0 Comments


Recommended Comments

There are no comments to display.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement
  • Advertisement
  • Blog Entries

  • Similar Content

    • By sausagejohnson
      Last week, support was added to Orx for gamepad controller mapping as well as half-axes, analog thresholds and stick/button/trigger controls remapping.
      This is made possible by utilizing the SDL Game Controller Database initiative in order to standardize controller sticks and buttons.
      What this means for games is that no matter what type of controller you plug in, JOY_LX_1 means the X axis on the Left Stick of the first controller. This is much better than the previous JOY_X_1 which meant the same thing, but no guarantee which stick on your controller this would be. This greatly removes the need for creating a re-mapper screen to your games (though still good for convenience).
      An example of use would look like the following. Firstly the config:
      [MainInput] JOY_LX_1 = LeftRight Then in code:
      if (orxInput_IsActive("LeftRight")) {     orxFLOAT x = orxInput_GetValue("LeftRight");     //do something } There are a number of joystick tutorials that cover the new features.
    • By Masterbuiler64
      Good Morning, Afternoon, or Evening,
      My name is Dalton Potter and I am a budding game developer looking to learn skills and develop a beautiful project me and my friend came up with a year ago or so and have refined ever since. The idea is a basically a mix of Final Fantasy and Zelda in terms of exploration and battle, but will throw in its own unique features to switch things up a bit. What we have in place so far is the main story and many connecting character back stories, a map of the over world (still not 100% confirmed however), how some of the main characters look (also not 100% confirmed), a few battle and puzzle mechanic ideas, general story progression, locations, a few beta music tracks, and lore. What we lack however is any solid assets or work done on it as neither of us have any expertise in game development, but have both unanimously agreed that this idea is too good to forget and pass up.
      We are currently looking for people to help us work on the project as time goes on and maybe, just maybe, it may grow into a full blown team of people working on a game and eventually sell it on Steam or other client services. Any replies to this topic will be read as soon as possible depending on my schedule. I have also attached a couple photos and sound files of some design concepts we have. I also have a Pastebin made of the entire story and main character back stories, as well as history into how the idea came to be, though I'll let the Pastebin be requested as needed in the future.
      Hopefully this project turns from being just an idea into something amazingly beautiful and playable......it just needs to be created that's all.....
      Thank you in advance,
      Dalton Potter
      P.S. The sound file, "Power and Prestige" is a song that sounds as though it could be used as a trailer theme, and "Curiosity" sounds as though it could be used on a farm at sunrise.
      Source of music was from YouTube, but the groups official site is as follows: http://floatingcloud.net/
       
      EDIT: I am adding in a link to the pastebin so those that view this can get look at the story for the game. Link: https://pastebin.com/U7dKp8PS

      Floating Cloud - Power and Prestige.mp3

      Floating Cloud - Curiosity.mp3

    • By BlackSpoon
      Hi guys, let me introduce my new project - Just Smash It! It's all about destruction! Break your way smashing objects with aimed shots!
      * Realistic physics of destruction
      * Smooth game flow
      * Pleasant graphic and sound design
      * Infinite mode after passing the basic set of levels
      * Small size, great time-killer!
      Play Market: https://play.google.com/store/apps/details?id=com.blackspoongames.smashworld
      Feedback are welcome!
    • By Seer
      I have programmed an implementation of the Separating Axis Theorem to handle collisions between 2D convex polygons. It is written in Processing and can be viewed on Github here. There are a couple of issues with it that I would like some help in resolving.
      In the construction of Polygon objects, you specify the width and height of the polygon and the initial rotation offset by which the vertices will be placed around the polygon. If the rotation offset is 0, the first vertex is placed directly to the right of the object. If higher or lower, the first vertex is placed clockwise or counter-clockwise, respectively, around the circumference of the object by the rotation amount. The rest of the vertices follow by a consistent offset of TWO_PI / number of vertices. While this places the vertices at the correct angle around the polygon, the problem is that if the rotation is anything other than 0, the width and height of the polygon are no longer the values specified. They are reduced because the vertices are placed around the polygon using the sin and cos functions, which often return values other than 1 or -1. Of course, when the half width and half height are multiplied by a sin or cos value other than 1 or -1, they are reduced. This is my issue. How can I place an arbitrary number of vertices at an arbitrary rotation around the polygon, while maintaining both the intended shape specified by the number of vertices (triangle, hexagon, octagon), and the intended width and height of the polygon as specified by the parameter values in the constructor?
      The Polygon code:
      class Polygon { PVector position; PShape shape; int w, h, halfW, halfH; color c; ArrayList<PVector> vertexOffsets; Polygon(PVector position, int numVertices, int w, int h, float rotation) { this.position = position; this.w = w; this.h = h; this.halfW = w / 2; this.halfH = h / 2; this.c = color(255); vertexOffsets = new ArrayList<PVector>(); if(numVertices < 3) numVertices = 3; shape = createShape(); shape.beginShape(); shape.fill(255); shape.stroke(255); for(int i = 0; i < numVertices; ++i) { PVector vertex = new PVector(position.x + cos(rotation) * halfW, position.y + sin(rotation) * halfH); shape.vertex(vertex.x, vertex.y); rotation += TWO_PI / numVertices; PVector vertexOffset = vertex.sub(position); vertexOffsets.add(vertexOffset); } shape.endShape(CLOSE); } void move(float x, float y) { position.set(x, y); for(int i = 0; i < shape.getVertexCount(); ++i) { PVector vertexOffset = vertexOffsets.get(i); shape.setVertex(i, position.x + vertexOffset.x, position.y + vertexOffset.y); } } void rotate(float angle) { for(int i = 0; i < shape.getVertexCount(); ++i) { PVector vertexOffset = vertexOffsets.get(i); vertexOffset.rotate(angle); shape.setVertex(i, position.x + vertexOffset.x, position.y + vertexOffset.y); } } void setColour(color c) { this.c = c; } void render() { shape.setFill(c); shape(shape); } }  
      My other issue is that when two polygons with three vertices each collide, they are not always moved out of collision smoothly by the Minimum Translation Vector returned by the SAT algorithm. The polygon moved out of collision by the MTV does not rest against the other polygon as it should, it instead jumps back a small distance. I find this very strange as I have been unable to replicate this behaviour when resolving collisions between polygons of other vertex quantities and I cannot find the flaw in the implementation, though it must be there. What could be causing this incorrect collision resolution, which from my testing appears to only occur between polygons of three vertices?
      Any help you can provide on these issues would be greatly appreciated. Thank you.
    • By Rio Lloyd
      Hey all!
      we are a team of 3 looking for more members, 
      we are making an isometrical Survival RPG.
      we are looking For Members who can make low poly 3D artists who can do character models, environments, tools and more.
       
      if interested and want to know more email me at rioishere14@gmail.com
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!