• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.

Valgor

Members
  • Content count

    11
  • Joined

  • Last visited

Community Reputation

126 Neutral

About Valgor

  • Rank
    Member
  1. Thank you so much for taking the time to respond in so much detail! There is much to think on. A player will never reach the edge of the world ( tile 0_0 at position 0,0) because the world will be one large island, or blocked by impassable mountains. Using a camera rectrangle - I like this idea. I've thought about it before but figure that might be something to mess with later. QuadTree research and implemention was next in line after getting a continous map working. When you say to store the tiles in a 2d array and/or have a TextureDB class, I just want to be clear you aren't suggesting we load all maps and textures into the memory? I'm loading maps from the harddrive as they are needed. I would toy with the idea of a buffer, but if the entire map is huge? Thank you for the break down of my class and suggestions to the over all design!
  2. [quote name='ultramailman' timestamp='1351625175' post='4995533'] Hello Valgor I am working on the same thing as you, except I call my "tiles" "cells" instead, because the word "tile" is reserved for little blue and brown bricks that make up the world. What I do is I keep a 3x3 2d array. array[1][1] is the center cell, and the others are the neighbor cells. Every time the player changes to a new cell, all the surrounding 8 cells are loaded too. [/quote] Using the word "cell" does sound like a better idea! I started out with the idea you have, using the surrounding 8 cells, but I thought there would be too much over head updating and moving content around the data structure that holds the current world (in your case, an array). So if you move to the east, then you have to load three new cells and move 6 cells in your arrays. I wanted to smiplfy this, so I am assuming I will be using larger maps and will only need to update at max 4 cells ever.
  3. [quote name='slayemin' timestamp='1351611304' post='4995451'] Hold on, I'm not quite sure I understand how you're describing your maps... Is it a tile based system, where you have a 100x100 grid of tiles, all rendered on the screen at once? Or is it a system where each map grid is an area which fills up the entire screen (like old school Zelda) and you move in the cardinal directions to go to the next area? [/quote] Not like Zelda. The world is, say, a 100x100 grid of tiles. If you are in tile, say, 5_5 and within a boundry inside of that tile, then that is the only tile loaded. If you pass that inter boundry then neigboring tile are then loaded. Only a maximum of four tiles will ever be loaded. So if you are in 5_5 and move the northeast corner of that tile, then the following maps get loaded: 6_5 (east tile), 5_4 (north tile), and 6_4 (NE tile), and 5_5 is still loaded. Once you move into another tile and move within it's inter boundry, you can unload the older tiles, leaving only the current tile you are in in memory.
  4. [quote name='phil_t' timestamp='1351483689' post='4994936'] I'm not sure I understand the need for all the code about directions ... you could just figure out which tiles need to be loaded based on the player's current position in the map[/quote] Figuring out which tile to load is what the direction code is about. It's a book keeping system to see which one to load based on your current tile and also helps to let the program know where to render that tile on the screen.
  5. For some reason there are no spaces between the boxes! It is a matrix transformed into another matrix. Written out: [ N, NE, C, E, S, SE] ---> [ NW, N, W, C, SW, S] Match this with what I have in the above post. Hope that makes sense.
  6. Hello, incoming huge post! I am creating a 2D RPG where the entire world is open and continous. That is, there are no instances (for now). I am looking for any and all criticism over my design and code. I also hope this will help future developers. I will explain my ideas and walk through the design. At the bottom you can find my entire implemention. The world is divided up into tiles where each tile is one image. Each tile is named "X_Y" where x and y are the coordinates with respect to the entire world. Suppose our playable character starts in 3_3, and the tile the character is actively in is called the center tile. The character renders to the center of the screen always (think Diablo), so we keep track of the map tile's (x,y) position and also the character's (x,y) position relative to the map. The difference in distance between the two is called the xOffSet and yOffSet. There are two main steps in the Update method. (1) Checks to see if we need to load nearby tile and (2) see if we are no longer in the center tile. (1) The center tile has an interboundry rectangle, so that if this boundary is crossed, we must load a nearby tile to render. Suppose we are in 3_3 moving east towards the edge so the 4_3 must be loaded. The code to check for this is here: [source lang="csharp"]if (Math.Abs(mapPosition.X) > interBoundaryWidth) { if (!bEast) { Load(EAST, 1, 0); bEast = true; } } else if (bEast) { Unload(EAST); bEast = false; }[/source] bEast is a boolean that says if the map to the east of the center tile is loaded. We see if our map's position has crossed the inter boundary. If so, we check if the eastern tile is loaded already so that we only load it once. We call the Load function telling it the direction relative to the center tile and that the coordinates going to added are 1 in the x direction and 0 in the y. Since we are in 3_3, this will load 4_3. bEast is set to true so we dont load it again. Backing up to the beginning, suppose the map's position is still within the interboundry. Then, if the Eastern map is loaded, we want to unload it and set the boolean to false. This step is needed if we traveled east, passed the interboundary, loaded 4_3, but then turned back west far enough that we don't need to render 4_3 anymore. Similar sections of code are used for all possible directions including the need to load NE, NW, SE, and SW maps. (2) This section sees if our character has moved out of the center tile and into another. Continuing with the east example, suppose our character moves from being in 3_3 into 4_3. [source lang="csharp"]if (Math.Abs(mapPosition.X) + (GraphicsDeviceManager.DefaultBackBufferWidth / 2) > tileWidth) { foreach (MapTile bt in mapTiles) { if (bt.direction == CENTER) bt.direction = WEST; else if (bt.direction == NORTH) bt.direction = NW; else if (bt.direction == SOUTH) bt.direction = SW; } foreach (MapTile bt in mapTiles) { if (bt.direction == EAST) { bt.direction = CENTER; mapName = bt.name; } else if (bt.direction == NE) bt.direction = NORTH; else if (bt.direction == SE) bt.direction = SOUTH; } worldManager.setCharacterPosition(new Vector2(characterPosition.X + tileWidth, characterPosition.Y));[/source] The first if statement sees if we have crossed outside of the map tile's width and thus into a new map tile. If we have, we want to update all the tiles to reflect the direction on the new center tile. Consider this crude drawing that maps each possible tile into the new direction. Note that only the N/NE or S/SE sections could possibly be loaded at the same time since the north and south tiles cannot be loaded at the same time because the maps are bigger than our screen. "C" is for "Center" which is where our character is located. --------- ----------- | N | NE | | NW | N | ---------- ------------ | C | E | ---> | W | C | ---------- ------------ |S | SE | | SW | S | ---------- ------------ So our center tile becomes the west tile, and the west tile becomes the center tile, and so on for the other tiles. The order of changing the directions is important, which is why I have two foreach loops. Lastly, we update the character's position to that it starts on the far left side of the new center tile. Finally, the rendering is based on the tile's direction which can be seen in my code below. If you have read this far, please leave a comment! I'm open to improvements and hopefully would like to help others tackling this problem. Thanks for reading! [source lang="csharp"] namespace Arkenstone { // The Map class contains and manages up to four total MapTiles. class Map { String mapName; // This will be the name of the map the playable character is in. List<MapTile> mapTiles; // Contains up to 4 loaded tiles. int mapListSize = 3; // Size limit for backgroundTiles. float xOffSet = (GraphicsDeviceManager.DefaultBackBufferWidth - 48) / 2; // = 376, 48 = mainCharacter's spirte width float yOffSet = (GraphicsDeviceManager.DefaultBackBufferHeight - 72) / 2; // = 264, 72 = mainCharacter's sprite height int tileHeight; // All map tiles are the same height. int tileWidth; // All map tiles are the same width. int interBoundaryWidth; // Inside width boundary of a map tile used to know when to load other maps. int interBoundaryHeight; // Inside height boundary of a map tile used to know when to load other maps. bool bEast, bWest, bNorth, bSouth; // Directional booleans set to true when a map is loaded. bool bNE, bSE, bSW, bNW; // Directional booleans set to true when a map is loaded. // Directional strings. private const string CENTER = "CENTER"; private const string NORTH = "NORTH"; private const string SOUTH = "SOUTH"; private const string EAST = "EAST"; private const string WEST = "WEST"; private const string NE = "NE"; private const string SE = "SE"; private const string NW = "NW"; private const string SW = "SW"; Vector2 characterPosition; // Character's position relative to the map. That is, with the offsets. ContentManager contentManager; // Keep a copy of the content manager since it is used so often. Vector2 mapPosition; //top x,y for the map tile used for drawing. public Map() { // Only have 4 maps total, ever. mapTiles = new List<MapTile>(mapListSize); // Create new tiles. MapTile mapTile1 = new MapTile(); MapTile mapTile2 = new MapTile(); MapTile mapTile3 = new MapTile(); MapTile mapTile4 = new MapTile(); // Fill the list. mapTiles.Add(mapTile1); mapTiles.Add(mapTile2); mapTiles.Add(mapTile3); mapTiles.Add(mapTile4); } // Loads map the first map "x_y" public void LoadContent(int x, int y, ContentManager contentManager) { try { this.contentManager = contentManager; mapName = (x).ToString() + "_" + (y).ToString(); mapTiles[0].LoadContent(this.contentManager, mapName, CENTER); tileHeight = mapTiles[0].Source.Height; tileWidth = mapTiles[0].Source.Width; interBoundaryHeight = mapTiles[0].innerBoundary.Height; interBoundaryWidth = mapTiles[0].innerBoundary.Width; // When the character is first loaded, no other map tiles are in view. bWest = bNorth = bEast = bSouth = false; bNE = bSE = bSW = bNW = false; } catch (Exception e) { Console.WriteLine(mapName + " does not exist."); } } public void Update(WorldManager worldManager) { // Get the character's position relitive to the map. characterPosition = worldManager.mainCharacter.mapPosition; // Set the top x,y for the map mapPosition = new Vector2(-xOffSet + characterPosition.X, -yOffSet + characterPosition.Y); // If we are outside the inter boundaries of the center tile, load the next tile so that it can be rendered. #region Map loading // East if (Math.Abs(mapPosition.X) > interBoundaryWidth) { if (!bEast) { Load(EAST, 1, 0); bEast = true; } } else if (bEast) { Unload(EAST); bEast = false; } // South if (Math.Abs(mapPosition.Y) > interBoundaryHeight) { if (!bSouth) { Load(SOUTH, 0, 1); bSouth = true; } } else if (bSouth) { Unload(SOUTH); bSouth = false; } // West if (mapPosition.X > 0) { if (!bWest) { Load(WEST, -1, 0); bWest = true; } } else if (bWest) { Unload(WEST); bWest = false; } // North if (mapPosition.Y > 0) { if (!bNorth) { Load(NORTH, 0, -1); bNorth = true; } } else if (bNorth) { Unload(NORTH); bNorth = false; } // NE if (mapPosition.Y > 0 && Math.Abs(mapPosition.X) > interBoundaryWidth) { if (!bNE) { Load(NE, 1, -1); bNE = true; } } else if (bNE) { Unload(NE); bNE = false; } // NW if (mapPosition.Y > 0 && mapPosition.X > 0) { if (!bNW) { Load(NW, -1, -1); bNW = true; } } else if (bNW) { Unload(NW); bNW = false; } // SE if (Math.Abs(mapPosition.Y) > interBoundaryHeight && Math.Abs(mapPosition.X) > interBoundaryWidth) { if (!bSE) { Load(SE, 1, 1); bSE = true; } } else if (bSE) { Unload(SE); bSE = false; } // SW if (Math.Abs(mapPosition.Y) > interBoundaryHeight && mapPosition.X > 0) { if (!bSW) { Load(SW, -1, 1); bSW = true; } } else if (bSW) { Unload(SW); bSW = false; } #endregion // This region checks if the character has moved out of the center tile, and updates accordingly so we are back in the center tile. #region Moved In Positions // Moved to the west square if (mapPosition.X > (GraphicsDeviceManager.DefaultBackBufferWidth / 2)) { // Moving from (x,y) to (x-1, y) foreach (MapTile bt in mapTiles) { if (bt.direction == CENTER) bt.direction = EAST; else if (bt.direction == NORTH) bt.direction = NE; else if (bt.direction == SOUTH) bt.direction = SE; } foreach (MapTile bt in mapTiles) { if (bt.direction == WEST) { bt.direction = CENTER; mapName = bt.name; // Updates the name of the map our character is in. } else if (bt.direction == NW) bt.direction = NORTH; else if (bt.direction == SW) bt.direction = SOUTH; } // Update the character's position. worldManager.setCharacterPosition(new Vector2 (characterPosition.X - tileWidth, characterPosition.Y)); } // Moved to the east tile. else if (Math.Abs(mapPosition.X) + (GraphicsDeviceManager.DefaultBackBufferWidth / 2) > tileWidth) { foreach (MapTile bt in mapTiles) { if (bt.direction == CENTER) bt.direction = WEST; else if (bt.direction == NORTH) bt.direction = NW; else if (bt.direction == SOUTH) bt.direction = SW; } foreach (MapTile bt in mapTiles) { if (bt.direction == EAST) { bt.direction = CENTER; mapName = bt.name; } else if (bt.direction == NE) bt.direction = NORTH; else if (bt.direction == SE) bt.direction = SOUTH; } worldManager.setCharacterPosition(new Vector2(characterPosition.X + tileWidth, characterPosition.Y)); } // Moved to the north tile else if (mapPosition.Y > (GraphicsDeviceManager.DefaultBackBufferHeight / 2)) { foreach (MapTile bt in mapTiles) { if (bt.direction == CENTER) bt.direction = SOUTH; else if (bt.direction == WEST) bt.direction = SW; else if (bt.direction == EAST) bt.direction = SE; } foreach (MapTile bt in mapTiles) { if (bt.direction == NORTH) { bt.direction = CENTER; mapName = bt.name; } else if (bt.direction == NE) bt.direction = EAST; else if (bt.direction == NW) bt.direction = WEST; } worldManager.setCharacterPosition(new Vector2(characterPosition.X, characterPosition.Y - tileHeight)); } // Moved to the south tile. else if (Math.Abs(mapPosition.Y) + (GraphicsDeviceManager.DefaultBackBufferHeight / 2) > tileHeight) { foreach (MapTile bt in mapTiles) { if (bt.direction == CENTER) bt.direction = NORTH; else if (bt.direction == WEST) bt.direction = NW; else if (bt.direction == EAST) bt.direction = NE; } foreach (MapTile bt in mapTiles) { if (bt.direction == SOUTH) { bt.direction = CENTER; mapName = bt.name; } else if (bt.direction == SE) bt.direction = EAST; else if (bt.direction == SW) bt.direction = WEST; } worldManager.setCharacterPosition(new Vector2(characterPosition.X, characterPosition.Y + tileHeight)); } #endregion } // Loads a BackgroundTile named "a_b". public void Load(string direction, int a, int b) { // Search for an empty slot in the list to load a map tile. foreach (MapTile backgroundTile in mapTiles) { // This if statement is for safety so we don't accidently try to load a tile that is already loaded. if (backgroundTile.direction == direction) { // Map is already loaded. break; } if (!backgroundTile.isLoaded) { // Deconstruct the name to get the grid number String[] coordinates = mapName.Split('_'); int x = Convert.ToInt32(coordinates[0]); int y = Convert.ToInt32(coordinates[1]); // Example: we are in "4_5" and moving east into the view of the next eastern square. // We then want to load map "5_5". The a and b parameters have the required offset. // That is, a=1 and b=0. string newMapName = (x + a).ToString() + "_" + (y + b).ToString(); backgroundTile.LoadContent(this.contentManager, newMapName, direction); break; } } } // Unloads the BackgroundTile in the given direction. public void Unload(string direction) { foreach (MapTile backgroundTile in mapTiles) { if (backgroundTile.direction == direction) { backgroundTile.UnloadContent(contentManager); break; } } } public void Draw(SpriteBatch spriteBatch, WorldManager worldManager) { // Character's position does not change between the world map's update and the world map's draw, but // keeping this for safety in case I change the order in the future. Could be deleted later. characterPosition = worldManager.mainCharacter.mapPosition; // Update top x,y for the map mapPosition = new Vector2(-xOffSet + characterPosition.X, -yOffSet + characterPosition.Y); // Draws squares to the screen foreach (MapTile backgroundTile in mapTiles) { if (backgroundTile.isLoaded) { // Draw the tiles based on their directional position. switch (backgroundTile.direction) { case CENTER: backgroundTile.Draw(spriteBatch, mapPosition); break; case EAST: backgroundTile.Draw(spriteBatch, new Vector2(Math.Abs(tileWidth) - Math.Abs(mapPosition.X), mapPosition.Y)); break; case WEST: backgroundTile.Draw(spriteBatch, new Vector2(-Math.Abs(tileWidth) + Math.Abs(mapPosition.X), mapPosition.Y)); break; case NORTH: backgroundTile.Draw(spriteBatch, new Vector2(mapPosition.X, -Math.Abs(tileHeight) + Math.Abs(mapPosition.Y))); break; case SOUTH: backgroundTile.Draw(spriteBatch, new Vector2(mapPosition.X, Math.Abs(tileHeight) - Math.Abs(mapPosition.Y))); break; case NW: backgroundTile.Draw(spriteBatch, new Vector2(-Math.Abs(tileWidth) + Math.Abs(mapPosition.X), -Math.Abs(tileHeight) + Math.Abs(mapPosition.Y))); break; case NE: backgroundTile.Draw(spriteBatch, new Vector2(Math.Abs(tileWidth) - Math.Abs(mapPosition.X), -Math.Abs(tileHeight) + Math.Abs(mapPosition.Y))); break; case SE: backgroundTile.Draw(spriteBatch, new Vector2(Math.Abs(tileWidth) - Math.Abs(mapPosition.X), Math.Abs(tileHeight) - Math.Abs(mapPosition.Y))); break; case SW: backgroundTile.Draw(spriteBatch, new Vector2(-Math.Abs(tileWidth) + Math.Abs(mapPosition.X), Math.Abs(tileHeight) - Math.Abs(mapPosition.Y))); break; } } } } } }[/source]
  7. [source lang="csharp"]bool kicking = false; // Assuming keyboard input is already given in another function // which then sets the kicking boolean to true; private void oncekick(GameTime gametime) { timer += (float)gametime.ElapsedGameTime.TotalMilliseconds; if (timer > interval) { if ( kicking ) { currentframe++; if (currentframe > 6) { currentframe = 0; kicking = false; } } timer = 0f; } }[/source] This is my idea on how to do it. The kicking boolean is set in the class definition. Every game update call will update the current frame. If it's still too fast you can increase the interval time.
  8. Hello, Does anyone know of any 2D RPG games that are free or open sourced? I'm looking for examples of how other games of this genre handle various tasks and organization. Thanks!
  9. I posted this in the graphics section and recieved no replies, so maybe I'll have better luck here! I've been working on a 2D RPG in XNA. While browsing tutorials and videos, I've heard them mention doing animation in a seperate script file. Since tutorials are always brief and never indepth, the following questions persist: 1) Are scripting languages faster than C# for animations? Is that why we would want to use them? 2) Is this only for time/movie like animations and not animations that require input (such as pressing up to animate my sprite to move up compared to a cut scene that plays regardless of input). 3) Good, possible, and best scripting lanuage to use for animation? 4) Any other reason to use scripts in a game? Thanks!
  10. 159 views but no replies! Any information would be helpful. Do you guys use scripts to animate your sprites or use whatever language you are coding in?
  11. I've been working on a 2D RPG in XNA. While browsing tutorials and videos, I've heard them mention doing animation in a seperate script file. Since tutorials are always brief and never indepth, the following questions persist: 1) Are scripting languages faster than C# for animations? Is that why we would want to use them? 2) Is this only for time/movie like animations and not animations that require input (such as pressing up to animate my sprite to move up compared to a cut scene that plays regardless of input). 3) Good, possible, and best scripting lanuage to use for animation? Thanks!