Archived
Private
Public Access
1
0

Initial commit

This commit is contained in:
2022-09-04 12:45:01 +02:00
commit f4a01d6a69
11601 changed files with 4206660 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
package de.craftix.game;
import java.awt.image.BufferedImage;
public class Animation {
private int state;
private int frame;
private int frames;
private long delay;
private long startTime;
private Spritesheed sprite;
private boolean started;
public Animation(Spritesheed sprite, int state, int frames, long delay){
this.sprite = sprite;
this.state = state;
this.frames = frames;
this.delay = delay;
frame = 0;
startTime = System.currentTimeMillis();
started = true;
}
public Animation(Spritesheed sprite, long delay) {
this.sprite = sprite;
this.delay = delay;
started = false;
}
public void update() {
if (started && System.currentTimeMillis() - startTime >= delay) {
frame++;
if (frame == frames) frame = 0;
startTime = System.currentTimeMillis();
}
}
public void start(int state, int frames) {
this.frames = frames;
this.state = state;
startTime = System.currentTimeMillis();
frame = 0;
started = true;
}
public void stop() {started = false;}
public BufferedImage getImage() {return sprite.getTexture(frame, state);}
public int getState() {return state;}
public void setImages(int state, int frames) {
this.state = state;
this.frames = frames;
frame = 0;
startTime = System.currentTimeMillis();
}
}

View File

@@ -0,0 +1,16 @@
package de.craftix.game;
import de.craftix.game.entity.Player;
public class Camera {
private Player player;
public Camera(Player player) {
this.player = player;
}
public int getCamX() {return (int) player.getX() + player.getWidth() / 2 - GamePanel.width / 2 / GamePanel.SCALE;}
public int getCamY() {return (int) player.getY() + player.getHeight() / 2 - GamePanel.height / 2 / GamePanel.SCALE;}
}

View File

@@ -0,0 +1,30 @@
package de.craftix.game;
import javax.swing.*;
import java.awt.*;
public class Game extends JFrame {
public static final int width = 600;
public static final int height = 400;
public static final int BLOCKSIZE = 16;
public static final int FPS = 60;
private static final long serialVersionUID = 1L;
public static Spritesheed terrain = new Spritesheed(5, ImageLoader.load("img/terrain.png"), 16, 16);
public Game(){
super("Minecraft Sky Survival Platformer of Awesomeness");
setLayout(new BorderLayout());
add(new GamePanel(), BorderLayout.CENTER);
pack();
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args) {
new Game();
}
}

View File

@@ -0,0 +1,40 @@
package de.craftix.game;
import java.awt.*;
public abstract class GameObject {
protected float x;
protected float y;
protected int width;
protected int height;
public GameObject(float x, float y, int width, int height){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public void setLocation(float x, float y) {
this.x = x;
this.y = y;
}
public Rectangle getBox(){
Rectangle rectangle = new Rectangle();
rectangle.setBounds((int)x, (int)y, width, height);
return rectangle;
}
public void setX(float x) {this.x = x;}
public void setY(float y) {this.y = y;}
public void setWidth(int width) {this.width = width;}
public void setHeight(int height) {this.height = height;}
public float getX() {return x;}
public float getY() {return y;}
public int getHeight() {return height;}
public int getWidth() {return width;}
public int getCenterX() {return (int)x + width / 2;}
public int getCenterY() {return (int)y + height / 2;}
}

View File

@@ -0,0 +1,128 @@
package de.craftix.game;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.VolatileImage;
public class GamePanel extends JPanel implements KeyListener, MouseListener, ActionListener, ComponentListener {
private static final long serialVersionUID = 1L;
public static int width;
public static int height;
public static final int SCALE = 3;
public static Mouse mouse;
private Timer timer;
private GameStateManager gsm;
private VolatileImage image;
public GamePanel() {
super();
setPreferredSize(new Dimension(Game.width, Game.height));
addComponentListener(this);
addMouseListener(this);
addKeyListener(this);
setBackground(Color.BLACK);
setFocusable(true);
requestFocus();
mouse = new Mouse(this);
width = getPreferredSize().width;
height = getPreferredSize().height;
gsm = new GameStateManager(GameStateManager.PLAYSTATE);
}
@Override
public void addNotify() {
super.addNotify();
image = createVolatileImage(width / SCALE, height / SCALE);
timer = new Timer(1000 / Game.FPS, this::actionPerformed);
timer.start();
}
private void update() {
gsm.update();
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = image.createGraphics();
g2.setBackground(new Color(146, 189, 221));
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
gsm.render(g2);
g.drawImage(image, 0, 0, width, height, null);
}
@Override
public void actionPerformed(ActionEvent e) {
update();
repaint();
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
gsm.keyPressed(e, e.getKeyCode());
}
@Override
public void keyReleased(KeyEvent e) {
gsm.keyReleased(e, e.getKeyCode());
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
gsm.mousePressed(e);
}
@Override
public void mouseReleased(MouseEvent e) {
gsm.mouseReleased(e);
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void componentResized(ComponentEvent e) {
if (!e.getSource().equals(this)) return;
width = getWidth();
height = getHeight();
image = createVolatileImage(width / SCALE, height / SCALE);
}
@Override
public void componentMoved(ComponentEvent e) {
}
@Override
public void componentShown(ComponentEvent e) {
}
@Override
public void componentHidden(ComponentEvent e) {
}
}

View File

@@ -0,0 +1,43 @@
package de.craftix.game;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
public class GameStateManager {
public static final int PLAYSTATE = 0;
private int state;
private State[] states;
public GameStateManager(int state) {
states = new State[1];
states[0] = new Playstate(this);
}
public void update() {
states[state].update();
}
public void render(Graphics2D g) {
states[state].render(g);
}
public void keyPressed(KeyEvent e, int k) {
states[state].keyPressed(e, k);
}
public void keyReleased(KeyEvent e, int k) {
states[state].keyReleased(e, k);
}
public void mousePressed(MouseEvent e) {
states[state].mousePressed(e);
}
public void mouseReleased(MouseEvent e) {
states[state].mouseReleased(e);
}
}

View File

@@ -0,0 +1,17 @@
package de.craftix.game;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
public class ImageLoader {
public static BufferedImage load(String path){
if (path == null) return null;
try {
return ImageIO.read(new File(path));
}catch (Exception e) {e.printStackTrace();}
return null;
}
}

View File

@@ -0,0 +1,78 @@
package de.craftix.game;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
public class Mouse implements MouseListener, MouseMotionListener {
public int x;
public int y;
public int conX;
public int conY;
public boolean pressed;
public Mouse(GamePanel panel) {
panel.addMouseListener(this);
panel.addMouseMotionListener(this);
}
private void setCoordinates(Point p) {
x = p.x;
y = p.y;
}
private void setConvertedCoordinates(Point p) {
conX = p.x / GamePanel.SCALE + Playstate.camera.getCamX();
conY = p.y / GamePanel.SCALE + Playstate.camera.getCamY();
}
@Override
public void mouseDragged(MouseEvent e) {
setConvertedCoordinates(e.getPoint());
setCoordinates(e.getPoint());
Playstate.world.getBlock(conX, conY).destroy();
}
@Override
public void mouseMoved(MouseEvent e) {
setConvertedCoordinates(e.getPoint());
setCoordinates(e.getPoint());
}
@Override
public void mousePressed(MouseEvent e) {
setConvertedCoordinates(e.getPoint());
setCoordinates(e.getPoint());
pressed = true;
Playstate.world.getBlock(conX, conY).destroy();
}
@Override
public void mouseReleased(MouseEvent e) {
setConvertedCoordinates(e.getPoint());
setCoordinates(e.getPoint());
pressed = false;
}
//UNUSED
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}

View File

@@ -0,0 +1,54 @@
package de.craftix.game;
import de.craftix.game.entity.Player;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
public class Playstate extends State {
public static World world;
public static Player player;
public static Camera camera;
public Playstate(GameStateManager gsm) {
super(gsm);
world = new World("world.txt");
player = new Player(10, 5, 20, 31, 0.75f);
camera = new Camera(player);
}
@Override
public void update() {
player.update();
world.update();
}
@Override
public void render(Graphics2D g) {
g.clearRect(0, 0, GamePanel.width, GamePanel.height);
world.render(g);
player.render(g);
}
@Override
public void keyPressed(KeyEvent e, int k) {
player.keyPressed(e, k);
}
@Override
public void keyReleased(KeyEvent e, int k) {
player.keyReleased(e, k);
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
}

View File

@@ -0,0 +1,31 @@
package de.craftix.game;
import java.awt.image.BufferedImage;
public class Spritesheed {
private int cols;
private int width;
private int height;
private BufferedImage sprite;
public Spritesheed(int cols, BufferedImage sprite, int width, int height) {
this.width = width;
this.height = height;
this.cols = cols;
this.sprite = sprite;
}
public BufferedImage getTexture(int id){
int row = (id / cols);
int col = (id % cols);
return sprite.getSubimage(col * width, row * height, width, height);
}
public BufferedImage getTexture(int col, int row){
return sprite.getSubimage(col * width, row * height, width, height);
}
public int getCols() {return cols;}
}

View File

@@ -0,0 +1,22 @@
package de.craftix.game;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
public abstract class State {
protected GameStateManager gsm;
public State(GameStateManager gsm){
this.gsm = gsm;
}
public abstract void update();
public abstract void render(Graphics2D g);
public abstract void keyPressed(KeyEvent e, int k);
public abstract void keyReleased(KeyEvent e, int k);
public abstract void mousePressed(MouseEvent e);
public abstract void mouseReleased(MouseEvent e);
}

View File

@@ -0,0 +1,80 @@
package de.craftix.game;
import de.craftix.game.block.Block;
import de.craftix.game.block.Material;
import de.craftix.game.entity.Player;
import java.awt.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
public class World {
private int blocksX;
private int blocksY;
private Block[][] blocks;
private File worldFile;
public World(String worldFile) {
this.worldFile = new File("worlds/" + worldFile);
loadWorldFromFile();
}
public void update() {
for(int row = 0; row < blocksY; row++) {
for(int col = 0; col < blocksX; col++) {
blocks[row][col].update();
}
}
}
public void render(Graphics2D g) {
int blocksRendered = 0;
Player player = Playstate.player;
int startX = player.getCenterX() - GamePanel.width / GamePanel.SCALE / 2;
int startY = player.getCenterY() - GamePanel.height / GamePanel.SCALE / 2;
int endX = player.getCenterX() + GamePanel.width / GamePanel.SCALE / 2 + Game.BLOCKSIZE;
int endY = player.getCenterY() + GamePanel.height / GamePanel.SCALE / 2 + Game.BLOCKSIZE;
for (int row = startY; row <= endY; row += Game.BLOCKSIZE) {
for (int col = startX; col <= endX; col += Game.BLOCKSIZE) {
int blockX = getColTile(col);
int blockY = getRowTile(row);
if (blockX >= 0 && blockY >= 0 && blockX < this.blocksX && blockY < this.blocksY) {
blocks[blockY][blockX].render(g);
blocksRendered++;
}
}
}
g.setColor(Color.WHITE);
g.drawString("Blocks Rendered: " + blocksRendered, 5, 10);
}
private void loadWorldFromFile() {
try {
BufferedReader reader = new BufferedReader(new FileReader(worldFile));
blocksX = Integer.parseInt(reader.readLine());
blocksY = Integer.parseInt(reader.readLine());
blocks = new Block[blocksY][blocksX];
for (int row = 0; row < blocksY; row++) {
String line = reader.readLine();
String[] tokens = line.split(" ");
for (int col = 0; col < blocksX; col++){
int id = Integer.parseInt(tokens[col]);
blocks[row][col] = new Block(Material.values()[id], col * Game.BLOCKSIZE, row * Game.BLOCKSIZE, Game.BLOCKSIZE, Game.BLOCKSIZE);
}
}
reader.close();
} catch (Exception e) {e.printStackTrace();}
}
public int getRowTile(int y) {return y / Game.BLOCKSIZE;}
public int getColTile(int x) {return x / Game.BLOCKSIZE;}
public Block[][] getBlocks() {return blocks;}
public Block getBlock(float x, float y) {return blocks[getRowTile((int)y)][getColTile((int)x)];}
}

View File

@@ -0,0 +1,66 @@
package de.craftix.game.block;
import de.craftix.game.*;
import java.awt.*;
public class Block extends GameObject {
public static Spritesheed destroy = new Spritesheed(10, ImageLoader.load("img/destroy.png"), 16, 16);
//DestroyAnimation
private long destroyDuration;
private long destroyStartTime;
private boolean destroying;
private Animation animation;
private Material material;
public Block(Material material, float x, float y, int width, int height) {
super(x, y, width, height);
this.material = material;
destroyDuration = material.getDestroyDuration();
long dt = destroyDuration / destroy.getCols();
animation = new Animation(destroy, dt);
}
public void update() {
//BLOCK DESTROYING
if (destroying) {
int mx = GamePanel.mouse.conX;
int my = GamePanel.mouse.conY;
animation.update();
//CHECK INTERRUPTION
if (!GamePanel.mouse.pressed || !getBox().contains(new Point(mx, my))) {
destroying = false;
animation.stop();
}
//DESTROYING BLOCK AFTER DURATION
if (System.currentTimeMillis() - destroyStartTime >= destroyDuration) {
material = Material.AIR;
destroying = false;
animation.stop();
}
}
}
public void destroy() {
if (!destroying && material != Material.AIR) {
destroying = true;
destroyStartTime = System.currentTimeMillis();
animation.start(0, destroy.getCols());
}
}
public void render(Graphics2D g) {
g.drawImage(material.getImage(), (int)x - Playstate.camera.getCamX(), (int)y - Playstate.camera.getCamY(), null);
//DRAW BLOCK DESTROYING
if (destroying) g.drawImage(animation.getImage(), (int)x - Playstate.camera.getCamX(), (int)y - Playstate.camera.getCamY(), null);
}
public Material getMaterial() {return material;}
}

View File

@@ -0,0 +1,32 @@
package de.craftix.game.block;
import de.craftix.game.Game;
import java.awt.image.BufferedImage;
public enum Material {
AIR(0, true, 0),
STONE(1, false, 2000l),
DIRT(2, false, 1000l),
GRASS(3, false, 1200l),
SAND(4, false, 750l);
private int id;
private long destroyDuration;
private boolean walkable;
private BufferedImage image;
Material(int id, boolean walkable, long destroyDuration){
this.id = id;
this.walkable = walkable;
this.destroyDuration = destroyDuration;
this.image = Game.terrain.getTexture(id);
}
public int getId() {return id;}
public boolean isWalkable() {return walkable;}
public BufferedImage getImage() {return image;}
public long getDestroyDuration() {return destroyDuration;}
}

View File

@@ -0,0 +1,140 @@
package de.craftix.game.entity;
import de.craftix.game.*;
import java.awt.*;
public abstract class Entity extends GameObject {
//CONSTANTS
private final float GRAVITY = 0.2f;
private final float MAX_FALLING_SPEED = 2.5f;
private final float JUMP_START = -3.5f;
//MOVEMENT
protected float speed;
protected float dx;
protected float dy;
protected boolean left;
protected boolean right;
protected boolean falling;
protected boolean jumping;
//COLLISION
protected boolean topLeft;
protected boolean topRight;
protected boolean midLeft;
protected boolean midRight;
protected boolean bottomLeft;
protected boolean bottomRight;
//ANIMATION
protected int[] frames = { 1, 1, 2, 2 };
protected int idle;
protected final int IDLE_LEFT = 0;
protected final int IDLE_RIGHT = 1;
protected final int LEFT = 2;
protected final int RIGHT = 3;
protected Animation animation;
public Entity(float x, float y, int width, int height, float speed, Spritesheed sprite) {
super(x, y, width, height);
this.speed = speed;
animation = new Animation(sprite, IDLE_LEFT, frames[IDLE_LEFT], 150l);
this.idle = IDLE_LEFT;
}
public void render(Graphics2D g) {
g.drawImage(animation.getImage(), (int)x, (int)y, null);
}
public void update() {
calculateMovement();
calculateCollisions();
calculateAnimations();
move();
}
private void calculateAnimations(){
animation.update();
if (left && animation.getState() != LEFT) {
animation.setImages(LEFT, frames[LEFT]);
idle = IDLE_LEFT;
}else if (right && animation.getState() != RIGHT){
animation.setImages(RIGHT, frames[RIGHT]);
idle = IDLE_RIGHT;
}
if (!left && !right){
animation.setImages(idle, frames[idle]);
}
}
private void calculateMovement() {
if (left) dx = -speed;
if (right) dx = speed;
if (falling && !jumping) {
dy += GRAVITY;
if (dy > MAX_FALLING_SPEED) dy = MAX_FALLING_SPEED;
}
if (jumping && !falling) {
dy = JUMP_START;
jumping = false;
falling = true;
}
}
private void calculateCollisions() {
float toX = x + dx;
float toY = y + dy;
//COLLISION LEFT AND RIGHT
calculateCorners(toX, y - 1);
if (dx < 0) if (topLeft || midLeft || bottomLeft) dx = 0;
if (dx > 0) if (topRight || midRight || bottomRight) dx = 0;
//COLLISION TOP AND BOTTOM
calculateCorners(x, toY);
if (topLeft || topLeft) {
dy = 0;
falling = true;
int playerRow = Playstate.world.getRowTile((int)toY);
y = (playerRow + 1) * Game.BLOCKSIZE;
}
if (bottomLeft || bottomRight && falling) {
falling = false;
dy = 0;
int playerRow = Playstate.world.getRowTile((int)toY + height);
y = playerRow * Game.BLOCKSIZE - height;
}
if (!bottomLeft && !bottomRight) falling = true;
}
private void calculateCorners(float x, float y) {
try {
World world = Playstate.world;
int leftTile = world.getColTile((int)x);
int rightTile = world.getColTile((int)x + width - 1);
int topTile = world.getRowTile((int)y);
int midTile = world.getRowTile((int)y + height / 2);
int bottomTile = world.getRowTile((int)y + height);
topLeft = !world.getBlocks()[topTile][leftTile].getMaterial().isWalkable();
topRight = !world.getBlocks()[topTile][rightTile].getMaterial().isWalkable();
midLeft = !world.getBlocks()[midTile][leftTile].getMaterial().isWalkable();
midRight = !world.getBlocks()[midTile][rightTile].getMaterial().isWalkable();
bottomLeft = !world.getBlocks()[bottomTile][leftTile].getMaterial().isWalkable();
bottomRight = !world.getBlocks()[bottomTile][rightTile].getMaterial().isWalkable();
}catch (Exception e) {topLeft = topRight = midLeft = midRight = bottomLeft = bottomRight = false;}
}
private void move() {
x += dx;
y += dy;
dx = 0;
}
}

View File

@@ -0,0 +1,34 @@
package de.craftix.game.entity;
import de.craftix.game.GamePanel;
import de.craftix.game.ImageLoader;
import de.craftix.game.Spritesheed;
import java.awt.*;
import java.awt.event.KeyEvent;
public class Player extends Entity {
public Player(float x, float y, int width, int height, float speed) {
super(x, y, width, height, speed, new Spritesheed(2, ImageLoader.load("img/player.png"), 20, 32));
}
public void keyPressed(KeyEvent e, int k){
switch (k){
case KeyEvent.VK_A: left = true; break;
case KeyEvent.VK_D: right = true; break;
case KeyEvent.VK_SPACE: if (!falling && !jumping) jumping = true; break;
}
}
public void keyReleased(KeyEvent e, int k){
switch (k){
case KeyEvent.VK_A: left = false; break;
case KeyEvent.VK_D: right = false; break;
}
}
@Override
public void render(Graphics2D g){
g.drawImage(animation.getImage(), GamePanel.width / 2 / GamePanel.SCALE - width / 2, GamePanel.height / 2 / GamePanel.SCALE - height / 2, null);
}
}