- Release setup
- Camera bug fix
- Timer saving and logic
This week we set up the release for Alpha. In the process of this, we had to have a major rethink about how we are using scrum based on the criticisms of how we use it. We also took on board the advice to be more strict about culling parts of development that are less essential. Finally, we made sure to break down goals and tasks as much as we possibly could, to ensure more transparency was there in our development process.
Thursday (the first day of our release and sprint, the day after our presentation) myself and Ronan spent a good portion of the morning considering ways to redefine how we work. After a lengthy discussion, we ended up looking at it as "a week's work is 13 points at most". By week's work, we mean the effort a single sprint worth of work is given. This way, it ensures that nobody is doing too much, and because all the tasks will be broken down immensely, nobody will be doing too little either. Furthermore, if we aim for around 10 points a week each, it ensures that if something is underestimated, there is a spare bit of effort available to make up for that task being more difficult than expected.
Later that day we had our meeting, and we discussed this new way of working with the rest of the group. We all agreed that it was a good idea to do Scrum like this moving forward. We then started breaking down the tasks we considered for Alpha from the presentation, as well as whatever bug fixes that needed done from PoC along with any other tasks that were required from us but not consciously planned, like the lighting document as an example. We all spent time looking over the story point estimates to see if there was any misunderstandings and ensured everyone understood what was involved with the tasks and sorted out any objections. Myseltf and Ronan had made a head start on the tasks earlier in the day, so we got all of our tasks planned, broken down, estimated and relatively prioritised, so we made sure to run these by the rest of the team. We spent the entire meeting planning and estimating tasks, but we ran out of time. I didn't think it was wise to try and continue over hangouts, so I just told everyone to look at estimating more of the work to be reviewed the next day, along with the prioritisation process that we were yet to go through.
The next day, we continued our work at sorting out the tasks. We spent a lot of time brainstorming things out for what needs to go in the release, what would be nice to go in the release etc. The way we estimated the points is a more streamlined planning poker, where each individual still comes up with an estimate for the tasks, but the tasks are then scrutinised as a group until there is absolute clarity about what is involved and how difficult it will be. We found that this works very well, as it saves a lot of time but still works the same as planning poker.
Our prioritisation process was very similar to this. I made sure to keep the backlog items roughly grouped together by area as the items got added, and this meant that each area of the game could be prioritised within its own section so that when we went to add it to the release we could clearly draw a line across that area for things that made it in to the release and things that didn't. Each person prioritised their specialist area, and then this priority was re-evaluated as it was added to the release by the team as a whole. Being able to see these changes made in real time made things easy, as everyone was on their own machine.
I had the entire team in the same room on Scrum at the same time, so as things were being done we were watching and discussing it as a group. This process of individual development followed by group filtering sped the process up.
I'd estimate that we spent 4 hours over the two days working on this as a collective group, and an additional 4 hours being myself and Ronan discussing how to proceed along with individual people planning and sorting the tasks in their own time. I feel like this was a slow but necessary process, and now that it is done and prioritised the weekly meetings should be suitably brief.
I spent the rest of Friday to Sunday working on things from other modules.
On Monday, I started working on fixing the camera bug (after a little bit of help from Shane getting git to work properly). I essentially spent the time I had available for this on Monday pursuing dead ends however, as nothing was having the results I wanted. I spent my time trying to re-write the way the 3rd person camera worked entirely, and getting it to rotate and move while focused on the bike just wasn't working properly any other way I tried it. I went to bed and slept on it.
On Tuesday, I started my work on it by trying to modify what was already there. I took the thing that had worked best from Monday evening, which was to modify the spring arm, and integrated that into what we already had. Essentially, I tried to rotate the spring arm by the same pitch as the bike is rotated as it goes down through the level, and this worked fairly well, so I put some constraints on this to make it behave even better. For example, when the player is on level ground, rotate it up further than usual to let the player see further down.
Next, I changed the camera rotation to rotate around an arbitrary point that I set to be slightly in front of the bike, as I felt like the bike being the central point of focus wasn't working that well. I set up a variable, got the bike position, got the forward vector of the bike rotation, added them together, multiplied up the vector to be able to control the points' location, and used the LookAtPoint where I was using the bike position previously in the rotation code.
I then moved on to working on the split times implementation. I first looked at Shane's saving code in the UMG Options blueprint, since saving and loading is the most important part of this problem. I essentially spent the rest of Tuesday evening thinking about how I will do it, and I wrote this down, which I will paste here:
"The bike overlaps with the trigger box, then get a snapshot of the current time into an array (using a doOnce?) and do this a number of times throughout the race up until the finish line (so these are all split times). Then you have the "best times" or whatever already loaded in or something, compare the corresponding times, get the difference and print that all out.. For the end logic do a simple check to see if you had a better best time overall and if you did then you overwrite what is in the "best time" file. "
I knew what to do but not how or where to do it properly. The "whatevers or somethings" were the areas I was less sure of, so I asked Shane and he said he should be able to help me on Wednesday so I retired for the night.
Wednesday morning, I got a few pointers on how to do the saving and loading from Shane and got to working on the split time stuff. It took a good bit of help from him to get me started properly but once I got on track things started to go better.
I'll explain my process in steps below:
- Make a SplitTimeSave class that extends the SaveGame class and give it the 4 time variables to be saved (3 split times and a final time)
- Make a SplitTimeTrigger class that extends the TriggerBox class. Give it a SplitTimePosition integer variable and a reference variable to the LevelPlayer
- In the LevelPlayer, make a LoadSplitTimes function that loads in the times from file or sets up defaults if there are no files and stores them in the SplitTimeSave file, which is referenced in the level player.
- Create a SetTimeSplit function in the LevelPlayer and have it be called everytime the player triggers a SplitTimeTrigger. In the SplitTimeTrigger, the SetTimeSplit function is called and passes the SplitTimePosition (essentially which trigger box it is e.g. the first one etc) in, which sets the corresponding float in an Array of split times. If the box that is triggered is the finish line, then the FinishRace function is called.
- In the FinishRace function, the first thing that happens is a FinishRaceEvent is fired to stop the timer as the player crosses the finish line. The player's final time is then compared with the time that was loaded in, and if it was a better time, the SaveSplitTimes function is called, which writes the times from the current run out to file.
This is not the order things were developed but rather the order in which they are done to create the desired system. I will show below the different blueprints.
This is the SplitTimeSave file.
This is the SplitTimeTrigger class. Note the SplitTimePosition being fed into the SetTimeSplit function.
Here, the local SplitTimes array is set based on which trigger box is triggered. If the final one is triggered, FinishRace is called.
The FinishRaceEvent is for stopping the actual timer on in the event graph. The local time is checked against the stored time, and if it is less, it is stored to file in the SaveSplitTimes function.
The local times are fed into the SaveSplit object which is then saved out to file.
This entire process is prefaced by the LoadSaveTimes function, which is called at the start in the event graph. Here we see the times either getting loaded or set to their default values.
Here we see the LoadSaveTimes being called on begin play, and the FinishRace event causing the Timer to stop.
Scrum wise (heh), there were no issues other than on Wednesday, a few of us were behind schedule so we took some stories off the sprint to be done next week. This is a minor problem with planning in some way, but we feel as though we will make the time up next week to get back on schedule. My main issue was the camera bug fix taking too long and ultimately still not being very good even after all that.