Don’t be a wheel in the rut

Over the course of my professional career I have witnessed at least one “wheel in the rut” problem at every job. Typically the subject of the observation is an employee who has been working at the company for some time - at least 4 years - and has a mid-tier or senior position. The result of this problem is a vicious cycle of poor quality in and poor quality out, whereas an employee not in the rut will take poor quality in and produce high quality out that eventually removes traces of the sub-par. I’ve often wondered what exactly leads to this dilemma and I have come up with some possibilities.

Lack of motivation. This is a symptom of all such people I have observed and it seems to stem from the fact that even if they did produce good work in pieces over time, it eventually gets engulfed in the larger system that is still composed of poor quality and poor practices. If we take a single page as an example, perhaps they rewrite a large portion of the page so it contains sound code and quality. They commit the code and feel pretty code about doing the right thing. Then other people get their hands on it and because they are not properly trained or there is not oversight, it slowly gets pulled apart. Once this code loses context it just becomes apart of the greater awfulness. As a developer, you cannot possibly endure this year after year without it having an impact on your mentality. It can lead to disgust and general apathy, but more importantly, our subject will just lose interest in producing good code because it will eventually become crap.

Constant changes. Another common source of the dilemma is when the upper management constantly shifts directions and imposes urgent features upon their trusted employees. Say our subject actually was working on a very good code base for a feature but halfway through the focus shifts to something different or the project is scrapped entirely. At some point these constant interruptions will weigh in your decision to even bother going after a sound code-base because in the end it will probably not even matter.

Skill levels of co-workers. If you are surrounded by people who have a completely different mindset and working knowledge than you, then it will probably be frustrating to convey important concepts without sounding like a naysayer or disgruntled. We all know it can be extremely difficult to disagree with someone in a dignified manner, especially for developers since a lot of developers do not have the background in personal interactions to avoid conflicts. As a result the subject might just do things their own way without letting anyone know or purposefully close off areas of code so that they can do the changes their own way.

Nothing exciting. After years of doing the same thing in the same company on the same foundation, it can get boring. This is something that can have large effects on the mood and general happiness of our subject and if they do not find ways to challenge and expand then they will never be fulfilled after the first couple years.

So how can you avoid becoming stuck in this rut? It’s pretty simple actually: challenge yourself, learn something new, teach those around you and over sound plans to change the things you don’t like. Yes you might be met with some push back but after you successfully implement these changes you will be seen as someone who cares deeply and is helping to shape the company’s future - not relive the company’s past.

Things I’m looking forward to in the next decade

Technology has come a long way and the rate of both proliferation and adoption is seemingly exponential. There have been a huge amount of changes in just 10 years if you look back to 2002 and what your daily life involved. As such here are some areas I am looking out for and cannot wait until I see advancements in.

  1. Alternate mobile devices. The advancement of mobile in the last decade is astounding. From simplistic phones that are capable of texting and phone calls to full-featured computers capable of more than some computers! That trend is very important as the power of technology is now available everywhere and there are virtually no impediments to information. The next evolution of this trend will naturally be in devices that are attached in some way to your body. I see this being primarily in the glasses/contacts area since that will have the greatest benefit but I could be surprised as well. Think about the possibilities and power of having augmented reality at all times of the day. I think it’s certainly feasible to have this TODAY except for the advancements in optics that would be required for such a feat. Having auto-recognition of foreign things, the social aspect, mapping and planning, zooming, photos etc… All of this would be fascinating. Of course that also brings in the other side of advertising and privacy but that will always be an issue.
  2. 3d printing. This technology is amazing. At the very heart of the idea is that you purchase a machine capable of building other machines or objects. So if you have a generic block of material you can “print” a coffee cup. This has so much potential it’s mind blowing. You can use this technology to replace broken parts on virtually anything you own. Missing tools? No problem. Print the toolset to assemble that piece. I foresee a huge shift in product development towards having companies provide raw materials and kits instead of actual products. This would be pretty beneficial to everyone since manufacturing costs would bottom out and you’d be paying for schematics and raw materials instead. 
  3. Nanotechnology. I’ve been interested in this for a while but haven’t seen a ton coming out of the research which is a little bit disheartening. There are so many applications for nano-scale devices that the transformation that would cause in our lives would be huge. Everything from medicine to manufacturing would be affected and mostly for the better. Everything could get smaller and have a greater control over interactions at the smallest of scales.
  4. Automobiles. Google is working as we speak on self-driving cars and that will have a HUGE impact on our lives. Less accidents, less traffic, less pollution and more ability to concern yourself with more important items. The whole of the automotive industry would be upended which should eventually lead to far more efficient cars since the protective items could eventually go away as accidents are few and far between.
  5. Exploration. There are a few private firms taking on the challenge of space which should eventually lead to the move into space. It’s something that will still take a millennium to really come to fruition but in the mean time it’s exciting to see what can happen when smaller companies fight for dominance. The benefits here should be pretty obvious. 
Easier menu management for AndEngine

I wanted to make creating menus a little bit easier for myself so I created a chainable menu class that mimics float, padding and brs (similar to CSS conceptually). You can find the classes and an example at:
https://github.com/methodin/FlowMenu
An example of the menu would be:

// Create our menumenu.init()    .add(rect)    .br(90, true)    .container(FlowMenu.CENTER)        .container(FlowMenu.CENTER)            .add(options.statusText)        .end()        .br(40)        .container()            .add(new Text(0, 0, font, “Score:”),250)            .add(options.scoreText)            .br()            .add(new Text(0, 0, font, “Splits:”),250)            .add(options.splitsText)        .end()        .br(40)        .container(FlowMenu.CENTER)            .add(nextMenuItem)        .end()    .end();

Easier menu management for AndEngine

I wanted to make creating menus a little bit easier for myself so I created a chainable menu class that mimics float, padding and brs (similar to CSS conceptually). You can find the classes and an example at:

https://github.com/methodin/FlowMenu

An example of the menu would be:

// Create our menu
menu.init()
    .add(rect)
    .br(90, true)
    .container(FlowMenu.CENTER)
        .container(FlowMenu.CENTER)
            .add(options.statusText)
        .end()
        .br(40)
        .container()
            .add(new Text(0, 0, font, “Score:”),250)
            .add(options.scoreText)
            .br()
            .add(new Text(0, 0, font, “Splits:”),250)
            .add(options.splitsText)
        .end()
        .br(40)
        .container(FlowMenu.CENTER)
            .add(nextMenuItem)
        .end()
    .end();

Managing SQLite databases in Android

https://github.com/methodin/Android-DB

Android is great for many things but straight out of the box, managing SQLite queries and connections is anything but straightforward. After many hours of searching and digging I finally managed to piece together a few helpful classes - after learning some painful lessons.

One of the most important classes you will need to familiarize yourself with is SQLiteOpenHelper (DBHelper in the github source below). For our purposes we extend this class and take advantage of two main functions: onCreate and onUpgrade.

OnCreate is the first event you will be dealing with when using SQLite. This function prepares the database structure for the first time it is ever instantiated from an Application. The first time. This is very important as this function is only ever called once unless you destroy the file/db structure. You should plan out your tables as much as you can before using this function or be aware that you will have to clear data for your application in order to get this called again. Inside this function you will just need to call database.execSQL for however many tables you need to create.

The next function you will have to deal with is onUpgrade. This function is executed whenever Android notices a difference between the current version and the version currently defined in the code (DB_VERSION). So if our original version is 1 then we post an update to the market with DB_VERSION defined as 2, Android will see this difference on any device with the older version and execute the onUpgrade function.

In this function you will need to log all of the changes that correspond to that particular version. So if you need to add a column from version 1 to 2, you’d have to check to see if the new version is 2, and if it is, execute an ALTER TABLE command. I haven’t been able to determine if Android will execute onUpgrade multiple times if they are multiple versions behind, but I doubt it, so in the version I have hear I run the updates if the oldVersion if less than the new version instead of checking for equality.

Now that we have the structures taken care of we now have to actually work with  queries. To do this will be wrapping some of the basic SQLite functions into a DB class that will provide us with some common operations. For every table we have in the system we will be creating a TableDB class (UsersDB for users etc…). This class will expose a static String variable for every column in the table and we assume we always use “id” for the primary key.

We start the class exposing some of the basic Transaction methods, which is pretty straightforward. I don’t have an easy way to handle failure (rollback) but I will leave that as an exercise for you. We then define the CRUD functions which is also straightforward. One note here is that the Update method uses the ContentValues class in addition to a HashMap for extra flexibility. You could do the same for the other CRUD methods.

Finally we define a set of fetch, fetchOne functions that should be self-explanatory. These except varying parameters. For fetch, no parameters will return all rows, conditions would be a flat WHERE clause that doesn’t need to be escaped and String,String[] conditions for a WHERE clause with question mark placeholders and an array of values to escape and replace using data sanitation. The fetchOne functions are quite similar except the basic function accepts a row ID.

Straight out of the basic you can get away with creating skeleton classes that extend DB but for more advanced purposes you will probably want to override at least one of these methods to handle for advanced tasks, or even edit them completely to fit your needs. While not perfect this is at least a helpful addition to the chaos that is SQLite on Android. 

Simple cron script in Node and Coffee

I needed a simple way to handle crons when working with Node so I decided to quickly whip up a function that allows me to verbally add in cron entries into a single script and just run that script every minute. 

This allows you add cron entries like:

run.attempt('every 1 minute', () ->
    lock.check('one', (conflict) ->
        return false if conflict
// Do something

Right now I just coded in minutes and hours but doing the rest is pretty trivial.

I can’t remember where I got the lock file script but if I find the source I’ll give credit.

Setting sprite animation direction along a Path Modifier in AndEngine

So you are using the sweet PathModifier functionality in AndEngine and it’s working great but you realize that you want to get a little more complex and show your animating sprite in different directions depending on the direction the sprite is traveling along the path. For the demo purposes here we only have 4 directions (up, down, left, right) but it could be easily extended to have 8 or even 16 directions depending on how detailed you want to make your sprites. So we’ll assume you have your PathModifier already but you need to add a IPathModifierListener:

pathModifier.setPathModifierListener(new IPathModifierListener() {
  @Override
  public void onWaypointPassed(PathModifier arg0, IEntity arg1, int waypoint) {
    final float[] xs = arg0.getPath().getCoordinatesX();
    final float[] ys = arg0.getPath().getCoordinatesY();        
    if(waypoint <= xs.length-2) {
      final float xCur = xs[waypoint];
      final float yCur = ys[waypoint];
      final float xNext = xs[waypoint+1];
      final float yNext = ys[waypoint+1];
      double angle = Math.atan2(yCur-yNext, xNext-xCur);
      angle = (angle* 180 / Math.PI);
      if(angle >= 45 && angle <= 135) {
        direction = DIRECTION_UP;
      } else if(angle >= 135 && angle <= 225) {
        direction = DIRECTION_LEFT;
      } else if(angle >= 225 && angle <= 315) {
        direction = DIRECTION_DOWN;
      } else {
        direction = DIRECTION_RIGHT;
      }
      changeDirection();
    }
  }
});

So here we are calculating the angle between the point just passed and the next set of points along our path using the atan2 function. Since this gives us radians we have to convert to degrees to make our life easier. Once we have the angle we can just figure out which animation we want by mapping quadrants to directions. Simple.

My changeDirection function just takes the direction number (0 through 4) and calls the animate function on my sprite and sets the start index to direction*4 and the end index to (direction*4)+3.

My sprite has 4 rows of 4 columns. Each row is a different direction so I just mapped the value of all the DIRECTION integers to the row in my AnimatedSprite.

// Animates the sprite towards the new direction
public void changeDirection() {
  sprite.animate(ANIMATION_DEFAULT, direction*4, (direction*4)+3, true);
}

And finally my ANIMATION_DEFAULT is just an array of durations per each frame in my animation (I have 4 frames per direction):

long[]{200,200,200,200}

A more useful touch class for andengine

Andengine is a great library for game development and for the most part it makes my life much easier. One particular pain point, however, is touch events. There are numerous helpers to handle this but the default behavior is that all touch events registered respond to all touch events in that area. So if you have a hidden button beneath a visible button the chain might be:

  • Show button touch event gets called
  • Hidden button touch event gets called
  • Scene touch event gets called

Which in almost every case is not desirable. In my game I more or less want to disable event bubbling and automatically not respond to events if the item is hidden. For that I created a new class called TouchHelper that takes the place of the default touchevent handler and gives us this behavior by default. You can enable/disable bubbling and it will respect the visible flags so an invisible item cannot be touched. In my game I use it by first instantiating it under my GameOptions class and then in my main scene onSceneTouchEvent I call:

@Override
public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
  if(!options.touch.onTouched(pScene, pSceneTouchEvent))
  {
    // No other items were touched so fall back to the default action - e.g. dragging the scene around
  }

In other words, the TouchHelper class will first see if any sprites were touched and if not you can just fall back to a generic action like dragging the scene around (or do nothing). This makes my life significantly easier since now I don’t have to track what I touched while dragging etc… 

The class is defined below

public class TouchHelper {
  // An array list of listeners
  private final HashMap<Sprite,TouchObject> listeners = new HashMap<Sprite,TouchObject>();
  //private final ArrayList<TouchObject> listeners = new ArrayList<TouchObject>();
  // Keep track of the last item touched
  private TouchObject lastTouched = null;
  // The game options
  private final GameOptions options;
 
  public TouchHelper(GameOptions pOptions) {
    options = pOptions;
  }
 
  // Adds a new listener to our array
  public void registerListener(Sprite pEntity, boolean hud){
    listeners.put(pEntity, new TouchObject(pEntity, hud));
  }
 
  // Removes the listener from our array
  public void unregisterListener(Sprite pEntity){
    listeners.remove(pEntity);
  }
 
  // Default action - no bubble
  public boolean onTouched(Scene pScene, TouchEvent pSceneTouchEvent){
    return onTouched(pScene, pSceneTouchEvent, false);
  }
 
  // Find the first item that can be clicked
  public boolean onTouched(Scene pScene, TouchEvent pSceneTouchEvent, boolean pBubble){
    boolean wasTouched = false;    
    if(pSceneTouchEvent.isActionDown()) {
      Iterator<Entry<Sprite, TouchObject» itr = listeners.entrySet().iterator();
      lastTouched = null;
      Map.Entry<Sprite, TouchObject> pairs;
      TouchObject o;
      while (itr.hasNext()){
        pairs = itr.next();
        o = pairs.getValue();
        if(o.touched(pSceneTouchEvent, pSceneTouchEvent.getX(), pSceneTouchEvent.getY())) {
          wasTouched = true;
          lastTouched = o;
          if(!pBubble) {
            break;
          }
        }
      }
    } else {
      if(lastTouched != null) {
        lastTouched.touched(pSceneTouchEvent, pSceneTouchEvent.getX(), pSceneTouchEvent.getY(), true);
        wasTouched = true;
      }
      if(!pSceneTouchEvent.isActionMove()) {
        lastTouched = null;
      }
    }
    return wasTouched;
  }
 
  public class TouchObject {
    private final ITouchArea touchArea;
    private final Sprite entity;
    private final boolean hud;
    public TouchObject(Sprite pEntity, boolean pHud){
      entity = pEntity;
      touchArea = pEntity;
      hud = pHud;
    }
 
    // We are telling this that the object was touched or not
    public boolean touched(TouchEvent pSceneTouchEvent, float pX, float pY, boolean touched){
      if(hud) {
        pX -= options.camera.getMinX();
        pY -= options.camera.getMinY();
      }      
      if(touched) {
        touchArea.onAreaTouched(pSceneTouchEvent, pX, pY);
        return true;
      }
      return false;
    }
 
    // The object might be touched
    public boolean touched(TouchEvent pSceneTouchEvent, float pX, float pY){
      if(hud) {
        pX -= options.camera.getMinX();
        pY -= options.camera.getMinY();
      }        
      if(isTouching(pX, pY)) {      
        touchArea.onAreaTouched(pSceneTouchEvent, pX, pY);
        return true;
      }
      return false;
    }
 
    // Returns whether or not the user is touching this object
    public boolean isTouching(float pX, float pY){
      return entity.isVisible()
        && pX >= entity.getX() && pX <= entity.getX()+entity.getWidth()
        && pY >= entity.getY() && pY <= entity.getY()+entity.getHeight();
    }
  }
}

The one caveat here is this class uses a GameOptions class which holds things like my camera. For my purposes I need a reference to the camera because as I drag the scene around the X,Y global coordinates need to be offset by the camera offset (Unless hud is set to false)

Here are a couple examples of usages:

Sprite start = new Sprite(600,0,options.start){
  public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pX, final float pY) {
    if(pSceneTouchEvent.isActionDown()){
      // Start the game
    }
    return true;
  }
};
// Pass true to denote “this item is in a hud” so keep it static
options.touch.registerListener(start, true);

This adds a sprite button to the game that just cares about actionDown.

sprite = new Sprite(pX,pY,world.options.bomb){
  public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pX, final float pY) {
    if(pSceneTouchEvent.isActionDown()) {
      b.start(pX,pY);
      b.updateLength();
    } else if(pSceneTouchEvent.isActionMove()) {
      b.to(pX,pY);
    } else {
      b.end();
    }
    return true;
  }
};
world.options.touch.registerListener(sprite, false); 

This registers a listener on an object in the scene that also responds to move and up (e.g. drag and drop). As you can see this should simplify how you handle touch actions in your game and save a lot of headaches.

10 things I’ve learned as a developer

  1. Never sacrifice yourself for your job. Always value your free time, your friends, your life and your hobbies over your job. Your company sees you as an asset and you are not required for it to survive. It’s much better to be happy with yourself as it will translate to better work at your job.
  2. Never become bored. If you find yourself dreading your work and generally find it completely boring find a way to change that. Talk to your boss and ask for more challenging work. Find something you’d be interested in working on and proposing that you do it.
  3. Don’t overwork yourself because your brain wants equilibrium. The more you work the harder you will crash. It can be any form, too: emotional, physical, mental, health etc… The longer you keep up unrealistic pace the harder your brain will work to counteract that and its not pretty when its unleashed.
  4. Never be a yes man because no one respects a brown-noser. Yes there are some people out there that like it when you kiss their ass but they’ll never respect you enough to put you in a position of power unless they are truly an idiot.
  5. Don’t be afraid to offer alternatives. The most important thing you can do as a developer is identify when something is overly complex and offer suggestions to simplify it. This alone shaves days off projects and everyone will be happier in the long run.
  6. It’s okay to say no. Sometimes requests are just plain ridiculous. Can you run grunt work for a client event though they have perfectly good resources to do it yourself? Yes. Should you? Probably not. After all once you do they will always expect you to.
  7. Finish a simple version first then work to expand upon it. Don’t set out with a 500 page specification document and expect to get it done in 4-6 months. It won’t. There are always major issues lurking in there somewhere so cut it down to 1/3, set a target deadline and finish it then work in phases. It doesn’t have to be released to the public but make sure you can work with palpable goals.
  8. A square peg does not fit in a round hole. Just because you learned something new doesn’t mean you should use it. Understand when certain concepts are useful to you and understand when an alternative would be better.
  9. Never make assumptions. Chances are its a complex system you are forced to make assumptions about and they will probably be wrong. Better to do the work up front to save your ass later.
  10. It’s okay to fail. Learn to see the warning sign of an epic failure and don’t be afraid to admit you think an issue was more complex than you thought. It’s better to get people involved earlier than to be blamed later for a projects failure.

Using Tiled with Andengine for beginners

Prerequisites:

  1. Download Tiled
  2. Download Andengine
  3. Run and understand the TMXTiledMapExample

I will make a few assumptions to start off with. First I will assume you are going to be working on a side-scroller game. Second that you want to use the Tiled editor to not only draw tiles but to interact with those tiles in the game. There are a couple ways to go about this but I chose a specific route of separating the actual tiles with the object that will be our walls.

But first thing’s first, let’s create our level.

This first thing you will want to do is import your graphics via Map/New Tileset, add a new Tile Layer then draw some objects in your map. Just start off with a couple floors and maybe some walls. Something like the following will work:

Now add a new object layer via Layer/Add Object Layer. This will act as our collection of wall objects (essentially rectangles that will become our physics body in andengine). Make sure the Object Layer is selected then click on the Blue Icon at the top and lay out some wall objects over your tiles. It should look something like this:

Now comes the fun part. Tiled has a concept of Properties. This works on objects in addition to layers. If you right-click on either you will see Object Properties (or Layer Properties) and there you can add in key/value pairs. This concept is what we will use in our code to tell us what type of object it is and any other attribute we’d want to know in order to specifically change the way the object acts. In general the code and method I will be outlining is meant to work well with individual objects. So every rectangle you draw would have to be set with the same properties in order for it to work. But as I said, since we can also set these properties on a Layer, we can use that to set the default for all objects in the Layer and that way we only have to override it if an object is different from the rest in the Layer.

So let’s do that. Right click on the Object Layer you draw your rectangular walls in, hit Layer Properties, and under Name set it to type and for Value set it to wall. And there you go. We now have a bunch of rectangles that are defined in a layer as walls. 

Now we must code. A lot of this code was taken from the example source listed at the top of this guide but obviously I added a bunch of code to use the properties we will be setting. You should export your tmx file and add it into your andengine project somewhere that can be loaded (assets/tmx would be fine). In your onLoadScene you can place the following:

// Load the TMX level
try {
  final TMXLoader tmxLoader = new TMXLoader(this,
    this.mEngine.getTextureManager(),
    TextureOptions.BILINEAR_PREMULTIPLYALPHA);
  this.mTMXTiledMap = tmxLoader.loadFromAsset(this,
    “tmx/myLevel.tmx”);
} catch (final TMXLoadException tmxle) {
  Debug.e(tmxle);
}

for(TMXLayer tmxLayer : this.mTMXTiledMap.getTMXLayers()) {
  mScene.getChild(1).attachChild(tmxLayer);
}
 

All this really does is load our map (assets/tmx/myLevel.tmx) and add it to the scene. At this point nothing spectactular is happening. Now add the following:

// Add all TMX objects to map
final ArrayList<TMXObjectGroup> groups =
  mTMXTiledMap.getTMXObjectGroups();

ArrayList<TMXObject> objects;

for(final TMXObjectGroup group: groups) {
  objects = group.getTMXObjects();
  for(final TMXObject object : objects) {
    String type = “”;
    if(group.getTMXObjectGroupProperties().size() > 0) {
      type = group.getTMXObjectGroupProperties().get(0).getValue();
    }

    HashMap<String,String> properties =
      new HashMap<String,String>();
    int size = object.getTMXObjectProperties().size();
    for(int i=0;i<size;i++) {
      properties.put(object.getTMXObjectProperties().get(i).getName(),
        object.getTMXObjectProperties().get(i).getValue());
    }

    if(properties.containsKey(“type”)) {
      type = properties.get(“type”);
    }

    Entities.addEntity(
      this,
      mScene,
      object.getX(),
      object.getY(),
      object.getWidth(),
      object.getHeight(),
      type,
      properties
    );
  }
}

What we are doing is looping through all the object layers and subsequently all the objects in that layer. We first see the layer itself has a type, and if it does, we will default our object type to that. We then get all the properties we defined in Tiled and store it in a HashMap. Finally we override our current type if the object itself has a type. We are now ready to add the object to andengine. We do that through an Entities class that handles all the specific objects we have. That class would look something like this:

public class Entities {
  private static Body body;
  public static final Object LEVEL_TYPE_WALL = “wall”;
  public static void addEntity(
    Activity pParent,
    Scene pScene,
    int pX,
    int pY,
    int pWidth,
    int pHeight,
    String pType,
    HashMap<String,String> properties)
  {
    if(pType.equals(Entities.LEVEL_TYPE_WALL)) {
      Entities.addWall(pParent, pScene, pX, pY, pWidth, pHeight,properties);
    } 
  }

  private static void addWall(
    Activity pParent,
    Scene pScene,
    int pX,
    int pY,
    int pWidth,
    int pHeight,
    HashMap<String,String> properties)
  {
    final Shape wall = new Rectangle(pX, pY, pWidth, pHeight);
    wall.setVisible(false);
    if(properties.containsKey(“rotate”)){
      wall.setRotation(Float.parseFloat(properties.get(“rotate”)));
    }
    body = PhysicsFactory.createBoxBody(
      pParent.mPhysicsWorld,
      wall,
      BodyType.StaticBody,
      ParticlyActivity.STATIC_FIXTURE_DEF
    );
    pScene.getFirstChild().attachChild(wall);
  }

And there you have it. Assuming your FIXTURE_DEFs are setup correctly you should now be able to add a ball in your game, center a camera around it, and be able to interact with the level you designed in Tiled.

And as an added bonus I added a nice hook to add rotated objects in by adding a property of rotate with an angle in degrees.

As you can see this gives you a ton of flexibility. Not only for adding in an type of object you want in your game from Tiled, but to control exactly how they should behave. Some of the examples I have is to add the Dude in Particly, the goal, the waypoints, teleports and launchers. The possibilities are endless!

Happy coding!

Sound Day 2

Before I went to bed last night I recorded a bunch of voice and hits using my phone. The resulting files are amr since I used Voice Recorder so I had to go into Ubuntu Software Center and install both Audacity for editing and Mobile Media Converter for converting the amr files to wav. After editing I exported all the sounds as .ogg files into the game. Today I realized instead of doing stupid logic for determining if I’ve traveled far enough to warrant a sound, I decided to use the force of impact to guide the volume and in that way it would actually feel more natural… since, you know, that’s how nature works. I also recorded some win and lose sounds and tweaked the volume algorithm. Now above a certain force the protagonist will emit a sound and under that force you just hear the normal impact sounds. They feel a bit twangy at the moment so I’ll probably record more of them by throwing a stress ball against the wall or dresser to see if the resulting sounds are any better.

In other news vps.net is having issues with the server I host on so that kind of sucks. Second time this week I’ve had problems. Might consider looking for an alternative if this keeps up.

I might decide to release this this weekend with just the sounds as an update to make sure I don’t lose any more people then make another release the following weak that includes some additional maps and some of the other stuff I wanted to fix. 

The load time is significantly slower so I will also move all the texture and sound loading to the initial screen so the wait time is dramatically reduced.

1 2 3 4 5