Parcourir la source

starting of class to component pattern (EntityController, EntityAnimator), basic AIs

Kajetan Johannes Hammerle il y a 6 ans
Parent
commit
ec952b354d

+ 50 - 24
src/me/hammerle/supersnuvi/entity/Entity.java

@@ -1,8 +1,9 @@
 package me.hammerle.supersnuvi.entity;
 
+import me.hammerle.supersnuvi.entity.animator.EntityAnimator;
+import me.hammerle.supersnuvi.entity.ai.EntityController;
 import java.util.LinkedList;
 import me.hammerle.supersnuvi.gamelogic.Level;
-import me.hammerle.supersnuvi.javafx.Image;
 import me.hammerle.supersnuvi.rendering.Game;
 import me.hammerle.supersnuvi.tiles.Location;
 import me.hammerle.supersnuvi.util.CollisionBox;
@@ -39,7 +40,9 @@ public class Entity
     private final double maxHealth;
     private double health;
     
-    private Image image;
+    private EntityAnimator animator;
+    
+    private EntityController controller;
     
     private final Level level;
     
@@ -59,8 +62,8 @@ public class Entity
         this.height = height;
         this.maxHealth = health;
         this.health = health;
-        
-        image = Utils.getColoredImage(0, 0, 0, 255, (int) width, (int) height);
+        this.animator = new EntityAnimator(this);
+        this.controller = new EntityController(this);
     }
 
     public Level getLevel()
@@ -68,12 +71,41 @@ public class Entity
         return level;
     }
     
+    //--------------------------------------------------------------------------
+    // utility
+    //--------------------------------------------------------------------------
+    
+    public final double squaredDistance(Entity other)
+    {
+        return (posX - other.posX) * (posX - other.posX) + (posY - other.posY) * (posY - other.posY);
+    }
+    
+    public final double signedDistanceX(Entity other)
+    {
+        if(posX < other.posX)
+        {
+            return Math.min(0.0, posX + width - other.posX);
+        }
+        return Math.max(0.0, posX - (other.posX + other.width));
+    }
+    
+    //--------------------------------------------------------------------------
+    // controller - either ai or player
+    //--------------------------------------------------------------------------
+    
+    public final void setController(EntityController controller)
+    {
+        this.controller = controller;
+    }
+    
     //--------------------------------------------------------------------------
     // ticking
     //--------------------------------------------------------------------------
     
-    public void tick() 
+    public final void tick() 
     {
+        controller.tick();
+        
         inWater = false;
         
         if(isAffectedByGravity())
@@ -104,9 +136,9 @@ public class Entity
         LinkedList<CollisionBox> list = level.getMovementBoxesAt(this, getBox());
         if(!list.isEmpty())
         {
-            System.out.println(getBox());
-            list.forEach(s -> System.out.println(s));
-            System.out.println("WELL");
+            //System.out.println(getBox());
+            //list.forEach(s -> System.out.println(s));
+            //System.out.println("WELL");
             posX = prevPosX;
             posY = prevPrevY;
         }
@@ -130,6 +162,8 @@ public class Entity
                 motionX = 0.0;
             }
         }
+        
+        animator.tick();
     }
     
     //--------------------------------------------------------------------------
@@ -187,11 +221,6 @@ public class Entity
         this.friction = friction;
     }
     
-    public boolean isRunning()
-    {
-        return false;
-    }
-    
     //--------------------------------------------------------------------------
     // collision stuff
     //--------------------------------------------------------------------------
@@ -517,12 +546,14 @@ public class Entity
         }
     }
     
-    public void onCollideWithTile(Location loc, Face face)
+    public final void onCollideWithTile(Location loc, Face face)
     {
+        controller.onCollideWithTile(loc, face);
     }
     
-    public void onCollideWithEntity(Entity ent, Face face)
+    public final void onCollideWithEntity(Entity ent, Face face)
     {
+        controller.onCollideWithEntity(ent, face);
     }
     
     //--------------------------------------------------------------------------
@@ -644,19 +675,14 @@ public class Entity
         return posY + height;
     }
     
-    public void setImage(Image image)
+    public final void setAnimator(EntityAnimator animator)
     {
-        this.image = image;
-    }
-    
-    public boolean drawImageFlipped()
-    {
-        return false;
+        this.animator = animator;
     }
     
-    public Image getImage()
+    public EntityAnimator getAnimator()
     {
-        return image;
+        return animator;
     }
     
     public double getRenderOffsetX()

+ 13 - 83
src/me/hammerle/supersnuvi/entity/Hero.java

@@ -1,13 +1,11 @@
 package me.hammerle.supersnuvi.entity;
 
+import me.hammerle.supersnuvi.entity.ai.HumanController;
+import me.hammerle.supersnuvi.entity.animator.DefaultAnimator;
 import me.hammerle.supersnuvi.gamelogic.Level;
 import me.hammerle.supersnuvi.gamelogic.StateRenderer;
-import me.hammerle.supersnuvi.javafx.Image;
-import me.hammerle.supersnuvi.javafx.KeyHandler;
-import me.hammerle.supersnuvi.util.SoundUtils;
-import me.hammerle.supersnuvi.util.Utils;
 
-public class Hero extends AnimatedEntity
+public class Hero extends Entity
 {
     private final double jumpPower;
     
@@ -17,30 +15,17 @@ public class Hero extends AnimatedEntity
         
         jumpPower = StateRenderer.CONFIG.getDouble("jump", 10);
                 
-        face = Utils.getImage("snuvi/snuvi");
-        super.setImage(face);
-        move = new Image[9];
-        move[0] = Utils.getImage("snuvi/snuvi_frame1");
-        move[1] = Utils.getImage("snuvi/snuvi_frame2");
-        move[2] = Utils.getImage("snuvi/snuvi_frame3");
-        move[3] = Utils.getImage("snuvi/snuvi_frame4");
-        move[4] = Utils.getImage("snuvi/snuvi_frame5");
-        move[5] = Utils.getImage("snuvi/snuvi_frame6");
-        move[6] = Utils.getImage("snuvi/snuvi_frame7");
-        move[7] = Utils.getImage("snuvi/snuvi_frame8");
-        move[8] = Utils.getImage("snuvi/snuvi_frame9");
+        setAnimator(new DefaultAnimator(this, "snuvi/snuvi", new String[] 
+                {
+                    "snuvi/snuvi_frame1", "snuvi/snuvi_frame2", "snuvi/snuvi_frame3",
+                    "snuvi/snuvi_frame4", "snuvi/snuvi_frame5", "snuvi/snuvi_frame6",
+                    "snuvi/snuvi_frame7", "snuvi/snuvi_frame8", "snuvi/snuvi_frame9"
+                }, new String[] 
+                {
+                    "snuvi/snuvi_jump"
+                }));
         
-        moveAir = new Image[1];
-        moveAir[0] = Utils.getImage("snuvi/snuvi_jump");
-        /*moveAir[0] = Utils.getImage("snuvi/snuvi_frame1");
-        moveAir[1] = Utils.getImage("snuvi/snuvi_frame2");
-        moveAir[2] = Utils.getImage("snuvi/snuvi_frame3");
-        moveAir[3] = Utils.getImage("snuvi/snuvi_frame4");
-        moveAir[4] = Utils.getImage("snuvi/snuvi_frame5");
-        moveAir[5] = Utils.getImage("snuvi/snuvi_frame6");
-        moveAir[6] = Utils.getImage("snuvi/snuvi_frame7");
-        moveAir[7] = Utils.getImage("snuvi/snuvi_frame8");
-        moveAir[8] = Utils.getImage("snuvi/snuvi_frame9");*/
+        setController(new HumanController(this));
     }
 
     @Override
@@ -49,61 +34,6 @@ public class Hero extends AnimatedEntity
         return jumpPower * getMaxSpeedModifier();
     }
 
-    @Override
-    public void tick() 
-    {
-        controlTick();
-        super.tick();
-    }
-
-    @Override
-    public boolean isRunning() 
-    {
-        return KeyHandler.RUN.isDown();
-    }
-    
-    public void controlTick() 
-    {
-        if(KeyHandler.JUMP.isDown() && jump())
-        {
-            SoundUtils.playSound(SoundUtils.Sound.JUMP);
-        }
-        
-        double speed = 3.0;
-        if(isRunning())
-        {
-            if((getLevel().getEnergy() / Level.MAX_ENERGY) > 0.25)
-            {
-                speed = 4.5;
-            }
-            if(isMoving())
-            {
-                getLevel().addEnergy(-0.3);
-            }
-        }
-        
-        if(KeyHandler.LEFT.isDown())
-        {
-            setMotionX(-speed * getMaxSpeedModifier());
-        }
-        else if(KeyHandler.RIGHT.isDown())
-        {
-            setMotionX(speed * getMaxSpeedModifier());
-        }
-        
-        if(isOnGround() && getPreviousMotionX() != 0)
-        {
-            if(isInWater())
-            {
-                SoundUtils.playSound(SoundUtils.Sound.WALK_WATER);
-            }
-            else
-            {
-                SoundUtils.playSound(SoundUtils.Sound.WALK);
-            }           
-        }
-    }
-
     @Override
     public double getRenderOffsetY()
     {

+ 32 - 0
src/me/hammerle/supersnuvi/entity/ai/EntityController.java

@@ -0,0 +1,32 @@
+package me.hammerle.supersnuvi.entity.ai;
+
+import me.hammerle.supersnuvi.entity.Entity;
+import me.hammerle.supersnuvi.tiles.Location;
+import me.hammerle.supersnuvi.util.Face;
+
+public class EntityController
+{
+    protected final Entity ent;
+    
+    public EntityController(Entity ent)
+    {
+        this.ent = ent;
+    }
+    
+    public void tick()
+    {
+    }
+    
+    public boolean isRunning()
+    {
+        return false;
+    }
+    
+    public void onCollideWithTile(Location loc, Face face)
+    {
+    }
+    
+    public void onCollideWithEntity(Entity ent, Face face)
+    {
+    }
+}

+ 51 - 0
src/me/hammerle/supersnuvi/entity/ai/FollowHeroController.java

@@ -0,0 +1,51 @@
+package me.hammerle.supersnuvi.entity.ai;
+
+import me.hammerle.supersnuvi.entity.Entity;
+import me.hammerle.supersnuvi.entity.Hero;
+import me.hammerle.supersnuvi.tiles.Location;
+import me.hammerle.supersnuvi.util.Face;
+
+public class FollowHeroController extends EntityController
+{
+    private final double motion;
+    
+    public FollowHeroController(Entity ent, double motion)
+    {
+        super(ent);
+        this.motion = motion;
+    }
+
+    @Override
+    public void tick() 
+    {
+        Hero hero = ent.getLevel().getHero();
+        if(hero.squaredDistance(ent) <= 102400)
+        {
+            double distance = ent.signedDistanceX(hero);
+            if(distance < 0)
+            {
+                ent.setMotionX(motion);
+            }
+            else if(distance > 0)
+            {
+                ent.setMotionX(-motion);
+            }
+        }
+    }
+
+    @Override
+    public void onCollideWithEntity(Entity ent, Face face) 
+    {
+    }
+
+    @Override
+    public void onCollideWithTile(Location loc, Face face) 
+    {
+        if((face == Face.LEFT || face == Face.RIGHT) && 
+                Math.abs(ent.getPreviousMotionX() - ent.getMotionX()) > 0.001 &&
+                Math.abs(ent.signedDistanceX(ent.getLevel().getHero())) > 0.001)
+        {
+            ent.jump();
+        }
+    }
+}

+ 64 - 0
src/me/hammerle/supersnuvi/entity/ai/HumanController.java

@@ -0,0 +1,64 @@
+package me.hammerle.supersnuvi.entity.ai;
+
+import me.hammerle.supersnuvi.entity.Entity;
+import me.hammerle.supersnuvi.entity.ai.EntityController;
+import me.hammerle.supersnuvi.gamelogic.Level;
+import me.hammerle.supersnuvi.javafx.KeyHandler;
+import me.hammerle.supersnuvi.util.SoundUtils;
+
+public class HumanController extends EntityController
+{
+    public HumanController(Entity ent) 
+    {
+        super(ent);
+    }
+    
+    @Override
+    public boolean isRunning() 
+    {
+        return KeyHandler.RUN.isDown();
+    }
+
+    @Override
+    public void tick() 
+    {
+        if(KeyHandler.JUMP.isDown() && ent.jump())
+        {
+            SoundUtils.playSound(SoundUtils.Sound.JUMP);
+        }
+        
+        double speed = 3.0;
+        if(isRunning())
+        {
+            if((ent.getLevel().getEnergy() / Level.MAX_ENERGY) > 0.25)
+            {
+                speed = 4.5;
+            }
+            if(ent.isMoving())
+            {
+                ent.getLevel().addEnergy(-0.3);
+            }
+        }
+        
+        if(KeyHandler.LEFT.isDown())
+        {
+            ent.setMotionX(-speed * ent.getMaxSpeedModifier());
+        }
+        else if(KeyHandler.RIGHT.isDown())
+        {
+            ent.setMotionX(speed * ent.getMaxSpeedModifier());
+        }
+        
+        if(ent.isOnGround() && ent.getPreviousMotionX() != 0)
+        {
+            if(ent.isInWater())
+            {
+                SoundUtils.playSound(SoundUtils.Sound.WALK_WATER);
+            }
+            else
+            {
+                SoundUtils.playSound(SoundUtils.Sound.WALK);
+            }           
+        }
+    }
+}

+ 46 - 0
src/me/hammerle/supersnuvi/entity/ai/WalkController.java

@@ -0,0 +1,46 @@
+package me.hammerle.supersnuvi.entity.ai;
+
+import me.hammerle.supersnuvi.entity.Entity;
+import me.hammerle.supersnuvi.tiles.Location;
+import me.hammerle.supersnuvi.util.Face;
+
+public class WalkController extends EntityController
+{
+    private double motion;
+    
+    public WalkController(Entity ent, double motion)
+    {
+        super(ent);
+        this.motion = motion;
+    }
+
+    @Override
+    public void tick() 
+    {
+        ent.setMotionX(motion);
+    }
+
+    @Override
+    public void onCollideWithEntity(Entity ent, Face face) 
+    {
+        switchDirection(face);
+    }
+
+    @Override
+    public void onCollideWithTile(Location loc, Face face) 
+    {
+        switchDirection(face);
+    }
+    
+    private void switchDirection(Face face)
+    {
+        if(face == Face.LEFT)
+        {
+            motion = -Math.abs(motion);
+        }
+        else if(face == Face.RIGHT)
+        {
+            motion = Math.abs(motion);
+        }
+    }
+}

+ 32 - 17
src/me/hammerle/supersnuvi/entity/AnimatedEntity.java → src/me/hammerle/supersnuvi/entity/animator/DefaultAnimator.java

@@ -1,24 +1,42 @@
-package me.hammerle.supersnuvi.entity;
+package me.hammerle.supersnuvi.entity.animator;
 
-import me.hammerle.supersnuvi.gamelogic.Level;
+import me.hammerle.supersnuvi.entity.Entity;
 import me.hammerle.supersnuvi.javafx.Image;
+import me.hammerle.supersnuvi.util.Utils;
 
-public class AnimatedEntity extends Entity
+public class DefaultAnimator extends EntityAnimator
 {
     private int counter;
     private int frame;
     
-    protected Image face;
-    protected Image[] move;
-    protected Image[] moveAir;
+    private Image currentFace;
+    
+    private final Image face;
+    private final Image[] move;
+    private final Image[] moveAir;
     private boolean flipped;
     
-    public AnimatedEntity(Level level, double x, double y, double width, double height, double health) 
+    public DefaultAnimator(Entity ent, String face, String[] move, String[] moveAir) 
     {
-        super(level, x, y, width, height, health);
+        super(ent);
         flipped = false;
         counter = 0;
-        frame = 0;   
+        frame = 0;  
+        
+        this.face = Utils.getImage(face);
+        this.currentFace = this.face;
+        
+        this.move = new Image[move.length];
+        for(int i = 0; i < move.length; i++)
+        {
+            this.move[i] = Utils.getImage(move[i]);
+        }
+        
+        this.moveAir = new Image[moveAir.length];
+        for(int i = 0; i < moveAir.length; i++)
+        {
+            this.moveAir[i] = Utils.getImage(moveAir[i]);
+        }
     }
 
     @Override
@@ -30,15 +48,12 @@ public class AnimatedEntity extends Entity
     @Override
     public void tick() 
     {
-        super.tick();
-        
         counter++;
         if(counter >= 5)
         {
             counter = 0;
             frame++;
         }
-        
         if(frame < 0)
         {
             frame = 0;
@@ -48,10 +63,10 @@ public class AnimatedEntity extends Entity
     @Override
     public Image getImage() 
     {
-        double motionX = getPreviousMotionX();
-        if(isOnGround())
+        double motionX = ent.getPreviousMotionX();
+        if(ent.isOnGround())
         {
-            setImage(face);
+            currentFace = face;
             if(motionX != 0)
             {
                 if(frame >= move.length)
@@ -68,7 +83,7 @@ public class AnimatedEntity extends Entity
         }
         else
         {
-            setImage(moveAir[0]);
+            currentFace = moveAir[0];
             if(motionX != 0)
             {
                 if(frame >= moveAir.length)
@@ -83,6 +98,6 @@ public class AnimatedEntity extends Entity
                 frame = 0;
             }
         }
-        return super.getImage();
+        return currentFace;
     }
 }

+ 28 - 0
src/me/hammerle/supersnuvi/entity/animator/EntityAnimator.java

@@ -0,0 +1,28 @@
+package me.hammerle.supersnuvi.entity.animator;
+
+import me.hammerle.supersnuvi.entity.Entity;
+import me.hammerle.supersnuvi.javafx.Image;
+
+public class EntityAnimator 
+{
+    protected final Entity ent;
+    
+    public EntityAnimator(Entity ent)
+    {
+        this.ent = ent;
+    }
+    
+    public void tick()
+    {
+    }
+    
+    public Image getImage()
+    {
+        return null;
+    }
+    
+    public boolean drawImageFlipped()
+    {
+        return false;
+    }
+}

+ 16 - 3
src/me/hammerle/supersnuvi/gamelogic/Level.java

@@ -7,7 +7,10 @@ import java.util.List;
 import java.util.TreeSet;
 import java.util.stream.Collectors;
 import me.hammerle.supersnuvi.entity.Entity;
+import me.hammerle.supersnuvi.entity.animator.EntityAnimator;
 import me.hammerle.supersnuvi.entity.Hero;
+import me.hammerle.supersnuvi.entity.ai.FollowHeroController;
+import me.hammerle.supersnuvi.entity.ai.WalkController;
 import me.hammerle.supersnuvi.tiles.BottledSoulTile;
 import me.hammerle.supersnuvi.tiles.Location;
 import me.hammerle.supersnuvi.tiles.StartTile;
@@ -86,6 +89,10 @@ public final class Level
         }
         
         resetLevel();
+        
+        //Hero test = new Hero(this, 150, 150);
+        //test.setController(new FollowHeroController(test, 1.5));
+        //entities.put(entityCounter++, test);
     }
     
     // -------------------------------------------------------------------------
@@ -235,13 +242,14 @@ public final class Level
             
             entities.values().forEach(en -> 
             {
-                if(en.drawImageFlipped())
+                EntityAnimator animator = en.getAnimator();
+                if(animator.drawImageFlipped())
                 {
-                    renderer.drawFlippedImage(en.getImage(), en.getRenderX() + en.getRenderOffsetX(), en.getRenderY() + en.getRenderOffsetY());
+                    renderer.drawFlippedImage(animator.getImage(), en.getRenderX() + en.getRenderOffsetX(), en.getRenderY() + en.getRenderOffsetY());
                 }
                 else
                 {
-                    renderer.drawImage(en.getImage(), en.getRenderX() + en.getRenderOffsetX(), en.getRenderY() + en.getRenderOffsetY());
+                    renderer.drawImage(animator.getImage(), en.getRenderX() + en.getRenderOffsetX(), en.getRenderY() + en.getRenderOffsetY());
                 }
             });
             
@@ -464,4 +472,9 @@ public final class Level
         }
         return boxes;
     }
+    
+    public Hero getHero()
+    {
+        return hero;
+    }
 }

+ 11 - 0
src/me/hammerle/supersnuvi/tiles/CrumblingStoneTile.java

@@ -28,6 +28,17 @@ public class CrumblingStoneTile extends Tile
         super.setMovementBox(CollisionBox.createScaledBox(0, 0.4, 1, 1));
     }
 
+    @Override
+    public CollisionBox getCollisionBox(int x, int y) 
+    {
+        int i = states.getOrDefault(getKey(x, y), 0) / 2;
+        if(i >= 39)
+        {
+            return CollisionBox.NULL_BOX;
+        }
+        return super.getCollisionBox(x, y);
+    }
+
     @Override
     public CollisionBox getMovementBox(int x, int y) 
     {

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

@@ -17,9 +17,9 @@ public class SlipperyTile extends BaseBoxTile
         {
             if(ent.getPreviousMotionY() != -Entity.GRAVITY && Math.abs(ent.getMotionX()) <= 0.05)
             {
-                ent.setMotionX(ent.drawImageFlipped() ? -2.5 : 2.5);
+                ent.setMotionX(ent.getAnimator().drawImageFlipped() ? -2.5 : 2.5);
             }
-            ent.setFriction(0.1);
+            ent.setFriction(0.08);
         }
     }
 }