Entity.java 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. package me.hammerle.supersnuvi.entity;
  2. import java.util.List;
  3. import me.hammerle.supersnuvi.entity.components.ai.Controller;
  4. import me.hammerle.supersnuvi.entity.components.Energy;
  5. import me.hammerle.supersnuvi.entity.components.Health;
  6. import me.hammerle.supersnuvi.entity.components.ItemCollector;
  7. import me.hammerle.supersnuvi.entity.components.Movement;
  8. import me.hammerle.supersnuvi.gamelogic.Level;
  9. import me.hammerle.supersnuvi.util.CollisionObject;
  10. import me.hammerle.supersnuvi.util.Face;
  11. import me.hammerle.supersnuvi.util.Utils;
  12. public final class Entity
  13. {
  14. public static final float GRAVITY = 8.0f;
  15. public static final float STEP = 0.0625f;
  16. // this one is a little bit bigger to prevent wrong calculation
  17. // while joing upwars
  18. public static final float UP_STEP = STEP + 0.00390625f;
  19. // the last position is used for interpolation during rendering
  20. private float lastPosX;
  21. private float lastPosY;
  22. // the current position of the entity
  23. private float posX;
  24. private float posY;
  25. // the collision box of the entity
  26. private final CollisionObject box;
  27. // the motion before the movement collision check
  28. private float preMotionX;
  29. private float preMotionY;
  30. // the motion after the movement collision check
  31. private float motionX;
  32. private float motionY;
  33. // a flag indicating that the entity is on the ground
  34. private boolean onGround = false;
  35. // the level of the entity
  36. private final Level level;
  37. // entity components
  38. protected Controller controller;
  39. protected Health health;
  40. protected Energy energy;
  41. protected Movement move;
  42. protected ItemCollector itemCollector;
  43. // face
  44. private Face face = Face.RIGHT;
  45. protected Entity(Level level, float x, float y, CollisionObject box)
  46. {
  47. lastPosX = x;
  48. lastPosY = y;
  49. posX = x;
  50. posY = y;
  51. // ensure the box cannot be modified from the outside
  52. this.box = box.copy().offset(x, y);
  53. preMotionX = 0.0f;
  54. preMotionY = 0.0f;
  55. motionX = 0.0f;
  56. motionY = 0.0f;
  57. this.level = level;
  58. // components
  59. this.controller = Controller.NULL;
  60. this.health = Health.NULL;
  61. this.energy = Energy.NULL;
  62. this.move = Movement.NULL;
  63. this.itemCollector = ItemCollector.NULL;
  64. }
  65. public Level getLevel()
  66. {
  67. return level;
  68. }
  69. //--------------------------------------------------------------------------
  70. // components
  71. //--------------------------------------------------------------------------
  72. public boolean isAnimated()
  73. {
  74. return controller.isAnimated();
  75. }
  76. public Health getHealth()
  77. {
  78. return health;
  79. }
  80. public Energy getEnergy()
  81. {
  82. return energy;
  83. }
  84. public Movement getMovement()
  85. {
  86. return move;
  87. }
  88. public ItemCollector getItemCollector()
  89. {
  90. return itemCollector;
  91. }
  92. //--------------------------------------------------------------------------
  93. // basic stuff
  94. //--------------------------------------------------------------------------
  95. public float getSquaredDistance(Entity e)
  96. {
  97. return Utils.getSquaredDistance(
  98. posX + box.getWidth() * 0.5f, posY + box.getHeight() * 0.5f,
  99. e.posX + e.box.getWidth() * 0.5f, e.posY + e.box.getHeight() * 0.5f);
  100. }
  101. public CollisionObject getBox()
  102. {
  103. return box;
  104. }
  105. public float getX()
  106. {
  107. return posX;
  108. }
  109. public float getY()
  110. {
  111. return posY;
  112. }
  113. public float getLastX()
  114. {
  115. return lastPosX;
  116. }
  117. public float getLastY()
  118. {
  119. return lastPosY;
  120. }
  121. public float getCenterX()
  122. {
  123. return posX + box.getWidth() * 0.5f;
  124. }
  125. public float getCenterY()
  126. {
  127. return posY + box.getHeight() * 0.5f;
  128. }
  129. public Face getFace()
  130. {
  131. if(motionX == 0.0f)
  132. {
  133. return face;
  134. }
  135. face = motionX < 0.0f ? Face.LEFT : Face.RIGHT;
  136. return face;
  137. }
  138. public void updateFace()
  139. {
  140. }
  141. public float getMotionX()
  142. {
  143. return motionX;
  144. }
  145. public void setMotionX(float motionX)
  146. {
  147. this.motionX = motionX;
  148. }
  149. public float getMotionY()
  150. {
  151. return motionY;
  152. }
  153. public void setMotionY(float motionY)
  154. {
  155. this.motionY = motionY;
  156. }
  157. public float getPreMotionX()
  158. {
  159. return preMotionX;
  160. }
  161. public float getPreMotionY()
  162. {
  163. return preMotionY;
  164. }
  165. //--------------------------------------------------------------------------
  166. // ticking
  167. //--------------------------------------------------------------------------
  168. public void tick()
  169. {
  170. lastPosX = posX;
  171. lastPosY = posY;
  172. controller.tick();
  173. energy.tick();
  174. preMotionX = motionX;
  175. preMotionY = motionY;
  176. if(move.hasGravity())
  177. {
  178. preMotionY += GRAVITY * move.getGravityFactor();
  179. }
  180. if(move.canMoveEverywhere())
  181. {
  182. motionX = preMotionX;
  183. motionY = preMotionY;
  184. }
  185. else
  186. {
  187. CollisionObject testBox = box.copy().expand(preMotionX, preMotionY).expand(0.0f, -UP_STEP);
  188. List<CollisionObject> boxes = level.getMovementBoxesAt(testBox, this);
  189. if(!boxes.isEmpty())
  190. {
  191. float mx = preMotionX;
  192. float my = preMotionY;
  193. testBox.reset();
  194. float oldX = testBox.getMinX();
  195. float oldY = testBox.getMinY();
  196. while(mx != 0.0 || my != 0.0)
  197. {
  198. testBox.save();
  199. if(mx < 0.0)
  200. {
  201. if(mx > -STEP)
  202. {
  203. testBox.offsetX(mx);
  204. mx = 0.0f;
  205. }
  206. else
  207. {
  208. testBox.offsetX(-STEP);
  209. mx += STEP;
  210. }
  211. }
  212. else if(mx > 0.0)
  213. {
  214. if(mx < STEP)
  215. {
  216. testBox.offsetX(mx);
  217. mx = 0.0f;
  218. }
  219. else
  220. {
  221. testBox.offsetX(STEP);
  222. mx -= STEP;
  223. }
  224. }
  225. for(CollisionObject cb : boxes)
  226. {
  227. if(cb.isColliding(testBox))
  228. {
  229. testBox.offsetY(-UP_STEP);
  230. for(CollisionObject cb2 : boxes)
  231. {
  232. if(cb2.isColliding(testBox))
  233. {
  234. mx = 0.0f;
  235. testBox.reset();
  236. break;
  237. }
  238. }
  239. break;
  240. }
  241. }
  242. testBox.save();
  243. if(my < 0.0)
  244. {
  245. if(my > -STEP)
  246. {
  247. testBox.offsetY(my);
  248. my = 0.0f;
  249. }
  250. else
  251. {
  252. testBox.offsetY(-STEP);
  253. my += STEP;
  254. }
  255. }
  256. else if(my > 0.0)
  257. {
  258. if(my < STEP)
  259. {
  260. testBox.offsetY(my);
  261. my = 0.0f;
  262. }
  263. else
  264. {
  265. testBox.offsetY(STEP);
  266. my -= STEP;
  267. }
  268. }
  269. for(CollisionObject cb : boxes)
  270. {
  271. if(cb.isColliding(testBox))
  272. {
  273. my = 0.0f;
  274. testBox.reset();
  275. break;
  276. }
  277. }
  278. }
  279. motionX = testBox.getMinX() - oldX;
  280. motionY = testBox.getMinY() - oldY;
  281. }
  282. else
  283. {
  284. motionX = preMotionX;
  285. motionY = preMotionY;
  286. }
  287. }
  288. posX += motionX;
  289. posY += motionY;
  290. box.reset().offset(posX, posY);
  291. if(!move.canMoveEverywhere())
  292. {
  293. //onGround = preMotionY > 0.0f && motionY == 0;
  294. onGround = !level.getMovementBoxesAt(box.copy().expand(0.0f, STEP * 2), this).isEmpty();
  295. move.setInWater(false);
  296. move.setFrictionFactor(0.6f);
  297. // apply collision
  298. CollisionObject cb = box.copy();
  299. for(Face f : Face.values())
  300. {
  301. cb.reset();
  302. cb.expand(f.getCollisionOffsetX(), f.getCollisionOffsetY());
  303. level.getEntitiesCollidingWith(this, cb).forEach(ent -> this.controller.onCollideWithEntity(ent, f));
  304. level.getCollisionBoxesAt(cb).forEach(loc ->
  305. {
  306. controller.onCollideWithTile(loc, f);
  307. loc.getTile().onEntityCollide(this, loc.getX(), loc.getY(), f.getOpposite(), level);
  308. });
  309. }
  310. motionX *= move.getFrictionFactor();
  311. if(Math.abs(motionX) < 0.3)
  312. {
  313. motionX = 0.0f;
  314. }
  315. }
  316. health.tick();
  317. }
  318. public void renderTick(float lag)
  319. {
  320. controller.renderTick(lag);
  321. }
  322. //--------------------------------------------------------------------------
  323. // gravity, friction
  324. //--------------------------------------------------------------------------
  325. public boolean isOnGround()
  326. {
  327. return onGround;
  328. }
  329. }