Selaa lähdekoodia

removed collision boxes / lines, refactoring, platform physics work

Kajetan Johannes Hammerle 5 vuotta sitten
vanhempi
commit
d17909cc24
25 muutettua tiedostoa jossa 352 lisäystä ja 695 poistoa
  1. 4 4
      levels/00-Tech_Demo.snuvi
  2. 185 9
      src/me/hammerle/supersnuvi/entity/Entity.java
  3. 5 0
      src/me/hammerle/supersnuvi/entity/components/Movement.java
  4. 6 0
      src/me/hammerle/supersnuvi/entity/components/StoneMovement.java
  5. 9 2
      src/me/hammerle/supersnuvi/entity/components/ai/PlatformController.java
  6. 22 77
      src/me/hammerle/supersnuvi/gamelogic/Level.java
  7. 5 0
      src/me/hammerle/supersnuvi/math/Vector.java
  8. 1 5
      src/me/hammerle/supersnuvi/tiles/BaseBoxTile.java
  9. 17 0
      src/me/hammerle/supersnuvi/tiles/BaseMoveCollisionTile.java
  10. 9 19
      src/me/hammerle/supersnuvi/tiles/BottledSoulTile.java
  11. 10 26
      src/me/hammerle/supersnuvi/tiles/CrumblingStoneTile.java
  12. 0 2
      src/me/hammerle/supersnuvi/tiles/GoalTile.java
  13. 2 5
      src/me/hammerle/supersnuvi/tiles/HeadHitOnceTile.java
  14. 1 1
      src/me/hammerle/supersnuvi/tiles/HeadHitTile.java
  15. 0 3
      src/me/hammerle/supersnuvi/tiles/InteractTile.java
  16. 0 2
      src/me/hammerle/supersnuvi/tiles/KillTile.java
  17. 1 5
      src/me/hammerle/supersnuvi/tiles/PressureTile.java
  18. 4 10
      src/me/hammerle/supersnuvi/tiles/RampTile.java
  19. 0 2
      src/me/hammerle/supersnuvi/tiles/SpikeTile.java
  20. 0 75
      src/me/hammerle/supersnuvi/tiles/Tile.java
  21. 2 4
      src/me/hammerle/supersnuvi/tiles/WaterTile.java
  22. 0 174
      src/me/hammerle/supersnuvi/util/CollisionBox.java
  23. 0 213
      src/me/hammerle/supersnuvi/util/CollisionLine.java
  24. 0 57
      src/me/hammerle/supersnuvi/util/CollisionObject.java
  25. 69 0
      src/me/hammerle/supersnuvi/util/Utils.java

+ 4 - 4
levels/00-Tech_Demo.snuvi

@@ -70,9 +70,9 @@ function onLevelReset()
     level.setTile(index, 7, 11, 73);
     level.setTile(index, 8, 10, 74);
     
-    $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);
+    $platform = platform.spawn(tile.toLevelCoord(4), tile.toLevelCoord(11), 3);
+    platform.addmove($platform, tile.toLevelCoord(4), tile.toLevelCoord(10), 6, 9, 1);
+    platform.addmove($platform, tile.toLevelCoord(3), tile.toLevelCoord(6), 6, 9, 1);
 }
 
 function onInteract(x, y, ent)
@@ -115,7 +115,7 @@ function onAutoInteract(x, y, ent)
     elseif(x == 8 && y == 10)
     {
         //entity.setMotionY(ent, tile.scale(-80));
-        entity.addHealth(entity.getHero(), -1);
+        //entity.addHealth(entity.getHero(), -1);
     }
 }
 

+ 185 - 9
src/me/hammerle/supersnuvi/entity/Entity.java

@@ -1,5 +1,7 @@
 package me.hammerle.supersnuvi.entity;
 
+import java.util.ArrayList;
+import java.util.List;
 import me.hammerle.supersnuvi.entity.components.ai.Controller;
 import me.hammerle.supersnuvi.entity.components.Energy;
 import me.hammerle.supersnuvi.entity.components.Health;
@@ -30,6 +32,8 @@ public final class Entity
     private final float height;  
     // own force used by the controller component
     private final Vector ownForce = new Vector();
+    // the final motion of the last tick
+    private final Vector lastMotion = new Vector();
     // the motion, reduced by the movement collision check
     private final Vector motion = new Vector();
     // the friction reducing motion each tick
@@ -203,6 +207,11 @@ public final class Entity
         return maxX > getX() && getX() + width > minX && maxY > getY() && getY() + height > minY;
     }
     
+    public boolean isColliding(Entity ent)
+    {
+        return isColliding(ent.getX(), ent.getY(), ent.getX() + ent.width, ent.getY() + ent.height);
+    }
+    
     private Face getCollidingFace(Entity o)
     {
         return Utils.getCollidingFace(
@@ -226,6 +235,10 @@ public final class Entity
     
     public void tick(Level level) 
     {
+        // last motion is current motion, last motion will be set in move
+        motion.set(lastMotion);
+        lastMotion.set(0.0f, 0.0f);
+        
         // reset own force
         ownForce.set(0.0f, 0.0f);
         
@@ -233,8 +246,11 @@ public final class Entity
         lastPos.set(pos);
         
         // update onGround before controller tick
-        // ToDo: does not work for ramps
         onGround = isOnTileGround(level);
+        if(onGround)
+        {
+            motion.setY(0.0f);
+        }
         
         // tick components
         controller.tick(this, level);
@@ -262,11 +278,26 @@ public final class Entity
         });
     }
     
-    public void move(Level level)
+    public int move(Level level)
     {
+        if(motion.getX() == 0.0f && motion.getY() == 0.0f)
+        {
+            return 0;
+        }
+        Vector maxMotion = new Vector();
+        maxMotion.set(motion);
+        
         reduceMotionByTiles(level);   
-        reduceMotionByEntities(level);     
+        reduceMotionByEntities(level);    
         pos.add(motion);
+        
+        int r = (motion.getX() == 0.0f && motion.getY() == 0.0f) ? 0 : 1;
+        
+        lastMotion.add(motion);
+        maxMotion.sub(motion);
+        motion.set(maxMotion);
+        
+        return r;
     }
     
     private boolean isOnTileGround(Level level)
@@ -291,6 +322,18 @@ public final class Entity
                 }
             }
         }
+        
+        for(Entity ent : level.getEntities())
+        {
+            if(ent == this)
+            {
+                continue;
+            }
+            if(ent.getMovement().isSolid() && ent.isColliding(minX, minY, maxX, maxY))
+            {
+                return true;
+            }
+        }
         return false;
     }
     
@@ -322,6 +365,106 @@ public final class Entity
     
     private void reduceMotionByEntities(Level level)
     {
+        if(motion.getX() == 0.0f && motion.getY() == 0.0f)
+        {
+            return;
+        }
+        
+        float mx = motion.getX();
+        float my = motion.getY();
+        
+        float oldPosX = pos.getX();
+        float oldPosY = pos.getY();
+
+        while(mx != 0.0 || my != 0.0)
+        {
+            if(mx != 0.0f)
+            {
+                float oldX = pos.getX();
+                if(mx < 0.0)
+                {
+                    if(mx > -STEP)
+                    {
+                        pos.addX(mx);
+                        mx = 0.0f;
+                    }
+                    else
+                    {
+                        pos.addX(-STEP);
+                        mx += STEP;
+                    }
+                }
+                else if(mx > 0.0)
+                {
+                    if(mx < STEP)
+                    {
+                        pos.addX(mx);
+                        mx = 0.0f;
+                    }
+                    else
+                    {
+                        pos.addX(STEP);
+                        mx -= STEP;
+                    }
+                }
+
+                List<Entity> list = isCollidingWithEntities(level);
+                for(Entity ent : list)
+                {
+                    if(move.isSolid() || ent.move.isSolid())
+                    {
+                        //controller.onCollideWithEntity(this, ent, getCollidingFace(ent));
+                        pos.setX(oldX);
+                        mx = 0.0f;
+                    }
+                }
+            }
+            if(my != 0.0f)
+            {
+                float oldY = pos.getY();
+
+                if(my < 0.0)
+                {
+                    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;
+                    }
+                }
+
+                List<Entity> list = isCollidingWithEntities(level);
+                for(Entity ent : list)
+                {
+                    if(move.isSolid() || ent.move.isSolid())
+                    {
+                        //controller.onCollideWithEntity(this, ent, getCollidingFace(ent));
+                        pos.setY(oldY);
+                        my = 0.0f;
+                    }
+                }
+            }
+        }
+
+        motion.set(pos.getX() - oldPosX, pos.getY() - oldPosY);
+        pos.set(oldPosX, oldPosY);
     }
     
     private boolean isCollidingWithTiles(int startX, int startY, int endX, int endY, Level level)
@@ -342,10 +485,42 @@ public final class Entity
         }
         return false;
     }
+    
+    private List<Entity> isCollidingWithEntities(Level level)
+    {
+        float minX = pos.getX();
+        float minY = pos.getY();
+        float maxX = pos.getX() + width;
+        float maxY = pos.getY() + height;
+        ArrayList<Entity> list = new ArrayList<>();
+        for(Entity ent : level.getEntities())
+        {
+            if(ent == this)
+            {
+                continue;
+            }
+            if(ent.isColliding(minX, minY, maxX, maxY))
+            {
+                list.add(ent);
+            }
+        }
+        for(Entity ent : level.getEntitiesInQueue())
+        {
+            if(ent == this)
+            {
+                continue;
+            }
+            if(ent.isColliding(minX, minY, maxX, maxY))
+            {
+                list.add(ent);
+            }
+        }
+        return list;
+    }
 
     public void reduceMotionByTiles(Level level)
     {
-        if(move.canMoveEverywhere())
+        if(move.canMoveEverywhere() || (motion.getX() == 0.0f && motion.getY() == 0.0f))
         {
             return;
         }
@@ -353,11 +528,6 @@ public final class Entity
         float mx = motion.getX();
         float my = motion.getY();
         
-        if(mx == 0.0f && my == 0.0f)
-        {
-            return;
-        }
-        
         int startX;
         int endX;
         if(mx < 0.0f)
@@ -487,4 +657,10 @@ public final class Entity
     {
         return onGround;
     }   
+
+    @Override
+    public String toString()
+    {
+        return String.format("(%f, %f, %f, %f)", pos.getX(), pos.getY(), pos.getX() + width, pos.getY() + height);
+    }
 }

+ 5 - 0
src/me/hammerle/supersnuvi/entity/components/Movement.java

@@ -53,4 +53,9 @@ public class Movement
     {
         return 1.0f;
     }
+    
+    public boolean isSolid()
+    {
+        return false;
+    }
 }

+ 6 - 0
src/me/hammerle/supersnuvi/entity/components/StoneMovement.java

@@ -27,4 +27,10 @@ public class StoneMovement extends Movement
     {
         return true;
     }  
+
+    @Override
+    public boolean isSolid()
+    {
+        return true;
+    }
 }

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

@@ -115,11 +115,18 @@ public class PlatformController extends Controller
     {
         if(face == Face.UP)
         {
-            other.applyForce(ent.getOwnForceX(), 0.0f);
+            if(ent.getOwnForceY() < 0)
+            {
+                other.applyForce(ent.getOwnForceX(), ent.getOwnForceY() - Entity.GRAVITY * other.getMovement().getGravityFactor());
+            }
+            else
+            {
+                other.applyForce(ent.getOwnForceX(), ent.getOwnForceY());
+            }
         }
         else if(face == Face.LEFT || face == Face.RIGHT)
         {
-            other.applyForce(ent.getOwnForceX() - other.getOwnForceX(), 0.0f);
+            other.applyForce(ent.getOwnForceX(), 0.0f);
         }
     }
 }

+ 22 - 77
src/me/hammerle/supersnuvi/gamelogic/Level.java

@@ -1,6 +1,6 @@
 package me.hammerle.supersnuvi.gamelogic;
 
-import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
@@ -13,7 +13,6 @@ import me.hammerle.supersnuvi.rendering.Light;
 import me.hammerle.supersnuvi.rendering.TileUpdater;
 import me.hammerle.supersnuvi.tiles.Location;
 import me.hammerle.supersnuvi.tiles.Tile;
-import me.hammerle.supersnuvi.util.CollisionObject;
 import me.hammerle.supersnuvi.util.Utils;
 
 public abstract class Level
@@ -135,7 +134,15 @@ public abstract class Level
             }
             return false;
         });
-        entities.values().forEach(ent -> ent.move(this));
+        int changes = 1;
+        while(changes > 0)
+        {
+            changes = 0;
+            for(Entity ent : entities.values())
+            {
+                changes += ent.move(this);
+            }
+        }
 
         if(!spawnQueue.isEmpty())
         {
@@ -155,8 +162,8 @@ public abstract class Level
     {
         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;
+        float maxX = ent.getX() + ent.getWidth() + Entity.STEP;
+        float maxY = ent.getY() + ent.getHeight() + Entity.STEP;
         entities.values().stream().filter(other -> ent != other && other.isColliding(minX, minY, maxX, maxY)).forEach(c);
     }
     
@@ -165,6 +172,16 @@ public abstract class Level
         entities.values().forEach(c);
     }
     
+    public final Collection<Entity> getEntities()
+    {
+        return entities.values();
+    }
+    
+    public final Collection<Entity> getEntitiesInQueue()
+    {
+        return spawnQueue;
+    }
+    
     // -------------------------------------------------------------------------
     // controlling
     // -------------------------------------------------------------------------
@@ -236,78 +253,6 @@ public abstract class Level
         return Game.get().getTile(i);
     }
     
-    private CollisionObject getMovementBox(int x, int y)
-    {
-        int i = getData().getInteractionTile(x, y);
-        if(i == -1)
-        {
-            return CollisionObject.NULL_BOX;
-        }
-        return Game.get().getTile(i).getMovementBox(x, y, this).reset().offset(Utils.toCoord(x), Utils.toCoord(y));
-    }
-    
-    public final List<CollisionObject> getMovementBoxesAt(CollisionObject box, Entity not)
-    {
-        List<CollisionObject> boxes;
-        if(not != null)
-        {
-            //boxes = getEntitiesCollidingWith(not, box).stream().map(ent -> ent.getBox()).collect(Collectors.toList());
-            boxes = new LinkedList<>();
-        }
-        else
-        {
-            boxes = new LinkedList<>();
-        }
-        int startX = Utils.toBlock(box.getMinX());
-        int endX = Utils.toBlock(box.getMaxX());
-        int startY = Utils.toBlock(box.getMinY());
-        int endY = Utils.toBlock(box.getMaxY());
-        
-        for(int x = startX; x <= endX; x++)
-        {
-            for(int y = startY; y <= endY; y++)
-            {
-                CollisionObject cb = getMovementBox(x, y);
-                if(cb.mayCollide(box) && cb != CollisionObject.NULL_BOX)
-                {
-                    boxes.add(cb.copy());
-                }
-            }
-        }
-        return boxes;
-    }
-    
-    private CollisionObject getCollisionBox(int x, int y)
-    {
-        int i = getData().getInteractionTile(x, y);
-        if(i == -1)
-        {
-            return CollisionObject.NULL_BOX;
-        }
-        return Game.get().getTile(i).getCollisionBox(x, y, this).reset().offset(Utils.toCoord(x), Utils.toCoord(y));
-    }
-    
-    public final List<Location> getCollisionBoxesAt(CollisionObject cb)
-    {
-        LinkedList<Location> boxes = new LinkedList<>();
-        int startX = Utils.toBlock(cb.getMinX());
-        int endX = Utils.toBlock(cb.getMaxX());
-        int startY = Utils.toBlock(cb.getMinY());
-        int endY = Utils.toBlock(cb.getMaxY());
-        
-        for(int x = startX; x <= endX; x++)
-        {
-            for(int y = startY; y <= endY; y++)
-            {
-                if(getCollisionBox(x, y).isColliding(cb))
-                {
-                    boxes.add(new Location(getInteractionTile(x, y), this, x, y));
-                }
-            }
-        }
-        return boxes;
-    }
-    
     // -------------------------------------------------------------------------
     // scripting
     // -------------------------------------------------------------------------

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

@@ -48,6 +48,11 @@ public class Vector implements IVector
         add(v.x, v.y);
     }
     
+    public void sub(Vector v)
+    {
+        add(-v.x, -v.y);
+    }
+    
     public void addY(float y)
     {
         this.y += y;

+ 1 - 5
src/me/hammerle/supersnuvi/tiles/BaseBoxTile.java

@@ -9,16 +9,12 @@ public class BaseBoxTile extends BaseTile
     public BaseBoxTile(float tMinX, float tMinY, float tMaxX, float tMaxY)
     {
         super(tMinX, tMinY, tMaxX, tMaxY);
-        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;
+        return isColliding(minX, minY, maxX, maxY, x, y, l);
     }
 
     @Override

+ 17 - 0
src/me/hammerle/supersnuvi/tiles/BaseMoveCollisionTile.java

@@ -0,0 +1,17 @@
+package me.hammerle.supersnuvi.tiles;
+
+import me.hammerle.supersnuvi.gamelogic.Level;
+
+public class BaseMoveCollisionTile extends BaseCollisionTile
+{
+    public BaseMoveCollisionTile(float tMinX, float tMinY, float tMaxX, float tMaxY, float x1, float y1, float x2, float y2)
+    {
+        super(tMinX, tMinY, tMaxX, tMaxY, x1, y1, x2, y2);
+    }
+
+    @Override
+    public boolean isMoveColliding(float minX, float minY, float maxX, float maxY, int x, int y, Level l)
+    {
+        return super.isColliding(minX, minY, maxX, maxY, x, y, l);
+    }
+}

+ 9 - 19
src/me/hammerle/supersnuvi/tiles/BottledSoulTile.java

@@ -2,8 +2,6 @@ package me.hammerle.supersnuvi.tiles;
 
 import me.hammerle.supersnuvi.entity.Entity;
 import me.hammerle.supersnuvi.util.BlockDataStorage;
-import me.hammerle.supersnuvi.util.CollisionBox;
-import me.hammerle.supersnuvi.util.CollisionObject;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.util.SoundUtils;
 import me.hammerle.supersnuvi.gamelogic.Level;
@@ -17,36 +15,28 @@ public class BottledSoulTile extends BaseCollisionTile
     {
         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));
         this.score = score;
     }
 
     @Override
     public void onEntityCollide(Entity ent, int x, int y, Face face, Level l) 
     {
-        if(ent.getItemCollector().canCollect())
+        if(ent.getItemCollector().canCollect() && states.add(x, y, l))
         {
-            if(states.add(x, y, l))
+            l.getTileUpdater().add(l.getData().getBackgroundIndex(), x, y);
+            if(ent.getItemCollector().isHero())
             {
-                l.getTileUpdater().add(l.getData().getBackgroundIndex(), x, y);
-                if(ent.getItemCollector().isHero())
-                {
-                    SoundUtils.playSound(SoundUtils.Sound.COLLECT);
-                    l.addBottles(score);
-                }
-                ent.getHealth().addHealthPercent(0.143f * score);
+                SoundUtils.playSound(SoundUtils.Sound.COLLECT);
+                l.addBottles(score);
             }
+            ent.getHealth().addHealthPercent(0.143f * score);
         }
     }
-    
+
     @Override
-    public CollisionObject getCollisionBox(int x, int y, Level l) 
+    public boolean isColliding(float minX, float minY, float maxX, float maxY, int x, int y, Level l)
     {
-        if(states.contains(x, y, l))
-        {
-            return CollisionObject.NULL_BOX;
-        }
-        return super.getCollisionBox(x, y, l);
+        return !states.contains(x, y, l) && super.isColliding(minX, minY, maxX, maxY, x, y, l);
     }
 
     @Override

+ 10 - 26
src/me/hammerle/supersnuvi/tiles/CrumblingStoneTile.java

@@ -3,56 +3,40 @@ package me.hammerle.supersnuvi.tiles;
 import me.hammerle.supersnuvi.entity.Entity;
 import me.hammerle.supersnuvi.entity.EntityBuilder;
 import me.hammerle.supersnuvi.util.BlockDataStorage;
-import me.hammerle.supersnuvi.util.CollisionBox;
-import me.hammerle.supersnuvi.util.CollisionObject;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.util.SoundUtils;
 import me.hammerle.supersnuvi.util.Utils;
 import me.hammerle.supersnuvi.gamelogic.Level;
 
-public class CrumblingStoneTile extends BaseCollisionTile
+public class CrumblingStoneTile extends BaseMoveCollisionTile
 {
     private final BlockDataStorage states = new BlockDataStorage();
     
     public CrumblingStoneTile() 
     {
         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.setMovementBox(CollisionBox.createScaledTileBox(0.0f, 0.0f, 1.0f, 0.6f));
     }
 
     @Override
-    public CollisionObject getCollisionBox(int x, int y, Level l) 
+    public boolean isColliding(float minX, float minY, float maxX, float maxY, int x, int y, Level l)
     {
-        if(states.contains(x, y, l))
-        {
-            return CollisionObject.NULL_BOX;
-        }
-        return super.getCollisionBox(x, y, l);
+        return !states.contains(x, y, l) && super.isColliding(minX, minY, maxX, maxY, x, y, l);
     }
 
     @Override
-    public CollisionObject getMovementBox(int x, int y, Level l) 
+    public boolean isMoveColliding(float minX, float minY, float maxX, float maxY, int x, int y, Level l)
     {
-        if(states.contains(x, y, l))
-        {
-            return CollisionObject.NULL_BOX;
-        }
-        return super.getMovementBox(x, y, l);
+        return !states.contains(x, y, l) && super.isMoveColliding(minX, minY, maxX, maxY, x, y, l);
     }
 
     @Override
     public void onEntityCollide(Entity ent, int x, int y, Face face, Level l) 
     {
-        super.onEntityCollide(ent, x, y, face, l);
-        if(face == Face.UP)
+        if(face == Face.UP && !ent.getMovement().canMoveEverywhere() && states.add(x, y, l))
         {
-            if(states.add(x, y, l))
-            {
-                l.getTileUpdater().add(l.getData().getBackgroundIndex(), x, y);      
-                l.spawnEntity(EntityBuilder.buildCrumblingStone(l, Utils.toCoord(x), Utils.toCoord(y)));
-                SoundUtils.playSound(SoundUtils.Sound.STONE_CRUMBLING);
-            }
+            l.getTileUpdater().add(l.getData().getBackgroundIndex(), x, y);      
+            l.spawnEntity(EntityBuilder.buildCrumblingStone(l, Utils.toCoord(x), Utils.toCoord(y)));
+            SoundUtils.playSound(SoundUtils.Sound.STONE_CRUMBLING);
         }
     }
 
@@ -73,4 +57,4 @@ public class CrumblingStoneTile extends BaseCollisionTile
     {
         states.clear(x, y, l);
     }
-}
+}

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

@@ -1,7 +1,6 @@
 package me.hammerle.supersnuvi.tiles;
 
 import me.hammerle.supersnuvi.entity.Entity;
-import me.hammerle.supersnuvi.util.CollisionBox;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.gamelogic.Level;
 
@@ -10,7 +9,6 @@ public class GoalTile extends BaseCollisionTile
     public GoalTile(float tMinX, float tMinY, float tMaxX, float 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));
     }
 
     @Override

+ 2 - 5
src/me/hammerle/supersnuvi/tiles/HeadHitOnceTile.java

@@ -50,7 +50,7 @@ public class HeadHitOnceTile extends BaseBoxTile
     @Override
     public void onEntityCollide(Entity ent, int x, int y, Face face, Level l)
     {
-        if(face == Face.DOWN && ent.getMotionY() < 0 && states.add(x, y, l))
+        if(face == Face.DOWN && ent.getItemCollector().isHero() && ent.getMotionY() > 0 && states.add(x, y, l))
         {
             l.getTileUpdater().add(l.getData().getBackgroundIndex(), x, y);
             l.callEvent("tile_hit", (sc) -> 
@@ -58,10 +58,7 @@ public class HeadHitOnceTile extends BaseBoxTile
                 sc.setVar("tile_x", (double) x);
                 sc.setVar("tile_y", (double) y);
                 sc.setVar("entity", ent);
-            }, (sc) -> 
-            {
-                
-            });
+            }, null);
         }
     }
     

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

@@ -14,7 +14,7 @@ public class HeadHitTile extends BaseBoxTile
     @Override
     public void onEntityCollide(Entity ent, int x, int y, Face face, Level l)
     {
-        if(face == Face.DOWN && ent.getMotionY() < 0)
+        if(face == Face.DOWN && ent.getItemCollector().isHero() && ent.getMotionY() > 0)
         {
             l.callEvent("tile_hit", (sc) -> 
             {

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

@@ -2,7 +2,6 @@ package me.hammerle.supersnuvi.tiles;
 
 import me.hammerle.supersnuvi.Keys;
 import me.hammerle.supersnuvi.entity.Entity;
-import me.hammerle.supersnuvi.util.CollisionObject;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.gamelogic.Level;
 
@@ -11,8 +10,6 @@ public class InteractTile extends BaseCollisionTile
     public InteractTile(float tMinX, float tMinY, float tMaxX, float tMaxY)
     {
         super(tMinX, tMinY, tMaxX, tMaxY, 0.0f, 0.0f, Tile.SIZE, Tile.SIZE);
-        super.setCollisionBox(CollisionObject.DEFAULT_TILE_BOX);
-        super.setMovementBox(CollisionObject.NULL_BOX);
     }
 
     @Override

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

@@ -1,7 +1,6 @@
 package me.hammerle.supersnuvi.tiles;
 
 import me.hammerle.supersnuvi.entity.Entity;
-import me.hammerle.supersnuvi.util.CollisionBox;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.gamelogic.Level;
 
@@ -10,7 +9,6 @@ public class KillTile extends BaseCollisionTile
     public KillTile(float tMinX, float tMinY, float tMaxX, float 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));
     }
 
     @Override

+ 1 - 5
src/me/hammerle/supersnuvi/tiles/PressureTile.java

@@ -1,8 +1,6 @@
 package me.hammerle.supersnuvi.tiles;
 
 import me.hammerle.supersnuvi.entity.Entity;
-import me.hammerle.supersnuvi.util.CollisionBox;
-import me.hammerle.supersnuvi.util.CollisionObject;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.gamelogic.Level;
 
@@ -12,8 +10,6 @@ public class PressureTile extends BaseCollisionTile
     {
         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.setMovementBox(CollisionObject.NULL_BOX);
     }
     
     @Override
@@ -49,7 +45,7 @@ public class PressureTile extends BaseCollisionTile
     @Override
     public void onEntityCollide(Entity ent, int x, int y, Face face, Level l)
     {
-        if(face == Face.UP)
+        if(face == Face.UP && ent.getItemCollector().isHero())
         {
             l.callEvent("auto_tile_interact", (sc) -> 
             {

+ 4 - 10
src/me/hammerle/supersnuvi/tiles/RampTile.java

@@ -1,7 +1,5 @@
 package me.hammerle.supersnuvi.tiles;
 
-import me.hammerle.supersnuvi.entity.Entity;
-import me.hammerle.supersnuvi.util.CollisionLine;
 import me.hammerle.supersnuvi.gamelogic.Level;
 import me.hammerle.supersnuvi.util.Utils;
 
@@ -19,10 +17,6 @@ public class RampTile extends BaseTile
         ly1 = y1;
         lx2 = x2;
         ly2 = y2;
-        
-        CollisionLine line = new CollisionLine(x1, y1, x2, y2);
-        super.setCollisionBox(line);
-        super.setMovementBox(line);
     }
 
     @Override
@@ -38,9 +32,9 @@ public class RampTile extends BaseTile
         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);
+        return Utils.intersect(x1, y1, x2, y2, minX, minY, maxX, minY) || 
+                Utils.intersect(x1, y1, x2, y2, maxX, minY, maxX, maxY) ||
+                Utils.intersect(x1, y1, x2, y2, maxX, maxY, minX, maxY) ||
+                Utils.intersect(x1, y1, x2, y2, minX, maxY, minX, minY);
     }
 }

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

@@ -3,7 +3,6 @@ package me.hammerle.supersnuvi.tiles;
 import me.hammerle.snuviengine.api.Texture;
 import me.hammerle.supersnuvi.entity.Entity;
 import me.hammerle.supersnuvi.rendering.LevelRenderer;
-import me.hammerle.supersnuvi.util.CollisionBox;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.gamelogic.Level;
 
@@ -22,7 +21,6 @@ public class SpikeTile extends BaseCollisionTile
         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;
         frame = 0;
-        super.setCollisionBox(CollisionBox.createScaledTileBox(0.1f, 0.1f, 0.9f, 0.9f));
     }
 
     @Override

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

@@ -1,7 +1,6 @@
 package me.hammerle.supersnuvi.tiles;
 
 import me.hammerle.supersnuvi.entity.Entity;
-import me.hammerle.supersnuvi.util.CollisionObject;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.gamelogic.Level;
 
@@ -10,85 +9,11 @@ public abstract class Tile
     public final static int SIZE = 32;
     public final static float SIZE_SCALE = SIZE / 32.0f;
     
-    private CollisionObject movementCollision;
-    private CollisionObject collisionBox;
-    
-    public Tile()
-    {
-        movementCollision = null;
-        collisionBox = null;
-    }
-
-    /** Sets the collision box for movement
-     *
-     * @param cb a collision box
-     * @return the tile which the change was applied to
-     */
-    public Tile setMovementBox(CollisionObject cb)
-    {
-        if(cb == CollisionObject.NULL_BOX)
-        {
-            this.movementCollision = null;
-        }
-        else
-        {
-            this.movementCollision = cb.copy();
-        }
-        return this;
-    }
-    
-    /** Sets the collision box for normal collision
-     *
-     * @param cb a collision box
-     * @return the tile which the change was applied to
-     */
-    public Tile setCollisionBox(CollisionObject cb)
-    {
-        if(cb == CollisionObject.NULL_BOX)
-        {
-            this.collisionBox = null;
-        }
-        else
-        {
-            this.collisionBox = cb.copy();
-        }
-        return this;
-    }
-    
-    /** Sets the default collision box for movement and for collision
-     *
-     * @return the tile which the change was applied to
-     */
-    public Tile setDefaultCollisionBox()
-    {
-        this.movementCollision = CollisionObject.DEFAULT_TILE_BOX.copy();
-        this.collisionBox = CollisionObject.DEFAULT_TILE_BOX.copy();
-        return this;
-    }
-    
-    public CollisionObject getCollisionBox(int x, int y, Level l)
-    {
-        if(collisionBox != null)
-        {
-            return collisionBox;
-        }
-        return CollisionObject.NULL_BOX.reset();
-    }
-    
     public boolean shouldAiUseCollisionBox(int x, int y, Level l)
     {
         return true;
     }
     
-    public CollisionObject getMovementBox(int x, int y, Level l)
-    {
-        if(movementCollision != null)
-        {
-            return movementCollision;
-        }
-        return CollisionObject.NULL_BOX.reset();
-    }
-    
     public void onEntityCollide(Entity ent, int x, int y, Face face, Level l)
     {
         

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

@@ -3,8 +3,6 @@ package me.hammerle.supersnuvi.tiles;
 import me.hammerle.snuviengine.api.Texture.Animation;
 import me.hammerle.supersnuvi.entity.Entity;
 import me.hammerle.supersnuvi.rendering.LevelRenderer;
-import me.hammerle.supersnuvi.util.CollisionBox;
-import me.hammerle.supersnuvi.util.CollisionObject;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.gamelogic.Level;
 
@@ -23,8 +21,8 @@ public class WaterTile extends BaseTile
     {
         super(0.3125f, 0.00390625f * (15 - level), 0.375f, 0.0625f);
         this.level = level;
-        super.setCollisionBox(CollisionBox.createScaledTileBox(0.03125f, getOffsetY() / Tile.SIZE, 0.96875f, 1.0f));
-        super.setMovementBox(CollisionObject.NULL_BOX);
+        //super.setCollisionBox(CollisionBox.createScaledTileBox(0.03125f, getOffsetY() / Tile.SIZE, 0.96875f, 1.0f));
+        //super.setMovementBox(CollisionObject.NULL_BOX);
     }
 
     @Override

+ 0 - 174
src/me/hammerle/supersnuvi/util/CollisionBox.java

@@ -1,174 +0,0 @@
-package me.hammerle.supersnuvi.util;
-
-import me.hammerle.supersnuvi.tiles.Tile;
-
-public class CollisionBox extends CollisionObject
-{
-    private float minX;
-    private float maxX;
-    private float minY;
-    private float maxY;
-    
-    private float cMinX;
-    private float cMaxX;
-    private float cMinY;
-    private float cMaxY;
-    
-    public CollisionBox(float x1, float y1, float x2, float y2)
-    {
-        minX = Math.min(x1, x2);
-        maxX = Math.max(x1, x2);
-        minY = Math.min(y1, y2);
-        maxY = Math.max(y1, y2);
-        cMinX = minX;
-        cMaxX = maxX;
-        cMinY = minY;
-        cMaxY = maxY;
-    }
-    
-    public static CollisionObject createScaledTileBox(float x1, float y1, float x2, float y2)
-    {
-        return new CollisionBox(x1 * Tile.SIZE, y1 * Tile.SIZE, x2 * Tile.SIZE, y2 * Tile.SIZE);
-    }
-    
-    @Override
-    public CollisionObject copy()
-    {
-        return new CollisionBox(cMinX, cMinY, cMaxX, cMaxY);
-    }
-    
-    @Override
-    public void save()
-    {
-        minX = cMinX;
-        maxX = cMaxX;
-        minY = cMinY;
-        maxY = cMaxY;
-    }
-    
-    @Override
-    public CollisionObject reset()
-    {
-        cMinX = minX;
-        cMaxX = maxX;
-        cMinY = minY;
-        cMaxY = maxY;
-        return this;
-    }
-
-    @Override
-    public float getWidth() 
-    {
-        return maxX - minX;
-    }
-    
-    @Override
-    public float getHeight() 
-    {
-        return maxY - minY;
-    }
-    
-    @Override
-    public float getMinX() 
-    {
-        return cMinX;
-    }
-
-    @Override
-    public float getMaxX() 
-    {
-        return cMaxX;
-    }
-
-    @Override
-    public float getMinY() 
-    {
-        return cMinY;
-    }
-
-    @Override
-    public float getMaxY() 
-    {
-        return cMaxY;
-    }
-   
-    @Override
-    public CollisionObject expand(float x, float y)
-    {
-        if(x < 0.0f)
-        {
-            cMinX += x;
-        }
-        else
-        {
-            cMaxX += x;
-        }
-        if(y < 0.0f)
-        {
-            cMinY += y;
-        }
-        else
-        {
-            cMaxY += y;
-        }
-        return this;
-    }
-    
-    @Override
-    public CollisionObject offsetX(float x)
-    {
-        cMinX += x;
-        cMaxX += x;
-        return this;
-    }
-    
-    @Override
-    public CollisionObject offsetY(float y)
-    {
-        cMinY += y;
-        cMaxY += y;
-        return this;
-    }
-    
-    @Override
-    public boolean isColliding(CollisionObject cb)
-    {
-        switch(cb.getType())
-        {
-            case BOX:
-                return cMaxX > cb.getMinX() && cb.getMaxX() > cMinX && cMaxY > cb.getMinY() && cb.getMaxY() > cMinY;
-            case LINE:
-                float x1 = cb.getMinX();
-                float y1 = cb.getMinY();
-                float x2 = cb.getMaxX();
-                float y2 = cb.getMaxY();
-                return CollisionLine.intersect(x1, y1, x2, y2, cMinX, cMinY, cMaxX, cMinY) || 
-                        CollisionLine.intersect(x1, y1, x2, y2, cMaxX, cMinY, cMaxX, cMaxY) ||
-                        CollisionLine.intersect(x1, y1, x2, y2, cMaxX, cMaxY, cMinX, cMaxY) ||
-                        CollisionLine.intersect(x1, y1, x2, y2, cMinX, cMaxY, cMinX, cMinY);
-        }
-        return false;
-        
-    }
-
-    @Override
-    public String toString() 
-    {
-        StringBuilder sb = new StringBuilder("box[x1 = ");
-        sb.append(cMinX);
-        sb.append(", y1 = ");
-        sb.append(cMinY);
-        sb.append(", x2 = ");
-        sb.append(cMaxX);
-        sb.append(", y2 = ");
-        sb.append(cMaxY);
-        sb.append(']');
-        return sb.toString();
-    } 
-
-    @Override
-    public Type getType()
-    {
-        return Type.BOX;
-    }
-}

+ 0 - 213
src/me/hammerle/supersnuvi/util/CollisionLine.java

@@ -1,213 +0,0 @@
-package me.hammerle.supersnuvi.util;
-
-public class CollisionLine extends CollisionObject
-{
-    private float x1;
-    private float y1;
-    private float x2;
-    private float y2;
-    
-    private float cx1;
-    private float cy1;
-    private float cx2;
-    private float cy2;
-    
-    public CollisionLine(float x1, float y1, float x2, float y2)
-    {
-        this.x1 = x1;
-        this.y1 = y1;
-        this.x2 = x2;
-        this.y2 = y2;
-        
-        this.cx1 = x1;
-        this.cy1 = y1;
-        this.cx2 = x2;
-        this.cy2 = y2;
-    }
-    
-    @Override
-    public Type getType()
-    {
-        return Type.LINE;
-    }
-
-    @Override
-    public CollisionObject copy()
-    {
-        return new CollisionLine(cx1, cy1, cx2, cy2);
-    }
-
-    @Override
-    public void save()
-    {
-        x1 = cx1;
-        y1 = cy1;
-        x2 = cx2;
-        y2 = cy2;
-    }
-
-    @Override
-    public CollisionObject reset()
-    {
-        cx1 = x1;
-        cy1 = y1;
-        cx2 = x2;
-        cy2 = y2;
-        return this;
-    }
-
-    @Override
-    public float getWidth()
-    {
-        return Math.abs(x1 - x2);
-    }
-
-    @Override
-    public float getHeight()
-    {
-        return Math.abs(y1 - y2);
-    }
-
-    @Override
-    public float getMinX()
-    {
-        return cx1;
-    }
-
-    @Override
-    public float getMaxX()
-    {
-        return cx2;
-    }
-
-    @Override
-    public float getMinY()
-    {
-        return cy1;
-    }
-
-    @Override
-    public float getMaxY()
-    {
-        return cy2;
-    }
-
-    @Override
-    public CollisionObject expand(float x, float y)
-    {
-        return this;
-    }
-
-    @Override
-    public CollisionObject offsetX(float x)
-    {
-        cx1 += x;
-        cx2 += x;
-        return this;
-    }
-
-    @Override
-    public CollisionObject offsetY(float y)
-    {
-        cy1 += y;
-        cy2 += y;
-        return this;
-    }
-
-    @Override
-    public boolean isColliding(CollisionObject cb)
-    {
-        switch(cb.getType())
-        {
-            case BOX:
-                return cb.isColliding(this);
-            case LINE:
-                return CollisionLine.intersect(x1, y1, x2, y2, cb.getMinX(), cb.getMinY(), cb.getMaxX(), cb.getMaxY());
-        }
-        return false;
-    }
-    
-    @Override
-    public String toString() 
-    {
-        StringBuilder sb = new StringBuilder("line[x1 = ");
-        sb.append(cx1);
-        sb.append(", y1 = ");
-        sb.append(cy1);
-        sb.append(", x2 = ");
-        sb.append(cx2);
-        sb.append(", y2 = ");
-        sb.append(cy2);
-        sb.append(']');
-        return sb.toString();
-    } 
-    
-    public static boolean intersect(float x11, float y11, float x12, float y12, float x21, float y21, float x22, float y22)
-    {
-        if(compareFloats(x11, x12))
-        {
-            if(compareFloats(x21, x22))
-            {
-                return false;
-            }
-            else
-            {
-                if(!isBetween(x11, x21, x22))
-                {
-                    return false;
-                }
-                float k = (y21 - y22) / (x21 - x22);
-                float d = y22 - k * x22;
-                float y = d + x11 * k;
-                return isBetween(y, y11, y12) && isBetween(y, y21, y22);
-            }
-        }
-        else
-        {
-            if(compareFloats(x21, x22))
-            {
-                if(!isBetween(x21, x11, x12))
-                {
-                    return false;
-                }
-                float k = (y11 - y12) / (x11 - x12);
-                float d = y12 - k * x12;
-                float y = d + x21 * k;
-                return isBetween(y, y11, y12) && isBetween(y, y21, y22);
-            }
-            else
-            {
-                float k1 = (y11 - y12) / (x11 - x12);
-                float k2 = (y21 - y22) / (x21 - x22);
-                if(compareFloats(k1, k2))
-                {
-                    return false;
-                }
-                float d1 = y12 - k1 * x12;
-                float d2 = y22 - k2 * x22;
-                
-                float x = (d1 - d2) / (k2 - k1);
-                if(!isBetween(x, x11, x12) || !isBetween(x, x21, x22))
-                {
-                    return false;
-                }
-                float y = k1 * x + d1;
-                return isBetween(y, y11, y12) && isBetween(y, y21, y22);
-            }
-        }
-    }
-    
-    private static final float ERROR = 1.0f / 512.0f;
-    
-    private static boolean isBetween(float y, float y1, float y2)
-    {
-        float min = Math.min(y1, y2) - ERROR;
-        float max = Math.max(y1, y2) + ERROR;
-        return y >= min && y <= max;
-    }
-    
-    private static boolean compareFloats(float a, float b)
-    {
-        return Math.abs(a - b) < ERROR;
-    }
-}

+ 0 - 57
src/me/hammerle/supersnuvi/util/CollisionObject.java

@@ -1,57 +0,0 @@
-package me.hammerle.supersnuvi.util;
-
-import static me.hammerle.supersnuvi.util.CollisionBox.createScaledTileBox;
-
-public abstract class CollisionObject 
-{
-    public final static CollisionObject NULL_BOX = new CollisionBox(0.0f, 0.0f, 0.0f, 0.0f);
-    public final static CollisionObject DEFAULT_TILE_BOX = createScaledTileBox(0.0f, 0.0f, 1.0f, 1.0f);
-    
-    public enum Type
-    {
-        LINE, BOX
-    }
-    
-    public abstract Type getType();
-    public abstract CollisionObject copy();
-    public abstract void save(); 
-    public abstract CollisionObject reset();
-    
-    public abstract float getWidth();
-    public abstract float getHeight();
-    
-    public abstract float getMinX();
-    public abstract float getMaxX();
-    public abstract float getMinY();
-    public abstract float getMaxY();
-   
-    public abstract CollisionObject expand(float x, float y);
-    
-    public final CollisionObject offset(float x, float y)
-    {
-        offsetX(x);
-        offsetY(y);
-        return this;
-    }
-    
-    public abstract CollisionObject offsetX(float x);
-    public abstract CollisionObject offsetY(float y);
-    
-    public abstract boolean isColliding(CollisionObject cb);
-    
-    public final boolean mayCollide(CollisionObject cb)
-    {
-        // box intersect test, even for lines, prevents failures
-        float minX1 = Math.min(cb.getMinX(), cb.getMaxX());
-        float minY1 = Math.min(cb.getMinY(), cb.getMaxY());
-        float maxX1 = Math.max(cb.getMinX(), cb.getMaxX());
-        float maxY1 = Math.max(cb.getMinY(), cb.getMaxY());
-        
-        float minX2 = Math.min(getMinX(), getMaxX());
-        float minY2 = Math.min(getMinY(), getMaxY());
-        float maxX2 = Math.max(getMinX(), getMaxX());
-        float maxY2 = Math.max(getMinY(), getMaxY());
-        
-        return maxX1 > minX2 && maxX2 > minX1 && maxY1 > minY2 && maxY2 > minY1;
-    }
-}

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

@@ -63,4 +63,73 @@ public class Utils
         
         return f;
     }
+    
+    public static boolean intersect(float x11, float y11, float x12, float y12, float x21, float y21, float x22, float y22)
+    {
+        if(compareFloats(x11, x12))
+        {
+            if(compareFloats(x21, x22))
+            {
+                return false;
+            }
+            else
+            {
+                if(!isBetween(x11, x21, x22))
+                {
+                    return false;
+                }
+                float k = (y21 - y22) / (x21 - x22);
+                float d = y22 - k * x22;
+                float y = d + x11 * k;
+                return isBetween(y, y11, y12) && isBetween(y, y21, y22);
+            }
+        }
+        else
+        {
+            if(compareFloats(x21, x22))
+            {
+                if(!isBetween(x21, x11, x12))
+                {
+                    return false;
+                }
+                float k = (y11 - y12) / (x11 - x12);
+                float d = y12 - k * x12;
+                float y = d + x21 * k;
+                return isBetween(y, y11, y12) && isBetween(y, y21, y22);
+            }
+            else
+            {
+                float k1 = (y11 - y12) / (x11 - x12);
+                float k2 = (y21 - y22) / (x21 - x22);
+                if(compareFloats(k1, k2))
+                {
+                    return false;
+                }
+                float d1 = y12 - k1 * x12;
+                float d2 = y22 - k2 * x22;
+                
+                float x = (d1 - d2) / (k2 - k1);
+                if(!isBetween(x, x11, x12) || !isBetween(x, x21, x22))
+                {
+                    return false;
+                }
+                float y = k1 * x + d1;
+                return isBetween(y, y11, y12) && isBetween(y, y21, y22);
+            }
+        }
+    }
+    
+    private static final float ERROR = 1.0f / 512.0f;
+    
+    private static boolean isBetween(float y, float y1, float y2)
+    {
+        float min = Math.min(y1, y2) - ERROR;
+        float max = Math.max(y1, y2) + ERROR;
+        return y >= min && y <= max;
+    }
+    
+    private static boolean compareFloats(float a, float b)
+    {
+        return Math.abs(a - b) < ERROR;
+    }
 }