feat: Player's Bow can now shoot Arrows

(physics need adjusting)
This commit is contained in:
Laureηt 2021-04-05 23:14:56 +02:00
parent caa6c614eb
commit d92730db13
10 changed files with 221 additions and 41 deletions

View file

@ -1,4 +1,4 @@
sourceCompatibility = 1.7 sourceCompatibility = 1.15
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8' [compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
sourceSets.main.java.srcDirs = [ "src/" ] sourceSets.main.java.srcDirs = [ "src/" ]

View file

@ -0,0 +1,89 @@
package bzh.fainsin.sagittarius;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Vector2;
class Arrow extends Entity {
// ---------- ATTRIBUTEs ----------
private Vector2 velocity = new Vector2();
private Vector2 acceleration = new Vector2();
private Vector2 force = new Vector2();
float TTL = 20;
private final float length = 100;
// ---------- CONSTRUCTORs ----------
Arrow(float angle, float power, Player shooter) {
super(shooter.position, 1);
this.velocity = new Vector2(power, 0).setAngleDeg(angle);
this.acceleration = new Vector2();
this.force = computeForce();
}
// ---------- METHODs ----------
private Vector2 computeForce() {
Vector2 force = new Vector2();
for (Planet attractor : SagittariusGame.planetList) {
Vector2 diff = attractor.position.cpy().sub(this.position);
Vector2 attraction = diff.scl( SagittariusGame.G * attractor.mass / diff.len2() );
force.add(attraction);
}
return force;
}
private boolean hasLanded() {
for (Planet planet : SagittariusGame.planetList) {
if (this.distanceTo(planet) < planet.getRadius()) {
return true;
}
}
return false;
}
void update(float deltaTime) {
if (!this.hasLanded()) {
integrationVerlet(deltaTime);
this.TTL -= deltaTime;
this.angle = this.velocity.angleRad();
}
}
private void integrationVerlet(float deltaTime) {
// Verlet integration
// https://gamedev.stackexchange.com/questions/15708/how-can-i-implement-gravity/41917#41917
// TODO : vectorialiser
this.acceleration = this.force.cpy();
this.position.x += deltaTime * ( this.velocity.x + deltaTime * this.acceleration.x / 2 );
this.position.y += deltaTime * ( this.velocity.y + deltaTime * this.acceleration.y / 2 );
this.force = computeForce();
this.velocity.x += deltaTime * ( this.acceleration.x + this.force.x ) / 2;
this.velocity.y += deltaTime * ( this.acceleration.y + this.force.y ) / 2;
}
void render(ShapeRenderer shapeRenderer) {
Vector2 tail = new Vector2(-this.length, 0).rotateRad(this.angle).add(this.position);
shapeRenderer.line(this.position, tail);
}
void renderDebug(Batch batch, BitmapFont font) {
font.draw(batch, "TTL = " + this.TTL, this.position.x, this.position.y + font.getCapHeight()*5);
font.draw(batch, "pos = " + this.position, this.position.x, this.position.y + font.getCapHeight()*4);
font.draw(batch, "speed = " + this.velocity, this.position.x, this.position.y + font.getCapHeight()*3);
font.draw(batch, "accel = " + this.acceleration, this.position.x, this.position.y + font.getCapHeight()*2);
font.draw(batch, "force = " + this.force, this.position.x, this.position.y + font.getCapHeight()*1);
font.draw(batch, "angle = " + this.angle, this.position.x, this.position.y);
}
}

View file

@ -0,0 +1,63 @@
package bzh.fainsin.sagittarius;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Buttons;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
class Bow {
// ---------- ATTRIBUTEs ----------
private Player shooter;
private boolean aimAssist = false;
private boolean pressed = false;
private float angle;
private Vector2 anchor;
private Vector2 aim;
private float power;
// ---------- CONSTRUCTORs ----------
Bow(Player shooter, boolean aimAssist) {
this.shooter = shooter;
this.aimAssist = aimAssist;
}
// ---------- METHODs ----------
void update(double deltaTime) {
if (Gdx.input.isButtonJustPressed(Buttons.LEFT) && !pressed) {
this.anchor = SagittariusGame.worldCursor.cpy();
pressed = true;
} else if (Gdx.input.isButtonPressed(Buttons.LEFT) && pressed) {
computeArrow();
} else if (pressed) {
SagittariusGame.arrowList.add(getArrow());
pressed = false;
}
}
private Arrow getArrow() {
return new Arrow(angle, power, shooter);
}
private void computeArrow() {
aim = this.anchor.cpy().sub(SagittariusGame.worldCursor);
angle = aim.angleDeg();
power = MathUtils.clamp(aim.len(), 0, 1000);
}
public void render(ShapeRenderer shapeRenderer) {
if (pressed) {
shapeRenderer.line(this.anchor, SagittariusGame.worldCursor);
//shapeRenderer.polyline(traj);
}
}
}

View file

@ -16,29 +16,10 @@ abstract class Entity {
// ---------- CONSTRUCTORs ---------- // ---------- CONSTRUCTORs ----------
protected Entity(Vector2 position, float mass) { protected Entity(Vector2 position, float mass) {
this.position = position; this.position = position.cpy();
this.mass = mass; this.mass = mass;
} }
// ---------- GETs ----------
Vector2 getPosition() {
return this.position;
}
float getMass() {
return this.mass;
}
float getAngle() {
return this.angle;
}
Color getColor() {
return this.color;
}
// ---------- METHODs ---------- // ---------- METHODs ----------
/** /**
@ -47,7 +28,7 @@ abstract class Entity {
* @return distance to entity * @return distance to entity
*/ */
float distanceTo(Entity entity) { float distanceTo(Entity entity) {
return this.position.sub(entity.getPosition()).len(); return this.position.cpy().sub(entity.position).len();
} }
} }

View file

@ -39,17 +39,17 @@ class GameScreen extends ScreenAdapter {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
} }
private void update(float delta) { private void update(float deltaTime) {
SagittariusGame.update(delta); SagittariusGame.update(deltaTime);
hud.update(); hud.update();
camera.position.set(WIDTH / 2, HEIGHT / 2, 0); camera.position.set(WIDTH / 2, HEIGHT / 2, 0);
camera.update(); camera.update();
} }
@Override @Override
public void render(float delta) { public void render(float deltaTime) {
update(delta); update(deltaTime);
clearScreen(); clearScreen();
@ -67,6 +67,11 @@ class GameScreen extends ScreenAdapter {
player.renderDebug(batch, font); player.renderDebug(batch, font);
} }
// arrows
for (Arrow arrow : SagittariusGame.arrowList) {
arrow.renderDebug(batch, font);
}
batch.end(); batch.end();
// ---------- shapeRenderer ---------- // ---------- shapeRenderer ----------
@ -83,6 +88,11 @@ class GameScreen extends ScreenAdapter {
player.render(shapeRenderer); player.render(shapeRenderer);
} }
// arrows
for (Arrow arrow : SagittariusGame.arrowList) {
arrow.render(shapeRenderer);
}
shapeRenderer.end(); shapeRenderer.end();
// HUD // HUD

View file

@ -23,7 +23,14 @@ class HUD implements Disposable {
public void render() { public void render() {
batch.begin(); batch.begin();
// framerate
font.draw(batch, frameRate + " fps", 3, Gdx.graphics.getHeight() - 3); font.draw(batch, frameRate + " fps", 3, Gdx.graphics.getHeight() - 3);
// cursor positions
font.draw(batch, "x_r = " + (int) SagittariusGame.screenCursor.x + ", y_r = " + (int) SagittariusGame.screenCursor.y, SagittariusGame.screenCursor.x + 5, Gdx.graphics.getHeight() - SagittariusGame.screenCursor.y + 5);
font.draw(batch, "x_g = " + (int) SagittariusGame.worldCursor.x + ", y_g = " + (int) SagittariusGame.worldCursor.y, SagittariusGame.screenCursor.x + 5, Gdx.graphics.getHeight() - SagittariusGame.screenCursor.y + 20);
batch.end(); batch.end();
} }

View file

@ -6,45 +6,59 @@ import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector2;
public class Player extends Entity { class Player extends Entity {
// ---------- ATTRIBUTEs ---------- // ---------- ATTRIBUTEs ----------
private Planet home; private Planet home;
private final float width = 50; private final float width = 50;
private final float height = 100; private final float height = 100;
private Bow bow;
private Vector2 positionBottom = new Vector2(); // TODO : reorganize, center of mass....
// ---------- CONSTRUCTORs ---------- // ---------- CONSTRUCTORs ----------
Player(Planet home) { Player(Planet home) {
super(new Vector2(), 1); super(home.position, 1);
this.home = home; this.home = home;
this.bow = new Bow(this, false);
this.angle = 45; // TODO : tmp
} }
// ---------- METHODs ---------- // ---------- METHODs ----------
void render(ShapeRenderer shapeRenderer) { void render(ShapeRenderer shapeRenderer) {
shapeRenderer.setColor(color); shapeRenderer.setColor(color);
shapeRenderer.rect(position.x, position.y, width/2, 0, width, height, 1, 1, angle-90); shapeRenderer.rect(positionBottom.x - width/2, positionBottom.y, width/2, 0, width, height, 1, 1, angle-90);
this.bow.render(shapeRenderer);
} }
void renderDebug(Batch batch, BitmapFont font) { void renderDebug(Batch batch, BitmapFont font) {
font.draw(batch, "x = " + (int) position.x + ", y = " + (int) position.y, position.x, position.y); font.draw(batch, "x = " + (int) position.x + ", y = " + (int) position.y, position.x, position.y);
} }
void update(float delta) { void update(float deltaTime) {
computePosition(); computePosition();
this.angle += 100.0f / home.getRadius(); bow.update(deltaTime);
// this.angle += 100.0f / home.getRadius(); // TODO : debug, remove later
} }
void computePosition() { void computePosition() {
Vector2 homePosition = this.home.getPosition(); Vector2 homePosition = this.home.position;
float homeRadius = this.home.getRadius(); float homeRadius = this.home.getRadius();
this.position.x = homePosition.x + homeRadius*MathUtils.cosDeg(angle) - width/2; this.position.x = homePosition.x + (homeRadius + height/2)*MathUtils.cosDeg(angle);
this.position.y = homePosition.y + homeRadius*MathUtils.sinDeg(angle); this.position.y = homePosition.y + (homeRadius + height/2)*MathUtils.sinDeg(angle); // TODO, faire des opérations vectorielles ?
this.positionBottom.x = homePosition.x + homeRadius*MathUtils.cosDeg(angle);
this.positionBottom.y = homePosition.y + homeRadius*MathUtils.sinDeg(angle);
}
Planet getHome() {
return this.home;
} }
} }

View file

@ -1,6 +1,7 @@
package bzh.fainsin.sagittarius; package bzh.fainsin.sagittarius;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator;
import com.badlogic.gdx.Game; import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
@ -12,6 +13,9 @@ public class SagittariusGame extends Game {
// ---------- ATTRIBUTEs ---------- // ---------- ATTRIBUTEs ----------
// Constants
static final int G = 100;
// Vectors // Vectors
static Vector2 screenCursor; static Vector2 screenCursor;
static Vector2 worldCursor; static Vector2 worldCursor;
@ -19,6 +23,7 @@ public class SagittariusGame extends Game {
// Entities // Entities
static ArrayList<Planet> planetList; static ArrayList<Planet> planetList;
static ArrayList<Player> playerList; static ArrayList<Player> playerList;
static ArrayList<Arrow> arrowList;
// ---------- METHODs ---------- // ---------- METHODs ----------
@ -27,15 +32,17 @@ public class SagittariusGame extends Game {
setScreen(new GameScreen()); setScreen(new GameScreen());
planetList = new ArrayList<Planet>(); planetList = new ArrayList<Planet>();
planetList.add( new Planet(new Vector2(100, 100), 1, 50) ); planetList.add( new Planet(new Vector2(400, 400), 1000, 50) );
planetList.add( new Planet(new Vector2(400, 400), 1, 100, Color.CYAN) ); planetList.add( new Planet(new Vector2(1000, 400), 1000, 100, Color.CYAN) );
playerList = new ArrayList<Player>(); playerList = new ArrayList<Player>();
playerList.add( new Player(planetList.get(0)) ); playerList.add( new Player(planetList.get(0)) );
playerList.add( new Player(planetList.get(1)) );
arrowList = new ArrayList<Arrow>();
} }
static void update(float delta) { static void update(float deltaTime) {
// cursors // cursors
screenCursor = new Vector2(Gdx.input.getX(), Gdx.input.getY()); screenCursor = new Vector2(Gdx.input.getX(), Gdx.input.getY());
@ -44,7 +51,16 @@ public class SagittariusGame extends Game {
// players // players
for (Player player : playerList) { for (Player player : playerList) {
player.update(delta); player.update(deltaTime);
}
// arrows
for (Iterator<Arrow> it = arrowList.iterator(); it.hasNext(); ) {
Arrow arrow = it.next();
arrow.update(deltaTime);
if (arrow.TTL <= 0) {
it.remove();
}
} }
} }

View file

@ -1,4 +1,4 @@
sourceCompatibility = 1.7 sourceCompatibility = 1.15
sourceSets.main.java.srcDirs = [ "src/" ] sourceSets.main.java.srcDirs = [ "src/" ]
sourceSets.main.resources.srcDirs = ["../core/assets"] sourceSets.main.resources.srcDirs = ["../core/assets"]

View file

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists