123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- package me.hammerle.supersnuvi.entity;
- import java.util.List;
- import me.hammerle.supersnuvi.entity.components.animator.Renderer;
- 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.gamelogic.Level;
- import me.hammerle.supersnuvi.util.CollisionBox;
- import me.hammerle.supersnuvi.util.Face;
- import me.hammerle.supersnuvi.util.Utils;
- public final class Entity
- {
- public static float GRAVITY = 8.0f;
- public static float STEP = 0.0625f;
-
- // 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 CollisionBox 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 = false;
-
- // the level of the entity
- private final Level level;
-
- // entity components
- protected Renderer renderer;
- protected Controller controller;
- protected Health health;
- protected Energy energy;
- protected Movement move;
- protected ItemCollector itemCollector;
-
- protected Entity(Level level, float x, float y, CollisionBox 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.level = level;
-
- // components
- this.renderer = Renderer.NULL;
- this.controller = Controller.NULL;
- this.health = Health.NULL;
- this.energy = Energy.NULL;
- this.move = Movement.NULL;
- this.itemCollector = ItemCollector.NULL;
- }
-
- public Level getLevel()
- {
- return level;
- }
-
- //--------------------------------------------------------------------------
- // components
- //--------------------------------------------------------------------------
-
- public boolean isAnimated()
- {
- return renderer.isAnimated();
- }
-
- 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 float getX()
- {
- return posX;
- }
-
- public float getY()
- {
- return 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 Face getFace()
- {
- return preMotionX > 0.0f ? Face.RIGHT : Face.LEFT;
- }
-
- 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;
- }
-
- //--------------------------------------------------------------------------
- // ticking
- //--------------------------------------------------------------------------
-
- public void tick()
- {
- lastPosX = posX;
- lastPosY = posY;
-
- controller.tick();
- health.tick();
- energy.tick();
-
- preMotionX = motionX;
- preMotionY = motionY;
-
- if(move.hasGravity())
- {
- preMotionY += GRAVITY * move.getGravityFactor();
- }
- if(move.canMoveEverywhere())
- {
- motionX = preMotionX;
- motionY = preMotionY;
- }
- else
- {
- CollisionBox testBox = box.copy().expand(preMotionX, preMotionY);
- List<CollisionBox> boxes = level.getMovementBoxesAt(testBox);
- 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(CollisionBox cb : boxes)
- {
- if(cb.isColliding(testBox))
- {
- mx = 0.0f;
- testBox.reset();
- 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(CollisionBox 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);
-
- onGround = preMotionY > 0.0f && motionY == 0;
-
- move.setInWater(false);
- move.setFrictionFactor(0.7f);
- // apply collision
- CollisionBox cb = box.copy();
- for(Face f : Face.values())
- {
- cb.reset();
- cb.expand(f.getCollisionOffsetX(), f.getCollisionOffsetY());
- level.getEntitiesCollidingWith(this, box).forEach(ent -> ent.controller.onCollideWithEntity(ent, f));
- level.getCollisionBoxesAt(cb).forEach(loc ->
- {
- controller.onCollideWithTile(loc, f);
- loc.getTile().onEntityCollide(this, loc.getX(), loc.getY(), f.getOpposite());
- });
- }
- }
-
- public void renderTick(float lag)
- {
- renderer.renderTick(lag);
- }
-
- //--------------------------------------------------------------------------
- // gravity, friction
- //--------------------------------------------------------------------------
-
- public boolean isOnGround()
- {
- return onGround;
- }
- }
|