CS 61B Project 3 CS61BYoW
In Project 3, you will create an engine for generating explorable worlds. This is a large design project that will require you and one partner to work through every stage of development from ideation to presentation. The goal of this project is to teach you how to handle a larger piece of code with little starter code in the hopes of emulating something like a product development cycle. In accordance with this, the grading of this project will be different from other projects. Since there is no notion of “the correct answer” when it comes to world design and implementation, you will be assessed much like a performance review you might receive at an internship or job in addition to a very general autograder. While this means you will be graded slightly subjectively, we promise to be pretty nice bosses and will respect you as any boss should respect their hard working employees. Please talk to us if you feel the grading scheme feels unfair.
Copyright By PowCoder代写 加微信 powcoder
This project will require you a great deal of exploration and experimentation. Searching the web for
answers (not solutions from past semesters) should be a regular activity throughout this process. Please know that there
are no right and wrong answers, as this is a very open-ended project. However, there are some implementations and ideas that
are better than others. It is ok and expected that you will go through several iterations before settling on something that you deem good.
That is, this project is about software engineering.
You’re not required to use any of the fancy data structures or concepts from class (A*, MSTs, Disjoint Sets, etc). This project is about software engineering, not about data structures or algorithms. The data structures and algorithms we’ve learned about in class will make your code significantly simpler and more efficient, but please don’t use things just because we learned about them in class. Only use these tools if you feel comfortable using them in your implementation.
A video playlist (from Spring 2018) discussing tips for working on this project can be found at this link. Note that the API has changed slightly, but the basic ideas are all still true. Slides for these videos can be found at this link.
There are several key deadlines for this assignment:
Phase 0 – Team formation: You must submit the Project 3 Partnership form by Sunday, 11/06, 11:59 PM PST. You will not be able to change your partner later. Read and understand the partnership guidelines before starting the assignment
Phase 1 – World Generation: Due on Gradescope by 11/14 at 11:59 PM.
Phase 2 – Interactivity: Due on Gradescope by 11/30 at 11:59 PM.
You cannot submit Phase 2 of the project late (using slip days), as it will be
graded during a lab checkoffs with a TA (including 47b students). While in theory you could submit Phase 1 and the supporting labs (Lab 11 and Lab 12) late, Phase 2 of the project
builds upon these assignments, so it is unlikely that you will be able to submit these assignments late and still
complete Phase 2 on time.
Now on to the assignment spec!
Overview #
Your task for the next 4 weeks is to design and implement a 2D tile-based world exploration engine. By “tile-based”, we mean the worlds you generate will consist of a 2D grid of tiles. By “world exploration engine” we mean that your software will build a world, which the user will be able to explore by walking around and interacting with objects in that world. Your world will have an overhead perspective. As an example of a much more sophisticated system than you will build, the NES game “Zelda II” is (sometimes) a tile based world exploration engine that happens to be a video game:
The system you build can either use graphical tiles (as shown above), or it can use text based tiles, like the game shown below:
We will provide a tile renderer, a small set of starter tiles, and the headers for a few required methods that must be implemented for your world engine and that will be used by the autograder. The project will have two major deadlines. By the first deadline, you should be able to generate random worlds that meet the criteria below. By the second deadline, a user should be able to explore and interact with the world.
The major goal of this project is to give you a chance to attempt to manage the enormous complexity that comes with building a large system. Be warned: The system you build probably isn’t going to be that fun for users! Three weeks is simply not enough time, particularly for novice programmers. However, we do hope you will find it to be a fulfilling project, and the worlds you generate might even be beautiful.
Skeleton Code Structure #
The skeleton code contains two key packages that you’ll be using: byow.TileEngine and byow.Core. byow.TileEngine provides some basic methods for rendering, as well as basic code structure for tiles, and contains:
TERenderer.java – contains rendering-related methods.
TETile.java – the type used for representing tiles in the world.
Tileset.java – a library of provided tiles.
IMPORTANT NOTE: Do NOT change TETile.java’s character field or character() method as it may lead to bad autograder results.
The other package byow.Core contains everything unrelated to tiles. We recommend that you put all of your code for this project in the byow.Core package, though this not required. The byow.Core package comes with the following classes:
RandomUtils.java – Handy utility methods for doing randomness related things.
Main.java – How the user starts the entire system. Reads command line arguments and calls the appropriate function in Engine.java.
Engine.java – Contains the two methods that allow interacting with your system.
byow.Core.Engine provides two methods for interacting with your system. The first is public TETile[][] interactWithInputString(String input). This method takes as input a series of keyboard inputs, and returns a 2D TETile array representing the state of the universe after processing all the key presses provided in input (described below). The second is public void interactWithKeyboard(). This method takes input from the keyboard, and draws the result of each keypress to the screen. Lab 11 covers how to render tiles, and Lab 12 covers how to get user input.
This project makes heavy use of StdDraw, which is a package that has basic graphics rendering capabilities. Additionally, it supports user interaction with keyboard and mouse clicks. You will likely need to consult the API specification for StdDraw at some points in the project, which can be found here.
Your project should only use standard java libraries (imported from java.*) or any libraries we provided with your repo. However, for the extra credit video only, you may use external libraries if you’d like. Your final submission for the Phase 2 Autograder and Checkoff should not use any external libraries other than the ones provided in the skeleton.
IMPORTANT NOTE: Do NOT use static variables unless they have the final keyword! In 2018, many students ran into major debugging issues by trying to use static variables. Static non-final variables add a huge amount of complexity to a system. Additionally, do not call System.exit() as this will cause the autograder to exit and fail.
Phase 1: World Generation #
As mentioned above, the first goal of the project will be to write a world generator. The requirements for your world are listed below:
The world must be a 2D grid, drawn using our tile engine. The tile engine is described in lab11.
The world must be pseudorandomly generated. Pseudorandomness is discussed in lab 11.
The generated world must include distinct rooms and hallways, though it may also include outdoor spaces.
At least some rooms should be rectangular, though you may support other shapes as well.
Your world generator must be capable of generating hallways that include turns (or equivalently, straight hallways that intersect).
The world should contain a random number of rooms and hallways.
The locations of the rooms and hallways should be random.
The width and height of rooms should be random.
Hallways should have a width of 1 or 2 tiles and a random length.
Rooms and hallways must have walls that are visually distinct from floors. Walls and floors should be visually distinct from unused spaces.
Rooms and hallways should be connected, i.e. there should not be gaps in the floor between adjacent rooms or hallways.
All rooms should be reachable, i.e. there should be no rooms with no way to enter
The world should be substantially different each time, i.e. you should not have the same basic layout with easily predictable features
As an example of a world that meets all of these requirements (click for higher resolution), see the image below. In this image, # represents a wall tile, a dot represents a floor tile, and there is also one golden colored wall segment that represents a locked door. All unused spaces are left blank.
Once you’ve completed lab 11, you can start working on your world generation algorithm.
It is very likely that you will end up throwing away your first world generation algorithm. This is normal! In real world systems, it is common to build several completely new versions before getting something you’re happy with. The room generation algorithm above was my 3rd one, and was ultimately much simpler than either of my first two.
You’re welcome to search the web for cool world generation algorithms. You should not copy and paste code from existing games or graphical demos online, but you’re welcome to draw inspiration from code on the web. Make sure to cite your sources using @source tags. You can also try playing existing 2D tile based games for inspiration. Brogue is an example of a particularly elegant, beautiful game. Dwarf Fortress is an example of an incredibly byzantine, absurdly complex world generation engine.
The Default Tileset and Tile Rendering Engine #
The tile rendering engine we provide takes in a 2D array of TETile objects and draws it to the screen. Let’s call this TETile[][] world for now. world[0][0] corresponds to the bottom left tile of the world. The first coordinate is the x coordinate, e.g. world[9][0] refers to the tile 9 spaces over to the right from the bottom left tile. The second coordinate is the y coordinate, and the value increases as we move upwards, e.g. world[0][5] is 5 tiles up from the bottom left tile. All values should be non-null, i.e. make sure to fill them all in before calling renderFrame. Make sure you understand the orientation of the world grid! If you’re unsure, write short sample programs that draw to the grid to deepen your understanding. If you mix up x vs. y or up vs. down, you’re going to have an incredibly confusing time debugging.
We have provided a small set of default tiles in Tileset.java and these should serve as a good example of how to create TETile objects. We strongly recommend adding your own tiles as well.
The tile engine also supports graphical tiles! To use graphical tiles, simply provide the filename of the tile as the fifth argument to the TETile constructor. Images must be 16 x 16, and should ideally be in PNG format. There is a large number of open source tilesets available online for tile based games. Feel free to use these.
Any TETile object you create should be given a unique character that other tiles do not use. Even if you are using your own images for rendering the tile, each TETile should still have its own character representation.
If you do not supply a filename, or the file cannot be opened, then the tile engine will use the unicode character provided instead. This means that if someone else does not have the image file locally in the same location you specified, your world will still be displayed, but using unicode characters instead of textures you chose.
The tile rendering engine relies on StdDraw. We recommend against using StdDraw commands like setXScale or setYScale unless you really know what you’re doing, as you may considerably alter or damage the a e s t h e t i c of the system otherwise.
Starting Your Program #
Your program will be started by running the main method of the Main class. You will see that this method calls one of two possible methods, based on the way a user wants to interact with your program. Users can provide the program a command line argument, describing how they want to generate the random world and what exploration they wish to complete, in which case, Main.main calls the Core.Engine.interactWithInputSting(String s) method. When running Core.Main.main with an input string, the format of the command argument should be -s inputString, where inputString is the input of interactWithInputString(). If no command line argument was provided, the user wants to interact with the program using a GUI menu and exploring the world using the keyboard, in which case Main.main calls the Core.Engine.interactWithKeyboard() method.
For phase 1, your project does not need to support interactWithKeyboard() but it must support interactWithInputString(). Specifically, you should be able to handle an input of the format “N#######S” where each # is a digit and there can be an arbitrary number of #s. This corresponds to requesting a new world (N), providing a seed (#s), and then pressing S to indicate that the seed has been completely entered.
We recommend that you do not implement Core.Engine.interactWithKeyboard() until you get to phase 2 of the project (interactivity), though you’re welcome to do so at anytime. It will be easier to test drive and debug your world generator by using interactWithInputString instead.
We also recommend not using Core.Main.main until you get to phase 2. It’s easier to do phase 1 by writing your own main method in the class you interact with the most, that creates a renderer, calls interactWithInputString, then draws the result. If you write your own main method, you can ignore the -s flag and make the input string your only program argument. To provide a main method command line argument through IntelliJ, if you’ve already tried to run the main method, go to Run > Edit Configurations, and you can edit the Program Arguments box to input your string, as shown below.
If you haven’t run the main method yet, right click the green arrow next to your main method like shown below, and click “Modify Run Configurations” to access the same window as above.
Finally, we recommend that you make minimal modifications to the Core.Main class. It is a much better idea to delegate all the work of the program to other classes you will create.
When your Core.Engine.interactWithKeyboard() method is run, your program must display a Main Menu that provides at LEAST the options to start a new world, load a previously saved world, and quit. The Main Menu should be fully navigable via the keyboard, using N for “new world”, L for “load world”, and Q for quit. You may include additional options or methods of navigation if you so choose.
After pressing N on the keyboard for “new world”, the user should be prompted to enter a “random seed”, which is a long value of their choosing. This long data type will be used to generate the world randomly (as described later and in lab 12).
The UI should show the seed value that the user has entered so far.
After the user has pressed the final number in their seed, they should press S to tell the system that they’ve entered the entire seed that they want. Your world generator should be able to handle any positive seed up to 9,223,372,036,854,775,807. There is no defined behavior for seeds larger than this.
The behavior of the “Load” command is described later in this specification.
If the system is instead started with Core.Engine.interactWithInputString(), no menu should be displayed and nothing should be drawn to the screen. The system should otherwise process the given String as if a human user was pressing the given keys using the Core.Engine.interactWithKeyboard() method. For example, if we call Core.Engine.interactWithInputString(“N3412S”), your program should generate a world with seed 3412 and return the generated 2D tile array. Note that letters in the input string can be upper or lower case and your engine should be able to accept either keypress (ie. “N” and “n” should both initiate the process of world generation). You should NOT render any tiles or play any sound when using interactWithInputString().
If you want to allow the user to have additional options, e.g. the ability to pick attributes of their character, specify world generation parameters, etc., you should create additional options. For example, you might add a fourth option “S” to the main menu for “select creature and create new world” if you want the user to be able to pick what sort of creature to play as. These additional options may have arbitrary behavior of your choosing, however, the behavior of N, L, and Q must be exactly as described in the spec!
Phase 1 Summary #
For Phase 1, you should be able to run Main.main by providing an input String, and have your program create a world, that adhere to the requirements mentioned above along with our randomness requirements mentioned in the Submission and Grading section below. Note that you should render the world to check your code by writing your own main method, but for the autograder, interactWithInputString() should not render the world, only returning the row as a TETile array.
Worlds should be visibly different for different seeds provided to the program.
Design Document #
Since we did not provide you with any significant skeleton code for Project 3, and since the project is very open ended, we expect that BYOW implementations will vary a fair amount between students. We recommend that you have a design document that reflects the current state of your project.
Before you begin writing any code, use the guidelines listed here to create a plan for every feature of your BYOW program, and convince yourself that your design is correct. Writing a design document is an iterative process. After coming up with your initial design, you may find some flaws in it, requiring you to revisit your design and update its description according to your new findings.
Note: Your design document will NOT be graded ever.
Design Document Guidelines #
You may use the following format for your BYOW design document.
Design Document Sections #
1. Classes and Data Structures #
Include here any class definitions. For each class, list the instance variables (if any). Include a brief description of each variable and its purpose in the class. Your explanations in this section should be as concise as possible. Leave the full explanation to the following sections. You may cut this section short if you find your document is too wordy.
2. Algorithms #
This is where you tell us how your code works. For each class, include a high-level description of the methods in that class. That is, do not include a line-by-line breakdown of your code, but something you would write in a javadoc comment above a method, including any edge cases you are accounting for. We have read the project spec too, so make sure you do not repeat or rephrase
程序代写 CS代考 加微信: powcoder QQ: 1823890830 Email: powcoder@163.com