Why Experts Exchange?

Experts Exchange always has the answer, or at the least points me in the correct direction! It is like having another employee that is extremely experienced.

Jim Murphy
Programmer at Smart IT Solutions

When asked, what has been your best career decision?

Deciding to stick with EE.

Mohamed Asif
Technical Department Head

Being involved with EE helped me to grow personally and professionally.

Carl Webster
CTP, Sr Infrastructure Consultant
Ask ANY Question

Connect with Certified Experts to gain insight and support on specific technology challenges including:

Troubleshooting
Research
Professional Opinions
Ask a Question
Did You Know?

We've partnered with two important charities to provide clean water and computer science education to those who need it most. READ MORE

troubleshooting Question

Phys2d running really slow.. need to understand why

Avatar of jvilla1983
jvilla1983 asked on
Game ProgrammingJava
3 Comments1 Solution934 ViewsLast Modified:
Hi.. My group is using Slick and Java to create a game for one of my classes. The problem is that we used Phys2d as a way to create the physics in the game, great product.. but it's making the game run really slow. Is there any way one of you could help us out a bit?

Here is my code..  
************************First Class******************************
 
package com.abc.ZeldaClone;
 
import net.phys2d.math.Vector2f;
import net.phys2d.raw.Body;
 
public abstract class AbstractEntity implements Entity {
	protected Body body;
 
	public void setVelocity(float x, float y) {
		Vector2f vec = new Vector2f(body.getVelocity());
		vec.scale(-1);
		body.adjustVelocity(vec);
		body.adjustVelocity(new Vector2f(x,y));
	}
	
	public void setX(float x) {
		body.setPosition(x, getY());
	}
 
	public void setY(float y) {
		body.setPosition(getX(), y);
	}
	
	public void setPosition(float x, float y) {
		body.setPosition(x, y);
	}
	
	public float getX() {
		return body.getPosition().getX();
	}
 
	public float getY() {
		return body.getPosition().getY();
	}
 
	public float getVelX() {
		return body.getVelocity().getX();
	}
 
	public float getVelY() {
		return body.getVelocity().getY();
	}
}
***************************Second Class******************************
 
public abstract class AbstractMap implements Environment {
    
    protected World world = new World(new Vector2f(0, 10), 20); 
    protected ArrayList<Entity> entities = new ArrayList<Entity>();
    protected Rectangle bounds;
    protected TiledMap map;
    // width of the map, in tiles
    protected int width;
    // height of the map, in tiles
    protected int height;
    // width of a tile, in pixels
    protected int tileWidth;
    // height of a tile, in pixels
    protected int tileHeight;
    
    private int totalDelta;
    private int stepSize = 5;
    
    public AbstractMap(String mapFile) throws SlickException {
        map = new TiledMap(mapFile);
        width = map.getWidth();
        height = map.getHeight();
        tileWidth = map.getTileWidth();
        tileHeight = map.getTileHeight();
        bounds = new Rectangle(0, 0, width * tileWidth, height * tileHeight);
        
        world.addListener(new CollisionListener() {
            public void collisionOccured(CollisionEvent event) {
                Body bodya = event.getBodyA();
                Body bodyb = event.getBodyB();
                System.out.println("Collision occurred between " + 
                    bodya.toString() + " and " + bodyb.toString());
                Entity a = (Entity) bodya.getUserData();
                Entity b = (Entity) bodyb.getUserData();
                if (a instanceof Player && a.isAttacking()) {
                    // the player initiated the contact, and the player is
                    // attacking, so hit the enemy
                    b.setHealth(b.getHealth() - 1);
                    if (!isAlive(b)) {
                        // enemy b is dead, so kill it
                        removeEntity(b);
                    }
                } else {
                    // the contact was not initiated by the player (or the
                    // player was not attacking, so the player takes damage
                    a.setHealth(a.getHealth() - 1);
                }
            }
        });
    }
    
    public void addEntity(Entity entity) {
        if (entity.getBody() != null) {
            world.add(entity.getBody());
        }
        
        entities.add(entity);
        entity.setWorld(world);
    }
    
    public void removeEntity(Entity entity) {
        world.remove(entity.getBody());
        entities.remove(entity);
    }
    
    public boolean isAlive(Entity entity) {
        int index = entities.indexOf(entity);
        if (index > -1) {
            Entity e = entities.get(index);
            return e.getHealth() > 0;
        } else {
            return false;
        }
    }
    
    public ArrayList<Enemy> getEnemies() {
        ArrayList<Enemy> enemies = new ArrayList<Enemy>();
        for (Entity e : entities) {
            if (e instanceof Enemy) {
                enemies.add((Enemy) e);
            }
        }
        return enemies;
    }
    
    public ArrayList<Entity> getEntities() {
        return entities;
    }
    
    public TiledMap getMap() {
        return map;
    }
    
    public void render(Graphics g) {
        map.render(0, 0);
        for (Entity e : entities) {
            e.render(g);
        }
    }
 
    public void update(int delta) {
        boolean first = true;
        
        totalDelta += delta;
        while (totalDelta > stepSize) {
            world.step(stepSize * 0.01f);
            totalDelta -= stepSize;
 
            if (first) {
                first = false;
                for (Entity e : entities) {
                    e.preUpdate(delta);
                }
            }
            
            for (Entity e : entities) {
                e.update(stepSize);
            }
            checkBounds();
        }
    }
 
    public int getWidth() {
        return width;
    }
 
    public void setWidth(int width) {
        this.width = width;
    }
 
    public int getHeight() {
        return height;
    }
 
    public void setHeight(int height) {
        this.height = height;
    }
    
    private void checkBounds() {
        float xp = 0;
        float yp = 0;
        for (Entity e : entities) {
            xp = e.getX();
            yp = e.getY();
            if (xp >= bounds.getWidth() - (tileWidth + 16)) {
                e.setX(bounds.getWidth() - (tileWidth + 16));
            }
            if (xp <= bounds.getX() + tileWidth + 16) {
                e.setX(bounds.getX() + tileWidth + 16);
            }
            if (yp >= bounds.getHeight() - (tileHeight + 16)) {
                e.setY(bounds.getHeight() - (tileHeight + 16));
            }
            if (yp <= bounds.getY() + tileHeight + 16) {
                e.setY(bounds.getY() + tileHeight + 16);
            }
        }
    }
}
*******************************Thrid Class ***********************
 
package com.abc.ZeldaClone;
 
import org.newdawn.slick.*;
 
import net.phys2d.math.*;
import net.phys2d.raw.*;
import net.phys2d.raw.shapes.*;
 
public abstract class Actor extends AbstractEntity {
    
    private World world;
    private Direction direction;
    private boolean moving;
    private boolean attacking;
    // the size of the Actor's collision bounds
    private float size;
    private float velx;
    private float vely;
    
    protected PackedSpriteSheet sheet;
    
    public Actor(String name, float x, float y, float mass, float size) {
        this.size = size;
        setDirection(Direction.SOUTH);
        setMoving(false);
        setAttacking(false);
        body = new Body(name, new Box(size, size), mass);
        body.setUserData(this);
        body.setRestitution(0);
        body.setFriction(0f);
        body.setMaxVelocity(20, 20);
        body.setRotatable(false);
        body.setGravityEffected(false);
        setPosition(x, y);
    }
    
    public abstract int getHealth();
    
    public abstract void setHealth(int health);
    
    public abstract boolean isAlive();
    
    public abstract void render(Graphics g);
    
    public synchronized void setWorld(World world) {
        this.world = world;
    }
    
    public float getSize() {
        return size;
    }
    
    public synchronized void applyForce(float x, float y) {
        body.addForce(new Vector2f(x, y));
        setVelocity(x, y);
    }
    
    public synchronized void preUpdate(int delta) {
        if (!isMoving()) {
            setVelocity(0, 0);
        }
        velx = getVelX();
        vely = getVelY();
    }
    
    public synchronized void update(int delta) {
        setVelocity(velx, vely);
    }
    
    public synchronized boolean isMoving() {
        return moving;
    }
 
    public synchronized void setMoving(boolean moving) {
        this.moving = moving;
    }
 
    public synchronized Direction getDirection() {
        return direction;
    }
    
    public synchronized void setDirection(Direction direction) {
        this.direction = direction;
    }
 
    public synchronized boolean isFacingEast() {
        return direction == Direction.EAST;
    }
 
    public synchronized boolean isFacingNorth() {
        return direction == Direction.NORTH;
    }
 
    public synchronized boolean isFacingSouth() {
        return direction == Direction.SOUTH;
    }
 
    public synchronized boolean isFacingWest() {
        return direction == Direction.WEST;
    }
 
    public synchronized boolean isAttacking() {
        return attacking;
    }
 
    public synchronized void setAttacking(boolean attacking) {
        this.attacking = attacking;
    }
 
    public synchronized Body getBody() {
        return body;
    }
}
*********************************Fourth Class**************************
 
package com.abc.ZeldaClone;
 
public enum Direction {
    NORTH("North", 1),
    SOUTH("South", 2),
    EAST("East", 3),
    WEST("West", 4);
    
    private int directionValue;
    private String directionName;
    
    private Direction(String name, int value) {
        directionValue = value;
        directionName = name;
    }
    
    public String getDirection() {
        return directionName;
    }
    
    public int valueOf() {
        return directionValue;
    }
    
    public String toString() {
        return directionName;
    }
}
*****************************Fifth Class*****************************
 
package com.abc.ZeldaClone;
 
import net.phys2d.raw.*;
 
import org.newdawn.slick.*;
import org.newdawn.slick.geom.*;
 
public class Dungeon extends AbstractMap {
    
    private Shape[][] shapes;
    
    public Dungeon(String mapFile) throws SlickException {
        super(mapFile);
        shapes = new Shape[width][height];
        
        int xp = 0;
        int yp = 0;
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                if (xp + x >= width) {
                    continue;
                }
                if (yp + y >= height) {
                    continue;
                }
                
                if (shapes[xp + x][yp + y] != null) {
                    shapes[x][y] = new Rectangle(xp, yp, tileWidth, tileHeight);
                }
            }
        }
    }
    
    public Rectangle getBounds() {
        return bounds;
    }
    
    public void renderBounds(Graphics g) {
        g.setColor(Color.yellow);
        g.draw(bounds);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                if (shapes[x][y] != null) {
                    g.draw(shapes[x][y]);
                }
            }
        }
        
        g.scale(1.0f / tileWidth, 1.0f / tileHeight);
        g.setColor(Color.white);
        g.setLineWidth(2);
    }
    
}
********************************6th class******************************
 
package com.abc.ZeldaClone;
 
import java.util.*;
 
import org.newdawn.slick.*;
 
public class Enemy extends Actor {
    
    private static final long MOVE_TIME = 1500L;
    private static final long WAIT_TIME = 500L;
    
    private String name;
    private int health;
    private int frame;
    private int frameTimer = 0;
    private int frameInterval = 100;
    private Thread t;
    
    public Enemy(String name, String spriteSheet, float x, float y, float mass, float size)
        throws SlickException {
        super(name, x, y, mass, size);
        this.name = name;
        sheet = new PackedSpriteSheet(spriteSheet);
        setHealth(3);
        
        Runnable r = new Runnable() {
            public void run() {
                runWork();
            }
        };
        t = new Thread(r); 
        t.start();
    }
 
    public void runWork() {
        float moveForce = 10;
        
        while (isAlive()) {
            long msRemaining = MOVE_TIME;
            long startTime = System.currentTimeMillis();
            long endTime = startTime + MOVE_TIME;
            
            setMoving(true);
            setDirection(getRandomDirection());
            while (msRemaining > 0L) {
                if (isFacingEast()) {
                    applyForce(moveForce, 0);
                } else if (isFacingWest()) {
                    applyForce(-moveForce, 0);
                } else if (isFacingNorth()) {
                    applyForce(0, -moveForce);
                } else if (isFacingSouth()) {
                    applyForce(0, moveForce);
                }
                msRemaining = endTime - System.currentTimeMillis();
            }
            setMoving(false);
            try {
                Thread.sleep(WAIT_TIME);
            } catch (InterruptedException e) {
                // shhhhh....
            }
        }
    }
    
    private Direction getRandomDirection() {
        Direction[] directions = Direction.values();
        int random = getRandomInteger(directions.length);
        return directions[random];
    }
    
    private int getRandomInteger(int limit) {
        Random number_generator = new Random();
        return number_generator.nextInt(limit);
    }
    
    public synchronized int getHealth() {
        return health;
    }
 
    public synchronized void setHealth(int health) {
        this.health = health;
    }
    
    public synchronized boolean isAlive() {
        return health > 0;
    }
    
    public void render(Graphics g) {
        String spriteName = null;
        Image image = null;
        int f = (frame % 6) + 1;
        //g.drawString("Enemy Health " + getHealth(), 300, 10);
        
        if (name.equals("Fire")) {
            if (isMoving()) {
                spriteName = (f % 2 == 0) ? "fire_1" : "fire_2";
            } else {
                spriteName = "fire_1";
            }
        } else if (name.equals("Octorok")) {
            if (isMoving()) {
                if (!isFacingNorth() && !isFacingSouth()) {
                    spriteName = (f % 2 == 0) ? "left_1" : "left_2";
                } else if (isFacingNorth()) {
                    spriteName = (f % 2 == 0) ? "north_1" : "north_2";
                } else if (isFacingSouth()) {
                    spriteName = (f % 2 == 0) ? "south_1" : "south_2";
                }
            } else {
                if (isFacingNorth()) {
                    spriteName = "north_1";
                } else if (isFacingSouth()) {
                    spriteName = "south_1";
                } else if (isFacingEast() || isFacingWest()) {
                    spriteName = "left_1";
                }
            }
        }
        
        image = sheet.getSprite(spriteName);
        
        if (isFacingEast()) {
            image = image.getFlippedCopy(true, false);
        }
        
        image.drawCentered(getX(), getY());
    }
 
    public void preUpdate(int delta) {
        super.preUpdate(delta);
        
        frameTimer -= delta;
        while (frameTimer < 0) {
            frame++;
            frameTimer += frameInterval;
        }
    }
}
*******************************7th class****************************
 
package com.abc.ZeldaClone;
 
import net.phys2d.raw.Body;
import net.phys2d.raw.World;
 
import org.newdawn.slick.Graphics;
 
public interface Entity {
	public void setWorld(World world);
	public Body getBody();
	public void preUpdate(int delta);
	public void update(int delta);
	public void render(Graphics g);
	public float getSize();
	public float getX();
	public float getY();
	public void setX(float x);
	public void setY(float y);
	public int getHealth();
	public void setHealth(int health);
	public boolean isAttacking();
    public boolean isFacingEast();
    public boolean isFacingNorth();
    public boolean isFacingSouth();
    public boolean isFacingWest();
    public void applyForce(float x, float y);
}
****************************8th class *****************************
 
package com.abc.ZeldaClone;
 
import java.util.*;
 
import org.newdawn.slick.Graphics;
import org.newdawn.slick.geom.Rectangle;
 
public interface Environment {
	public void render(Graphics g);
	public void renderBounds(Graphics g);
	public void update(int delta);
	public Rectangle getBounds();
	public ArrayList<Entity> getEntities();
	public void addEntity(Entity entity);
	public void removeEntity(Entity entity);
	public ArrayList<Enemy> getEnemies();
}
***********************************9th Class**************************
 
package com.abc.ZeldaClone;
 
import org.newdawn.slick.*;
import org.newdawn.slick.state.*;
 
public class InGameState extends BasicGameState {
    
    private static final int ID = 1;
    
    private Environment env;
    private float xoffset;
    private float yoffset;
    private int totalDelta;
    private int controlInterval = 50;
    private boolean showBounds = false;
    private Actor player;
    private Music music;
    
    public int getID() {
        return ID;
    }
    
    public void init(GameContainer arg0, StateBasedGame arg1)
            throws SlickException {
        restart();
    }
 
    public void restart() throws SlickException {
        music = new Music("res/z2-cast.xm");
        //music.loop();
        Dungeon dungeon = new Dungeon("res/dungeon1.tmx");
        
        player = new Player("Player", "res/link_sheet.def", 150, 150, 1f, 54);
        dungeon.addEntity(player);
        dungeon.addEntity(new Enemy("Fire", "res/enemy_sheet.def", 200, 300, 1f, 32));
        dungeon.addEntity(new Enemy("Octorok", "res/link_sheet.def", 250, 100, 1f, 54));
        this.env = dungeon;
    }
    
    public void render(GameContainer container, StateBasedGame game, Graphics g)
            throws SlickException {
        g.translate(-(int) xoffset, -(int) yoffset);
        env.render(g);
        if (showBounds) {
            env.renderBounds(g);
        }
        g.translate((int) xoffset, (int) yoffset);
        
        if (!player.isAlive()) {
            // game over
            env.removeEntity(player);
            drawString(g, "GAME OVER", 200);
            drawString(g, "Press \"R\" to try again.", 215);
        }
        
    }
 
    private void drawString(Graphics g, String str, int y) {
        int x = (800 - g.getFont().getWidth(str)) / 2;
        g.setColor(Color.black);
        g.drawString(str, x + 1, y + 1);
        g.setColor(Color.white);
        g.drawString(str, x, y);
    }
    
    public void update(GameContainer container, StateBasedGame game, int delta)
            throws SlickException {
        Input input = container.getInput();
        
        // restart and bounds toggling
        if (input.isKeyPressed(Input.KEY_R)) {
            restart();
            return;
        }
        
        if (input.isKeyPressed(Input.KEY_B)) {
            showBounds = !showBounds;
        }
        
        if (input.isKeyPressed(Input.KEY_M)) {
            if (music.playing()) {
                music.stop();
            } else {
                music.loop();
            }
        }
        
        float moveForce = 100;
        
        totalDelta += delta;
        
        // setup the player's moving flag, this controls the animation
        player.setMoving(false);
        player.setAttacking(false);
        
        if (input.isKeyDown(Input.KEY_LEFT) || input.isKeyDown(Input.KEY_RIGHT)
                || input.isKeyDown(Input.KEY_UP)
                || input.isKeyDown(Input.KEY_DOWN)) {
            player.setMoving(true);
        } else {
            player.setMoving(false);
        }
        
        if (totalDelta > controlInterval) {
            controlInterval -= totalDelta;
            if (input.isKeyDown(Input.KEY_LEFT)) {
                player.setDirection(Direction.WEST);
                player.applyForce(-moveForce, 0);
            }
            if (input.isKeyDown(Input.KEY_RIGHT)) {
                player.setDirection(Direction.EAST);
                player.applyForce(moveForce, 0);
            }
            if (input.isKeyDown(Input.KEY_UP)) {
                player.setDirection(Direction.NORTH);
                player.applyForce(0, -moveForce);
            }
            if (input.isKeyDown(Input.KEY_DOWN)) {
                player.setDirection(Direction.SOUTH);
                player.applyForce(0, moveForce);
            }
 
            if (input.isKeyDown(Input.KEY_A)) {
                player.setAttacking(true);
            }
        }
        
        env.update(delta);
    }
}
******************************10th class*******************************
 
package com.abc.ZeldaClone;
 
import org.newdawn.slick.*;
 
public class Player extends Actor {
    
    private int health;
    private int frame;
    private int frameTimer = 0;
    private int frameInterval = 100;
    
    public Player(String name, String resource, float x, float y, float mass, float size)
        throws SlickException {
        super(name, x, y, mass, size);
        sheet = new PackedSpriteSheet(resource);
        health = 5;
    }
 
    public synchronized int getHealth() {
        return health;
    }
 
    public synchronized void setHealth(int health) {
        this.health = health;
    }
 
    public synchronized boolean isAlive() {
        return getHealth() > 0;
    }
    
    public void render(Graphics g) {
        String spriteName = null;
        Image image = null;
        int f = (frame % 6) + 1;
        g.drawString("Player Health " + getHealth(), 175, 10);
        g.drawString("xpos " + getX() + ", ypos " + getY(), 175, 20);
        
        if (isMoving()) {
            if (!isFacingNorth() && !isFacingSouth()) {
                spriteName = (f % 2 == 0) ? "left_1" : "left_2";
            } else if (isFacingNorth()) {
                spriteName = (f % 2 == 0) ? "north_1" : "north_2";
            } else if (isFacingSouth()) {
                spriteName = (f % 2 == 0) ? "south_1" : "south_2";
            }
        } else {
            if (isFacingNorth()) {
                spriteName = "north_1";
            } else if (isFacingSouth()) {
                spriteName = "south_1";
            } else if (isFacingEast() || isFacingWest()) {
                spriteName = "left_1";
            }
        }
        
        if (isAttacking()) {
            if (!isFacingNorth() && !isFacingSouth()) {
                if (f % 3 == 0) {
                    spriteName = "left_attack_1";
                } else if (f % 3 == 1) {
                    spriteName = "left_attack_2";
                } else {
                    spriteName = "left_attack_3";
                }
            } else if (isFacingNorth()) {
                if (f % 3 == 0) {
                    spriteName = "north_attack_1";
                } else if (f % 3 == 1) {
                    spriteName = "north_attack_2";
                } else {
                    spriteName = "north_attack_3";
                }
            } else if (isFacingSouth()) {
                if (f % 3 == 0) {
                    spriteName = "south_attack_1";
                } else if (f % 3 == 1) {
                    spriteName = "south_attack_2";
                } else {
                    spriteName = "south_attack_3";
                }
            }
        }
        image = sheet.getSprite(spriteName);
        
        if (isFacingEast()) {
            image = image.getFlippedCopy(true, false);
        }
        
        image.drawCentered(getX(), getY());
    }
 
    public void preUpdate(int delta) {
        super.preUpdate(delta);
        
        frameTimer -= delta;
        while (frameTimer < 0) {
            frame++;
            frameTimer += frameInterval;
        }
    }
    
}
******************************11th class****************************
 
package com.abc.ZeldaClone;
 
import org.newdawn.slick.*;
import org.newdawn.slick.state.*;
 
public class ZeldaClone extends StateBasedGame {
    
    private GameContainer container;
    private boolean vsync = true;
    
    public ZeldaClone() {
        super("Zelda Clone v0.3");
    }
    
    public void initStatesList(GameContainer container) throws SlickException {
        this.container = container;
        container.setTargetFrameRate(30);
        container.setVSync(vsync);
        addState(new InGameState());
    }
    
    public void keyPressed(int key, char c) {
        super.keyPressed(key, c);
        
        if (key == Input.KEY_F7) {
            vsync = !vsync;
            container.setVSync(vsync);
        }
    }
    
    public static void main(String[] argv) throws SlickException {
        AppGameContainer container = new AppGameContainer(new ZeldaClone(),
            800, 600, false);
        container.start();
    }
}
ASKER CERTIFIED SOLUTION
Avatar of MicheleMarcon
Commented:
This problem has been solved!
Unlock 1 Answer and 3 Comments.
See Answers