2021-06-16 14:07:47 +02:00

610 lines
18 KiB
Java

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<Active_throw_Hitbox> activeP1 = new ArrayList<Active_throw_Hitbox>(
p1.getCurrentframe().getActThrowHitBox());
ArrayList<Passive_throw_HitBox> passiveP2 = new ArrayList<Passive_throw_HitBox>(
p2.getCurrentframe().getPassThrowHitBox());
ArrayList<ThrowPart> tP = new ArrayList<ThrowPart>(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<Active_HitBox> activeP1 = new ArrayList<Active_HitBox>(p1.getCurrentframe().getActHitBox());
ArrayList<Passive_HitBox> passiveP2 = new ArrayList<Passive_HitBox>(p2.getCurrentframe().getPassHitBox());
ArrayList<attackPart> aP = new ArrayList<attackPart>(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()));
}
}
}