Jun 212013
 

In an old post I explained how to shoot an object to hit a moving target in 2D. The method in 3D is basically the same, but the code below is much cleaner and might be simpler to understand even for the 2D case.

Unity3D example and source code

Unity webplayer example

Unity project

The interesting bit of C#:

private Vector3 FindInterceptVector(Vector3 shotOrigin, float shotSpeed,
    Vector3 targetOrigin, Vector3 targetVel) {
   
    Vector3 dirToTarget = Vector3.Normalize(targetOrigin - shotOrigin);
   
    // Decompose the target's velocity into the part parallel to the
    // direction to the cannon and the part tangential to it.
    // The part towards the cannon is found by projecting the target's
    // velocity on dirToTarget using a dot product.
    Vector3 targetVelOrth =
    Vector3.Dot(targetVel, dirToTarget) * dirToTarget;
   
    // The tangential part is then found by subtracting the
    // result from the target velocity.
    Vector3 targetVelTang = targetVel - targetVelOrth;
   
    /*
    * targetVelOrth
    * |
    * |
    *
    * ^...7  <-targetVel
    * |  /.
    * | / .
    * |/ .
    * t--->  <-targetVelTang
    *
    *
    * s--->  <-shotVelTang
    *
    */

   
    // The tangential component of the velocities should be the same
    // (or there is no chance to hit)
    // THIS IS THE MAIN INSIGHT!
    Vector3 shotVelTang = targetVelTang;
   
    // Now all we have to find is the orthogonal velocity of the shot
   
    float shotVelSpeed = shotVelTang.magnitude;
    if (shotVelSpeed > shotSpeed) {
        // Shot is too slow to intercept target, it will never catch up.
        // Do our best by aiming in the direction of the targets velocity.
        return targetVel.normalized * shotSpeed;
    } else {
        // We know the shot speed, and the tangential velocity.
        // Using pythagoras we can find the orthogonal velocity.
        float shotSpeedOrth =
        Mathf.Sqrt(shotSpeed * shotSpeed - shotVelSpeed * shotVelSpeed);
        Vector3 shotVelOrth = dirToTarget * shotSpeedOrth;
       
        // Finally, add the tangential and orthogonal velocities.
        return shotVelOrth + shotVelTang;
    }
}

Update:

If you want to find the point where they meet, you can calculate the time it will take, and then multiply the shot velocity by that. In practice they will collide sooner since they have a certain radius, but we can take that into account when we calculate the time.

// Find the time of collision (distance / relative velocity)
float timeToCollision = ((shotOrigin - targetOrigin).magnitude - shotRadius - targetRadius)
        / (shotVelOrth.magnitude-targetVelOrth.magnitude);

// Calculate where the shot will be at the time of collision
Vector3 shotVel = shotVelOrth + shotVelTang;
Vector3 shotCollisionPoint = shotOrigin + shotVel * timeToCollision;
Feb 222012
 

I needed a profanity filter for the highscores in an app I made, but I couldn’t find anything free that worked the way I wanted, so I made a simple one myself. It’s pretty basic but someone might have use for it.

You need a list of lowercase words to filter for. The one I used is far too big to paste here, but you can find one by searching for “bad word list”.

private static const badWords:Array = ["lots","of","bad","words"];
// Returns a profane word if found, else ""
static public function checkName(text:String):String {
  text = text.toLowerCase();
 
  for (var i:int = 0; i < charReplacements.length; i++ ) {
    var ra:Array = charReplacements[i] as Array;
    text = strReplace(text, ra[0], ra[1]);
  }
 
  for each (var w:Object in badWords) {
    if (text.indexOf(String(w)) != -1) {
      return String(w);
    }
  }
  return "";
}

The function will detect character sequences that look like some other character, to make it harder to bypass the filter. For example, 1 becomes i, û becomes u, |\| becomes n etc.
In this way “Fuc|<” would be detected for instance. The sequence replacements can even be used to identify inappropriate symbols like “(.)”, by converting them to (in)appropriate words if you like. :)

private static const charReplacements:Array = [["@", "a"], ["0", "o"], ["1", "i"],
  ["2", "r"], ["3", "e"], ["4", "a"], ["5", "s"], ["7", "t"], ["8", "b"],
  ["9", "g"], ["|<", "k"], ["|\/|", "m"], ["|\|", "n"], ["ä", "a"], ["ã", "a"],
  ["â", "a"], ["ä", "a"], ["á", "a"], ["à", "a"], ["å", "a"], ["é", "e"],
  ["è", "e"], ["ë", "e"], ["ê", "e"], ["§", "s"], ["$", "s"], ["£", "l"],
  ["€", "e"], ["ü", "u"], ["û", "u"], ["ú", "u"], ["ù", "u"], ["î", "i"],
  ["ï", "i"], ["í", "i"], ["ì", "i"], ["ÿ", "y"], ["ý", "y"], ["ö", "o"],
  ["ô", "o"], ["õ", "o"], ["ó", "o"], ["ò", "o"], ["(.)","boob"]];

You will also need this helper function for string replacement:

// Helper that replaces all "find" with "replace" in the given input string
public static function strReplace(input:String, find:String, replace:String):String {
  while (input.indexOf("find") != -1)
    input = input.split(find).join(replace);
  return input.split(find).join(replace);
}

It works quite well, let me know if you found it useful or have any suggesstions.

Sep 072011
 

I’m have been working on Coin Runner since Ludum Dare 21. Here is a screenshot of how it looks at the moment, although a lot of it is still placeholder art. As you can see, there are now achievements.

It plays a lot better than the compo version!

There’s also lot’s of new items and skills you can buy. More info coming soon!


 Posted by at 03:32
Jul 252011
 

Ludum Dare 20 was almost three months ago, and I have been working on a new version of my game The World Above every now and then.

The original game had a lot of flaws. There was only one level, you couldn’t move for a few seconds when you collided which was very frustrating, the resolution was way too high making it unplayable on smaller screens, if you ran out of fuel it was a chore to continue playing as you fell and crashed over and over, and it just suffered from a general lack of playtesting.

Even though there was many problems, I feel like there is a good game in there. I’m especially happy with the controls and movement of the submarine, and I want to get it closer to it’s potential. Due to work over the summer, progress is slow, but I have fixed most of the problems in the LD version, added some new features such as time powerups and mines and replaced many of the rushed sprites with shiny new ones. There are now multiple levels instead of the huge single level, and the tiles in the level are now about half of the original size. (can’t remember why I made ’em so huge!)

New animating title screen

Continue reading for more info and screenshots.

Continue reading »

Jul 022011
 

Someone recently wondered how to pick a color of a pixel from the screen in as3. If you have a bitmap image you can simply grab the color value using BitmapData.getPixel(). But if you want to capture a pixel color value in the stage as the user sees it, including vector graphics, you need another technique.

The way I found was to make a 1×1 bitmap, and then drawing the stage to the bitmap using a translation matrix for the offset. The result is then in the single pixel of the bitmap.

public function pickColorFromStage(x:int, y:int):uint {
   var bmd:BitmapData = new BitmapData(1, 1, false, 0x000000);
   var matrix:Matrix = new Matrix();
   matrix.translate(-x, -y);
   bmd.draw(stage, matrix);
   return bmd.getPixel(0, 0);
}
 Posted by at 13:14
Jun 262011
 

I have made it possible to load/save presets as base64 strings, so that people can share brush presets easily. I used this lib for as3: base64-optimized-as3-lib. The nice thing about this is that the presets are text strings, and can be posted in comments, shared by mail or IM, or any other kind of text communication. The base64 string represents a serialized flash Object-object, storing key-value pairs for each setting, so it should be possible to make presets specifying just some of the settings, while leaving the rest, although in this version all the settings are stored.

You can save the base64 string in a text document at the moment as it’s not possible to save them in the application, but I have added some hard coded presets you can try using the numbered buttons. (they can be accessed with keys 0-9 aswell)

Presets window

To open the preset window, click Presets in the panel or press P. To make a base64 string for your brush, click “Generate base64”, and copy the text. To use a base64 brush that someone sent you, just paste it in the text area and click “Load from base64”.

Open FloralParticles 0.45

You can share presets in the comments below if you want. I might even add good ones as standard presets in the application. :)

 Posted by at 19:03
Jun 222011
 

Some of the new features:

  • Improved line rendering
  • Color mixing
  • Multi-step undo/redo
  • Fade-To-Color setting
  • Save to PNG (lossless and faster)
  • Background vignette (toggleable)
  • Fullscreen mode
  • Mouse smoothing
  • New spawner behaviours
  • Opacity setting, global and fading per particle

Open FloralParticles 0.4

Any suggestions or feedback are welcome, just post a comment below.

Floral Particles 0.4

 Posted by at 00:18
Jun 212011
 
floralparticlesPNG4

I’ve been adding a lot of new features, including a new line rendering method using polygons which looks much better than just using line drawing in flash. That enabled the neat “tire track” effect you can see in the first image, by using a negative bias for first edge the polygons.

Also added is an opacity slider, speed multiplier, a bunch of new controls for the brush behaviour, a color mixing slider which makes the particles pick up the colors from the canvas and a bunch of other stuff. It’s a lot of fun!

A runnable is coming soon.

Continue reading »

 Posted by at 01:12