Freitag, 13. Juli 2007

Quicklist class

I found this QuickList class to be very useful for passing dynamic parameters to functions without using Vectors and the likes:




/**
* Simple class for generating lists.
*
* QuickList differs from the List Collection in as much as once created,
* a QuickList does
* not change. New elements are added to a QuickList by creating a
* new QuickList which includes both the new element and the old QuickList.
*
* This makes QuickList suitable for generating low-overhead
* temporary data structures (amongst other things).
*/
public class QuickList {

/**
* All elements in this QuickList apart from the first
*/
private QuickList tail;
/**
* The first element in this QuickList
*/
private Object head;

/**
* Empty Quicklist. Add to the empty QuickList in order to generate a new list
*/
public static final QuickList EMPTY = new QuickList(null, null);

/**
* Creates a new instance of QuickList.
*
* @param tail A list to which a new item is being appended
* @param head a new item to append to a list
*/
protected QuickList(QuickList tail, Object head) {
this.head = head;
this.tail = tail;
}

/**
* Adds an item to a list.
*
* Note that this method does not change this list, but instead returns a
* new list with the new item added to it.
*
* @param item An item to add to the list
* @return A new list with item added to the front
*/
public QuickList add(Object item) {
return new QuickList(this, item);
}

/**
* Get the first item in this list.
*
* @return the first item in this list
*/
public Object head() {
return head;
}

/**
* Get the rump of this list (everything except the first item).
*
* @return A list including all items except the first
*/
public QuickList tail() {
return tail;
}

/**
* Calculate the size of a QuickList
*
* @return Number of elements in this quicklist (not counting EMPTY element)
*/
public int size() {
if (this == EMPTY) return 0;
else return tail.size() + 1;
}
}



To copy this code, please open the source of this page and copy it (STRG+C) from there.

Samstag, 16. Juni 2007

Defining waypoints for your sprite, or, moving your sprite on a straight line

If you want to move your sprite from one point to another on a straight line, you will have to calculate the line based on the two positions given. Since the equation for a line is

mx+b = y

you will have to calculate the slope (m) and the intercept (b) to be able to calculate any position in between the starting and the end position. The two methods for doing this in J2ME:




class Util {
/**
* Slope calculation for line given by two x-y-positions
*
* @param x1 First position's x-parameter
* @param y1 First position's y-parameter
* @param x2 Second position's x-parameter
* @param y2 Second position's y-parameter
* @return calculated slope value
*/
public static double calcLineSlope(int x1, int y1, int x2, int y2) {
double dx = x1 - x2;
double dy = y1 - y2;
if ((dx != 0) && (dy != 0)) {
return (dy / dx);
} else {
return 0;
}
}

/**
* Intercept calculation for line given by x-y-position and slope
*
* @param x x-parameter of given position
* @param y y-parameter of given position
* @param m slope of line
* @return calculated intercept value
*/
public static double calcLineIntercept(int x, int y, double m) {
if (m != 0) {
return y - m*x;
} else {
return 0;
}
}
}


 


To put these functions into use, you can try something like the following EnemySprite class



import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.Sprite;

class EnemySprite extends Sprite {

double cur_m;
double cur_b;
int target_x;
int target_y;

int speed;

// Constructor, is called when you instantiate your EnemySprite
public EnemySprite(Image img) {
super(img);

speed = 5;

// Starting position (20, 20), target position (30, 100)
this.setPosition(20, 20);
target_x = 30; target_y = 100;
cur_m = Util.calcLineSlope(target_x, target_y, this.getX(), this.getY());
cur_b = Util.calcLineIntercept(this.getX(), this.getY(), cur_m);
}

// Call this method in your game loop
public void update () {
if ((this.getX() != target_x) || (this.getY() != target_y)) {
double dx = Math.abs(target_x - this.getX());
double dy = Math.abs(target_y - this.getY());
if ((dx != 0) && (dy != 0)) {
int nextx = 0;

if (Math.abs(this.getX() - target_x) < speed) {
nextx = target_x;
} else {
nextx = (this.getX() < target_x) ?
this.getX() + speed :
this.getX() - speed;
}
int nexty = (int)(nextx * cur_m + cur_b);

this.setPosition(nextx, nexty);
} else {
if (dx != 0) {
if (Math.abs(this.getX() - target_x) < 2*speed) {
this.setPosition(target_x, this.getY());
} else {
int nextx = (this.getX() < target_x) ?
this.getX() + 2*speed :
this.getX() - 2*speed;
this.setPosition(nextx, this.getY());
}
}
if (dy != 0) {
if (Math.abs(this.getY() - target_y) < 2*speed) {
this.setPosition(this.getX(), target_y);
} else {
int nexty = (this.getY() < target_y) ?
this.getY() + 2*speed:
this.getY() - 2*speed;
this.setPosition(this.getX(), nexty);
}
}
}
} else {

// Target position reached, inititalize next waypoint...

}
}
}


 


This will only work with MIDP 2.0, since floating-point-values are not supported in MIDP 1.0 to my knowledge.

To copy and paste this code, please open the source of this page and copy from there.



--thgc