PageRenderTime 81ms CodeModel.GetById 38ms RepoModel.GetById 1ms app.codeStats 0ms

/src/com/github/begla/blockmania/world/characters/Player.java

https://github.com/Alumen/Blockmania
Java | 376 lines | 230 code | 58 blank | 88 comment | 65 complexity | 29dc69dde3b7f99d8ac99bc18e2332d7 MD5 | raw file
  1. /*
  2. * Copyright 2011 Benjamin Glatzel <benjamin.glatzel@me.com>.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package com.github.begla.blockmania.world.characters;
  18. import com.github.begla.blockmania.audio.AudioManager;
  19. import com.github.begla.blockmania.blocks.Block;
  20. import com.github.begla.blockmania.datastructures.AABB;
  21. import com.github.begla.blockmania.datastructures.ViewFrustum;
  22. import com.github.begla.blockmania.intersections.RayBlockIntersection;
  23. import com.github.begla.blockmania.main.Configuration;
  24. import com.github.begla.blockmania.noise.PerlinNoise;
  25. import com.github.begla.blockmania.world.World;
  26. import javolution.util.FastList;
  27. import org.lwjgl.input.Keyboard;
  28. import org.lwjgl.input.Mouse;
  29. import org.lwjgl.opengl.GL11;
  30. import org.lwjgl.util.glu.GLU;
  31. import org.lwjgl.util.vector.Vector3f;
  32. import java.util.Collections;
  33. import static org.lwjgl.opengl.GL11.*;
  34. /**
  35. * Extends the character class and provides support for player functionality. Also provides the
  36. * modelview matrix from the player's point of view.
  37. *
  38. * @author Benjamin Glatzel <benjamin.glatzel@me.com>
  39. */
  40. public final class Player extends Character {
  41. private byte _selectedBlockType = 1;
  42. private final PerlinNoise _pGen = new PerlinNoise(42);
  43. private final ViewFrustum _viewFrustum = new ViewFrustum();
  44. public Player(World parent) {
  45. super(parent, Configuration.getSettingNumeric("WALKING_SPEED"), Configuration.getSettingNumeric("RUNNING_FACTOR"), Configuration.getSettingNumeric("JUMP_INTENSITY"));
  46. }
  47. public void update() {
  48. _godMode = Configuration.getSettingBoolean("GOD_MODE");
  49. _walkingSpeed = Configuration.getSettingNumeric("WALKING_SPEED");
  50. _runningFactor = Configuration.getSettingNumeric("RUNNING_FACTOR");
  51. _jumpIntensity = Configuration.getSettingNumeric("JUMP_INTENSITY");
  52. super.update();
  53. }
  54. /**
  55. * Positions the player within the world and adjusts the player's view accordingly.
  56. */
  57. public void render() {
  58. RayBlockIntersection.Intersection is = calcSelectedBlock();
  59. // Display the block the player is aiming at
  60. if (Configuration.getSettingBoolean("PLACING_BOX")) {
  61. if (is != null) {
  62. if (Block.getBlockForType(_parent.getBlockAtPosition(is.getBlockPosition())).shouldRenderBoundingBox()) {
  63. Block.AABBForBlockAt(is.getBlockPosition()).render();
  64. }
  65. }
  66. }
  67. super.render();
  68. }
  69. public void applyPlayerModelViewMatrix() {
  70. glMatrixMode(GL11.GL_MODELVIEW);
  71. glLoadIdentity();
  72. if (!(Configuration.getSettingBoolean("DEMO_FLIGHT") && Configuration.getSettingBoolean("GOD_MODE"))) {
  73. if (Configuration.getSettingBoolean("BOBBING") && !Configuration.getSettingBoolean("GOD_MODE")) {
  74. double bobbing = _pGen.noise(getPosition().x * 0.5, 0, getPosition().z * 0.5);
  75. glRotated(bobbing * Configuration.BOBBING_ANGLE, 0, 0, 1);
  76. }
  77. Vector3f eyePosition = calcEyePosition();
  78. GLU.gluLookAt(eyePosition.x, eyePosition.y, eyePosition.z, eyePosition.x + _viewingDirection.x, eyePosition.y + _viewingDirection.y, eyePosition.z + _viewingDirection.z, 0, 1, 0);
  79. } else {
  80. GLU.gluLookAt(getPosition().x, getPosition().y, getPosition().z, getPosition().x, 40, getPosition().z + 128, 0, 1, 0);
  81. }
  82. // Update the current view frustum
  83. _viewFrustum.updateFrustum();
  84. }
  85. public void applyNormalizedModelViewMatrix() {
  86. glMatrixMode(GL11.GL_MODELVIEW);
  87. glLoadIdentity();
  88. if (!(Configuration.getSettingBoolean("DEMO_FLIGHT") && Configuration.getSettingBoolean("GOD_MODE"))) {
  89. GLU.gluLookAt(0, 0, 0, _viewingDirection.x, _viewingDirection.y, _viewingDirection.z, 0, 1, 0);
  90. }
  91. }
  92. public void updatePosition() {
  93. /*
  94. * DEMO MODE
  95. */
  96. if (Configuration.getSettingBoolean("DEMO_FLIGHT") && Configuration.getSettingBoolean("GOD_MODE")) {
  97. getPosition().z += Configuration.getSettingNumeric("WALKING_SPEED");
  98. int maxHeight = _parent.maxHeightAt((int) getPosition().x, (int) getPosition().z + 8) + 16;
  99. getPosition().y += (maxHeight - getPosition().y) / 128f;
  100. if (getPosition().y > 128)
  101. getPosition().y = 128;
  102. if (getPosition().y < 40f)
  103. getPosition().y = 40f;
  104. return;
  105. }
  106. super.updatePosition();
  107. }
  108. /**
  109. * Calculates the currently looked at block in front of the player.
  110. *
  111. * @return Intersection point of the looked at block
  112. */
  113. RayBlockIntersection.Intersection calcSelectedBlock() {
  114. FastList<RayBlockIntersection.Intersection> inters = new FastList<RayBlockIntersection.Intersection>();
  115. for (int x = -3; x <= 3; x++) {
  116. for (int y = -3; y <= 3; y++) {
  117. for (int z = -3; z <= 3; z++) {
  118. byte blockType = _parent.getBlock((int) (getPosition().x + x), (int) (getPosition().y + y), (int) (getPosition().z + z));
  119. // Ignore special blocks
  120. if (Block.getBlockForType(blockType).letSelectionRayThrough()) {
  121. continue;
  122. }
  123. // The ray originates from the "player's eye"
  124. FastList<RayBlockIntersection.Intersection> iss = RayBlockIntersection.executeIntersection(_parent, (int) getPosition().x + x, (int) getPosition().y + y, (int) getPosition().z + z, calcEyePosition(), _viewingDirection);
  125. if (iss != null) {
  126. inters.addAll(iss);
  127. }
  128. }
  129. }
  130. }
  131. /**
  132. * Calculated the closest intersection.
  133. */
  134. if (inters.size() > 0) {
  135. Collections.sort(inters);
  136. return inters.get(0);
  137. }
  138. return null;
  139. }
  140. /**
  141. * Places a block of a given type in front of the player.
  142. *
  143. * @param type The type of the block
  144. */
  145. public void placeBlock(byte type) {
  146. if (getParent() != null) {
  147. RayBlockIntersection.Intersection is = calcSelectedBlock();
  148. if (is != null) {
  149. Block centerBlock = Block.getBlockForType(getParent().getBlock((int) is.getBlockPosition().x, (int) is.getBlockPosition().y, (int) is.getBlockPosition().z));
  150. if (!centerBlock.playerCanAttachBlocks()) {
  151. return;
  152. }
  153. Vector3f blockPos = is.calcAdjacentBlockPos();
  154. // Prevent players from placing blocks inside their bounding boxes
  155. if (Block.AABBForBlockAt((int) blockPos.x, (int) blockPos.y, (int) blockPos.z).overlaps(getAABB())) {
  156. return;
  157. }
  158. getParent().setBlock((int) blockPos.x, (int) blockPos.y, (int) blockPos.z, type, true, false);
  159. AudioManager.getInstance().getAudio("PlaceRemoveBlock").playAsSoundEffect(0.7f + (float) Math.abs(_rand.randomDouble()) * 0.3f, 0.7f + (float) Math.abs(_rand.randomDouble()) * 0.3f, false);
  160. }
  161. }
  162. }
  163. /**
  164. * Plants a tree of a given type in front of the player.
  165. *
  166. * @param type The type of the tree
  167. */
  168. public void plantTree(int type) {
  169. RayBlockIntersection.Intersection is = calcSelectedBlock();
  170. if (is != null) {
  171. Vector3f blockPos = is.getBlockPosition();
  172. if (type == 0) {
  173. _parent.getObjectGenerator("tree").generate((int) blockPos.x, (int) blockPos.y, (int) blockPos.z, true);
  174. } else {
  175. _parent.getObjectGenerator("pineTree").generate((int) blockPos.x, (int) blockPos.y, (int) blockPos.z, true);
  176. }
  177. }
  178. }
  179. /**
  180. * Removes a block.
  181. */
  182. void removeBlock() {
  183. if (getParent() != null) {
  184. RayBlockIntersection.Intersection is = calcSelectedBlock();
  185. if (is != null) {
  186. Vector3f blockPos = is.getBlockPosition();
  187. byte currentBlockType = getParent().getBlock((int) blockPos.x, (int) blockPos.y, (int) blockPos.z);
  188. getParent().setBlock((int) blockPos.x, (int) blockPos.y, (int) blockPos.z, (byte) 0x0, true, true);
  189. _parent.getBlockParticleEmitter().setOrigin(blockPos);
  190. _parent.getBlockParticleEmitter().emitParticles(128, currentBlockType);
  191. AudioManager.getInstance().getAudio("PlaceRemoveBlock").playAsSoundEffect(0.6f + (float) Math.abs(_rand.randomDouble()) * 0.4f, 0.7f + (float) Math.abs(_rand.randomDouble()) * 0.3f, false);
  192. }
  193. }
  194. }
  195. /**
  196. * Processes the keyboard input.
  197. *
  198. * @param key Pressed key on the keyboard
  199. * @param state The state of the key
  200. * @param repeatEvent True if repeat event
  201. */
  202. public void processKeyboardInput(int key, boolean state, boolean repeatEvent) {
  203. switch (key) {
  204. case Keyboard.KEY_E:
  205. if (state && !repeatEvent) {
  206. placeBlock(_selectedBlockType);
  207. }
  208. break;
  209. case Keyboard.KEY_Q:
  210. if (state && !repeatEvent) {
  211. removeBlock();
  212. }
  213. break;
  214. case Keyboard.KEY_UP:
  215. if (!repeatEvent && state) {
  216. cycleBlockTypes(1);
  217. }
  218. break;
  219. case Keyboard.KEY_DOWN:
  220. if (!repeatEvent && state) {
  221. cycleBlockTypes(-1);
  222. }
  223. break;
  224. case Keyboard.KEY_SPACE:
  225. if (!repeatEvent && state) {
  226. jump();
  227. }
  228. break;
  229. }
  230. }
  231. /**
  232. * Processes the mouse input.
  233. *
  234. * @param button Pressed mouse button
  235. * @param state State of the mouse button
  236. */
  237. public void processMouseInput(int button, boolean state) {
  238. if (button == 0 && state) {
  239. placeBlock(_selectedBlockType);
  240. } else if (button == 1 && state) {
  241. removeBlock();
  242. }
  243. }
  244. /**
  245. * Checks for pressed keys and mouse movement and executes the respective movement
  246. * command.
  247. */
  248. public void processMovement() {
  249. double dx = Mouse.getDX();
  250. double dy = Mouse.getDY();
  251. yaw(dx * Configuration.MOUSE_SENS);
  252. pitch(dy * Configuration.MOUSE_SENS);
  253. if (Keyboard.isKeyDown(Keyboard.KEY_W)) {
  254. walkForward();
  255. }
  256. if (Keyboard.isKeyDown(Keyboard.KEY_S)) {
  257. walkBackwards();
  258. }
  259. if (Keyboard.isKeyDown(Keyboard.KEY_A)) {
  260. strafeLeft();
  261. }
  262. if (Keyboard.isKeyDown(Keyboard.KEY_D)) {
  263. strafeRight();
  264. }
  265. if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) && _touchingGround) {
  266. _running = true;
  267. } else {
  268. _running = false;
  269. }
  270. }
  271. /**
  272. * Cycles the selected block type.
  273. *
  274. * @param upDown Cycling direction
  275. */
  276. void cycleBlockTypes(int upDown) {
  277. _selectedBlockType += upDown;
  278. if (_selectedBlockType >= Block.getBlockCount()) {
  279. _selectedBlockType = 1;
  280. } else if (_selectedBlockType < 1) {
  281. _selectedBlockType = (byte) (Block.getBlockCount() - 1);
  282. }
  283. }
  284. /**
  285. * Returns some information about the player as a string.
  286. *
  287. * @return The string
  288. */
  289. @Override
  290. public String toString() {
  291. return String.format("player (x: %.2f, y: %.2f, z: %.2f | x: %.2f, y: %.2f, z: %.2f | b: %d | gravity: %.2f | x: %.2f, y: %.2f, z:, %.2f)", getPosition().x, getPosition().y, getPosition().z, _viewingDirection.x, _viewingDirection.y, _viewingDirection.z, _selectedBlockType, _gravity, _movementDirection.x, _movementDirection.y, _movementDirection.z);
  292. }
  293. protected AABB generateAABBForPosition(Vector3f p) {
  294. return new AABB(p, new Vector3f(.3f, 0.7f, .3f));
  295. }
  296. /**
  297. * Returns player's AABB.
  298. *
  299. * @return The AABB
  300. */
  301. public AABB getAABB() {
  302. return generateAABBForPosition(getPosition());
  303. }
  304. @Override
  305. protected void handleVerticalCollision() {
  306. // Nothing special to do.
  307. }
  308. @Override
  309. protected void handleHorizontalCollision() {
  310. // Uh. A wall.
  311. }
  312. public ViewFrustum getViewFrustum() {
  313. return _viewFrustum;
  314. }
  315. public byte getSelectedBlockType() {
  316. return _selectedBlockType;
  317. }
  318. }