99import com .redomar .game .event .MouseHandler ;
1010import com .redomar .game .gfx .Screen ;
1111import com .redomar .game .gfx .SpriteSheet ;
12+ import com .redomar .game .gfx .lighting .Night ;
1213import com .redomar .game .level .LevelHandler ;
1314import com .redomar .game .lib .Either ;
1415import com .redomar .game .lib .Font ;
2324import java .awt .image .BufferStrategy ;
2425import java .awt .image .BufferedImage ;
2526import java .awt .image .DataBufferInt ;
27+ import java .io .Serial ;
2628
2729/*
2830 * This module forms the core architecture of the JavaGame. It coordinates the various
3335public class Game extends Canvas implements Runnable {
3436
3537 // Setting the size and name of the frame/canvas
38+ @ Serial
3639 private static final long serialVersionUID = 1L ;
3740 private static final String game_Version = "v1.8.6 Alpha" ;
38- private static final int WIDTH = 160 ;
39- private static final int HEIGHT = (WIDTH / 3 * 2 );
40- private static final int SCALE = 3 ;
41+ private static final int SCALE = 100 ;
42+ private static final int WIDTH = 3 * SCALE ;
43+ private static final int SCREEN_WIDTH = WIDTH * 2 ;
44+ private static final int HEIGHT = (2 * SCALE );
45+ private static final int SCREEN_HEIGHT = (HEIGHT * 2 ) + 30 ;
46+ private static final Screen screen = new Screen (WIDTH , HEIGHT , new SpriteSheet ("/sprite_sheet.png" ));
4147 private static final String NAME = "Game" ; // The name of the JFrame panel
4248 private static final Time time = new Time (); // Represents the calendar's time value, in hh:mm:ss
4349 private static final boolean [] alternateCols = new boolean [2 ]; // Boolean array describing shirt and face colour
44-
4550 private static Game game ;
46-
4751 // The properties of the player, npc, and fps/tps
4852 private static boolean changeLevel = false ; // Determines whether the player teleports to another level
4953 private static boolean npc = false ; // Non-player character (NPC) initialized to non-existing
5054 private static int map = 0 ; // Map of the level, initialized to map default map
5155 private static int shirtCol ; // The colour of the character's shirt
52- private static int faceCol ; // The colour (ethnicity ) of the character (their face)
56+ private static int faceCol ; // The colour (ethnicizty ) of the character (their face)
5357 private static int fps ; // The frame rate (frames per second), frequency at which images are displayed on the canvas
5458 private static int tps ; // The ticks (ticks per second), unit measure of time for one iteration of the game logic loop.
5559 private static int steps ;
5660 private static boolean devMode ; // Determines whether the game is in developer mode
5761 private static boolean closingMode ; // Determines whether the game will exit
58-
62+ private static int tileX = 0 ;
63+ private static int tileY = 0 ;
5964 // Audio, input, and mouse handler objects
6065 private static JFrame frame ;
6166 private static AudioHandler backgroundMusic ;
6267 private static boolean running = false ; // Determines whether the game is currently in process
6368 private static InputHandler input ; // Accepts keyboard input and follows the appropriate actions
6469 private static MouseHandler mouse ; // Tracks mouse movement and clicks, and follows the appropriate actions
6570 private static InputContext context ; // Provides methods to control text input facilities
66-
6771 // Graphics
68- private final BufferedImage image = new BufferedImage (WIDTH , HEIGHT , BufferedImage .TYPE_INT_RGB );
72+ private final BufferedImage image = new BufferedImage (WIDTH , HEIGHT , BufferedImage .TYPE_INT_ARGB );
6973 private final int [] pixels = ((DataBufferInt ) image .getRaster ().getDataBuffer ()).getData (); // Array of red, green and blue values for each pixel
7074 private final int [] colours = new int [6 * 6 * 6 ]; // Array of 216 unique colours (6 shades of red, 6 of green, and 6 of blue)
7175 private final BufferedImage image2 = new BufferedImage (WIDTH , HEIGHT - 30 , BufferedImage .TYPE_INT_RGB );
7276 private final Font font = new Font (); // Font object capable of displaying 2 fonts: Arial and Segoe UI
7377 private final Printer printer = new Printer ();
7478 boolean musicPlaying = false ;
7579 private int tickCount = 0 ;
76- private Screen screen ;
7780 private LevelHandler level ; // Loads and renders levels along with tiles, entities, projectiles and more.
7881 //The entities of the game
7982 private Player player ;
@@ -87,9 +90,9 @@ public Game() {
8790 context = InputContext .getInstance ();
8891
8992 // The game can only be played in one distinct window size
90- setMinimumSize (new Dimension (WIDTH * SCALE , HEIGHT * SCALE ));
91- setMaximumSize (new Dimension (WIDTH * SCALE , HEIGHT * SCALE ));
92- setPreferredSize (new Dimension (WIDTH * SCALE , HEIGHT * SCALE ));
93+ setMinimumSize (new Dimension (SCREEN_WIDTH , SCREEN_HEIGHT ));
94+ setMaximumSize (new Dimension (SCREEN_WIDTH , SCREEN_HEIGHT ));
95+ setPreferredSize (new Dimension (SCREEN_WIDTH , SCREEN_HEIGHT ));
9396
9497 setFrame (new JFrame (NAME )); // Creates the frame with a defined name
9598 getFrame ().setDefaultCloseOperation (JFrame .EXIT_ON_CLOSE ); // Exits the program when user closes the frame
@@ -288,6 +291,28 @@ public static void setClosing(boolean closing) {
288291 Game .closingMode = closing ;
289292 }
290293
294+ private static void mousePositionTracker () {
295+ MouseHandler mouseHandler = Game .getMouse ();
296+ int mouseX = mouseHandler .getX ();
297+ int mouseY = mouseHandler .getY ();
298+
299+ // Adjust mouse coordinates based on the current offset and scale of the game world
300+ tileX = ((mouseX + 4 + screen .getxOffset ()) / (8 * 2 )) + screen .getxOffset () / 16 ;
301+ tileY = ((mouseY + 4 + screen .getyOffset ()) / (8 * 2 )) + screen .getyOffset () / 16 ;
302+ }
303+
304+ public static int getTileX () {
305+ return tileX ;
306+ }
307+
308+ public static int getTileY () {
309+ return tileY ;
310+ }
311+
312+ public static Screen getScreen () {
313+ return screen ;
314+ }
315+
291316 /*
292317 * This method initializes the game once it starts. It populates the colour array with actual colours (6 shades each of RGB).
293318 * This method also builds the initial game level (custom_level), spawns a new vendor NPC, and begins accepting keyboard and mouse input/tracking.
@@ -301,12 +326,16 @@ public void init() {
301326 int rr = (r * 255 / 5 ); // Split all 256 colours into 6 shades (0, 51, 102 ... 255)
302327 int gg = (g * 255 / 5 );
303328 int bb = (b * 255 / 5 );
304- colours [index ++] = rr << 16 | gg << 8 | bb ; // All colour values (RGB) are placed into one 32-bit integer, populating the colour array
329+ // All colour values (RGB) are placed into one 32-bit integer, populating the colour array
330+ // The first 8 bits are for alpha, the next 8 for red, the next 8 for green, and the last 8 for blue
331+ // 0xFF000000 is ignored in BufferedImage.TYPE_INT_RGB, but is used in BufferedImage.TYPE_INT_ARGB
332+ colours [index ++] = 0xFF << 24 | rr << 16 | gg << 8 | bb ;
305333 }
306334 }
307335 }
308336
309- screen = new Screen (WIDTH , HEIGHT , new SpriteSheet ("/sprite_sheet.png" ));
337+ screen .setViewPortHeight (SCREEN_HEIGHT );
338+ screen .setViewPortWidth (SCREEN_WIDTH );
310339 input = new InputHandler (this ); // Input begins to record key presses
311340 setMouse (new MouseHandler (this )); // Mouse tracking and clicking is now recorded
312341// setWindow(new WindowHandler(this));
@@ -343,12 +372,13 @@ public synchronized void stop() {
343372 */
344373 public void run () {
345374 long lastTime = System .nanoTime ();
346- double nsPerTick = 1000000000D / 60D ; // The number of nanoseconds in one tick (number of ticks limited to 60 per update)
375+ int nsPerS = 1_000_000_000 ;
376+ double nsPerTick = nsPerS / 60D ; // The number of nanoseconds in one tick (number of ticks limited to 60 per update)
347377 // 1 billion nanoseconds in one second
348378 int ticks = 0 ;
349379 int frames = 0 ;
350380
351- long lastTimer = System .currentTimeMillis (); // Used for updating ticks and frames once every second
381+ long lastTimer = System .nanoTime (); // Used for updating ticks and frames once every second
352382 double delta = 0 ;
353383
354384 init (); // Initialize the game environment
@@ -371,8 +401,8 @@ public void run() {
371401 render ();
372402 }
373403
374- if (System .currentTimeMillis () - lastTimer >= 1000 ) { // If elapsed time is greater than or equal to 1 second, update
375- lastTimer += 1000 ; // Updates in another second
404+ if (System .nanoTime () - lastTimer >= nsPerS ) { // If elapsed time is greater than or equal to 1 second, update
405+ lastTimer += nsPerS ; // Updates in another second
376406 getFrame ().setTitle ("JavaGame - Version " + WordUtils .capitalize (game_Version ).substring (1 , game_Version .length ()));
377407 fps = frames ;
378408 tps = ticks ;
@@ -393,12 +423,15 @@ public void tick() {
393423 printer .cast ().print ("Failed to play music" , PrintTypes .MUSIC );
394424 printer .exception (exception .toString ());
395425 musicPlaying = false ;
396- }, isPlaying -> musicPlaying = isPlaying );
397-
426+ }, isPlaying -> {
427+ musicPlaying = isPlaying ;
428+ if (musicPlaying && !Game .getBackgroundMusic ().getActive ()) {
429+ input .overWriteKey (input .getM_KEY (), false );
430+ }
431+ });
398432 level .tick ();
399433 }
400434
401-
402435 /**
403436 * This method displays the current state of the game.
404437 */
@@ -417,6 +450,7 @@ public void render() {
417450 level .renderEntities (screen );
418451 level .renderProjectileEntities (screen );
419452
453+
420454 for (int y = 0 ; y < screen .getHeight (); y ++) {
421455 for (int x = 0 ; x < screen .getWidth (); x ++) {
422456 int colourCode = screen .getPixels ()[x + y * screen .getWidth ()];
@@ -452,10 +486,10 @@ public void render() {
452486 changeLevel = false ;
453487 }
454488
455- Graphics g = bs .getDrawGraphics ();
456- g .drawRect (0 , 0 , getWidth (), getHeight ());
489+ Graphics2D g = (Graphics2D ) bs .getDrawGraphics ();
457490 g .drawImage (image , 0 , 0 , getWidth (), getHeight () - 30 , null );
458491 status (g , isDevMode (), isClosing ());
492+ overlayRender (g );
459493 g .drawImage (image2 , 0 , getHeight () - 30 , getWidth (), getHeight (), null );
460494 g .setColor (Color .WHITE );
461495 g .setFont (font .getSegoe ());
@@ -484,12 +518,24 @@ public void render() {
484518 bs .show ();
485519 }
486520
521+ /**
522+ * This method renders the overlay of the game, which is a transparent layer that is drawn over the game.
523+ */
524+ private void overlayRender (Graphics2D g ) {
525+ g .setColor (new Color (0f , 0f , 0f , .192f )); // Transparent color
526+ g .fillRect (0 , 0 , getWidth (), getHeight ()-30 );
527+ }
528+
487529 /*
488530 * This method displays information regarding various aspects/stats of the game, dependent upon
489531 * whether it is running in developer mode, or if the application is closing.
490532 */
491- private void status (Graphics g , boolean TerminalMode , boolean TerminalQuit ) {
533+ private void status (Graphics2D g , boolean TerminalMode , boolean TerminalQuit ) {
492534 if (TerminalMode ) {
535+ new Night (g , screen ).render (player .getPlayerAbsX (), player .getPlayerAbsY ());
536+ // make the background transparent
537+ g .setColor (new Color (0 , 0 , 0 , 100 ));
538+ g .fillRect (0 , 0 , 195 , 165 );
493539 g .setColor (Color .CYAN );
494540 g .drawString ("JavaGame Stats" , 0 , 10 );
495541 g .drawString ("FPS/TPS: " + fps + "/" + tps , 0 , 25 );
@@ -499,9 +545,29 @@ private void status(Graphics g, boolean TerminalMode, boolean TerminalQuit) {
499545 g .drawString ("Foot Steps: " + steps , 0 , 40 );
500546 g .drawString ("NPC: " + WordUtils .capitalize (String .valueOf (isNpc ())), 0 , 55 );
501547 g .drawString ("Mouse: " + getMouse ().getX () + "x |" + getMouse ().getY () + "y" , 0 , 70 );
502- if (getMouse ().getButton () != -1 ) g .drawString ("Button: " + getMouse ().getButton (), 0 , 85 );
503- g .setColor (Color .CYAN );
504- g .fillRect (getMouse ().getX () - 12 , getMouse ().getY () - 12 , 24 , 24 );
548+ g .drawString ("Mouse: " + (getMouse ().getX () - 639 / 2d ) + "x |" + (getMouse ().getY () - 423 / 2d ) + "y" , 0 , 85 );
549+ if (getMouse ().getButton () != -1 ) g .drawString ("Button: " + getMouse ().getButton (), 0 , 100 );
550+ mousePositionTracker ();
551+ g .drawString ("Player: " + (int ) player .getX () + "x |" + (int ) player .getY () + "y" , 0 , 115 );
552+ double angle = Math .atan2 (getMouse ().getY () - player .getPlayerAbsY (), getMouse ().getX () - player .getPlayerAbsX ()) * (180.0 / Math .PI );
553+ g .drawString ("Angle: " + angle , 0 , 130 );
554+
555+ g .setColor (Color .cyan );
556+ g .drawString ("Player: \t \t \t \t \t \t \t \t \t \t \t \t " + player .getPlayerAbsX () + "x |" + player .getPlayerAbsY () + "y" , 0 , 145 );
557+ g .drawString ("Player Offset: \t " + screen .getxOffset () + "x |" + screen .getyOffset () + "y" , 0 , 160 );
558+
559+ // Set a different color for the player-origin line
560+ g .setStroke (new BasicStroke (1 ));
561+ g .setColor (Color .GREEN ); // Green for the new line from the player's origin
562+ g .drawLine (player .getPlayerAbsX (), player .getPlayerAbsY (), getMouse ().getX (), getMouse ().getY ()); // Draw the line from the player's origin to the cursor
563+ g .setColor (Color .DARK_GRAY );
564+ g .drawLine (getWidth () / 2 + 8 , getHeight () / 2 - 8 , getMouse ().getX (), getMouse ().getY ()); // Draw the line from the player's origin to the cursor
565+ g .drawLine (getWidth () / 2 + 8 , 0 , getWidth () / 2 + 8 , getHeight () - 30 );
566+ g .drawLine (0 , getHeight () / 2 - 8 , getWidth (), getHeight () / 2 - 8 );
567+ g .setColor (Color .yellow );
568+ g .fillRect (player .getPlayerAbsX (), player .getPlayerAbsY (), 1 , 1 );
569+
570+
505571 }
506572 // If the game is shutting off
507573 if (!TerminalQuit ) {
@@ -529,5 +595,4 @@ public Vendor getVendor() {
529595 public void setVendor (Vendor vendor ) {
530596 this .vendor = vendor ;
531597 }
532-
533598}
0 commit comments