Jump to content
  • Advertisement

Search the Community

Showing results for tags 'Concept'.

The search index is currently processing. Current results may not be complete.


More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Categories

  • Audio
    • Music and Sound FX
  • Business
    • Business and Law
    • Career Development
    • Production and Management
  • Game Design
    • Game Design and Theory
    • Writing for Games
    • UX for Games
  • Industry
    • Interviews
    • Event Coverage
  • Programming
    • Artificial Intelligence
    • General and Gameplay Programming
    • Graphics and GPU Programming
    • Engines and Middleware
    • Math and Physics
    • Networking and Multiplayer
  • Visual Arts
  • Archive

Categories

  • Audio
  • Visual Arts
  • Programming
  • Writing

Categories

  • Game Dev Loadout
  • Game Dev Unchained

Categories

  • Game Developers Conference
    • GDC 2017
    • GDC 2018
  • Power-Up Digital Games Conference
    • PDGC I: Words of Wisdom
    • PDGC II: The Devs Strike Back
    • PDGC III: Syntax Error

Forums

  • Audio
    • Music and Sound FX
  • Business
    • Games Career Development
    • Production and Management
    • Games Business and Law
  • Game Design
    • Game Design and Theory
    • Writing for Games
  • Programming
    • Artificial Intelligence
    • Engines and Middleware
    • General and Gameplay Programming
    • Graphics and GPU Programming
    • Math and Physics
    • Networking and Multiplayer
  • Visual Arts
    • 2D and 3D Art
    • Art Critique and Feedback
  • Community
    • GameDev Challenges
    • GDNet+ Member Forum
    • GDNet Lounge
    • GDNet Comments, Suggestions, and Ideas
    • Coding Horrors
    • Your Announcements
    • Hobby Project Classifieds
    • Indie Showcase
    • Article Writing
  • Affiliates
    • NeHe Productions
    • AngelCode
  • Topical
    • Virtual and Augmented Reality
    • News
  • Workshops
    • C# Workshop
    • CPP Workshop
    • Freehand Drawing Workshop
    • Hands-On Interactive Game Development
    • SICP Workshop
    • XNA 4.0 Workshop
  • Archive
    • Topical
    • Affiliates
    • Contests
    • Technical
  • GameDev Challenges's Topics
  • For Beginners's Forum
  • Unreal Engine Users's Unreal Engine Group Forum
  • Unity Developers's Forum
  • Unity Developers's Asset Share

Calendars

  • Community Calendar
  • Games Industry Events
  • Game Jams
  • GameDev Challenges's Schedule

Blogs

There are no results to display.

There are no results to display.

Product Groups

  • Advertisements
  • GameDev Gear

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


About Me


Website


Role


Twitter


Github


Twitch


Steam

Found 297 results

  1. Tony Vilgotsky

    What makes a game an "indie" game?

    Hello, dear colleagues! Recently I had a long evening of reflections on the topic, what makes a video game an indie game? Of course, indie projects are the whole niche in this days, but it seems sometimes that when some people are talking about “indie games”, they just don’t know what they are talking about. For some reason many people think that being indie means to be a low-qualified person who is obligated to produce tons of clones of classic games which were hits decades ago. And when they come to game making, they even don’t consider an opportunity to create something more original and interesting. They deliberately produce all these clones. Moreover, with deliberately downgraded graphics, sound and mechanics, which makes sense when it comes to retro scene, but… retro scene is a separate scene and all the indie games don’t have to fit its standards. And then they complain: why nobody is buying this? I think that the answer is obvious: modern gamers prefer modern graphics. So why shoot your own leg, filling your game with pixels, which aren’t even “an art”? I’m even silent about the gameplay clones. I think that there should be fewer of them, because indie development is just that thing that gives you freedom to be more original and implement bolder decisions. The world is playing Tetris for 200 years already (correct me if I’m wrong) - and nobody wants to play Tetris with crocodiles instead of bricks. It’s sometimes even getting funny: recently I’ve joined a new team (as a junior writer), making a 3D action/adventure game Between Realms with Unreal engine. This is an indie team and indie game, but the goal is to produce a major hit. The game incorporates modern 3D graphics, cutscenes and professional voice overs. And when we posted some stuff from it on the Internet, some people just didn’t believe that we are actually an indie team! I think it’s because modern indie projects almost always belong to the pixel scene or notably simplified from the visual side. So, when we show our materials, some people don’t believe that we belong to indie niche. Does it mean that one has to produce simple games with poor 2D pixel graphics to be considered an indie developer? From my (and my colleagues’) point of view, indie development must be not a compromise between production speed, expense and quality, but a freedom to create a conceptual product which is not limited by obligatory to sell millions of copies. Those who are tied by this obligatory, are forced to produce standardized, so to say, “tentpole” projects. But with modern technologies the developer is able to create nice, commercially promising, but still an independent project. As developers, we want to raise the bar of indie standard and wish all the rest to reach the same with the games which would be not only original in terms of gameplay but also attractive visually. What are you thoughts on this matter? Can a project with budget over $100 be called an indie project? What are the main features of typical indie game? What really makes a game an “indie” game?
  2. I continue the extension of the graphic facade (see previous article), with here the addition of a very classic form of drawing for video games: tiles. These make it possible to compose an image using small images called tiles. There are several types of tiles, I propose in this article the simplest case with rectangular tiles. This post is part of the AWT GUI Facade series. For the implementation, the approach that I propose to follow is similar to the one used for images: we use a factory (Factory Method Pattern) to instantiate layers that allow drawing with tiles. On the GUIFacade main interface side, I add the following two methods, one to create a layer, and the other to draw it: For layers (Layer interface), I propose to manage the tiles with one texture image by layer, and with tiles of a fixed size. In addition, the rendering of tiles can be memorized by the layer: in doing so, it is sufficient to indicate which tiles should be displayed in which places, and then the layer will display these tiles continuously. These renderings are called in this article sprites, so as not to confuse them with tiles (e.g., a tile is just a small picture, and a sprite is a small picture displayed at a specific location on the screen). At this stage of design, layers able to renders independently may seem unnecessary: we could continuously consult the game data for rendering. Later, when it will be necessary to make multi-threaded synchronization, independent layers are a blessing. In addition, for low-level implementations (such as OpenGL), it allows you to use vertex buffers, which greatly speeds up rendering. These properties can be obtained via an interface like the following one: The getTileWidth() and getTileHeight() methods return the size of the tiles (for example, 16 by 16 pixels); The getTextureWidth() and getTextureHeight() methods return the number of tiles in the texture image, in width and height; The setTileSize() method is used to set the size of tiles; The setTexture() method is used to define and load the texture image; The setSpriteCount() method is used to set the number of sprites managed by the layer; The setSpriteTexture() method is used to define the tile used by a sprite. The tile rectangle defines the used tile: they are coordinates in tiles, and not in pixels. For example, if the tile size is 16×16 pixels, and the tile rectangle is (3,4,1,2), then the tile location in pixels is (3 * 16,4 * 16,1 * 16,2 * 16) = (48,64,16,32). By convention, if the rectangle argument is null, then the sprite is disabled; The setSpriteLocation() method is used to define the location where the sprite is drawn. The rectangle is in pixels, and may be larger or smaller than the tiles used, to achieve a zoom effect. AWT Implementation For the implementation, we still use the AWT library, with the AWTLayer class (the methods of the Layer interface are not repeated): The tileWidth, tileHeight, textureWidth, and textureHeight attributes define the size of the tiles and the texture image; The texture attribute contains the texture image; The texture and location arrays contain all sprite information: tiles to use and render locations; The draw() method draws the entire layer. Most methods are accessors / mutators (getters / setters) whose implementation is very simple. The draw () method is less obvious: public void draw(Graphics graphics) { for (int i = 0; i < locations.length; i++) { if (textures[i] != null) { graphics.drawImage(texture, locations[i].x, locations[i].y, locations[i].x + locations[i].width, locations[i].y + locations[i].height, textures[i].x * tileWidth, textures[i].y * tileHeight, (textures[i].x+textures[i].width) * tileWidth, (textures[i].y+textures[i].height) * tileHeight, null); } } } All sprites are traversed (l.2), if a sprite is well defined (l.3), we draw an image (l.4-13). Lines 5 to 8 define the rendering location, in pixels: it is the coordinates of the upper left corner and the lower right corner of the rectangle. Lines 9 to 12 define a rectangle in the texture image: all coordinates are multiplied by tile size (tileWidth, tileHeight). Use case To illustrate this facade with tile drawing, I propose to consider two layers: one for the background, and the other for the buildings. In both cases, we consider the same tile size of 16 × 16 pixels, and the same area of rendering (the level of the game) of 17 × 17 tiles. In addition, a scale factor is used to zoom tiles. These parameters are placed in variables: int scale = 2; int tileWidth = 16; int tileHeight = 16; int levelWidth = 17; int levelHeight = 17; For the background layer, each sprite uses only one tile, and we always use the same one: Layer backgroundLayer = gui.createLayer(); backgroundLayer.setTileSize(tileWidth,tileHeight); backgroundLayer.setTexture("advancewars-tileset1.png"); backgroundLayer.setSpriteCount(levelWidth*levelHeight); for(int y=0;y<levelHeight;y++) { for(int x=0;x<levelWidth;x++) { int index = x + y * levelWidth; backgroundLayer.setSpriteLocation(index, new Rectangle(scale*x*tileWidth, scale*y*tileHeight, scale*tileWidth, scale*tileHeight)); backgroundLayer.setSpriteTexture(index, new Rectangle(new Point(7,0), new Dimension(1,1))); } } Lines 1-4 instantiate and initialize the layer. Then, for each cell of the level (l, 5-6), we associate a sprite (l, 7). To achieve this association, it is necessary to define a unique number for each cell of the level: to do this, the cells are numbered from left to right then from top to bottom. The rendering area of each sprite is defined in lines 8-9, which is a simple scaling: everything is multiplied by the tileWidth, tileHeight, and the global scale. Finally, the tile is selected in lines 10-11, with the 8th column of the first line of the texture Point (7,0) and the size of a tile Dimension (1,1) The following layer is used to display buildings, with the particularity that these have a height of two tiles in height: Layer groundLayer = gui.createLayer(); groundLayer.setTileSize(tileWidth,tileHeight); groundLayer.setTexture("advancewars-tileset2.png"); groundLayer.setSpriteCount(2); groundLayer.setSpriteLocation(0, new Rectangle(scale*8*tileWidth, scale*6*tileHeight, scale*tileWidth, scale*2*tileHeight) ); groundLayer.setSpriteTexture(0, new Rectangle(new Point(0,2), new Dimension(1,2))); groundLayer.setSpriteLocation(1, new Rectangle(scale*8*tileWidth, scale*7*tileHeight, scale*tileWidth, scale*2*tileHeight) ); groundLayer.setSpriteTexture(1, new Rectangle(new Point(0,4), new Dimension(1,2))); Lines 1-4 instantiate the layer and initialize its properties: tile size, texture image, and sprite numbers (2). Lines 6 through 11 define the properties of the first sprite (index 0): its render location is at cell (8,6) of the grid (l. 7), its render size equals a tile width and two heights of tiles (l. 8). Its tiles are at coordinates (0,2) in the texture and use a tile of width one and height two (l. 11). Lines 13 to 18 define the properties of the second sprite: it is drawn on the cell just below, and its tiles start at the coordinates (0,4) in the texture. If all goes well, the top of the second building sprite should cover the bottom of the first: Finally, in the game’s main loop, displaying layers is as easy as displaying an image: if (gui.beginPaint()) { gui.drawLayer(backgroundLayer); gui.drawLayer(groundLayer); gui.endPaint(); } The code of this article can be downloaded here: awtfacade04.zip Some improvements have been made compared to the version of the previous article: it uses a canvas and limits the number of images per second. These improvements are purely related to the problems of video games, and does not change the concepts presented above. To compile: javac com/learngameprog/awtfacade04/Main.java To run: java com.learngameprog.awtfacade04.Main Next post in this series View the full article
  3. In this article, I propose to use the Visitor Pattern to easily load a level. The GUI facade in the previous post is used to display the level. This pattern allows (among other things) to easily browse a data structure to extract information. In our case, it is an XML file created by “Tiled Map Editor” which is analyzed to load a level in memory. This post is part of the AWT GUI Facade series I start by creating a level in XML with Tiled: You have to choose in the left panel Tile layer format as “XML”. This produces an XML file that looks like this: <map version="1.0" orientation="orthogonal" renderorder="left-up" width="16" height="16" tilewidth="16" tileheight="16" nextobjectid="1"> <tileset firstgid="1" name="advancewars-tileset1" tilewidth="16" tileheight="16" tilecount="256"> <image source="advancewars-tileset1.png" width="256" height="256"/> </tileset> <tileset firstgid="257" name="advancewars-tileset2" tilewidth="16" tileheight="16" tilecount="256"> <image source="advancewars-tileset2.png" width="256" height="256"/> </tileset> <layer name="Ground" width="16" height="16"> <data> <tile gid="41"/> <tile gid="41"/> <tile gid="41"/> <tile gid="41"/> <tile gid="41"/> <tile gid="41"/> <tile gid="41"/> <tile gid="41"/> ... <tile gid="41"/> </data> </layer> <layer name="Objects" width="16" height="16"> <data> <tile gid="0"/> <tile gid="0"/> <tile gid="0"/> <tile gid="0"/> <tile gid="0"/> ... <tile gid="0"/> <tile gid="0"/> <tile gid="0"/> </data> </layer> </map> We first have a <main> tag with global properties, then two <tileset> tags that define the tile sets used (one for the background, the other for the objects), and finally two <layer> tags that define the tiles for two layers (one for the background, the other for the objects). To decode this file, I propose to use the XML parser included in the standard Java library. It is based on the Visitor pattern, and allows you to easily work on tags without having to worry about character decoding issues. Visitor Pattern The Visitor pattern can be presented as follows: The IElement interface represents the elements of the structure. In this example, there are two possible types of objects: ElementA and ElementB. The interface requires a method like accept() which takes as argument a visitor who implements the IVisitor interface. There can be several ways to visit the structure, and so many other methods similar to accept(). Parameters can also be used to influence the traversal. The IVisitor interface is implemented by the user who wants to traverse the structured data. In general, the interface methods correspond to the different types of elements that compose it: in this example, they are the ElementA and ElementB classes. It is quite possible to imagine other cases that may interest a user, such as being at the beginning or at the end of an element. In all cases, the accept() method calls the methods of the IVisitor interface according to the cases encountered during its course. Within these methods, the user is free to view and modify the data. Load a level To read and store the level information, I define a Level class that contains this information in attributes: public class Level { private ArrayList<String> tilesetImages = new ArrayList(); private int tileWidth; private int tileHeight; private int width; private int height; private int[][][] level; private int tilesetWidth; private int tilesetHeight; private int x; private int y; ... The tilesetImages attribute contains the file names of texture images; The tileWidth and tileHeight attributes contain the width and height of a tile (16 x 16 pixels in our example); The width and height attributes contain the width and height of the level (16 x 16 cells in our example); The level attribute contains for each cell coordinate: the (x, y) tile coordinates of the tile to draw, and the tile set to use. The following attributes are only used to decode the information in the file. To decode the file, I define a LevelLoader class that implements org.xml.sax.helpers.DefaultHandler. The LevelLoader class is the equivalent of the Visitor class in the diagram above, and DefaultHandler is the equivalent of IVisitor. I’m only interested in the startElement() method, equivalent to the visitElementA() and visitElementB() methods in the diagram above. This method is called whenever the parser encounters a new opening tag: public class LevelLoader extends DefaultHandler { public void startElement (String uri, String localName, String qName, Attributes attributes) throws SAXException { if (qName.equals("tileset")) { if (tilesetImages.isEmpty()) { tileWidth = Integer.parseInt(attributes.getValue("tilewidth")); tileHeight = Integer.parseInt(attributes.getValue("tileheight")); } } else if (qName.equals("image")) { if (tilesetImages.isEmpty()) { tilesetWidth = Integer.parseInt(attributes.getValue("width")) / tileWidth; tilesetHeight = Integer.parseInt(attributes.getValue("height")) / tileHeight; } tilesetImages.add(attributes.getValue("source")); } else if (qName.equals("layer")) { if (level == null) { width = Integer.parseInt(attributes.getValue("width")); height = Integer.parseInt(attributes.getValue("height")); level = new int[height][width][3]; } x = 0; y = 0; } else if (qName.equals("tile")) { int id = Integer.parseInt(attributes.getValue("gid")); if (id != 0) { if (id >= 257) { level[x][y][2] = 1; id -= 256; level[x][y][0] = id % tilesetWidth - 1; level[x][y][1] = id / tilesetWidth - 1; } else { level[x][y][0] = id % tilesetWidth - 1; level[x][y][1] = id / tilesetWidth; } } x ++; if (x >= width) { x = 0; y ++; if (y > height) { throw new SAXException("Erreur dans le fichier"); } } } } } The method is a long discussion based on the tag encountered, whose name is placed in the qName argument. For the “tileset” and “image” cases the information relating to a set of tiles is decoded. For the “layer” case, the level is initialized, and for “tile”, the information relating to a tile is stored. The x and y attributes are used to store the coordinates of the next tile to be decoded. Finally, I define a load() method in the Level class that uses the LevelLoader class to load the level: public boolean load(String fileName) { try { SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser saxParser = spf.newSAXParser(); XMLReader xmlReader = saxParser.getXMLReader(); xmlReader.setContentHandler(new LevelLoader()); URL fileURL = this.getClass().getClassLoader().getResource(fileName); xmlReader.parse(fileURL.toString()); return true; } catch(Exception ex) { return false; } } The Level class also has accessors/mutators (getters/setters) not listed here. Display the level To display the level, I use the GUI facade from the previous post: Level level = new Level(); if (!level.load("advancewars-map1.tmx")) { JOptionPane.showMessageDialog(null, "Error when loading advancewars-map1.tmx", "Error", JOptionPane.ERROR_MESSAGE); return; } int scale = 2; Layer backgroundLayer = gui.createLayer(); backgroundLayer.setTileSize(level.getTileWidth(),level.getTileHeight()); backgroundLayer.setTexture(level.getTilesetImage(0)); backgroundLayer.setSpriteCount(level.getWidth()*level.getHeight()); 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); } } } Layer groundLayer = gui.createLayer(); groundLayer.setTileSize(level.getTileWidth(),level.getTileHeight()); groundLayer.setTexture(level.getTilesetImage(1)); groundLayer.setSpriteCount(level.getWidth()*level.getHeight()); 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); } } } gui.createWindow("Load a level with the Visitor Pattern", scale*level.getTileWidth()*level.getWidth(), scale*level.getTileHeight()*level.getHeight()); The code of this post can be downloaded here: Download Now! To compile: javac com/learngameprog/awtfacade05/Main.java To run: java com.learngameprog.awtfacade05.Main View the full article
  4. Hello and welcome to this weeks Dev Diary! Today I'll be continuing on how upscaling heightmaps affects the end result, when you wan't to create more detailed terrain with ease. After last weeks test with the heightmap upscales, I decided to try to upscale the heigthmap even further - from 3000 x 3000 pixels to 40 000 x 40 000 pixels, just to see if there would be any return on investment. Or in other words, if there would be any benefit from the extra detail, that the upscaling algorithm creates. Initial Testing First, lets compare the first set of renders. Like last week, all the settings remain unchanged between renders and only the heightmap is changed between them. This is done in order to eliminate the changes that changing the the lighting or camera angle could cause by creating/showing shadows in different perspective, if moved between renders. Plane 8m x 8m in size. Subdivided several times, first by 100, second by 6 and third by 1 (or 100:6:1 subdivision) Diffuse Scale 1.0, midpoint 0.5 (defaults) Resolutions from top to bottom; 750 x 750, 3000 x 3000, 40 000 x 40 000. The above 750 x 750 pixel heightmap sample is from the original 3000 x 3000 heightmap. The above 3000 x 3000 pixel heightmap sample is from the upscaled 12 000 x 12 000 pixel heightmap. The above 10 000 x 10 000 pixel heightmap sample is from the upscaled 40 000 x 40 000 pixel heightmap. Both upscales were made using the original 3000 x 3000 pixel heightmap and slicing a 1:16th piece (or 1 km2 piece) from the bottom left corner of each of them, in order to highlight the difference in details. As you can see, the differences are most notable between the Original and the smaller upscale, but from there, the added detail is a tad harder to notice - but it is there. After this, I also tried to ramp up the data points, or in other words subdivide the plane even further and see how much that changed the outcome. The settings are identical, but the subdivision is greater (100:10:1 instead of 100:6:1 subdivision) 750 x 750 pixel heightmap sample, with the 100:10:1 subdivision. 3000 x 3000 pixel heightmap sample, with the 100:10:1 subdivision. 10 000 x 10 000 pixel heightmap sample, with the 100:10:1 subdivision. The added data points did increase the level of detail quite a bit. The difference between the two upscales are still hard to see, but still visible after closer inspection. The difference is more visible on 4K monitors, but can be seen on Full HD monitors also. Having these images on top of each other and toggling between them shows the differences much more clearly. Going For More Detail Since it will look essentially the same on the rendered images, if I increase the land area of the plane in order to try to bring out even more detail out of the renders, I'm not conducting those tests. How ever, there is still one more way to up the ante - an even further zoom in to the minute detail differences of the upscales. To do this, I needed to take even smaller samples, dividing the heigthmaps in 8x8 grids (instead of 4x4 as shown above) and taking one piece out of each of them. For consistency, I'll use the bottom left corner as a sample. 375 x 375 pixel heightmap sample from the 3k heightmap, with the 100:10:1 subdivision. 1500 x 1500 pixel heightmap sample from the 12k heightmap, with the 100:10:1 subdivision. 5000 x 5000 pixel heightmap sample from the 40k heightmap, with the 100:10:1 subdivision. Edit; You can see the difference most clearly on the illuminated back portion of the landscape as more "grain" or roughness among the white. The Question Remains But is it really worth it? That depends if you want all the possible variation out of the heightmap, that could possibly get squeezed out of it, as it is not necessary. but it might just create enough minute differences in the terrain, that the end result will look more natural in the end. But on the down side, the more faces you have, the more the performance hit will be. Even as the added data points, or mesh resolution will affect the performance of the game, Skyrim also has high def mesh mods, which make the original rather low poly models into much more detailed meshes, especially the rocks, mountain faces and characters. In this light, it might be more than feasible to increase the detail level of your terrain meshes even further. The land area of the smaller samples of the above testing is roughly 500 square meters, that has been fitted on a 8 by 8 meter plane object. The second thing to consider is how many objects you would need to divide your terrain in to, in order to maximize the resolution you can get out of the heightmaps. As creating a single object that would be miles long would require some serious machine power and RAM from your computer, it's not feasible for all to make a large monolithic map area. Creating a large amount of smaller pieces on the other hand is more work intensive and requires more time and patience from the developer to insert them all in the game world and line them all up in the correct order. The Conlusion Edit; The benefits of upscaling your heightmap only show, when you divide it to smaller samples > the smaller the pieces, that you divide your upscaled heightmap at, the more benefit the upscaling has. Alternatively, the same benefits of the upscaled heightmap can be seen when making a larger and closer to IRL size map, but to my knowledge, a huge monolithic map with lots of detail takes up more processing power. Though this might be an utterly out-dated notion these days - I need to do more research on that. What i know for sure, is that it limits the amount of subdivision that can be used while editing the landscape, as Blender is very likely to crash on my PC when I go with any larger subdivision than 100:10:1 and the amount of subdivision matters. Edit; When you are upscaling your heightmap, the algorithm you do it with matters the most, as the more the algorithm creates more gradual shades between white and black while trying to make sense of the original shapes, the more likely you get more added details to the landscape. Still, this method is not for purists, as it does not bring the absolute original shape of the land back to the image, just adds more variation. Edit; As an example, if you know that the heightmap represents a 4 km2 sized area and the accuracy of the satellite/airplane measurement was something between 2 - 30 meters. If your heightmap has an accuracy rating of 10 meters, then by upscaling the heightmap to 10 times the size of your source image, your get a simulated accuracy of 1 meters. If you want to have more granularity than that, you can go for as large as you want (or can), but at some point there will be no visual benefits. To determine that point, you need to experiment for your self on a case-by-case basis. Edit; As the GameDev forum does not show the images in full screen, some of the differences between the images is apparently lost, when trying to spot tiny differences. The original images in full screen show the differences much more clearly. You can download them from here 040.7z All in all, the more you are willing to work for your terrain mesh fidelity, the more you seem to be able to get out of upscaling your heightmaps. This seems to continue as far as you your self are willing to take it, or at least to much smaller (or larger, depending on how you look at it) scales than what my testing indicates here. It will be interesting to see how much of a performance hit it will have, when using a higher detail mesh for terrain. This will be revealed when I get to the first testing phase, with only a small land area and the 3D character model that I created earlier. But before that, next weeks Dev Diary will be about slicing big images seamlessly into smaller image files semi-automatically using GIMP, so stay tuned! Thank you for tuning in, and I'll see you on the next one! You can check out every possible mid week announcements about the project on these official channels; • YouTube • Facebook • Twitter • Discord • Reddit • Pinterest • SoundCloud • LinkedIn •
  5. The facade seen in the previous article has only an interface with its methods. It is also possible to enrich a facade with additional interfaces, connected to each other by various means. To illustrate it, I propose to add image management. This addition also makes it possible to present another design pattern: the Factory Method Pattern. This post is part of the AWT GUI Facade series. In graphic libraries, it is generally not possible to directly access the raw data of an image, it is always necessary to go through an identifier or a class to apply some processing. Knowing this, a relevant approach is to encapsulate what makes it possible to process the image in a dedicated class, for example: Compared to the previous article, the following methods have been added to the GUIFacade interface: The createImage() method creates an Image from the name of a file. In doing so, we are using the Factory Method pattern, which allows us to abstract the creation of objects, and whose creation process depends on inheritance. In this case, the user of the createImage() method does not know which implementation of the Image interface will be used. This choice depends on the class that implements GUIFacade interface, whose details are not necessarily known to the user, since it is a facade. Once again, the idea is to free the user of specific features, and let him focus on the problem he has to deal with, in our case the rendering of a 2D tile game. The drawImage() method is used to draw an image at (x, y) coordinates. Other methods dedicated to the creation and processing of images can be imagined, these are only examples among others. The Image interface is used to represent access to an image managed by the graphics library. Methods can be proposed to work with an image. In our example, the getWidth() and getHeight() methods return the width and height of the image. Other methods can be imagined, such as a draw() method that would draw the image, instead of the one within the GUIFacade interface. For the implementation of the facade, we still use the AWT library. For the Image interface implementation, an AWTImage class is proposed: public class AWTImage implements Image { private BufferedImage image; @Override public int getWidth() { if (image == null) { throw new RuntimeException("The image was not loaded"); } return image.getWidth(); } @Override public int getHeight() { if (image == null) { throw new RuntimeException("The image was not loaded"); } return image.getHeight(); } void loadImage(String fileName) { try { image = ImageIO.read(this.getClass().getClassLoader().getResource(fileName)); } catch (IOException ex) { throw new RuntimeException("Error when reading "+fileName); } } void draw(Graphics graphics,int x,int y) { graphics.drawImage(image, x, y, null); } } The AWTImage class holds an image reference to a java.awt.image.BufferedImage. getWidth() and getHeight() methods return the width and height of the image. The other two methods are not part of the facade, and are invisible to its users. They are used by the AWTGUIFacade class to load the image (loadImage() method) and display it in a java.awt.Graphics (draw() method): public class AWTGUIFacade implements GUIFacade { ... @Override public Image createImage(String fileName) { AWTImage image = new AWTImage(); image.loadImage(fileName); return image; } @Override public void drawImage(Image image, int x, int y) { if (!(image instanceof AWTImage)) throw new IllegalArgumentException("Invalid image type"); AWTImage awtImage = (AWTImage) image; awtImage.draw(graphics,x,y); } } This new version of the facade can be used in the following way to display a window with an image: public static void run(GUIFacade gui) { Image titleImage = gui.createImage("title.png"); gui.createWindow("AWT Graphic User Interface Facade", titleImage.getWidth(),titleImage.getHeight()); while(!gui.isClosingRequested()) { if (gui.beginPaint()) { gui.drawImage(titleImage,0,0); gui.endPaint(); } } gui.dispose(); } The image is created from the file “title.png” (1. 2), a window of the size of the image is also created (l.3), and as long as the game is not finished (l. 5), the drawing is started (1. 6), the picture is displayed (1. 7) and the drawing is ended (1. 8). The code of this post can be downloaded here: awtfacade03.zip To compile: javac com/learngameprog/awtfacade03/Main.java To run: java com.learngameprog.awtfacade03.Main Next post in this series View the full article
  6. In this article, I propose to continue the design of a facade for a 2D tile game (previous post). I add two new features: creation/destruction of the window, and basic drawing. Each feature is managed by a batch of methods in a GUIFacade interface. This post is part of the AWT GUI Facade series. The GUIFacade interface can be represented in the following way: The first four methods handle the window: The createWindow() method builds the window with a given title; The setClosingRequested() method is used to define whether the game should be completed; The isClosingRequested() method lets you know if the game needs to be completed; The dispose() method destroys the window and all associated elements. The last three methods allow you to draw in the window: The beginPaint() method starts the drawing, and returns true if it is possible; The drawLine() method draws a line. This is an example of a drawing method, a whole collection can be imagined to draw rectangles, circles, etc .; The endPaint() method completes the drawing. Most graphic libraries used to follow these steps where you have to start by “preparing” the drawing with a method like beginPaint(), then “free” it with a method like endPaint(). In addition, there is usually a form of blocking between these two calls, which means that you have to draw “as quickly as possible” if you want to offer a good user experience. These methods can be used as follows: the window is created (l.2) and we repeat until the game is finished (l.3). If it is possible to start drawing (l.4), draw a line (l.5) and finish the drawing (l.6). Finally, the window is destroyed (l. 9): public static void run(GUIFacade gui) { gui.createWindow("AWT GUI Facade"); while(!gui.isClosingRequested()) { if (gui.beginPaint()) { gui.drawLine(100, 150, 600, 350); gui.endPaint(); } } gui.dispose(); } Note: In this example, there is no limitation on the number of frames per second. This can saturate a processor core and cause minor issues on some configurations. We’ll see in another post how to get a better frame rate. The use of the facade does not depend on its implementation: it is possible to use different implementations, for example the AWT library included in the standard Java library: public class AWTGUIFacade implements GUIFacade { private AWTWindow window; private boolean closingRequested = false; private BufferStrategy bufferStrategy; private Graphics graphics; @Override public void createWindow(String title) { window = new AWTWindow(this); window.init(title); window.setLocationRelativeTo(null); window.setVisible(true); window.createBufferStrategy(2); } @Override public void setClosingRequested(boolean b) { closingRequested = b; } @Override public boolean isClosingRequested() { return closingRequested; } @Override public void dispose() { window.dispose(); } @Override public boolean beginPaint() { bufferStrategy = window.getBufferStrategy(); if (bufferStrategy == null) return false; graphics = bufferStrategy.getDrawGraphics(); if (graphics == null) return false; graphics.setColor(Color.black); graphics.fillRect(0, 0, window.getWidth(), window.getHeight()); return true; } @Override public void drawLine(int x1, int y1, int x2, int y2) { graphics.setColor(Color.white); graphics.drawLine(x1, y1, x2, y2); } @Override public void endPaint() { graphics.dispose(); bufferStrategy.show(); } } The window attribute is a reference to an AWTWindow class that inherits from java.awt.Frame, shown below. The closingRequested attribute is true if the game must end. The bufferStrategy and graphics attributes are used to handle double buffering rendering. The init() method is the same as in the previous article, except for the creation of a double buffer with window.createBufferStrategy(2); The setClosingRequested() and isClosingRequested() methods manage the closingRequested attribute. The dispose() method controls the destruction of the window. The beginPaint() and endPaint() methods handle the display cycle. In the first one, the current buffer is obtained (1.37), then a java.awt.Graphics is created from it (1.40). In both situations, various reasons may cause issues, in which case false is returned. The end of the beginPaint() method erases all the content: this approach can be interesting or not, depending on the case. The endPaint() method destroys graphics (1. 56) and inverts the two buffers (1. 57). Finally, the drawLine() method uses graphics to draw a line: it’s easy to imagine other use cases for drawing rectangles, circles, and so on. The AWTWindow class is an AWT window initialized by the init() method with a specific configuration. When window closing is requested by the user, the facade is notified that the game must be completed (1. 16): public class AWTWindow extends Frame { private final AWTGUIFacade gui; public AWTWindow(AWTGUIFacade gui) { this.gui = gui; } public void init(String title) { setTitle(title); setSize(640, 480); setResizable(false); addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent we) { gui.setClosingRequested(true); } }); } } Note: The rendering method is simple but not optimal: it is better to use canvas to draw inside a window. This implementation may cause some undesirable effects. The code of this post can be downloaded here: awtfacade02.zip To compile: javac com/learngameprog/awtfacade02/Main.java To run: java com.learngameprog.awtfacade02.Main Next post in this series View the full article
  7. In this series, I propose to discover the Facade Pattern. In short, this pattern defines an interface that allows a reduced and simplified use of a set of features. To illustrate, we design a facade of the AWT graphic library for a 2D tile game. This post is part of the AWT GUI Facade series. Let’s start with the simplest facade with a unique createWindow() method that allows the user to create a new window: Creating a window with this facade is very simple: we instantiate an implementation of the facade (l.1), and call the createWindow() method (l.2): GUIFacade gui = new AWTGUIFacade(); gui.createWindow("AWT GUI Facade"); In this example, I propose to implement a window creation with the AWT library: other implementations are possible without changing the GUIFacade interface and its use. An AWTWindow class that implements java.awt.Frame is defined to handle our window: The createWindow() method of the AWTGUIFacade class instantiates an AWTWindow (l .4), initializes it with a title (l.5), places it in the center of the screen (l.6) and makes it visible (l. 7): public class AWTGUIFacade implements GUIFacade { @Override public void createWindow(String title) { AWTWindow window = new AWTWindow(); window.init(title); window.setLocationRelativeTo(null); window.setVisible(true); } } The AWTWindow class has an init() method that initializes the window with a given title (l.3), a size of 640 by 480 pixels (l.4), prohibits resizing (l.5), and ensures that the window is destroyed when closed (L.6-11): public class AWTWindow extends Frame { public void init(String title) { setTitle(title); setSize(640, 480); setResizable(false); addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent we) { dispose(); } }); } } The creation of the window is split between the createWindow() method of the AWTGUIFacade class and the init() method of the AWTWindow class. The main motivation here is to separate the more dynamic operations, such as the position of the window, from more static operations, such as the title or the fact that the window is not designed to be resized. There are many other possibilities depending on the possible extensions of the facade. With this facade, a user can easily create a window for a specific use, without having to know all the methods of a graphic library. Moreover, apart from the instantiation of a layout of the facade (i.e., new AWTGUIFacade()), all the following code no longer depends on the graphic library (the gui variable in the first example code is of type GUIFacade). This means that it is possible to switch from one implementation to another, and therefore from one graphic library to another. This property is very interesting when you want to cross-platform, or if the first choice of the graphic library was not good. In any case, we can switch from one library to another without having to rewrite the entire application! This article presents a very simple first approach, and presents the basics of the facade pattern. In the following articles, things will become more complex, and you will see what can be achieved from a pattern whose principle seems so simple! The code of this post can be downloaded here: awtface01.zip To compile: javac com/learngameprog/awtfacade01/Main.java To run: java com.learngameprog.awtfacade01.Main Next post in this series View the full article
  8. Hey guys, I'm putting together a little thing in Python, a city builder of sorts. Nothing fancy, to be sure. The user will click on buttons to purchase items. In-game currency will be collected via taxes. I'd like to include population growth and pretty much anything that the big city builders keep track of. One of the things I'm not sure how to do is simulate population growth. Each house will have a capacity, so it would be easy to say that a population couldn't grow beyond a certain point (to keep things simple), or if the population grew beyond residential capacity, there would be a homeless population to keep track of (maybe later). What factors would affect population? I'm thinking several things but not sure how to include them in formulas. Building a school could encourage more people to move in. Building other service buildings would help as well. This may not be a game design question (rather something for another forum), but how would you factor in multiple things to raise or lower the chances the population grows? And money won't be the only metric. Farms will produce food, which might be needed in order to build restaurants. The pic I've attached shows the very basic and early GUI I'm playing with. Since there won't be any other graphics beyond the buttons (and maybe graphs later), there will be lots of buttons and pages to produce a lot of interactions and gameplay methods. I'd love any ideas you have to offer.
  9. theaaronstory

    Rudimentary concepts brought to life

    It's been a while . . . I've spent these last couple of weeks experimenting and slowly building up the foundations (concepts) of a playable character; which would ultimately end up in the demo. It's based on an old Frankish design, with some additional tweaks here and there. Granted, it is really-rough around the edges, but I wanted to see how it all came together; thus left some parts for the imagination (will polish it later, like the straps and the cape, etc.). Initially, when I landed on this design, I decided to cramp as much detail onto this model as I could–just so that it would double as promotional material. That being said, that inadvertently created this intangible struggle of having to create two separate low poly models for said purposes. Suffice to say that the more I worked on this, the more clear it became that it might be a better idea to switch engines all together (to Unreal). But . . . and this is the main source of my conundrum: this would also mean that the project would be thrown back several months; not entirely sure that the delay would justify itself. Whatever might be the case, I'll keep working on this small, linear dungeon crawler ("cave run") and see where this project will go from here . . . Furthermore, I thought to share some close-ups of the model:
  10. Hello and welcome to this weeks Dev Diary! Today, as promised last week, I'll be explaining how Astuvansalmi relates to the last weeks title; " Amūńe, The Old One ". Facts and Speculation Known facts are rare, as the Finnish language, or any language on the Finnic lands, have never had written language until fairly recently. Spoken stories were the only known way that people taught their customs and culture to each other - the way of the land, one could call it, due to it's organic nature. This is also why the names of the gods have changed and split into multitudes over the millennia, hence we can only ques what was the original names of the ancient gods, that were recently called by their modern names. Facts at the Astuvansalmi are as follows; There resides one of the oldest and largest rock painting collection in the northern Europe. It has seemingly had religious significance for many millennia, as there has been found several items from different times. Most significant ones are amber statues of a man, a woman, a boy and a bears head, which points to the sites religious meaning. The human figurines were named as following; Statue of the man is called "Astuvan Ukko", the "Ukko of Astuva". Ukko can mean several things, "Old Man", "Grandfather" or when talking about a god, "The Old One". Statue of the woman is called "Astuvan Akka", the "Akka of Astuva". Akka means "Old Woman", "Grandmother" or a feminine "Old One", when used from a goddess. Also the largest one found. Statue of the boy is called "Astuvan Poika", the "Poika of Astuva". Poika is a straight translation for "Boy", so there's no mystery there. The head of the bear is a reference to the forefathers, as bears were widely considered to be the ancestors of the locals, which has also been called "the Bear Clan". All of the figurines had a hole through them, which indicates that the statues were actually a necklace or a pendant at o