Entity.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  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.001953125f;
  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;
  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. return face;
  132. }
  133. public float getMotionX()
  134. {
  135. return motionX;
  136. }
  137. public void setMotionX(float motionX)
  138. {
  139. this.motionX = motionX;
  140. }
  141. public float getMotionY()
  142. {
  143. return motionY;
  144. }
  145. public void setMotionY(float motionY)
  146. {
  147. this.motionY = motionY;
  148. }
  149. public float getPreMotionX()
  150. {
  151. return preMotionX;
  152. }
  153. public float getPreMotionY()
  154. {
  155. return preMotionY;
  156. }
  157. //--------------------------------------------------------------------------
  158. // ticking
  159. //--------------------------------------------------------------------------
  160. public void tick()
  161. {
  162. lastPosX = posX;
  163. lastPosY = posY;
  164. controller.tick();
  165. energy.tick();
  166. preMotionX = motionX;
  167. preMotionY = motionY;
  168. if(preMotionX != 0.0f)
  169. {
  170. face = preMotionX > 0.0f ? Face.RIGHT : Face.LEFT;
  171. }
  172. if(move.hasGravity())
  173. {
  174. preMotionY += GRAVITY * move.getGravityFactor();
  175. }
  176. if(move.canMoveEverywhere())
  177. {
  178. motionX = preMotionX;
  179. motionY = preMotionY;
  180. }
  181. else
  182. {
  183. CollisionObject testBox = box.copy().expand(preMotionX, preMotionY);
  184. List<CollisionObject> boxes = level.getMovementBoxesAt(testBox, this);
  185. if(!boxes.isEmpty())
  186. {
  187. float mx = preMotionX;
  188. float my = preMotionY;
  189. testBox.reset();
  190. float oldX = testBox.getMinX();
  191. float oldY = testBox.getMinY();
  192. while(mx != 0.0 || my != 0.0)
  193. {
  194. testBox.save();
  195. if(mx < 0.0)
  196. {
  197. if(mx > -STEP)
  198. {
  199. testBox.offsetX(mx);
  200. mx = 0.0f;
  201. }
  202. else
  203. {
  204. testBox.offsetX(-STEP);
  205. mx += STEP;
  206. }
  207. }
  208. else if(mx > 0.0)
  209. {
  210. if(mx < STEP)
  211. {
  212. testBox.offsetX(mx);
  213. mx = 0.0f;
  214. }
  215. else
  216. {
  217. testBox.offsetX(STEP);
  218. mx -= STEP;
  219. }
  220. }
  221. for(CollisionObject cb : boxes)
  222. {
  223. if(cb.isColliding(testBox))
  224. {
  225. testBox.offsetY(-UP_STEP);
  226. for(CollisionObject cb2 : boxes)
  227. {
  228. if(cb2.isColliding(testBox))
  229. {
  230. mx = 0.0f;
  231. testBox.reset();
  232. break;
  233. }
  234. }
  235. break;
  236. }
  237. }
  238. testBox.save();
  239. if(my < 0.0)
  240. {
  241. if(my > -STEP)
  242. {
  243. testBox.offsetY(my);
  244. my = 0.0f;
  245. }
  246. else
  247. {
  248. testBox.offsetY(-STEP);
  249. my += STEP;
  250. }
  251. }
  252. else if(my > 0.0)
  253. {
  254. if(my < STEP)
  255. {
  256. testBox.offsetY(my);
  257. my = 0.0f;
  258. }
  259. else
  260. {
  261. testBox.offsetY(STEP);
  262. my -= STEP;
  263. }
  264. }
  265. for(CollisionObject cb : boxes)
  266. {
  267. if(cb.isColliding(testBox))
  268. {
  269. my = 0.0f;
  270. testBox.reset();
  271. break;
  272. }
  273. }
  274. }
  275. motionX = testBox.getMinX() - oldX;
  276. motionY = testBox.getMinY() - oldY;
  277. /*if(motionX != 0.0f || motionY != 0.0f)
  278. {
  279. System.out.println("____________________");
  280. System.out.println(testBox + " " + preMotionX + " " + preMotionY);
  281. System.out.println(box);
  282. boxes.forEach(b -> System.out.println(b));
  283. System.out.println(motionX + " " + motionY);
  284. System.out.println("____________________");
  285. }*/
  286. }
  287. else
  288. {
  289. motionX = preMotionX;
  290. motionY = preMotionY;
  291. }
  292. }
  293. posX += motionX;
  294. posY += motionY;
  295. box.reset().offset(posX, posY);
  296. //onGround = preMotionY > 0.0f && motionY == 0;
  297. onGround = !level.getCollisionBoxesAt(box.copy().expand(0.0f, STEP * 2)).isEmpty();
  298. move.setInWater(false);
  299. move.setFrictionFactor(0.6f);
  300. // apply collision
  301. CollisionObject cb = box.copy();
  302. for(Face f : Face.values())
  303. {
  304. cb.reset();
  305. cb.expand(f.getCollisionOffsetX(), f.getCollisionOffsetY());
  306. level.getEntitiesCollidingWith(this, box).forEach(ent -> ent.controller.onCollideWithEntity(ent, f));
  307. level.getCollisionBoxesAt(cb).forEach(loc ->
  308. {
  309. controller.onCollideWithTile(loc, f);
  310. loc.getTile().onEntityCollide(this, loc.getX(), loc.getY(), f.getOpposite());
  311. });
  312. }
  313. motionX *= move.getFrictionFactor();
  314. if(Math.abs(motionX) < 0.3)
  315. {
  316. motionX = 0.0f;
  317. }
  318. health.tick();
  319. }
  320. public void renderTick(float lag)
  321. {
  322. controller.renderTick(lag);
  323. }
  324. //--------------------------------------------------------------------------
  325. // gravity, friction
  326. //--------------------------------------------------------------------------
  327. public boolean isOnGround()
  328. {
  329. return onGround;
  330. }
  331. }