Merge branch 'Gameplay' into 'master'
Merge of Gameplay into Master See merge request fautin/jeu-de-combat!6
This commit is contained in:
commit
b98d1908f6
7
.classpath
Normal file
7
.classpath
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="GamePlay"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
17
GamePlay/Actions/Attack.java
Normal file
17
GamePlay/Actions/Attack.java
Normal file
@ -0,0 +1,17 @@
|
||||
package Actions;
|
||||
import input.*;
|
||||
|
||||
public class Attack {
|
||||
/**
|
||||
* Defines if the attack is a special one (E.G. a fireball) or a normal one (a punch)
|
||||
*/
|
||||
private static boolean isSpecial;
|
||||
|
||||
/**
|
||||
* The suite of Inputs to have the move come out.
|
||||
* For example, a classic fireball would be something like
|
||||
* {{DOWN},{DOWN,RIGHT},{RIGHT},{A}}
|
||||
*/
|
||||
private static Button[][] command;
|
||||
|
||||
}
|
31
GamePlay/Entities/Character.java
Normal file
31
GamePlay/Entities/Character.java
Normal file
@ -0,0 +1,31 @@
|
||||
package Entities;
|
||||
|
||||
import Frames.Frame;
|
||||
|
||||
/**
|
||||
* Character class, which is a sub-class of an entity
|
||||
* @author Victor
|
||||
*
|
||||
*/
|
||||
public class Character extends Entity {
|
||||
private static int maxHP;
|
||||
|
||||
/**
|
||||
* Main constructor for a character. By default its max health is 1000 if not specified
|
||||
*/
|
||||
public Character() {
|
||||
super();
|
||||
this.maxHP = 1000;
|
||||
}
|
||||
|
||||
public Character(int posx, int posy, Frame f, int maxHP) {
|
||||
super(posx, posy, f);
|
||||
this.maxHP = maxHP;
|
||||
}
|
||||
|
||||
public void setMaxHP(int HP) {
|
||||
this.maxHP = HP;
|
||||
}
|
||||
|
||||
public int getMaxHP() { return this.getMaxHP();}
|
||||
}
|
50
GamePlay/Entities/Entity.java
Normal file
50
GamePlay/Entities/Entity.java
Normal file
@ -0,0 +1,50 @@
|
||||
package Entities;
|
||||
|
||||
import Frames.Frame;
|
||||
|
||||
/**
|
||||
* Entity class, which is the main class regrouping characters and projectiles
|
||||
* @author Victor
|
||||
*
|
||||
*/
|
||||
public class Entity {
|
||||
private int posx;
|
||||
private int posy;
|
||||
private Frame currentFrame;
|
||||
|
||||
/**
|
||||
* base constructor of the entity class
|
||||
*/
|
||||
public Entity() {
|
||||
this.posx = 0;
|
||||
this.posy = 0;
|
||||
this.currentFrame = new Frame();
|
||||
}
|
||||
|
||||
/**
|
||||
* constructor of the entity class with parameters
|
||||
* @param posx the position of the entity on the x axis
|
||||
* @param posy the position of the entity on the y axis
|
||||
* @param f the current frame of the new entity
|
||||
*/
|
||||
public Entity(int posx, int posy, Frame f) {
|
||||
this.posx = posx;
|
||||
this.posy = posy;
|
||||
this.currentFrame = f;
|
||||
}
|
||||
|
||||
public void setPos(int x, int y) {
|
||||
this.posx = x;
|
||||
this.posy = y;
|
||||
}
|
||||
|
||||
public void setCurrentFrame(Frame f) {
|
||||
this.currentFrame = f;
|
||||
}
|
||||
|
||||
public int getPosX() {return this.posx;}
|
||||
|
||||
public int getPosY() {return this.posy;}
|
||||
|
||||
public Frame getCurrentframe() {return this.currentFrame;}
|
||||
}
|
4
GamePlay/Entities/Projectile.java
Normal file
4
GamePlay/Entities/Projectile.java
Normal file
@ -0,0 +1,4 @@
|
||||
package Entities;
|
||||
|
||||
public class Projectile extends Entity{
|
||||
}
|
55
GamePlay/Frames/Frame.java
Normal file
55
GamePlay/Frames/Frame.java
Normal file
@ -0,0 +1,55 @@
|
||||
package Frames;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import Hitboxes.*;
|
||||
/**
|
||||
* Main class for frames
|
||||
* @author Victor Azra
|
||||
*
|
||||
*/
|
||||
public class Frame {
|
||||
|
||||
private Double move_y;
|
||||
private Double move_x;
|
||||
private ArrayList<Passive_HitBox> passHitBox;
|
||||
private ArrayList<Active_HitBox> actHitBox;
|
||||
private ArrayList<Passive_throw_HitBox> passThrowHitBox;
|
||||
private ArrayList<Active_throw_Hitbox> actThrowHitBox;
|
||||
private Push_HitBox pushHitBox;
|
||||
|
||||
public Frame() {
|
||||
this.move_y = 0.0;
|
||||
this.move_x = 0.0;
|
||||
this.passHitBox = new ArrayList<Passive_HitBox>();
|
||||
this.actHitBox = new ArrayList<Active_HitBox>();
|
||||
this.passThrowHitBox = new ArrayList<Passive_throw_HitBox>();
|
||||
this.actThrowHitBox = new ArrayList<Active_throw_Hitbox>();
|
||||
this.pushHitBox = new Push_HitBox();
|
||||
}
|
||||
|
||||
public Frame(Double move_y, Double move_x, ArrayList<Passive_HitBox> passHitBox, ArrayList<Active_HitBox> actHitBox,
|
||||
ArrayList<Passive_throw_HitBox> passThrowHitBox, ArrayList<Active_throw_Hitbox> actThrowHitBox,
|
||||
Push_HitBox pushHitBox) {
|
||||
this.move_y = move_y;
|
||||
this.move_x = move_x;
|
||||
this.passHitBox = passHitBox;
|
||||
this.actHitBox = actHitBox;
|
||||
this.passThrowHitBox = passThrowHitBox;
|
||||
this.actThrowHitBox = actThrowHitBox;
|
||||
this.pushHitBox = pushHitBox;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mainly use for projectiles
|
||||
*/
|
||||
public Frame(Double move_y, Double move_x, ArrayList<Passive_HitBox> passHitBox, ArrayList<Active_HitBox> actHitBox) {
|
||||
this.move_y = move_y;
|
||||
this.move_x = move_x;
|
||||
this.passHitBox = passHitBox;
|
||||
this.actHitBox = actHitBox;
|
||||
this.passThrowHitBox = new ArrayList<Passive_throw_HitBox>();
|
||||
this.actThrowHitBox = new ArrayList<Active_throw_Hitbox>();
|
||||
this.pushHitBox = new Push_HitBox();
|
||||
}
|
||||
|
||||
}
|
70
GamePlay/Frames/nextFrameBuffer.java
Normal file
70
GamePlay/Frames/nextFrameBuffer.java
Normal file
@ -0,0 +1,70 @@
|
||||
package Frames;
|
||||
|
||||
/**
|
||||
* This will handle the next frames to be played by each entity.
|
||||
* @author Victor Azra
|
||||
*/
|
||||
public class nextFrameBuffer {
|
||||
|
||||
private Frame current;
|
||||
private nextFrameBuffer next;
|
||||
|
||||
/**
|
||||
* creates a new framebuffer, empty for now
|
||||
*/
|
||||
public nextFrameBuffer() {
|
||||
this.current = null;
|
||||
this.next = null;
|
||||
}
|
||||
|
||||
public void setCurrentFrame(Frame f) {
|
||||
this.current = f;
|
||||
}
|
||||
|
||||
public void clone(nextFrameBuffer f) {
|
||||
this.current = f.current;
|
||||
this.next = f.next;
|
||||
}
|
||||
|
||||
public void setNext(nextFrameBuffer f) {
|
||||
this.next.clone(f);
|
||||
}
|
||||
|
||||
public void emptyQueue() {
|
||||
this.next = null;
|
||||
}
|
||||
|
||||
public void empty() {
|
||||
this.current = null;
|
||||
this.next = null;
|
||||
}
|
||||
|
||||
public void goToNext() {
|
||||
this.current = this.next.current;
|
||||
this.next = this.next.next;
|
||||
}
|
||||
|
||||
public Frame getCurrentFrame() {
|
||||
return this.current;
|
||||
}
|
||||
|
||||
public Frame getNextframe() {
|
||||
return this.next.current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a frame at the end of the buffer
|
||||
* @param f the frame to add at the end
|
||||
*/
|
||||
public void addFrameToQueue(Frame f) {
|
||||
if(this.current == null) {
|
||||
this.current = f;
|
||||
} else if(this.next == null){
|
||||
nextFrameBuffer fb = new nextFrameBuffer();
|
||||
fb.current = f;
|
||||
this.next = fb;
|
||||
} else {
|
||||
this.next.addFrameToQueue(f);
|
||||
}
|
||||
}
|
||||
}
|
5
GamePlay/Hitboxes/Active_HitBox.java
Normal file
5
GamePlay/Hitboxes/Active_HitBox.java
Normal file
@ -0,0 +1,5 @@
|
||||
package Hitboxes;
|
||||
|
||||
public class Active_HitBox extends HitBox {
|
||||
|
||||
}
|
5
GamePlay/Hitboxes/Active_throw_Hitbox.java
Normal file
5
GamePlay/Hitboxes/Active_throw_Hitbox.java
Normal file
@ -0,0 +1,5 @@
|
||||
package Hitboxes;
|
||||
|
||||
public class Active_throw_Hitbox extends HitBox {
|
||||
|
||||
}
|
100
GamePlay/Hitboxes/HitBox.java
Normal file
100
GamePlay/Hitboxes/HitBox.java
Normal file
@ -0,0 +1,100 @@
|
||||
package Hitboxes;
|
||||
|
||||
public class HitBox {
|
||||
|
||||
private Double position_x;
|
||||
private Double position_y;
|
||||
private Double size_x;
|
||||
private Double size_y;
|
||||
|
||||
public HitBox() {
|
||||
this.position_x = 0.0;
|
||||
this.position_y = 0.0;
|
||||
this.size_x = 0.0;
|
||||
this.size_y = 0.0;
|
||||
}
|
||||
|
||||
public void setPosition_x(Double position_x){
|
||||
this.position_x = position_x;
|
||||
}
|
||||
|
||||
public void setPosition_y(Double position_y){
|
||||
this.position_y = position_y;
|
||||
}
|
||||
|
||||
public HitBox(Double position_x, Double position_y, Double size_x, Double size_y) {
|
||||
|
||||
if(position_x < 0.0) {
|
||||
position_x = 0.0;
|
||||
}else if(position_x > 1.0) {
|
||||
position_x = 1.0;
|
||||
}
|
||||
this.position_x = position_x;
|
||||
|
||||
if(position_y < 0.0) {
|
||||
position_y = 0.0;
|
||||
}else if(position_y > 1.0) {
|
||||
position_y = 1.0;
|
||||
}
|
||||
this.position_y = position_y;
|
||||
|
||||
if(size_x < 0.0) {
|
||||
size_x = 0.0;
|
||||
}else if(size_x > 1.0) {
|
||||
size_x = 1.0;
|
||||
}
|
||||
this.size_x = size_x;
|
||||
|
||||
if(size_y < 0.0) {
|
||||
size_y = 0.0;
|
||||
}else if(size_y > 1.0) {
|
||||
size_y = 1.0;
|
||||
}
|
||||
this.size_y = size_y;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* @param hb an Hitbox
|
||||
* @return true if HitBox overlap else return false
|
||||
*/
|
||||
public Boolean hit(HitBox hb) {
|
||||
Boolean horiz = false;
|
||||
Boolean ver = false;
|
||||
Double horizontal1 = this.position_x + this.size_x;
|
||||
Double vertical1 = this.position_y + this.size_y;
|
||||
Double horizontal2 = hb.position_x + hb.size_x;
|
||||
Double vertical2 = hb.position_y + hb.size_y;
|
||||
|
||||
|
||||
/*
|
||||
* HitBox overlap horizontally
|
||||
*/
|
||||
if(this.position_x < hb.position_x) { //this is at left of hb
|
||||
if(hb.position_x < horizontal1) {
|
||||
horiz = true;
|
||||
}
|
||||
}else {//this is at left of hb
|
||||
if(this.position_x < horizontal2) {
|
||||
horiz = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* HitBox overlap vertically
|
||||
*/
|
||||
if(this.position_y < hb.position_y) { //this is at top of hb
|
||||
if(hb.position_y < vertical1) {
|
||||
ver = true;
|
||||
}
|
||||
}else {//this is at left of hb
|
||||
if(this.position_x < vertical2) {
|
||||
ver = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return horiz && ver;
|
||||
}
|
||||
|
||||
}
|
5
GamePlay/Hitboxes/Passive_HitBox.java
Normal file
5
GamePlay/Hitboxes/Passive_HitBox.java
Normal file
@ -0,0 +1,5 @@
|
||||
package Hitboxes;
|
||||
|
||||
public class Passive_HitBox extends HitBox {
|
||||
|
||||
}
|
5
GamePlay/Hitboxes/Passive_throw_HitBox.java
Normal file
5
GamePlay/Hitboxes/Passive_throw_HitBox.java
Normal file
@ -0,0 +1,5 @@
|
||||
package Hitboxes;
|
||||
|
||||
public class Passive_throw_HitBox extends HitBox {
|
||||
|
||||
}
|
13
GamePlay/Hitboxes/Push_HitBox.java
Normal file
13
GamePlay/Hitboxes/Push_HitBox.java
Normal file
@ -0,0 +1,13 @@
|
||||
package Hitboxes;
|
||||
|
||||
public class Push_HitBox extends HitBox {
|
||||
|
||||
public Push_HitBox() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Push_HitBox(Double position_x, Double position_y, Double size_x, Double size_y) {
|
||||
super(position_x, position_y, size_x, size_y);
|
||||
}
|
||||
|
||||
}
|
0
GamePlay/Match/.gitignore
vendored
Normal file
0
GamePlay/Match/.gitignore
vendored
Normal file
41
GamePlay/Match/match.java
Normal file
41
GamePlay/Match/match.java
Normal file
@ -0,0 +1,41 @@
|
||||
package Match;
|
||||
|
||||
import input.InputBuffer;
|
||||
import Entities.*;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
private int timer;
|
||||
private InputBuffer inputsP1, inputsP2;
|
||||
private int hpP1, hpP2;
|
||||
private int roundsWonP1, roundsWonP2;
|
||||
private Entities.Character p1, p2; //characters of player 1 and 2
|
||||
|
||||
/**
|
||||
* base constructor of the match class.
|
||||
* Initiates a new match with with two given characters
|
||||
*/
|
||||
public match(Entities.Character p1, Entities.Character p2) {
|
||||
this.timer = 99;
|
||||
this.inputsP1 = new input.InputBuffer(inputBufferSize);
|
||||
this.inputsP2 = new input.InputBuffer(inputBufferSize);
|
||||
this.p1 = p1;
|
||||
this.p2 = p2;
|
||||
this.hpP1 = p1.getMaxHP();
|
||||
this.hpP2 = p2.getMaxHP();
|
||||
this.roundsWonP1 = 0;
|
||||
this.roundsWonP2 = 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
19
GamePlay/input/Button.java
Normal file
19
GamePlay/input/Button.java
Normal file
@ -0,0 +1,19 @@
|
||||
package input;
|
||||
|
||||
public enum Button {
|
||||
UP, DOWN, LEFT, RIGHT, A, B, C, D;
|
||||
|
||||
public int toInt() {
|
||||
switch (this) {
|
||||
case UP : return 0;
|
||||
case DOWN : return 1;
|
||||
case LEFT : return 2;
|
||||
case RIGHT : return 3;
|
||||
case A : return 4;
|
||||
case B : return 5;
|
||||
case C : return 6;
|
||||
case D : return 7;
|
||||
default : return -1;
|
||||
}
|
||||
}
|
||||
}
|
80
GamePlay/input/InputBuffer.java
Normal file
80
GamePlay/input/InputBuffer.java
Normal file
@ -0,0 +1,80 @@
|
||||
package input;
|
||||
|
||||
public class InputBuffer {
|
||||
|
||||
/**
|
||||
* a list of various inputs being recorded, such as inputs pressed at each frame
|
||||
* Each element is a tab where each element represent a possible input
|
||||
* (UP, Down, Right, Left, A, B, C, D)
|
||||
* if the value at the corresponding index is true, then the input is pressed
|
||||
* By default, no input is pressed.
|
||||
*/
|
||||
private Inputs[] inputList;
|
||||
|
||||
/*
|
||||
* the size of the input buffer
|
||||
*/
|
||||
private int size;
|
||||
|
||||
/*
|
||||
* the current position in the tab of the last newest input recorded
|
||||
* This should never bee accessed outside of this class.
|
||||
*/
|
||||
private int pos;
|
||||
|
||||
|
||||
/**
|
||||
* base constructor of the InputBuffer. Creates a buffer of size 1, with every input empty
|
||||
*/
|
||||
public InputBuffer() {
|
||||
this.size = 1;
|
||||
this.pos = 0;
|
||||
this.inputList = new Inputs[1];
|
||||
}
|
||||
|
||||
public InputBuffer(int size) {
|
||||
this.size = size;
|
||||
this.pos = 0;
|
||||
this.inputList = new Inputs[this.size];
|
||||
|
||||
for(int i = 0; i < this.size; i++) {
|
||||
this.inputList[i] = new Inputs();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return the latest added inputs
|
||||
*/
|
||||
public Inputs getLatestInputs() {
|
||||
return this.inputList[this.pos];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the last input without moving the current position
|
||||
* @param inputs
|
||||
*/
|
||||
private void setLatestInputs(Inputs inputs) {
|
||||
this.inputList[pos] = inputs;
|
||||
}
|
||||
|
||||
/**
|
||||
* advances the current position to the next one (goes back to the first if at the end
|
||||
*/
|
||||
private void nextPos() {
|
||||
this.pos++;
|
||||
if(this.pos == size) {this.pos = 0;}
|
||||
}
|
||||
|
||||
/**
|
||||
* record a new input in the
|
||||
* @param inputs a size 8 tab of inputs
|
||||
*/
|
||||
private void recordInputs(Inputs inputs) {
|
||||
this.nextPos();
|
||||
this.setLatestInputs(inputs);
|
||||
}
|
||||
}
|
||||
|
66
GamePlay/input/Inputs.java
Normal file
66
GamePlay/input/Inputs.java
Normal file
@ -0,0 +1,66 @@
|
||||
package input;
|
||||
|
||||
/**
|
||||
* The class handling the parsing of one input.
|
||||
* @author Victor
|
||||
*
|
||||
*/
|
||||
public class Inputs {
|
||||
private static final int numberOfInputs = 8;
|
||||
private static boolean[] tab;
|
||||
|
||||
public Inputs() {
|
||||
this.tab = new boolean[numberOfInputs];
|
||||
for(int i = 0; i < numberOfInputs; i ++) {
|
||||
this.tab[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* record one input
|
||||
* @param i the integer value corresponding to the tab location
|
||||
*/
|
||||
public void recordOneInput(Button b) {
|
||||
int i = b.toInt();
|
||||
this.tab[i] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a specific input (for example UP) has been recorded
|
||||
* @param i the integer value corresponding to the input
|
||||
* @return
|
||||
*/
|
||||
public boolean containsInput(Button b) {
|
||||
return this.tab[b.toInt()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a number of inputs are contained simultaneously
|
||||
* @param in a number of inputs. Check if those are containes in this
|
||||
* @return true if all inputs of in are also in this
|
||||
*/
|
||||
public boolean containsInputs(Inputs in) {
|
||||
for(int i = 0; i < numberOfInputs; i++) {
|
||||
if(this.tab[i] != in.getInputs()[i]) {return false;}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a number of inputs are contained simultaneously, in the form of an array of Buttons
|
||||
* @param bs a number of inputs. Check if those are contained in this
|
||||
* @return true if all inputs of in are also in this
|
||||
*/
|
||||
public boolean containsButtonTab(Button[] bs) {
|
||||
for(int i = 0; i < bs.length; i++) {
|
||||
if(!this.containsInput(bs[i])) { return false;}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean[] getInputs() {
|
||||
return this.tab;
|
||||
}
|
||||
|
||||
|
||||
}
|
BIN
docs/class-diagram.jpeg
Normal file
BIN
docs/class-diagram.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 128 KiB |
1
docs/gameplay_loop.drawio
Normal file
1
docs/gameplay_loop.drawio
Normal file
@ -0,0 +1 @@
|
||||
<mxfile host="app.diagrams.net" modified="2021-05-16T13:25:42.623Z" agent="5.0 (X11)" etag="YzwQWMtaXkj075fu6hOE" version="14.6.13" type="device"><diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1">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</diagram></mxfile>
|
BIN
docs/gameplay_loop.png
Normal file
BIN
docs/gameplay_loop.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 400 KiB |
Loading…
x
Reference in New Issue
Block a user