Jump to content
  • Advertisement
Sign in to follow this  
  • entries
    11
  • comments
    0
  • views
    764

AWT GUI Facade (6): Mouse and Game Loop

Sign in to follow this  
phylyp

899 views

After loading a level, I now propose to add interaction with the use of a mouse. This will be an opportunity to see two other patterns: the Observer Pattern to handle mouse events, and the Game Loop Pattern for synchronization between controls, updates, and display.

This post is part of the AWT GUI Facade series

Mouse Facade

To add the management of the mouse to the facade, I propose to introduce a new Mouse interface that contains all the functions related to the mouse:

Mouse Facade

Separating the interface for the mouse from the general interface of the facade has two advantages: lighten the general interface and allow the simultaneous management of several mice.

As far as methods are concerned, I chose the simplest API possible:

  • isButtonPressed() method: returns true if a button is pressed;
  • getX() and getY() methods: return the (x, y) coordinates of the cursor in the window

This API is also lowlevel, to match what most graphic libraries offer. In addition, it allows having at any time the complete state of the mouse, which is often necessary for video games.

For the general GUIFacade interface, a new getMouse() method is added to return an implementation of the Mouse interface.

Mouse handling in AWT

To implement this interface, AWT library included in the standard Java library is still used. This one offers a high-level API, which meets the needs of office applications. It is based on the Observer Pattern, which allows an element to observe (or listen to) another element, and to be notified when an event occurs. In the case of the mouse, these events are for example the pressure of a button or the movement of the cursor.

This API is divided into several interfaces, for example, the interface MouseListener allows to manage the events related to the buttons:

Mouse handling in Java AWT library with the Observer Pattern

The MouseListener interface contains the methods implemented by the observer: for example, when a button is pressed, the mousePressed() method is called and the observer can then act accordingly. The Component class, which is the superclass of many graphic components within AWT, can be observed by anyone who requests it thanks to the addMouseListener() method. For the example of this article, it is the Canvas used to make the level of the game that is observed: each action of the mouse in its display area causes calls to the methods of the MouseListener interface.

Facade implementation

I propose that the implementation of the Mouse interface of the facade takes the form of an AWTMouse class:

Java AWT implementation of the mouse Facade

The class implements the Mouse, MouseListener, and MouseMotionListener interfaces. The first methods provide information about the mouse (contained in its attributes):

public class AWTMouse implements Mouse, MouseListener, MouseMotionListener {

    private final boolean[] buttons;

    private int x;

    private int y;
    
    public AWTMouse() {
        buttons = new boolean[4];
    }

    @Override
    public boolean isButtonPressed(int button) {
        if (button >= buttons.length) {
            return false;
        }
        return buttons[button];
    }

    @Override
    public int getX() {
        return x;
    }

    @Override
    public int getY() {
        return y;
    }

    ...

The following ones respond to mouse events and update mouse information:

@Override
    public void mouseClicked(MouseEvent e) {
    }

    @Override
    public void mousePressed(MouseEvent e) {
        if (e.getButton() <= 3) {
            buttons[e.getButton()] = true;
        }
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        if (e.getButton() <= 3) {
            buttons[e.getButton()] = false;
        }
    }

    @Override
    public void mouseEntered(MouseEvent e) {
    }

    @Override
    public void mouseExited(MouseEvent e) {
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        x = e.getX();
        y = e.getY();
    }

    @Override
    public void mouseMoved(MouseEvent e) {
        x = e.getX();
        y = e.getY();
    }
}

Finally, the AWTWindow class contains as before the canvas, and this one is used to “listen” the events of the mouse:

public void init(String title, int width, int height) {

    ...

    mouse = new AWTMouse();
    canvas.addMouseListener(mouse);
    canvas.addMouseMotionListener(mouse);
}

Game Loop

It only remains to exploit this new interface in an example. To do this, I propose to introduce the Game Loop Pattern in its simplest version (without multi-threaded considerations). It is based on a set of methods that can be grouped together in the same class:

Game Loop Pattern
  • The init() method is called at startup to initialize the game and its data;
  • The processInput() method is called at each iteration of the game to manage the controls (keyboard, mouse, …). In short, its main role is to transform the user’s “instructions” into more abstract “orders” or “commands” that the game engine knows how to interpret. Considering time, these operations go to the rhythm of the user.
  • The update() method applies changes to game data based on various sources, such as commands produced by user controls or operations that must be applied to each update. Considering time, these operations go to the speed of the game engine.
  • The render() method handles display. This method will most often order or transfer data on the graphics card, the latter dealing with very low-level tasks at the pixel level. Considering time, these operations go to the refresh rate of the screen (default 60Hz).
  • The run() method calls the previous ones and contains the actual game loop.

In this example, I don’t implement all the elements required to meet all these principles. I propose here a basic form of this pattern, sufficient to begin to understand all these notions.

For the init() method, we build the two layers and initialize the window:

public void init(Level level) {
    this.level = level;

    backgroundLayer = gui.createLayer();
    backgroundLayer.setTileSize(level.getTileWidth(),level.getTileHeight());
    backgroundLayer.setTexture(level.getTilesetImage(0));
    backgroundLayer.setSpriteCount(level.getWidth()*level.getHeight());

    groundLayer = gui.createLayer();
    groundLayer.setTileSize(level.getTileWidth(),level.getTileHeight());
    groundLayer.setTexture(level.getTilesetImage(1));
    groundLayer.setSpriteCount(level.getWidth()*level.getHeight());

    gui.createWindow("Exemple de contrôle avec la souris",
        scale*level.getTileWidth()*level.getWidth(),
        scale*level.getTileHeight()*level.getHeight());
}

For the processInput() method, if the following conditions are met:

  • the left button is pressed;
  • there is a cell of the level under the cursor;
  • the tile of this cell is in the second set of tiles (the one of the second layer),

then we put a tile with grass (this will erase all buildings in the map):

public void processInput() {
    Mouse mouse = gui.getMouse();
    if (mouse.isButtonPressed(MouseEvent.BUTTON1)) {
        int x = mouse.getX() / (scale*level.getTileWidth());
        int y = mouse.getY() / (scale*level.getTileHeight());
        if (x >= 0 && x < level.getWidth() && y >= 0 && y < level.getHeight()) {
            if (level.getTileset(x,y) == 1) {
                level.setTileset(x,y,0);
                level.setTile(x,y,new Point(7,0));
            }
        }
    }
}

For the update() method, the content of the level data is used to define the sprite textures. It is the same as in the previous post, except that this operation is repeated regularly:

public void update() {
    for(int y=0;y<level.getHeight();y++) {
        for(int x=0;x<level.getWidth();x++) {
            int index = x + y * level.getWidth();
            backgroundLayer.setSpriteLocation(index, new Rectangle(scale*x*level.getTileWidth(), scale*y*level.getTileHeight(), scale*level.getTileWidth(), scale*level.getTileHeight()));
            if (level.getTileset(x, y) == 0) {
                Rectangle tile = new Rectangle(level.getTile(x, y), new Dimension(1,1));
                backgroundLayer.setSpriteTexture(index, tile);
            }
            else {
                backgroundLayer.setSpriteTexture(index, null);
            }
        }
    }

    for(int y=0;y<level.getHeight();y++) {
        for(int x=0;x<level.getWidth();x++) {
            int index = x + y * level.getWidth();
            groundLayer.setSpriteLocation(index, new Rectangle(scale*x*level.getTileWidth(), scale*(y-1)*level.getTileHeight(), scale*level.getTileWidth(), scale*2*level.getTileHeight()));
            if (level.getTileset(x, y) == 1) {
                Rectangle tile = new Rectangle(level.getTile(x, y), new Dimension(1,2));
                groundLayer.setSpriteTexture(index, tile);
            }
            else {
                groundLayer.setSpriteTexture(index, null);
            }
        }
    }
}

The render() method just draws the two layers:

public void render() {
    if (gui.beginPaint()) {
        gui.drawLayer(backgroundLayer);
        gui.drawLayer(groundLayer);
        gui.endPaint();
    }
}

Finally, the run() method contains the game loop that calls the other methods at most 60 times per second:

public void run() {

    int fps = 60;
    long nanoPerFrame = (long) (1000000000.0 / fps);
    long lastTime = 0;

    while(!gui.isClosingRequested()) {
        long nowTime = System.nanoTime();
        if ((nowTime-lastTime) < nanoPerFrame) {
            continue;
        }
        lastTime = nowTime;            

        processInput();
        update();
        render();

        long elapsed = System.nanoTime() - lastTime;
        long milliSleep = (nanoPerFrame - elapsed) / 1000000;
        if (milliSleep > 0) {
            try {
                Thread.sleep (milliSleep);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }               
    }      
    gui.dispose();        
}

This basic implementation of the Game Loop pattern does not respect all its principles. There is no real notion of control, and it will be difficult to run each part at different rates. In addition, in terms of design, there are also questionable choices, like the Level class that serves as both a level loader, storage for the level, and a form of buffer. Through future posts, I will present all that is needed to achieve more effective implementations.

The code of this post can be downloaded here:

To compile: javac com/learngameprog/awtfacade06/Main.java
To run: java com.learngameprog.awtfacade06.Main

The post AWT GUI Facade (6): Mouse and Game Loop appeared first on Design Patterns and Video Games.


View the full article

Sign in to follow this  


0 Comments


Recommended Comments

There are no comments to display.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement
  • Advertisement
  • Blog Entries

  • Similar Content

    • By basnijhof01
      Okay so, I have just finished a Unity 2D course and I have this idea for a game I wanted to make.
      I want to make a Pokémon-like game that's called Pokémon Forest, it's called Pokémon Forest cause you will be able to play all the different Pokémon professors when they were young and trainers themselves. It's a huge open world game with every single region in it. Here are the main aspects of the game:
      Playable characters:
      Samuel Oak, who will be played in the Kanto region. His specialty will be the study of the relationships between people and Pokémon.
      Jonas Elm, who will be played in the Johto region. His specialty will be the study of breeding patterns and interactions between Pokémon.
      James Birch, will be played in the Hoenn region. His specialty will be the study of Pokémon habitats in correlation with human existences.
      Oliver Rowan, who will be played in the Sinnoh region. His specialty will be the study of Pokémon evolutionary patterns.
      Aurea Juniper, who will be played in the Unova region. Her specialty will be the study of Pokémon origins in relation to mythology.
      Augustine Sycamore, who will be played in the Kalos region. His specialty will be the study of the new type of evolution: "Mega Evolution".
      Noah Kukui, who will be played in the Alola region. His specialty will be the study of Pokémon moves and will sometimes get himself hit to study the moves.
      Emily Magnolia, who will be played in the Galar region. Her specialty will be the study of the new type of Phenomenon: "Dynamax".
       
      Base Story for every character:
      The choice between three starter Pokémon that have Grass, Fire, and Water as their primary types (they will encounter them in some way)
      A villainous team serving as the main antagonists of the game, so 8 different teams, 1 per character.
      A rival who starts their journey at the same time as the player, and is found multiple times throughout the game, so 8 rivals, 1 per character.
      The player challenges eight Gym Leaders, as well as the Elite Four and Pokémon Champion. Except for Noah Kukui, in Alola Gym Leaders are replaced by the island challenge.
       
      Other aspects of the game:
      It will be a 2D pixelated-like game.
      GTA 5 style, you have 8 different playable characters which will all be playable and you will be able to switch between them whenever you want.
      You play all the different pokemon professors when they were young.
      The professors were 11/12 years old, so the game will take place around 50 years ago.
      It's one big open world game where you can visit all the different regions: Kanto, Johto, Hoenn, Sinnoh, Unova, Kalos, Alola and Galar.
      Every professor has to defeat its own evil team and later on they have to work together to beat one BIG team: Team Rocket.
      The leader of team Rocket will be Giuseppe, Giovanni's father.
      Team Rocket will be unlocked after every character has defeated the elite four (they can only defeat the elite four after they defeated their region's evil team).
      You will be able to catch all 59 legendary Pokémon.
      All the gym leaders will be different from the original games(except the ones who were pretty old in the original games)
      The player is able to have six Pokémon with him at most, while additional Pokémon can be kept in the Pokémon Storage System, 8 different Storage Systems for 8 different players.
      The playable characters will be able to trade Pokémon and items with each other.
      Evolution via leveling up, trade, and evolutionary stones.
      Every region will have its original Pokémon, so for example Kanto will have the original 151 Pokémon.
      Every pokemon will have 1 or 2 types, there are 18 different types in total.
      There will be 742 different moves, all from the original Pokémon games.
      All moves will be TMs, except the Z-powered moves and moves who belong to that Pokémon (like Spirit Shackle for Decidueye).
      The HMs will also be replaced by TMs, the Pokémon who were able to learn the HMs don't need the HMs to do the specific action. For example Diglett could learn Cut and Rock Smash,
      so now it can Cut through trees and Smash Rocks without having to learn the move, you just need to have him in your party.
      There will be a friendship system, however, there will be no Poké Pelago and Pokémon-Amie.
       
      So this is it. I still need to make all the different storylines for the different characters. Does anyone have any tips on how to make the game not boring, cause it is a long ass game. I will give the different characters different specialties, so they will have different abilities or something. That will make it so that the player will want to play the different characters.
      Thanks in advance!
    • By GriffKA
      We glad to introduce the very first concept of the game for you! 🙂 Don’t blame us for poor graphics and outdated technologies (the prototype is written in Flash to speed up development).
      perimetria.griffgriffgames.com
      Originally, the concept was borrowed from an educational game for children where every child has to position a rectangle on paper to avoid overlapping with already positioned figures. We thought that it would become really fun if we add some extra features to make the process more challenging.
      We're waiting for your feedback!


    • By ToeBeans The Brave
      Okay, this would be for a PC game. It would be a pixel 2D fighting game with heavy story elements.
       
      General Story:
      A girl is sent to a mysterious medical facility that houses different kinds of "summoners", or people who accidentally end up summoning manifestations of their emotions. It is more of an experimental kind of set up rather than the helpful facade that the caretakers like to put up, and there are a lot of odd rules in place that keep the residents from wandering the hallways or contacting anyone outside of the walls.
      The girl suffers from OCD, and it gives her a lot of anxiety that ends up turning into small, dark creatures that she has to fight off on occasion. Throughout her stay at the facility, she meets and becomes friends with various caretakers, such as the doctors and nurses, and other patients who have their own monsters to deal with.
      Everything is calm, and peaceful. That is, until people at the facility start disappearing. It started with one staff member. Then another. Now even the patients are starting to go missing. The facility tries to play it off as if everything is normal, but even they can't cover up the strange noises at night, and the rumors of something terrible going on within the walls of what was thought to be a safe place.\As tension and anxiety rises, all of the monsters become stronger and more aggressive.
      And so the girl, along with her new friends, decide to investigate what exactly is going on by sneaking around the facility and collecting clues, all the while fighting against their inner demons.
       
      I am not experienced with making stories, so please judge the crap out of this so I know what to improve on. If I made something too ambiguous, I'd be happy to clarify what I mean, or give a more detailed description.
    • By Brad B
      I have always loved video games and in the last few years I've been trying to learn how to make them. While I'm learning and practicing and growing in many areas, my real strength has always been in story telling. I've been imaging stories, worlds and characters all my life. So far, the only way I've shared them is word of mouth. Explaining them to friends about them when hanging out. Telling them to girlfriends when cuddling for a sort of "story time". I've gotten a reputation for being rather good at "Story Telling". Problem is, I'm not good at writing.
      I've often thought that I could really make something great within the medium of video games though. So, in the business world of game design, is there a place for Story Tellers? Where I could build a world and the story of the characters in it, and work with the team of developers to make it into a product? And how would I find a position like that?
      Because, I truly think I could be great at that. I've thought before that If I could find the right person to show it to, I could put together a sort of portfolio, showcasing a selection of, lets say, 3 concepts. With summaries of the World, characters, plot, etc. I really feel I have a gift for this, and many other people have recognized the same. I just need to know where to take this gift to use it.
    • By WinterDragon
      I'm learning javascript for game development.
      One of my side projects is to build a database that I can enter images and data into, which can then output visual assets based on images and data into a pre-built video game environment.
      thinking about building the database first, what could I use to program this? mysql?
      anatomical database for creature creation sandbox - open source indie video game
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!