Pitching games & fab48hr gamejam

48hr GameJam

I went to the 48hr game jam at QUT which was full of impressive games and people. Here is my top 3, and what they were about:

CQdkYRLUkAABO_9SOL – I had a blast with this. While the controls were a little difficult the team had taken steps to account for this. Shooting a missile or asteroid at a target did not have to be precise, as these targets had gravity wells that would draw the projectile into the target. This allowed for more fast-paced gameplay, where you would fire and forget about it, immediately moving on to your next strategy before the completion of the last, creating a more chaotic experience. I found it suffered slightly from a slow ramp up in difficulty, which was helpful on the first play but not as much on subsequent plays. The colour choice of red and orange for opposing players was slightly confusing too, however, I was so quickly invested in this game that I threw my arms up in the air when I won.

CQcMLapW8AATNWLDUNE RAIDER – From first impressions I was surprised, this game looks complete. The amount of polish is astounding. The idea of the game is to move from the bottom of the screen to the top, grab some gold and move back to the bottom. The first to get enough gold wins. You have the option of how much gold you take, but the more gold you take, the slower you move. There is also the ability to leap forward, which you can use to knock another player around. There are also giant sand worms appearing randomly across the map, which will empty your gold sack if you touch them. Unfortunately, the best strategy to win is to fill your sack to maximum, and leap back to the goal, as you are only slightly slower than max speed at that point. Others can knock you around, but will be most likely focused on trying to win themselves. Still an absolutely brilliant game.

21743298288_ccf9e9e630_bWHERES MY SPACESHIP? – Playing over 4 four screens, fly a spaceship through wormholes to collect the most asteroids. The enjoyment/stress of this game comes from random screen transitions and the fun of trying not to collide with the other players as they franticly sprint around the room trying to locate their ship. Of course, you can steal each others asteroids so I sat at the drop off point and grabbed everyone’s asteroids as they warped in, easily guiding them into my collection port. Figuring that out was immensely fun, but I worry that once this strategy is figured out by players, gameplay may lose its excitement. Still a very impressive display of technology, and a highly enjoyable game.

I did a pitch for my game Clearcutter. In my pitch, I had issues with some of the slide content, where I had chosen to load up the videos on youtube. I should have downloaded them and dropped the files into the slide themselves to avoid loading issues. These videos were also not needed, as they were only showing the main view of the game and the general feel of movement & mechanics. I also drew a picture of the main screen, which was not needed as I ended up starting work on the project itself, which I presented for part of the pitch. This was able to effectively show the main player screen, basic mechanics and movement/game feel. The feedback that I received mainly pointed out that the way I was talking about how the game would work made it very hard to conceptualize the game itself, but the second I showed the prototype, It was instantly understood. I also had an issue with needing to read from a script, which I had set up on my laptop. This meant that instead of talking to the audience, I was talking to my laptop. A simple fix would have been to create small cards to read from and spending more time practicing my pitch, which is a recurring problem that I have.

Strong points that I had were generating interest with an exciting intro, explaining the background and theme of my game, even if it was a little confusing, and actually having a very basic version of my game set up to demonstrate what my game would be.

My plan for my future is after completing my current course, gaining industry experience, and to grow my network. Working in local studios will help with that and taking any programming jobs that have a decent pay, whether they are in the gaming industry or not, will help me save money to either move or help create my own studio. I also plan to take a course in business management.

1rIGqbm

Another game that was made for our week 1 project was Caffeine Chaos, by Ash Stevens, which had to meet the same brief requirements as my game. You had control over two avatars, Tony and Steve, whom you controlled using the WASD and arrow keys to move them around. Steve controlled normally, but Tony had an inverted Y-axis, which flipped around based on the proximity of the two avatars, and movement was the only control you had over them. Proximity. For having the avatars as close together without touching as possible, players were rewarded with easier controls over the avatars and increased movement speed. The game had a 2-minute time limit, there was no death, and the game was in real time

Through this, the game meets all the limitations set out in the brief. The game has two directional inputs, which is fairly minimalistic as most arcade games have a joystick and six buttons available. The mechanics are strong, but could be explained to the player better, with the inclusion of visual cues to display which state the control scheme is currently in.

Speed, Juice and Optimization

This week, I made a game called CLEARCUTTER

0640e66bd401445e445aac4f6c368bb1

It’s a game where you take control of two rockets simultaneously, and try to cut down as many trees as possible in 2 minutes, while not hitting them with the rockets. the closer your rockets are together the faster you accelerate, but if they touch, you explode and lose speed.

There were several tasks that I aimed to achieve for this game that I had not attempted before

  • Modifying terrain at runtime with minimal frame loss
  • Creating an endless obstacle course with a scaling challenge over time
  • Optimization of program
  • Creation of an effective high score table that persist across play sessions
  • Use of visual and aural feedback systems (like juice)
  • Creation of a ‘trail renderer’ tool, that could use shapes as its starting point
  • Use of visuals instead of text to describe mechanics to the player

I excelled in the areas of simple coding or setting up structures that I had previously set up in other projects. This sounds like it should go without saying, but there is a startling difference in the time taken between this and something new. A problem that I had was with transitioning from the planning stage to the coding stage when I had the idea, but not the knowledge of implementing it and I had to spend a lot of time researching the subject. I also had issues with clumsily bodging a solution together. This is normally good enough for simple code or a small project but becomes an issue when other structures begin to depend on it, or when refactoring the code is required. It looks like spaghetti and pressing changes to a single line can cause huge issues if you can even understand what it does. I of course also had issues with getting stuck on a problem that I did not know the solution to. It meant hours of research over things that were often simple or silly mistakes I had made earlier.

When compared to work I had experience in, there were hours of difference. This was made obvious to me when setting up the high score table. It is just three arrays of data stored into player prefs, and then set and shifted under correct circumstances. Here is an example of that code.


 void Start()
 {



 // check if this is first play
 if (PlayerPrefs.GetInt("HasScore") < 1)
 {
 WriteNewScores();
 }

 //clear out the restart option text until it is available
 restartText.text = " ";
 // fade in the scene from black
 GameObject.FindWithTag("ScreenFade").GetComponent<ScreenFade>().FadeIn();

 LoadScores();

 input.interactable = false;
 newHighscore.enabled = false;

 // if the gamecontroller exists, get the score and speed from it
 if (GameObject.FindGameObjectWithTag("GameController") != null)
 {
 gameController = GameObject.FindGameObjectWithTag("GameController");
 gameScore = gameController.GetComponent<UI>().GetTreeCutScore();
 topSpeed = gameController.GetComponent<UI>().topSpeed * 100;
 CheckHighScore(gameScore);
 }
 //if not, set up from title scene transition
 else
 {
 fromTitle = true;
 newHighscore.enabled = true;
 newHighscore.text = "HIGHSCORES";
 restartText.enabled = true;
 restartText.text = "Press A to return";
 }

 // now load the new scores in case of highscore and display them for the player
 LoadScores();
 DisplayScores();

 // destroy the game controller, as it is no longer needed (and to stop it from looping through the game with restart)
 Destroy(gameController);


 }

 void Update()
 {
 // if the player presses A, and is able, restart the game
 if (Input.GetButtonDown("Fire1") && inputDone)
 {
 StartCoroutine(FadeTimer());
 GameObject.FindWithTag("ScreenFade").GetComponent<ScreenFade>().FadeOut();
 }
 }

 IEnumerator FadeTimer()
 {
 // destroy the screen fade object so it doesnt loop with restart, and load the title scene after 1 second
 yield return new WaitForSeconds(1);
 Destroy(GameObject.FindWithTag("ScreenFade"));
 Application.LoadLevel("StartScene");

 }

 void WriteNewScores()
 {
 // (for first play) set up the highscore table with 10 scores so it is not empty
 for (int index = 0; index <= 9; index++)
 {
 PlayerPrefs.SetInt("Score" + index.ToString(), 120 - (index * 12 + 20));
 PlayerPrefs.SetString("Name" + index.ToString(), "MAX");
 PlayerPrefs.SetString("Speed" + index.ToString(), (400 - (index * 9 + Random.Range(-200, 100))).ToString("0.00"));
 PlayerPrefs.SetInt("HasScore", 1);
 }
 }

 void DisplayScores()
 {
 // clear the score text field
 scoreText.text = "";

 // and write the scores stored in the arrays to screen
 for (int index = 0; index < scoreArray.Count; index++)
 {
 scoreText.text += (index + 1) + " " + nameArray[index] + " " + scoreArray[index].ToString() + " " + speedArray[index] + "GM/H" + "\n";
 }
 }

 void LoadScores()
 {
 //clear out the arrays
 scoreArray.Clear();
 nameArray.Clear();
 speedArray.Clear();

 // and add the player pref stored scores back into them
 for (int index = 0; index <= 9; index++)
 {
 scoreArray.Add(PlayerPrefs.GetInt("Score" + index.ToString()));
 nameArray.Add(PlayerPrefs.GetString("Name" + index.ToString()));
 speedArray.Add(PlayerPrefs.GetString("Speed" + index.ToString()));
 }
 }

 public void GetInput()
 {
 // receive the input from the input field and convert to upper case;
 nameInput = input.text.ToUpper();

 // if the input is not blank, to stop clicking auto restarting, then set the players input into the name player pref, using the stored int as the index key
 if (nameInput != "")
 {
 input.interactable = false;
 PlayerPrefs.SetString("Name" + tempInt.ToString(), nameInput);
 input.text = "";
 }

 // refresh the text display to show the new score & input, show restart info & allow restart
 LoadScores();
 DisplayScores();
 inputDone = true;
 restartText.text = "Press A to restart";
 }

 void CheckHighScore(int value)
 {
 // if we came from the title, dont do this
 if (!fromTitle)
 {
 foreach (int item in scoreArray)
 {
 // go through each score in the array, and if we have one that is higher, run update score & set text to reflect this to player
 if (value > item)
 {
 inputDone = false;
 UpdateScore(value);
 input.ActivateInputField();
 input.interactable = true;
 newHighscore.enabled = true;
 newHighscore.text = "!! NEW HIGHSCORE !!";
 break;
 }
 else
 {
 //if not, display the players score and info, and allow restart
 newHighscore.enabled = true;
 restartText.enabled = true;
 newHighscore.text = "You cut " + gameScore.ToString() + " trees, with top speed of: " + topSpeed.ToString("0.00") + "GM/H" + "\n";
 restartText.text = "Press A to restart";
 }
 }
 }
 }

 void UpdateScore(int value)
 {
 // run through array bottom to top (lowest to highest scores)
 for (int index = 9; index >= 0; index--)
 {
 // the first score that is higher than the players score will cause the score below it to be replaced
 if (value > scoreArray[index])
 {
 PlayerPrefs.SetInt("Score" + (index + 1).ToString(), PlayerPrefs.GetInt("Score" + index.ToString()));
 PlayerPrefs.SetString("Name" + (index + 1).ToString(), PlayerPrefs.GetString("Name" + index.ToString()));
 PlayerPrefs.SetString("Speed" + (index + 1).ToString(), PlayerPrefs.GetString("Speed" + index.ToString()));
 LoadScores();
 DisplayScores();
 }

 else
 {
 // if the score is lower than the players' then it will be shifted down a slot.
 PlayerPrefs.SetInt("Score" + (index + 2).ToString(), PlayerPrefs.GetInt("Score" + (index + 1).ToString()));
 PlayerPrefs.SetString("Name" + (index + 2).ToString(), PlayerPrefs.GetString("Name" + (index + 1).ToString()));
 PlayerPrefs.SetString("Speed" + (index + 2).ToString(), PlayerPrefs.GetString("Speed" + (index + 1).ToString()));
 // set the players score to the correct slot
 PlayerPrefs.SetInt("Score" + (index + 1).ToString(), gameScore);
 PlayerPrefs.SetString("Speed" + (index + 1).ToString(), topSpeed.ToString("0.00"));
 PlayerPrefs.SetString("Name" + (index + 1).ToString(), " ");
 tempInt = index + 1;
 // load and display the new score, with a gap for the players name
 LoadScores();
 DisplayScores();
 break;


 }
 if (index == 0)
 {
 // if we hit the top slot, shift it down and set the players score there
 PlayerPrefs.SetInt("Score" + (index + 1).ToString(), PlayerPrefs.GetInt("Score" + index.ToString()));
 PlayerPrefs.SetString("Name" + (index + 1).ToString(), PlayerPrefs.GetString("Name" + index.ToString()));
 PlayerPrefs.SetString("Speed" + (index + 1).ToString(), PlayerPrefs.GetString("Speed" + index.ToString()));

 PlayerPrefs.SetInt("Score" + index.ToString(), gameScore);
 PlayerPrefs.SetString("Speed" + index.ToString(), topSpeed.ToString("0.00"));
 PlayerPrefs.SetString("Name" + index.ToString(), " ");
 tempInt = index;

 LoadScores();
 DisplayScores();
 break;
 }
 }
 }

}

This is messy and not very optimal, but at under 200 lines, it should have taken an hour or so, not several.

Another issue I had was choosing a solution that I previously worked with and knew pretty well, that was not suited to the job. To check for collisions with trees, and cut them down as the player flew past them, I did a raycast check every frame from one rocket to the other. It worked fine, right up to the point where the rockets were moving. The problem was that the area of detection would eventually move so fast as to start on one side of an object you are trying to detect, and in the next frame, have moved to the other side of it, missing it completely. This issue is known as tunneling, which you get when you introduce high speeds or small objects to your game. There are several complex and elegant solutions that will avoid a tunneling issue, but what I chose to do was create a collision box whose size, rotation and position would change to reflect the amount of movement that would occur in each frame. In short, its depth was equal to the player’s speed, it was always looking at one of the rockets to keep its rotation, and its position was in between the rockets, and half their speed ahead of them.

This setup is so effective that I am confident it would detect collisions at any speed.

I tried to add feedback loops into the game, or juice and a lot of these were based on speed. To help the player feel as though they were moving fast, I made the field of view scale up to a point as they gained speed. It seems fairly subtle until you have a sudden loss in speed from collision. Once the speed reached 275, a particle emitter switched on and created shockwave like rings around the rocket. I also scaled the sizes of the rockets exhaust trail and light to reflect the acceleration from the rockets proximity to one another. In testing, this was usually noticed by the player a minute into their first run or less. This, coupled with the high score table led most players to try another run, so they could try and implement their idea of the best strategy. This best strategy was almost always the one I had wanted the player to attempt from the design stage. Along with camera effects like bloom, sun shafts, audio effects for knocking down trees and a high energy BGM, these were the positive juice items that I included.

Negative juice items were things like warning signals and explosions. The warning signals seemed reasonably effective in the early game at conveying to the player that they should not collide with trees and seemed to raise stress levels in the late game with an almost constant warning alarm going off. There was an issue with a lack of collisions at high speed, as the detection is from a single raycast forwards. I chose to leave this in, as the difficulty of reaching extreme speeds would be impossible, and would remove some of the enjoyable experience that could be had in my game. The explosions happen at the end of the run, which was received well, and also when the rockets collide with each other, which created a problem. The explosion takes up a large amount of the screen, is very bright and very loud: it is an extremely strong feedback. At the start of the game, as the rockets are constantly drawn together, they will collide. To a new player, this causes stress and the player learns that the rockets must be kept apart. Because of this, many new players held the rockets as far apart from each other for the whole run, missing the lesson of proximity = acceleration. This causes a slow and boring run, when the player realizes they were playing it wrong (from the high scores, which are now daunting multitudes greater than the players score) they will give up. This might be fixed by ramping up the strength of that attraction over the first 10 seconds, so there is no explosion at the start unless they collide the rockets themselves (but may make the controls confusing) or by better explaining this mechanic before the player is allowed to play the game (for the first run).

While creating this game, I had some serious optimization issues, which were highly problematic due to the large variation in speed, and immense top speed (~100 units/frame is the highest I have seen). The FPS would often drop below 30, when at these speeds I needed it to sit at 60. On some computers, it would even sit well above 90 for a while, which also made the game unplayable as the controls were way too touchy and the player had no time to react to anything. Moving terrains, spawning in hundreds of trees despite speed and fading out every material on a tree as you destroyed it, lots of grass and poorly optimized code were causing these issues. I received help to identify what was causing the severe loss in framerate, cleared up the code to make it as light as possible, changed the way my trees were spawned in (instead of just every half second, it also waited till the player had moved forward 5 units, so that if you were moving slowly there wasn’t a huge wall of trees spawning) and reduced the quality of the models, as since you are moving so fast, there is no time to notice model detail. Reducing the size of the terrains helped with the hang time of moving them, and once the other frame rate issues were fixed, there was plenty of time left for the operation to complete before causing a hang.

I am fairly happy with how this game turned out and if there is a good reason to keep working on it I have some plans with more things I could do to it.