package gameplay.match; import engine.Engine; import engine.gui.UIElementText; import engine.input.Button; import engine.input.GamepadInput; import engine.math.Vector3f; import engine.object.ObjectGl; import engine.object.Sprite; import gameplay.Characters.Blue.CharacterBlue; import gameplay.actions.Attack; import gameplay.actions.attackPart; import gameplay.actions.Throw; import gameplay.actions.ThrowPart; import gameplay.entities.Status; import gameplay.frames.Frame; import gameplay.hitboxes.Active_HitBox; import gameplay.hitboxes.Passive_HitBox; import gameplay.hitboxes.Active_throw_Hitbox; import gameplay.hitboxes.Passive_throw_HitBox; import gameplay.input.InputBuffer; import gameplay.entities.Character; import gameplay.input.Inputs; import gameplay.input.ButtonIG; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; import static org.lwjgl.glfw.GLFW.*; /** * Main class that describes the base structure of the match, with characters, * timer and such * * @author Victor Azra * */ public class match { /** * the number of inputs read for each character, a.k.a. for how many frames the * inputs are saved in memory. */ private static final int inputBufferSize = 120; /** * the level of the "ground", used to determine if a character is in the air or * not. */ private static final int groundLevel = 180; private static int timer; private static InputBuffer inputsP1, inputsP2; private static int roundsWonP1, roundsWonP2; private static Character p1, p2; // characters of player 1 and 2 private static long timeStamp1; private static long timeStamp2; private static int frameCount; private static int oldPosXp1; private static int oldPosXp2; private static int oldPosYp1; private static int oldPosYp2; private static GamepadInput gamepad1 = null; private static GamepadInput gamepad2 = null; // GUI private static UIElementText coordP1; private static UIElementText coordP2; private static ObjectGl objP1, objP2; private static Engine engine; private static Frame f; private static int acCode = 0; private static int height, width; /** * Starts a new round, by placing the timer back at base value, characters back * at full hp and such. */ private static void startNewRound() { timer = 99; inputsP1 = new InputBuffer(inputBufferSize); inputsP2 = new InputBuffer(inputBufferSize); p1.setPos(-750, groundLevel); // TODO : change to better values if needed p2.setPos((int) (750 - objP2.getWidth() * objP2.getScalingFactor()), groundLevel); // TODO : change to better // values if needed objP1.translate(new Vector3f(p1.getPosX(), p1.getPosY(), 0)); objP2.translate(new Vector3f(p2.getPosX(), p2.getPosY(), 0)); } /** * Ends the round. Used for playing animations and such. TODO : Implement this * once we know what to do. */ private static void endRound() { } /** * Ends the match. Used for playing animations and such. TODO : Implement this * once we know what to do. */ private static void endMatch() { } public static void parse() throws FileNotFoundException { JSONParser jsonP = new JSONParser(); try { JSONObject jsonO = (JSONObject) jsonP.parse(new FileReader("game.set")); JSONArray game = (JSONArray) jsonO.get("game"); JSONObject settings = (JSONObject) game.get(0); height = Integer.parseInt((String) settings.get("height")); width = Integer.parseInt((String) settings.get("width")); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); } } public static void main(String[] args) throws Exception { parse(); engine = new Engine(width, height, new Vector3f(4.0f, 3.0f)); engine.init(); boolean Joystick1Present = glfwJoystickPresent(GLFW_JOYSTICK_1); boolean Joystick2Present = glfwJoystickPresent(GLFW_JOYSTICK_2); String path = "textures/Sprite.png"; String pathToBG = "textures/background_beach.png"; ObjectGl background = new ObjectGl(0f, 1f, 1f, 10f, pathToBG, null); background.setTextureWrap(0, 0, 621, 224); background.translate(new Vector3f(-3011.0f, 1400.0f, 1.0f)); engine.add_objectGl(background); p1 = CharacterBlue.generateCharBlue(); p2 = CharacterBlue.generateCharBlue(); objP1 = new Sprite(10f, 5f, path, null); objP2 = new Sprite(15f, 5f, path, null); objP2.setColor(new Vector3f(1.0f, 0.0f, 1.0f)); engine.add_objectGl(objP1); engine.add_objectGl(objP2); f = p1.getCurrentframe(); objP1.setTextureWrap(f.getSprite()[0], f.getSprite()[1], f.getSprite()[2], f.getSprite()[3]); f = p2.getCurrentframe(); objP2.setTextureWrap(f.getSprite()[0], f.getSprite()[1], f.getSprite()[2], f.getSprite()[3]); objP2.flipTextureWrapH(); if (Joystick1Present) { gamepad1 = new GamepadInput(GLFW_JOYSTICK_1); gamepad1.inputRefresh(); System.out.println("P1 Controller: " + gamepad1.getGamepadName()); } if (Joystick2Present) { gamepad2 = new GamepadInput(GLFW_JOYSTICK_2); gamepad2.inputRefresh(); System.out.println("P2 Controller: " + gamepad2.getGamepadName()); } // GUI setup coordP1 = new UIElementText( "objP1: " + objP1.getXPos() + ":" + objP1.getYPos() + " P1: " + p1.getPosX() + ":" + p1.getPosY(), 5f, 0f, 1f, 80f, engine); engine.add_uiElement(coordP1); coordP2 = new UIElementText( "objP2: " + objP2.getXPos() + ":" + objP2.getYPos() + " P1: " + p2.getPosX() + ":" + p2.getPosY(), 5f, 0f, 0.9f, 80f, engine); engine.add_uiElement(coordP2); while (frameCount < 5940 && engine.getRunning()) { ac(acCode); if (engine.shouldClose()) engine.setRunning(false); } } private static void ac(int i) { // System.out.println(i); switch (i) { // initiate a round case 0: startNewRound(); timeStamp1 = System.currentTimeMillis(); frameCount = 0; acCode = 10; break; // checks if one or both of the chars are out of health case 10: oldPosXp1 = p1.getPosX(); oldPosXp2 = p2.getPosX(); oldPosYp1 = p1.getPosY(); oldPosYp2 = p2.getPosY(); if (p1.getCurrentHP() <= 0 && p2.getCurrentHP() <= 0) { acCode = 11; } else if (p1.getCurrentHP() <= 0) { acCode = 12; } else if (p2.getCurrentHP() <= 0) { acCode = 13; } else { acCode = 20; } break; // end round case 11: endRound(); if (roundsWonP1 >= 2 || roundsWonP2 >= 2) { endMatch(); } // TODO : will probably need to specify more else { acCode = 0; } break; // if p1 is at 0 health case 12: roundsWonP2++; acCode = 11; break; // if p2 is at 0 health case 13: roundsWonP1++; acCode = 11; break; // read both players inputs case 20: if (glfwJoystickPresent(GLFW_JOYSTICK_1)) { gamepad1.inputRefresh(); inputsP1.recordInputsFromGamepad(gamepad1, p1.getPosX() < p2.getPosX()); handleInputs(p1, inputsP1); } if (glfwJoystickPresent(GLFW_JOYSTICK_2)) { gamepad2.inputRefresh(); inputsP2.recordInputsFromGamepad(gamepad2, p2.getPosX() <= p1.getPosX()); handleInputs(p2, inputsP2); } // acCode = 21; break; // start of the handling of hitboxes case 21: try { handleThrows(p1, p2); } catch (IndexOutOfBoundsException e) { } try { handleHits(p1, p2, inputsP2); handleHits(p2, p1, inputsP1); } catch (IndexOutOfBoundsException e) { } ; acCode = 22; break; // Update of the current frame of each character case 22: if (p1.getCurrentframe().islastFrameOfHit()) { p1.removeFirstAttackPart(); } if (p2.getCurrentframe().islastFrameOfHit()) { p2.removeFirstAttackPart(); } nextFrame(p1, inputsP1); nextFrame(p2, inputsP2); boolean p1LooksRight = p1.getPosX() < p2.getPosX(); updatePos(p1, p1LooksRight); updatePos(p2, !p1LooksRight); if (p1LooksRight) { f = p1.getCurrentframe(); objP1.setTextureWrap(f.getSprite()[0], f.getSprite()[1], f.getSprite()[2], f.getSprite()[3]); objP1.translate(new Vector3f(p1.getPosX() - oldPosXp1, p1.getPosY() - oldPosYp1, 0)); f = p2.getCurrentframe(); objP2.setTextureWrap(f.getSprite()[0], f.getSprite()[1], f.getSprite()[2], f.getSprite()[3]); objP2.translate(new Vector3f(0 - (p2.getPosX() - oldPosXp2), p2.getPosY() - oldPosYp2, 0)); Frame nf = new Frame(); nf.clone(p2.getCurrentframe()); nf.invertHitBoxes(); p2.setCurrentFrame(nf); objP2.flipTextureWrapH(); } else { Frame p1f = p1.getCurrentframe(); objP1.setTextureWrap(p1f.getSprite()[0], p1f.getSprite()[1], p1f.getSprite()[2], p1f.getSprite()[3]); objP1.translate(new Vector3f(p1.getPosX() - oldPosXp1, p1.getPosY() - oldPosYp1, 0)); Frame p2f = p2.getCurrentframe(); objP2.setTextureWrap(p2f.getSprite()[0], p2f.getSprite()[1], p2f.getSprite()[2], p2f.getSprite()[3]); objP2.translate(new Vector3f(p2.getPosX() - oldPosXp2, p2.getPosY() - oldPosYp2, 0)); Frame nf = new Frame(); nf.clone(p1.getCurrentframe()); nf.invertHitBoxes(); p1.setCurrentFrame(nf); objP1.flipTextureWrapH(); } engine.update(); engine.render(); acCode = 23; break; // Waits the end of 1/60th of a second since start of frame then loops back to // start case 23: // GUI update here coordP1.setText( "objP1: " + objP1.getXPos() + ":" + objP1.getYPos() + " P1: " + p1.getPosX() + ":" + p1.getPosY()); coordP2.setText( "objP2: " + objP2.getXPos() + ":" + objP2.getYPos() + " P2: " + p2.getPosX() + ":" + p2.getPosY()); timeStamp2 = System.currentTimeMillis(); while (timeStamp2 - timeStamp1 < (1000 / 60)) { timeStamp2 = System.currentTimeMillis(); } frameCount++; timeStamp1 = System.currentTimeMillis(); acCode = 10; break; } } /** * Will handle the inputs recorder and have the character do a corresponding * action if possible Order of priority is Throw > Special > Normal > Jump > * Dash > Crouch > Move > do nothing * * @param c * @param input */ private static void handleInputs(Character c, InputBuffer input) { Inputs latestIn = input.getLatestInputs(); boolean actionSet = false; if (latestIn.containsButtonTab(c.getNormalthrow().getCommand()[0]) && c.getCurrentframe().isNormalCancellable()) { c.clearNextFrames(); c.addNextFramesList(c.getNormalthrow().getFrame()); actionSet = true; } else { int atkCount = 0; // do an attack if possible while (atkCount < c.getAttacks().length && !actionSet) { Attack atk = c.getAttacks()[atkCount]; Boolean attackIsPossible = input.commandRecognized(atk.getCommand()) && atk.getRequiredStatus().equals(c.getStatus()) && ((atk.isSpecial() && c.getCurrentframe().isSpecialCancellable()) || (!atk.isSpecial() && c.getCurrentframe().isNormalCancellable())); if (attackIsPossible) { c.clearNextFrames(); c.addNextFramesList(atk.getFrame()); c.setAttackPartsArray(atk.getParts()); actionSet = true; } atkCount++; } if (c.getCurrentframe().isJumpCancellable() && !actionSet) { if (input.commandRecognized(c.getForwardJump().getCommand())) { c.clearNextFrames(); c.addNextFramesList(c.getForwardJump().getFrame()); actionSet = true; c.setStatus(Status.JUMPING); } else if (input.commandRecognized(c.getBackJump().getCommand())) { c.clearNextFrames(); c.addNextFramesList(c.getBackJump().getFrame()); actionSet = true; c.setStatus(Status.JUMPING); } else if (input.commandRecognized(c.getNeutralJump().getCommand())) { c.clearNextFrames(); c.addNextFramesList(c.getNeutralJump().getFrame()); actionSet = true; c.setStatus(Status.JUMPING); } } if (c.getCurrentframe().isDashCancellable() && !actionSet) { if (input.commandRecognized(c.getForwardDash().getCommand())) { c.clearNextFrames(); c.addNextFramesList(c.getForwardDash().getFrame()); actionSet = true; } else if (input.commandRecognized(c.getBackDash().getCommand())) { c.clearNextFrames(); c.addNextFramesList(c.getBackDash().getFrame()); actionSet = true; } } if (c.getCurrentframe().isMoveCancellable() && !actionSet) { if (input.getLatestInputs().containsInput(ButtonIG.DOWN)) { c.clearNextFrames(); c.addNextFrames(c.getDefaultCrouchingFrames()); } else if (input.getLatestInputs().containsInput(ButtonIG.BACK)) { c.clearNextFrames(); c.addNextFrames(c.getBackWalkFrames()); } if (input.getLatestInputs().containsInput(ButtonIG.FORWARD)) { c.clearNextFrames(); c.addNextFrames(c.getForwardWalkFrames()); } } } } private static void handleThrows(Character p1, Character p2) { ArrayList activeP1 = new ArrayList( p1.getCurrentframe().getActThrowHitBox()); ArrayList passiveP2 = new ArrayList( p2.getCurrentframe().getPassThrowHitBox()); ArrayList tP = new ArrayList(p1.getNextThrowParts()); ThrowPart hit = new ThrowPart(tP.get(0).getFrames()); hit.clone(tP.get(0)); for (Active_throw_Hitbox atH : activeP1) { for (Passive_throw_HitBox ptH : passiveP2) { if (!hit.hasHit()) { boolean p1LooksRight = p1.getPosX() < p2.getPosX(); boolean touchH = (p1LooksRight && (atH.getPosX() + p1.getPosX() + atH.getSize_x() > ptH.getPosX() + p2.getPosX() + ptH.getSize_x()) && (atH.getPosX() < ptH.getPosX())) || (!p1LooksRight && (atH.getPosX() + p1.getPosX() + atH.getSize_x() < ptH.getPosX() + p2.getPosX() + ptH.getSize_x()) && (atH.getPosX() > ptH.getPosX())); boolean touchV = (atH.getPosY() - atH.getSize_y() < ptH.getPosY()) && (atH.getPosY() > ptH.getPosY() - ptH.getSize_y()); if (touchH && touchV) { hit.setHasHit(true); tP.set(0, hit); } } } } } /** * handles the if the first character hits the second one * * @param p1 the character whose hits to handle * @param p2 the character who is or isn't hit * @param inputsP2 the inputs of the player 2, used to see if they're guarding */ private static void handleHits(Character p1, Character p2, InputBuffer inputsP2) { ArrayList activeP1 = new ArrayList(p1.getCurrentframe().getActHitBox()); ArrayList passiveP2 = new ArrayList(p2.getCurrentframe().getPassHitBox()); ArrayList aP = new ArrayList(p1.getNextAttackParts()); attackPart hit = new attackPart(aP.get(0).getFrames()); hit.clone(aP.get(0)); for (Active_HitBox aH : activeP1) { for (Passive_HitBox pH : passiveP2) { if (!hit.hasHit()) { boolean p1LooksRight = p1.getPosX() < p2.getPosX(); boolean touchH = (p1LooksRight && (aH.getPosX() + p1.getPosX() + aH.getSize_x() > pH.getPosX() + p2.getPosX() + pH.getSize_x()) && (aH.getPosX() < pH.getPosX())) || (!p1LooksRight && (aH.getPosX() + p1.getPosX() + aH.getSize_x() < pH.getPosX() + p2.getPosX() + pH.getSize_x()) && (aH.getPosX() > pH.getPosX())); boolean touchV = (aH.getPosY() - aH.getSize_y() < pH.getPosY()) && (aH.getPosY() > pH.getPosY() - pH.getSize_y()); if (touchH && touchV) { getHit(p2, hit, inputsP2.getLatestInputs()); hit.setHasHit(true); aP.set(0, hit); } } } } } /** * Handles a character getting hit by an attack part. * * @param c the character that's getting hit * @param aP the attackPart hitting the character * @param inputs the current inputs of c */ private static void getHit(Character c, attackPart aP, Inputs inputs) { boolean getsHit = (c.getStatus() == Status.JUMPING) || (c.getStatus() == Status.HITINAIR) || (c.getStatus() == Status.FALLING) || inputs.containsInput(ButtonIG.BACK) || (aP.isLow() && !inputs.containsInput(ButtonIG.DOWN)) || (aP.isOverHead() && inputs.containsInput(ButtonIG.DOWN)); Frame[] nextFrames; c.clearNextFrames(); if (getsHit) { switch (c.getStatus()) { case JUMPING: case HITINAIR: case FALLING: nextFrames = new Frame[20]; for (int i = 0; i < nextFrames.length; i++) { nextFrames[i] = c.getHitInAirFrame(); } c.addNextFrames(nextFrames); c.reduceHP(aP.getDamage()); c.setStatus(Status.HITINAIR); break; default: c.clearNextFrames(); if (!aP.knocksDown()) { nextFrames = new Frame[aP.getHitstun()]; if (inputs.containsInput(ButtonIG.DOWN)) { for (int i = 0; i < nextFrames.length; i++) { nextFrames[i] = c.getCrouchHitFrame(); } } else { for (int i = 0; i < nextFrames.length; i++) { nextFrames[i] = c.getStandHitFrame(); } } } else { nextFrames = new Frame[c.getKnockedDownFrames().length]; for (int i = 0; i < nextFrames.length; i++) { nextFrames[i] = c.getKnockedDownFrames()[i]; } } c.addNextFrames(nextFrames); c.reduceHP(aP.getDamage()); break; } } else { nextFrames = new Frame[aP.getBlockstun()]; if (inputs.containsInput(ButtonIG.DOWN)) { for (int i = 0; i < nextFrames.length; i++) { nextFrames[i] = c.getCrouchGuardFrame(); } } else { for (int i = 0; i < nextFrames.length; i++) { nextFrames[i] = c.getStandGuardFrame(); } } c.reduceHP(aP.getChipDamage()); c.addNextFrames(nextFrames); } } /** * Sets the character to its next logical frame * * @param c the character * @param in the input buffer corresponding to the character */ private static void nextFrame(Character c, InputBuffer in) { try { // if(!c.getFrames().getNextframe().equals(null)){ c.goToNextFrames(); } catch (NullPointerException e) { switch (c.getStatus()) { case FALLING: case HITINAIR: if (c.getPosY() > groundLevel) { c.setStatus(Status.FALLING); c.setCurrentFrame(c.getFallingframe()); } else { c.setPos(c.getPosX(), groundLevel); c.setStatus(Status.KNOCKEDDOWN); c.addNextFrames(c.getKnockedDownFrames()); } break; default: c.setStatus(Status.NORMAL); if (in.getLatestInputs().containsInput(ButtonIG.DOWN)) { c.addNextFrames(c.getDefaultCrouchingFrames()); } else { c.addNextFrames(c.getDefaultStandingFrames()); } break; } } } private static void updatePos(Character c, boolean looksRight) { if (looksRight) { c.setPos((int) (c.getPosX() + c.getCurrentframe().getMove_x()), (int) (c.getPosY() + c.getCurrentframe().getMove_y())); } else { c.setPos((int) (c.getPosX() - c.getCurrentframe().getMove_x()), (int) (c.getPosY() + c.getCurrentframe().getMove_y())); } } }