𦦠Current Course: The Otter Game
This doesn’t work well in the embed, I would suggest checking out the GitHub for a better experience. https://harleiquill.github.io/p5-self-portrait-sp25/
README – This documentation is pretty long, and pretty wandering, but it is what I turned in with my project to Professor DuBose. It covers the start, reasons, design choices, processes, and boring dev stuff that we never get to see in the wild. So, I’m including it here with this. I hope you enjoy the game, and if you get really bored, enjoy the README, too. đ
Current Course
By Jillina Harken
Spring 2025
Project Goal:
Create a p5.js game where an otter navigates a river, dodging obstacles (logs) while trying to surviveâŚ
This project is an interactive âself-portraitâ represented through an otter swimming down a stream. The otter reflects my deep connection to friendship and community, as otters are social animals that hold onto one another to stay together. In the same way, I hold onto my friendships for support and connection, and encourage those who are close to me to do the sameâespecially when they come up against an obstacle and need extra support.
The interactive component allows users to use the arrow keys or wasd keys to swim around obstacles in the stream. If they hit the obstacle, the otter will collide based on game logic with the obstacle, and a reassuring message will appear, encouraging them to try again. This represents the way I approach challenges in lifeâsetbacks happen, but perseverance matters more than perfection. The user can also just continually push buttons to make the otter move because itâs fun.
For the name of the game, I have decided on using a play on words in a few different ways. âCurrentâ being a riverâs current and âcourseâ referring to the path – so literally thereâs that aspect. More abstract, current could be âright nowâ as in this is the path weâre on right now, and we donât know if it works or where it leads, but weâre doing our best! Also along those lines, this is ONLY the âcurrentâ course, and there are many more tributaries on this river we may choose in the future; so even if we fail here, there are many chances for success in the future.
After defining this as a simple game of dodging obstacles, I included many stretch goals in my initial project proposal. Some of these were things I was able to include, some are things I believe may be too complex for my skill and the p5.js environment weâre working in.
One of the most challenging aspects of this project was learning to write in a language that Iâm not familiar with. I am excellent at communicating via the English language, a skill I have spent many years working on. However, the logical world of computer languages is not something that was previously within my wheelhouse. Learning to communicate what I want the computer to do based on a logical language has been a paradigm shift for me. Itâs especially challenging when thinking back on how hard I worked to do this same project in undergrad. Previously, I got so tied up in the tiny details that I was paralyzed from getting anything concrete established within that project. I recall that just getting a background to show up with an overlay was a challenge for me, and it makes me laugh to think of it now because I used a semi-transparent red rectangle as part of my troubleshooting with the sprite hitbox during this project. If someone had told me during my undergrad iteration of this class that I would be using that challenging task to troubleshoot something, I probably would have laughed right in their face.
Above and beyond creating something that I can share with the world, I have woven in deep layers of meaning behind the game. From the animal I picked (which was initially going to be a racoon), to the background images (this was going to be an alley full of trash), I really worked hard to define the game in a positive light. While this may not be a part of the game many people explore, care for, or find the answer to; it still means a lot to me. As I mentioned in my initial proposal, the choice of the otter was based on the social needs of the little critters. Their family units holding hands while floating so they donât get separated has been something that has always touched me very deeply, because we can see that reflected in human society. If we donât hold on to one another, we tend to drift apart. Including positive messages instead of negative ones when the player makes a mistake was another important choice because I believe strongly in removing toxicity from gaming. The game over screen includes a message that says the otter looks tired, instead of being âdeadâ, which was a deliberate choice to remove the negative thought of an otter dying because the player made a mistake.
When we started this project I had decided to challenge myself this time around, and I definitely did that. However, I wasnât sure how developing a game could be a âself portraitâ when we started. Looking back now, I can see that even if I havenât used so much symbolism there would still be so much of me in this game. Even without context on the design choices, I can see how this game represents my ideals in so many ways, and I am proud of what I have accomplished here.
Stretch Goals (starting)
Adding a second otter that occasionally appears to âhold handsâ with the main otter.This is too complex for my skill level and the p5.js environment, especially since the otterâs hitbox would have to be doubled while the new otter is on the screen. Although my skills in p5.js have definitely improved over this semester, I do not think this is something Iâm ready to tackle in the remaining time we have left for this project.- Gentle sound effects or background music to enhance immersion.
- Different randomized messages of encouragement when an obstacle is hit. (The initial goal will be to just have one message, then the additional messages and randomization portion will be a stretch goal.)
Splash sounds for when the otter lands back in the water or jumps.The otter is no longer âjumpingâ as its movement, because it is now just swimming along this stretch goal no longer truly applies.- Small happy otter sounds for when the obstacle is successfully avoided for positive reinforcement.
Multiple otters randomized along the bank to wave or encourage the otter in the stream.Because this is no longer in p5.play the animation of the otter has become a struggle, so adding in new sprites that are animated is a bit beyond my skill level.- Random fish in the stream that can be caught by the otter for a snack. This will allow the user to occasionally return their number of lives to 3. [In Progress]
- A set of three lives for missing obstacles, which can be regenerated by fish snacks, the loss of all three lives will result in a more serious fail message and the game will reset.
- A way to track points for each obstacle successfully avoided.
- A way to enter initials for high score tracking.
- Rolling text on load to describe the otterâs story very briefly before moving to the game screen.
- A start screen with brief directions (e.g. click to start, click to jump) and a title splash screen.
- A pause button. (I have no idea how Iâd do this, but if I have time after the core of the project, this would be an interesting challenge.)
Stretch Goals (added along the way)
- Pause Screen
- GameOver Screen
- Animated Sprite
- UI Banner along bottom to display lives, score, and pause command.
- Animated river layer. (I found a multipack of images and because the layers were all separated I decided to try my hand at getting the river part to be animated!)
- Animate the cloud layer to move opposite of the river. [In Progress]
- Add a rectangle behind the collision messages. [In Progress]
- Change the colors of the different game state display screens.
Phase 1: Initial Setup
- Pulled the proper repo from GitHub including the HTML & JS structure – somehow this step got confused beyond recognition. I ended up with a repo from the original project back in the â22 undergrad iteration I took. Then, I ended up working on a branch of the project, then I ended up with an angry GitHub desktop app because there were mismatched files due to working on the messed up repo in multiple locations. Because of my struggle with the repo, I ended up with multiple .js files such as testing, testfile, notes, etc. which I was very happy to clean up after getting the repo sorted properly in the last couple of weeks.
- Loaded p5.js, p5.play, and p5.sound in the HTML file – this had to be edited to load these assets properly, and then re-done to remove p5.play when it became apparent that it wouldnât work for what I was doing and the best way forward was to continue in p5.js since Iâd already done so much work there. This prevented me from having to start all over in p5.play where I was struggling with the documentation to get things working.
- Set up a canvas dynamically based on the window size, although this does not resize as dynamically as I had hoped, it still loads the game perfectly in the initial window size.
- Preloaded assets (river backgrounds, otter sprite, log images)
- Defined key game variables (otter position, obstacles, river bounds, game states – isPaused, etc. which were later changed)
Phase 2: Basic Game Mechanics
- Implemented otter movement (WASD & arrow keys) This was much easier than I think it wouldâve ever been for me in the undergrad class. Because I am also taking a class on MAX with Professor Zaki, I was better able to understand the ascii nature of keyboard entry. This allowed me, also, a way to find the ascii number for the keys I wanted to clearly define, and that knowledge definitely helped me in this project as well.
- Created a scrolling river background (animated layer) This was an interesting thing to learn for me, because I was not sure how to âuse mathâ to make the layer move. Understanding that draw is repeating constantly helped me understand why we would subtract one over and over from the location of the image, and why adding one would have the exact opposite effect. This has led to the stretch goal of having the cloudy sky layer move the other direction as a way to challenge my grasp of the logic at play here.
- Set movement constraints so the otter stays within the river and that it doesnât stray outside of the area the obstacles spawn in and bypass the gameâs logic.
- Spawned obstacles (logs) at a fixed interval – the use of the random function allows for the logs to spawn anywhere within the proper bounding box for the river. This removes the userâs ability to remember a pattern of how the obstacles will come out, so they cannot simply train themselves on a pattern to get a higher score. As we see reflected in real life, things come at us at random and are never truly predictable.
- Made obstacles move leftward across the screen – thinking of how normal side-scrolling games work, I decided to use -1 for the movement of the river and obstacles, meaning they travel from the right of the screen to the left. This gives the illusion of the otter constantly moving to the right, which is an industry standard for which direction the player sprite should move in similar games.
- Added collision detection (originally using otterâs full image size 64×64, then changed to a hitbox which is a transparent rectangle that fits over the otterâs body) – This was a challenging goal for me because the otter image I found was originally animated. There was a lot of clear space above the otter in the image with the otter being only around half the height of the image. When I tried to resize the image it destroyed the size and made it fuzzy. Changing from using the image and all its transparencies for the hitbox was a game changer that allowed me to use the otter image without having to do a ton of guesswork about where those boundaries really even were within the game.
Phase 3: Debugging & Fixes
- Fixed river animation (ensuring correct scrolling behavior) This was so problematic for me at the start, because I didnât understand the math involved in the placement of the image. After our classes where we worked on the snowman and talked about the grid within the canvas it made much more sense.
- Resolved issue where obstacles werenât spawning – this was another annoying challenge for me that required a lot of iterative testing and pulling out of hair. Once I understood the mathematical side of the animation I was using it became much easier to add in the moving objects for the
- Fixed collision detection (implemented a smaller hitbox for the otter) – the otter was colliding with obstacles based on the total image size 64×64 without regard to the transparency. Once I removed the image as the definition of the hitbox and changed it to a rect object the issue with collision from objects way far above the otter stopped. This was step one of a long process that included using a semi-transparent rect to visualize the hitbox and then making the rect completely transparent to show the otter sprite in its place.
- Adjusted bounding boxes so obstacles could spawn lower – getting the river to be the right size was a lot of trial and error once I got it working properly. I had to go through several iterations of changing numbers for the width and height of the bounding boxes until I got them just where I wanted them. This allows for the otter to swim from the top of the river to the top of the trees and from the far left of the screen to the middle. It also keeps the spawning of the obstacles from going outside of that area, too, since those variables are all related. (riverTop, riverBottom, etc.)
- Debugged game restart issues – as I worked on stretch goals for this project, I ran into new and interesting problems to debug and fix. One of those issues was that I was using isPaused and gameOver in an if/else statement to define the gameOver parameters. Professor DuBoise suggested that I change this and make gameStates, which I did and it worked perfectly. Now, when the player reaches 0 lives the game state changes to 3 and the game over screen displays perfectly. This also resets the number of lives to 3 and the score to 0.
- Solved the problem where the game would restart with only 1 life – one of the issues I ran into while trying to make the game reset was that even though I had told it to set lives = 3, it was remaining at lives = 0, so each time an obstacle was hit it displayed the game over screen. This was because I had set the function for this in the global scope, so it was not altering the variable within the draw() function.
- Handled âobs is undefinedâ errors – this error was very frustrating, but it actually didnât take me long to fix. I was moving code from the very commented on sketch.js to a clean file while leaving the original code for Professor DuBose to look at. This (in my estimation, I have no proof) optimizes the code and makes it much cleaner. Because I intend to post this on my portfolio website, I wanted to ensure that I didnât leave all the debugging remnants and non-working code in the project.
- Fixed text rendering errors (e.g., missing arguments for text()) – during my trial and error of changing the size and color of text that was displayed on the screen I was getting errors about the way I was defining the text – e.g. using CENTER instead of CENTER, CENTER or Center, Center, etc. – and I had to read through the documentation over and over until I found the right combination for what I was trying to do. Luckily this helped me to better understand how the text() function works, so when I made my game over screen I didnât need to reference the documentation, and I was even able to properly use â${score}â in this message after setting up the banner along the bottom which shows both the score and â${lives}â which have to be inside of tick marks (tilde key) and not single quotes. (in Google docs this is changing the font to a green color and not displaying the tick marks `, so I added in the single quote for visual)
- Adjusted the otterâs hitbox to better match its sprite size – perhaps one of the more time consuming things I had to troubleshoot was the size of the hitbox that I used to replace the otter.png as the collision detection object. This seemed to take forever because I could not wrap my head around the way the math needed to look. I used ChatGPT to figure this part out, because I just kept confusing myself and making the image change sizes, or the box cover large portions of the screen. ChatGPT was able to help me figure out the right math to use to move the box in the proper direction, and I figured out the exact numbers needed which did not match the solution the AI gave me. In fact, the AI suggested for otterX to only divide by two, but I ended up also multiplying by 0.1 to move the rectangleâs location (width-wise) as well with a finer level of control similar to the suggested * 0.2 for the otterâs height.
ChatGPT Solutions:
Adjust for CenteringotterX + (otterWidth – hitboxWidth) / 2 â Centers the hitbox horizontallyotterY + (otterHeight – hitboxHeight) / 2 + hitboxHeight * 0.2 â Moves the hitbox slightly downward (Try adjusting hitboxHeight * 0.2 to fine-tune.)Next StepsTest it! See if the hitbox now correctly aligns with the otterâs actual mass.If it still needs adjustments:Move the hitbox further down â increase + hitboxHeight * 0.2Move the hitbox up slightly â decrease + hitboxHeight * 0.2Make it wider/thinner â adjust hitboxWidthMake it taller/shorter â adjust hitboxHeight |
My integrated solutions and comments:
// Draw Otter if (otterImage) image(otterImage, otterX, otterY, otterWidth, otterHeight); // DEBUG: Visualize the hitbox by making the box red and slightly transparent fill(255, 0, 0, 150) changed to 255, 0, 0, 0 after the proper location was defined. fill(255, 0, 0, 0); // Semi-transparent red — changed to fully transparent after troubleshooting. noStroke();rect( otterX + (otterWidth – hitboxWidth) / 2 – hitboxWidth * 0.1, // Center horizontally and move slightly to align. otterY + (otterHeight – hitboxHeight) / 2 + hitboxHeight * 0.6, // Move rect down to better align with otter png. hitboxWidth, hitboxHeight); |
Phase 4: UI Improvements
- Created a fade-in instruction screen at game start – instead of jumping straight from the instructions to the game there is a fade between them. This was purely aesthetic and to learn something new. I had a lot of fun learning how to do the fade effect, which was part of a conversation with Kayla and Zach during one of our workshop nights. [I donât believe this was a suggestion from either of them, more it was something one of us mentioned during a conversation that I believe was related to Kaylaâs project.]
- Added a proper pause screen (P key toggles pause) – set the p to change case so if someone accidentally hits the capslock key it will still pause the game when the p key is hit. After fighting so hard with getting text centered because I was not using the proper case, I was frustrated to say the least. I wanted to ensure that no one lost lives or possibly the game because they couldnât hit the pause button fast enough. The best way to ensure this was to make sure that the case of the P didnât matter, which I did by using key.toLowerCase() in the keyTyped function in the global scope.
- Implemented a Game Over screen with restart instructions – This was particularly difficult because I wanted to continue using the isPaused function that Iâd previously gotten to work. It was a difficult experience for me to get the paused screen working, so I assumed if I used isPaused to stop game logic and gameOver (using &&) it would display the game over screen. However, this didnât work even a little bit and Professor DuBose suggested creating game states numbered 0-3. This made the check much easier than attempting to reuse functions and variables in ways they werenât meant to be used. This finally got to the working state after doing the following:
- Refactored game logic using a gameState system:
- 0 = Instructions Screen
- 1 = Game Running
- 2 = Pause Screen
- 3 = Game Over Screen
- Base on Professor DuBoseâs suggestion, I made a gameState variable that switched specific screens on or off and started and stopped game logic.
- Ensured UI elements only show in the correct states – after changing the way the game handles gameStates, the entire UI banner at the bottom stopped showing up. I couldnât understand what Iâd done wrong here, so I fed the code to ChatGPT and it notified me that I was in the wrong scope for the banner to draw – I had thought that I had it in there properly, so I checked again with this suggestion from ChatGPT and I found that I had actually added in an extra } right bracket, which had ended the draw function prematurely and was leaving everything below it out in the global scope.
- Changed the background color of the pause screen to black for contrast, but I may end up changing it to the same darker purple of the instruction screen. In fact, Iâd like to change all the screens so they match in color and maybe even add an image behind the text, but those are stretch goals!
- Fixed missing bottom banner displaying score & lives – Once I integrated the gameStates I was able to define when I wanted things to show up and when they werenât necessary. For instance, the bottom banner thatâs active during game play doesnât need to show up on the instruction screen, pause screen, or the game over screen.
Phase 5: Refinements & Final Adjustments
- Balanced obstacle spawning (logs now spawn properly across the river height without leaving gaps for the otter to slip through!)
- Adjusted river height & movement limits to prevent unfair advantages like having the otter hide below the banner where the obstacles werenât spawning. Now, the otterâs bounding box stays well within the river so that it cannot be manipulated into false high scores.
- Ensured the otterâs hitbox moves properly with the sprite – there was a moment where the otter image was much larger than the hit box, and it seemed as if the hitbox kept shifting where it was when I resized the image. This was fixed by using photoshop to clip the transparent segment of the image. However, this didnât work because the hitbox wasnât the image at this point but the rect that was placed over the image of the otter.
- Finalized Game Over logic so it properly resets lives & score – by creating numbered game states I was able to fine tune the if/else statement at the bottom of the code, directing it to reset the number of lives and the score when the game over screen is triggered. This solved the issue of the game ending each time the otter collided after the first three lives were used.
- Fine-tuned pause mechanics to ensure smooth transitions, and considered a stretch goal to add a fade to the pause screen also.
- Optimized gameState switching so each screen flows correctly by allowing it to trigger on a click or a button press for the instruction screen and the game over screen; the pause screen remains triggered only by hitting the p button for each.
Optimized gameState switching
// Handle Keypressfunction keyTyped() { if (gameState === 0) { startFade = true; } else if (gameState === 1 && key.toLowerCase() === ‘p’) { gameState = 2; } else if (gameState === 2 && key.toLowerCase() === ‘p’) { gameState = 1; } else if (gameState === 3) { gameState = 0; lives = 3; // RESET LIVES on restart from gameOver score = 0; // RESET SCORE so it’s not carried over obstacles = []; // CLEAR OBSTACLES }} // Restart on Clickfunction mousePressed() { if (gameState === 3) { gameState = 0; // On gameOver, restart at the instruction screen. lives = 3; // RESET LIVES score = 0; // RESET SCORE obstacles = []; // CLEAR OBSTACLES } if (gameState === 0) gameState = 1; // From instruction screen, start game.} |
Future Stretch Goals (Backlogged)
- Adding collectible fish – this will be a way to keep the game going longer, but also will reward players for getting past many obstacles, and it will reduce the âpunishmentâ of losing a life for hitting an obstacle as they get better at navigating the game.
Replacing logs with actual log images(randomly chosen from a set)I was actually able to get this done in the few days I was writing up this README.- Adding sound effects & background music – actually hoping to get this done before I upload to my website, although I think this game is pretty amazing as it is because I know how hard I worked on it!
- Further UI polishing (animated buttons, transitions, etc.) – For players who are on mobile, I feel like it would be nice if they could click on a button to change game states, because Iâm not sure how mobile handles the ascii side of keyboard inputs.
- Fix the window dynamic resizing so that it resizes with each window size change and doesnât simply start with the window-based size and remain that same size. (I love that it resizes based on the browser/window being used, but I really want it to dynamically resize if the window changes during gameplay!)
- Animate the otter sprite using the otter_swim images instead of using just the first one.
Questions:
Pick a single comment that you wrote, and describe why it is a good comment.
- // let purple = frameColor — this was to fix an error stating “purple” was not defined, realized I forgot to enclose the color name in backticks.
This comment was one of the most helpful ones I made, along with other examples of this same technique that are still present in the sketch-old.js file. I used comments to keep certain fragments of code within the larger file to show myself where I had been working on troubleshooting, what code I had used exactly, and why it had been commented out later. This helped me use multiple iterations of troubleshooting steps without losing the process steps used and what their results were. For instance, here, I had been getting an error that the variable âpurpleâ was not defined. I tried to troubleshoot this by adding a variable named purple that would equal the variable I was trying to assign that color to. This, obviously, did not work because purple still did not have a hex code assigned to it within my code. After this step, I looked into the use of color in text, backgrounds, and fills and noticed that in those places a box appeared next to the color that contained the color. This was because the item was contained within tick marks (tilde key) which pointed to the object within the p5.js code itself. When I commented this false fix out, I left it visible as a reminder to myself why that color word had not been picked up by the code properly in case I made a similar mistake later. As I have gone through many iterations of the code, I left fragments like this in my working versions – although some of them are lost to incorrect repos due to my confusion with how the repos were named and the previous portrait project I had from the creative coding 22 class from undergrad.
let riverTop, riverBottom, riverLeft, riverRight;
let logImages = []; // Array to store log images
let obs;
//Otter Vars
let otterX, otterY;
let otterSpeed = 5;
let otterScale = 1.5;
let otterWidth = 32 * otterScale;
let otterHeight = 32 * otterScale;
let otterImage ;
let rectWidth = otterWidth / 1.8; // Use the same scaled width as the otter
let rectHeight = otterHeight / 3; // Use the same scaled height as the otter
let hitboxWidth = otterWidth * 0.6; // Reduce width to % of image width
let hitboxHeight = otterHeight * 0.2; // Reduce height to % of image height
//Collision Vars
let hitMessage = “”; // Stores the current hit message
let messageTimer = 0; // Timer for displaying messages
Another important use of comments within my code comes from clarifying the variables so I could easily find them for troubleshooting purposes, and to help me remember what they were for since coding is not a normal thing for me to engage in. These comments told me exactly what the variables were doing so I could pinpoint where they were needed and why. Breaking the variables into different segments with blank lines also helped me to sort through them quickly when looking for a specific item. For instance, with the rectWidth and otterWidth being the same it allowed me a way to resize the otter image and the hitbox that I laid over it with a single equation. This may not have been the easiest or cleanest way to achieve this result, but it is one that I understood and was able to integrate into my own organizational structure for clarity.
How does your code illustrate or exemplify the concepts or arguments put forward in one of the readings?
One of the things I feel was important in the reading of âIntroductionâ by Marino from the week 3 readings was that there has to be a level of critical thinking when reading through code, especially if it is written by someone else and well above our own grasp of coding. In this reading, people tore apart code and said it was proof of climate change being manipulated and falsified because they had no context for the comments that were within the code. Similarly, if someone read through my code with no context, they may have been confused by why there were entire bits of code that had been commented out and re-written. If they didnât understand how the code ignores lines with // at the start, they might have thought my code was very repetitive. However, as the coder, I knew that those iterations were previous tries to get a solution to prevent me from trying those same solutions over again. This was an important part of my coding journey because without those things, and with my limited knowledge of coding, I might have gotten caught in a loop of trying the same 2-3 solutions over and over again without the results changing, which would have driven me crazy. This is something I saw in my undergrad time in creative coding – when something wasnât working, I just simply deleted it. I wonder now if I had used comments to leave the erroneous code in place and just found different approaches to it if I could have gotten further along with the experience I had hoped to shape for users with that code.
This article helped me to see that commenting can be a powerful tool to keep some fragments of code around while working through iterations to address problems that spring up within the code. This use of commenting helped them address an inconsistency in the data they had while not being sure where the issue that was causing the error was coming from. It also communicated that it was a âfudge factorâ or in my mind a temporary fix to their program that would be later removed when the error was found.
So, in looking back on this reading, and the way I used comments within my own code multiple times, I can understand where there must be context when looking at someone elseâs code. This was further driven home by my workshop time with other students who were not using comments as frequently as I was. When I asked them why they had used a certain function, they would often have no answer. This meant they were trying to reinvent the wheel over and over again, because they were not clear about the processes they were using. While working with Kayla I found she was often very frustrated by the many things she had tried in her code. However, she was just deleting things that didnât work and moving on. In her busy life between work, multiple classes, and trying multiple solutions it is not surprising that she could get lost in the weeds of coding. This is something that happens with professional coders as well, because they can easily lose their train of thought when taking a break (even overnight) from the coding work and doing something else. Commenting is a tool that keeps us communicating with ourselves and our collaborators (when we have them) so that solutions can be tried and documented instead of tried multiple times because we forgot we tried them at all.
Looking back at a more recent reading, I can see the five levels from the Monfort Bogost âAfterwordâ piece at work here; and most of it was without consideration for the article since I conceptualized and proposed this project long before we got to this reading. One of the things I was very deeply caught up in with this project was consideration for the user – I didnât want a normal smash and grab game filled with violence; this is about an otter overcoming obstacles in life. The use of the term âlivesâ is only in reference to an industry standard, because I donât want the otter losing to be a âdeathâ which has very negative connotations. There is definitely a nod towards reception aesthetics at play here, even in the comforting âfailâ messages that I constructed to pop up when the player collides with a log.
The use of a pause button, a button push to start the game, the display banner, and the different game state screens all speak to interface; interactive pieces to the user interface that manage and guide the player and their interactions with the game.
To speak to the third item on their list, function or form, I would say that I took part in this a great deal through defining the boundaries of the river, otter, and obstacles as well as defining the collisions and non-collisions to either remove a life or add a score amount. I worked with âfunctionsâ to develop and sculpt the function of this game.
Moving on to the fourth and fifth subjects: code and platform, I feel like there was a great deal of interaction here as I literally worked with code to produce a game; but also thinking about platforms and the many forms and iterations they are I was working within a very complex scaffolding of platforms. This, I think, is a cornerstone of what platform studies is – especially when I zoom out and look at the fact that I worked on this on a Windows desktop PC, a Mac laptop, and I used my Android phone to try running the program as well â which to be clear, didnât work well, and is why I have a stretch goal to make it mobile friendly – but this is all tied into what a platform is and what it means to work within one. Not only is the physical system a platform, but also the Visual Studio Code program, the GitHub website and app that allow for (mostly) seamless transfer of the code from one system to another, the browsers used to display the code, the Live Server that allowed the code to run from the computer, the many intricate workings of the internet that allowed for research â this project was supported by all of these platforms and more. I would argue to a point that the framework of my social network and our use of the discord chat platform were also involved, as I vented to my best friend over that chat program multiple times about how hard this was and how I would never be able to get the game running.
Conceptually, I understood before starting this project that platforms were everywhere and could take on a multitude of different âskinsâ in the real world. In thinking of my other research, such as the payphone project, platforms and infrastructure define every aspect of human life; even if we donât acknowledge that ourselves. There is no service that we rely on for our lives that doesnât find ways to tie into what a platform is or could be; and I think the definition of it being programmable only helps us to pull back from this abyss of wonder at what a platform could be in this world.
Infrastructure is the delivery method that we hang our platforms on; but this is not mutually exclusive, because a platform can also be part of the infrastructure, depending on the context. Many social media sites tout their status as a platform, and while this is likely to prevent the legal trappings of being held responsible for what people say on their site, it also points to the fact that without the infrastructure of the internet we could not have these platforms. But, without the infrastructure of the power grid, we could not have the internet. While many opinions have been shared and evaluated to define exactly what a platform is, I feel like this project had opened my eyes even more to what a platform could be and has definitely given me some interesting ideas for projects in other areas of my life.
Acknowledgements
There are so many acknowledgements to put in here, Iâm definitely going to have a struggle to get them all in.
- âAnimationâ of objects –
- https://p5js.org/tutorials/animating-with-media-objects/
- This is the snippet from the tutorial that helped the most:
- This is basically the code I used to make the river2 image animated versus the other layers which were static:
- I bracketed the animation inside of an if/else statement to make the game âpauseâ or stop animating the river2 image if the game was set to the isPaused state, which changed in my final iteration when I used gameState to determine the play/pause features.
- I also used this same idea when I was âanimatingâ the alphaFade of the instruction screen, because I wanted the transparency of the menu page to slowly âmoveâ from solid to transparent.
- Collision Detection – https://happycoding.io/tutorials/processing/collision-detection
- This was one of the sites that I went to when I was trying to figure out how to do collision detection. I needed this function in my code to determine when the otter would lose one of its lives.
- While I did start with the collision detection in p5.js documentation, all I could get from it was how to change colors of the objects when they were found to be overlapping, and their example was for circles, so the only way I could get this to trip was to change the r variable. There was no movement here, so I had to go back to the drawing board and search for other help.
- // Collision detection system
- function collides(x1, y1, w1, h1, x2, y2, w2, h2) {
- return (
- x1 < x2 + w2 &&
- x1 + w1 > x2 &&
- y1 < y2 + h2 &&
- y1 + h1 > y2
- );
- This is the math section that determines what boolean value to send to the collides if/else statement. For each check that is done it will then go through:
- This was one of the most complicated things for me, because it took me some time to understand that I wasnât looking at the x, y value of each corner. Weâre looking at the x, y of the top left corner, and the code determines the other 3 corners based on the w and h of the object in question. (Or, with a circle, which didnât make sense at first, it is looking for the radius from the point the circle originates.) So, there are two objects to be determined here, which is why we have x1 y1 w1 h1 and x2 y2 w2 h2. In my code these turned into otterX otterY otterWidth and otterHeight for the otter rectangle hitbox and the obs.x obs.y obs.width and obs.height for the obstacles.
- I was still having some struggles with conceptualizing the way rectangles were formed within the p5.js, so as I mentioned in the Phase 3 section, I asked ChatGPT for help with how to position the rect so it overlapped the image of the otter and became the same size as it to ensure the hitbox was as accurate as possible for someone of my skill level. In spite of the help given by the AI, there was still a lot of alteration done after that point, but that was where the answer came from.
- Use of the return command inside the if function for updateObstacles() was another item that I found on the internet; I believe it was from a javascript forum. Basically, this was used to end the function since the function is within a loop. [draw()].
- Based on my research, this or noLoop() would have worked, and noLoop() looks like it may be the p5.js native answer to the problem of stopping the object updates if the âisPausedâ state is true. I decided to stick with using return here because when I did noLoop() it broke the game, which may have been because I was still loading the p5.play library in the html file, and we determined that I was causing a wealth of problems for myself trying to crush these two things together.
- Displaying Variables on a banner-
- One of the things I really wanted to challenge myself to do was have a score that went up by ten points for every obstacle that was avoided. But, I had no idea how to display a variable in p5.js, and so I had a banner that I drew at the bottom of the screen as just a basic rect(), using a variable for bannerHeight so I could easily manipulate it without digging through the code to find the right location for it. [Iâve since found the search function is pretty helpful here, but on the Mac it kept just searching the files instead of searching in the one file, so I got kinda salty with the whole thing and just made a lot of variables so I could edit them from the top of the code.] The answer from my Google search ended up being an âAI resultâ – but it gave me the answer I needed, which was that using ${varName} would display the variable, which I then used to populate the information on the bottom banner.
- There were several instances where I simply didnât know how to do something, and I asked ChatGPT to point me in the right direction. This didnât result in the copying of code, but it did lead me to a function, command, or idea that I donât think I wouldâve come up with on my own. I knew what I wanted to do, and I was able to easily describe it, but I didnât always know how to translate that into code. I wish I had kept better track of this, because now I feel like it will be âsuper obviousâ that I used it, but forgot to mention it, and it will seem like I was cheating. [Brain weasels, I know, but there you have it. Iâve been informed this is paranoia talking and that Iâve obviously put in the work and shouldnât be worried about it.]
- The Obvious Help from AI:
- RGB color codes.
- I asked ChatGPT for color codes and it provided pretty close to what I wanted. I found this much easier than scouring the internet or scrolling through colors.
- ChatGPT also helped identify complementary color choices, which I pretty much ignored completely; although if I were to redo the color scheme like I thought about, I might add in sage green and maybe a similar navy color to tie them all together coherently.
- The wording for the reassuring messages.
- I had a lot of ideas for what I wanted to say, but they all sounded really contrived and lame. I asked ChatGPT to help me think up more messages.
- âOof! Keep swimming, little otter!â and âOh no! You hit an obstacle!â were the two I personally wrote here, and out of a really long list I picked the other 4. One started as âThat rock came out of nowhere!â but has been changed to âThat logâ since all the images I used for the obstacles were logs and I didnât know how to determine if it was a log or rock based on random image selection, so I didnât add in the rocks. (They donât float really anyways, so probably not the best idea Iâve ever had to include them.)
- Troubleshooting code
- There were many instances where I needed to troubleshoot what was or wasnât working and how to fix it. ChatGPT helped in this situation by giving me ideas on what code to insert to do the troubleshooting. For instance, when I was attempting to use multiple frames of the otter to animate the little dude while he was swimming, I couldnât get the stupid images to load right. I finally gave up on this and made it into a stretch goal. The issue I had here was that I was so hyper focused on fixing this that I was spending too long working on a fix and no time on development other places.
- This is the function that ChatGPT offered, and while it did seem to work in that it would print to the console, there wasnât an else to log if the items had not loaded; so I ended up with half a solution here as to why the otter wasnât showing up at all. I did end up adding an else { console.log(âThe otter isnât ready yet!â); but it just kept sending the else and then the if and nothing was actually showing up – later, I found that I had forgotten to close one of the functions that had a return in it – this had caused the loop to just stop, which made everything stop working. Brackets are pretty sneaky.
- One of the main reasons that I had added key.toLowerCase to the project was because I had accidentally hit capslock and the p button wasnât causing the pause function to work. ChatGPT suggested using the toLowerCase function, and I had recalled we used something similar in the CodeCademy lessons to make change the case of the letters we entered. (If I recall correctly, we learned it to make name in all lowercase after entering the variable as all capital letters?) At any rate, I knew how to do this, I just hadnât thought of it – and then using the MAX program I was able to suss out the ASCii code for both P and p to add into the keyTyped function.
- While you canât really trust ChatGPT completely, there were two times when I uploaded my entire code to the AI to see if it could figure out why the whole game wasnât working, because itâs super frustrating to change one tiny thing and then have the whole code break. Unfortunately, ChatGPT hallucinates a whole lot when working with code, and as someone who doesnât know code very well, I found it very unhelpful in these situations. One of the issues I had frequently when asking ChatGPT for help was that it was reverting everything to javascript, moving everything into the global scope so it wasnât looping with draw, and for some reason changing the name of variables to random things that angered my sense of organization.
- RGB color codes.
- The Obvious Help from AI:
- One of the biggest helps that I received was from Professor DuBose – especially in the matter of gameStates and how to have multiple screen changes that would make the game pause, but without using the same isPaused variable, which was probably why my gameOver screen wouldnât work. I was terrified to make this change, because in my mind I was thinking over all the places I would have to go in and change if/else statements, all the things impacted by the isPaused state, and what changing them there might look like. However, I decided I wanted the gameOver screen enough that it was worth the effort. This resulted in around 4 hours of work today (20 March) to overhaul the code, add in the gameStates, and change many of the functions.
- 0 = start
- 1 = playing
- 2 = paused
- 3 = game over
- After changing adding in these game states, however, I found it was pretty easy to alter the functions (especially because they were well commented and I used variables that were descriptive, as we spoke about earlier this semester), and even to add the keyPressed and mousePressed functions to all of those different screens. mousePressed() now turns off the instructions as well as restarting the game from gameOver. keyPressed() now changes all of the game states, except the pause one is p/P only. Adding those additional else statements into these functions was quick, easy, and really brought the quality of my program up several notches. Having an easy way to bundle everything together since the gameStates were all different variations of the same variable also reduced the amount of code needed and it gave me the freedom to explore how to use keyPressed and mousePressed in different ways for different game states:
- This has given me some motivation to try adding in some sounds, which I helped Kayla with a little, so I know that I would need to preload() the sound before calling it â but, Iâm very excited to try adding this in to the live version of the code, as well as music that would start as part of the change between gameStates. So, all of that needs to be attributed to Professor DuBose as well, because his help with the game states definitely changed how things were working for me.
- Finally, I need to leave some sort of acknowledgement for my bestie, Chris Rocha, who is a serial coder and works with Very Important Systems at Oracle. While he didnât actually give me any code, he did give me some tough love that resulted in me pushing myself harder this semester than I did previously. His encouragement to try more things, break stuff, and learn how to fix it from the inside has definitely changed how I approach coding. Okay, maybe he didnât give me any code, but honestly without him Iâd probably be doing something just as simple and asinine as I tried and failed to do in undergrad, because I had no motivation to break things, no permission to not be perfect. But, Iâve realized this semester that breaking things is kind of what coders do – and they keep breaking things in new and interesting ways until eventually the whole thing just works and itâs magical. Iâve felt that magical high when I got everything working togetherâ even if I almost immediately broke it again trying to do something else weird and new. Those experiences piled up one on top of another until here I am with hundreds of lines of code under my belt and a fully functioning game that I built by myself. Thatâs kind of worth all the chaos and time I poured into this.