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 ;
37- 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 ;
40+ private static final String game_Version = "v1.8.7 Alpha" ;
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" ));
47+ private static final Screen screen2 = new Screen (WIDTH , HEIGHT , new SpriteSheet ("/sprite_sheet.png" ));
4148 private static final String NAME = "Game" ; // The name of the JFrame panel
4249 private static final Time time = new Time (); // Represents the calendar's time value, in hh:mm:ss
4350 private static final boolean [] alternateCols = new boolean [2 ]; // Boolean array describing shirt and face colour
44-
4551 private static Game game ;
46-
4752 // The properties of the player, npc, and fps/tps
4853 private static boolean changeLevel = false ; // Determines whether the player teleports to another level
4954 private static boolean npc = false ; // Non-player character (NPC) initialized to non-existing
@@ -55,25 +60,26 @@ public class Game extends Canvas implements Runnable {
5560 private static int steps ;
5661 private static boolean devMode ; // Determines whether the game is in developer mode
5762 private static boolean closingMode ; // Determines whether the game will exit
58-
63+ private static int tileX = 0 ;
64+ private static int tileY = 0 ;
5965 // Audio, input, and mouse handler objects
6066 private static JFrame frame ;
6167 private static AudioHandler backgroundMusic ;
6268 private static boolean running = false ; // Determines whether the game is currently in process
6369 private static InputHandler input ; // Accepts keyboard input and follows the appropriate actions
6470 private static MouseHandler mouse ; // Tracks mouse movement and clicks, and follows the appropriate actions
6571 private static InputContext context ; // Provides methods to control text input facilities
66-
6772 // Graphics
68- private final BufferedImage image = new BufferedImage (WIDTH , HEIGHT , BufferedImage .TYPE_INT_RGB );
73+ private final BufferedImage image = new BufferedImage (WIDTH , HEIGHT , BufferedImage .TYPE_INT_ARGB );
74+ private final BufferedImage image3 = new BufferedImage (WIDTH , HEIGHT , BufferedImage .TYPE_INT_ARGB );
6975 private final int [] pixels = ((DataBufferInt ) image .getRaster ().getDataBuffer ()).getData (); // Array of red, green and blue values for each pixel
76+ private final int [] pixels3 = ((DataBufferInt ) image3 .getRaster ().getDataBuffer ()).getData (); // Array of red, green and blue values for each pixel
7077 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)
7178 private final BufferedImage image2 = new BufferedImage (WIDTH , HEIGHT - 30 , BufferedImage .TYPE_INT_RGB );
7279 private final Font font = new Font (); // Font object capable of displaying 2 fonts: Arial and Segoe UI
7380 private final Printer printer = new Printer ();
7481 boolean musicPlaying = false ;
7582 private int tickCount = 0 ;
76- private Screen screen ;
7783 private LevelHandler level ; // Loads and renders levels along with tiles, entities, projectiles and more.
7884 //The entities of the game
7985 private Player player ;
@@ -87,9 +93,9 @@ public Game() {
8793 context = InputContext .getInstance ();
8894
8995 // 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 ));
96+ setMinimumSize (new Dimension (SCREEN_WIDTH , SCREEN_HEIGHT ));
97+ setMaximumSize (new Dimension (SCREEN_WIDTH , SCREEN_HEIGHT ));
98+ setPreferredSize (new Dimension (SCREEN_WIDTH , SCREEN_HEIGHT ));
9399
94100 setFrame (new JFrame (NAME )); // Creates the frame with a defined name
95101 getFrame ().setDefaultCloseOperation (JFrame .EXIT_ON_CLOSE ); // Exits the program when user closes the frame
@@ -288,6 +294,28 @@ public static void setClosing(boolean closing) {
288294 Game .closingMode = closing ;
289295 }
290296
297+ private static void mousePositionTracker () {
298+ MouseHandler mouseHandler = Game .getMouse ();
299+ int mouseX = mouseHandler .getX ();
300+ int mouseY = mouseHandler .getY ();
301+
302+ // Adjust mouse coordinates based on the current offset and scale of the game world
303+ tileX = ((mouseX + 4 + screen .getxOffset ()) / (8 * 2 )) + screen .getxOffset () / 16 ;
304+ tileY = ((mouseY + 4 + screen .getyOffset ()) / (8 * 2 )) + screen .getyOffset () / 16 ;
305+ }
306+
307+ public static int getTileX () {
308+ return tileX ;
309+ }
310+
311+ public static int getTileY () {
312+ return tileY ;
313+ }
314+
315+ public static Screen getScreen () {
316+ return screen ;
317+ }
318+
291319 /*
292320 * This method initializes the game once it starts. It populates the colour array with actual colours (6 shades each of RGB).
293321 * 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 +329,18 @@ public void init() {
301329 int rr = (r * 255 / 5 ); // Split all 256 colours into 6 shades (0, 51, 102 ... 255)
302330 int gg = (g * 255 / 5 );
303331 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
332+ // All colour values (RGB) are placed into one 32-bit integer, populating the colour array
333+ // The first 8 bits are for alpha, the next 8 for red, the next 8 for green, and the last 8 for blue
334+ // 0xFF000000 is ignored in BufferedImage.TYPE_INT_RGB, but is used in BufferedImage.TYPE_INT_ARGB
335+ colours [index ++] = 0xFF << 24 | rr << 16 | gg << 8 | bb ;
305336 }
306337 }
307338 }
308339
309- screen = new Screen (WIDTH , HEIGHT , new SpriteSheet ("/sprite_sheet.png" ));
340+ screen .setViewPortHeight (SCREEN_HEIGHT );
341+ screen2 .setViewPortHeight (SCREEN_HEIGHT );
342+ screen .setViewPortWidth (SCREEN_WIDTH );
343+ screen2 .setViewPortWidth (SCREEN_WIDTH );
310344 input = new InputHandler (this ); // Input begins to record key presses
311345 setMouse (new MouseHandler (this )); // Mouse tracking and clicking is now recorded
312346// setWindow(new WindowHandler(this));
@@ -343,12 +377,13 @@ public synchronized void stop() {
343377 */
344378 public void run () {
345379 long lastTime = System .nanoTime ();
346- double nsPerTick = 1000000000D / 60D ; // The number of nanoseconds in one tick (number of ticks limited to 60 per update)
380+ int nsPerS = 1_000_000_000 ;
381+ double nsPerTick = nsPerS / 60D ; // The number of nanoseconds in one tick (number of ticks limited to 60 per update)
347382 // 1 billion nanoseconds in one second
348383 int ticks = 0 ;
349384 int frames = 0 ;
350385
351- long lastTimer = System .currentTimeMillis (); // Used for updating ticks and frames once every second
386+ long lastTimer = System .nanoTime (); // Used for updating ticks and frames once every second
352387 double delta = 0 ;
353388
354389 init (); // Initialize the game environment
@@ -371,8 +406,8 @@ public void run() {
371406 render ();
372407 }
373408
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
409+ if (System .nanoTime () - lastTimer >= nsPerS ) { // If elapsed time is greater than or equal to 1 second, update
410+ lastTimer += nsPerS ; // Updates in another second
376411 getFrame ().setTitle ("JavaGame - Version " + WordUtils .capitalize (game_Version ).substring (1 , game_Version .length ()));
377412 fps = frames ;
378413 tps = ticks ;
@@ -393,12 +428,15 @@ public void tick() {
393428 printer .cast ().print ("Failed to play music" , PrintTypes .MUSIC );
394429 printer .exception (exception .toString ());
395430 musicPlaying = false ;
396- }, isPlaying -> musicPlaying = isPlaying );
397-
431+ }, isPlaying -> {
432+ musicPlaying = isPlaying ;
433+ if (musicPlaying && !Game .getBackgroundMusic ().getActive ()) {
434+ input .overWriteKey (input .getM_KEY (), false );
435+ }
436+ });
398437 level .tick ();
399438 }
400439
401-
402440 /**
403441 * This method displays the current state of the game.
404442 */
@@ -425,6 +463,16 @@ public void render() {
425463 }
426464 }
427465 }
466+ for (int y = 0 ; y < screen2 .getHeight (); y ++) {
467+ for (int x = 0 ; x < screen2 .getWidth (); x ++) {
468+ int colourCode = screen2 .getPixels ()[x + y * screen2 .getWidth ()];
469+ if (colourCode < 1 ){
470+ pixels3 [x + y * WIDTH ] = 0xff0000 ;
471+ } else if (colourCode < 255 ) {
472+ pixels3 [x + y * WIDTH ] = colours [colourCode ];
473+ }
474+ }
475+ }
428476
429477 if (isChangeLevel () && getTickCount () % 60 == 0 ) {
430478 Game .setChangeLevel (true );
@@ -452,10 +500,10 @@ public void render() {
452500 changeLevel = false ;
453501 }
454502
455- Graphics g = bs .getDrawGraphics ();
456- g .drawRect (0 , 0 , getWidth (), getHeight ());
503+ Graphics2D g = (Graphics2D ) bs .getDrawGraphics ();
457504 g .drawImage (image , 0 , 0 , getWidth (), getHeight () - 30 , null );
458505 status (g , isDevMode (), isClosing ());
506+ overlayRender (g );
459507 g .drawImage (image2 , 0 , getHeight () - 30 , getWidth (), getHeight (), null );
460508 g .setColor (Color .WHITE );
461509 g .setFont (font .getSegoe ());
@@ -484,12 +532,24 @@ public void render() {
484532 bs .show ();
485533 }
486534
535+ /**
536+ * This method renders the overlay of the game, which is a transparent layer that is drawn over the game.
537+ */
538+ private void overlayRender (Graphics2D g ) {
539+ g .setColor (new Color (0f , 0f , 0f , 0f )); // Transparent color
540+ g .fillRect (0 , 0 , getWidth (), getHeight ()-30 );
541+ }
542+
487543 /*
488544 * This method displays information regarding various aspects/stats of the game, dependent upon
489545 * whether it is running in developer mode, or if the application is closing.
490546 */
491- private void status (Graphics g , boolean TerminalMode , boolean TerminalQuit ) {
547+ private void status (Graphics2D g , boolean TerminalMode , boolean TerminalQuit ) {
492548 if (TerminalMode ) {
549+ new Night (g , screen ).render (player .getPlayerAbsX (), player .getPlayerAbsY ());
550+ // make the background transparent
551+ g .setColor (new Color (0 , 0 , 0 , 100 ));
552+ g .fillRect (0 , 0 , 195 , 165 );
493553 g .setColor (Color .CYAN );
494554 g .drawString ("JavaGame Stats" , 0 , 10 );
495555 g .drawString ("FPS/TPS: " + fps + "/" + tps , 0 , 25 );
@@ -499,9 +559,29 @@ private void status(Graphics g, boolean TerminalMode, boolean TerminalQuit) {
499559 g .drawString ("Foot Steps: " + steps , 0 , 40 );
500560 g .drawString ("NPC: " + WordUtils .capitalize (String .valueOf (isNpc ())), 0 , 55 );
501561 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 );
562+ g .drawString ("Mouse: " + (getMouse ().getX () - 639 / 2d ) + "x |" + (getMouse ().getY () - 423 / 2d ) + "y" , 0 , 85 );
563+ if (getMouse ().getButton () != -1 ) g .drawString ("Button: " + getMouse ().getButton (), 0 , 100 );
564+ mousePositionTracker ();
565+ g .drawString ("Player: " + (int ) player .getX () + "x |" + (int ) player .getY () + "y" , 0 , 115 );
566+ double angle = Math .atan2 (getMouse ().getY () - player .getPlayerAbsY (), getMouse ().getX () - player .getPlayerAbsX ()) * (180.0 / Math .PI );
567+ g .drawString ("Angle: " + angle , 0 , 130 );
568+
569+ g .setColor (Color .cyan );
570+ g .drawString ("Player: \t \t \t \t \t \t \t \t \t \t \t \t " + player .getPlayerAbsX () + "x |" + player .getPlayerAbsY () + "y" , 0 , 145 );
571+ g .drawString ("Player Offset: \t " + screen .getxOffset () + "x |" + screen .getyOffset () + "y" , 0 , 160 );
572+
573+ // Set a different color for the player-origin line
574+ g .setStroke (new BasicStroke (1 ));
575+ g .setColor (Color .GREEN ); // Green for the new line from the player's origin
576+ g .drawLine (player .getPlayerAbsX (), player .getPlayerAbsY (), getMouse ().getX (), getMouse ().getY ()); // Draw the line from the player's origin to the cursor
577+ g .setColor (Color .DARK_GRAY );
578+ g .drawLine (getWidth () / 2 + 8 , getHeight () / 2 - 8 , getMouse ().getX (), getMouse ().getY ()); // Draw the line from the player's origin to the cursor
579+ g .drawLine (getWidth () / 2 + 8 , 0 , getWidth () / 2 + 8 , getHeight () - 30 );
580+ g .drawLine (0 , getHeight () / 2 - 8 , getWidth (), getHeight () / 2 - 8 );
581+ g .setColor (Color .yellow );
582+ g .fillRect (player .getPlayerAbsX (), player .getPlayerAbsY (), 1 , 1 );
583+
584+
505585 }
506586 // If the game is shutting off
507587 if (!TerminalQuit ) {
@@ -529,5 +609,4 @@ public Vendor getVendor() {
529609 public void setVendor (Vendor vendor ) {
530610 this .vendor = vendor ;
531611 }
532-
533612}
0 commit comments