diff --git a/README.md b/README.md index 317a3e58..b7d32002 100644 --- a/README.md +++ b/README.md @@ -1,96 +1,119 @@ -# Project Name (Start editing here) +# On The Other Side # ![](https://ga-dash.s3.amazonaws.com/production/assets/logo-9f88ae6c9c3871690e33280fcf557f33.png) Project #1: The Game +### Introduction +[On The Other Side](https://imjustlooking.github.io/project-1/) is a platform puzzle game in which the player guides two balls into their respective 'goals'. + +I created this game over a course of 6 days as part of our WDI-12 batch's first project assignment at General Assembly. + +This idea came about initially as a backup plan. I was considering if my coding-beginner skills were robust enough to create something more demanding, like a resources-based survival game. The concept felt like a relatively achievable project which I could manage, and, while it was, it was also quite a satisfying run. ### Overview +This game operates in two dimensions which reflect each other in certain ways. You control the ball on the left, and **on the other side**, its ball moves in the opposite direction. Blue moves left, Red moves right. -Let's start out with something fun - **a game!** +![](/assets/img/ballmovedemo.gif) -Everyone will get a chance to **be creative**, and work through some really **tough programming challenges** – since you've already gotten your feet wet with Tic Tac Toe, it's up to you to come up with a fun and interesting game to build. +However, the terrain **on the other side** isn't always the same. -**You will be working individually for this project**, but we'll be guiding you along the process and helping as you go. Show us what you've got! +To pass each level, the player has to move **both balls** into their respective holes. +![](/assets/img/ballGoalDemo.gif) ---- +If the balls fall beyond the playing field, they can click the reset button below the panel. -### Technical Requirements +Upon clearing each level, a button appears and allows the player to proceed after clicking. -Your app must: + -* **Render a game in the browser** -* **Any number of players** will be okay, switch turns will be great -* **Design logic for winning** & **visually display which player won** -* **Include separate HTML / CSS / JavaScript files** -* Stick with **KISS (Keep It Simple Stupid)** and **DRY (Don't Repeat Yourself)** principles -* Use **Javascript** for **DOM manipulation**, jQuery is not compulsory -* **Deploy your game online**, where the rest of the world can access it -* Use **semantic markup** for HTML and CSS (adhere to best practices) -* **No canvas** project will be accepted, only HTML5 + CSS3 + JS please +### Basic flow ---- +Basic flow chart which outlines the game mechanics +# ![](/assets/img/ontheothersidev1.jpg) -### Necessary Deliverables +Tried to do another flow chart below, which was still quite basic, additional features were added subsequently. +# +![](/assets/img/flowchart.jpg) -* A **working game, built by you**, hosted somewhere on the internet -* A **link to your hosted working game** in the URL section of your GitHub repo -* A **git repository hosted on GitHub**, with a link to your hosted game, and frequent commits dating back to the very beginning of the project -* **A ``readme.md`` file** with explanations of the technologies used, the approach taken, installation instructions, unsolved problems, etc. --- +### Thoughts and progress -### Suggested Ways to Get Started +I did not track my progress rigorously, but had been committing and pushing major changes onto git hub. Here, I look through the update logs, and try to reconcile each day's efforts and (many) frustrations. -* **Break the project down into different components** (data, presentation, views, style, DOM manipulation) and brainstorm each component individually. Use whiteboards! -* **Use your Development Tools** (console.log, inspector, alert statements, etc) to debug and solve problems -* Work through the lessons in class & ask questions when you need to! Think about adding relevant code to your game each night, instead of, you know... _procrastinating_. -* **Commit early, commit often.** Don’t be afraid to break something because you can always go back in time to a previous version. -* **Consult documentation resources** (MDN, jQuery, etc.) at home to better understand what you’ll be getting into. -* **Don’t be afraid to write code that you know you will have to remove later.** Create temporary elements (buttons, links, etc) that trigger events if real data is not available. For example, if you’re trying to figure out how to change some text when the game is over but you haven’t solved the win/lose game logic, you can create a button to simulate that until then. +Firstly, as far as the game overview is concerned, the game's logic works similarly to my vision (though improvements can always be implemented). However, there was a piece of the initial idea which I had scrapped: +###### *"There is a special skill the player can use, align, which lets both balls move in the same direction for a few seconds. Click 'button' to activate this each level."* ---- +I didn't pursue this eventually due to time restrictions and the tedious nature of my level set-ups. -### Potential Project Ideas +#### Let's quickly get into the timeline: -##### Blackjack -Make a one player game where people down on their luck can lose all their money by guessing which card the computer will deal next! +**Day 0, Friday:** +Idea proposal to instructor Primaulia. +Scrappy flowchart planning (refer to pictures above), readme writeup of game description, ~~no real~~ zero coding done -##### Self-scoring Trivia -Test your wits & knowledge with whatever-the-heck you know about (so you can actually win). Guess answers, have the computer tell you how right you are! +**Day 1, Saturday:** +Coding begins. Created the playing field, added the balls and movement logic upon user-input keystrokes. Added functions to rectify the ball movement exceeding the border ---- +Quite an encouraging start. -### Useful Resources +**Day 2, Sunday:** +I remember giving the project lower emphasis after being particularly productive the previous day. I played PUBG, it's a good game, and I hadn't played at all since the course began. -* **[MDN Javascript Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript)** _(a great reference for all things Vanilla Javascript)_ -* **[jQuery Docs](http://api.jquery.com)** _(if you're using jQuery)_ -* **[GitHub Pages](https://pages.github.com)** _(for hosting your game)_ -* **[How to write readme - Markdown CheatSheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet)** _(for editing this readme)_ -* **[How to write a good readme for github repo!](https://gist.github.com/PurpleBooth/109311bb0361f32d87a2)** _(to make it better)_ +Since Monday approaches, at night I added winning conditions and logic. Integrated into ball movement. ---- +**Day 3, Monday:** +Thought about the game flow, and it seemed quite daunting while coding the basics previously. + +*Referred to one physics formula to add gravity to the game: (displacement = 0.5 * gravitational acceleration * time(Squared))* + +Quite pleasant that it works realistically. I still am at time of writing. However, the system was still far from completion compared to my peers and I was annoyed at my pace. + +Also added a jump feature which ties into gravity. + +**Day 4,5 Monday,Tuesday:** +Project low point. + +The gravity feature works based on a high frequency setInterval, in order to smoothen the ball drop. It also means it's possible to slip through the platforms. I created the platforms (vertical obstacles) in between day 3 and 4, but didn't log the comments. + +Asked TA's for help, got some recommendations. Wasn't really what I was looking for, and my code might have been too smelly. It seems there is a stopping distance even though the console log registers triggers. Managed to find a solution to fix the ball position as well as allocate an allowance. Also increased frequency of gravity(). More stable chances of ball not slipping through. (still occurs occasionally now) + +Time is short, so once I got gravity to work more reliably, started to set up a demo level. Anyway, was about to throw in the towel and create another game, when I realized after some google-fu that we can adjust CSS properties such that removed elements do not leave any 'pixel placement scrambling effects'. position: absolute was a lifesaver and morale booster. I had ALSO created walls (horizontal obstacles), which I will find on the next day to be ridiculously bugged. + +**Day 6 Wednesday:** +Yesterday. The wall additions allow for some horizontal super mario meets pipe interaction. +# ![](/assets/img/mariopipe.gif) + +Except this happens horizontally, and my ball doesn't require an opening to pass through.Horrible and also funny, more horrible though. I should have recorded a gif but I wasn't thinking about documenting it. + + Spent 3-4 hours improving the collision detection models. I have also been questioned many times on why I have separate collision models set up for the left and the right side of each Wall. It's because the inequalities to check the pixel position will spill over and cause super mario ball to happen. Anyway, I fixed it for most of the part, though the ball still floats through occasionally, even now. We can thicken the Wall or make the ball land first though. + + I also went home and added a few levels. Level set up is a tedious process, trying to balance making the game slightly challenging and rewarding as much as I could. Lots of trial and error while inputting the pixel positioning. I had used constructors for the platform and Walls. Added some button functionalities to proceed to next level etc. One of the biggest improvements to my workflow was adding a skip button because I had to keep beating each level to see how the level layout would be like. I left the skip button in the game for frustrated players and also presentations. + + **Day 7 Thursday, today, 5th Sept:** + + Soft launch day. Game looks decent to me, had a few coursemates who tried it and seemed to like it a bit. Added some really basic CSS colors. Also put in more immersement such as sounds, as well as auxiliary features to toggle sounds. Included hotkeys for buttons so user can do away with the hassle of moving the mouse every few seconds to click. + + I'm an hour and thirty minutes away from the code freeze. While I feel the mechanics were quite a headache to implement, ultimately I'm happy to have chosen this project. This was what I signed up for, to learn and apply. It really let me connect the dots in a way that only I was responsible for, and I'm pleased at the outcome, though it's not that visually pleasing. Thank you for reading this portion, I hope you too have had experienced that satisfaction before. -### Project Feedback + Evaluation +### Improvements to be made +**Walls:** I had tried to apply a for loop on Walls to make multiple horizontal obstacles. However, it seemed it did not work on multiple Walls beyond the first. Troubleshooting it didn't really work either. In the end, I opted to work with this restriction and include just one wall in each level set up. -* __Project Workflow__: Did you complete the user stories, wireframes, task tracking, and/or ERDs, as specified above? Did you use source control as expected for the phase of the program you’re in (detailed above)? +**Level setup:** Honestly the levels could be improved much more, but most of my project time was allocated to fine tuning the mechanics. The placement of the platforms and walls can be adjusted further to give the player a more rewarding gameplay experience, e.g. more required use of asymmetric movements between the balls. -* __Technical Requirements__: Did you deliver a project that met all the technical requirements? Given what the class has covered so far, did you build something that was reasonably complex? +**CSS:** Not the most enticing game to play at first glance. My h1 element has some whitespace which I unsuccessfully tried to remove. (but that's not the main point) I did try to make the display as simple as possible, summarize the instructions etc. Also, improve the 'juiciness' of the game such as bounciness of the platforms upon landing. -* __Creativity__: Did you add a personal spin or creative element into your project submission? Did you deliver something of value to the end user (not just a login button and an index page)? +**Smelly code:** +I believe there are ways to be more efficient at coding, like reducing how many times an instance appears. DRY and KISS: I'm still learning! -* __Code Quality__: Did you follow code style guidance and best practices covered in class, such as spacing, modularity, and semantic naming? Did you comment your code as your instructors have in class? -* __Deployment__: Did you deploy your application to a public url using GitHub Pages? +### References +Not much here, unless online resources such as stack overflow, MDN, are to be counted, then I'd have a long list. -* __Total__: Your instructors will give you a total score on your project between: +I used free sound files via [freesound.org](http://freesound.org) which I linked the author's profiles to at the bottom of my game. - Score | Expectations - ----- | ------------ - **0** | _Incomplete._ - **1** | _Does not meet expectations._ - **2** | _Meets expectations, good job!_ - **3** | _Exceeds expectations, you wonderful creature, you!_ +I also used wikipedia for the gravity formula, but it seems the page no longer looks the same, or I can't find it. But [here's](http://www.school-for-champions.com/science/gravity_equations_falling_displacement.htm#.WdXiRROCzVo) another resource you can use to see the gravity displacement. - This will serve as a helpful overall gauge of whether you met the project goals, but __the more important scores are the individual ones__ above, which can help you identify where to focus your efforts for the next project! +# ![](/assets/img/gravityformula.png) diff --git a/assets/css/stylesheet.css b/assets/css/stylesheet.css index e69de29b..59bcfe9c 100644 --- a/assets/css/stylesheet.css +++ b/assets/css/stylesheet.css @@ -0,0 +1,86 @@ +.container { + margin: 0 auto; + text-align: center; +} + +body { + background: #ffcdd2; + background-size: cover; +} +h1,h2 {text-align: center} +h1,h2 {font-family: 'Libre Baskerville', serif;} +/*h1 {background-color: #083D77; + padding: 10px; + width: 100%; + height: 50px; + margin: 0; + color: #EBEBD3; + text-align: center; +}*/ +p { text-align: center} +.half { + width: 300px; + height: 200px; + border: 1px solid black; + background-color: white; + position: relative; + display: inline-block; +} + +ul{color: grey} +li {display: inline} +a {text-decoration: none; +color:grey } +.start, .skip {display: block; + margin: 0 auto} + +.start {background-color: #e55b77} +.start:hover {background-color: #eb3d72} + +#ball1 { + background-image: radial-gradient(ellipse farthest-corner at 30px 45px , #00FFFF 0%, rgba(0, 0, 255, 0) 50%, #0000FF 95%); + top: 30px; + left: 255px; +} + +#ball2 { + background-image: radial-gradient(ellipse farthest-corner at -30px 45px , #ffb6c1 0%, rgba(0, 255, 0, 0) 50%, #ff0000 95%); + top: 30px; + left: 30px; +} + +#clear { + clear: both; +} + +.balls { + border-radius: 99px; + position: relative; + width: 15px; + height: 15px; + display: inline-block; + float: left; + margin: 0; + transition: all 0.5s ease-out; +} + +.nextLevel {background-color: #4CAF50} +.nextLevel:hover {background-color: #46a049} + +.fade {background-color: #BEBEBE} +.play {background-color: #E0E0E0} +.reset {background-color: #2196F3; +margin: 0 auto; +display: block} +.mute {display: block;} +.reset:hover {background: #0b7dda} + +.goalBorder { + border: 2px solid #9ecaed; + border-radius: 7px; +} + +.platformBorder { + border-top: medium thick green; + border-radius: 3px; +} diff --git a/assets/img/ballGoalDemo.gif b/assets/img/ballGoalDemo.gif new file mode 100644 index 00000000..136a106a Binary files /dev/null and b/assets/img/ballGoalDemo.gif differ diff --git a/assets/img/ballmovedemo.gif b/assets/img/ballmovedemo.gif new file mode 100644 index 00000000..a719a0b2 Binary files /dev/null and b/assets/img/ballmovedemo.gif differ diff --git a/assets/img/flowchart.jpg b/assets/img/flowchart.jpg new file mode 100644 index 00000000..0f2743c3 Binary files /dev/null and b/assets/img/flowchart.jpg differ diff --git a/assets/img/gravityformula.png b/assets/img/gravityformula.png new file mode 100644 index 00000000..d1f58ae5 Binary files /dev/null and b/assets/img/gravityformula.png differ diff --git a/assets/img/mariopipe.gif b/assets/img/mariopipe.gif new file mode 100644 index 00000000..23f1801b Binary files /dev/null and b/assets/img/mariopipe.gif differ diff --git a/assets/img/ontheothersidev1.jpg b/assets/img/ontheothersidev1.jpg new file mode 100644 index 00000000..721358ec Binary files /dev/null and b/assets/img/ontheothersidev1.jpg differ diff --git a/assets/js/script.js b/assets/js/script.js index e69de29b..a6376749 100644 --- a/assets/js/script.js +++ b/assets/js/script.js @@ -0,0 +1,548 @@ +var $ball1 = $('#ball1') +var $ball2 = $('#ball2') +var $body = $('body') +var goalLevel = 1 // to assign goal Id's for each play field +var gravity = 50 // gravity multiplier +var platformNo = 1 // to assign platform Id's +var gLock = false // toggle for gravity +var allowance = 1 // to accomodate for gravity stopping distance, i.e. hover value +var jumpLimit = true // switch for jump +var start1 = [] // indicates ball1 starting position, index position increases with level +var start2 = [] +var currentLevel +var lose = new Audio('assets/sounds/lose.wav') +var loseCheck = false +var jumpSound = new Audio('assets/sounds/jump.wav') +var muteSwitch = true // mute switch +var muteBeep = new Audio('assets/sounds/beep.wav') +var switchPress = new Audio('assets/sounds/switchpress.wav') + +$(function () { + $('body').on('keydown', startClick) + function startClick (e) { if (e.keyCode === 32) $('.start').click() } + + $('.start').on('click', () => { + $('.start').remove() + $('h2').remove() + $('.half').removeClass('fade') // .fade greys out background when play (.play) is off + $('.half').addClass('play') + $body.on('keydown', ballMove) + function ballMove (e) { + var unit = 20 // 20 + if (e.key === 'd' || e.key === 'D' || e.key === 'ArrowRight') { + if (ball1Goal() === false && (borderCheck1Right()) && (wallCheck1Right()) && (!$('.fade').length)) ball1Hori(unit) // if ball1 doesn't exceed right border + if (ball2Goal() === false && (borderCheck2Left()) && (wallCheck2Left()) && (!$('.fade').length)) ball2Hori(unit) // opposite side for ball2 + } + if (e.key === 'a' || e.key === 'A' || e.key === 'ArrowLeft') { + if (ball1Goal() === false && (borderCheck1Left()) && (wallCheck1Left()) && (!$('.fade').length)) ball1Hori(-unit) + if (ball2Goal() === false && (borderCheck2Right()) && (wallCheck2Right()) && (!$('.fade').length)) ball2Hori(-unit) + } + if (e.key === 'w' || e.key === 'W' || e.key === 'ArrowUp') { + if (jumpLimit) { + if (!ball1Goal()) ball1Jump() + if (!ball2Goal()) ball2Jump() + } + } + if (e.key === 'r' || e.key === 'R') { + resetLevel() + } + if (e.key === 'n' || e.key === 'N') { + $('.nextLevel').click() + } + if (e.key === 'm' || e.key === 'M') { + $('.mute').click() + } + } + level1() + setInterval(ballSnap, 500) // checking if border exceeds + setInterval(gravity1, 30) + setInterval(gravity2, 30) + $('.reset').on('click', resetLevel) + $('.skip').on('click', skipLevel) + $('.mute').on('click', toggleSound) + checkClear = setInterval(levelClear, 500) + }) +}) + +// this controls horizontal ball movement +function ball1Hori (a) { + document.getElementById('ball1').style.left = (Number($ball1.css('left').replace('px', '')) + a).toString() + 'px' +} +function ball2Hori (a) { + document.getElementById('ball2').style.left = (Number($ball2.css('left').replace('px', '')) - a).toString() + 'px' +} + +// these are checks on the game border to see if hori movement can proceed +function borderCheck1Right () { + if (Number($ball1.css('left').replace('px', '')) < $('.half').width() - $ball1.width()) { + return true // condition to keep ball1 within right border + } else return false +} +function borderCheck2Right () { + if (Number($ball2.css('left').replace('px', '')) < $('.half').width() - $ball2.width()) { + return true + } else return false +} +function borderCheck1Left () { + if (Number($ball1.css('left').replace('px', '')) > 0) { + return true + } else return false +} +function borderCheck2Left () { + if (Number($ball2.css('left').replace('px', '')) > 0) { + return true + } else return false +} + +// to check for collision against wall-type obstacles +function wallCheck1Left () { + if (($ball1.position().left <= $('.wall1').eq(0).position().left + $('.wall1').eq(0).width()) && + ($ball1.position().left > $('.wall1').eq(0).position().left) && + ($ball1.position().top >= $('.wall1').eq(0).position().top) && + ($ball1.position().top + $ball1.height() <= $('.wall1').eq(0).position().top + $('.wall1').eq(0).height())) { + $ball1.css('left', ($('.wall1').eq(0).position().left + $('.wall1').eq(0).width()).toString() + 'px') + return false + } else { + return true + } +} +function wallCheck1Right () { + if (($ball1.position().left + $ball1.width() >= $('.wall1').eq(0).position().left) && + ($ball1.position().left < $('.wall1').eq(0).position().left) && + ($ball1.position().top >= $('.wall1').eq(0).position().top) && + ($ball1.position().top + $ball1.height() <= $('.wall1').eq(0).position().top + $('.wall1').eq(0).height())) { + $ball1.css('left', ($('.wall1').eq(0).position().left - $ball1.width()).toString() + 'px') + return false + } else { + return true + } +} +function wallCheck2Left () { + if (($ball2.position().left <= $('.wall2').eq(0).position().left + $('.wall2').eq(0).width()) && + ($ball2.position().left > $('.wall2').eq(0).position().left) && + ($ball2.position().top >= $('.wall2').eq(0).position().top) && + ($ball2.position().top + $ball2.height() <= $('.wall2').eq(0).position().top + $('.wall2').eq(0).height())) { + $ball2.css('left', ($('.wall2').eq(0).position().left + $('.wall2').eq(0).width()).toString() + 'px') + return false + } else { + return true + } +} +function wallCheck2Right () { + if (($ball2.position().left + $ball2.width() >= $('.wall2').eq(0).position().left) && + ($ball2.position().left < $('.wall2').eq(0).position().left) && + ($ball2.position().top >= $('.wall2').eq(0).position().top) && + ($ball2.position().top + $ball2.height() <= $('.wall2').eq(0).position().top + $('.wall2').eq(0).height())) { + $ball2.css('left', ($('.wall2').eq(0).position().left - $ball2.width()).toString() + 'px') + return false + } else { + return true + } +} +//ball jumping functions, independent. +function ball1Jump () { + gravityTimeout(100) + if (muteSwitch === false) jumpSound.play() + jumpLimit = false + $ball1.css('top', (Number($ball1.css('top').replace('px', '')) - 8.5 * $ball1.height()).toString() + 'px') + setTimeout(() => { jumpLimit = true }, 1000) +} + +function ball2Jump () { + gravityTimeout(100) + if (muteSwitch === false) jumpSound.play() + jumpLimit = false + $ball2.css('top', (Number($ball2.css('top').replace('px', '')) - 8.5 * $ball2.height()).toString() + 'px') + setTimeout(() => { jumpLimit = true }, 1000) +} + +// these cause the balls to fall downward +var seconds1 = 0 +function gravity1 () { + if (!gLock) { + var $ball1Height = $ball1.css('top') + for (i = 0; i < $('#game1').find('.platform').length; i++) { + if (($ball1.position().left < $('#game1').find('.platform').eq(i).position().left + $('#game1').find('.platform').eq(i).width()) && + ($ball1.position().left + $ball1.width() >= $('#game1').find('.platform').eq(i).position().left) && + ($ball1.position().top + $ball1.height() >= $('#game1').find('.platform').eq(i).position().top - allowance) && + ($ball1.position().top + $ball1.height() <= $('#game1').find('.platform').eq(i).position().top + $('#game1').find('.platform').eq(i).height())) { + $ball1.css('top', $ball1.css('top')) + seconds1 = 0 + return + } else { + seconds1 += 0.02 + // to tally against the gravity setInterval + $ball1.css('top', (Number($ball1Height.replace('px', '')) + (0.5 * gravity * seconds1 ^ 2)).toString() + 'px') + if ($ball1.position().top + $ball1.height() > $('.half').height()) { + if (loseCheck === false && muteSwitch === false) { + lose.play() + loseCheck = true + } + $ball1.css('top', ($('.half').height() + 20).toString() + 'px') + $ball1.css('left', '245px') + $('#game1').removeClass('play') + $('#game1').addClass('fade') + return + } + } + } + } +} + +var seconds2 = 0 +function gravity2 () { + if (!gLock) { + var $ball2Height = $ball2.css('top') + for (i = 0; i < $('#game2').find('.platform').length; i++) { + if (($ball2.position().left < $('#game2').find('.platform').eq(i).position().left + $('#game2').find('.platform').eq(i).width()) && + ($ball2.position().left + $ball2.width() >= $('#game2').find('.platform').eq(i).position().left) && + ($ball2.position().top + $ball2.height() >= $('#game2').find('.platform').eq(i).position().top - allowance) && + ($ball2.position().top + $ball2.height() <= $('#game2').find('.platform').eq(i).position().top + $('#game2').find('.platform').eq(i).height())) { + $ball2.css('top', $ball2.css('top')) + seconds2 = 0 + return + } else { + seconds2 += 0.02 // independent gravity timer counter so that their vertical acceleration is independent + $ball2.css('top', (Number($ball2Height.replace('px', '')) + (0.5 * gravity * seconds2 ^ 2)).toString() + 'px') + if ($ball2.position().top + $ball2.height() > $('.half').height()) { + if (loseCheck === false && muteSwitch == false) { + lose.play() + loseCheck = true + } + $ball2.css('top', ($('.half').height() + 20).toString() + 'px') + $ball2.css('left', '40px') + $('#game2').removeClass('play') + $('#game2').addClass('fade') + return + } + } + } + } +} + +// turn off gravity momentarily +function gravityTimeout (x) { + gLock = true + setTimeout(() => { gLock = false }, x) +} + +// snap ball back to edge of frame if it is out of play field +function ballSnap () { + if (borderCheck1Right() !== true) { + $ball1.css('left', ($('.half').width() - $ball1.width()).toString() + 'px') + } + if (borderCheck2Right() !== true) { + $ball2.css('left', ($('.half').width() - $ball2.width()).toString() + 'px') + } + if (borderCheck1Left() !== true) { + $ball1.css('left', '0px') + } + if (borderCheck2Left() !== true) { + $ball2.css('left', '0px') + } +} + +// goal creation constructor to customize goals in different levels +class goal { + constructor (color = 'black', width = '23px', height = '23px', top, left, id) { + this.color = color + this.width = width + this.height = height + this.top = top + this.left = left + } +} +function createGoal (topPixels, leftPixels, half) { + var goalCreate = new goal() + + var $goalCreate = $('
') + $goalCreate.css({ + backgroundColor: goalCreate.color, + width: goalCreate.width, + height: goalCreate.height, + top: topPixels, + left: leftPixels, + position: 'absolute', + display: 'inline-block', + opacity: 0.5 + // float: 'left' + }) + $goalCreate.attr('id', goalLevel.toString()) + $goalCreate.addClass('goalBorder') + goalLevel++ + half.append($goalCreate) +} + +// platform creation constructor to customize layout in different levels +class platform { + constructor (color = 'black', width = '100px', height = '5px', top, left, id) { + this.color = color + this.width = width + this.height = height + this.top = top + this.left = left + } +} +function createPlatform (topPixels, leftPixels, half, width, height, type) { + var platformCreate = new platform() + + var $platformCreate = $('
') + $platformCreate.css({ + backgroundColor: platformCreate.color, + width: width, + height: height, + top: topPixels, + left: leftPixels, + position: 'absolute', + display: 'inline-block' + }) + $platformCreate.addClass(type) + $platformCreate.addClass('platformBorder') + + $platformCreate.attr('id', 'p' + platformNo.toString()) + platformNo++ + half.append($platformCreate) +} + +// to check if respective balls have reached their target +function ball1Goal () { + if (($ball1.position().left < $('.goal:first').position().left + $('.goal:first').width()) && + ($ball1.position().top < $('.goal:first').position().top + $('.goal:first').height()) && + ($ball1.position().left + $ball1.width() > $('.goal:first').position().left) && + ($ball1.position().top + $ball1.height() > $('.goal:first').position().top)) { + $('.goal:first').css('backgroundColor', 'white') + if (muteSwitch === false) switchPress.play() + return true + } else return false +} + +function ball2Goal () { + if (($ball2.position().left < $('.goal:last').position().left + $('.goal:last').width()) && + ($ball2.position().top < $('.goal:last').position().top + $('.goal:last').height()) && + ($ball2.position().left + $ball2.width() > $('.goal:last').position().left) && + ($ball2.position().top + $ball2.height() > $('.goal:last').position().top)) { + $('.goal:last').css('backgroundColor', 'white') + if (muteSwitch === false) switchPress.play() + return true + } else return false +} + +// skip, alert, reset, mute button functionality +function skipLevel () { + // switch(currentLevel) { + // case 1: + seconds2 = 0 + seconds1 = 0 + gravityTimeout(500) + $ball1.css('top', $('.goal:first').position().top.toString() + 'px') + $ball1.css('left', $('.goal:first').position().left.toString() + 'px') + $ball2.css('top', $('.goal:last').position().top.toString() + 'px') + $ball2.css('left', $('.goal:last').position().left.toString() + 'px') +} +function toggleSound () { + if (muteSwitch === true) { + muteBeep.play() + muteSwitch = false + $('.mute').html('I regret doing that (M)') + } else if (muteSwitch === false) { + muteSwitch = true + $('.mute').html("Life's lonely without sound (M)") + } +} + +function alert1 () { + alert('Game over') +} +function resetLevel () { + loseCheck = false + seconds2 = 0 + seconds1 = 0 + gravityTimeout(500) + $('.goal').css('backgroundColor', 'black') + if ($('.half').length) { + $('.half').removeClass('fade') + $('.half').addClass('play') + } + if ($('.nextLevel').length) { // Check if winning condition has already been triggered, and resets if so + $('.nextLevel').remove() + checkClear = setInterval(levelClear, 500) + } + switch (currentLevel) { + case 1: + $ball1.css('top', '30px') + $ball1.css('left', '255px') + $ball2.css('top', '30px') + $ball2.css('left', '30px') + break + case 2: + $ball1.css('top', (start1[0].top).toString() + 'px') + $ball1.css('left', (start1[0].left + $('.goal').width() / 2).toString() + 'px') + $ball2.css('top', (start2[0].top).toString() + 'px') + $ball2.css('left', (start2[0].left + $('.goal').width() / 2 - $ball2.width()).toString() + 'px') + break + case 3: + $ball1.css('top', (start1[1].top).toString() + 'px') + $ball1.css('left', (start1[1].left + $('.goal').width() / 2).toString() + 'px') + $ball2.css('top', (start2[1].top).toString() + 'px') + $ball2.css('left', (start2[1].left + $('.goal').width() / 2 - $ball2.width()).toString() + 'px') + break + case 4: + $ball1.css('top', (start1[2].top).toString() + 'px') + $ball1.css('left', (start1[2].left + $('.goal').width() / 2).toString() + 'px') + $ball2.css('top', (start2[2].top).toString() + 'px') + $ball2.css('left', (start2[2].left + $('.goal').width() / 2 - $ball2.width()).toString() + 'px') + break + case 5: + $ball1.css('top', (start1[3].top).toString() + 'px') + $ball1.css('left', (start1[3].left + $('.goal').width() / 2).toString() + 'px') + $ball2.css('top', (start2[3].top).toString() + 'px') + $ball2.css('left', (start2[3].left + $('.goal').width() / 2 - $ball2.width()).toString() + 'px') + break + + } +} + +// level set up +function level1 () { + createGoal('125px', '30px', $('#game1')) + createGoal('125px', '247px', $('#game2')) + start1.push($('.goal:first').position()) + start2.push($('.goal:last').position()) + currentLevel = $('.goal').last().attr('id') / 2 + createPlatform('150px', '0', $('#game1'), '300px', '5px', 'floor1') + createPlatform('120px', '190px', $('#game1'), '50px', '50px', 'wall1') + createPlatform('150px', '0', $('#game2'), '300px', '5px', 'floor2') + createPlatform('120px', '60px', $('#game2'), '50px', '50px', 'wall2') +} + +function level2 () { + $('.goal').remove() + $('.platform').remove() + + createGoal('60px', '227px', $('#game1')) + createGoal('60px', '50px', $('#game2')) + start1.push($('.goal:first').position()) + start2.push($('.goal:last').position()) + currentLevel = $('.goal').last().attr('id') / 2 + createPlatform('155px', '0', $('#game1'), '250px', '5px', 'floor1') + createPlatform('83px', '238px', $('#game1'), '20px', '5px', 'floor1') + createPlatform('110px', '250px', $('#game1'), '50px', '5px', 'wall1') + + createPlatform('155px', '50px', $('#game2'), '130px', '5px', 'floor2') + createPlatform('155px', '210px', $('#game2'), '90px', '5px', 'floor2') + createPlatform('83px', '40px', $('#game2'), '20px', '5px', 'floor2') + createPlatform('110px', '0', $('#game2'), '30px', '5px', 'wall2') + checkClear = setInterval(levelClear, 500) + return $('.nextLevel').remove() +} + +function level3 () { + $('.goal').remove() + $('.platform').remove() + + createGoal('10px', '10px', $('#game1')) + createGoal('10px', '90px', $('#game2')) + start1.push($('.goal:first').position()) + start2.push($('.goal:last').position()) + currentLevel = $('.goal').last().attr('id') / 2 + createPlatform('83px', '225px', $('#game1'), '35px', '5px', 'floor1') + createPlatform('0px', '210px', $('#game1'), '15px', '100px', 'wall1') + createPlatform('120px', '280px', $('#game1'), '15px', '5px', 'floor1') + createPlatform('170px', '190px', $('#game1'), '70px', '5px', 'floor1') + createPlatform('150px', '100px', $('#game1'), '70px', '5px', 'floor1') + createPlatform('120px', '30px', $('#game1'), '70px', '5px', 'floor1') + createPlatform('95px', '5', $('#game1'), '50px', '5px', 'floor1') + createPlatform('70px', '10px', $('#game1'), '20px', '5px', 'floor1') + createPlatform('40px', '15px', $('#game1'), '10px', '5px', 'floor1') + + createPlatform('83px', '40px', $('#game2'), '30px', '5px', 'floor2') + createPlatform('0', '70px', $('#game2'), '15px', '100px', 'wall2') + createPlatform('130px', '0', $('#game2'), '95px', '5px', 'floor2') + createPlatform('100px', '120px', $('#game2'), '20px', '5px', 'floor2') + createPlatform('70px', '150px', $('#game2'), '20px', '5px', 'floor2') + createPlatform('40px', '95px', $('#game2'), '60px', '5px', 'floor2') + checkClear = setInterval(levelClear, 500) + return $('.nextLevel').remove() +} + +function level4 () { + $('.goal').remove() + $('.platform').remove() + + createGoal('120px', '180px', $('#game1')) + createGoal('30px', '210px', $('#game2')) + start1.push($('.goal:first').position()) + start2.push($('.goal:last').position()) + currentLevel = $('.goal').last().attr('id') / 2 + createPlatform('75px', '8px', $('#game1'), '30px', '7px', 'floor1') + createPlatform('55px', '150px', $('#game1'), '25px', '100px', 'wall1') + createPlatform('75px', '56px', $('#game1'), '30px', '7px', 'floor1') + createPlatform('75px', '106px', $('#game1'), '29px', '7px', 'floor1') + createPlatform('75px', '175px', $('#game1'), '30px', '7px', 'floor1') + createPlatform('95px', '235px', $('#game1'), '25px', '7px', 'floor1') + createPlatform('143px', '176px', $('#game1'), '27px', '7px', 'floor1') + + createPlatform('85px', '80px', $('#game2'), '25px', '7px', 'floor2') + createPlatform('0', '63px', $('#game2'), '16px', '100px', 'wall2') + createPlatform('95px', '150px', $('#game2'), '20px', '7px', 'floor2') + createPlatform('70px', '163px', $('#game2'), '20px', '7px', 'floor2') + createPlatform('55px', '195px', $('#game2'), '30px', '7px', 'floor2') + checkClear = setInterval(levelClear, 500) + return $('.nextLevel').remove() +} + +function level5 () { + $('.goal').remove() + $('.platform').remove() + + createGoal('0', '274px', $('#game1')) + createGoal('0', '0', $('#game2')) + start1.push($('.goal:first').position()) + start2.push($('.goal:last').position()) + currentLevel = $('.goal').last().attr('id') / 2 + createPlatform('163px', '130px', $('#game1'), '70px', '7px', 'floor1') + createPlatform('50px', '150px', $('#game1'), '40px', '30px', 'wall1') + createPlatform('143px', '220px', $('#game1'), '30px', '7px', 'floor1') + createPlatform('100px', '130px', $('#game1'), '70px', '7px', 'floor1') + createPlatform('23px', '210px', $('#game1'), '80px', '7px', 'floor2') + + createPlatform('95px', '195px', $('#game2'), '28px', '7px', 'floor2') + createPlatform('95px', '260px', $('#game2'), '40px', '7px', 'floor2') + createPlatform('0', '179px', $('#game2'), '16px', '100px', 'wall2') + createPlatform('135px', '250px', $('#game2'), '28px', '7px', 'floor2') + createPlatform('145px', '100px', $('#game2'), '130px', '7px', 'floor2') + createPlatform('99px', '0', $('#game2'), '70px', '7px', 'floor2') + createPlatform('49px', '60px', $('#game2'), '20px', '7px', 'floor2') + createPlatform('30px', '10px', $('#game2'), '30px', '7px', 'floor2') + + checkClear = setInterval(levelClear, 500) + return $('.nextLevel').remove() +} + +// to check if winning conditions have been met +function levelClear () { + if (ball1Goal() === true && ball2Goal() === true) { + switch (currentLevel) { + case 1: + clearInterval(checkClear) + $('.container').append('') + break + case 2: + clearInterval(checkClear) + $('.container').append('') + break + case 3: + clearInterval(checkClear) + $('.container').append('') + break + case 4: + clearInterval(checkClear) + $('.container').append('') + break + case 5: + clearInterval(checkClear) + $('.container').append('') + break + } + } +} diff --git a/assets/sounds/ballbounce.wav b/assets/sounds/ballbounce.wav new file mode 100644 index 00000000..05ff59fc Binary files /dev/null and b/assets/sounds/ballbounce.wav differ diff --git a/assets/sounds/beep.wav b/assets/sounds/beep.wav new file mode 100644 index 00000000..7d952f91 Binary files /dev/null and b/assets/sounds/beep.wav differ diff --git a/assets/sounds/jump.wav b/assets/sounds/jump.wav new file mode 100644 index 00000000..01023738 Binary files /dev/null and b/assets/sounds/jump.wav differ diff --git a/assets/sounds/lose.wav b/assets/sounds/lose.wav new file mode 100644 index 00000000..59d2b697 Binary files /dev/null and b/assets/sounds/lose.wav differ diff --git a/assets/sounds/switchpress.wav b/assets/sounds/switchpress.wav new file mode 100644 index 00000000..d0e40fc0 Binary files /dev/null and b/assets/sounds/switchpress.wav differ diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 00000000..e1eacea6 Binary files /dev/null and b/favicon.ico differ diff --git a/index.html b/index.html index 5b002212..5da0c83d 100644 --- a/index.html +++ b/index.html @@ -2,10 +2,50 @@ - - + + + + + On The Other Side - + + +


+
+
+ +
+ + +
+
+ +
+ +
+ +
+ +
+ + + +

Click start to begin

+ +

Help steer Blue and Red into the grey boxes to win.
+ You can only move Blue directly with W,A,D or ↑,←,→.
+ Red will go opposite in the horizontal plane.

+

+
+ + + diff --git a/project-1 b/project-1 new file mode 160000 index 00000000..e849801e --- /dev/null +++ b/project-1 @@ -0,0 +1 @@ +Subproject commit e849801e9aaa35b3afd9b9c32bd08e0d405f7297