[Change] Refactored Animation

[Add] Documentation Comments.
This commit is contained in:
Ritchie Cunningham 2022-03-07 23:07:57 +00:00
parent 9f7127d9bd
commit e150b70113
20 changed files with 610 additions and 236 deletions

View File

@ -7,5 +7,6 @@
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Users/user/Downloads/jsfml/jsfml.jar"/>
<classpathentry kind="src" path="Bruh_Example"/>
<classpathentry kind="output" path="bin"/>
</classpath>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
bin/tfg/TextUIElement.class Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

164
src/tfg/AnimatedSprite.java Normal file
View File

@ -0,0 +1,164 @@
package tfg;
import org.jsfml.graphics.IntRect;
import org.jsfml.graphics.Sprite;
import org.jsfml.system.Vector2f;
import org.jsfml.system.Vector2i;
/**
* A sprite that supports animation.
* @author Ritchie Cunningham
*/
public class AnimatedSprite {
/**
* Speed of animation in Hz.
*/
private final float animationSpeed = 15;
/**
* The frame (stage) in the animation.
*/
private int animationFrame = 0;
/**
* Keeps track of time between frame changes.
*/
private int frameCounter = 0;
/**
* Whether or not the sprite is currently animated.
*/
private boolean animating = false;
/**
* The position at which the sprite is rendered.
*/
private Vector2f spritePosition = new Vector2f(0,0);
/**
* The sprite to animate.
*/
private Sprite animatedSprite;
/**
* Location of the entity this sprite represents.
*/
private Location entityLoc;
/**
* Size of the sprite.
*/
private final Vector2i spriteSize = new Vector2i(32, 48);
/**
* Create a new animated sprite.
* @param s The sprite to animate.
* @param l The location of the entity the sprite represents.
*/
public AnimatedSprite(Sprite s, Location l) {
animatedSprite = s;
entityLoc = l;
}
/**
* Start the animation.
*/
public void startWalkingAnimation() {
startAnimation();
}
/**
* Update animation.
*/
public void animate() {
if(animating) { /* Then update animation. */
if(frameCounter >= animationSpeed) { /* If 15Hz has passed. */
stopAnimation();
} else {
/* Get the position between old and new. */
spritePosition = entityLoc.interpolate(animationSpeed, frameCounter);
Vector2i entityPos = entityLoc.getPosition(); /* Get the entity position. */
/* Subtract new position from starting position to get a number from 0.0 - 1.0. */
Vector2f animationProgress =
Vector2f.sub(spritePosition, new Vector2f(entityPos.x,entityPos.y));
/* Take the abs value because we're measuring distance. */
float change = Math.abs(animationProgress.x+animationProgress.y);
/* Determine frame based on position. */
if(change >= 0.f && change < .25f) {
animationFrame = 0;
} else if(change >= .25f && change < .5f) {
animationFrame = 1;
} else if(change >=.5f && change < .75f) {
animationFrame = 2;
} else if(change >= .75f && change <= 1.0f) {
animationFrame = 3;
}
}
frameCounter++; /* Increment on each update to keep track of time. */
}
}
/**
* Stop the animation.
*/
private void stopAnimation() {
/* Reset the following. */
animating = false;
frameCounter = 0;
animationFrame = 0;
}
/**
* Start the animation.
*/
private void startAnimation() {
animating = true;
}
/**
* Determine whether or not the animation completed.
* @return If the animation finished.
*/
public boolean finishedAnimating() {
return !animating;
}
/**
* Update the entity position.
* @param l The new location.
*/
public void updatePosition(Location l) {
entityLoc = l; /* Update the entity lcoation. */
Vector2i entityPos = entityLoc.getPosition(); /* Get Pos from last location. */
spritePosition = new Vector2f(entityPos.x, entityPos.y); /* Update sprite pos. */
}
/**
* Get the animated sprite to draw it.
* @return The anumated sprite.
*/
public Sprite getSprite() {
/* Set texture based on direction and animation frame. */
animatedSprite.setTextureRect(getTextureCoords());
/* Set sprite position */
animatedSprite.setPosition(new Vector2f(spritePosition.x * spriteSize.x,
(spritePosition.y*spriteSize.x)-(spriteSize.y-spriteSize.x)));
return animatedSprite;
}
private IntRect getTextureCoords() {
int topX = animationFrame * 32; /* x coord of the image. */
int topY = 0; /* Top y coord of the image. */
/* Match the correct image to the direction. */
switch(entityLoc.getDirection()) {
case NORTH:
topY = 144;
break;
case SOUTH:
topY = 0;
break;
case EAST:
topY = 96;
break;
case WEST:
topY = 48;
break;
}
/* Create and return an int rectangle. */
IntRect textureCoordsRect = new IntRect(topX, topY, spriteSize.x, spriteSize.y);
return textureCoordsRect;
}
}

View File

@ -1,3 +1,7 @@
package tfg;
/**
* The cardinal directions.
* @author Ritchie Cunningham
*/
public enum Direction { NORTH, SOUTH, EAST, WEST };

View File

@ -1,7 +1,6 @@
package tfg;
import org.jsfml.graphics.Color;
import org.jsfml.graphics.Font;
import org.jsfml.graphics.RenderWindow;
import org.jsfml.graphics.TextStyle;
import org.jsfml.system.Clock;
@ -13,93 +12,117 @@ import org.jsfml.window.event.Event;
/**
* TFG Game's main class.
* This class ideally should be as short as possible.
* @author Ritchie Cunningham
*/
public class Game {
private RenderWindow renderWindow = new RenderWindow();
private final String renderWindowTitle = "TFG Game";
private final Vector2i renderWindowDimensions = new Vector2i(640, 480);
private Player player;
private Camera camera;
private boolean renderWindowFocused = true;
private Font pixel = new Font();
private int fps;
private static boolean limitFPS = false;
private UITextElement fpsCounter;
/**
* Main window where everything will be rendered to and handle input.
*/
private RenderWindow window = new RenderWindow();
/**
* Set's the window title.
*/
private final String windowTitle = "TFG Game";
/**
* Set dimensions (resolution) the window is created with.
*/
private final Vector2i windowDimensions = new Vector2i(640, 480);
/**
* Main object representing the player.
*/
private Player player = new Player();
/**
* UI Element responsible for displaying the FPS.
*/
private final TextUIElement fpsUI =
new TextUIElement(InterfacePosition.TOP_LEFT, Color.YELLOW,24,TextStyle.BOLD);
/**
* Repesents whether or not the user has the window opened and in focus.
*/
private boolean windowFocus = true;
/**
* Create an instance of the game and run it.
* @param args Command line arguments passed in at run-time.
*/
public static void main(String[] args) {
Game g = new Game(); /* Create temp object of self. */
g.run(); /* Invoke run. */
}
/**
* Configure one-time settings at start-up.
*/
public void handleInitialization() {
renderWindow.create(new VideoMode(renderWindowDimensions.x,
renderWindowDimensions.y), renderWindowTitle);
fpsCounter = new UITextElement(InterfacePosition.TOP_LEFT,
Color.YELLOW,24,TextStyle.BOLD);
if(limitFPS) {
renderWindow.setFramerateLimit(60);
}
player = new Player();
window.create(new VideoMode(windowDimensions.x, windowDimensions.y),
windowTitle);
player.changeMap(new Map(10, 10, Tile.SAND));
camera = new Camera(renderWindow);
}
/**
* Run the game.
* Initializes the game and holds the main loop.
*/
public void run() {
handleInitialization();
int framesDrawn = 0;
float updateRate = 20.0f; /* 20hz */
long maxUpdates = 1;
Clock updateClock = new Clock();
Clock frameClock = new Clock();
updateClock.restart();
int framesDrawn = 0; /* Count each frame that is rendered */
float updateRate = 20.0f; /* Limit the logic loop to update at 20hz */
Clock updateClock = new Clock(); /* Clock used to restrict update loop rate */
Clock frameClock = new Clock(); /* Used to calc average FPS. */
updateClock.restart(); /* Reset update clock. */
/* Calc next update time in millisecs. */
long nextUpdate = updateClock.getElapsedTime().asMilliseconds();
while(renderWindow.isOpen()) {
long updates = 0;
/* As long as window is open, run main loop. */
while(window.isOpen()) {
handleInput();
/* Make note of the current update time. */
long updateTime = updateClock.getElapsedTime().asMicroseconds();
while ((updateTime-nextUpdate) >= updateRate && updates++ < maxUpdates) {
while ((updateTime-nextUpdate) >= updateRate) {
handleLogic();
nextUpdate += updateRate;
nextUpdate += updateRate; /* Compute next appropriate update time. */
}
handleDrawing();
framesDrawn++;
framesDrawn++; // Frame has rendered, increment.
/* How long has it been since last calulating FPS? */
float elapsedTime = frameClock.getElapsedTime().asSeconds();
if(elapsedTime >= 1.0f) {
fps = (int)(framesDrawn/elapsedTime);
fpsCounter.updateString("FPS: " + fps);
framesDrawn = 0;
frameClock.restart();
if(elapsedTime >= 1.0f) { /* If one second */
/* Divide the frames rendered by one second. */
fpsUI.updateString("FPS: " + (int) (framesDrawn/elapsedTime));
framesDrawn = 0; /* Reset the count. */
frameClock.restart(); /* Reset the frame clock. */
}
}
}
public void handleInput() {
for(Event event : renderWindow.pollEvents()) {
/*
* Window based event queue.
* Good for single-press actions, not for repeated actions though.
*/
for(Event event : window.pollEvents()) {
switch(event.type) {
case CLOSED:
renderWindow.close();
window.close();
break;
case GAINED_FOCUS:
renderWindowFocused = true;
windowFocus = true;
break;
case LOST_FOCUS:
renderWindowFocused = false;
windowFocus = false;
default:
break;
}
}
if(renderWindowFocused) {
/*
* Real-time input.
* Good for repeated actions, bad for single-press actions.
*/
if(windowFocus) {
if(Keyboard.isKeyPressed(Key.W)) {
player.move(Direction.NORTH);
} else if(Keyboard.isKeyPressed(Key.S)) {
@ -109,22 +132,29 @@ public class Game {
} else if(Keyboard.isKeyPressed(Key.D)) {
player.move(Direction.EAST);
} else if(Keyboard.isKeyPressed(Key.ESCAPE)) {
renderWindow.close();
window.close();
}
}
}
/**
* Update at a fixed rate (20Hz).
*/
public void handleLogic() {
player.update();
Camera.MoveTo(player.getPosition(), 0.5f);
}
/**
* Updates as fast as possible. Draws all objects onto the screen.
*/
public void handleDrawing() {
renderWindow.clear();
renderWindow.draw(player.getMap());
renderWindow.draw(player);
renderWindow.draw(fpsCounter);
renderWindow.display();
/* The window has automatic double-buffering. */
window.clear();
/* Draw each object like layers, background to foreground. */
window.draw(player.getMap());
window.draw(player);
window.draw(fpsUI);
window.display();
}
}

View File

@ -1,4 +1,6 @@
package tfg;
import org.jsfml.system.Vector2f;
import org.jsfml.system.Vector2i;
/**
@ -6,52 +8,100 @@ import org.jsfml.system.Vector2i;
* @author Ritchie Cunningham
*/
public class Location implements Cloneable {
/**
* Vector position (x,y).
*/
private Vector2i locPosition = new Vector2i(0,0);
/**
* Cardinal direction (N,S,E,W).
*/
private Direction locDirection;
/**
* Create a new location at x, y facing south.
* @param x New x-coorindate.
* @param y New y-coordinate.
*/
public Location(int x, int y) {
this(x, y, Direction.SOUTH);
}
/**
* Create a new location at x, y with with specified direction.
* @param x New x-coordinate.
* @param y New y-coordinate.
* @param d New direction.
*/
public Location(int x, int y, Direction d) {
locPosition = new Vector2i(x,y);
locDirection = d;
}
/**
* Get position.
* @return Integer vector of position.
*/
public Vector2i getPosition() {
return locPosition;
}
/**
* Get the direction.
* @return The direction.
*/
public Direction getDirection() {
return locDirection;
}
/**
* Set the position.
* @param newPosition the new position vector.
*/
public void setPosition(Vector2i newPosition) {
locPosition = newPosition;
}
/**
* Set the direction.
* @param newDirection The new direction.
*/
public void setDirection(Direction newDirection) {
locDirection = newDirection;
}
/**
* Add another position with the current position.
* @param position The position to add with the current position.
*/
public void addPosition(Vector2i position) {
locPosition = Vector2i.add(locPosition, position);
}
/**
* Subtract another position from the current position.
* @param position The position to subtract from the current position.
*/
public void subtractPosition(Vector2i position) {
locPosition = Vector2i.sub(locPosition, position);
}
/**
* Get the location in the direction from the current position.
* @param d The relative direction.
* @return The position in the relative direction.
*/
Location getRelativeLocation(Direction d) {
Location thisLocation = this;
Location newLocation = new Location(0,0);
/* Copy the current location. */
try {
newLocation = thisLocation.clone();
} catch(CloneNotSupportedException ex) {
ex.printStackTrace();
}
/* Modify the new location based on the direction. */
switch(d) {
case NORTH:
newLocation.subtractPosition(new Vector2i(0,1));
@ -70,6 +120,43 @@ public class Location implements Cloneable {
return newLocation;
}
/**
* Return a position in-between two locations.
* @param speed Size of the step.
* @param step Current step.
* @return Vector position in-between two locations.
*/
public Vector2f interpolate(float speed, int step) {
Vector2f interpolateAddition = new Vector2f(0,0); /* Init new vector. */
/*
* 1.0f / speed calculated the step increments
* Multiplying it by step calculates the current increment.
*/
float additionAmount = (1.0f/speed)*step; /* Current increment. */
/* Apply the increment to the vector based on the direction. */
switch(locDirection) {
case NORTH:
interpolateAddition = new Vector2f(0, -additionAmount);
break;
case SOUTH:
interpolateAddition = new Vector2f(0, additionAmount);
break;
case EAST:
interpolateAddition = new Vector2f(additionAmount, 0);
break;
case WEST:
interpolateAddition = new Vector2f(-additionAmount, 0);
break;
}
Vector2i currentPos = getPosition();
/* Add the increment to the base vector */
return Vector2f.add(new Vector2f(currentPos.x, currentPos.y), interpolateAddition);
}
/**
* Allows location to be copied.
*/
protected Location clone() throws CloneNotSupportedException {
return (Location) super.clone();
}

View File

@ -20,76 +20,128 @@ import java.util.Arrays;
* @author Ritchie Cunningham
*/
public class Map implements Drawable {
private Vector2i mapDimensions = new Vector2i(0, 0);
/**
* The size (length, width) of the map.
*/
private Vector2i dimensions = new Vector2i(0, 0);
private Tile[][] tileArray;
private Texture mapTilesheetTexture = new Texture();
private VertexArray mapVertexArray = new VertexArray();
/**
* The tilesheet texture.
*/
private Texture tilesheetTexture = new Texture();
/**
* Vertex array for the tile map.
* This is a streamlined way to draw many sprites at once.
*/
private VertexArray vertexArray = new VertexArray();
/**
* Create a new map of specified size and tile type.
* @param l Map length.
* @param w Map width.
* @param t Default tile to auto-pupulate map.
*/
public Map(int l, int w, Tile t) {
mapDimensions = new Vector2i(l,w);
tileArray = new Tile[mapDimensions.x][mapDimensions.y];
dimensions = new Vector2i(l,w);
tileArray = new Tile[dimensions.x][dimensions.y];
try {
mapTilesheetTexture.loadFromFile(Paths.get("res/terrain.png"));
tilesheetTexture.loadFromFile(Paths.get("res/terrain.png"));
} catch(IOException ex) {
ex.printStackTrace();
}
mapVertexArray.setPrimitiveType(PrimitiveType.QUADS);
initializeMap(t);
/* Set vertex array to use quads because the tiles are square. */
vertexArray.setPrimitiveType(PrimitiveType.QUADS);
initializeMap(t); /* Auto-populate the map with specified tile. */
}
/**
* Create a new map of speceified size that default to grass.
* @param l Map length.
* @param w Map width.
*/
public Map(int l, int w) {
this(l,w,Tile.GRASS);
}
/**
* Fill the entire map to the specified tile.
* @param initialTile The tile to populate the map with.
*/
public void initializeMap(Tile initialTile) {
/**
* Arrays.fill does not work with matrices,
* therefore we have to loop through the outer level to fill the inner.
*/
for(Tile[] row : tileArray) {
/* Set each tile in the row to the specified tile. */
Arrays.fill(row,initialTile);
}
}
/**
* Draw the map onto the window.
*/
public void draw(RenderTarget target, RenderStates states) {
mapVertexArray.clear();
vertexArray.clear(); /* empty array from previous draw. */
final int tileSize = Tile.getSize();
for(int i = 0; i < mapDimensions.x; i++) {
for(int j = 0; j < mapDimensions.y; j++) {
Tile tileType = tileArray[i][j];
/* Iterate through every tile in the map. */
for(int i = 0; i < dimensions.x; i++) {
for(int j = 0; j < dimensions.y; j++) {
Tile tileType = tileArray[i][j]; /* Grab current tile in the loop. */
/* Grab texture coord to render the tile. */
Vector2f textureCoords = Tile.getTextureCoords(tileType);
/*
* Add each corner of the tile to the vertex array
* counter-clockwise.
*/
/* Top left. */
mapVertexArray.add(new Vertex(
vertexArray.add(new Vertex(
new Vector2f(i*tileSize, j* tileSize), textureCoords));
/* Bottom left. */
mapVertexArray.add(new Vertex(
vertexArray.add(new Vertex(
new Vector2f(i*tileSize,(j*tileSize)+tileSize),
Vector2f.add(textureCoords, new Vector2f(tileSize,tileSize))));
/* Bottom right. */
mapVertexArray.add(new Vertex(
vertexArray.add(new Vertex(
new Vector2f((i*tileSize)+tileSize, (j*tileSize)+tileSize),
Vector2f.add(textureCoords, new Vector2f(tileSize,tileSize))));
/* Top right. */
mapVertexArray.add(new Vertex(
vertexArray.add(new Vertex(
new Vector2f((i*tileSize)+tileSize, j*tileSize),
Vector2f.add(textureCoords, new Vector2f(tileSize,0))));
}
}
RenderStates newStates = new RenderStates(mapTilesheetTexture);
mapVertexArray.draw(target, newStates);
/* Apply texture to the vertex array. */
RenderStates newStates = new RenderStates(tilesheetTexture);
vertexArray.draw(target, newStates); /* Draw vertex array. */
}
/**
* Return the tile at specified location.
* @param l Location of the tile to get.
* @return Tile at the specified location.
*/
public Tile getTile(Location l) {
Vector2i position = l.getPosition();
Tile t = tileArray[position.x][position.y];
Vector2i position = l.getPosition(); /* Get pos from loc. */
Tile t = tileArray[position.x][position.y]; /* Get tile at this pos. */
return t;
}
/**
* Determine whether or not the location fits within the map.
* @param l Location to test.
* @return If location is valid.
*/
public boolean isValidLocation(Location l) {
Vector2i coordinates = l.getPosition();
Vector2i coordinates = l.getPosition(); /* Pos from last location. */
/* Return true if the location is greater than 0. */
return ((coordinates.x >= 0) && (coordinates.y >=0) &&
(coordinates.x < mapDimensions.x) &&
(coordinates.y < mapDimensions.y) && Tile.getCanWalkOn(getTile(l)));
(coordinates.x < dimensions.x) &&
(coordinates.y < dimensions.y) && Tile.getCanWalkOn(getTile(l)));
}
}

View File

@ -4,156 +4,137 @@ import org.jsfml.audio.Sound;
import org.jsfml.audio.SoundBuffer;
import org.jsfml.audio.SoundSource;
import org.jsfml.graphics.Drawable;
import org.jsfml.graphics.IntRect;
import org.jsfml.graphics.RenderStates;
import org.jsfml.graphics.RenderTarget;
import org.jsfml.graphics.Sprite;
import org.jsfml.graphics.Texture;
import org.jsfml.system.Vector2f;
import org.jsfml.system.Vector2i;
import java.io.IOException;
import java.nio.file.Paths;
/**
* Player Class
* Holds everything that pertains to the player (you?).
* @author Ritchie Cunningham
*/
public class Player implements Drawable {
/**
* The players location.
*/
private Location playerLoc;
/**
* The texture for the sprite.
*/
private Texture playerSpritesheetTexture = new Texture();
private Sprite playerSprite = new Sprite();
/**
* The player sprite that supports animation.
*/
private final AnimatedSprite playerSprite;
/**
* The map the player is currently on.
*/
private Map currentMap;
private final Vector2i playerSize = new Vector2i(32, 48);
/**
* The action the player is currently performing.
*/
private PlayerAction currentAction = PlayerAction.NONE;
private Location newPlayerLoc;
private int frameCounter = 0;
private final float animationSpeed = 15.f;
private int animationFrame = 0;
private SoundBuffer cannotMoveBuffer = new SoundBuffer();
private Sound cannotMove = new Sound();
private Vector2f tempPosition = new Vector2f(0,0); /* Horrible Hack. */
/**
* The buffer that allows the 'stuck' sound to be loaded.
*/
private final SoundBuffer cannotMoveBuffer = new SoundBuffer();
/**
* The object that plays the 'stuck' sound.
*/
private final Sound cannotMove = new Sound();
public Player() {
playerLoc = new Location(0, 0);
/**
* Create a new player with a location at (x,y).
* @param x Starting x pos.
* @param y Starting y pos.
*/
public Player(int x, int y) {
playerLoc = new Location(x, y);
/* Load sprite texture and 'stuck' sound. */
try {
playerSpritesheetTexture.loadFromFile(Paths.get("res/player.png"));
cannotMoveBuffer.loadFromFile(Paths.get("res/stuck.wav"));
} catch(IOException ex) {
ex.printStackTrace();
}
playerSprite = new Sprite(playerSpritesheetTexture);
Sprite sprite = new Sprite(); /* Create a new regular sprite. */
sprite.setTexture(playerSpritesheetTexture);
/* Create a new animated sprite from the regular sprite. */
playerSprite = new AnimatedSprite(sprite, playerLoc);
cannotMove.setBuffer(cannotMoveBuffer);
}
/**
* Create a new player at(0,0).
*/
public Player() {
this(0,0);
}
/**
* Change the map the is on.
* @param m New map.
*/
public void changeMap(Map m) {
currentMap = m;
}
/**
* Get the map the player is currently on.
* @return Map player is currently on.
*/
public Map getMap() {
return currentMap;
}
/**
* Move the player in the specified direction.
* @param d Direction to move the player.
*/
public void move(Direction d) {
if(currentAction == PlayerAction.NONE) {
/*
* Get the location relative to the current location.
* e.g. NORTH would return the location above the current location.
*/
Location newLoc = playerLoc.getRelativeLocation(d);
playerLoc.setDirection(d);
if(currentMap.isValidLocation(newLoc)) {
currentAction = PlayerAction.MOVING;
newPlayerLoc = newLoc;
playerLoc.setDirection(d);
playerSprite.startWalkingAnimation();
} else if(cannotMove.getStatus() == SoundSource.Status.STOPPED) {
cannotMove.play();
}
}
}
public void resetLocation() {
playerLoc = new Location(0, 0);
}
public Vector2f getPosition() {
return playerSprite.getPosition();
}
public IntRect getTextureCoords() {
IntRect textureCoordsRect = new IntRect(0,0,0,0);
switch(playerLoc.getDirection()) {
case NORTH:
textureCoordsRect =
new IntRect(0+(animationFrame*32), 144, playerSize.x, playerSize.y);
break;
case SOUTH:
textureCoordsRect =
new IntRect(0+(animationFrame*32),0,playerSize.x,playerSize.y);
break;
case EAST:
textureCoordsRect =
new IntRect(0+(animationFrame*32),96,playerSize.x,playerSize.y);
break;
case WEST:
textureCoordsRect =
new IntRect(0+(animationFrame*32),48,playerSize.x,playerSize.y);
break;
}
return textureCoordsRect;
}
/**
* Update the animation progress.
*/
public void update() {
/* Dirty dirty hack and should be fixed asap. */
tempPosition = new Vector2f(0,0);
Vector2i currentPlayerPosition = playerLoc.getPosition();
if(currentAction == PlayerAction.MOVING) {
if(frameCounter >= animationSpeed) {
frameCounter = 0;
if(playerSprite.finishedAnimating()) {
currentAction = PlayerAction.NONE;
playerLoc = newPlayerLoc;
newPlayerLoc = null;
Vector2i newPlayerPosition = playerLoc.getPosition();
tempPosition = new Vector2f(newPlayerPosition.x, newPlayerPosition.y);
animationFrame = 0;
/* Actually move the location. */
playerLoc = playerLoc.getRelativeLocation(playerLoc.getDirection());
/* Update the sprite with new location. */
playerSprite.updatePosition(playerLoc);
} else {
float additionX = 0.0f;
float additionY = 0.0f;
switch(playerLoc.getDirection()) {
case NORTH:
additionY = -(1.0f / animationSpeed) * (frameCounter);
break;
case SOUTH:
additionY = (1.0f / animationSpeed) * (frameCounter);
case EAST:
additionX = (1.0f / animationSpeed) * (frameCounter);
break;
case WEST:
additionX = -(1.0f / animationSpeed) * (frameCounter);
break;
}
float change = Math.abs(additionX + additionY);
if(change >= 0.f && change < .25f) {
animationFrame = 0;
} else if(change >= .25f && change < .5f) {
animationFrame = 1;
} else if(change >= .5f && change < .75f) {
animationFrame = 2;
} else if(change >= .75f && change <= 1.0f) {
animationFrame = 3;
}
tempPosition = new Vector2f(currentPlayerPosition.x + additionX,
currentPlayerPosition.y + additionY);
playerSprite.animate(); /* Proceed with the animation. */
}
frameCounter++;
} else {
tempPosition = new Vector2f(currentPlayerPosition.x, currentPlayerPosition.y);
}
}
/**
* Draw the player on screen.
*/
public void draw(RenderTarget target, RenderStates states) {
playerSprite.setPosition(
new Vector2f(tempPosition.x*playerSize.x,
(tempPosition.y*playerSize.x)-(playerSize.y-playerSize.x)));
playerSprite.setTextureRect(getTextureCoords());
RenderStates newStates = new RenderStates(playerSpritesheetTexture);
playerSprite.draw(target, newStates);
/* Get the animated sprite and draw it. */
playerSprite.getSprite().draw(target, states);
}
}

View File

@ -1,7 +1,7 @@
package tfg;
/**
* Actions the player can carry out.
* Potential actions the player can carry out.
* @author Ritchie Cunningham
*/
public enum PlayerAction {NONE, MOVING }

View File

@ -0,0 +1,88 @@
package tfg;
import org.jsfml.graphics.Color;
import org.jsfml.graphics.Drawable;
import org.jsfml.graphics.Font;
import org.jsfml.graphics.RenderStates;
import org.jsfml.graphics.RenderTarget;
import org.jsfml.graphics.Text;
import org.jsfml.graphics.TextStyle;
import java.io.IOException;
import java.nio.file.Paths;
/**
* UI Elements containing a dynamic text label.
* @author Ritchie Cunningham
*/
public class TextUIElement implements Drawable {
/**
* The font for the text.
*/
private Font font = new Font();
/**
* The text object containing style and content.
*/
private Text text = new Text();
/**
* Create a new Text UI Element with the specified options and a default style.
* @param p Position on the screen to display the label.
* @param c The Color to set the text.
* @param size The size to render the text.
*/
public TextUIElement(InterfacePosition p, Color c, int size) {
this(p, c, size, TextStyle.REGULAR);
}
/**
* Create a new Text UI element with the specified options and style.
* @param p Position on the screen to display the label.
* @param c Color to set the text.
* @param size Size to render the text.
* @param style Style to apply to the text.
*/
public TextUIElement(InterfacePosition p, Color c, int size, int style) {
/* Attempt to load font. */
try {
font.loadFromFile(Paths.get("res/kpixel.ttf"));
} catch (IOException ex) {
ex.printStackTrace();
}
text.setFont(font); /* Apply the selected font. */
text.setCharacterSize(size); /* Update the character size. */
text.setColor(c); /* Change the color. */
text.setStyle(style); /* Set the desired style. */
setPosition(p); /* Position the label. */
}
/**
* Update the value of the text.
* @param s New value for the text.
*/
public void updateString(String s) {
text.setString(s);
}
/**
* Position the element on the screen.
* @param p Position on screen.
*/
public void setPosition(InterfacePosition p) {
switch(p) {
case TOP_LEFT:
text.setPosition(0,0); /* Default (0,0) if pos is top left. */
break;
default:
break;
}
}
/**
* Draw the UI elements to screen.
*/
public void draw(RenderTarget target, RenderStates states) {
text.draw(target, states);
}
}

View File

@ -3,14 +3,26 @@ package tfg;
import org.jsfml.system.Vector2f;
/**
* Map tiles for the Map class.
* Enumeration of tiles comprising maps.
* @author Ritchie Cunningham
*/
public enum Tile {
WATER, SAND, GRASS;
WATER, /* Wet and wild tile. */
SAND, /* Urgh, it gets between my toes. */
GRASS; /* Soft, green, vivid, inviting.. */
/**
* Length or width of a map tile.
* Each tile *MUST* be a square, therefore the area of
* the tile is this number squared.
*/
private static int tileSize = 32;
/**
* Get the coords of a specific tile from the tile-set image.
* @param t The tole to get the coordinates of.
* @return Coords of the tile image in the tile-set.
*/
public static Vector2f getTextureCoords(Tile t) {
Vector2f textureCoordinates = new Vector2f(0, 0);
switch(t) {
@ -21,29 +33,39 @@ public enum Tile {
textureCoordinates = new Vector2f(576, 352);
break;
case GRASS:
textureCoordinates = new Vector2f(448, 252);
textureCoordinates = new Vector2f(448, 352);
break;
}
return textureCoordinates;
}
/**
* Get the side length of a square tile.
* The tile area is tileSize^2.
* @return Length of a square map tile.
*/
public static int getSize() {
return tileSize;
}
/**
* Determine if this tile is safe for the player to walk on.
* @param t Tile to test.
* @return If the player can walk on it.
*/
public static boolean getCanWalkOn(Tile t) {
boolean able = false;
boolean canWalk = false;
switch(t) {
case WATER:
able = false;
canWalk = false;
break;
case SAND:
able = true;
canWalk = true;
break;
case GRASS:
able = true;
canWalk = true;
break;
}
return able;
return canWalk;
}
}

View File

@ -1,55 +0,0 @@
package tfg;
import org.jsfml.graphics.Color;
import org.jsfml.graphics.Drawable;
import org.jsfml.graphics.Font;
import org.jsfml.graphics.RenderStates;
import org.jsfml.graphics.RenderTarget;
import org.jsfml.graphics.Text;
import org.jsfml.graphics.TextStyle;
import java.io.IOException;
import java.nio.file.Paths;
/**
* GUI Elements
* @author Ritchie Cunningham
*/
public class UITextElement implements Drawable {
private Font font = new Font();
private Text text = new Text();
private String value;
public UITextElement(InterfacePosition p, Color c, int size) {
this(p, c, size, TextStyle.REGULAR);
}
public UITextElement(InterfacePosition p, Color c, int size, int style) {
try {
font.loadFromFile(Paths.get("res/kpixel.ttf"));
} catch (IOException ex) {
ex.printStackTrace();
}
text = new Text("", font, size);
text.setColor(c);
text.setStyle(style);
setPosition(p);
}
public void updateString(String s) {
text.setString(s);
}
public void setPosition(InterfacePosition p) {
switch(p) {
case TOP_LEFT:
text.setPosition(0,0);
break;
}
}
public void draw(RenderTarget target, RenderStates states) {
text.draw(target, states);
}
}