| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 | package me.hammerle.supersnuvi.entity;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;import me.hammerle.supersnuvi.entity.components.ItemCollector;import me.hammerle.supersnuvi.entity.components.Movement;import me.hammerle.supersnuvi.tiles.Tile;import me.hammerle.supersnuvi.util.CollisionObject;import me.hammerle.supersnuvi.util.Face;import me.hammerle.supersnuvi.util.Utils;import me.hammerle.supersnuvi.gamelogic.Level;public final class Entity{    public static final float GRAVITY = 8.0f * Tile.SIZE_SCALE;    public static final float STEP = 0.0625f;    // this one is a little bit bigger to prevent wrong calculation    // while joing upwars    public static final float UP_STEP = STEP + 0.00390625f;        // the last position is used for interpolation during rendering    private float lastPosX;    private float lastPosY;    // the current position of the entity    private float posX;    private float posY;        // the collision box of the entity    private final CollisionObject box;        // the motion before the movement collision check    private float preMotionX;    private float preMotionY;    // the motion after the movement collision check    private float motionX;    private float motionY;        // a flag indicating that the entity is on the ground    private boolean onGround = true;        // entity components    protected Controller controller = Controller.NULL;    protected Health health = Health.NULL;    protected Energy energy = Energy.NULL;    protected Movement move = Movement.NULL;    protected ItemCollector itemCollector = ItemCollector.NULL;        // face    private Face face = Face.RIGHT;        private final String type;        protected Entity(String type, float x, float y, CollisionObject box)    {        lastPosX = x;        lastPosY = y;        posX = x;        posY = y;        // ensure the box cannot be modified from the outside        this.box = box.copy().offset(x, y);                preMotionX = 0.0f;        preMotionY = 0.0f;        motionX = 0.0f;        motionY = 0.0f;                this.type = type;    }        public String getType()    {        return type;    }        //--------------------------------------------------------------------------    // components    //--------------------------------------------------------------------------        public boolean isAnimated()    {        return controller.isAnimated();    }        public Controller getController()    {        return controller;    }        public Health getHealth()    {        return health;    }        public Energy getEnergy()    {        return energy;    }        public Movement getMovement()    {        return move;    }        public ItemCollector getItemCollector()    {        return itemCollector;    }        //--------------------------------------------------------------------------    // basic stuff    //--------------------------------------------------------------------------        public float getSquaredDistance(Entity e)    {        return Utils.getSquaredDistance(                posX + box.getWidth() * 0.5f, posY + box.getHeight() * 0.5f,                 e.posX + e.box.getWidth() * 0.5f, e.posY + e.box.getHeight() * 0.5f);    }        public CollisionObject getBox()    {        return box;    }        public float getX()    {        return posX;    }        public float getY()    {        return posY;    }        public void setPosition(float x, float y)    {        lastPosX = x;        lastPosY = y;        posX = x;        posY = y;        box.reset().offset(posX, posY);    }        public float getLastX()    {        return lastPosX;    }        public float getLastY()    {        return lastPosY;    }        public float getCenterX()    {        return posX + box.getWidth() * 0.5f;    }        public float getCenterY()    {        return posY + box.getHeight() * 0.5f;    }        public float getWidth()    {        return box.getWidth();    }        public float getHeight()    {        return box.getHeight();    }        public Face getFace()    {        if(motionX == 0.0f)        {            return face;        }        face = motionX < 0.0f ? Face.LEFT : Face.RIGHT;        return face;    }        public void updateFace()    {            }        public float getMotionX()    {        return motionX;    }        public void setMotionX(float motionX)    {        this.motionX = motionX;    }        public float getMotionY()    {        return motionY;    }        public void setMotionY(float motionY)    {        this.motionY = motionY;    }        public float getPreMotionX()    {        return preMotionX;    }        public float getPreMotionY()    {        return preMotionY;    }        public boolean isAt(float x, float y)    {        return Math.abs(x - posX) < STEP && Math.abs(y - posY) < STEP;    }        //--------------------------------------------------------------------------    // ticking    //--------------------------------------------------------------------------        public void tick(Level level)     {        lastPosX = posX;        lastPosY = posY;                controller.tick(level);        energy.tick();                preMotionX = motionX;        preMotionY = motionY;                if(move.hasGravity())        {            preMotionY += GRAVITY * move.getGravityFactor();        }        if(move.canMoveEverywhere())        {            motionX = preMotionX;            motionY = preMotionY;        }        else        {            CollisionObject testBox = box.copy().expand(preMotionX, preMotionY).expand(0.0f, -UP_STEP);            List<CollisionObject> boxes = level.getMovementBoxesAt(testBox, this);            if(!boxes.isEmpty())            {                float mx = preMotionX;                float my = preMotionY;                                testBox.reset();                                float oldX = testBox.getMinX();                float oldY = testBox.getMinY();                                while(mx != 0.0 || my != 0.0)                {                    testBox.save();                    if(mx < 0.0)                    {                        if(mx > -STEP)                        {                            testBox.offsetX(mx);                            mx = 0.0f;                        }                        else                        {                            testBox.offsetX(-STEP);                            mx += STEP;                        }                    }                    else if(mx > 0.0)                    {                        if(mx < STEP)                        {                            testBox.offsetX(mx);                            mx = 0.0f;                        }                        else                        {                            testBox.offsetX(STEP);                            mx -= STEP;                        }                    }                    for(CollisionObject cb : boxes)                    {                        if(cb.isColliding(testBox))                        {                            testBox.offsetY(-UP_STEP);                            for(CollisionObject cb2 : boxes)                            {                                if(cb2.isColliding(testBox))                                {                                    mx = 0.0f;                                    testBox.reset();                                    break;                                }                            }                            break;                        }                    }                                        testBox.save();                    if(my < 0.0)                    {                        if(my > -STEP)                        {                            testBox.offsetY(my);                            my = 0.0f;                        }                        else                        {                            testBox.offsetY(-STEP);                            my += STEP;                        }                    }                    else if(my > 0.0)                    {                        if(my < STEP)                        {                            testBox.offsetY(my);                            my = 0.0f;                        }                        else                        {                            testBox.offsetY(STEP);                            my -= STEP;                        }                    }                    for(CollisionObject cb : boxes)                    {                        if(cb.isColliding(testBox))                        {                            my = 0.0f;                            testBox.reset();                            break;                        }                    }                }                                motionX = testBox.getMinX() - oldX;                motionY = testBox.getMinY() - oldY;            }            else            {                motionX = preMotionX;                motionY = preMotionY;            }        }                posX += motionX;        posY += motionY;        box.reset().offset(posX, posY);                if(!move.canMoveEverywhere())        {            //onGround = preMotionY > 0.0f && motionY == 0;            onGround = !level.getMovementBoxesAt(box.copy().expand(0.0f, STEP * 2), this).isEmpty();            move.setInWater(false);            move.setFrictionFactor(0.6f);            // apply collision            CollisionObject cb = box.copy();            for(Face f : Face.values())            {                cb.reset();                cb.expand(f.getCollisionOffsetX(), f.getCollisionOffsetY());                level.getEntitiesCollidingWith(this, cb).forEach(ent -> this.controller.onCollideWithEntity(ent, f));                level.getCollisionBoxesAt(cb).forEach(loc ->                 {                    controller.onCollideWithTile(loc, f);                    loc.getTile().onEntityCollide(this, loc.getX(), loc.getY(), f.getOpposite(), level);                });            }            motionX *= move.getFrictionFactor();            if(Math.abs(motionX) < 0.3)            {                motionX = 0.0f;            }        }        health.tick();    }        public void renderTick(float lag)    {        controller.renderTick(lag);    }        //--------------------------------------------------------------------------    // gravity, friction    //--------------------------------------------------------------------------        public boolean isOnGround()    {        return onGround;    }   }
 |