WoobyCTF, The Beginning
February 3, 2012 23:30
Every time I've put together a larger program for my own enjoyment, it's always been in either C# or c++. For some reason I've always avoided Java as a reasonable language for large-scale projects. After having played minecraft and peeking around the source code for it, it seems like I just have to try it out. Additionally, whenever I have wrote in Java in the past, I have always used simple text editors to do so such as gedit or Kate in linux. This time around, I've decided to to the development in Windows in Eclipse. It will be an entirely new experience for me as I've never used this particular IDE for a personal project before but I really am looking forward to the experience.
My goal with this post and forthcoming posts is to keep me moving forward on this project. Whenever I have to write about my experiences and problems with anything, it keeps be accountable and motivated. Plus, I've always enjoyed web programming so it also gives me an excuse to develop the back end for this site.
In this blog, I'll be writing about my experiences of developing and documenting my progress. Maybe blowing off some steam as I struggle with an algorithm or bragging about an excellent implementation of something. Either way, I enjoy writing and I'll be putting my thoughts down here.
So for this first project, I've decided to put together a remake of a game that I played when I was younger with my older brother. It was a capture the flag style game originally made for DOS. My brother and I would play frequently. Since it was on the computer, we would leave the room as the other person was making their moves. It really is a fond part of my childhood so I am really looking forward to creating it for myself and hopefully improving it to some extent.
Today I focused entirely on building up the structure of the model. I created about twenty classes and started laying out the design of the model. I spent a couple of hours building the dependencies up and planning things as I did so. I've built good-sized games before so I am already quite familiar with the benefits and drawbacks of several different designs, so I didn't have to spend too much time weighing out all the options. After getting a basic outline put together, I put together the visibility algorithm to determine, given a character and that character's stance (crawling, looking, running, or walking), what cells around him he is able to see. I spent most of my time today looking at this algorithm.
Let's imagine we have a 21x21 grid with the middle cell being the location of the character. I considered doing a direct line of sight type of algorithm. In this case, I would draw a line from the middle cell to every cell around the outside and determine visibility based on the cells that line intersects. This benefits from using absolute line of sight from a character. Looking into it, I found it to be kind of difficult to implement, so I decided on a recursive algorithm for now. The algorithm takes in the starting cell, and begins fanning out, each cell making a recursive call to itself with the new cumulative distance. After having implemented that, I didn't like it too much. I think I'm actually going to fall back onto that iterative solution. I think having direct line of sight as a part of the algorithm would be fantastic and add a tiny bit of realism and strategy into the game. Next time I sit down, that will have to be the first thing I start looking at.
My recursive solution is the following:
public void populateVisibilityNumericalGrid(int x, int y, int characterIndex, int previousVisibility, int direction) {
if (!map.withinMap(x, y)) {
return;
}
int curVisibility = previousVisibility + map.getVisibilityAt(x, y);
if (curVisibility >= 10) { // needs to be replaced with the viewDistance of the current character's stance
return;
}
int translatedX = (x - playerxLocation) + (gridDimension / 2);
int translatedY = (y - playeryLocation) + (gridDimension / 2);
if (visibilityNumericalGrid[translatedX][translatedY] == 0 || visibilityNumericalGrid[translatedX][translatedY] > curVisibility) {
visibilityNumericalGrid[translatedX][translatedY] = curVisibility;
}
switch (direction) {
case 0: //Start case
populateVisibilityNumericalGrid(x-1, y-1, characterIndex, 0, 8);
populateVisibilityNumericalGrid(x, y-1, characterIndex, 0, 1);
populateVisibilityNumericalGrid(x+1, y-1, characterIndex, 0, 2);
populateVisibilityNumericalGrid(x+1, y, characterIndex, 0, 3);
populateVisibilityNumericalGrid(x+1, y+1, characterIndex, 0, 4);
populateVisibilityNumericalGrid(x, y+1, characterIndex, 0, 5);
populateVisibilityNumericalGrid(x-1, y+1, characterIndex, 0, 6);
populateVisibilityNumericalGrid(x-1, y, characterIndex, 0, 7);
case 1: //up
populateVisibilityNumericalGrid(x-1, y-1, characterIndex, curVisibility, direction);
populateVisibilityNumericalGrid(x, y-1, characterIndex, curVisibility, direction);
populateVisibilityNumericalGrid(x+1, y-1, characterIndex, curVisibility, direction);
break;
case 2: //Upright
populateVisibilityNumericalGrid(x, y-1, characterIndex, curVisibility, direction);
populateVisibilityNumericalGrid(x+1, y-1, characterIndex, curVisibility, direction);
populateVisibilityNumericalGrid(x+1, y, characterIndex, curVisibility, direction);
break;
case 3: //Right
populateVisibilityNumericalGrid(x+1, y-1, characterIndex, curVisibility, direction);
populateVisibilityNumericalGrid(x+1, y, characterIndex, curVisibility, direction);
populateVisibilityNumericalGrid(x+1, y+1, characterIndex, curVisibility, direction);
break;
case 4: //DownRight
populateVisibilityNumericalGrid(x+1, y, characterIndex, curVisibility, direction);
populateVisibilityNumericalGrid(x+1, y+1, characterIndex, curVisibility, direction);
populateVisibilityNumericalGrid(x, y+1, characterIndex, curVisibility, direction);
break;
case 5: //Down
populateVisibilityNumericalGrid(x+1, y+1, characterIndex, curVisibility, direction);
populateVisibilityNumericalGrid(x, y+1, characterIndex, curVisibility, direction);
populateVisibilityNumericalGrid(x-1, y+1, characterIndex, curVisibility, direction);
break;
case 6: //DownLeft
populateVisibilityNumericalGrid(x, y+1, characterIndex, curVisibility, direction);
populateVisibilityNumericalGrid(x-1, y+1, characterIndex, curVisibility, direction);
populateVisibilityNumericalGrid(x-1, y, characterIndex, curVisibility, direction);
break;
case 7: //Left
populateVisibilityNumericalGrid(x-1, y+1, characterIndex, curVisibility, direction);
populateVisibilityNumericalGrid(x-1, y, characterIndex, curVisibility, direction);
populateVisibilityNumericalGrid(x-1, y-1, characterIndex, curVisibility, direction);
break;
case 8: //UpLeft
populateVisibilityNumericalGrid(x-1, y, characterIndex, curVisibility, direction);
populateVisibilityNumericalGrid(x-1, y-1, characterIndex, curVisibility, direction);
populateVisibilityNumericalGrid(x, y-1, characterIndex, curVisibility, direction);
break;
}
}
Like I said, it turned out a little dirty. I think I can put together a more elegant and better solution iteratively tomorrow using line of sight.