Showing posts with label gems. Show all posts
Showing posts with label gems. Show all posts

Saturday, June 12, 2010

Simple Easing

I found a really nice system for easing values over time. I haven't come up with a name for it, though. There's only one catch: in its current state, it only works over fixed time intervals. But there's probably a really simple fix for that.

In a normal code scenario (I'm going to use C) you declare a variable like this:
int variable;
Now, to use this now special "easing" system of variable change, you simply add two more variables to your declaration. The declaration now looks like this:
int variable;
int variableWant;
const int VARIABLE_SPEED = 3;
The first one is the original variable, which I'll call the "actual" value. The second one is the "want" variable, and the third is the "speed" variable. The "want" value is the one you will be changing, while the "actual" value is the one you'll be reading. "Want" is kinda like the "set" variable, while "actual" is the "get" variable. You can use any naming scheme for these variables, but those are the ones I use.

To make this work, you add the following code (which corresponds to the naming scheme above) to a regular-interval function:
variable = (variable * (VARIABLE_SPEED - 1) + variableWant) / VARIABLE_SPEED;
This may look complicated at first, but it's actually really simple. It calculates a new "actual" value based on the "actual" and "want" values by averaging them with specific weight on "actual." If you remember anything about averaging (which you should) you should remember that the last step is to divide by the number of added terms. Well, if you look above, there are (VARIABLE_SPEED - 1) "actual" terms, while there is 1 "want" term. This means that the total number of terms is (VARIABLE_SPEED - 1) + 1, or simply VARIABLE_SPEED, which is what we divide by.

The last variable which hasn't gotten enough attention is VARIABLE_SPEED. This variable's function is simple: it determines the rate at which the ease takes place. If this value is 1, the ease will happen instantly. If the value is 3, the ease will happen rather slow. For a value of 100, you'll be waiting a while.

The only issue with this method of variable change over time is that, theoretically, for values of VARIABLE_SPEED greater than 1, the "actual" value never actually becomes the "want" value. Adding this functionality simply means adding an if statement that sets the "actual" to the "want" for differences less than some constant.

Saturday, February 6, 2010

C struct Inheritance

Inheritance is generally thought of as belonging to object oriented programming languages like C++ and Python, but it can actually work with procedural languages like C.

In C, there is a data type called the struct, which is basically a collection of various types.

A struct typedef like this:

typedef struct
{
int val1;
char *name;
} super_t;

can be "sub-structed" by another struct typedef like this:

typedef struct
{
super_t sup; // this HAS to go at the beginning of the struct
char otherval;
} sub_t;


With the types set up like this, if a pointer to a variable of type sub_t is casted to a pointer to super_t, then the attributes of super_t can be accessed like normal.

The only problem is that a sub_t instance needs to get the values of its superclass through the sup variable.

Thursday, January 14, 2010

Functions are not the devil

Hypothetical: your initialization function is a huge mess. It's probably 200 lines all by itself.

What do you do? Break it up into functions. Functions are not the devil.

That's right, you can make all of your messy initialization functions into clean little bits of comprehensible code with this amazing programming feature called Functions!!!

Turn your initialization function into something like this:

function Init()
{
g.log.Add (1, "Initializing level "+g.level+"...");

// making the level
level = lm.LevelFor(g.level);
PopulateLevel (g);

// the player
InitPlayer (g);

// display initialization
InitRadar (g);
InitDisplay (g);

// stamping the level stats
StampStats (g);
}
With the magic of the almighty Function!!!

In all seriousness, the programming world has functions for a reason. I'm not trying to criticize the lack of functions in code. I'm simply trying to help people realize that having a thousand short little functions is a lot better than having twenty monolithic functions.

But you had better have some sort of function naming scheme in mind or things can get very hairy very fast.

Sunday, January 3, 2010

AS3 Dynamic Construction

This is a little ActionScript 3.0 programming gem I discovered ON MY OWN without Google's help...

Check out the following code:

class Animal
{
function Animal()
{
trace ("Animal has been created");
}
}

class Dog extends Animal
{
function Dog()
{
trace ("Dog has been created. Woof!");
}
}

var notADogType:Animal = new Dog(); // outputs "Dog has been created. Woof!"
var doggie:Dog = new (Object(notADogType).constructor)() // outputs "Dog has been created. Woof!"

That's all fine and dandy, but give this a whirl:

var puppy:Animal = new Dog(); // outputs "Dog has been created. Woof"
var noType:* = puppy;

var newDog:Dog = new (Object(noType).constructor)() // outputs "Dog has been created. Woof!"

This is really useful to put in a superclass of something to return a new one of that type. Take this for example:

class Thing
{
function newOne():Thing
{
return new (Object(this).constructor)();
}

function overrideMe()
{
trace ("I'm just a thing");
}
}

class Car
{
override function overrideMe()
{
trace ("I'm a car. Vroooom!");
}
}

var volvo:Thing = new Car();
volvo.overrideMe(); // outputs "I'm a car. Vroooom!"

var justAThing:Thing = volvo.newOne();
justAThing.overrideMe(); // outputs "I'm a car. Vroooom!"

This proved to be very helpful in my latest game.

Note: there are inaccuracies in the code, such as: you can't put the code in a frame and expect it to work. Also, when a subclass is constructed, its superclass's constructor is called as well. But the general concept still works.

Basically, regardless of the type of someInstance, Object(someInstance).constructor points to the class used to construct someInstance. You can use that exactly like it's a normal class, but don't forget to put parentheses around Object(someInstance).constructor. Wanna typecast? (Object(someInstance).constructor)(otherObject). Create a new one new (Object(someInstance).constructor)().

I can't believe this isn't documented very well...