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;
- }
- }
|