瀏覽代碼

refactoring, preparation for collision / physic update, collision moved
into entities / tiles

Kajetan Johannes Hammerle 5 年之前
父節點
當前提交
0252c11b6d
共有 39 個文件被更改,包括 788 次插入510 次删除
  1. 12 14
      levels/00-Tech_Demo.snuvi
  2. 14 10
      src/me/hammerle/supersnuvi/Game.java
  3. 3 1
      src/me/hammerle/supersnuvi/Keys.java
  4. 297 219
      src/me/hammerle/supersnuvi/entity/Entity.java
  5. 51 25
      src/me/hammerle/supersnuvi/entity/EntityBuilder.java
  6. 4 12
      src/me/hammerle/supersnuvi/entity/components/DefaultEnergy.java
  7. 3 24
      src/me/hammerle/supersnuvi/entity/components/DefaultHealth.java
  8. 2 14
      src/me/hammerle/supersnuvi/entity/components/DefaultMovement.java
  9. 2 9
      src/me/hammerle/supersnuvi/entity/components/Energy.java
  10. 2 20
      src/me/hammerle/supersnuvi/entity/components/Health.java
  11. 0 10
      src/me/hammerle/supersnuvi/entity/components/IDeath.java
  12. 10 0
      src/me/hammerle/supersnuvi/entity/components/IDespawn.java
  13. 2 26
      src/me/hammerle/supersnuvi/entity/components/Movement.java
  14. 5 4
      src/me/hammerle/supersnuvi/entity/components/StoneMovement.java
  15. 6 13
      src/me/hammerle/supersnuvi/entity/components/ai/Controller.java
  16. 24 16
      src/me/hammerle/supersnuvi/entity/components/ai/HumanController.java
  17. 41 27
      src/me/hammerle/supersnuvi/entity/components/ai/LondonerController.java
  18. 16 12
      src/me/hammerle/supersnuvi/entity/components/ai/PlatformController.java
  19. 7 13
      src/me/hammerle/supersnuvi/entity/components/ai/StartScreenHeroController.java
  20. 2 7
      src/me/hammerle/supersnuvi/entity/components/ai/StoneController.java
  21. 14 8
      src/me/hammerle/supersnuvi/gamelogic/Level.java
  22. 7 0
      src/me/hammerle/supersnuvi/math/IVector.java
  23. 84 0
      src/me/hammerle/supersnuvi/math/Vector.java
  24. 32 0
      src/me/hammerle/supersnuvi/tiles/BaseBoxTile.java
  25. 41 0
      src/me/hammerle/supersnuvi/tiles/BaseCollisionTile.java
  26. 3 2
      src/me/hammerle/supersnuvi/tiles/BottledSoulTile.java
  27. 2 2
      src/me/hammerle/supersnuvi/tiles/CrumblingStoneTile.java
  28. 2 2
      src/me/hammerle/supersnuvi/tiles/GoalTile.java
  29. 3 3
      src/me/hammerle/supersnuvi/tiles/InteractTile.java
  30. 2 2
      src/me/hammerle/supersnuvi/tiles/KillTile.java
  31. 3 3
      src/me/hammerle/supersnuvi/tiles/PressureTile.java
  32. 24 0
      src/me/hammerle/supersnuvi/tiles/RampTile.java
  33. 2 2
      src/me/hammerle/supersnuvi/tiles/SlipperyTile.java
  34. 2 2
      src/me/hammerle/supersnuvi/tiles/SpikeTile.java
  35. 15 0
      src/me/hammerle/supersnuvi/tiles/Tile.java
  36. 1 1
      src/me/hammerle/supersnuvi/tiles/TrampolinTile.java
  37. 4 4
      src/me/hammerle/supersnuvi/tiles/WaterTile.java
  38. 4 3
      src/me/hammerle/supersnuvi/util/Face.java
  39. 40 0
      src/me/hammerle/supersnuvi/util/Utils.java

+ 12 - 14
levels/00-Tech_Demo.snuvi

@@ -4,7 +4,7 @@ event.load("tile_hit");
 event.load("auto_tile_interact");
 event.load("auto_tile_interact");
 //event.load("entity_spawn");
 //event.load("entity_spawn");
 
 
-sgoto(0, @loop);
+//sgoto(0, @loop);
 
 
 @main
 @main
 wait();
 wait();
@@ -31,20 +31,18 @@ elseif(event == "entity_spawn")
 goto(@main);
 goto(@main);
 
 
 
 
-@loop
-
-light.setPositionSmooth(0, entity.getX(entity.getHero()) + 16, entity.getY(entity.getHero()) + 32);
-
-sgoto(0, @loop);
-goto(@main);
+//@loop
+//light.setPositionSmooth(0, entity.getX(entity.getHero()) + 16, entity.getY(entity.getHero()) + 32);
+//sgoto(0, @loop);
+//goto(@main);
 
 
 
 
 function onLevelReset()
 function onLevelReset()
 {
 {
-    light.setAmbient(0.0, 0.0, 0.0);
-    light.setColor(0, 1.2, 0.9, 0);
-    light.setPosition(0, entity.getX(entity.getHero()), entity.getY(entity.getHero()));
-    light.setStrength(0, 0.005);
+    //light.setAmbient(0.0, 0.0, 0.0);
+    //light.setColor(0, 1.2, 0.9, 0);
+    //light.setPosition(0, entity.getX(entity.getHero()), entity.getY(entity.getHero()));
+    //light.setStrength(0, 0.005);
     
     
     hero = entity.getHero();
     hero = entity.getHero();
     x = tile.toTileCoord(entity.getX(hero));
     x = tile.toTileCoord(entity.getX(hero));
@@ -72,9 +70,9 @@ function onLevelReset()
     level.setTile(index, 7, 11, 73);
     level.setTile(index, 7, 11, 73);
     level.setTile(index, 8, 10, 74);
     level.setTile(index, 8, 10, 74);
     
     
-    $platform = platform.spawn(tile.toLevelCoord(3), tile.toLevelCoord(3), 3);
-    platform.addmove($platform, tile.toLevelCoord(0), tile.toLevelCoord(9), 1, 2, 50);
-    platform.addmove($platform, tile.toLevelCoord(3), tile.toLevelCoord(3), 1, 2, 50);
+    $platform = platform.spawn(tile.toLevelCoord(5), tile.toLevelCoord(11), 3);
+    platform.addmove($platform, tile.toLevelCoord(5), tile.toLevelCoord(11), 6, 4, 1);
+    platform.addmove($platform, tile.toLevelCoord(5), tile.toLevelCoord(5), 6, 4, 1);
 }
 }
 
 
 function onInteract(x, y, ent)
 function onInteract(x, y, ent)

+ 14 - 10
src/me/hammerle/supersnuvi/Game.java

@@ -128,7 +128,10 @@ public class Game extends Engine
             SoundUtils.stopSound(SoundUtils.Sound.MENU_MUSIC);
             SoundUtils.stopSound(SoundUtils.Sound.MENU_MUSIC);
             
             
             snuviScheduler.setActiveLevel(currentLevel);
             snuviScheduler.setActiveLevel(currentLevel);
-            currentLevel.tick();
+            //if(Keys.TEST.isReleased())
+            {
+                currentLevel.tick();
+            }
             snuviScheduler.tick(currentLevel);
             snuviScheduler.tick(currentLevel);
             
             
             // doing that here to prevent concurent modification
             // doing that here to prevent concurent modification
@@ -306,7 +309,8 @@ public class Game extends Engine
         }
         }
     }
     }
     
     
-    private final static int COLOR_OVERLAY = 0x77000000;
+    private final static int COLOR_OVERLAY = 0x77808080;
+    private final static int COLOR_OVERLAY2 = 0x77202020;
 
 
     private String getKeyName(KeyBinding key)
     private String getKeyName(KeyBinding key)
     {
     {
@@ -356,7 +360,7 @@ public class Game extends Engine
                 Shader.setBlendingEnabled(true);
                 Shader.setBlendingEnabled(true);
                 cr.drawRectangle(left, top, right, bottom, COLOR_OVERLAY);
                 cr.drawRectangle(left, top, right, bottom, COLOR_OVERLAY);
                 float base = top + (3 + startScreenIndex) * line;
                 float base = top + (3 + startScreenIndex) * line;
-                cr.drawRectangle(left, base, right, base + line, COLOR_OVERLAY);
+                cr.drawRectangle(left, base, right, base + line, COLOR_OVERLAY2);
                 Shader.setBlendingEnabled(false);
                 Shader.setBlendingEnabled(false);
                         
                         
                 Shader.setTextureEnabled(true);
                 Shader.setTextureEnabled(true);
@@ -392,7 +396,7 @@ public class Game extends Engine
                 Shader.setBlendingEnabled(true);
                 Shader.setBlendingEnabled(true);
                 cr.drawRectangle(left, top, right, bottom, COLOR_OVERLAY);
                 cr.drawRectangle(left, top, right, bottom, COLOR_OVERLAY);
                 float base = top + (3 + slotScreenIndex) * line;
                 float base = top + (3 + slotScreenIndex) * line;
-                cr.drawRectangle(left, base, right, base + line, COLOR_OVERLAY);
+                cr.drawRectangle(left, base, right, base + line, COLOR_OVERLAY2);
                 Shader.setBlendingEnabled(false);
                 Shader.setBlendingEnabled(false);
                         
                         
                 Shader.setTextureEnabled(true);
                 Shader.setTextureEnabled(true);
@@ -429,7 +433,7 @@ public class Game extends Engine
                 Shader.setBlendingEnabled(true);
                 Shader.setBlendingEnabled(true);
                 cr.drawRectangle(left, top, right, bottom, COLOR_OVERLAY);
                 cr.drawRectangle(left, top, right, bottom, COLOR_OVERLAY);
                 float base = top + (3 + optionScreenIndex) * line;
                 float base = top + (3 + optionScreenIndex) * line;
-                cr.drawRectangle(left, base, right, base + line, COLOR_OVERLAY);
+                cr.drawRectangle(left, base, right, base + line, COLOR_OVERLAY2);
                 Shader.setBlendingEnabled(false);
                 Shader.setBlendingEnabled(false);
                         
                         
                 Shader.setTextureEnabled(true);
                 Shader.setTextureEnabled(true);
@@ -522,7 +526,7 @@ public class Game extends Engine
                     baseIndex = half;
                     baseIndex = half;
                 }
                 }
                 float base = top + (3 + baseIndex) * line;
                 float base = top + (3 + baseIndex) * line;
-                cr.drawRectangle(left, base, right, base + line, COLOR_OVERLAY);
+                cr.drawRectangle(left, base, right, base + line, COLOR_OVERLAY2);
                 Shader.setBlendingEnabled(false);
                 Shader.setBlendingEnabled(false);
                         
                         
                 Shader.setTextureEnabled(true);
                 Shader.setTextureEnabled(true);
@@ -777,16 +781,16 @@ public class Game extends Engine
             ent.setPosition(x, y);
             ent.setPosition(x, y);
             return Void.TYPE;
             return Void.TYPE;
         });
         });
-        snuviParser.registerFunction("entity.getmotionx", (sc, in) -> (double) ((Entity) in[0].get(sc)).getMotionX());
-        snuviParser.registerFunction("entity.getmotiony", (sc, in) -> (double) ((Entity) in[0].get(sc)).getMotionY());
+        snuviParser.registerFunction("entity.getmotionx", (sc, in) -> (double) ((Entity) in[0].get(sc)).getOwnForceX());
+        snuviParser.registerFunction("entity.getmotiony", (sc, in) -> (double) ((Entity) in[0].get(sc)).getOwnForceY());
         snuviParser.registerFunction("entity.setmotionx", (sc, in) -> 
         snuviParser.registerFunction("entity.setmotionx", (sc, in) -> 
         {
         {
-            ((Entity) in[0].get(sc)).setMotionX(in[1].getFloat(sc));
+            ((Entity) in[0].get(sc)).applyForce(in[1].getFloat(sc), 0.0f);
             return Void.TYPE;
             return Void.TYPE;
         });
         });
         snuviParser.registerFunction("entity.setmotiony", (sc, in) -> 
         snuviParser.registerFunction("entity.setmotiony", (sc, in) -> 
         {
         {
-            ((Entity) in[0].get(sc)).setMotionY(in[1].getFloat(sc));
+            ((Entity) in[0].get(sc)).applyForce(0.0f, in[1].getFloat(sc));
             return Void.TYPE;
             return Void.TYPE;
         });
         });
         snuviParser.registerFunction("entity.ishero", (sc, in) -> currentLevel.getHero() == in[0].get(sc));
         snuviParser.registerFunction("entity.ishero", (sc, in) -> currentLevel.getHero() == in[0].get(sc));

+ 3 - 1
src/me/hammerle/supersnuvi/Keys.java

@@ -17,10 +17,12 @@ public class Keys
     public final static KeyBinding ESCAPE = KeyHandler.register(GLFW_KEY_ESCAPE);
     public final static KeyBinding ESCAPE = KeyHandler.register(GLFW_KEY_ESCAPE);
     public final static KeyBinding ENTER = KeyHandler.register(GLFW_KEY_ENTER);
     public final static KeyBinding ENTER = KeyHandler.register(GLFW_KEY_ENTER);
     
     
+    public final static KeyBinding TEST = KeyHandler.register(GLFW_KEY_T);
+    
     private final static KeyBinding[] KEYS = 
     private final static KeyBinding[] KEYS = 
     {
     {
         UP, DOWN, LEFT, RIGHT, 
         UP, DOWN, LEFT, RIGHT, 
-        JUMP, RUN, ESCAPE, ENTER
+        JUMP, RUN, ESCAPE, ENTER, TEST
     };
     };
     
     
     public static void rebind(KeyBinding binding)
     public static void rebind(KeyBinding binding)

+ 297 - 219
src/me/hammerle/supersnuvi/entity/Entity.java

@@ -1,72 +1,61 @@
 package me.hammerle.supersnuvi.entity;
 package me.hammerle.supersnuvi.entity;
 
 
-import java.util.List;
 import me.hammerle.supersnuvi.entity.components.ai.Controller;
 import me.hammerle.supersnuvi.entity.components.ai.Controller;
 import me.hammerle.supersnuvi.entity.components.Energy;
 import me.hammerle.supersnuvi.entity.components.Energy;
 import me.hammerle.supersnuvi.entity.components.Health;
 import me.hammerle.supersnuvi.entity.components.Health;
 import me.hammerle.supersnuvi.entity.components.ItemCollector;
 import me.hammerle.supersnuvi.entity.components.ItemCollector;
 import me.hammerle.supersnuvi.entity.components.Movement;
 import me.hammerle.supersnuvi.entity.components.Movement;
 import me.hammerle.supersnuvi.tiles.Tile;
 import me.hammerle.supersnuvi.tiles.Tile;
-import me.hammerle.supersnuvi.util.CollisionObject;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.util.Utils;
 import me.hammerle.supersnuvi.util.Utils;
 import me.hammerle.supersnuvi.gamelogic.Level;
 import me.hammerle.supersnuvi.gamelogic.Level;
+import me.hammerle.supersnuvi.math.Vector;
+import me.hammerle.supersnuvi.entity.components.IDespawn;
 
 
 public final class Entity
 public final class Entity
 {
 {
     public static final float GRAVITY = 8.0f * Tile.SIZE_SCALE;
     public static final float GRAVITY = 8.0f * Tile.SIZE_SCALE;
     public static final float STEP = 0.0625f;
     public static final float STEP = 0.0625f;
     // this one is a little bit bigger to prevent wrong calculation
     // this one is a little bit bigger to prevent wrong calculation
-    // while joing upwars
+    // while going upwards
     public static final float UP_STEP = STEP + 0.00390625f;
     public static final float UP_STEP = STEP + 0.00390625f;
     
     
     // the last position is used for interpolation during rendering
     // the last position is used for interpolation during rendering
-    private float lastPosX;
-    private float lastPosY;
+    private final Vector lastPos = new Vector();
     // the current position of the entity
     // the current position of the entity
-    private float posX;
-    private float posY;
-    
-    // the collision box of the entity
-    private final CollisionObject box;
-    
-    // the motion before the movement collision check
-    private float preMotionX;
-    private float preMotionY;
-    // the motion after the movement collision check
-    private float motionX;
-    private float motionY;
-    
+    private final Vector pos = new Vector();
+    // the width of the entity
+    private final float width;
+    // the height of the entity
+    private final float height;  
+    // own force used by the controller component
+    private final Vector ownForce = new Vector();
+    // the motion, reduced by the movement collision check
+    private final Vector motion = new Vector();
+    // the friction reducing motion each tick
+    private final Vector friction = new Vector(0.0f, 1.0f);
     // a flag indicating that the entity is on the ground
     // a flag indicating that the entity is on the ground
     private boolean onGround = true;
     private boolean onGround = true;
-    
     // entity components
     // entity components
-    protected Controller controller = Controller.NULL;
-    protected Health health = Health.NULL;
-    protected Energy energy = Energy.NULL;
-    protected Movement move = Movement.NULL;
-    protected ItemCollector itemCollector = ItemCollector.NULL;
-    
-    // face
-    private Face face = Face.RIGHT;
-    
+    private final Controller controller;
+    private final Health health;
+    private final Energy energy;
+    private final Movement move;
+    private final ItemCollector itemCollector;
+    private final IDespawn onDespawn;
+    // the type of the entity, used by snuvi script
     private final String type;
     private final String type;
     
     
-    protected Entity(String type, float x, float y, CollisionObject box)
+    protected Entity(float width, float height, Controller c, Health h, Energy e, Movement m, ItemCollector ic, IDespawn d, String type)
     {
     {
-        lastPosX = x;
-        lastPosY = y;
-        posX = x;
-        posY = y;
-
-        // ensure the box cannot be modified from the outside
-        this.box = box.copy().offset(x, y);
-        
-        preMotionX = 0.0f;
-        preMotionY = 0.0f;
-        motionX = 0.0f;
-        motionY = 0.0f;
-        
+        this.width = width;
+        this.height = height;
+        this.controller = c;
+        this.health = h;
+        this.energy = e;
+        this.move = m;
+        this.itemCollector = ic;
+        this.onDespawn = d;
         this.type = type;
         this.type = type;
     }
     }
     
     
@@ -109,119 +98,126 @@ public final class Entity
         return itemCollector;
         return itemCollector;
     }
     }
     
     
+    public void onDespawn()
+    {
+        onDespawn.onDespawn(this);
+    }
+    
     //--------------------------------------------------------------------------
     //--------------------------------------------------------------------------
     // basic stuff
     // basic stuff
     //--------------------------------------------------------------------------
     //--------------------------------------------------------------------------
     
     
     public float getSquaredDistance(Entity e)
     public float getSquaredDistance(Entity e)
     {
     {
-        return Utils.getSquaredDistance(
-                posX + box.getWidth() * 0.5f, posY + box.getHeight() * 0.5f, 
-                e.posX + e.box.getWidth() * 0.5f, e.posY + e.box.getHeight() * 0.5f);
-    }
-    
-    public CollisionObject getBox()
-    {
-        return box;
+        return Utils.getSquaredDistance(getCenterX(), getCenterY(), e.getCenterX(), e.getCenterY());
     }
     }
     
     
     public float getX()
     public float getX()
     {
     {
-        return posX;
+        return pos.getX();
     }
     }
     
     
     public float getY()
     public float getY()
     {
     {
-        return posY;
+        return pos.getY();
     }
     }
     
     
     public void setPosition(float x, float y)
     public void setPosition(float x, float y)
     {
     {
-        lastPosX = x;
-        lastPosY = y;
-        posX = x;
-        posY = y;
-        box.reset().offset(posX, posY);
+        lastPos.set(x, y);
+        pos.set(x, y);
     }
     }
     
     
     public float getLastX()
     public float getLastX()
     {
     {
-        return lastPosX;
+        return lastPos.getX();
     }
     }
     
     
     public float getLastY()
     public float getLastY()
     {
     {
-        return lastPosY;
+        return lastPos.getY();
     }
     }
     
     
     public float getCenterX()
     public float getCenterX()
     {
     {
-        return posX + box.getWidth() * 0.5f;
+        return pos.getX() + width * 0.5f;
     }
     }
     
     
     public float getCenterY()
     public float getCenterY()
     {
     {
-        return posY + box.getHeight() * 0.5f;
+        return pos.getY() + height * 0.5f;
     }
     }
     
     
     public float getWidth()
     public float getWidth()
     {
     {
-        return box.getWidth();
+        return width;
     }
     }
     
     
     public float getHeight()
     public float getHeight()
     {
     {
-        return box.getHeight();
+        return height;
+    }
+    
+    public float getMotionX()
+    {
+        return motion.getX();
     }
     }
     
     
-    public Face getFace()
+    public float getMotionY()
     {
     {
-        if(motionX == 0.0f)
-        {
-            return face;
-        }
-        face = motionX < 0.0f ? Face.LEFT : Face.RIGHT;
-        return face;
+        return motion.getY();
     }
     }
     
     
-    public void updateFace()
+    public float getOwnForceX()
     {
     {
-        
+        return ownForce.getX();
     }
     }
     
     
-    public float getMotionX()
+    public float getOwnForceY()
     {
     {
-        return motionX;
+        return ownForce.getY();
+    }
+
+    public void applyOwnForce(float x, float y)
+    {
+        ownForce.add(x, y);
     }
     }
     
     
-    public void setMotionX(float motionX)
+    public void applyForce(float x, float y)
     {
     {
-        this.motionX = motionX;
+        motion.add(x, y);
     }
     }
     
     
-    public float getMotionY()
+    public void setFriction(float fx, float fy)
     {
     {
-        return motionY;
+        friction.set(fx, fy);
     }
     }
     
     
-    public void setMotionY(float motionY)
+    public boolean isAt(float x, float y)
     {
     {
-        this.motionY = motionY;
+        return Math.abs(x - pos.getX()) < STEP && Math.abs(y - pos.getY()) < STEP;
     }
     }
     
     
-    public float getPreMotionX()
+    public boolean isColliding(float minX, float minY, float maxX, float maxY)
     {
     {
-        return preMotionX;
+        return maxX > getX() && getX() + width > minX && maxY > getY() && getY() + height > minY;
     }
     }
     
     
-    public float getPreMotionY()
+    private Face getCollidingFace(Entity o)
     {
     {
-        return preMotionY;
+        return Utils.getCollidingFace(
+                o.getX(), o.getY(), o.getX() + o.getWidth(), o.getY() + o.getHeight(),
+                getX(), getY(), getX() + getWidth(), getY() + getHeight());
     }
     }
     
     
-    public boolean isAt(float x, float y)
+    public boolean jump() 
     {
     {
-        return Math.abs(x - posX) < STEP && Math.abs(y - posY) < STEP;
+        if(onGround)
+        {
+            ownForce.addY(-move.getJumpPower());
+            return true;
+        }
+        return false;
     }
     }
     
     
     //--------------------------------------------------------------------------
     //--------------------------------------------------------------------------
@@ -230,175 +226,257 @@ public final class Entity
     
     
     public void tick(Level level) 
     public void tick(Level level) 
     {
     {
-        lastPosX = posX;
-        lastPosY = posY;
+        // reset own force
+        ownForce.set(0.0f, 0.0f);
         
         
-        controller.tick(level);
-        energy.tick();
+        // remeber last position for rendering
+        lastPos.set(pos);
         
         
-        preMotionX = motionX;
-        preMotionY = motionY;
+        // update onGround before controller tick
+        // ToDo: does not work for ramps
+        onGround = isOnTileGround(level);
         
         
-        if(move.hasGravity())
+        // tick components
+        controller.tick(this, level);
+        energy.tick(this);
+        health.tick();
+        
+        // apply gravity if needed
+        if(move.hasGravity(this))
         {
         {
-            preMotionY += GRAVITY * move.getGravityFactor();
+            motion.addY(GRAVITY * move.getGravityFactor());
         }
         }
 
 
+        // apply friction
+        motion.mul(friction);
+        
+        // modify current motion by own force
+        motion.add(ownForce);
+        
+        // (entity <-> tile) collision
+        doTileCollision(level);
+        // (entity <-> entity) collision
+        level.forEachCollidingEntity(this, (ent) -> 
+        {
+            controller.onCollideWithEntity(this, ent, getCollidingFace(ent));
+        });
+    }
+    
+    public void move(Level level)
+    {
+        reduceMotionByTiles(level);   
+        reduceMotionByEntities(level);     
+        pos.add(motion);
+    }
+    
+    private boolean isOnTileGround(Level level)
+    {
+        float minX = pos.getX();
+        float minY = pos.getY() + height;
+        float maxX = pos.getX() + width;
+        float maxY = pos.getY() + height + STEP * 2;
+        int startX = Utils.toBlock(minX);
+        int startY = Utils.toBlock(minY);
+        int endX = Utils.toBlock(maxX);
+        int endY = Utils.toBlock(maxY);
+
+        for(int x = startX; x <= endX; x++)
+        {
+            for(int y = startY; y <= endY; y++)
+            {
+                Tile t = level.getInteractionTile(x, y);
+                if(t.isMoveColliding(minX, minY, maxX, maxY, x, y, level))
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+    
+    private void doTileCollision(Level level)
+    {
+        float minX = pos.getX() - STEP;
+        float minY = pos.getY() - STEP;
+        float maxX = pos.getX() + width + STEP;
+        float maxY = pos.getY() + height + STEP;
+        int startX = Utils.toBlock(minX);
+        int startY = Utils.toBlock(minY);
+        int endX = Utils.toBlock(maxX);
+        int endY = Utils.toBlock(maxY);
+
+        for(int x = startX; x <= endX; x++)
+        {
+            for(int y = startY; y <= endY; y++)
+            {
+                Tile t = level.getInteractionTile(x, y);
+                if(t.isColliding(minX, minY, maxX, maxY, x, y, level))
+                {
+                    Face f = t.getCollidingFace(minX, minY, maxX, maxY, x, y, level);
+                    controller.onCollideWithTile(this, x, y, level, t, f);
+                    t.onEntityCollide(this, x, y, f.getOpposite(), level);
+                }
+            }
+        }
+    }
+    
+    private void reduceMotionByEntities(Level level)
+    {
+    }
+    
+    private boolean isCollidingWithTiles(int startX, int startY, int endX, int endY, Level level)
+    {
+        float minX = getX();
+        float minY = getY();
+        float maxX = minX + width;
+        float maxY = minY + height;
+        for(int x = startX; x <= endX; x++)
+        {
+            for(int y = startY; y <= endY; y++)
+            {
+                if(level.getInteractionTile(x, y).isMoveColliding(minX, minY, maxX, maxY, x, y, level))
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public void reduceMotionByTiles(Level level)
+    {
         if(move.canMoveEverywhere())
         if(move.canMoveEverywhere())
         {
         {
-            motionX = preMotionX;
-            motionY = preMotionY;
+            return;
+        }
+        
+        float mx = motion.getX();
+        float my = motion.getY();
+        
+        if(mx == 0.0f && my == 0.0f)
+        {
+            return;
+        }
+        
+        int startX;
+        int endX;
+        if(mx < 0.0f)
+        {
+            startX = Utils.toBlock(pos.getX() + mx);
+            endX = Utils.toBlock(pos.getX() + width);
         }
         }
         else
         else
         {
         {
-            CollisionObject testBox = box.copy().expand(preMotionX, preMotionY).expand(0.0f, -UP_STEP);
-            List<CollisionObject> boxes = level.getMovementBoxesAt(testBox, this);
-            if(!boxes.isEmpty())
+            startX = Utils.toBlock(pos.getX());
+            endX = Utils.toBlock(pos.getX() + width + mx);
+        }
+        
+        int startY;
+        int endY;
+        if(my < 0.0f)
+        {
+            startY = Utils.toBlock(pos.getY() + my);
+            endY = Utils.toBlock(pos.getY() + height);
+        }
+        else
+        {
+            startY = Utils.toBlock(pos.getY());
+            endY = Utils.toBlock(pos.getY() + height + my);
+        }
+        
+        
+        float oldPosX = pos.getX();
+        float oldPosY = pos.getY();
+        
+        while(mx != 0.0 || my != 0.0)
+        {
+            if(mx != 0.0f)
             {
             {
-                float mx = preMotionX;
-                float my = preMotionY;
-                
-                testBox.reset();
-                
-                float oldX = testBox.getMinX();
-                float oldY = testBox.getMinY();
-                
-                while(mx != 0.0 || my != 0.0)
+                float oldX = pos.getX();
+                if(mx < 0.0)
                 {
                 {
-                    testBox.save();
-
-                    if(mx < 0.0)
+                    if(mx > -STEP)
                     {
                     {
-                        if(mx > -STEP)
-                        {
-                            testBox.offsetX(mx);
-                            mx = 0.0f;
-                        }
-                        else
-                        {
-                            testBox.offsetX(-STEP);
-                            mx += STEP;
-                        }
+                        pos.addX(mx);
+                        mx = 0.0f;
                     }
                     }
-                    else if(mx > 0.0)
+                    else
                     {
                     {
-                        if(mx < STEP)
-                        {
-                            testBox.offsetX(mx);
-                            mx = 0.0f;
-                        }
-                        else
-                        {
-                            testBox.offsetX(STEP);
-                            mx -= STEP;
-                        }
+                        pos.addX(-STEP);
+                        mx += STEP;
                     }
                     }
-
-                    for(CollisionObject cb : boxes)
-                    {
-                        if(cb.isColliding(testBox))
-                        {
-                            testBox.offsetY(-UP_STEP);
-                            for(CollisionObject cb2 : boxes)
-                            {
-                                if(cb2.isColliding(testBox))
-                                {
-                                    mx = 0.0f;
-                                    testBox.reset();
-                                    break;
-                                }
-                            }
-                            break;
-                        }
-                    }
-                    
-                    testBox.save();
-
-                    if(my < 0.0)
+                }
+                else if(mx > 0.0)
+                {
+                    if(mx < STEP)
                     {
                     {
-                        if(my > -STEP)
-                        {
-                            testBox.offsetY(my);
-                            my = 0.0f;
-                        }
-                        else
-                        {
-                            testBox.offsetY(-STEP);
-                            my += STEP;
-                        }
+                        pos.addX(mx);
+                        mx = 0.0f;
                     }
                     }
-                    else if(my > 0.0)
+                    else
                     {
                     {
-                        if(my < STEP)
-                        {
-                            testBox.offsetY(my);
-                            my = 0.0f;
-                        }
-                        else
-                        {
-                            testBox.offsetY(STEP);
-                            my -= STEP;
-                        }
+                        pos.addX(STEP);
+                        mx -= STEP;
                     }
                     }
+                }
 
 
-                    for(CollisionObject cb : boxes)
+                if(isCollidingWithTiles(startX, startY, endX, endY, level))
+                {
+                    pos.addY(-UP_STEP);
+                    if(isCollidingWithTiles(startX, startY, endX, endY, level))
                     {
                     {
-                        if(cb.isColliding(testBox))
-                        {
-                            my = 0.0f;
-                            testBox.reset();
-                            break;
-                        }
+                        pos.addY(UP_STEP);
+                        pos.setX(oldX);
+                        mx = 0.0f;
                     }
                     }
                 }
                 }
-                
-                motionX = testBox.getMinX() - oldX;
-                motionY = testBox.getMinY() - oldY;
             }
             }
-            else
+            if(my != 0.0f)
             {
             {
-                motionX = preMotionX;
-                motionY = preMotionY;
-            }
-        }
-        
-        posX += motionX;
-        posY += motionY;
-        box.reset().offset(posX, posY);
-        
-        if(!move.canMoveEverywhere())
-        {
-            //onGround = preMotionY > 0.0f && motionY == 0;
-            onGround = !level.getMovementBoxesAt(box.copy().expand(0.0f, STEP * 2), this).isEmpty();
+                float oldY = pos.getY();
 
 
-            move.setInWater(false);
-            move.setFrictionFactor(0.6f);
-            // apply collision
-            CollisionObject cb = box.copy();
-            for(Face f : Face.values())
-            {
-                cb.reset();
-                cb.expand(f.getCollisionOffsetX(), f.getCollisionOffsetY());
-                level.getEntitiesCollidingWith(this, cb).forEach(ent -> this.controller.onCollideWithEntity(ent, f));
-                level.getCollisionBoxesAt(cb).forEach(loc -> 
+                if(my < 0.0)
                 {
                 {
-                    controller.onCollideWithTile(loc, f);
-                    loc.getTile().onEntityCollide(this, loc.getX(), loc.getY(), f.getOpposite(), level);
-                });
-            }
+                    if(my > -STEP)
+                    {
+                        pos.addY(my);
+                        my = 0.0f;
+                    }
+                    else
+                    {
+                        pos.addY(-STEP);
+                        my += STEP;
+                    }
+                }
+                else if(my > 0.0)
+                {
+                    if(my < STEP)
+                    {
+                        pos.addY(my);
+                        my = 0.0f;
+                    }
+                    else
+                    {
+                        pos.addY(STEP);
+                        my -= STEP;
+                    }
+                }
 
 
-            motionX *= move.getFrictionFactor();
-            if(Math.abs(motionX) < 0.3)
-            {
-                motionX = 0.0f;
+                if(isCollidingWithTiles(startX, startY, endX, endY, level))
+                {
+                    my = 0.0f;
+                    pos.setY(oldY);
+                }
             }
             }
         }
         }
-        health.tick();
+
+        motion.set(pos.getX() - oldPosX, pos.getY() - oldPosY);
+        pos.set(oldPosX, oldPosY);
     }
     }
     
     
     public void renderTick(float lag)
     public void renderTick(float lag)
     {
     {
-        controller.renderTick(lag);
+        controller.renderTick(this, lag);
     }
     }
     
     
     //--------------------------------------------------------------------------
     //--------------------------------------------------------------------------

+ 51 - 25
src/me/hammerle/supersnuvi/entity/EntityBuilder.java

@@ -3,65 +3,91 @@ package me.hammerle.supersnuvi.entity;
 import me.hammerle.supersnuvi.entity.components.DefaultHealth;
 import me.hammerle.supersnuvi.entity.components.DefaultHealth;
 import me.hammerle.supersnuvi.entity.components.DefaultMovement;
 import me.hammerle.supersnuvi.entity.components.DefaultMovement;
 import me.hammerle.supersnuvi.entity.components.DefaultEnergy;
 import me.hammerle.supersnuvi.entity.components.DefaultEnergy;
+import me.hammerle.supersnuvi.entity.components.Energy;
+import me.hammerle.supersnuvi.entity.components.Health;
 import me.hammerle.supersnuvi.entity.components.StoneMovement;
 import me.hammerle.supersnuvi.entity.components.StoneMovement;
 import me.hammerle.supersnuvi.entity.components.ai.HumanController;
 import me.hammerle.supersnuvi.entity.components.ai.HumanController;
 import me.hammerle.supersnuvi.entity.components.ai.LondonerController;
 import me.hammerle.supersnuvi.entity.components.ai.LondonerController;
-import me.hammerle.supersnuvi.entity.components.IDeath;
 import me.hammerle.supersnuvi.entity.components.ItemCollector;
 import me.hammerle.supersnuvi.entity.components.ItemCollector;
 import me.hammerle.supersnuvi.entity.components.ai.PlatformController;
 import me.hammerle.supersnuvi.entity.components.ai.PlatformController;
 import me.hammerle.supersnuvi.entity.components.ai.StartScreenHeroController;
 import me.hammerle.supersnuvi.entity.components.ai.StartScreenHeroController;
 import me.hammerle.supersnuvi.entity.components.ai.StoneController;
 import me.hammerle.supersnuvi.entity.components.ai.StoneController;
-import me.hammerle.supersnuvi.util.CollisionBox;
 import me.hammerle.supersnuvi.util.SoundUtils.Sound;
 import me.hammerle.supersnuvi.util.SoundUtils.Sound;
 import me.hammerle.supersnuvi.gamelogic.Level;
 import me.hammerle.supersnuvi.gamelogic.Level;
+import me.hammerle.supersnuvi.tiles.Tile;
+import me.hammerle.supersnuvi.entity.components.IDespawn;
 
 
 public final class EntityBuilder 
 public final class EntityBuilder 
 {
 {
     public static Entity buildHero(Level level, float x, float y)
     public static Entity buildHero(Level level, float x, float y)
     {
     {
-        Entity hero = new Entity("Hero", x, y, CollisionBox.createScaledTileBox(0.0f, 0.15625f, 0.84375f, 2.0f));
-        hero.controller = new HumanController(hero);
-        hero.health = new DefaultHealth(hero, (ent) -> level.scheduleReset(), 100.0f, null, Sound.MIRROR_CRACK, Sound.MIRROR_BREAK);
-        hero.energy = new DefaultEnergy(hero, 100.0f);
-        hero.move = new DefaultMovement(hero, 12.0f, 0.0f, 50.0f);
-        hero.itemCollector = ItemCollector.HERO;
+        Entity hero = new Entity(Tile.SIZE * 0.84375f, Tile.SIZE * 1.84375f, 
+                new HumanController(), 
+                new DefaultHealth(null, Sound.MIRROR_CRACK, Sound.MIRROR_BREAK), 
+                new DefaultEnergy(),
+                new DefaultMovement(12.0f, 0.0f, 50.0f), 
+                ItemCollector.HERO, 
+                (ent) -> level.scheduleReset(), 
+                "Hero");
+        hero.setPosition(x, y);
         return hero;
         return hero;
     }
     }
     
     
     public static Entity buildStartScreenHero(Level level, float x, float y)
     public static Entity buildStartScreenHero(Level level, float x, float y)
     {
     {
-        Entity hero = new Entity("Hero", x, y, CollisionBox.createScaledTileBox(0.0f, 0.15625f, 0.84375f, 2.0f));
-        hero.controller = new StartScreenHeroController(hero);
-        hero.health = new DefaultHealth(hero, (ent) -> level.scheduleReset(), 100.0f, null, Sound.MIRROR_CRACK, Sound.MIRROR_BREAK);
-        hero.energy = new DefaultEnergy(hero, 100.0f);
-        hero.move = new DefaultMovement(hero, 12.0f, 0.0f, 50.0f);
-        hero.itemCollector = ItemCollector.HERO;
+        Entity hero = new Entity(Tile.SIZE * 0.84375f, Tile.SIZE * 1.84375f, 
+                new StartScreenHeroController(), 
+                new DefaultHealth(null, Sound.MIRROR_CRACK, Sound.MIRROR_BREAK), 
+                new DefaultEnergy(),
+                new DefaultMovement(12.0f, 0.0f, 50.0f), 
+                ItemCollector.HERO, 
+                (ent) -> level.scheduleReset(), 
+                "Hero");
+        hero.setPosition(x, y);
         return hero;
         return hero;
     }
     }
     
     
     public static Entity buildLondoner(Level level, float x, float y, boolean evil)
     public static Entity buildLondoner(Level level, float x, float y, boolean evil)
     {
     {
-        Entity londoner = new Entity(evil ? "EvilLondoner" : "Londoner", x, y, CollisionBox.createScaledTileBox(0.21875f, 0.59375f, 0.65625f, 2.0f));
-        londoner.controller = new LondonerController(londoner, evil);
-        londoner.health = new DefaultHealth(londoner, IDeath.NULL, 100.0f, null, null, null);
-        londoner.energy = new DefaultEnergy(londoner, 100.0f);
-        londoner.move = new DefaultMovement(londoner, 3.0f, 0.0f, 50.0f);
+        Entity londoner = new Entity(Tile.SIZE * 0.4375f, Tile.SIZE * 1.40625f, 
+                new LondonerController(evil), 
+                new DefaultHealth(null, null, null),
+                new DefaultEnergy(),
+                new DefaultMovement(3.0f, 0.0f, 50.0f),
+                ItemCollector.NULL,
+                IDespawn.NULL, 
+                evil ? "EvilLondoner" : "Londoner");
+        londoner.setPosition(x, y);
         return londoner;
         return londoner;
     }
     }
     
     
     public static Entity buildCrumblingStone(Level level, float x, float y)
     public static Entity buildCrumblingStone(Level level, float x, float y)
     {
     {
-        Entity stone = new Entity("CrumblingStone", x, y, CollisionBox.DEFAULT_TILE_BOX);
-        stone.controller = new StoneController(stone);
-        stone.move = new StoneMovement(stone);
+        Entity stone = new Entity(Tile.SIZE, Tile.SIZE, 
+                new StoneController(),
+                Health.NULL,
+                Energy.NULL,
+                StoneMovement.STONE,
+                ItemCollector.NULL,
+                IDespawn.NULL, 
+                "CrumblingStone");
+        stone.setPosition(x, y);
         return stone;
         return stone;
     }
     }
     
     
     public static Entity buildPlatform(Level level, float x, float y, int tx)
     public static Entity buildPlatform(Level level, float x, float y, int tx)
     {
     {
-        Entity platform = new Entity("Platform", x, y, CollisionBox.createScaledTileBox(0.03125f, 0.0f, 0.03125f + tx, 0.78125f));
-        platform.controller = new PlatformController(platform);
-        platform.move = new StoneMovement(platform);
+        // render offset: -0.03125, 0
+        Entity platform = new Entity(Tile.SIZE * tx, Tile.SIZE * 0.78125f,
+                new PlatformController(),
+                Health.NULL,
+                Energy.NULL,
+                StoneMovement.STONE,
+                ItemCollector.NULL,
+                IDespawn.NULL,
+                "Platform");
+        platform.setPosition(x, y);
+        platform.setFriction(0.0f, 0.0f);
         return platform;
         return platform;
     }
     }
     
     

+ 4 - 12
src/me/hammerle/supersnuvi/entity/components/DefaultEnergy.java

@@ -5,23 +5,15 @@ import me.hammerle.supersnuvi.entity.Entity;
 
 
 public class DefaultEnergy extends Energy
 public class DefaultEnergy extends Energy
 {
 {
-    private final float maxEnergy;
-    private float energy;
+    private final float maxEnergy = 100.0f;
+    private float energy = maxEnergy;
     
     
     private static final float BASE = 1.0f / Game.getTicksForMillis(3000);
     private static final float BASE = 1.0f / Game.getTicksForMillis(3000);
-    
-    public DefaultEnergy(Entity ent, float maxEnergy) 
-    {
-        super(ent);
-        this.maxEnergy = maxEnergy;
-        this.energy = maxEnergy;
-    }
 
 
     @Override
     @Override
-    public void tick() 
+    public void tick(Entity ent) 
     {
     {
-        float mx = ent.getMotionX();
-        
+        float mx = ent.getOwnForceX();
         if(mx == 0.0f)
         if(mx == 0.0f)
         {
         {
             addEnergyPercent(BASE);
             addEnergyPercent(BASE);

+ 3 - 24
src/me/hammerle/supersnuvi/entity/components/DefaultHealth.java

@@ -1,32 +1,23 @@
 package me.hammerle.supersnuvi.entity.components;
 package me.hammerle.supersnuvi.entity.components;
 
 
 import me.hammerle.supersnuvi.Game;
 import me.hammerle.supersnuvi.Game;
-import me.hammerle.supersnuvi.entity.Entity;
-import me.hammerle.supersnuvi.tiles.Tile;
 import me.hammerle.supersnuvi.util.SoundUtils;
 import me.hammerle.supersnuvi.util.SoundUtils;
 import me.hammerle.supersnuvi.util.SoundUtils.Sound;
 import me.hammerle.supersnuvi.util.SoundUtils.Sound;
 
 
 public class DefaultHealth extends Health
 public class DefaultHealth extends Health
 {
 {
-    private final float maxHealth;
-    private float health;
+    private final float maxHealth = 100.0f;
+    private float health = maxHealth;
     
     
     private int hurtTicks = 0;
     private int hurtTicks = 0;
     private int invincibility = 0;
     private int invincibility = 0;
     
     
-    private final IDeath death;
-    
     private final Sound soundHeal;
     private final Sound soundHeal;
     private final Sound soundHurt;
     private final Sound soundHurt;
     private final Sound soundDeath;
     private final Sound soundDeath;
     
     
-    public DefaultHealth(Entity ent, IDeath death, float maxHealth, 
-            Sound soundHeal, Sound soundHurt, Sound soundDeath) 
+    public DefaultHealth(Sound soundHeal, Sound soundHurt, Sound soundDeath) 
     {
     {
-        super(ent);
-        this.death = death;
-        this.maxHealth = maxHealth;
-        this.health = maxHealth;
         this.soundHeal = soundHeal;
         this.soundHeal = soundHeal;
         this.soundHurt = soundHurt;
         this.soundHurt = soundHurt;
         this.soundDeath = soundDeath;
         this.soundDeath = soundDeath;
@@ -56,18 +47,6 @@ public class DefaultHealth extends Health
         return health <= 0.0f;
         return health <= 0.0f;
     }
     }
     
     
-    @Override
-    public boolean shouldDespawn() 
-    {
-        return (isDead() && !ent.isAnimated());
-    }
-
-    @Override
-    public void onDespawn()
-    {
-        death.onDeath(ent);
-    }
-    
     @Override
     @Override
     public boolean wasHurt() 
     public boolean wasHurt() 
     {
     {

+ 2 - 14
src/me/hammerle/supersnuvi/entity/components/DefaultMovement.java

@@ -11,9 +11,8 @@ public class DefaultMovement extends Movement
     private final float vy;
     private final float vy;
     private float friction = 1.0f;
     private float friction = 1.0f;
     
     
-    public DefaultMovement(Entity ent, float vx, float vy, float jumpPower) 
+    public DefaultMovement(float vx, float vy, float jumpPower) 
     {
     {
-        super(ent);
         this.jumpPower = jumpPower * Tile.SIZE_SCALE;
         this.jumpPower = jumpPower * Tile.SIZE_SCALE;
         this.vx = vx * Tile.SIZE_SCALE;
         this.vx = vx * Tile.SIZE_SCALE;
         this.vy = vy * Tile.SIZE_SCALE;
         this.vy = vy * Tile.SIZE_SCALE;
@@ -42,17 +41,6 @@ public class DefaultMovement extends Movement
         return vy * getFactor();
         return vy * getFactor();
     }
     }
 
 
-    @Override
-    public boolean jump() 
-    {
-        if(ent.isOnGround())
-        {
-            ent.setMotionY((ent.getMotionY() < 0.0f ? ent.getMotionY() : 0.0f) - getJumpPower());
-            return true;
-        }
-        return false;
-    }
-
     @Override
     @Override
     public float getJumpPower() 
     public float getJumpPower() 
     {
     {
@@ -60,7 +48,7 @@ public class DefaultMovement extends Movement
     }
     }
 
 
     @Override
     @Override
-    public boolean hasGravity()
+    public boolean hasGravity(Entity ent)
     {
     {
         return true;
         return true;
     }
     }

+ 2 - 9
src/me/hammerle/supersnuvi/entity/components/Energy.java

@@ -4,16 +4,9 @@ import me.hammerle.supersnuvi.entity.Entity;
 
 
 public class Energy
 public class Energy
 {
 {
-    public final static Energy NULL = new Energy(null);
+    public final static Energy NULL = new Energy();
     
     
-    protected final Entity ent;
-    
-    protected Energy(Entity ent)
-    {
-        this.ent = ent;
-    }
-    
-    public void tick()
+    public void tick(Entity ent)
     {
     {
     }
     }
 
 

+ 2 - 20
src/me/hammerle/supersnuvi/entity/components/Health.java

@@ -1,17 +1,8 @@
 package me.hammerle.supersnuvi.entity.components;
 package me.hammerle.supersnuvi.entity.components;
 
 
-import me.hammerle.supersnuvi.entity.Entity;
-
 public class Health
 public class Health
 {
 {
-    public final static Health NULL = new Health(null);
-    
-    protected final Entity ent;
-    
-    protected Health(Entity ent)
-    {
-        this.ent = ent;
-    }
+    public final static Health NULL = new Health();
     
     
     public void tick()
     public void tick()
     {
     {
@@ -21,16 +12,7 @@ public class Health
     {
     {
         return false;
         return false;
     }
     }
-    
-    public boolean shouldDespawn()
-    {
-        return false;
-    }
-    
-    public void onDespawn()
-    {
-    }
-    
+
     public boolean wasHurt()
     public boolean wasHurt()
     {
     {
         return false;
         return false;

+ 0 - 10
src/me/hammerle/supersnuvi/entity/components/IDeath.java

@@ -1,10 +0,0 @@
-package me.hammerle.supersnuvi.entity.components;
-
-import me.hammerle.supersnuvi.entity.Entity;
-
-public interface IDeath
-{
-    public static final IDeath NULL = (Entity ent) -> {};
-    
-    public void onDeath(Entity ent);
-}

+ 10 - 0
src/me/hammerle/supersnuvi/entity/components/IDespawn.java

@@ -0,0 +1,10 @@
+package me.hammerle.supersnuvi.entity.components;
+
+import me.hammerle.supersnuvi.entity.Entity;
+
+public interface IDespawn
+{
+    public static final IDespawn NULL = (Entity ent) -> {};
+    
+    public void onDespawn(Entity ent);
+}

+ 2 - 26
src/me/hammerle/supersnuvi/entity/components/Movement.java

@@ -4,14 +4,7 @@ import me.hammerle.supersnuvi.entity.Entity;
 
 
 public class Movement
 public class Movement
 {
 {
-    public final static Movement NULL = new Movement(null);
-    
-    protected final Entity ent;
-    
-    public Movement(Entity ent) 
-    {
-        this.ent = ent;
-    }
+    public final static Movement NULL = new Movement();
     
     
     public float getVelocityX()
     public float getVelocityX()
     {
     {
@@ -28,25 +21,12 @@ public class Movement
         return false;
         return false;
     }
     }
     
     
-    //--------------------------------------------------------------------------
-    // jumping
-    //--------------------------------------------------------------------------
-    
-    public boolean jump()
-    {
-        return false;
-    }
-    
     public float getJumpPower()
     public float getJumpPower()
     {
     {
         return 0.0f;
         return 0.0f;
     }
     }
     
     
-    //--------------------------------------------------------------------------
-    // gravity
-    //--------------------------------------------------------------------------
-    
-    public boolean hasGravity()
+    public boolean hasGravity(Entity ent)
     {
     {
         return false;
         return false;
     }
     }
@@ -56,10 +36,6 @@ public class Movement
         return 1.0f;
         return 1.0f;
     }
     }
     
     
-    //--------------------------------------------------------------------------
-    // friction
-    //--------------------------------------------------------------------------
-    
     public void setInWater(boolean b)
     public void setInWater(boolean b)
     {
     {
     }
     }

+ 5 - 4
src/me/hammerle/supersnuvi/entity/components/StoneMovement.java

@@ -4,13 +4,14 @@ import me.hammerle.supersnuvi.entity.Entity;
 
 
 public class StoneMovement extends Movement
 public class StoneMovement extends Movement
 {
 {
-    public StoneMovement(Entity ent) 
+    public final static StoneMovement STONE = new StoneMovement();
+
+    private StoneMovement()
     {
     {
-        super(ent);
     }
     }
-
+    
     @Override
     @Override
-    public boolean hasGravity() 
+    public boolean hasGravity(Entity ent) 
     {
     {
         return !ent.isAnimated();
         return !ent.isAnimated();
     }
     }

+ 6 - 13
src/me/hammerle/supersnuvi/entity/components/ai/Controller.java

@@ -2,25 +2,18 @@ package me.hammerle.supersnuvi.entity.components.ai;
 
 
 import me.hammerle.supersnuvi.entity.Entity;
 import me.hammerle.supersnuvi.entity.Entity;
 import me.hammerle.supersnuvi.gamelogic.Level;
 import me.hammerle.supersnuvi.gamelogic.Level;
-import me.hammerle.supersnuvi.tiles.Location;
+import me.hammerle.supersnuvi.tiles.Tile;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.util.Face;
 
 
 public class Controller
 public class Controller
 {
 {
-    public final static Controller NULL = new Controller(null);
+    public final static Controller NULL = new Controller();
     
     
-    protected final Entity ent;
-    
-    protected Controller(Entity ent)
-    {
-        this.ent = ent;
-    }
-    
-    public void tick(Level level)
+    public void tick(Entity ent, Level level)
     {
     {
     }
     }
     
     
-    public void renderTick(float lag)
+    public void renderTick(Entity ent, float lag)
     {
     {
     }
     }
     
     
@@ -29,11 +22,11 @@ public class Controller
         return false;
         return false;
     }
     }
     
     
-    public void onCollideWithTile(Location loc, Face face)
+    public void onCollideWithTile(Entity ent, int x, int y, Level l, Tile t, Face face)
     {
     {
     }
     }
     
     
-    public void onCollideWithEntity(Entity ent, Face face)
+    public void onCollideWithEntity(Entity ent, Entity other, Face face)
     {
     {
     }
     }
 }
 }

+ 24 - 16
src/me/hammerle/supersnuvi/entity/components/ai/HumanController.java

@@ -16,6 +16,8 @@ public class HumanController extends Controller
     protected final static int SIZE = 1024;
     protected final static int SIZE = 1024;
     private final static Texture HERO = new Texture("resources/hero.png");
     private final static Texture HERO = new Texture("resources/hero.png");
     
     
+    private final static float OFFSET_Y = -Tile.SIZE * 0.15625f;
+    
     protected float ox = 0.0f;
     protected float ox = 0.0f;
     protected float oy = 0.0f;
     protected float oy = 0.0f;
     protected float w = 0.0f;
     protected float w = 0.0f;
@@ -27,11 +29,8 @@ public class HumanController extends Controller
     private int idleCounter = 0;
     private int idleCounter = 0;
     protected int idleFrame = 0;
     protected int idleFrame = 0;
     protected int deathFrame = 0;
     protected int deathFrame = 0;
-
-    public HumanController(Entity ent) 
-    {
-        super(ent);
-    }
+    
+    protected Face face = Face.RIGHT;
     
     
     protected void nextWalkFrame()
     protected void nextWalkFrame()
     {
     {
@@ -73,11 +72,11 @@ public class HumanController extends Controller
     }
     }
     
     
     @Override
     @Override
-    public void tick(Level level) 
+    public void tick(Entity ent, Level level) 
     {
     {
         if(ent.getHealth().isDead())
         if(ent.getHealth().isDead())
         {
         {
-            ox = ent.getFace() == Face.RIGHT ? 0.0f: -1.15625f * Tile.SIZE;
+            ox = face == Face.RIGHT ? 0.0f: -1.15625f * Tile.SIZE;
             oy = 0.0f;
             oy = 0.0f;
             h = 2.0f;
             h = 2.0f;
             w = 2.0f;
             w = 2.0f;
@@ -105,33 +104,33 @@ public class HumanController extends Controller
         
         
         if(Keys.LEFT.isDown())
         if(Keys.LEFT.isDown())
         {
         {
-            ent.setMotionX(-speed);
+            ent.applyOwnForce(-speed, 0.0f);
             SoundUtils.playSound(ent.getMovement().isInWater() ? SoundUtils.Sound.WALK_WATER : SoundUtils.Sound.WALK);
             SoundUtils.playSound(ent.getMovement().isInWater() ? SoundUtils.Sound.WALK_WATER : SoundUtils.Sound.WALK);
         }
         }
         
         
         if(Keys.RIGHT.isDown())
         if(Keys.RIGHT.isDown())
         {
         {
-            ent.setMotionX(speed);
+            ent.applyOwnForce(speed, 0.0f);
             SoundUtils.playSound(ent.getMovement().isInWater() ? SoundUtils.Sound.WALK_WATER : SoundUtils.Sound.WALK);
             SoundUtils.playSound(ent.getMovement().isInWater() ? SoundUtils.Sound.WALK_WATER : SoundUtils.Sound.WALK);
         }
         }
         
         
         if(Keys.JUMP.isDown())
         if(Keys.JUMP.isDown())
         {
         {
-            if(ent.getEnergy().getEnergyPercent() >= 0.1f && ent.getMovement().jump())
+            if(ent.getEnergy().getEnergyPercent() >= 0.1f && ent.jump())
             {
             {
                 SoundUtils.playSound(Sound.JUMP);
                 SoundUtils.playSound(Sound.JUMP);
                 ent.getEnergy().addEnergyPercent(-0.1f);
                 ent.getEnergy().addEnergyPercent(-0.1f);
             }
             }
         }
         }
         
         
-        ox = ent.getFace() == Face.RIGHT ? 0.0f : -0.15625f * Tile.SIZE;
+        ox = face == Face.RIGHT ? 0.0f : -0.15625f * Tile.SIZE;
         oy = 0.0f;
         oy = 0.0f;
         h = 2.0f;
         h = 2.0f;
         w = 1.0f;
         w = 1.0f;
         
         
         if(ent.isOnGround())
         if(ent.isOnGround())
         {
         {
-            if(ent.getMotionX() == 0.0f)
+            if(ent.getOwnForceX() == 0.0f)
             {
             {
                 tx = (idleFrame * 32.0f) / SIZE;
                 tx = (idleFrame * 32.0f) / SIZE;
                 ty = 128.0f / SIZE;
                 ty = 128.0f / SIZE;
@@ -150,10 +149,19 @@ public class HumanController extends Controller
             tx = 0.0f;
             tx = 0.0f;
             ty = 0.0f;
             ty = 0.0f;
         }
         }
+        
+        if(ent.getOwnForceX() > 0)
+        {
+            face = Face.RIGHT;
+        }
+        else if(ent.getOwnForceX() < 0)
+        {
+            face = Face.LEFT;
+        }
     }
     }
 
 
     @Override
     @Override
-    public void renderTick(float lag)
+    public void renderTick(Entity ent, float lag)
     {
     {
         if(ent.getHealth().wasHurt())
         if(ent.getHealth().wasHurt())
         {
         {
@@ -174,7 +182,7 @@ public class HumanController extends Controller
 
 
         float m1;
         float m1;
         float m2;
         float m2;
-        if(ent.getFace() == Face.LEFT)
+        if(face == Face.LEFT)
         {
         {
             m1 = w * Tile.SIZE;
             m1 = w * Tile.SIZE;
             m2 = 0.0f;
             m2 = 0.0f;
@@ -185,8 +193,8 @@ public class HumanController extends Controller
             m2 = w * Tile.SIZE;
             m2 = w * Tile.SIZE;
         }
         }
         Shader.getTextureRenderer().drawRectangle(
         Shader.getTextureRenderer().drawRectangle(
-                x + ox + m1, y + oy, 
-                x + ox + m2, y + oy + h * Tile.SIZE, 
+                x + ox + m1, y + oy + OFFSET_Y, 
+                x + ox + m2, y + oy + h * Tile.SIZE + OFFSET_Y, 
                 tx, ty, 
                 tx, ty, 
                 tx + (w * 32.0f / SIZE), ty + (h * 32.0f / SIZE));
                 tx + (w * 32.0f / SIZE), ty + (h * 32.0f / SIZE));
         
         

+ 41 - 27
src/me/hammerle/supersnuvi/entity/components/ai/LondonerController.java

@@ -4,7 +4,6 @@ import me.hammerle.snuviengine.api.Shader;
 import me.hammerle.snuviengine.api.Texture;
 import me.hammerle.snuviengine.api.Texture;
 import me.hammerle.supersnuvi.entity.Entity;
 import me.hammerle.supersnuvi.entity.Entity;
 import me.hammerle.supersnuvi.gamelogic.Level;
 import me.hammerle.supersnuvi.gamelogic.Level;
-import me.hammerle.supersnuvi.tiles.Location;
 import me.hammerle.supersnuvi.tiles.RampTile;
 import me.hammerle.supersnuvi.tiles.RampTile;
 import me.hammerle.supersnuvi.tiles.Tile;
 import me.hammerle.supersnuvi.tiles.Tile;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.util.Face;
@@ -15,6 +14,11 @@ public class LondonerController extends Controller
 {
 {
     private final static Texture LONDONER = new Texture("resources/londoner.png");
     private final static Texture LONDONER = new Texture("resources/londoner.png");
     
     
+    // for render offset: 0.21875f, 0.59375f, 0.65625f, 2.0f
+    // render offset: -0.21875, -0.59375
+    private final static float OFFSET_X = -Tile.SIZE * 0.21875f;
+    private final static float OFFSET_Y = -Tile.SIZE * 0.59375f;
+    
     private final boolean evil;
     private final boolean evil;
     
     
     private float ox = 0.0f;
     private float ox = 0.0f;
@@ -26,16 +30,16 @@ public class LondonerController extends Controller
     private int deathCounter = 0;
     private int deathCounter = 0;
     private int deathFrame = 0;
     private int deathFrame = 0;
     
     
+    private Face oldFace = Face.LEFT;
     private Face direction = Face.LEFT;
     private Face direction = Face.LEFT;
     
     
     private boolean shouldJump = false;
     private boolean shouldJump = false;
     
     
     private Entity hurt = null;
     private Entity hurt = null;
     private Entity attacker = null;
     private Entity attacker = null;
-
-    public LondonerController(Entity ent, boolean evil) 
+    
+    public LondonerController(boolean evil) 
     {
     {
-        super(ent);
         this.evil = evil;
         this.evil = evil;
     }
     }
     
     
@@ -51,7 +55,7 @@ public class LondonerController extends Controller
     }
     }
     
     
     @Override
     @Override
-    public void tick(Level level) 
+    public void tick(Entity ent, Level level) 
     {
     {
         if(evil)
         if(evil)
         {
         {
@@ -59,7 +63,7 @@ public class LondonerController extends Controller
             {
             {
                 if(transformFrame < 3)
                 if(transformFrame < 3)
                 {
                 {
-                    ox = ent.getFace() == Face.RIGHT ? 0.0f: -1.125f * Tile.SIZE;
+                    ox = direction == Face.RIGHT ? 0.0f: -1.125f * Tile.SIZE;
                     tx = transformFrame * 0.125f + 0.125f;
                     tx = transformFrame * 0.125f + 0.125f;
                     ty = 0.375f;
                     ty = 0.375f;
                     transformFrame++;
                     transformFrame++;
@@ -74,7 +78,7 @@ public class LondonerController extends Controller
         
         
         if(ent.getHealth().isDead())
         if(ent.getHealth().isDead())
         {
         {
-            ox = ent.getFace() == Face.RIGHT ? -Tile.SIZE: -0.125f * Tile.SIZE;
+            ox = direction == Face.RIGHT ? -Tile.SIZE: -0.125f * Tile.SIZE;
             
             
             tx = deathFrame * 0.125f;
             tx = deathFrame * 0.125f;
             ty = hasRedEyes() ? 0.125f : 0.25f;
             ty = hasRedEyes() ? 0.125f : 0.25f;
@@ -94,36 +98,36 @@ public class LondonerController extends Controller
             float hx = level.getHero().getCenterX();
             float hx = level.getHero().getCenterX();
             if(hx < ent.getCenterX())
             if(hx < ent.getCenterX())
             {
             {
-                ent.setMotionX(-ent.getMovement().getVelocityX());
+                ent.applyOwnForce(-ent.getMovement().getVelocityX(), 0.0f);
             }
             }
             else
             else
             {
             {
-                ent.setMotionX(ent.getMovement().getVelocityX());
+                ent.applyOwnForce(ent.getMovement().getVelocityX(), 0.0f);
             }
             }
         }
         }
         else
         else
         {
         {
             if(direction == Face.LEFT)
             if(direction == Face.LEFT)
             {
             {
-                ent.setMotionX(-ent.getMovement().getVelocityX());
+                ent.applyOwnForce(-ent.getMovement().getVelocityX(), 0.0f);
             }
             }
             else
             else
             {
             {
-                ent.setMotionX(ent.getMovement().getVelocityX());
+                ent.applyOwnForce(ent.getMovement().getVelocityX(), 0.0f);
             }
             }
         }
         }
         
         
         if(shouldJump)
         if(shouldJump)
         {
         {
             SoundUtils.playSound(SoundUtils.Sound.LONDONER_JUMP);
             SoundUtils.playSound(SoundUtils.Sound.LONDONER_JUMP);
-            ent.getMovement().jump();
+            ent.jump();
             shouldJump = false;
             shouldJump = false;
         }
         }
         
         
         if(attacker != null)
         if(attacker != null)
         {
         {
-            this.ent.getHealth().addHealthPercent(-0.201f);
-            attacker.setMotionY(-attacker.getMovement().getJumpPower() * 0.5f);
+            ent.getHealth().addHealthPercent(-0.201f);
+            attacker.applyForce(0.0f, -attacker.getMovement().getJumpPower() * 0.5f);
             
             
             attacker = null;
             attacker = null;
             hurt = null;
             hurt = null;
@@ -133,25 +137,25 @@ public class LondonerController extends Controller
         {
         {
             hurt.getHealth().addHealthPercent(-0.1f);
             hurt.getHealth().addHealthPercent(-0.1f);
 
 
-            hurt.setMotionY(ent.getMotionY() - 20.0f * Tile.SIZE_SCALE);
+            hurt.applyForce(0.0f, -20.0f * Tile.SIZE_SCALE);
 
 
             if(ent.getCenterX() < hurt.getCenterX())
             if(ent.getCenterX() < hurt.getCenterX())
             {
             {
-                hurt.setMotionX(hurt.getMotionX() + 10.0f * Tile.SIZE_SCALE);
+                hurt.applyForce(10.0f * Tile.SIZE_SCALE, 0.0f);
             }
             }
             else
             else
             {
             {
-                hurt.setMotionX(hurt.getMotionX() - 10.0f * Tile.SIZE_SCALE);
+                hurt.applyForce(-10.0f * Tile.SIZE_SCALE, 0.0f);
             }
             }
             
             
             hurt = null;
             hurt = null;
         }
         }
         
         
-        ox = ent.getFace() == Face.RIGHT ? 0.0f: -1.125f * Tile.SIZE;
+        ox = direction == Face.RIGHT ? 0.0f: -1.125f * Tile.SIZE;
         
         
         if(ent.isOnGround())
         if(ent.isOnGround())
         {
         {
-            if(ent.getMotionX() == 0.0f)
+            if(ent.getOwnForceX() == 0.0f)
             {
             {
                 tx = 0.875f;
                 tx = 0.875f;
                 ty = hasRedEyes() ? 0.25f : 0.375f;
                 ty = hasRedEyes() ? 0.25f : 0.375f;
@@ -171,10 +175,12 @@ public class LondonerController extends Controller
             tx = 0.125f;
             tx = 0.125f;
             ty = hasRedEyes() ? 0.5f : 0.625f;
             ty = hasRedEyes() ? 0.5f : 0.625f;
         }
         }
+        
+        oldFace = direction;
     }
     }
 
 
     @Override
     @Override
-    public void renderTick(float lag)
+    public void renderTick(Entity ent, float lag)
     {
     {
         if(ent.getHealth().wasHurt())
         if(ent.getHealth().wasHurt())
         {
         {
@@ -195,7 +201,7 @@ public class LondonerController extends Controller
         
         
         float m1;
         float m1;
         float m2;
         float m2;
-        if(ent.getFace() == Face.LEFT)
+        if(oldFace == Face.LEFT)
         {
         {
             m1 = 2.0f * Tile.SIZE;
             m1 = 2.0f * Tile.SIZE;
             m2 = 0.0f;
             m2 = 0.0f;
@@ -206,8 +212,8 @@ public class LondonerController extends Controller
             m2 = 2.0f * Tile.SIZE;
             m2 = 2.0f * Tile.SIZE;
         }
         }
         Shader.getTextureRenderer().drawRectangle(
         Shader.getTextureRenderer().drawRectangle(
-                x + ox + m1, y,
-                x + ox + m2, y + 2.0f * Tile.SIZE, 
+                x + ox + m1 + OFFSET_X, y + OFFSET_Y,
+                x + ox + m2 + OFFSET_X, y + 2.0f * Tile.SIZE + OFFSET_Y, 
                 tx, ty, 
                 tx, ty, 
                 tx + 0.125f, ty + 0.125f);
                 tx + 0.125f, ty + 0.125f);
         
         
@@ -219,18 +225,22 @@ public class LondonerController extends Controller
     }
     }
     
     
     @Override
     @Override
-    public void onCollideWithTile(Location loc, Face face)
+    public void onCollideWithTile(Entity ent, int x, int y, Level l, Tile t, Face face)
     {
     {
+        if(ent.getHealth().isDead())
+        {
+            return;
+        }
         if(hasRedEyes())
         if(hasRedEyes())
         {
         {
-            if(!(loc.getTile() instanceof RampTile) && face == ent.getFace() && ent.getMotionX() == 0.0f)
+            if(!(t instanceof RampTile) && face == direction && ent.getOwnForceX() == 0.0f)
             {
             {
                 shouldJump = true;
                 shouldJump = true;
             }
             }
         }
         }
         else
         else
         {
         {
-            if(loc.getTile().shouldAiUseCollisionBox(loc.getX(), loc.getY(), loc.getLevel()))
+            if(t.shouldAiUseCollisionBox(x, y, l))
             {
             {
                 switch(face)
                 switch(face)
                 {
                 {
@@ -246,8 +256,12 @@ public class LondonerController extends Controller
     }
     }
 
 
     @Override
     @Override
-    public void onCollideWithEntity(Entity ent, Face face)
+    public void onCollideWithEntity(Entity ent, Entity other, Face face)
     {
     {
+        if(ent.getHealth().isDead())
+        {
+            return;
+        }
         switch(face)
         switch(face)
         {
         {
             case LEFT:
             case LEFT:

+ 16 - 12
src/me/hammerle/supersnuvi/entity/components/ai/PlatformController.java

@@ -34,11 +34,6 @@ public class PlatformController extends Controller
     private final ArrayList<MoveData> dataList = new ArrayList<>();
     private final ArrayList<MoveData> dataList = new ArrayList<>();
     private int moveIndex = 0;
     private int moveIndex = 0;
     private int waitTicks = 0;
     private int waitTicks = 0;
-
-    public PlatformController(Entity ent) 
-    {
-        super(ent);
-    }
   
   
     @Override
     @Override
     public boolean isAnimated()
     public boolean isAnimated()
@@ -70,7 +65,7 @@ public class PlatformController extends Controller
     }
     }
     
     
     @Override
     @Override
-    public void tick(Level level) 
+    public void tick(Entity ent, Level level) 
     {
     {
         if(dataList.isEmpty())
         if(dataList.isEmpty())
         {
         {
@@ -80,9 +75,6 @@ public class PlatformController extends Controller
         MoveData data = dataList.get(moveIndex);
         MoveData data = dataList.get(moveIndex);
         if(ent.isAt(data.x, data.y))
         if(ent.isAt(data.x, data.y))
         {
         {
-            ent.setMotionX(0.0f);
-            ent.setMotionY(0.0f);
-            
             waitTicks++;
             waitTicks++;
             if(waitTicks >= data.waitTicks)
             if(waitTicks >= data.waitTicks)
             {
             {
@@ -94,13 +86,12 @@ public class PlatformController extends Controller
         {
         {
             float motionX = clamp(data.x - ent.getX(), -data.speedX, data.speedX);
             float motionX = clamp(data.x - ent.getX(), -data.speedX, data.speedX);
             float motionY = clamp(data.y - ent.getY(), -data.speedY, data.speedY);
             float motionY = clamp(data.y - ent.getY(), -data.speedY, data.speedY);
-            ent.setMotionX(motionX);
-            ent.setMotionY(motionY);
+            ent.applyOwnForce(motionX, motionY);
         }
         }
     }
     }
 
 
     @Override
     @Override
-    public void renderTick(float lag)
+    public void renderTick(Entity ent, float lag)
     {
     {
         TEXTURE.bind();
         TEXTURE.bind();
         float x = Utils.interpolate(ent.getLastX(), ent.getX(), lag);
         float x = Utils.interpolate(ent.getLastX(), ent.getX(), lag);
@@ -118,4 +109,17 @@ public class PlatformController extends Controller
         }
         }
         Shader.getTextureRenderer().drawRectangle(x, y, x + Tile.SIZE, endY, 0.5f, 0.25f, 0.75f, 0.4453125f);
         Shader.getTextureRenderer().drawRectangle(x, y, x + Tile.SIZE, endY, 0.5f, 0.25f, 0.75f, 0.4453125f);
     }
     }
+
+    @Override
+    public void onCollideWithEntity(Entity ent, Entity other, Face face)
+    {
+        if(face == Face.UP)
+        {
+            other.applyForce(ent.getOwnForceX(), 0.0f);
+        }
+        else if(face == Face.LEFT || face == Face.RIGHT)
+        {
+            other.applyForce(ent.getOwnForceX() - other.getOwnForceX(), 0.0f);
+        }
+    }
 }
 }

+ 7 - 13
src/me/hammerle/supersnuvi/entity/components/ai/StartScreenHeroController.java

@@ -2,7 +2,6 @@ package me.hammerle.supersnuvi.entity.components.ai;
 
 
 import me.hammerle.supersnuvi.entity.Entity;
 import me.hammerle.supersnuvi.entity.Entity;
 import me.hammerle.supersnuvi.gamelogic.Level;
 import me.hammerle.supersnuvi.gamelogic.Level;
-import me.hammerle.supersnuvi.tiles.Location;
 import me.hammerle.supersnuvi.tiles.RampTile;
 import me.hammerle.supersnuvi.tiles.RampTile;
 import me.hammerle.supersnuvi.tiles.Tile;
 import me.hammerle.supersnuvi.tiles.Tile;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.util.Face;
@@ -11,30 +10,25 @@ public class StartScreenHeroController extends HumanController
 {
 {
     private boolean shouldJump = false;
     private boolean shouldJump = false;
     
     
-    public StartScreenHeroController(Entity ent) 
-    {
-        super(ent);
-    }
-    
     @Override
     @Override
-    public void tick(Level level) 
+    public void tick(Entity ent, Level level) 
     {
     {
-        ent.setMotionX(ent.getMovement().getVelocityX());
+        ent.applyOwnForce(ent.getMovement().getVelocityX(), 0.0f);
         
         
         if(shouldJump)
         if(shouldJump)
         {
         {
             shouldJump = false;
             shouldJump = false;
-            ent.getMovement().jump();
+            ent.jump();
         }
         }
         
         
-        ox = ent.getFace() == Face.RIGHT ? 0.0f : -0.15625f * Tile.SIZE;
+        ox = 0.0f;
         oy = 0.0f;
         oy = 0.0f;
         h = 2.0f;
         h = 2.0f;
         w = 1.0f;
         w = 1.0f;
         
         
         if(ent.isOnGround())
         if(ent.isOnGround())
         {
         {
-            if(ent.getMotionX() == 0.0f)
+            if(ent.getOwnForceX() == 0.0f)
             {
             {
                 tx = (idleFrame * 32.0f) / SIZE;
                 tx = (idleFrame * 32.0f) / SIZE;
                 ty = 128.0f / SIZE;
                 ty = 128.0f / SIZE;
@@ -56,9 +50,9 @@ public class StartScreenHeroController extends HumanController
     }
     }
 
 
     @Override
     @Override
-    public void onCollideWithTile(Location loc, Face face)
+    public void onCollideWithTile(Entity ent, int x, int y, Level l, Tile t, Face face)
     {
     {
-        if(face == Face.RIGHT && !(loc.getTile() instanceof RampTile))
+        if(face == Face.RIGHT && !(t instanceof RampTile))
         {
         {
             shouldJump = true;
             shouldJump = true;
         }
         }

+ 2 - 7
src/me/hammerle/supersnuvi/entity/components/ai/StoneController.java

@@ -12,11 +12,6 @@ public class StoneController extends Controller
     private final static Texture STONE = new Texture("resources/stone.png");
     private final static Texture STONE = new Texture("resources/stone.png");
     
     
     private int frame = 0;
     private int frame = 0;
-    
-    public StoneController(Entity ent)
-    {
-        super(ent);
-    }
 
 
     @Override
     @Override
     public boolean isAnimated()
     public boolean isAnimated()
@@ -25,7 +20,7 @@ public class StoneController extends Controller
     }
     }
 
 
     @Override
     @Override
-    public void renderTick(float lag)
+    public void renderTick(Entity ent, float lag)
     {
     {
         STONE.bind();
         STONE.bind();
         float x = Utils.interpolate(ent.getLastX(), ent.getX(), lag);
         float x = Utils.interpolate(ent.getLastX(), ent.getX(), lag);
@@ -39,7 +34,7 @@ public class StoneController extends Controller
     }
     }
 
 
     @Override
     @Override
-    public void tick(Level level)
+    public void tick(Entity ent, Level level)
     {
     {
         if(frame < 40)
         if(frame < 40)
         {
         {

+ 14 - 8
src/me/hammerle/supersnuvi/gamelogic/Level.java

@@ -1,10 +1,10 @@
 package me.hammerle.supersnuvi.gamelogic;
 package me.hammerle.supersnuvi.gamelogic;
 
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.List;
 import java.util.function.Consumer;
 import java.util.function.Consumer;
-import java.util.stream.Collectors;
 import me.hammerle.snuviscript.code.Script;
 import me.hammerle.snuviscript.code.Script;
 import me.hammerle.supersnuvi.Game;
 import me.hammerle.supersnuvi.Game;
 import me.hammerle.supersnuvi.entity.Entity;
 import me.hammerle.supersnuvi.entity.Entity;
@@ -32,7 +32,7 @@ public abstract class Level
     private float red = 1.0f;
     private float red = 1.0f;
     private float green = 1.0f;
     private float green = 1.0f;
     private float blue = 1.0f;
     private float blue = 1.0f;
-    private Light[] lights = new Light[32];
+    private final Light[] lights = new Light[32];
     
     
     public Level()
     public Level()
     {
     {
@@ -124,9 +124,9 @@ public abstract class Level
         entities.values().removeIf(ent -> 
         entities.values().removeIf(ent -> 
         {
         {
             ent.tick(this);
             ent.tick(this);
-            if(ent.getHealth().shouldDespawn() || (ent.getY() > getData().getHeight() * Tile.SIZE))
+            if((ent.getHealth().isDead() && !ent.isAnimated()) || (ent.getY() > getData().getHeight() * Tile.SIZE))
             {
             {
-                ent.getHealth().onDespawn();
+                ent.onDespawn();
                 callEvent("entity_despawn", (sc) -> 
                 callEvent("entity_despawn", (sc) -> 
                 {
                 {
                     sc.setVar("entity", ent);
                     sc.setVar("entity", ent);
@@ -135,6 +135,7 @@ public abstract class Level
             }
             }
             return false;
             return false;
         });
         });
+        entities.values().forEach(ent -> ent.move(this));
 
 
         if(!spawnQueue.isEmpty())
         if(!spawnQueue.isEmpty())
         {
         {
@@ -150,9 +151,13 @@ public abstract class Level
         }
         }
     }
     }
     
     
-    public final List<Entity> getEntitiesCollidingWith(Entity not, CollisionObject cb)
+    public final void forEachCollidingEntity(Entity ent, Consumer<Entity> c)
     {
     {
-        return entities.values().stream().filter(ent -> ent != not && ent.getBox().isColliding(cb)).collect(Collectors.toList());
+        float minX = ent.getX() - Entity.STEP;
+        float minY = ent.getY() - Entity.STEP;
+        float maxX = minX + ent.getWidth() + Entity.STEP;
+        float maxY = minY + ent.getHeight() + Entity.STEP;
+        entities.values().stream().filter(other -> ent != other && other.isColliding(minX, minY, maxX, maxY)).forEach(c);
     }
     }
     
     
     public final void forEachEntity(Consumer<Entity> c)
     public final void forEachEntity(Consumer<Entity> c)
@@ -221,7 +226,7 @@ public abstract class Level
     // collision
     // collision
     // -------------------------------------------------------------------------
     // -------------------------------------------------------------------------
     
     
-    private Tile getInteractionTile(int x, int y)
+    public Tile getInteractionTile(int x, int y)
     {
     {
         int i = getData().getInteractionTile(x, y);
         int i = getData().getInteractionTile(x, y);
         if(i == -1)
         if(i == -1)
@@ -246,7 +251,8 @@ public abstract class Level
         List<CollisionObject> boxes;
         List<CollisionObject> boxes;
         if(not != null)
         if(not != null)
         {
         {
-            boxes = getEntitiesCollidingWith(not, box).stream().map(ent -> ent.getBox()).collect(Collectors.toList());
+            //boxes = getEntitiesCollidingWith(not, box).stream().map(ent -> ent.getBox()).collect(Collectors.toList());
+            boxes = new LinkedList<>();
         }
         }
         else
         else
         {
         {

+ 7 - 0
src/me/hammerle/supersnuvi/math/IVector.java

@@ -0,0 +1,7 @@
+package me.hammerle.supersnuvi.math;
+
+public interface IVector
+{
+    public float getX();
+    public float getY();
+}

+ 84 - 0
src/me/hammerle/supersnuvi/math/Vector.java

@@ -0,0 +1,84 @@
+package me.hammerle.supersnuvi.math;
+
+public class Vector implements IVector
+{
+    private float x = 0.0f;
+    private float y = 0.0f;
+    
+    public Vector(float x, float y)
+    {
+        this.x = x;
+        this.y = y;
+    }
+    
+    public Vector()
+    {
+        this(0.0f, 0.0f);
+    }
+    
+    public void setX(float x)
+    {
+        this.x = x;
+    }
+    
+    public void setY(float y)
+    {
+        this.y = y;
+    }
+    
+    public void set(float x, float y)
+    {
+        this.x = x;
+        this.y = y;
+    }
+    
+    public void set(Vector v)
+    {
+        set(v.x, v.y);
+    }
+    
+    public void add(float x, float y)
+    {
+        this.x += x;
+        this.y += y;
+    }
+    
+    public void add(Vector v)
+    {
+        add(v.x, v.y);
+    }
+    
+    public void addY(float y)
+    {
+        this.y += y;
+    }
+    
+    public void addX(float x)
+    {
+        this.x += x;
+    }
+    
+    public void mul(Vector v)
+    {
+        x *= v.x;
+        y *= v.y;
+    }
+
+    @Override
+    public float getX()
+    {
+        return x;
+    }
+
+    @Override
+    public float getY()
+    {
+        return y;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("Vector(x = %f, y = %f)", x, y);
+    }
+}

+ 32 - 0
src/me/hammerle/supersnuvi/tiles/BaseBoxTile.java

@@ -1,5 +1,9 @@
 package me.hammerle.supersnuvi.tiles;
 package me.hammerle.supersnuvi.tiles;
 
 
+import me.hammerle.supersnuvi.gamelogic.Level;
+import me.hammerle.supersnuvi.util.Face;
+import me.hammerle.supersnuvi.util.Utils;
+
 public class BaseBoxTile extends BaseTile
 public class BaseBoxTile extends BaseTile
 {
 {
     public BaseBoxTile(float tMinX, float tMinY, float tMaxX, float tMaxY)
     public BaseBoxTile(float tMinX, float tMinY, float tMaxX, float tMaxY)
@@ -7,4 +11,32 @@ public class BaseBoxTile extends BaseTile
         super(tMinX, tMinY, tMaxX, tMaxY);
         super(tMinX, tMinY, tMaxX, tMaxY);
         super.setDefaultCollisionBox();
         super.setDefaultCollisionBox();
     }
     }
+
+    @Override
+    public boolean isMoveColliding(float minX, float minY, float maxX, float maxY, int x, int y, Level l)
+    {
+        float minTileX = Utils.toCoord(x);
+        float minTileY = Utils.toCoord(y);
+        return maxX > minTileX && minTileX + Tile.SIZE > minX && 
+                maxY > minTileY && minTileY + Tile.SIZE > minY;
+    }
+
+    @Override
+    public boolean isColliding(float minX, float minY, float maxX, float maxY, int x, int y, Level l)
+    {
+        float minTileX = Utils.toCoord(x);
+        float minTileY = Utils.toCoord(y);
+        return maxX > minTileX && minTileX + Tile.SIZE > minX && 
+                maxY > minTileY && minTileY + Tile.SIZE > minY;
+    }
+
+    @Override
+    public Face getCollidingFace(float minX, float minY, float maxX, float maxY, int x, int y, Level l)
+    {
+        float minTileX = Utils.toCoord(x);
+        float minTileY = Utils.toCoord(y);
+        return Utils.getCollidingFace(
+                minTileX, minTileY, minTileX + Tile.SIZE, minTileY + Tile.SIZE,
+                minX, minY, maxX, maxY);
+    }
 }
 }

+ 41 - 0
src/me/hammerle/supersnuvi/tiles/BaseCollisionTile.java

@@ -0,0 +1,41 @@
+package me.hammerle.supersnuvi.tiles;
+
+import me.hammerle.supersnuvi.gamelogic.Level;
+import me.hammerle.supersnuvi.util.Face;
+import me.hammerle.supersnuvi.util.Utils;
+
+public class BaseCollisionTile extends BaseTile
+{
+    private final float x1;
+    private final float y1;
+    private final float x2;
+    private final float y2;
+    
+    public BaseCollisionTile(float tMinX, float tMinY, float tMaxX, float tMaxY, float x1, float y1, float x2, float y2)
+    {
+        super(tMinX, tMinY, tMaxX, tMaxY);
+        this.x1 = x1;
+        this.y1 = y1;
+        this.x2 = x2;
+        this.y2 = y2;
+    }
+    
+    @Override
+    public boolean isColliding(float minX, float minY, float maxX, float maxY, int x, int y, Level l)
+    {
+        float minTileX = Utils.toCoord(x);
+        float minTileY = Utils.toCoord(y);
+        return maxX > minTileX + x1 && minTileX + x2 > minX && 
+                maxY > minTileY + y1 && minTileY + y2 > minY;
+    }
+
+    @Override
+    public Face getCollidingFace(float minX, float minY, float maxX, float maxY, int x, int y, Level l)
+    {
+        float minTileX = Utils.toCoord(x);
+        float minTileY = Utils.toCoord(y);
+        return Utils.getCollidingFace(
+                minTileX + x1, minTileY + y1, minTileX + x2, minTileY + y2,
+                minX, minY, maxX, maxY);
+    }
+}

+ 3 - 2
src/me/hammerle/supersnuvi/tiles/BottledSoulTile.java

@@ -8,14 +8,15 @@ import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.util.SoundUtils;
 import me.hammerle.supersnuvi.util.SoundUtils;
 import me.hammerle.supersnuvi.gamelogic.Level;
 import me.hammerle.supersnuvi.gamelogic.Level;
 
 
-public class BottledSoulTile extends BaseTile
+public class BottledSoulTile extends BaseCollisionTile
 {
 {
     private final BlockDataStorage states = new BlockDataStorage();
     private final BlockDataStorage states = new BlockDataStorage();
     private final int score;
     private final int score;
     
     
     public BottledSoulTile(int score)
     public BottledSoulTile(int score)
     {
     {
-        super(0.0625f * (score - 1), 0.0625f, 0.0625f * score, 0.125f);
+        super(0.0625f * (score - 1), 0.0625f, 0.0625f * score, 0.125f,
+                Tile.SIZE * 0.2f, Tile.SIZE * 0.2f, Tile.SIZE * 0.8f, Tile.SIZE * 0.8f);
         super.setCollisionBox(CollisionBox.createScaledTileBox(0.2f, 0.2f, 0.8f, 0.8f));
         super.setCollisionBox(CollisionBox.createScaledTileBox(0.2f, 0.2f, 0.8f, 0.8f));
         this.score = score;
         this.score = score;
     }
     }

+ 2 - 2
src/me/hammerle/supersnuvi/tiles/CrumblingStoneTile.java

@@ -10,13 +10,13 @@ import me.hammerle.supersnuvi.util.SoundUtils;
 import me.hammerle.supersnuvi.util.Utils;
 import me.hammerle.supersnuvi.util.Utils;
 import me.hammerle.supersnuvi.gamelogic.Level;
 import me.hammerle.supersnuvi.gamelogic.Level;
 
 
-public class CrumblingStoneTile extends BaseTile
+public class CrumblingStoneTile extends BaseCollisionTile
 {
 {
     private final BlockDataStorage states = new BlockDataStorage();
     private final BlockDataStorage states = new BlockDataStorage();
     
     
     public CrumblingStoneTile() 
     public CrumblingStoneTile() 
     {
     {
-        super(0.1875f, 0.125f, 0.25f, 0.1875f);
+        super(0.1875f, 0.125f, 0.25f, 0.1875f, 0.0f, 0.0f, Tile.SIZE, Tile.SIZE * 0.6f);
         super.setCollisionBox(CollisionBox.createScaledTileBox(0.0f, 0.0f, 1.0f, 0.6f));
         super.setCollisionBox(CollisionBox.createScaledTileBox(0.0f, 0.0f, 1.0f, 0.6f));
         super.setMovementBox(CollisionBox.createScaledTileBox(0.0f, 0.0f, 1.0f, 0.6f));
         super.setMovementBox(CollisionBox.createScaledTileBox(0.0f, 0.0f, 1.0f, 0.6f));
     }
     }

+ 2 - 2
src/me/hammerle/supersnuvi/tiles/GoalTile.java

@@ -5,11 +5,11 @@ import me.hammerle.supersnuvi.util.CollisionBox;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.gamelogic.Level;
 import me.hammerle.supersnuvi.gamelogic.Level;
 
 
-public class GoalTile extends BaseTile
+public class GoalTile extends BaseCollisionTile
 {
 {
     public GoalTile(float tMinX, float tMinY, float tMaxX, float tMaxY) 
     public GoalTile(float tMinX, float tMinY, float tMaxX, float tMaxY) 
     {
     {
-        super(tMinX, tMinY, tMaxX, tMaxY);
+        super(tMinX, tMinY, tMaxX, tMaxY, Tile.SIZE * 0.1f, Tile.SIZE * 0.1f, Tile.SIZE * 0.9f, Tile.SIZE * 0.9f);
         super.setCollisionBox(CollisionBox.createScaledTileBox(0.1f, 0.1f, 0.9f, 0.9f));
         super.setCollisionBox(CollisionBox.createScaledTileBox(0.1f, 0.1f, 0.9f, 0.9f));
     }
     }
 
 

+ 3 - 3
src/me/hammerle/supersnuvi/tiles/InteractTile.java

@@ -6,11 +6,11 @@ import me.hammerle.supersnuvi.util.CollisionObject;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.gamelogic.Level;
 import me.hammerle.supersnuvi.gamelogic.Level;
 
 
-public class InteractTile extends BaseTile
+public class InteractTile extends BaseCollisionTile
 {
 {
     public InteractTile(float tMinX, float tMinY, float tMaxX, float tMaxY)
     public InteractTile(float tMinX, float tMinY, float tMaxX, float tMaxY)
     {
     {
-        super(tMinX, tMinY, tMaxX, tMaxY);
+        super(tMinX, tMinY, tMaxX, tMaxY, 0.0f, 0.0f, Tile.SIZE, Tile.SIZE);
         super.setCollisionBox(CollisionObject.DEFAULT_TILE_BOX);
         super.setCollisionBox(CollisionObject.DEFAULT_TILE_BOX);
         super.setMovementBox(CollisionObject.NULL_BOX);
         super.setMovementBox(CollisionObject.NULL_BOX);
     }
     }
@@ -24,7 +24,7 @@ public class InteractTile extends BaseTile
     @Override
     @Override
     public void onEntityCollide(Entity ent, int x, int y, Face face, Level l)
     public void onEntityCollide(Entity ent, int x, int y, Face face, Level l)
     {
     {
-        if(ent.getItemCollector().isHero() && Keys.UP.getTime() == 1 && face == Face.DOWN)
+        if(ent.getItemCollector().isHero() && Keys.UP.getTime() == 1)
         {
         {
             l.callEvent("tile_interact", (sc) -> 
             l.callEvent("tile_interact", (sc) -> 
             {
             {

+ 2 - 2
src/me/hammerle/supersnuvi/tiles/KillTile.java

@@ -5,11 +5,11 @@ import me.hammerle.supersnuvi.util.CollisionBox;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.gamelogic.Level;
 import me.hammerle.supersnuvi.gamelogic.Level;
 
 
-public class KillTile extends BaseTile
+public class KillTile extends BaseCollisionTile
 {
 {
     public KillTile(float tMinX, float tMinY, float tMaxX, float tMaxY) 
     public KillTile(float tMinX, float tMinY, float tMaxX, float tMaxY) 
     {
     {
-        super(tMinX, tMinY, tMaxX, tMaxY);
+        super(tMinX, tMinY, tMaxX, tMaxY, Tile.SIZE * 0.1f, Tile.SIZE * 0.1f, Tile.SIZE * 0.9f, Tile.SIZE * 0.9f);
         super.setCollisionBox(CollisionBox.createScaledTileBox(0.1f, 0.1f, 0.9f, 0.9f));
         super.setCollisionBox(CollisionBox.createScaledTileBox(0.1f, 0.1f, 0.9f, 0.9f));
     }
     }
 
 

+ 3 - 3
src/me/hammerle/supersnuvi/tiles/PressureTile.java

@@ -6,14 +6,14 @@ import me.hammerle.supersnuvi.util.CollisionObject;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.gamelogic.Level;
 import me.hammerle.supersnuvi.gamelogic.Level;
 
 
-public class PressureTile extends BaseTile
+public class PressureTile extends BaseCollisionTile
 {
 {
     public PressureTile(float tMinX, float tMinY, float tMaxX, float tMaxY)
     public PressureTile(float tMinX, float tMinY, float tMaxX, float tMaxY)
     {
     {
-        super(tMinX, tMinY, tMaxX, tMaxY);
+        super(tMinX, tMinY, tMaxX, tMaxY,
+                Tile.SIZE * 0.09375f, Tile.SIZE * 0.90625f, Tile.SIZE * 0.90625f, Tile.SIZE);
         super.setCollisionBox(CollisionBox.createScaledTileBox(0.09375f, 0.90625f, 0.90625f, 1.0f));
         super.setCollisionBox(CollisionBox.createScaledTileBox(0.09375f, 0.90625f, 0.90625f, 1.0f));
         super.setMovementBox(CollisionObject.NULL_BOX);
         super.setMovementBox(CollisionObject.NULL_BOX);
-
     }
     }
     
     
     @Override
     @Override

+ 24 - 0
src/me/hammerle/supersnuvi/tiles/RampTile.java

@@ -1,13 +1,24 @@
 package me.hammerle.supersnuvi.tiles;
 package me.hammerle.supersnuvi.tiles;
 
 
+import me.hammerle.supersnuvi.entity.Entity;
 import me.hammerle.supersnuvi.util.CollisionLine;
 import me.hammerle.supersnuvi.util.CollisionLine;
 import me.hammerle.supersnuvi.gamelogic.Level;
 import me.hammerle.supersnuvi.gamelogic.Level;
+import me.hammerle.supersnuvi.util.Utils;
 
 
 public class RampTile extends BaseTile
 public class RampTile extends BaseTile
 {
 {
+    private final float lx1;
+    private final float ly1;
+    private final float lx2;
+    private final float ly2;
+    
     public RampTile(float tMinX, float fMinY, float tMaxX, float tMaxY, float x1, float y1, float x2, float y2)
     public RampTile(float tMinX, float fMinY, float tMaxX, float tMaxY, float x1, float y1, float x2, float y2)
     {
     {
         super(tMinX, fMinY, tMaxX, tMaxY);
         super(tMinX, fMinY, tMaxX, tMaxY);
+        lx1 = x1;
+        ly1 = y1;
+        lx2 = x2;
+        ly2 = y2;
         
         
         CollisionLine line = new CollisionLine(x1, y1, x2, y2);
         CollisionLine line = new CollisionLine(x1, y1, x2, y2);
         super.setCollisionBox(line);
         super.setCollisionBox(line);
@@ -19,4 +30,17 @@ public class RampTile extends BaseTile
     {
     {
         return false;
         return false;
     }
     }
+
+    @Override
+    public boolean isMoveColliding(float minX, float minY, float maxX, float maxY, int x, int y, Level l)
+    {
+        float x1 = Utils.toCoord(x) + lx1;
+        float y1 = Utils.toCoord(y) + ly1;
+        float x2 = Utils.toCoord(x) + lx2;
+        float y2 = Utils.toCoord(y) + ly2;
+        return CollisionLine.intersect(x1, y1, x2, y2, minX, minY, maxX, minY) || 
+                CollisionLine.intersect(x1, y1, x2, y2, maxX, minY, maxX, maxY) ||
+                CollisionLine.intersect(x1, y1, x2, y2, maxX, maxY, minX, maxY) ||
+                CollisionLine.intersect(x1, y1, x2, y2, minX, maxY, minX, minY);
+    }
 }
 }

+ 2 - 2
src/me/hammerle/supersnuvi/tiles/SlipperyTile.java

@@ -14,13 +14,13 @@ public class SlipperyTile extends BaseBoxTile
     @Override
     @Override
     public void onEntityCollide(Entity ent, int x, int y, Face face, Level l) 
     public void onEntityCollide(Entity ent, int x, int y, Face face, Level l) 
     {
     {
-        if(face == Face.UP)
+        /*if(face == Face.UP)
         {
         {
             if(ent.getPreMotionY() != Entity.GRAVITY && Math.abs(ent.getMotionX()) <= 0.07)
             if(ent.getPreMotionY() != Entity.GRAVITY && Math.abs(ent.getMotionX()) <= 0.07)
             {
             {
                 ent.setMotionX(ent.getFace() == Face.RIGHT ? 5.0f : -5.0f);
                 ent.setMotionX(ent.getFace() == Face.RIGHT ? 5.0f : -5.0f);
             }
             }
             ent.getMovement().setFrictionFactor(0.85f);
             ent.getMovement().setFrictionFactor(0.85f);
-        }
+        }*/
     }
     }
 }
 }

+ 2 - 2
src/me/hammerle/supersnuvi/tiles/SpikeTile.java

@@ -7,7 +7,7 @@ import me.hammerle.supersnuvi.util.CollisionBox;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.gamelogic.Level;
 import me.hammerle.supersnuvi.gamelogic.Level;
 
 
-public class SpikeTile extends BaseTile
+public class SpikeTile extends BaseCollisionTile
 {
 {
     private final static Texture.Animation SPIKES = LevelRenderer.TILES.addAnimation(96, 32, 
     private final static Texture.Animation SPIKES = LevelRenderer.TILES.addAnimation(96, 32, 
             "resources/spike_trap/spike_trap_frame1.png", "resources/spike_trap/spike_trap_frame2.png",
             "resources/spike_trap/spike_trap_frame1.png", "resources/spike_trap/spike_trap_frame2.png",
@@ -19,7 +19,7 @@ public class SpikeTile extends BaseTile
     
     
     public SpikeTile() 
     public SpikeTile() 
     {
     {
-        super(0.1875f, 0.0625f, 0.25f, 0.125f);
+        super(0.1875f, 0.0625f, 0.25f, 0.125f, Tile.SIZE * 0.1f, Tile.SIZE * 0.1f, Tile.SIZE * 0.9f, Tile.SIZE * 0.9f);
         counter = 0;
         counter = 0;
         frame = 0;
         frame = 0;
         super.setCollisionBox(CollisionBox.createScaledTileBox(0.1f, 0.1f, 0.9f, 0.9f));
         super.setCollisionBox(CollisionBox.createScaledTileBox(0.1f, 0.1f, 0.9f, 0.9f));

+ 15 - 0
src/me/hammerle/supersnuvi/tiles/Tile.java

@@ -155,4 +155,19 @@ public abstract class Tile
     {
     {
         return true;
         return true;
     }
     }
+    
+    public boolean isMoveColliding(float minX, float minY, float maxX, float maxY, int x, int y, Level l)
+    {
+        return false;
+    }
+    
+    public boolean isColliding(float minX, float minY, float maxX, float maxY, int x, int y, Level l)
+    {
+        return false;
+    }
+    
+    public Face getCollidingFace(float minX, float minY, float maxX, float maxY, int x, int y, Level l)
+    {
+        return Face.NULL;
+    }
 }
 }

+ 1 - 1
src/me/hammerle/supersnuvi/tiles/TrampolinTile.java

@@ -17,7 +17,7 @@ public class TrampolinTile extends BaseBoxTile
     {
     {
         if(face == Face.UP)
         if(face == Face.UP)
         {
         {
-            ent.setMotionY(-ent.getMovement().getJumpPower());
+            ent.applyForce(0.0f, -ent.getMovement().getJumpPower());
             SoundUtils.playSound(SoundUtils.Sound.JUMP_ON_BOUNCE_SHROOM);
             SoundUtils.playSound(SoundUtils.Sound.JUMP_ON_BOUNCE_SHROOM);
         }
         }
     }
     }

+ 4 - 4
src/me/hammerle/supersnuvi/tiles/WaterTile.java

@@ -32,10 +32,10 @@ public class WaterTile extends BaseTile
     {
     {
         super.onEntityCollide(ent, x, y, face, l);
         super.onEntityCollide(ent, x, y, face, l);
         ent.getMovement().setInWater(true);
         ent.getMovement().setInWater(true);
-        if(ent.getMotionY() > 0.0f)
-        {
-            ent.setMotionY(0.0f);
-        }
+        //if(ent.getMotionY() > 0.0f)
+        //{
+        //    ent.setMotionY(0.0f);
+        //}
     }
     }
 
 
     @Override
     @Override

+ 4 - 3
src/me/hammerle/supersnuvi/util/Face.java

@@ -4,13 +4,14 @@ import me.hammerle.supersnuvi.entity.Entity;
 
 
 public enum Face 
 public enum Face 
 {
 {
+    NULL(0, 0),
     LEFT(-Entity.STEP, 0),
     LEFT(-Entity.STEP, 0),
     RIGHT(Entity.STEP, 0),
     RIGHT(Entity.STEP, 0),
     UP(0, -Entity.STEP),
     UP(0, -Entity.STEP),
     DOWN(0, Entity.STEP);
     DOWN(0, Entity.STEP);
     
     
-    private float offsetX;
-    private float offsetY;
+    private final float offsetX;
+    private final float offsetY;
     
     
     Face(float offsetX, float offsetY)
     Face(float offsetX, float offsetY)
     {
     {
@@ -27,7 +28,7 @@ public enum Face
             case UP: return DOWN;
             case UP: return DOWN;
             case DOWN: return UP;
             case DOWN: return UP;
         }
         }
-        return UP;
+        return NULL;
     }
     }
     
     
     public float getCollisionOffsetX()
     public float getCollisionOffsetX()

+ 40 - 0
src/me/hammerle/supersnuvi/util/Utils.java

@@ -23,4 +23,44 @@ public class Utils
     {
     {
         return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
         return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
     }
     }
+    
+    public static Face getCollidingFace(
+            float xMin1, float yMin1, float xMax1, float yMax1, 
+            float xMin2, float yMin2, float xMax2, float yMax2)
+    {
+        float diffUp = yMax1 - yMin2;
+        float diffRight = xMax2 - xMin1;
+        float diffDown = yMax2 - yMin1;
+        float diffLeft = xMax1 - xMin2;
+        
+        float min = diffUp;
+        
+        Face f = Face.UP;
+        if(min > diffRight)
+        {
+            min = diffRight;
+            f = Face.RIGHT;
+        }
+        if(min > diffDown)
+        {
+            min = diffDown;
+            f = Face.DOWN;
+        }
+        if(min > diffLeft)
+        {
+            f = Face.LEFT;
+        }
+        
+        int c = 0;
+        c += (min == diffUp) ? 1 : 0;
+        c += (min == diffRight) ? 1 : 0;
+        c += (min == diffDown) ? 1 : 0;
+        c += (min == diffLeft) ? 1 : 0;
+        if(c >= 2)
+        {
+            return Face.NULL;
+        }
+        
+        return f;
+    }
 }
 }