public interface LivingCategory {

    public boolean kill();
}
 public class Body {
    
    public enum BodyType { StaticBody, DynamicBody }
    public Rectangle rectangle;
    public BodyType bodyType;
    public ServerEntity entity;
    public float restitutionX;
    public float restitutionY;
    public boolean grounded;
    public boolean toDestroy;
    public enum CollisionCategory { ALL, ENEMY, STATIC, NONE, WEAPON };
    public CollisionCategory category;
    private final Vector2 velocity;
    private final Vector2 temp1;
    private final Vector2 temp2;
    private final Vector2 temp3;
    private final Vector2 temp4;
    private final Vector2 temp5;
    private World world;
    private float gravityScale;
    public float xDamping;
    
    public Body() {
        bodyType = BodyType.StaticBody;
        velocity = new Vector2(0, 0);
        temp1 = new Vector2();
        temp2 = new Vector2();
        temp3 = new Vector2();
        temp4 = new Vector2();
        temp5 = new Vector2();
        restitutionX = 0;
        restitutionY = 0;
        gravityScale = 1f;
        grounded = false;
        toDestroy = false;
        xDamping = 0;
        category = CollisionCategory.ALL;
    }
    
    public Body(Rectangle rectangle) {
        this();
        this.rectangle = rectangle;
    }
    
    public Body(float x, float y, float width, float height) {
        this();
        rectangle = new Rectangle(x, y, width, height);
    }

    public Body(float x, float y, float w, float h, BodyType type) {
        this(x, y, w, h);
        bodyType = type;
    }
    
    public Body(Rectangle rectangle, BodyType type) {
        this(rectangle);
        bodyType = type;
    }

    public void setWorld(World world) {
        this.world = world;
    }
    
    public Vector2 getPosition() {
        return rectangle.getCenter(temp1);
    }

    public Vector2 getLinearVelocity() {
        return temp3.set(velocity);
    }

    public void setLinearVelocity(float x, float y) {
        velocity.set(x, y);
    } 

    public void setLinearVelocity(Vector2 velocity) {
        this.velocity.set(velocity);
    }

    public void setTransform(Vector2 position, float angle) {
        rectangle.setCenter(position);
    }


    public void setGravityScale(float gravityScale) {
        this.gravityScale = gravityScale;
    }

    public void setUserData(ServerEntity entity) {
        this.entity = entity;
    }
    
    public ServerEntity getUserData() {
        return entity;
    }

    public void update(float delta) {
        
        float xOffset = 0;
        
        if (toDestroy) {
            return;
        }
        velocity.x -= (xDamping * delta * velocity.x);
        
        grounded = false;
        // Calculate velocity
        temp2.set(world.gravity);
        temp2.scl(gravityScale);
        temp2.scl(delta);
        velocity.add(temp2);
        temp2.set(velocity);
        temp2.scl(delta);

        if (rectangle.x + rectangle.width > WorldRenderer.VIEWPORT_WIDTH 
                && velocity.x > 0) {
            xOffset = -WorldRenderer.VIEWPORT_WIDTH;
        } else if (rectangle.x < 0 && velocity.x < 0) {
            xOffset = WorldRenderer.VIEWPORT_WIDTH;
        }
        rectangle.x += xOffset;
        // Update position
        rectangle.getPosition(temp1);
        temp1.add(temp2);
        rectangle.getPosition(temp2);
        rectangle.getPosition(temp4);
        temp2.sub(temp1);
        
        if (Math.abs(velocity.y) > 5) {
            rectangle.setPosition(rectangle.x, temp1.y);
            for (Body body: world.bodies) {
                if (toDestroy || body == this || body.toDestroy ||
                        (body.category != CollisionCategory.ALL &&
                        body.category == category) 
                        || body.category ==CollisionCategory.NONE ||
                        (category == CollisionCategory.NONE && 
                        body.bodyType !=BodyType.StaticBody))
                    continue;
                if (body.rectangle.overlaps(rectangle)) {
                    solveVerticalCollision(body, temp1);
                }
            }
        }
        rectangle.setPosition(temp1.x, rectangle.y);
        for (Body body: world.bodies) {
            if (toDestroy || body == this || body.toDestroy ||
                    (body.category != CollisionCategory.ALL &&
                    body.category == category)
                    || body.category ==CollisionCategory.NONE ||
                    (category == CollisionCategory.NONE && 
                    body.bodyType !=BodyType.StaticBody))
                continue;
            if (body == this || body.toDestroy)
                continue;
            if (body.rectangle.overlaps(rectangle)) {
                solveHorizontalCollision(body, temp1);
            }
        }
        
        if (Math.abs(velocity.y) <= 5) {
            rectangle.setPosition(rectangle.x, temp1.y);
            for (Body body: world.bodies) {
                if (toDestroy || body == this || body.toDestroy ||
                        (body.category != CollisionCategory.ALL &&
                        body.category == category) 
                        || body.category ==CollisionCategory.NONE ||
                        (category == CollisionCategory.NONE && 
                        body.bodyType !=BodyType.StaticBody))
                    continue;
                if (body.rectangle.overlaps(rectangle)) {
                    solveVerticalCollision(body, temp1);
                }
            }
        }        
        rectangle.x -= xOffset;
    }

    public void applyLinearImpulse(float x, float y) {
        temp1.set(velocity);
        velocity.set(temp1.x + x, temp1.y + y);
    }
    
    public void solveHorizontalCollision(Body body, Vector2 temp1) {
        if (velocity.x < 0) {
            float x = body.rectangle.x + body.rectangle.width + 0.01f;
            temp1.x = Math.abs(temp4.x - x) < Math.abs(temp4.x - temp2.x) ?
                    x : temp4.x;
            velocity.x *= -restitutionX;
            CollisionProcessor.touchLeft(this, body);
        } else if(velocity.x > 0){
            float x = body.rectangle.x - rectangle.width - 0.01f;
            temp1.x = Math.abs(temp4.x - x) < Math.abs(temp4.x - temp2.x) ? x : temp4.x;
            velocity.x *= -restitutionX;
            CollisionProcessor.touchRight(this, body);
        }
        rectangle.setPosition(temp1.x, rectangle.y);
    }
    
    public void solveVerticalCollision(Body body, Vector2 position) {
        temp5.set(position);
        if (velocity.y > 0){
            float y = body.rectangle.y - rectangle.height - 0.01f;
            position.y = Math.abs(temp4.y - y) < Math.abs(temp4.y - temp2.y) ?
                    y: temp4.y;
            velocity.y *= -restitutionY;
            CollisionProcessor.jumpedOn(this, body);
        } else if(velocity.y <= 0) {
            float y = body.rectangle.y + body.rectangle.height + 0.01f;
            position.y = Math.abs(temp4.y - y) < Math.abs(temp4.y - temp2.y) ?
                    y: temp4.y;
            velocity.y *= -restitutionY;
            if (body.bodyType == BodyType.StaticBody) {
                grounded = true;
            } else {
                grounded = false;
            }
            CollisionProcessor.jumpOn(this, body);
        }
        rectangle.setPosition(rectangle.x, position.y);
    }

}
 public enum BodyType { StaticBody, DynamicBody }
 public class Ray {
    
    private final static Vector2 temp = new Vector2();

    public static Body findBody(World world, Body srcBody,
            Vector2 step, float length, boolean staticOnly) {
        Vector2 start = srcBody.getPosition();
        Body body = null;
        if (step.isZero()) {
            return null;
        }
        
        step.scl(2);
        
        float bestLength = 100000;
        length *= length;
        for (int i = 0; i < world.bodies.size(); i++) {
            if (staticOnly &&
                    world.bodies.get(i).bodyType != BodyType.StaticBody) {
                continue;
            }
            if (world.bodies.get(i) == srcBody) {
                continue;
            }
            temp .set(start);
            float currentLength = temp.dst2(start);
            while (currentLength < length && currentLength < bestLength) {
                if(world.bodies.get(i).rectangle.contains((temp.x + 
                        WorldRenderer.VIEWPORT_WIDTH) % 
                        WorldRenderer.VIEWPORT_WIDTH,
                        (temp.y + WorldRenderer.VIEWPORT_HEIGHT) %
                        WorldRenderer.VIEWPORT_HEIGHT)) {
                    body = world.bodies.get(i);
                    bestLength = currentLength;
                    continue;
                }
                temp.add(step);
                currentLength = temp.dst2(start);
            }
        }
        return body;
    }
    
    public static Body findBody(World world, Body srcBody,
            Vector2 step, float length) {
        return findBody(world, srcBody, step, length, false);
    }

}
 public class World {
    
    public final Vector2 gravity;
    public final ArrayList<Body> bodies;

    public World(Vector2 gravity) {
        this.gravity = gravity;
        bodies = new ArrayList<Body>();
    }

    public void step(float delta, int iterations, WorldManager worldManager) {
        int i = 0;
        while (i < bodies.size()) {
            Body body = bodies.get(i);
            if (body.toDestroy) {
                worldManager.destroyBody(body);
                bodies.remove(i);
            }
            i++;
        }
        for (i = 0; i< iterations; i++) {
            for (Body body: bodies) {
                if (body.getUserData() instanceof ServerPlayer)
                    body.update(delta/(float)iterations);
            }
            
            for (Body body: bodies) {
                if (body.bodyType == BodyType.DynamicBody && 
                        !(body.getUserData() instanceof ServerPlayer))
                    body.update(delta/(float)iterations);
            }
        }
    }
    
    public void addBody(Body body) {
        bodies.add(body);
    }

}
 public class AudioMessage implements Poolable{
    public byte audio;

    @Override
    public void reset() {
        audio = 0;
    }
    
    public void jump() {
        audio |= 1 << 0;
    }
    
    public void shoot() {
        audio |= 1 << 1;
    }
    
    public void hurt() {
        audio |= 1 << 2;
    }
    
    public void explode() {
        audio |= 1 << 3;
    }
    
    public void jumpedOn() {
        audio |= 1 << 4;
    }    
    
    public boolean getJump() {
        return ((audio & (1 << 0)) != 0);
    }
    
    public boolean getShoot() {
        return ((audio & (1 << 1)) != 0);
    }
    
    public boolean getHurt() {
        return ((audio & (1 << 2)) != 0);
    }
    
    public boolean getExplode() {
        return ((audio & (1 << 3)) != 0);
    }
    
    public boolean getJumpedOn() {
        return ((audio & (1 << 4)) != 0);
    }
    
}
 public class ServerArrow extends ServerEntity implements NonExplodingWeaponCategory {

    public static final float RADIUS = 3.5f;
    private float velocity;
    private Vector2 target;

    public float gravityTime;
    private Vector2 tempVector;
    
    public ServerArrow(short id, float x, float y, WorldBodyUtils world) {
        super(id, x, y, world);
        actorType = ActorType.ARROW;
        body = world.addBox(RADIUS, RADIUS, position.x, position.y,
                BodyType.DynamicBody);
        body.setLinearVelocity(velocity, 0);
        body.setGravityScale(0.01f);
        body.setUserData(this);
        gravityTime = 0.5f;
        tempVector = new Vector2();
    }
    
    @Override
    public void update(float delta) {
        gravityTime -= delta;
        Vector2 velocityVector = body.getLinearVelocity();
        position.set(body.getPosition());
        Body targetBody = Ray.findBody(world.worldManager.getWorld(),
                body, tempVector.set(Math.signum(velocityVector.x), 0), 200f);
        position.set(body.getPosition());
//        Gdx.app.log(body.getPosition().toString(), target.toString());
        if (target != null) {
            Vector2 currentVelocity = body.getLinearVelocity();
            Vector2 targetVelocity = tempVector.set(target);
            targetVelocity.sub(position);
            targetVelocity.scl(1/targetVelocity.x);
            targetVelocity.scl(currentVelocity.x);
            if(Math.abs(currentVelocity.x) > 1) {
                if(Math.abs(position.x - target.x) < 200 &&
                        Math.abs(position.y - target.y) < 100) {
                    if (currentVelocity.y < targetVelocity.y) {
                        currentVelocity.y += 50f / Math.ceil(Math.abs(position.y - target.y));
                    } else {
                        currentVelocity.y -= 50f / Math.ceil(Math.abs(position.y - target.y));
                    }
                    body.setLinearVelocity(currentVelocity);
                }
            }
        }
        
        if (Utils.wrapBody(position)) {
            body.setTransform(position, 0);
        }
        
        if (gravityTime < 0) {
            body.setGravityScale(0.5f);
        }
    }
    
    public void setTarget(Vector2 target) {
        this.target = target;
    }

    @Override
    public void dispose() {
        world.destroyBody(body);
    }

    @Override
    public void updateState(EntityState state) {
        super.updateState(state);
        state.angle = MathUtils.atan2(body.getLinearVelocity().y, body.getLinearVelocity().x);
    }

    @Override
    public float getWidth() {
        return RADIUS;
    }

    @Override
    public ServerEntity getShooter() {
        // TODO Auto-generated method stub
        return null;
    }
}
 public class ServerBomb extends ServerEntity implements ExplodingWeaponCategory {

    public static final float RADIUS = 10f;
    public ServerEntity bomber;
    public float destroyTime;
    private float velocity;
    
    public ServerBomb(short id, float x, float y, WorldBodyUtils world) {
        super(id, x, y, world);
        actorType = ActorType.BOMB;
        body = world.addBox(RADIUS, RADIUS, position.x, position.y,
                BodyType.DynamicBody);
        body.setLinearVelocity(velocity, 0);
        body.setUserData(this);
        body.restitutionX = 0.5f;
        body.restitutionY = 0.5f;
        destroyTime = 1.5f;
        body.setGravityScale(0.75f);
        body.xDamping = 0.02f;
    }
    
    @Override
    public void update(float delta) {
        destroyTime -= delta;
        position.set(body.getPosition());
        
        if (Utils.wrapBody(position)) {
            body.setTransform(position, 0);
        }
        
        if (destroyTime < 0) {
            explode();
        }
    }
    
    @Override
    public void dispose() {
        world.destroyBody(body);
    }

    @Override
    public void updateState(EntityState state) {
        super.updateState(state);
        state.angle = MathUtils.atan2(body.getLinearVelocity().y,
                body.getLinearVelocity().x);
    }

    @Override
    public float getWidth() {
        return RADIUS;
    }

    @Override
    public void explode() {
        if (body.toDestroy) {
            return;
        }
        world.audio.explode();
        Vector2 position = body.getPosition();
        world.destroyEntities(this, 35, position);
        
        if (position.x > WorldRenderer.VIEWPORT_WIDTH - 20) {
            position.x -= WorldRenderer.VIEWPORT_WIDTH;
        } else if (position.x < 20) {
            position.x += WorldRenderer.VIEWPORT_WIDTH;
        }
        world.destroyEntities(this, 35, position);
          
        position = body.getPosition();

        if (position.y > WorldRenderer.VIEWPORT_HEIGHT - 20) {
            position.y -= WorldRenderer.VIEWPORT_HEIGHT;
        } else if (position.x < 20) {
            position.y += WorldRenderer.VIEWPORT_HEIGHT;
        }
        world.destroyEntities(this, 35, position);
        
        dispose();
    }

    @Override
    public ServerEntity getBomber() {
        return bomber;
    }

}
 public class ServerBullet extends ServerEntity implements NonExplodingWeaponCategory {

    public static final float RADIUS = 5f;
    private float velocity;
    public float destroyTime;
    public ServerEntity shooter;
    
    public ServerBullet(short id, float x, float y, WorldBodyUtils world) {
        super(id, x, y, world);
        actorType = ActorType.BULLET;
        body = world.addBox(RADIUS, RADIUS, position.x, position.y,
                BodyType.DynamicBody);
        body.setLinearVelocity(velocity, 0);
        body.setGravityScale(0f);
        body.setUserData(this);
        destroyTime = 1f;
    }
    
    @Override
    public void update(float delta) {
        destroyTime -= delta;
        position.set(body.getPosition());
        
        if (Utils.wrapBody(position)) {
            body.setTransform(position, 0);
        }
        
        if (destroyTime < 0) {
            dispose();
        }
    }
    
    @Override
    public void dispose() {
        world.destroyBody(body);
    }

    @Override
    public void updateState(EntityState state) {
        super.updateState(state);
        state.angle = MathUtils.atan2(body.getLinearVelocity().y, body.getLinearVelocity().x);
    }

    @Override
    public float getWidth() {
        return RADIUS;
    }

    @Override
    public void addKill() {
        // TODO Auto-generated method stub
        
    }

    @Override
    public ServerEntity getShooter() {
        return shooter;
    }
}
 public abstract class ServerEntity {
    public ActorType actorType;
    public short id;
    protected boolean toLoadAssets;
    protected final Vector2 position;
    protected WorldBodyUtils world;
    public Body body;
    
    
    public ServerEntity(short id, float x, float y, WorldBodyUtils world){
        position = new Vector2(x, y);
        toLoadAssets = true;
        this.id = id;
        this.world = world;
    }

    public abstract void update(float delta);

    public abstract void dispose();

    public void updateState(EntityState state) {
        state.id = id;
        state.type = EntityUtils.actorTypeToByte(actorType);
        state.x = body.getPosition().x;
        state.y =  body.getPosition().y;
    }
    
    public abstract float getWidth();

    public void addKill(){
        
    }
    
    public boolean spawning() {
        return false;
    }

    public void reduceKill() {
        
    }

}
 public class ServerPlayer extends ServerEntity implements LivingCategory {

    public static final float WIDTH = 12;
    public static final float HEIGHT = 20;
    public static final float YOFFSET = 1f;
    private ControlsMessage currentControls;
    private boolean markForDispose;
    private float reloadTime;
    private Vector2 velocity;
    private float direction;
    private float directionX;
    private float directionY;
    private float startX, startY;
    private float spawnTime;
    public byte score;
    private byte totalBombs;
    private float addBombTimer;
    private String name;
    
    public ServerPlayer(short id, float x, float y, WorldBodyUtils world) {
        super(id, x, y, world);
        startX = x;
        startY = y;
        markForDispose = false;
        currentControls = new ControlsMessage();
        actorType = ActorType.PLAYER;
        body = world.addBox(WIDTH, HEIGHT - YOFFSET * 2, x, y,
                BodyType.DynamicBody);
        body.setUserData(this);
        reloadTime = 0;
        velocity = new Vector2();
        spawnTime = 0.1f;
        direction = 1;
        score = 0;
        totalBombs = 3;
        addBombTimer = 0;
        name = "";
    }
    
    @Override
    public void update(float delta) {
        if (totalBombs < 3) {
            addBombTimer += delta;
            if (addBombTimer >= 10) {
               totalBombs++;
               addBombTimer = 0;
            }
        } else {
            addBombTimer = 0;
        }
//        Gdx.app.log(Short.toString(id), Byte.toString(score));
        if (spawnTime > 0) {
            spawnTime += delta;
            if (spawnTime > 2f) {
                body.bodyType = BodyType.DynamicBody;
                spawnTime = -1f;
            }
//            return;
        }
        if (markForDispose) {
            dispose();
            return;
        }
        processPlayer();
        position.set(body.getPosition());
        reloadTime += delta;
    }
    
    public void markForDispose() {
        markForDispose = true;
    }
    
    private void processPlayer() {
        processControls(currentControls);
    }

    public void processControls(ControlsMessage controls) {
        velocity.set(body.getLinearVelocity());
        position.set(body.getPosition());

        if (velocity.y < -200f) {
            velocity.y = -200f;
        }
        
        if (Utils.wrapBody(position)) {
            body.setTransform(position, 0);
        }
        
        float x = controls.right()? 1 : (controls.left()? -1 : Math.signum(directionX) * 0.01f);
        float y = controls.up()? 1 : (controls.down()? -1 : 0);
        if (Math.abs(x) < 0.02f && y==0) {
            x = direction;
        } else {
            direction = Math.signum(x);
        }
        if (Math.abs(x) ==1 && Math.abs(y) == 1) {
            x = Math.signum(x) * 0.707f;
            y = 0;
        }
        directionX = x;
        directionY = y;

        if (reloadTime > 1) {
            if (controls.shoot()) {
                    world.AddBullet(position.x + x * 15, position.y + y * 15, this).body.
                    setLinearVelocity(x * 200, y * 200);;
                    reloadTime = 0;
            } else if (controls.throwBomb() && totalBombs > 0) {
                ServerBomb bomb = world.AddBomb(position.x + Math.signum(x) * 15, position.y + 10, this);
                if (bomb != null) {
                    bomb.body.setLinearVelocity(Math.signum(x) * 100, 100);
                    reloadTime = 0;
                    totalBombs--;
                }
            }
        }
        
        if(Math.abs(velocity.x) < 100f) {
            if (controls.right()){
                velocity.x = 100f;
            } else if (controls.left()){
                velocity.x = -100f;
            }
        }
        if(!controls.right() && !controls.left()) {
            velocity.x += -0.1f * velocity.x;
        }
        
        body.setLinearVelocity(velocity);

        if (controls.jump() && body.grounded) {
            body.applyLinearImpulse(0, 290f);
            world.audio.jump();
        }
    }

    public void setCurrentControls(ControlsMessage currentControls) {
        this.currentControls.buttonPresses = currentControls.buttonPresses;
    }
    
    @Override
    public boolean kill() {
        if (spawnTime < 0) {
            world.audio.hurt();
            Vector2 position = body.getPosition();
            position.set(startX, startY);
            body.setTransform(position, 0);
            spawnTime = 0.1f;
            totalBombs = 3;
            return true;
        }
        return false;
    }

    @Override
    public void dispose() {
        world.destroyBody(body);
    }

    @Override
    public void updateState(EntityState state) {
        super.updateState(state);
        state.vX = body.getLinearVelocity().x;
        state.vY = body.getLinearVelocity().y;
        state.angle = (float) Math.atan2(directionY, directionX);
        state.extra |= (short) (spawnTime > 0.01f ? 0 : 1);
        state.extra |= (totalBombs << 1);
        state.extra |= (score << 4);
    }

    @Override
    public float getWidth() {
        return WIDTH;
    }

    @Override
    public void addKill() {
        score++;
    }

    public void setName(String name) {
        this.name = name;
    }
    
    public String getName() {
        return name;
    }
    
    @Override
    public void reduceKill() {
        score--;
    }
    
}

import java.util.ArrayList;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.maps.MapObject;
import com.badlogic.gdx.maps.objects.RectangleMapObject;
import com.badlogic.gdx.math.Circle;
import com.badlogic.gdx.math.Intersector;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.sillygames.killingSpree.categories.LivingCategory;
import com.sillygames.killingSpree.managers.physics.Body;
import com.sillygames.killingSpree.managers.physics.Body.BodyType;
import com.sillygames.killingSpree.managers.physics.Ray;
import com.sillygames.killingSpree.managers.physics.World;
import com.sillygames.killingSpree.networking.messages.AudioMessage;
import com.sillygames.killingSpree.serverEntities.ServerArrow;
import com.sillygames.killingSpree.serverEntities.ServerBomb;
import com.sillygames.killingSpree.serverEntities.ServerBullet;
import com.sillygames.killingSpree.serverEntities.ServerEntity;
import com.sillygames.killingSpree.serverEntities.ServerPlayer;

package com.sillygames.killingSpree.managers;



public class WorldBodyUtils {
    
    public WorldManager worldManager;
    public ArrayList<ServerEntity> entities;
    private Circle circle;
    public AudioMessage audio;
    private World world;
    private Vector2 tempPlayerPosition;
    
    public WorldBodyUtils(WorldManager worldManager) {
        circle = new Circle();
        this.worldManager = worldManager;
        entities = new ArrayList<ServerEntity>();
        audio = worldManager.audio;
        this.world = worldManager.getWorld();
        tempPlayerPosition = new Vector2();
    }
    
    public Body addBox(float w, float h, float x, float y, BodyType type){
        Body body = new Body(x - w/2, y - h/2, w, h, type);
        body.setWorld(world);
        world.bodies.add(body);
        return body;
    }

    public void createWorldObject(MapObject object) {
        if (object instanceof RectangleMapObject) {
            Rectangle rectangle = ((RectangleMapObject) object).getRectangle();
            Body body = new Body(rectangle);
            world.bodies.add(body);
            
            if (rectangle.x < 20) {
                rectangle = new Rectangle(rectangle);
                rectangle.x += WorldRenderer.VIEWPORT_WIDTH;
                body = new Body(rectangle);
                world.bodies.add(body);
            }
            
            if (rectangle.x + rectangle.width > WorldRenderer.VIEWPORT_WIDTH - 20) {
                rectangle = new Rectangle(rectangle);
                rectangle.x -= WorldRenderer.VIEWPORT_WIDTH;
                body = new Body(rectangle);
                world.bodies.add(body);
            }
            
            if (rectangle.y < 20) {
                rectangle = new Rectangle(rectangle);
                rectangle.y += WorldRenderer.VIEWPORT_HEIGHT;
                body = new Body(rectangle);
                world.bodies.add(body);
            }
            if (rectangle.y > WorldRenderer.VIEWPORT_HEIGHT - 20) {
                rectangle = new Rectangle(rectangle);
                rectangle.y -= WorldRenderer.VIEWPORT_WIDTH;
                body = new Body(rectangle);
                world.bodies.add(body);
            }
        }
    }
    
    public ServerArrow AddArrow(float x, float y) {
        ServerArrow arrow = new ServerArrow(worldManager.id++, x, y, this);
        arrow.body.setUserData(arrow);
        entities.add(arrow);
        return arrow;
    }
    

    public ServerBullet AddBullet(float x, float y, ServerPlayer shooter) {
