diff --git a/src/gameplay/actions/attackPart.java b/src/gameplay/actions/attackPart.java index da85585..ec6db4c 100644 --- a/src/gameplay/actions/attackPart.java +++ b/src/gameplay/actions/attackPart.java @@ -10,6 +10,7 @@ public class attackPart { private double knockbackOnHit, knockbackOnBlock; private Frame[] frames; private boolean hasHit; + private boolean isOverHead, isLow, knocksDown; /** * Constructor with most parameters for an attack part, generally a hit @@ -20,8 +21,11 @@ public class attackPart { * @param knockbackOnHit the distance the enemy gets moved back if hit * @param knockbackOnBlock the distance the enemy gets moved back if blocked * @param frames the array of frames for the part + * @param isLow whether or not the hit hits low + * @param isOverHead whether or not the hit is an overhead + * @param knocksDown whether or not the hit knocks down */ - public attackPart(int damage, int chipDamage, int hitstun, int blockstun, double knockbackOnHit, double knockbackOnBlock, Frame[] frames) { + public attackPart(int damage, int chipDamage, int hitstun, int blockstun, double knockbackOnHit, double knockbackOnBlock, Frame[] frames, boolean isLow, boolean isOverHead, boolean knocksDown) { this.damage = damage; this.chipDamage = chipDamage; this.hitstun = hitstun; @@ -31,6 +35,9 @@ public class attackPart { this.frames = frames; if(this.frames.length >= 1) {this.frames[this.frames.length-1].setLastFrameOfHit(true);} this.hasHit = false; + this.isLow = isLow; + this.isOverHead = isOverHead; + this.knocksDown = knocksDown; } /** @@ -48,6 +55,10 @@ public class attackPart { this.knockbackOnBlock = 0.0; this.hasHit = false; if(this.frames.length >= 1) {this.frames[this.frames.length -1].setLastFrameOfHit(true);} + this.isLow = false; + this.isOverHead = false; + this.knocksDown = false; + } public boolean hasHit() { @@ -124,4 +135,32 @@ public class attackPart { this.knockbackOnBlock = aP.getKnockbackOnBlock(); this.damage = aP.getDamage(); } + + public boolean isHasHit() { + return hasHit; + } + + public boolean isOverHead() { + return isOverHead; + } + + public void setOverHead(boolean overHead) { + isOverHead = overHead; + } + + public boolean isLow() { + return isLow; + } + + public void setLow(boolean low) { + isLow = low; + } + + public boolean knocksDown() { + return knocksDown; + } + + public void setKnockDown(boolean knocksDown) { + this.knocksDown = knocksDown; + } } diff --git a/src/gameplay/entities/Character.java b/src/gameplay/entities/Character.java index 0f50432..8ae34ca 100644 --- a/src/gameplay/entities/Character.java +++ b/src/gameplay/entities/Character.java @@ -3,6 +3,7 @@ package gameplay.entities; import gameplay.actions.*; import gameplay.frames.Frame; import gameplay.frames.nextFrameBuffer; +import gameplay.input.InputBuffer; import java.util.ArrayList; @@ -38,6 +39,13 @@ public class Character extends Entity { private static Frame[] defaultCrouchingFrames; private static Frame[] forwardWalkFrames; private static Frame[] backWalkFrames; + private Frame hitInAirFrame; //the frame to display when hit in the air. Shouldmake the character rise + private Frame fallingframe; //the frame to display when falling from the air + private Frame[] knockedDownFrames; + private Frame standGuardFrame; + private Frame crouchGuardFrame; + private Frame standHitFrame; + private Frame crouchHitFrame; private ArrayList nextAttackParts; @@ -176,6 +184,14 @@ public class Character extends Entity { } } + /** + * Removes current attack part from the list, + * which indicates the character has moved on to the next one + */ + public void removeFirstAttackPart() { + this.nextAttackParts.remove(0); + } + public static int getCurrentHP() { return currentHP; } @@ -184,10 +200,74 @@ public class Character extends Entity { this.currentHP = currentHP; } + /** + * reduces the current hp of the character by a certain amount. + * @param dmg the amount of hp to reduce to the character's current hp + */ + public void reduceHP(int dmg) { + this.currentHP = this.currentHP - dmg; + } + /** * puts the character's current hp back to its max value */ public void resetCurrentHP() { this.currentHP = this.maxHP; } + + public Frame getHitInAirFrame() { + return hitInAirFrame; + } + + public void setHitInAirFrame(Frame hitInAirFrame) { + this.hitInAirFrame = hitInAirFrame; + } + + public Frame getFallingframe() { + return fallingframe; + } + + public void setFallingframe(Frame fallingframe) { + this.fallingframe = fallingframe; + } + + public Frame[] getKnockedDownFrames() { + return knockedDownFrames; + } + + public void setKnockedDownFrames(Frame[] knockedDownFrames) { + this.knockedDownFrames = knockedDownFrames; + } + + public Frame getStandGuardFrame() { + return standGuardFrame; + } + + public void setStandGuardFrame(Frame standGuardFrame) { + this.standGuardFrame = standGuardFrame; + } + + public Frame getCrouchGuardFrame() { + return crouchGuardFrame; + } + + public void setCrouchGuardFrame(Frame crouchGuardFrame) { + this.crouchGuardFrame = crouchGuardFrame; + } + + public Frame getStandHitFrame() { + return standHitFrame; + } + + public void setStandHitFrame(Frame standHitFrame) { + this.standHitFrame = standHitFrame; + } + + public Frame getCrouchHitFrame() { + return crouchHitFrame; + } + + public void setCrouchHitFrame(Frame crouchHitFrame) { + this.crouchHitFrame = crouchHitFrame; + } } diff --git a/src/gameplay/entities/Entity.java b/src/gameplay/entities/Entity.java index 57eda49..59bf224 100644 --- a/src/gameplay/entities/Entity.java +++ b/src/gameplay/entities/Entity.java @@ -53,7 +53,7 @@ public class Entity { public Frame getCurrentframe() {return this.frames.getCurrentFrame();} - public static nextFrameBuffer Frames() { + public static nextFrameBuffer getFrames() { return frames; } @@ -65,6 +65,8 @@ public class Entity { this.frames.emptyQueue(); } + public void goToNextFrames() { this.frames.goToNext();} + /** * adds frames to the character queue. * Warning : does not clear the queue first @@ -86,4 +88,6 @@ public class Entity { this.frames.addFrameToQueue(f.get(i)); } } + + } diff --git a/src/gameplay/frames/Frame.java b/src/gameplay/frames/Frame.java index 50ea8b9..6ab43a6 100644 --- a/src/gameplay/frames/Frame.java +++ b/src/gameplay/frames/Frame.java @@ -157,5 +157,28 @@ public class Frame { this.lastFrameOfHit = lastFrameOfHit; } + //Inverts all hitboxes of the frame horizontally. Used if the character looks to the left instead of the right + public void invertHitBoxes() { + for(Passive_HitBox p: this.passHitBox) {p.reverseHorizontally();} + for(Active_HitBox p: this.actHitBox) {p.reverseHorizontally();} + for(Passive_throw_HitBox p: this.passThrowHitBox) {p.reverseHorizontally();} + for(Active_throw_Hitbox p: this.actThrowHitBox) {p.reverseHorizontally();} + this.pushHitBox.reverseHorizontally(); + } + public void clone(Frame f) { + this.setMove_y(f.getMove_y()); + this.setMove_x(f.getMove_x()); + this.setPassHitBox(f.getPassHitBox()); + this.setActHitBox(f.getActHitBox()); + this.setPassThrowHitBox(f.getPassThrowHitBox()); + this.setActThrowHitBox(f.getActThrowHitBox()); + this.setPushHitBox(f.getPushHitBox()); + this.normalCancellable = f.isNormalCancellable(); + this.specialCancellable = f.isSpecialCancellable(); + this.jumpCancellable = f.jumpCancellable; + this.moveCancellable = f.isMoveCancellable(); + this.isDashCancellable = f.isDashCancellable; + this.lastFrameOfHit = islastFrameOfHit(); + } } diff --git a/src/gameplay/frames/nextFrameBuffer.java b/src/gameplay/frames/nextFrameBuffer.java index 2360a77..30b78fd 100644 --- a/src/gameplay/frames/nextFrameBuffer.java +++ b/src/gameplay/frames/nextFrameBuffer.java @@ -67,4 +67,5 @@ public class nextFrameBuffer { this.next.addFrameToQueue(f); } } + } diff --git a/src/gameplay/hitboxes/HitBox.java b/src/gameplay/hitboxes/HitBox.java index 55c706d..c6ded4d 100644 --- a/src/gameplay/hitboxes/HitBox.java +++ b/src/gameplay/hitboxes/HitBox.java @@ -120,4 +120,9 @@ public class HitBox { public void setSize_y(Double size_y) { this.size_y = size_y; } + + public void reverseHorizontally() { + this.position_x = 0 - position_x; + this.size_x = 0 - this.size_x; + } } \ No newline at end of file diff --git a/src/gameplay/input/InputBuffer.java b/src/gameplay/input/InputBuffer.java index 7b184da..c7323c8 100644 --- a/src/gameplay/input/InputBuffer.java +++ b/src/gameplay/input/InputBuffer.java @@ -138,5 +138,15 @@ public class InputBuffer { return ret; } + + /** + * Resets the inputbuffer. Clears every recorded input and puts the position back to 0. + */ + public void clear(){ + for(int i = 0; i < this.size; i++) { + this.inputList[i].clear(); + } + this.pos = 0; + } } diff --git a/src/gameplay/input/Inputs.java b/src/gameplay/input/Inputs.java index c5e2476..a013dfe 100644 --- a/src/gameplay/input/Inputs.java +++ b/src/gameplay/input/Inputs.java @@ -83,5 +83,14 @@ public class Inputs { } return s; } + + /** + * Clears the input (puts them all to false) + */ + public void clear(){ + for(int i = 0; i < numberOfInputs; i++) { + this.tab[i] = false; + } + } } diff --git a/src/gameplay/match/match.java b/src/gameplay/match/match.java index 8cb017c..7d19961 100644 --- a/src/gameplay/match/match.java +++ b/src/gameplay/match/match.java @@ -5,6 +5,7 @@ import engine.input.GamepadInput; import gameplay.actions.Attack; import gameplay.actions.attackPart; import gameplay.entities.Status; +import gameplay.frames.Frame; import gameplay.hitboxes.Active_HitBox; import gameplay.hitboxes.Passive_HitBox; import gameplay.input.InputBuffer; @@ -22,13 +23,18 @@ import static org.lwjgl.glfw.GLFW.*; * */ public class match { - + /** - * the number of inputs read for each character, a.k.a. for how many frames the inputs are saved in memory. + * 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 = 250; - private int timer; + private int timer; private InputBuffer inputsP1, inputsP2; private int roundsWonP1, roundsWonP2; private Character p1, p2; //characters of player 1 and 2 @@ -60,8 +66,8 @@ public class match { this.timer = 99; this.inputsP1 = new InputBuffer(inputBufferSize); this.inputsP2 = new InputBuffer(inputBufferSize); - this.p1.setPos(-500, 250); //TODO : change to better values if needed - this.p2.setPos(500, 250); //TODO : change to better values if needed + this.p1.setPos(-500, groundLevel); //TODO : change to better values if needed + this.p2.setPos(500, groundLevel); //TODO : change to better values if needed } /** @@ -144,11 +150,9 @@ public class match { nextFrame = false; if (engine.shouldClose()) engine.setRunning(false); } */ - int frame = 0; - boolean goToNextFrame = true; boolean Joystick1Present = glfwJoystickPresent(GLFW_JOYSTICK_1); boolean Joystick2Present = glfwJoystickPresent(GLFW_JOYSTICK_2); - match match = new match(new Character(),new Character()); //TOD0 : Change to not empty chars + match match = new match(new Character(),new Character()); //TODO : Change to not empty chars if (Joystick1Present) { gamepad1 = new GamepadInput(GLFW_JOYSTICK_1); @@ -214,6 +218,47 @@ public class match { case 21: handleThrows(); handleHits(p1,p2,inputsP2); + handleHits(p2,p1,inputsP1); + ac(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); + updatePos(p1); + updatePos(p2); + boolean p1LooksRight = p1.getPosX() < p2.getPosX(); + if(p1LooksRight) { + Frame f = new Frame(); + f.clone(p2.getCurrentframe()); + f.invertHitBoxes(); + p2.setCurrentFrame(f); + } else { + Frame f = new Frame(); + f.clone(p1.getCurrentframe()); + f.invertHitBoxes(); + p1.setCurrentFrame(f); + } + ac(23); + break; + + //Waits the end of 1/60th of a second since start of frame then loops back to start + case 23: + timeStamp2 = System.currentTimeMillis(); + while(timeStamp2-timeStamp1<(1000/60)) { + timeStamp2 = System.currentTimeMillis(); + } + frameCount++; + timeStamp1 = System.currentTimeMillis(); + ac(10); + break; } } @@ -322,7 +367,7 @@ public class match { boolean touchV = (aH.getPosY() - aH.getSize_y() < pH.getPosY()) && (aH.getPosY() > pH.getPosY() - pH.getSize_y()); if(touchH && touchV) { - if(p2.) + getHit(p2,hit,inputsP2.getLatestInputs()); hit.setHasHit(true); aP.set(0,hit); } @@ -332,4 +377,101 @@ public class match { } } + /** + * 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 void nextFrame(Character c, InputBuffer in) { + if(!c.getFrames().getNextframe().equals(null)){ + c.goToNextFrames(); + } else { + 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()); + } + default: + c.setStatus(Status.NORMAL); + if(in.getLatestInputs().containsInput(ButtonIG.DOWN)) { + c.addNextFrames(c.getDefaultCrouchingFrames()); + } else {c.addNextFrames(c.getDefaultStandingFrames());} + break; + } + } + } + + private void updatePos(Character c) { + c.setPos((int)(c.getPosX()+c.getCurrentframe().getMove_x()),(int)(c.getPosY()+c.getCurrentframe().getMove_y())); + } + }