Defensio Spam Checking

Yesterday, I read this post on DtD's Blog. For the last few months, I've been getting around 20-25 spam posts per day. That is a lot, especially for a small blog like this. Taking DtD's lead, I think I'll upgrade my spam defenses as well.

The packaged spam checker in Habari only detects around 5% of those spam messages, so I switched to the Defensio spam detection system. Here's to hoping that it works, because digging through page after page of comments like "free c1al1s" and "Hi, I'm new here, check out these links" is starting to get REALLY old.

Getting Tilt Data on an Android Phone

I haven't posted in a while, so I thought I'd post a little bit of code that I wrote for an android phone app that I'm working on. You see, Google recently deprecated one of the older ways of getting tilt data from the Android OS, but they didn't really document the new way of doing it. Plus, most resources I found online still use the old method, so I wrote a class to get the tilt data in an easy-to-use manner. (And without using any deprecated functions.)

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.Log;

public class TiltCalc {

private boolean needsRecalc = false;
private float[] tilt_data = {0, 0, 0}, gravity = {0, 0, 0}, magnet = {0, 0, 0};

// Change this to make the sensors respond quicker, or slower:
private static final int delay = SensorManager.SENSOR_DELAY_GAME;


// Special class used to handle sensor events:
private final SensorEventListener listen = new SensorEventListener() {
public void onSensorChanged(SensorEvent e) {
final float[] vals = e.values, target;

// Just capture the Gyroscope data, if it exists:
if(e.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
System.arraycopy(vals, 0, tilt_data, 0, 3);
return;
}

// Else, we'll capture the data, and mark the class for a re-calc:
target = (e.sensor.getType() == Sensor.TYPE_ACCELEROMETER) ? gravity : magnet;
needsRecalc = true;
System.arraycopy(vals, 0, target, 0, 3);
}

public void onAccuracyChanged(Sensor event, int res) {}
};

// The constructor will use a context object to register itself for various inputs:
public TiltCalc(Context c) {
SensorManager man = (SensorManager) c.getSystemService(Context.SENSOR_SERVICE);

Sensor mag_sensor = man.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
Sensor acc_sensor = man.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
Sensor gyr_sensor = man.getDefaultSensor(Sensor.TYPE_GYROSCOPE);

if(man.registerListener(listen, gyr_sensor, delay)) {
Log.d("TiltCalc", "Gyroscope detected, and successfully connected.");

// Try to fall back on an accelerometer+compass approach:
} else if( man.registerListener(listen, mag_sensor, delay) &&
man.registerListener(listen, acc_sensor, delay) ) {
Log.d("TiltCalc", "No gyroscope, falling back on accelerometer+compass.");

} else {
Log.d("TiltCalc", "No acceptable hardware found.");

// We will remove the listener, just in case one of the accelerometer sensors
// registered, just not the other one:
man.unregisterListener(listen);
}
}

// Will return the most up-to-date tilt data in the vals[] array
public void getTilt(float[] vals) {

// If some of the data has been changed, then we need to recalculate some things...
if(needsRecalc) {
float[] R={0,0,0,0,0,0,0,0,0};

// Calculate the rotation matrix, and use that to get the orientation:
if(SensorManager.getRotationMatrix(R, null, gravity, magnet))
SensorManager.getOrientation(R, tilt_data);

needsRecalc = false;
}

System.arraycopy(tilt_data, 0, vals, 0, 3);
}
}

The constructor needs a context object, so that it can register itself for sensor updates. The easiest way to do this is to call the function in the main activity, using 'this' as the context. (Activity is a subclass of Context...)

Then, you would just call getTilt(float[] vals) to get the 3 tilt values. That function will return the 3 tilt values into the float[] that is passed into the class. The tilt values will be setup like:

Diagram showing the tilt axes

So vals[0] is rotating the phone around like a compass, vals[1] is tilting the phone up and down, and vals[2] is tilting the phone left and right.

This class is coded so that if you have an accurate gyroscope in the phone, the class will use that to get the tilt data. However, in most cases, you won't have a gyroscope, so the class will fall back on a less accurate (but still perfectly usable) accelerometer + compass method of calculating tilt.

Note: I do not have a phone with a gyroscope, so that code is ENTIRELY untested. Plus, since Google didn't document the output format of gyroscope updates, this code is based on the very bold assumption that Google wouldn't give tilt data in differing formats based on the data's source.

Anyway, this code is public domain, so have fun. :)

California Elections

Just a quick post today. I just got back from voting in the California Primary Election, and I was excited to see that I was voter #256 in the roster. (Like, the 256th alphabetical voter in the list.) I was fairly excited about that. :)

Also, the polling place was in my old middle school, and I was sad to see that they had all the same computers. I went to that school in year 1999, and the computers were a few years old THEN. Those computers are technically from 2 decades ago... :/

Plus, the nice librarian who worked at the school when I was a student there, was still working there, but she's retiring in 2 days, and this is the last election that she'll be administering over. :(

So, I'm voter #256, my school needs a bigger tech budget, and the librarian is retiring in 2 days. All in all, this has been an interesting day, and I've only been awake for an hour or two. ;)

Gish Source

Gish Screenshot

Now that the Gish source code has been posted, it's time to actually look at this thing. Here are some of my notes while chugging through this thing quickly:

  1. Firstly, this project is in C, and not C++. C tends to be faster and more portable, but large game project tend to go with C++, so this surprised me, but in a good way. :)
  2. Secondly, in order to compile for Apple computers, you need to compile with "THINKSTUPID" defined. I lol'ed heartily about that.
  3. Thus far, I have not found any useful comments. They're all either licencing info or commented-out code. Too bad. :/
  4. This code uses OpenGL all over the place, not just in one neat file. This sucks, because in order for someone to port this to the Pandora, they'll have to go file-by-file through out this project, converting the glBegin()/glEnd() code to OpenGL ES's vertex buffers.
  5. Lots of the code REEKS of copy-and-paste, and magic numbers are littered throughout the code. This results in functions that are hundreds or thousands of lines long, with HUGE if-blocks that span nearly the entire function. Plus, many of the other functions could have been written WAY nicer. Consider loadstorylevel() from setup.c:
    void loadstorylevel(int levelnum)
    {
    #ifndef DEMO
    if (levelnum==1)
    loadlevel("sewer1.lvl");
    if (levelnum==2)
    loadlevel("sewer2.lvl");
    if (levelnum==3)
    loadlevel("sewer3.lvl");
    if (levelnum==4)
    loadlevel("sewer4.lvl");
    if (levelnum==5)
    loadlevel("sewer5.lvl");
    if (levelnum==6)
    loadlevel("sewer6.lvl");
    if (levelnum==7)
    loadlevel("sewer7.lvl");

    if (levelnum==8)
    loadlevel("cave1.lvl");
    if (levelnum==9)
    loadlevel("cave2.lvl");
    if (levelnum==10)
    loadlevel("cave3.lvl");
    if (levelnum==11)
    loadlevel("cave4.lvl");
    if (levelnum==12)
    loadlevel("cave5.lvl");
    if (levelnum==13)
    loadlevel("cave6.lvl");
    if (levelnum==14)
    loadlevel("cave7.lvl");

    if (levelnum==15)
    loadlevel("hell1.lvl");
    if (levelnum==16)
    loadlevel("hell2.lvl");
    if (levelnum==17)
    loadlevel("hell3.lvl");
    if (levelnum==18)
    loadlevel("hell4.lvl");
    if (levelnum==19)
    loadlevel("hell5.lvl");
    if (levelnum==20)
    loadlevel("hell6.lvl");
    if (levelnum==21)
    loadlevel("hell7.lvl");

    if (levelnum==22)
    loadlevel("egypt1.lvl");
    if (levelnum==23)
    loadlevel("egypt2.lvl");
    if (levelnum==24)
    loadlevel("egypt3.lvl");
    if (levelnum==25)
    loadlevel("egypt4.lvl");
    if (levelnum==26)
    loadlevel("egypt5.lvl");
    if (levelnum==27)
    loadlevel("egypt6.lvl");
    if (levelnum==28)
    loadlevel("egypt7.lvl");

    if (levelnum==29)
    loadlevel("church1.lvl");
    if (levelnum==30)
    loadlevel("church2.lvl");
    if (levelnum==31)
    loadlevel("church3.lvl");
    if (levelnum==32)
    loadlevel("church4.lvl");
    if (levelnum==33)
    loadlevel("church5.lvl");
    if (levelnum==34)
    loadlevel("church6.lvl");
    if (levelnum==64)
    loadlevel("sewer8.lvl");
    if (levelnum==65)
    loadlevel("cave8.lvl");
    if (levelnum==66)
    loadlevel("egypt8.lvl");
    if (levelnum==67)
    loadlevel("death.lvl");
    if (levelnum==68)
    loadlevel("death2.lvl");
    #else
    if (levelnum==1)
    loadlevel("demo1.lvl");
    if (levelnum==2)
    loadlevel("demo2.lvl");
    if (levelnum==3)
    loadlevel("demo3.lvl");
    if (levelnum==4)
    loadlevel("demo4.lvl");
    if (levelnum==5)
    loadlevel("demo5.lvl");
    #endif
    }
    That very well could have been just:
    void loadstorylevel(int levelnum) {
    char buf[16];

    assert(levelnum>0);

    #ifndef DEMO
    if (levelnum<=7 ) sprintf(buf, "sewer%d.lvl", levelnum);
    else if(levelnum<=14) sprintf(buf, "cave%d.lvl", levelnum-7);
    else if(levelnum<=21) sprintf(buf, "hell%d.lvl", levelnum-14);
    else if(levelnum<=28) sprintf(buf, "egypt%d.lvl", levelnum-21);
    else if(levelnum<=34) sprintf(buf, "church%d.lvl",levelnum-28);

    // All of the super-secret bonus levels are special cases:
    else if(levelnum==64) sprintf(buf, "sewer8.lvl");
    else if(levelnum==65) sprintf(buf, "cave8.lvl");
    else if(levelnum==66) sprintf(buf, "egypt8.lvl");
    else if(levelnum==67) sprintf(buf, "death.lvl");
    else if(levelnum==68) sprintf(buf, "death2.lvl");

    else assert(0);

    #else
    if (levelnum<=5) sprintf(buf, "demo%d.lvl", levelnum);
    else assert(0);

    #endif

    loadlevel(buf);
    }
    I know it really doesn't matter; the code does the same thing, but the code on the bottom is shorter and easier to read.
  6. I'm seeing all kinds of code that relies on chdir()'s, and other functions that force the program to be run out of the same directory as the executable. Plus, the high-scores, and game saves go into that same directory as well, and replays get saved into a replay directory. That type of code may be cool on Windows, but it's going to need some rewriting if we ever want to see a Gish *.deb, or *.rpm.
  7. Check out animation.c if you dare. 1 function. 1337 lines of code. That's a cool number for it to be, but O.O at the actual function...
  8. Finally, the reason I dove into this code in the first place... the physics code. The physics code is surprisingly simple. Gish himself is merely a bundle of unbreakable bonds and springs. (See: createtarboy() in object.c), as are all of the dynamic blocks and such. From what I can tell, the internals of their physics engine is actually incredibly simple. It will simply go through all dynamic objects subject for collision, and will then compare that block to every other dynamic block for collision handling. Each block will compare the level separately from the blocks, separately from the particles, and so on. With this engine, each physics update has a O(n2) running time, where n is the number of dynamic objects in the level. This simple approach seems to have worked well for Gish, but probably won't work for other projects, so don't try to use the Gish physics engine in other projects... It would probably be best to just stick with more advanced 2d physics libraries, like Box2d for C++, and Chipmunk for C. (I'm personally a huge fan of Chipmunk, and I used it in that Tetris Hell game I posted a short while back.)

One final note: this list may seem a little harsh at points, but I don't want it to be. I know that I have coded some pretty horrible things when I've been under pressure, and I don't want to act like I'm above committing my own personal coding sins. I am completely thrilled that the Gish code is now free under the GPL, and I hope more projects do the same!

That said, rewriting a few bits couldn't hurt... ;)

Where's the source?

So, it's been a couple of weeks since the Humble Bundle made over a million bucks. That's great, cause 4 of the games in the bundle offered to release their source code if the Bundle made over a million. Thus far, both Lugaru and Penumbra:Overture have released their source. Bit-Blot, the makers of Aquaria, seem to be chatting about implementing an online mod database, so they're obviously hard at work getting us some nice, high-quality source. However, I haven't heard anything from Cryptic Sea (the makers of Gish)...

I know the Cryptic Sea guys are probably hard at work, but I do wish we could hear more about the publishing process... That soft-body physics engine looks neat... I'm wondering how they did it... :) It's especially interesting, because I really liked Gish back in the day... it's the game that introduced me to indie gaming. I bought it back when it was released in 2004, again when it was released on Steam, and again with the Humble Bundle. (Although, I got the Bundle mostly for the other games...) I do seem to like supporting it. :)

Plus, it looks like, for the FIRST TIME EVER, the Pandora open-source handheld gaming console is less than "2 months away." (It's been "2 months away" for, like, 2 years now.) And so, it would be nice to see either Gish or Aquaria on it, since they're both really cool games, and both games are Linux-ready. (Although, I don't think either is ARM-ready, so porting might take some work...)

...

Oh, and despite the long breaks between posts, this blog is not dead. I'm currently working on a new project, and if it pans out, I'm sure that it will make for some good writing material. :)

EDIT: Gish released source! Wow, I didn't see that coming. I thought aquaria would release source first....

 1 2 3 … 10 Next →

About

User