Преглед изворни кода

textures for "?"-, "!"-, and "Empty"-Tile; added head hit once tile; refactoring; texture for platforms with variable width; scriptable platforms without physics; snuvi script commands: platform commands, level.getName, level.finish, entity.remove

Kajetan Johannes Hammerle пре 6 година
родитељ
комит
95e5b90a01

+ 21 - 4
levels/00-Tech_Demo.snuvi

@@ -2,6 +2,8 @@ event.load("level_reset");
 event.load("tile_interact");
 event.load("tile_interact");
 event.load("tile_hit");
 event.load("tile_hit");
 
 
+sgoto(200, @test);
+
 @main
 @main
 wait();
 wait();
 
 
@@ -20,6 +22,13 @@ elseif(event == "tile_hit")
 
 
 goto(@main);
 goto(@main);
 
 
+
+@test
+//entity.remove($platform);
+//level.finish();
+goto(@main);
+
+
 function onLevelReset()
 function onLevelReset()
 {
 {
     hero = entity.getHero();
     hero = entity.getHero();
@@ -34,12 +43,20 @@ function onLevelReset()
     entity.teleport(hero, x, y);
     entity.teleport(hero, x, y);
 
 
     index = level.getBackgroundIndex();
     index = level.getBackgroundIndex();
-    level.setTile(index, 0, 12, 70);
+    
+    level.setTile(index, 0, 12, 72);
+    level.setTile(index, 2, 12, 72);
+    level.setTile(index, 10, 8, 72);
+    
     level.setTile(index, 4, 12, -1);
     level.setTile(index, 4, 12, -1);
-    level.setTile(index, 2, 12, 70);
-    level.setTile(index, 1, 9, 71);
+    level.setTile(index, 4, 7, -1);
+    
+    level.setTile(index, 1, 9, 70);
     level.setTile(index, 4, 8, 71);
     level.setTile(index, 4, 8, 71);
-    level.setTile(index, 10, 8, 70);
+    
+    $platform = platform.spawn(tile.toLevelCoord(3), tile.toLevelCoord(3), 5);
+    platform.addmove($platform, tile.toLevelCoord(6), tile.toLevelCoord(9), 1, 2, 50);
+    platform.addmove($platform, tile.toLevelCoord(3), tile.toLevelCoord(3), 1, 2, 50);
 }
 }
 
 
 function onInteract(x, y)
 function onInteract(x, y)

BIN
resources/platform.png


BIN
resources/platform.xcf


BIN
resources/tiles.png


BIN
resources/tiles.xcf


+ 34 - 5
src/me/hammerle/supersnuvi/Game.java

@@ -11,6 +11,7 @@ import me.hammerle.snuviengine.api.Shader;
 import me.hammerle.snuviscript.code.SnuviParser;
 import me.hammerle.snuviscript.code.SnuviParser;
 import me.hammerle.supersnuvi.entity.Entity;
 import me.hammerle.supersnuvi.entity.Entity;
 import me.hammerle.supersnuvi.entity.EntityBuilder;
 import me.hammerle.supersnuvi.entity.EntityBuilder;
+import me.hammerle.supersnuvi.entity.components.ai.PlatformController;
 import me.hammerle.supersnuvi.gamelogic.Level;
 import me.hammerle.supersnuvi.gamelogic.Level;
 import me.hammerle.supersnuvi.gamelogic.StartScreenLevel;
 import me.hammerle.supersnuvi.gamelogic.StartScreenLevel;
 import me.hammerle.supersnuvi.savegame.SimpleConfig;
 import me.hammerle.supersnuvi.savegame.SimpleConfig;
@@ -41,7 +42,7 @@ public class Game extends Engine
     public static final NullTile FALLBACK_TILE = new NullTile();
     public static final NullTile FALLBACK_TILE = new NullTile();
     
     
     // tiles
     // tiles
-    private final Tile[] registeredTiles = new Tile[72];
+    private final Tile[] registeredTiles = new Tile[73];
     
     
     // levels
     // levels
     private Level currentLevel = null;
     private Level currentLevel = null;
@@ -625,10 +626,12 @@ public class Game extends Engine
             }
             }
         }
         }
         
         
-        // test interact tile
-        registeredTiles[70] = new InteractTile(0.5625f, 0.0f, 0.625f, 0.0625f);
-        // test hit tile
-        registeredTiles[71] = new HeadHitBlock(0.5625f, 0.0f, 0.625f, 0.0625f);
+        // !-Tile
+        registeredTiles[70] = new HeadHitTile(0.5625f, 0.0f, 0.625f, 0.0625f);
+        // ?-Tile
+        registeredTiles[71] = new HeadHitOnceTile(0.625f, 0.0f, 0.6875f, 0.0625f, 0.6875f, 0.0f, 0.75f, 0.0625f);
+        // button
+        registeredTiles[72] = new InteractTile(0.75f, 0.0f, 0.8125f, 0.0625f);
     }
     }
     
     
     public Tile getTile(int id)
     public Tile getTile(int id)
@@ -714,6 +717,7 @@ public class Game extends Engine
     
     
     private void addSnuviCommands()
     private void addSnuviCommands()
     {
     {
+        snuviParser.registerFunction("level.getname", (sc, in) -> currentLevel.getName());
         snuviParser.registerFunction("level.getwidth", (sc, in) -> (double) currentLevel.getWidth());
         snuviParser.registerFunction("level.getwidth", (sc, in) -> (double) currentLevel.getWidth());
         snuviParser.registerFunction("level.getheight", (sc, in) -> (double) currentLevel.getHeight());
         snuviParser.registerFunction("level.getheight", (sc, in) -> (double) currentLevel.getHeight());
         snuviParser.registerFunction("level.getlayers", (sc, in) -> (double) currentLevel.getData().getLayers());
         snuviParser.registerFunction("level.getlayers", (sc, in) -> (double) currentLevel.getData().getLayers());
@@ -735,6 +739,11 @@ public class Game extends Engine
             currentLevel.addMessage(in[0].getString(sc));
             currentLevel.addMessage(in[0].getString(sc));
             return Void.TYPE;
             return Void.TYPE;
         });
         });
+        snuviParser.registerFunction("level.finish", (sc, in) -> 
+        {
+            currentLevel.finishLevel();
+            return Void.TYPE;
+        });
         
         
         snuviParser.registerFunction("tile.totilecoord", (sc, in) -> (double) Utils.toBlock(in[0].getFloat(sc)));
         snuviParser.registerFunction("tile.totilecoord", (sc, in) -> (double) Utils.toBlock(in[0].getFloat(sc)));
         snuviParser.registerFunction("tile.tolevelcoord", (sc, in) -> (double) Utils.toCoord(in[0].getInt(sc)));
         snuviParser.registerFunction("tile.tolevelcoord", (sc, in) -> (double) Utils.toCoord(in[0].getInt(sc)));
@@ -785,5 +794,25 @@ public class Game extends Engine
             }
             }
             return ent;
             return ent;
         });
         });
+        snuviParser.registerFunction("entity.remove", (sc, in) -> 
+        {
+            Entity ent = (Entity) in[0].get(sc);
+            // move entity out of world so it is removed
+            ent.setPosition(0.0f, Float.MAX_VALUE * 0.5f);
+            return Void.TYPE;
+        });
+        
+        snuviParser.registerFunction("platform.spawn", (sc, in) -> 
+        {
+            Entity ent = EntityBuilder.buildPlatform(currentLevel, in[0].getInt(sc), in[1].getFloat(sc), in[2].getInt(sc));
+            currentLevel.spawnEntity(ent);
+            return ent;
+        });
+        snuviParser.registerFunction("platform.addmove", (sc, in) -> 
+        {
+            PlatformController controller = (PlatformController) ((Entity) in[0].get(sc)).getController();
+            controller.addMoveData(in[1].getFloat(sc), in[2].getFloat(sc), in[3].getFloat(sc), in[4].getFloat(sc), in[5].getInt(sc));
+            return Void.TYPE;
+        });
     }
     }
 }
 }

+ 20 - 12
src/me/hammerle/supersnuvi/entity/Entity.java

@@ -43,11 +43,11 @@ public final class Entity
     private final ILevel level;
     private final ILevel level;
     
     
     // entity components
     // entity components
-    protected Controller controller;
-    protected Health health;
-    protected Energy energy;
-    protected Movement move;
-    protected ItemCollector itemCollector;
+    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
     // face
     private Face face = Face.RIGHT;
     private Face face = Face.RIGHT;
@@ -68,13 +68,6 @@ public final class Entity
         motionY = 0.0f;
         motionY = 0.0f;
         
         
         this.level = level;
         this.level = level;
-        
-        // components
-        this.controller = Controller.NULL;
-        this.health = Health.NULL;
-        this.energy = Energy.NULL;
-        this.move =  Movement.NULL;
-        this.itemCollector =  ItemCollector.NULL;
     }
     }
     
     
     public ILevel getLevel()
     public ILevel getLevel()
@@ -91,6 +84,11 @@ public final class Entity
         return controller.isAnimated();
         return controller.isAnimated();
     }
     }
     
     
+    public Controller getController()
+    {
+        return controller;
+    }
+    
     public Health getHealth()
     public Health getHealth()
     {
     {
         return health;
         return health;
@@ -166,6 +164,11 @@ public final class Entity
         return posY + box.getHeight() * 0.5f;
         return posY + box.getHeight() * 0.5f;
     }
     }
     
     
+    public float getWidth()
+    {
+        return box.getWidth();
+    }
+    
     public float getHeight()
     public float getHeight()
     {
     {
         return box.getHeight();
         return box.getHeight();
@@ -216,6 +219,11 @@ public final class Entity
         return preMotionY;
         return preMotionY;
     }
     }
     
     
+    public boolean isAt(float x, float y)
+    {
+        return Math.abs(x - posX) < STEP && Math.abs(y - posY) < STEP;
+    }
+    
     //--------------------------------------------------------------------------
     //--------------------------------------------------------------------------
     // ticking
     // ticking
     //--------------------------------------------------------------------------
     //--------------------------------------------------------------------------

+ 9 - 0
src/me/hammerle/supersnuvi/entity/EntityBuilder.java

@@ -11,6 +11,7 @@ import me.hammerle.supersnuvi.tiles.Tile;
 import me.hammerle.supersnuvi.entity.components.IDeath;
 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.NoHealth;
 import me.hammerle.supersnuvi.entity.components.NoHealth;
+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.CollisionBox;
@@ -59,6 +60,14 @@ public final class EntityBuilder
         return stone;
         return stone;
     }
     }
     
     
+    public static Entity buildPlatform(ILevel level, float x, float y, int tx)
+    {
+        Entity platform = new Entity(level, x, y, new CollisionBox(1.0f, 0.0f, 1.0f + Tile.SIZE * tx, 25.0f));
+        platform.controller = new PlatformController(platform);
+        platform.move = new StoneMovement(platform);
+        return platform;
+    }
+    
     public static Entity fromId(int id, ILevel level, float x, float y)
     public static Entity fromId(int id, ILevel level, float x, float y)
     {
     {
         switch(id)
         switch(id)

+ 120 - 0
src/me/hammerle/supersnuvi/entity/components/ai/PlatformController.java

@@ -0,0 +1,120 @@
+package me.hammerle.supersnuvi.entity.components.ai;
+
+import java.util.ArrayList;
+import me.hammerle.snuviengine.api.Shader;
+import me.hammerle.snuviengine.api.Texture;
+import me.hammerle.supersnuvi.entity.Entity;
+import me.hammerle.supersnuvi.tiles.Tile;
+import me.hammerle.supersnuvi.util.Face;
+import me.hammerle.supersnuvi.util.Utils;
+
+public class PlatformController extends Controller
+{
+    private final static Texture TEXTURE = new Texture("resources/platform.png");
+    
+    private static class MoveData
+    {
+        private final float x;
+        private final float y;
+        private final float speedX;
+        private final float speedY;
+        private final int waitTicks;
+        
+        public MoveData(float x, float y, float speedX, float speedY, int waitTicks)
+        {
+            this.x = x;
+            this.y = y;
+            this.speedX = Math.abs(speedX);
+            this.speedY = Math.abs(speedY);
+            this.waitTicks = waitTicks;
+        }
+    }
+    
+    private final ArrayList<MoveData> dataList = new ArrayList<>();
+    private int moveIndex = 0;
+    private int waitTicks = 0;
+
+    public PlatformController(Entity ent) 
+    {
+        super(ent);
+    }
+  
+    @Override
+    public boolean isAnimated()
+    {
+        return true;
+    }
+    
+    public void addMoveData(float x, float y, float speedX, float speedY, int waitTicks)
+    {
+        dataList.add(new MoveData(x, y, speedX, speedY, waitTicks));
+    }
+    
+    public void clearMoveData()
+    {
+        dataList.clear();
+    }
+    
+    private float clamp(float f, float min, float max)
+    {
+        if(f < min)
+        {
+            return min;
+        }
+        else if(f > max)
+        {
+            return max;
+        }
+        return f;
+    }
+    
+    @Override
+    public void tick() 
+    {
+        if(dataList.isEmpty())
+        {
+            return;
+        }
+        
+        MoveData data = dataList.get(moveIndex);
+        if(ent.isAt(data.x, data.y))
+        {
+            ent.setMotionX(0.0f);
+            ent.setMotionY(0.0f);
+            
+            waitTicks++;
+            if(waitTicks >= data.waitTicks)
+            {
+                waitTicks = 0;
+                moveIndex = (moveIndex + 1) % dataList.size();
+            }
+        }
+        else
+        {
+            float motionX = clamp(data.x - ent.getX(), -data.speedX, data.speedX);
+            float motionY = clamp(data.y - ent.getY(), -data.speedY, data.speedY);
+            ent.setMotionX(motionX);
+            ent.setMotionY(motionY);
+        }
+    }
+
+    @Override
+    public void renderTick(float lag)
+    {
+        TEXTURE.bind();
+        float x = Utils.interpolate(ent.getLastX(), ent.getX(), lag);
+        float y = Utils.interpolate(ent.getLastY(), ent.getY(), lag);
+        
+        int mid = (int) Math.ceil((ent.getWidth() / Tile.SIZE) - 2);
+        float endY = y + ent.getHeight();
+        
+        Shader.getTextureRenderer().drawRectangle(x, y, x + Tile.SIZE, endY, 0.0f, 0.25f, 0.25f, 0.4453125f);
+        x += Tile.SIZE;
+        for(int i = 0; i < mid; i++)
+        {
+            Shader.getTextureRenderer().drawRectangle(x, y, x + Tile.SIZE, endY, 0.25f, 0.25f, 0.5f, 0.4453125f);
+            x += Tile.SIZE;
+        }
+        Shader.getTextureRenderer().drawRectangle(x, y, x + Tile.SIZE, endY, 0.5f, 0.25f, 0.75f, 0.4453125f);
+    }
+}

+ 2 - 2
src/me/hammerle/supersnuvi/gamelogic/Level.java

@@ -472,8 +472,8 @@ public final class Level implements ILevel
                         float minY = y * Tile.SIZE + t.getOffsetY();
                         float minY = y * Tile.SIZE + t.getOffsetY();
                         tr.addRectangle(minX, minY, 
                         tr.addRectangle(minX, minY, 
                                 minX + t.getWidth(), minY + t.getHeight(), 
                                 minX + t.getWidth(), minY + t.getHeight(), 
-                                t.getTextureMinX() + ERROR, t.getTextureMinY() + ERROR,
-                                t.getTextureMaxX() - ERROR, t.getTextureMaxY() - ERROR);
+                                t.getTextureMinX(x, y, this) + ERROR, t.getTextureMinY(x, y, this) + ERROR,
+                                t.getTextureMaxX(x, y, this) - ERROR, t.getTextureMaxY(x, y, this) - ERROR);
                     }
                     }
                 }
                 }
             }
             }

+ 2 - 2
src/me/hammerle/supersnuvi/gamelogic/StartScreenLevel.java

@@ -500,8 +500,8 @@ public final class StartScreenLevel implements ILevel
                         float minY = y * Tile.SIZE + t.getOffsetY();
                         float minY = y * Tile.SIZE + t.getOffsetY();
                         tr.addRectangle(minX, minY, 
                         tr.addRectangle(minX, minY, 
                                 minX + t.getWidth(), minY + t.getHeight(), 
                                 minX + t.getWidth(), minY + t.getHeight(), 
-                                t.getTextureMinX() + Level.ERROR, t.getTextureMinY() + Level.ERROR,
-                                t.getTextureMaxX() - Level.ERROR, t.getTextureMaxY() - Level.ERROR);
+                                t.getTextureMinX(x, y, this) + Level.ERROR, t.getTextureMinY(x, y, this) + Level.ERROR,
+                                t.getTextureMaxX(x, y, this) - Level.ERROR, t.getTextureMaxY(x, y, this) - Level.ERROR);
                     }
                     }
                 }
                 }
             }
             }

+ 6 - 4
src/me/hammerle/supersnuvi/tiles/BaseTile.java

@@ -1,5 +1,7 @@
 package me.hammerle.supersnuvi.tiles;
 package me.hammerle.supersnuvi.tiles;
 
 
+import me.hammerle.supersnuvi.gamelogic.ILevel;
+
 public class BaseTile extends Tile
 public class BaseTile extends Tile
 {
 {
     private final float tMinX;
     private final float tMinX;
@@ -16,25 +18,25 @@ public class BaseTile extends Tile
     }
     }
     
     
     @Override
     @Override
-    public float getTextureMinX()
+    public float getTextureMinX(int x, int y, ILevel l)
     {
     {
         return tMinX;
         return tMinX;
     }
     }
     
     
     @Override
     @Override
-    public float getTextureMaxX()
+    public float getTextureMaxX(int x, int y, ILevel l)
     {
     {
         return tMaxX;
         return tMaxX;
     }
     }
     
     
     @Override
     @Override
-    public float getTextureMinY()
+    public float getTextureMinY(int x, int y, ILevel l)
     {
     {
         return tMinY;
         return tMinY;
     }
     }
     
     
     @Override
     @Override
-    public float getTextureMaxY()
+    public float getTextureMaxY(int x, int y, ILevel l)
     {
     {
         return tMaxY;
         return tMaxY;
     }
     }

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

@@ -27,7 +27,7 @@ public class BottledSoulTile extends BaseTile
         {
         {
             if(states.add(x, y, l))
             if(states.add(x, y, l))
             {
             {
-                ent.getLevel().updateTile(x, y);
+                l.updateTile(x, y);
                 if(ent.getItemCollector().isHero())
                 if(ent.getItemCollector().isHero())
                 {
                 {
                     SoundUtils.playSound(SoundUtils.Sound.COLLECT);
                     SoundUtils.playSound(SoundUtils.Sound.COLLECT);

+ 79 - 0
src/me/hammerle/supersnuvi/tiles/HeadHitOnceTile.java

@@ -0,0 +1,79 @@
+package me.hammerle.supersnuvi.tiles;
+
+import me.hammerle.supersnuvi.entity.Entity;
+import me.hammerle.supersnuvi.gamelogic.ILevel;
+import me.hammerle.supersnuvi.util.BlockDataStorage;
+import me.hammerle.supersnuvi.util.Face;
+
+public class HeadHitOnceTile extends BaseBoxTile
+{
+    private final BlockDataStorage states = new BlockDataStorage();
+    
+    private final float tMinX2;
+    private final float tMaxX2;
+    private final float tMinY2;
+    private final float tMaxY2;
+    
+    public HeadHitOnceTile(float tMinX, float tMinY, float tMaxX, float tMaxY, float tMinX2, float tMinY2, float tMaxX2, float tMaxY2)
+    {
+        super(tMinX, tMinY, tMaxX, tMaxY);
+        this.tMinX2 = tMinX2;
+        this.tMaxX2 = tMaxX2;
+        this.tMinY2 = tMinY2;
+        this.tMaxY2 = tMaxY2;
+    }
+
+    @Override
+    public float getTextureMinX(int x, int y, ILevel l)
+    {
+        return states.contains(x, y, l) ? tMinX2 : super.getTextureMinX(x, y, l);
+    }
+
+    @Override
+    public float getTextureMinY(int x, int y, ILevel l)
+    {
+        return states.contains(x, y, l) ? tMinY2 : super.getTextureMinY(x, y, l);
+    }
+
+    @Override
+    public float getTextureMaxX(int x, int y, ILevel l)
+    {
+        return states.contains(x, y, l) ? tMaxX2 : super.getTextureMaxX(x, y, l);
+    }
+
+    @Override
+    public float getTextureMaxY(int x, int y, ILevel l)
+    {
+        return states.contains(x, y, l) ? tMaxY2 : super.getTextureMaxY(x, y, l); 
+    }
+
+    @Override
+    public void onEntityCollide(Entity ent, int x, int y, Face face, ILevel l)
+    {
+        if(face == Face.DOWN && ent.getMotionY() < 0 && states.add(x, y, l))
+        {
+            l.updateTile(x, y);
+            l.callEvent("tile_hit", (sc) -> 
+            {
+                sc.setVar("tile_x", (double) x);
+                sc.setVar("tile_y", (double) y);
+                sc.setVar("entity", ent);
+            }, (sc) -> 
+            {
+                
+            });
+        }
+    }
+    
+    @Override
+    public void reset(ILevel l) 
+    {
+        states.clear(l);
+    } 
+    
+    @Override
+    public void reset(int x, int y, ILevel l)
+    {
+        states.clear(x, y, l);
+    }
+}

+ 2 - 2
src/me/hammerle/supersnuvi/tiles/HeadHitBlock.java → src/me/hammerle/supersnuvi/tiles/HeadHitTile.java

@@ -4,9 +4,9 @@ import me.hammerle.supersnuvi.entity.Entity;
 import me.hammerle.supersnuvi.gamelogic.ILevel;
 import me.hammerle.supersnuvi.gamelogic.ILevel;
 import me.hammerle.supersnuvi.util.Face;
 import me.hammerle.supersnuvi.util.Face;
 
 
-public class HeadHitBlock extends BaseBoxTile
+public class HeadHitTile extends BaseBoxTile
 {
 {
-    public HeadHitBlock(float tMinX, float tMinY, float tMaxX, float tMaxY)
+    public HeadHitTile(float tMinX, float tMinY, float tMaxX, float tMaxY)
     {
     {
         super(tMinX, tMinY, tMaxX, tMaxY);
         super(tMinX, tMinY, tMaxX, tMaxY);
     }
     }

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

@@ -110,22 +110,22 @@ public abstract class Tile
         return 0;
         return 0;
     }
     }
     
     
-    public float getTextureMinX()
+    public float getTextureMinX(int x, int y, ILevel l)
     {
     {
         return 0.0f;
         return 0.0f;
     }
     }
     
     
-    public float getTextureMaxX()
+    public float getTextureMaxX(int x, int y, ILevel l)
     {
     {
         return 0.0625f;
         return 0.0625f;
     }
     }
     
     
-    public float getTextureMinY()
+    public float getTextureMinY(int x, int y, ILevel l)
     {
     {
         return 0.0f;
         return 0.0f;
     }
     }
     
     
-    public float getTextureMaxY()
+    public float getTextureMaxY(int x, int y, ILevel l)
     {
     {
         return 0.0625f;
         return 0.0625f;
     }
     }

+ 9 - 4
src/me/hammerle/supersnuvi/util/BlockDataStorage.java

@@ -8,9 +8,9 @@ public class BlockDataStorage
 {
 {
     private static class Data
     private static class Data
     {
     {
-        private final int x;
-        private final int y;
-        private final ILevel level;
+        private int x;
+        private int y;
+        private ILevel level;
         
         
         private Data(int x, int y, ILevel level)
         private Data(int x, int y, ILevel level)
         {
         {
@@ -57,6 +57,8 @@ public class BlockDataStorage
         }
         }
     }
     }
     
     
+    private final Data containCache = new Data(0, 0, null);
+    
     private final HashSet<Data> data = new HashSet<>();
     private final HashSet<Data> data = new HashSet<>();
     
     
     public BlockDataStorage()
     public BlockDataStorage()
@@ -71,7 +73,10 @@ public class BlockDataStorage
     
     
     public boolean contains(int x, int y, ILevel level)
     public boolean contains(int x, int y, ILevel level)
     {
     {
-        return data.contains(new Data(x, y, level));
+        containCache.x = x;
+        containCache.y = y;
+        containCache.level = level;
+        return data.contains(containCache);
     }
     }
     
     
     public void clear(ILevel level)
     public void clear(ILevel level)