Comments (5)
A grid-based platform seems too simplistic, ie. a square grid representing the entire world where each region/map is a square within that grid.
One possibility I have been toying with is:
- A set of regions, each defined in a configuration file. Within each region, relative data points could be set up for particular NPCs, rare items, etc.
- Each time a user selects N/E/S/W, this would advance one position in the selected direction.
- Each region would have certain exit points or connection portions. Effectively, this weaves together regions as more or less a graph, where regions be viewed as nodes which point to one another.
- A region could even be placed in the middle of an existing region, to serve as a teleportation point.
- I think it's suitable for each region to be a square.
For example, consider the WesternDungeon
region/map:
- Could be
500
units wide,300
units tall. - At point
(20, 20)
there could be a rare item, and at(70, 30)
an NPC to purchase spellbooks. - Alongside the eastern edge,
(500, 20)
to(500, 50)
there could be a connecting point to another region, and at(70, 60)
a teleportation point to another world.
With the above example, some regions could even be tunnels to other regions, as opposed to primary regions themselves.
As a side note, it seems too restrictive to place monsters at specific points in regions. I feel that this should be a randomly generated aspect of the game.
To maintain the user's current position, all that would need to be restored is the current region and relative position in that region.
Example configuration file format:
---
# westernDungeon.yaml
name: westernDungeon
width: 500
height: 300
keyPoints:
- type: npc
x: 70
y: 30
- type: item
x: 20
y: 20
exitRanges:
- dest: easternDungeon # Eastern edge of Western Dungeon.
xLow: 500
xHigh: 500
yLow: 20
yHigh: 50
- dest: anotherWorld # Teleportation point.
xLow: 70
xHigh: 70
yLow: 60
yHigh: 60
monsters:
- hellHounds
- massiveBugs
TL;DR:
- Each region defines it's relative boundaries, and what it contains.
- Each region defines what it connects to.
- Each region is defined by a configuration file.
The configuration file approach lends to the maximum configurability of this game. In other words, a server administrator should be able to tweak the game as they wish by simply adjusting configuration files.
from crystal-skull.
Switching Directions
After giving it further thought, I think the idea of only having regions aware of their neighboring exit points/maps, as opposed to having a single, main grid that controls everything, is too complex.
Some of the major pitfalls:
- Each map, being self-aware, would have to keep information about its neighboring maps, meaning you'd have maps referencing each other, which screams anti-pattern.
- One of the main goals of the above design was to just store the relative data points of a character (rather than the main grid point), to allow for easy world expansion. We can still do that.
- If you cross an exit point, how do you know where you are in the other map?
- If you have maps with the same height all lined up next to each other, you could probably make some assumptions, but that is unacceptable.
Overall, having a single controller map is going to make things easier.
New Proposal
The new proposal is:
- Define regions separately.
- Keeps track of relative points for NPCs, monsters, item drops, teleportation points, etc., similar to the above.
- Have a controller map, which places the regions relative to each other.
- The goal of storing the relative point is still to allow for easy world expansion, and even expansion of the map itself. In other words, you could move a map to a totally different place in the grid, or blow it up, and users would still be in that same spot.
- It would be important to never reduce the dimensions of a map.
- The goal of storing the relative point is still to allow for easy world expansion, and even expansion of the map itself. In other words, you could move a map to a totally different place in the grid, or blow it up, and users would still be in that same spot.
- Do some validation on load to confirm no regions are overlapping. Unconnected regions are OK, ex. islands.
It's important to note that the idea of a controller map only matters when you're moving, to determine if you're entering a neighboring region and where you end up in that neighboring region. So, when moving, we need to invoke a relative -> absolute converter, to determine if we're: 1) breaching a boundary, and 2) where in the new map we are.
I think there are basically 3 pieces to implement here:
- Location conversion algorithm, invoked when moving.
- Individual map format.
- Controller map format.
- Additions to game loop.
Location Conversion
I think it would be something like this;
- User starts at
WestDungeon
,(5, 5)
(relative point). - User engages game loop, selecting a direction to go in.
- See if you're going to breach the edge of the map: are either the next relative
X
orY
coordinates equal to the height or width of the current map? If not, no need to involve the controller map, simply advance within the relative dimensions of the current map. if so, continue. - Determine if there is even something on the other end (next steps), and advance into that region, continue. Otherwise, reject the mover, since you're at the edge with no region to jump to.
- Example, current map width is
200
(relativeX
range of0
to199
), height50
(relativeY
range of0
to49
),xMin
0
,yMin
0
. Traveling east, next relative point is(200, 40)
. The relative height is equal to the max height, so breach. There is a neighboring map withxMin
200
,yMin
20
, with a width of300
andheight
of200
. - Get the controller location by adding the current map's
xMin
(from controller) andxNext
, same forY
. Ex.xMin
0
+200
=200
,yMin
0
+40
=(200, 40)
. - Find the matching map by iterating over all maps and finding the one with the greatest
xMin
andyMin
less than or equal to the controller location. - Translate to the relative point in the new map. Add the current map's
xMin
to the next relativeX
and subtract the new map'sxMin
, ex.0
+200
-200
=0
. Same forY
, ex.0
+40
-20
=20
. - Save location.
Individual Maps
name: westernDungeon
width: 500
height: 300
keyPoints:
- type: npc
x: 70
y: 30
- type: item
x: 20
y: 20
monsters:
- hellHounds
- massiveBugs
name: easternDungeon
width: 200
height: 200
monsters:
- hellHounds
Controller Map
- map: westernDungeon
xMin: 0
yMin: 0
- map: easternDungeon
xMin: 500
yMin: 30
Notice no xMax
or yMax
- these can be inferred from the respective maps' dimensions; unfortunately, this requires careful coordination between the map definitions and controller, to ensure the width
and height
match up with the xMin
and yMin
of neighboring maps. Another option would be to not store any dimensions in the respective map definitions, and store the height
and width
in the controller, so it's all in one place.
from crystal-skull.
A few things to note in beginning implementation:
- An explicit controller map is unnecessary. The overall dimensions can simply be stored with the individual map definitions - the controller map is implicit in this regard.
- When checking if you're at a boundary, you also need to check
nextX
/Y
against0
, in addition to the height and width of the map in case you're going back or down instead of up or forward.
Other interesting things being added/caught:
- Config Singleton, to avoid needing to create multiple
Config
objects (thus resulting in a reload of the same data - changes mid-execution aren't supported) when referencing from multiple code files. - There are many places where data from the config is being instantiated into an object. These objects should realistically be loaded once unless necessarily, and preferably all references to other objects should be checked to confirm those referenced objects exist (to avoid complications during runtime).
- This combined with the Singleton makes it a no-brainer to refer to the actual object parsed from the config as opposed to just maintaining an ID and looking it up when needed. For example a
User
references aMap
for its location - rather than theUser
object holding amap_name
, just point to theMap
parsed from the config (obviously we're not dealing with actual pointers directly, but Python won't recreate the object if we assign object to aUser
instance variable, it'll just assign the address).
- This combined with the Singleton makes it a no-brainer to refer to the actual object parsed from the config as opposed to just maintaining an ID and looking it up when needed. For example a
- Realizing this project is in desperate need of a YAML schema, so we can check for the existence of required fields at startup, created #18.
from crystal-skull.
WIP branch: https://github.com/matthewjwhite/crystal-skull/compare/map?expand=1.
from crystal-skull.
Went with a way simpler approach of finding the map you're moving into by checking for the map that has that point in its space (see Dim::contains
). The other way was too complex and seemed to be fraught with unknown boundary cases.
from crystal-skull.
Related Issues (9)
- General enhancements HOT 2
- Fix up CI HOT 1
- Consider mongoengine HOT 2
- Add YAML validation HOT 3
- Add unit tests HOT 2
- Implement initial game loop HOT 3
- Implement initial battle system
- Implement initial user stats HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from crystal-skull.