forked from open-osrs/runelite
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
replace the client with something better
- Loading branch information
1 parent
9edd632
commit 1c1c64c
Showing
5 changed files
with
369 additions
and
0 deletions.
There are no files selected for viewing
18 changes: 18 additions & 0 deletions
18
runelite-client/src/main/java/com/thatgamerblue/snake/Direction.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.thatgamerblue.snake; | ||
|
||
public enum Direction { | ||
UP(0, -1, "^"), | ||
DOWN(0, 1, "v"), | ||
LEFT(-1, 0, "<"), | ||
RIGHT(1, 0, ">"); | ||
|
||
public int xOffset; | ||
public int yOffset; | ||
public String display; | ||
|
||
Direction(int xOff, int yOff, String display) { | ||
xOffset = xOff; | ||
yOffset = yOff; | ||
this.display = display; | ||
} | ||
} |
178 changes: 178 additions & 0 deletions
178
runelite-client/src/main/java/com/thatgamerblue/snake/GameHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
package com.thatgamerblue.snake; | ||
|
||
import java.awt.Color; | ||
import java.awt.Font; | ||
import java.awt.Graphics; | ||
import java.awt.Graphics2D; | ||
import java.awt.Point; | ||
import java.awt.event.KeyEvent; | ||
import java.awt.event.KeyListener; | ||
import java.util.HashSet; | ||
import java.util.Set; | ||
|
||
public class GameHandler implements KeyListener { | ||
private static final int DEFAULT_REFRESH_INTERVAL = 100; | ||
private static final int PX_PER_TILE = 16; | ||
private static final int WIDTH = SnakeGame.FRAME_WIDTH / PX_PER_TILE; | ||
private static final int HEIGHT = SnakeGame.FRAME_HEIGHT / PX_PER_TILE; | ||
private static final int MIDDLE_X = WIDTH / 2; | ||
private static final int MIDDLE_Y = HEIGHT / 2; | ||
private static final Color SNAKE_HEAD_COLOR = Color.GREEN; | ||
private static final Color SNAKE_BODY_COLOR = new Color(0, 128, 0); | ||
private static final Color APPLE_COLOR = Color.RED; | ||
private static final Font HEAD_FONT = new Font("Arial", Font.BOLD, 12); | ||
private static final Font FONT = new Font("Arial", Font.BOLD, 16); | ||
|
||
private final Set<Integer> keysPressed = new HashSet<>(); | ||
private Direction pendingDirection = Direction.LEFT; | ||
private Direction direction = Direction.LEFT; | ||
private SnakePart head; | ||
private SnakePart apple = new SnakePart(); | ||
private int score; | ||
|
||
public void reset() { | ||
head = new SnakePart(); | ||
SnakePart current = head; | ||
current.x = MIDDLE_X; | ||
current.y = MIDDLE_Y; | ||
|
||
for (int i = 0; i < 4; i++) { | ||
current.next = new SnakePart(); | ||
current = current.next; | ||
current.x = MIDDLE_X + i + 1; | ||
current.y = MIDDLE_Y; | ||
} | ||
|
||
direction = Direction.LEFT; | ||
pendingDirection = Direction.LEFT; | ||
createNewApple(); | ||
score = 0; | ||
SnakeGame.currentRefreshInterval = DEFAULT_REFRESH_INTERVAL; | ||
} | ||
|
||
public void update() { | ||
processInput(); | ||
direction = pendingDirection; | ||
SnakePart newHead = new SnakePart(); | ||
newHead.x = head.x + direction.xOffset; | ||
newHead.y = head.y + direction.yOffset; | ||
newHead.next = head; | ||
head = newHead; | ||
|
||
boolean ateApple = false; | ||
if (head.x == apple.x && head.y == apple.y) { | ||
createNewApple(); | ||
ateApple = true; | ||
score++; | ||
SnakeGame.currentRefreshInterval = Math.max(50, DEFAULT_REFRESH_INTERVAL - score); | ||
} | ||
|
||
if (!ateApple) { | ||
SnakePart current = head; | ||
while (current.next.next != null) { | ||
current = current.next; | ||
} | ||
current.next = null; | ||
} | ||
|
||
if (head.x < 0 || head.x >= WIDTH || head.y < 0 || head.y >= HEIGHT) { | ||
reset(); | ||
} | ||
|
||
SnakePart current = head.next; | ||
while (current.next != null) { | ||
if (current.x == head.x && current.y == head.y) { | ||
reset(); | ||
break; | ||
} | ||
current = current.next; | ||
} | ||
} | ||
|
||
private Point findAppleSpawn() { | ||
Set<Point> used = new HashSet<>(); | ||
for (SnakePart part = head; part != null; part = part.next) { | ||
used.add(new Point(part.x, part.y)); | ||
} | ||
int x, y; | ||
do { | ||
x = (int) (Math.random() * (WIDTH - 2)) + 1; | ||
y = (int) (Math.random() * (HEIGHT - 2)) + 1; | ||
} while (used.contains(new Point(x, y))); | ||
return new Point(x, y); | ||
} | ||
|
||
private void createNewApple() { | ||
Point spawn = findAppleSpawn(); | ||
apple.x = spawn.x; | ||
apple.y = spawn.y; | ||
} | ||
|
||
private void processInput() { | ||
if (keysPressed.contains(KeyEvent.VK_UP)) { | ||
if (direction != Direction.DOWN) { | ||
pendingDirection = Direction.UP; | ||
} | ||
} else if (keysPressed.contains(KeyEvent.VK_DOWN)) { | ||
if (direction != Direction.UP) { | ||
pendingDirection = Direction.DOWN; | ||
} | ||
} else if (keysPressed.contains(KeyEvent.VK_LEFT)) { | ||
if (direction != Direction.RIGHT) { | ||
pendingDirection = Direction.LEFT; | ||
} | ||
} else if (keysPressed.contains(KeyEvent.VK_RIGHT)) { | ||
if (direction != Direction.LEFT) { | ||
pendingDirection = Direction.RIGHT; | ||
} | ||
} | ||
} | ||
|
||
|
||
|
||
|
||
|
||
public void draw(Graphics g) { | ||
// draw snake head | ||
g.setColor(SNAKE_HEAD_COLOR); | ||
SnakePart current = head; | ||
while (current != null) { | ||
g.fillRect(current.x * PX_PER_TILE, current.y * PX_PER_TILE, PX_PER_TILE, PX_PER_TILE); | ||
g.setColor(Color.BLACK); | ||
g.drawRect(current.x * PX_PER_TILE, current.y * PX_PER_TILE, PX_PER_TILE, PX_PER_TILE); | ||
if (current == head) { | ||
g.setFont(HEAD_FONT); | ||
g.drawString(direction.display, head.x * PX_PER_TILE + 6, (head.y + 1) * PX_PER_TILE - 3); | ||
} | ||
|
||
current = current.next; | ||
g.setColor(SNAKE_BODY_COLOR); | ||
} | ||
g.setColor(APPLE_COLOR); | ||
g.fillRect(apple.x * PX_PER_TILE, apple.y * PX_PER_TILE, PX_PER_TILE, PX_PER_TILE); | ||
g.setColor(Color.BLACK); | ||
g.drawRect(apple.x * PX_PER_TILE, apple.y * PX_PER_TILE, PX_PER_TILE, PX_PER_TILE); | ||
|
||
g.setColor(Color.BLACK); | ||
g.setFont(FONT); | ||
g.drawString("Score: " + score, SnakeGame.FRAME_WIDTH - 100, SnakeGame.FRAME_HEIGHT - 10); | ||
} | ||
|
||
|
||
|
||
|
||
@Override | ||
public void keyTyped(KeyEvent e) { | ||
|
||
} | ||
|
||
@Override | ||
public void keyPressed(KeyEvent e) { | ||
keysPressed.add(e.getKeyCode()); | ||
} | ||
|
||
@Override | ||
public void keyReleased(KeyEvent e) { | ||
keysPressed.remove(e.getKeyCode()); | ||
} | ||
} |
143 changes: 143 additions & 0 deletions
143
runelite-client/src/main/java/com/thatgamerblue/snake/SnakeGame.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
package com.thatgamerblue.snake; | ||
|
||
import java.awt.BorderLayout; | ||
import java.awt.Component; | ||
import java.awt.Graphics; | ||
import java.awt.Image; | ||
import javax.swing.JFrame; | ||
import javax.swing.JPanel; | ||
|
||
public class SnakeGame { | ||
public static final int FRAME_WIDTH = 800; | ||
public static final int FRAME_HEIGHT = 608; | ||
public static long currentRefreshInterval = 100; | ||
private static GameHandler gameHandler; | ||
private final Object redrawLock = new Object(); | ||
private Component component; | ||
private Image imageBuffer; | ||
|
||
public void start(Component component) { | ||
this.component = component; | ||
gameHandler.reset(); | ||
imageBuffer = component.createImage(component.getWidth(), | ||
component.getHeight()); | ||
Thread thread = new Thread(this::runGameLoop); | ||
thread.start(); | ||
} | ||
|
||
private void runGameLoop() { | ||
// update the game repeatedly | ||
while (true) { | ||
long durationMs = redraw(); | ||
try { | ||
Thread.sleep(Math.max(0, currentRefreshInterval - durationMs)); | ||
} catch (InterruptedException e) { | ||
} | ||
} | ||
} | ||
|
||
private long redraw() { | ||
|
||
long t = System.currentTimeMillis(); | ||
|
||
// At this point perform changes to the model that the component will | ||
// redraw | ||
|
||
updateModel(); | ||
|
||
// draw the model state to a buffered image which will get | ||
// painted by component.paint(). | ||
drawModelToImageBuffer(); | ||
|
||
// asynchronously signals the paint to happen in the awt event | ||
// dispatcher thread | ||
component.repaint(); | ||
|
||
// use a lock here that is only released once the paintComponent | ||
// has happened so that we know exactly when the paint was completed and | ||
// thus know how long to pause till the next redraw. | ||
waitForPaint(); | ||
|
||
// return time taken to do redraw in ms | ||
return System.currentTimeMillis() - t; | ||
} | ||
|
||
private void updateModel() { | ||
gameHandler.update(); | ||
} | ||
|
||
private void drawModelToImageBuffer() { | ||
drawModel(imageBuffer.getGraphics()); | ||
} | ||
|
||
private void drawModel(Graphics g) { | ||
g.setColor(component.getBackground()); | ||
g.fillRect(0, 0, component.getWidth(), component.getHeight()); | ||
g.setColor(component.getForeground()); | ||
gameHandler.draw(g); | ||
} | ||
|
||
private void waitForPaint() { | ||
try { | ||
synchronized (redrawLock) { | ||
redrawLock.wait(); | ||
} | ||
} catch (InterruptedException e) { | ||
} | ||
} | ||
|
||
private void resume() { | ||
synchronized (redrawLock) { | ||
redrawLock.notify(); | ||
} | ||
} | ||
|
||
public void paint(Graphics g) { | ||
// paint the buffered image to the graphics | ||
g.drawImage(imageBuffer, 0, 0, component); | ||
|
||
// resume the game loop | ||
resume(); | ||
} | ||
|
||
public static class SnakeComponent extends JPanel { | ||
|
||
private final SnakeGame game; | ||
|
||
public SnakeComponent(SnakeGame game) { | ||
this.game = game; | ||
} | ||
|
||
@Override | ||
protected void paintComponent(Graphics g) { | ||
game.paint(g); | ||
} | ||
} | ||
|
||
public static void main(String[] args) { | ||
java.awt.EventQueue.invokeLater(() -> { | ||
SnakeGame game = new SnakeGame(); | ||
SnakeComponent component = new SnakeComponent(game); | ||
|
||
gameHandler = new GameHandler(); | ||
|
||
component.setPreferredSize(new java.awt.Dimension(FRAME_WIDTH, FRAME_HEIGHT)); | ||
JFrame frame = new JFrame(); | ||
|
||
frame.setTitle("OpenOSRS Snake"); | ||
frame.setResizable(false); | ||
|
||
frame.addKeyListener(gameHandler); | ||
frame.setFocusable(true); | ||
frame.setFocusTraversalKeysEnabled(false); | ||
|
||
frame.setLayout(new BorderLayout()); | ||
frame.getContentPane().add(component, BorderLayout.CENTER); | ||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | ||
frame.setVisible(true); | ||
frame.pack(); | ||
|
||
game.start(component); | ||
}); | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
runelite-client/src/main/java/com/thatgamerblue/snake/SnakePart.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.thatgamerblue.snake; | ||
|
||
public class SnakePart { | ||
public SnakePart next; | ||
int x, y; | ||
} |
Oops, something went wrong.