├── EntityExample.html ├── LICENSE.md ├── README.md ├── css ├── .DS_Store ├── fonts │ ├── .DS_Store │ └── NewCircle │ │ ├── License&ExtrasNewCicle.pdf │ │ ├── New Cicle Fina Italic.ttf │ │ ├── New Cicle Fina.ttf │ │ ├── New Cicle Gordita Italic.ttf │ │ ├── New Cicle Gordita.ttf │ │ ├── New Cicle Semi Italic.ttf │ │ └── New Cicle Semi.ttf ├── incremental_demo_style.css └── incremental_style.css ├── demo.html ├── demo_survival.html ├── documentation.html ├── index.html ├── js ├── .DS_Store ├── incrementalObject.js ├── incrementalObject_v1.0backup.js ├── jquery.js └── particleObject.js └── tutorials ├── 1 ├── demo.html └── index.html ├── .DS_Store └── v1.1 Working Tutorial ├── .DS_Store ├── css ├── .DS_Store └── incremental_style.css ├── demo.html ├── index.html └── js ├── .DS_Store ├── incrementalObject.js └── jquery.js /EntityExample.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Test 7 | 8 | 9 | 10 | 11 | 12 | 55 | 56 | 57 | 58 | 59 | 60 | 61 |
62 |
63 |
64 | 65 | 66 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) [2015] [Adarsh Sinha] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | incremental-game-engine-js (v1.6) 2 | ========================== 3 | 4 | A simple Javascript/jQuery framework to allow the quick creation, deployment, and expansion of incremental games. 5 | 6 | [This project uses the MIT License] 7 | 8 | 9 | [DOCUMENTATION](http://aldo111.github.io/incremental-game-engine-js/documentation.html "v1.5") 10 | 11 | [v1.6 Tutorial 1](http://aldo111.github.io/incremental-game-engine-js/tutorials/1 "v1.6 Tutorial") --> NEW 12 | 13 | [Descent: A v1.5.1 Simple Survival Game Demo](http://aldo111.github.io/incremental-game-engine-js/demo_survival.html "v1.5") 14 | 15 | --- 16 | 17 | [v1.1 (OLD TUTORIAL) DEMO](http://aldo111.github.io/incremental-game-engine-js/tutorials/v1.1%20Working%20Tutorial/demo.html "Demo made with old, ugly v1.1 tutorial") 18 | 19 | [v1.4 version of Tutorial Demo](http://aldo111.github.io/incremental-game-engine-js/demo.html "v1.4") 20 | 21 | 22 | 23 | 24 | Goal 25 | ==== 26 | The goal of this is to create a very simple-to-use javascript framework for other incremental-game enthusiasts! I've often seen many people online who would like to embark upon their own ventures but lack either the time or skills to get some of the boring stuff out of the way. 27 | 28 | So this is the purpose of the engine: get the boring stuff out of the way and onto the fun stuff! 29 | 30 | 31 | FILES 32 | ==== 33 | 34 | #### Essential: 35 | 1. js/incrementalObject.js -> The main file 36 | 2. js/jquery.js -> jQuery file used. 37 | 38 | 3. documentation.html -> page with documentation on methods. It's still a work-in-progress but helps to gain an idea of what's going on in each object. 39 | 40 | #### Non-Essential [Only for DEMOS/help]: 41 | 1. js/ParticleObject.js -> Just a simple particle script I made for the background stars. I was building the game engine on top of another project and so this is just a nice (visually appealing) artefact. Not required at all. 42 | 2. css/incremental_style.css -> The CSS of the demo 43 | 3. css/fonts/NewCircle/ -> The font I'm using for the demo page 44 | 4. index.html -> The Demo Page 45 | 5. css/incremental_demo_style.css -> The css of the v1.2 demo.html 46 | 6. tutorials/ -> contains tutorials 47 | 7. EntityExample.html -> very simply example of using an EntitySet and Entity independently and together 48 | 8. demo_survival.html -> A simple demo with some basic survival elements demonstrating the creation of a game with v1.5.1 of this library. 49 | 50 | 51 | NOTES 52 | ==== 53 | 54 | 1. Documentation is live! Check the link above. 55 | 56 | 2. While it was planned that jQuery would be removed to make this a vanilla JS library, jQuery has more than simplified certain sections of the code to avoid further unnecessary code. 57 | As a result, jQuery will continue to be used for DOM and DOM Events manipulation. A vanilla JS version will also be provided once we have all core features implemented. 58 | 59 | 60 | 61 | 62 | TODO (updated) 63 | ==== 64 | 65 | 1. Supplementing Trackers using Timers -> Additional (optional) parameter to all tracker functions that will execute a function if a certain value is reached. 66 | (DONE in a way -> Can be taken care of using the optional third argument in Common.track()) 67 | 68 | 2. Saving/Loading - attempted earlier but ran into unexpected trouble. Will reattempt soon. 69 | 3. UI (User Interface) and other related helper functions to help streamline creation of dynamic page elements. 70 | 4. Allow the definition of 'required and default attributes' for all Entities of an EntitySet -> essentially giving EntitySets 'types'. 71 | 5. Add multiple attributes using add/setAttribute (DONE -> updateAttributes) 72 | 6. Add a getRandomEntity() function that does exactly that. 73 | 7. Add the ability to give max/default/minimum values for attributes (similar to 4). 74 | 8. Add a game.stop() or game.pause() or equivalent 75 | 76 | As of v1.6 77 | 78 | 1. Add clicker text over a specific element, not just the mouse 79 | 2. Add hover events, not just clickers 80 | 3. Options for Game() 81 | 4. Shorthands for functions 82 | **DONE5. Add a "updateAttributes" function that takes in an object of n_attributes and updates/adds attributes accordingly 83 | 6. Get Tracks to update a value as soon as it changes, not just until the next loop 84 | 85 | VERSION CHANGES 86 | ==== 87 | 88 | ###v1.6 [Jan 9, 2015] 89 | 90 | 1. Common and AttributeSet now have an "updateAttributes(n_attributes)" function that allow multiple attributes to be added/updated through an object 91 | 2. Tracks now only update if there is an actual change in value. 92 | 3. Default FPS is now 1. 93 | 4. AttributeSet.addAttribute and Common.addAttribute now takes an extra, optional, 4th parameter called 'func', same in functionality as track()'s func parameter. 94 | 5. Added a Common.getAttributesOriginal() function which returns the attributes themselves, as opposed to copies like in getAttributes, but ALSO includes the AttributeSet prototype methods 95 | 6. Added track and untrack functions to AttributeSet as well in case one only wants to use AttributeSet and nothing else 96 | 7. Game.addFlag(..) console logging has been removed. 97 | 8. MIT License added. Sorry it took so long! 98 | 99 | 100 | ###v1.5.1 [Jan 6, 2015] 101 | 102 | 1. First update of the year - nothing too great. Just a minor change to the way addClickerText works. 103 | 2. Flags are now logged in the console for testing purposes (will be removed in 1.6). 104 | 105 | 106 | ###v1.5 [Dec 29, 2014] 107 | 108 | 1. Added Game.addFlag(), Game.removeFlag(), Game.checkFlag(), which allows one to store and track particular events/milestones/progress. 109 | 2. Added Game.addClickerText(), which adds text to the mouse's current position and moves it upwards for a second. 110 | 3. Modified Game.addClicker() to handle dynamic HTML elements. 111 | 4. Modified Common.track() to receive an optional third argument - a function, which takes one parameter (the value of the attribute being tracked), and should return the way that parameter must be displayed. 112 | 113 | 114 | ###v1.4 [Dec 26, 2014] 115 | 116 | 1. Game.play() function now handles missed frame execution (i.e. when game runs in background tab and interval time is throttled). 117 | 2. Added Game.addTimer(func, options) that executes a function during the game loop based on timer options passed (once, 'x' times, continuous..etc) 118 | 3. Fixed bug that didn't add attributes of an entity correctly when an entity was passed to EntitySet.addEntity(). 119 | 4. Fixed bug that didn't add the name correctly to a new entity when another entity was added to a set. 120 | 121 | 122 | ###v1.3.1 [Dec 26, 2014] 123 | 124 | 1. Fixed bug that resulted in incorrect results when checking whether an Entity Name existed through addEntity(...,...) 125 | 2. Return the AttributeSet itself instead of the value in add/setAttribute. 126 | 3. Modified Game.addClicker() to make the params of the function passed optional. 127 | 4. Documentation page created using EntitySet/Entities/AttributeSet. 128 | 129 | ###v1.3 [Dec 25, 2014] 130 | 131 | 1. Added Game.addClicker(id,functionToExecute,[params,for,function]) and Game.removeClicker(id) which allows any html element (denoted in id by #id or .class ..etc) to become a clicker for a function. 132 | 2. Added Game.play(function that needs to be played in the game loop) which runs the game loop function passed 'Game.getFPS() times per second'. 133 | 3. Added EntitySet.hasEntity(entity_name) that returns true/false depending on if an entity with that name exists in this set. 134 | 135 | ###v1.2.1 [Dec 24, 2014] 136 | 137 | 1. Entities added to a set are no longer added by reference - they are added by copy/value giving each set their own instance of that entity. 138 | 139 | 140 | ###v1.2 [Dec 23, 2014] 141 | 142 | 1. Added basic functionality to track and display any attribute belonging to any object (that's part of their .attributes[]) in any html element. 143 | 2. Minor code enhancements. 144 | 3. EntitySet.getSet() is now EntitySet.getEntities() to avoid confusion with Game.getSet(set name) ----> EntitySet.getSet() will still work but will be removed completely in future versions. 145 | 4. Added untracking of any attribute belonging to an object (second commit) 146 | 147 | ###v1.1 [Dec 22, 2014] 148 | 149 | 1. Sets/Entities are now returned upon adding/modifying them. 150 | 2. Entity Sets now have attributes as well 151 | 3. Added AttributeSets that are simply normal javascript objects with some extended properties to help manage the attributes within 152 | 4. Added a parent object called 'Common' which contains elements that every other object needs. 153 | 5. Added an attributes[] list to Common, which is inherited by Game(), EntitySet(), Entity() 154 | 6. Added functions to remove an EntitySet from Game().sets, as well as an Entity from EntitySet().getSet() 155 | 156 | 157 | ###v1.0 [Dec 21, 2014] 158 | 159 | 1. Added Entity and EntitySets to manage different sets of different entities. 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /css/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aldo111/incremental-game-engine-js/0e3a53301ff440203a4aac02d941955e9a777cb5/css/.DS_Store -------------------------------------------------------------------------------- /css/fonts/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aldo111/incremental-game-engine-js/0e3a53301ff440203a4aac02d941955e9a777cb5/css/fonts/.DS_Store -------------------------------------------------------------------------------- /css/fonts/NewCircle/License&ExtrasNewCicle.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aldo111/incremental-game-engine-js/0e3a53301ff440203a4aac02d941955e9a777cb5/css/fonts/NewCircle/License&ExtrasNewCicle.pdf -------------------------------------------------------------------------------- /css/fonts/NewCircle/New Cicle Fina Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aldo111/incremental-game-engine-js/0e3a53301ff440203a4aac02d941955e9a777cb5/css/fonts/NewCircle/New Cicle Fina Italic.ttf -------------------------------------------------------------------------------- /css/fonts/NewCircle/New Cicle Fina.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aldo111/incremental-game-engine-js/0e3a53301ff440203a4aac02d941955e9a777cb5/css/fonts/NewCircle/New Cicle Fina.ttf -------------------------------------------------------------------------------- /css/fonts/NewCircle/New Cicle Gordita Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aldo111/incremental-game-engine-js/0e3a53301ff440203a4aac02d941955e9a777cb5/css/fonts/NewCircle/New Cicle Gordita Italic.ttf -------------------------------------------------------------------------------- /css/fonts/NewCircle/New Cicle Gordita.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aldo111/incremental-game-engine-js/0e3a53301ff440203a4aac02d941955e9a777cb5/css/fonts/NewCircle/New Cicle Gordita.ttf -------------------------------------------------------------------------------- /css/fonts/NewCircle/New Cicle Semi Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aldo111/incremental-game-engine-js/0e3a53301ff440203a4aac02d941955e9a777cb5/css/fonts/NewCircle/New Cicle Semi Italic.ttf -------------------------------------------------------------------------------- /css/fonts/NewCircle/New Cicle Semi.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aldo111/incremental-game-engine-js/0e3a53301ff440203a4aac02d941955e9a777cb5/css/fonts/NewCircle/New Cicle Semi.ttf -------------------------------------------------------------------------------- /css/incremental_demo_style.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | * { 4 | 5 | margin:0; 6 | padding:0; 7 | -webkit-touch-callout: none; 8 | -webkit-user-select: none; 9 | -khtml-user-select: none; 10 | -moz-user-select: none; 11 | -ms-user-select: none; 12 | user-select: none; 13 | } 14 | 15 | 16 | body { 17 | width:100%; 18 | background-color:white; 19 | color:black; 20 | font-family:Georgia; 21 | 22 | } 23 | 24 | 25 | #available_houses { 26 | position:relative; 27 | width:100%; 28 | background-color:orange; 29 | min-height:100px; 30 | padding-top:10px; 31 | text-align:center; 32 | 33 | } 34 | 35 | #available_houses .house { 36 | 37 | width:80px; 38 | height:80px; 39 | border:2px solid black; 40 | background-color:white; 41 | opacity:0.8; 42 | border-radius:5px; 43 | margin:5px; 44 | display:inline-block; 45 | cursor:pointer; 46 | 47 | } 48 | 49 | #money { 50 | 51 | border:2px solid black; 52 | font-size:20pt; 53 | text-align:center; 54 | 55 | } 56 | 57 | header { 58 | 59 | background-color:orange; 60 | opacity:0.6; 61 | color:white; 62 | font-size:25pt; 63 | text-align:center; 64 | 65 | border-bottom:2px solid black; 66 | 67 | } 68 | 69 | #clicker { 70 | 71 | background-color:black; 72 | color:white; 73 | border:2px solid #00aaff; 74 | cursor:pointer; 75 | border-radius:5px; 76 | height:100px; 77 | width:200px; 78 | margin:0 auto; 79 | 80 | } 81 | 82 | #clicker:active, .house:active { 83 | 84 | background-color:#00aaff; 85 | 86 | } -------------------------------------------------------------------------------- /css/incremental_style.css: -------------------------------------------------------------------------------- 1 | 2 | @font-face { 3 | font-family:NewCircle; 4 | src: url("fonts/NewCircle/New Cicle Fina.ttf"); 5 | } 6 | 7 | * { 8 | 9 | margin:0; 10 | padding:0; 11 | -webkit-touch-callout: none; 12 | -webkit-user-select: none; 13 | -khtml-user-select: none; 14 | -moz-user-select: none; 15 | -ms-user-select: none; 16 | user-select: none; 17 | } 18 | 19 | 20 | body { 21 | 22 | background-color:#0a0a0a; 23 | font-family:NewCircle; 24 | font-size:84pt; 25 | 26 | } 27 | 28 | html, body { 29 | 30 | width:100%; 31 | height:100%; 32 | margin:0 px; 33 | 34 | } 35 | 36 | header { 37 | 38 | height:50px; 39 | text-align:center; 40 | background-color:white; 41 | font-size:25pt; 42 | padding-top:10px; 43 | 44 | } 45 | 46 | #canvas { 47 | display:block; 48 | position:absolute; 49 | top:0; 50 | left:0; 51 | z-index:-1; 52 | background-color:black; 53 | overflow:hidden; 54 | bottom:0; 55 | right:0; 56 | 57 | } 58 | 59 | 60 | 61 | #stats { 62 | color:#fafafa; 63 | padding:10px; 64 | background-color:#00aaff; 65 | opacity:0.9; 66 | z-index:3; 67 | font-size:62pt; 68 | word-wrap:breakword; 69 | text-align:center; 70 | 71 | } 72 | 73 | #stats li { 74 | 75 | list-style-type:none; 76 | 77 | } 78 | 79 | #clicker { 80 | 81 | background-color:#00ddaa; 82 | color:white; 83 | text-align:center; 84 | font-size:25pt; 85 | padding:20px; 86 | padding-right:0; 87 | cursor:pointer; 88 | height:20px; 89 | 90 | } 91 | 92 | 93 | #clicker:active { 94 | 95 | color:black; 96 | font-size:13pt; 97 | 98 | } 99 | 100 | #upgrades { 101 | width:100%; 102 | background-color:#252525; 103 | height:50px; 104 | color:white; 105 | cursor:pointer; 106 | 107 | } 108 | 109 | #upgrades li { 110 | 111 | list-style-type:none; 112 | font-size:15pt; 113 | width:25%; 114 | height:30px; 115 | padding-top:20px; 116 | float:left;; 117 | text-align:center; 118 | line-height:10px; 119 | background-color:#222; 120 | 121 | 122 | } 123 | 124 | #upgrades li:hover { 125 | 126 | background-color:#555; 127 | 128 | } 129 | 130 | 131 | sup { 132 | font-size:18pt; 133 | color:#0077aa; 134 | font-weight:bold; 135 | 136 | } 137 | -------------------------------------------------------------------------------- /demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | v1.4, Yay! 9 | 10 | 11 | 12 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 |
162 | GOLD HOUSE 163 |
164 |
165 |
166 |
167 | Money:
168 | 169 |
170 | Do your regular job 171 |
172 |
173 | Per Second:
174 | Per Click: 175 |
176 | 177 |
178 | 179 | 184 |
185 | 186 | 190 | 191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /demo_survival.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Descent (w/v1.5.1) 9 | 10 | 11 | 12 | 13 | 23 | 329 | 330 | 331 | 1175 | 1176 | 1177 | 1178 | 1179 | 1180 | 1181 | 1182 | 1183 | 1186 |
1187 | 1188 | 1194 | 1195 | 1196 | 1201 | 1202 |
1203 |
1204 | 1205 | 1206 | 1207 | 1208 | 1209 | 1210 | 1211 |
CollectedWood: / Food: / Metal: /
1212 |
1213 | 1214 |
1215 | 1216 |
Explore
1217 |
Hunt
1218 |
Camp
1219 |
Scavenge
1220 |
Scavenge Metal
1221 | 1222 | 1223 |
1224 | 1225 |
1226 | Camp Inhabitants 1227 | 1229 |
1230 | Camp Upgrades 1231 | 1233 |
1234 | 1235 |
1236 |
1237 | 1238 | 1239 | 1240 | 1241 | -------------------------------------------------------------------------------- /documentation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Documentation v1.6 8 | 9 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 488 | 489 |
490 |

491 |

Objects

492 |
493 | 494 |
495 | 496 |
497 | 498 |
499 | 500 |
501 |

Welcome

502 |

This page provides documentation for the Incremental Game Engine JS (title and 'engine' works-in-progress!)

Simply select the object on the left you wish to learn about.

503 | 504 |

What can you do with it so far?

505 |

506 | 1. Create a very simple clicker/incremental game in minutes using the pre-defined score variable and setting an HTML element with the id of 'clicker' and calling game.init()! 507 |

2. Use the library to maintain sets of 'entities' - objects with unique identifiers and attributes, and access these objects and sets in meaningful ways! 508 |

3. Track/Untrack any attributes in an HTML element (and optionally parse the value through a function to display it how you want to) that are a part of the 'attributes' array in Game, EntitySet, and Entity objects (and any other that inherits Common). 509 |

4. Bind/Unbind a click event on any HTML element to a function that can be executed! 510 |

5. Run games in background tabs by leveraging Game.play() 511 |

6. Display typical '+X...' type particle-text on the mouse for your clicker game 512 |

7. Flag/track events using Flags to observe any major milestones/events/progress changes! 513 |


And much more! The more you get used to it and the more you understand how the different functions work, you will be able to come up with more creative uses for things. If you feel something can be done in a more efficient or programmer-friendly way, please do point it out! 514 | 515 |

516 | 517 |

What else is coming?

518 |

519 | 1. Supplementing Trackers using Timers -> Additional (optional) parameter to all tracker functions that will execute a function if a certain value is reached. 520 |

2. Saving/Loading - attempted earlier but ran into unexpected trouble. Will reattempt soon. 521 |

3. UI (User Interface) and other related helper functions to help streamline creation of dynamic page elements. 522 |


And more! 523 | 524 |

525 | 526 | 527 |
528 | 529 |
530 |


531 |

532 |
533 | 534 | 535 |
536 | 537 | 538 | 539 | 540 | 541 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | IncGE v1.6 9 | 10 | 11 | 12 | 13 | 119 | 120 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | Fork me on GitHub 151 |
152 | Incremental Game Engine JS v1.6 153 |
154 | 155 |
156 | 157 | 162 | 163 | 164 |
165 |
166 | Click Me! 167 |
168 | 169 |
170 | 171 | 172 |
173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /js/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aldo111/incremental-game-engine-js/0e3a53301ff440203a4aac02d941955e9a777cb5/js/.DS_Store -------------------------------------------------------------------------------- /js/incrementalObject.js: -------------------------------------------------------------------------------- 1 | /*-------------------------------- 2 | Incremental Game Engine v1.5.1 3 | Created at https://github.com/Aldo111/incremental-game-engine-js [Started Dec 21, 2014 by Aldo111 on GitHub] 4 | Purpose-built library to serve efficient design and development of Incremental/Idle/Clicker games. 5 | If you do use this in your game, please provide the proper attribution or linkback to the original creator of this library, that is all! 6 | ----------------------------------*/ 7 | 8 | //=== 9 | 10 | 11 | //some constants -> if some function is not working as expected, check its return value, if any, against these errors 12 | const ERR_DOES_NOT_EXIST_CODE="errdne-999"; 13 | const ERR_INVALID_PARAMS_CODE="errinvalid-989"; 14 | const SUCC_CODE="success10101010"; 15 | //other global variables 16 | var Tracks=[]; 17 | 18 | //window changes 19 | // shim layer with setTimeout fallback 20 | window.requestAnimFrame = (function(){ 21 | return window.requestAnimationFrame || 22 | window.webkitRequestAnimationFrame || 23 | window.mozRequestAnimationFrame || 24 | false; 25 | })(); 26 | 27 | //Function that stores common elements 28 | function Common(n_attributes) { 29 | 30 | this.attributes=new AttributeSet(n_attributes); 31 | 32 | 33 | //The following methods basically allow the Object containing an Attribute set to get/set/add/remove attributes directly 34 | //into that set by doing Object.getAttribute(...) instead of Object.attributes.getAttribute(..) although one 35 | //can even do that since these functions just use AttributeSet's methods 36 | this.getAttribute=function(attr) { 37 | return this.attributes.getAttribute(attr); 38 | }; 39 | this.setAttribute=function(attr,value) { 40 | return this.attributes.setAttribute(attr,value); 41 | }; 42 | this.updateAttributes=function(n_attributes) { 43 | return this.attributes.updateAttributes(n_attributes); 44 | }; 45 | this.addAttribute=function(attr,value,ele,func) { 46 | 47 | return this.attributes.addAttribute(attr,value,ele,func); 48 | }; 49 | 50 | this.hasAttribute=function(attr) { 51 | return this.attributes.hasAttribute(attr); 52 | }; 53 | 54 | this.removeAttribute=function(attr) { 55 | return this.attributes.removeAttribute(attr); 56 | }; 57 | 58 | this.isDefined=function(a) { 59 | 60 | return (typeof a !=='undefined'); 61 | 62 | }; 63 | 64 | 65 | //the next function only returns a copy of the whole attributes set, not the attributes themselves -- to iterate over the actual attributes, 66 | //although not an intention of this system as these are meant to act as normal variables, you can run a for-in loop 67 | /* 68 | var x=0; 69 | for (i in Object.attributes) 70 | { 71 | //code here 72 | 73 | 74 | x++; 75 | if (x==Object.attributes.size()) break; //this is so that the user doesn't get any of the Prototype methods as attriutes 76 | } 77 | 78 | */ 79 | //this only gives us a copy of the attributes, not the actual attributes !! It's better to use the above way or just Obj.attributes.VARIABLE 80 | this.getAttributes=function() { 81 | 82 | return this.attributes.getAttributes(); 83 | 84 | }; 85 | 86 | this.getAttributesOriginal=function() { 87 | 88 | return this.attributes; //WARNING - comes with the AttributeSet prototype methods... use a for-in loop and check the counter variable against the attributes you want or check against the size as above 89 | 90 | } 91 | 92 | //prototype- tracks a particular element in an html element 93 | this.track=function(attr,ele,func) { 94 | 95 | if (typeof attr !== 'undefined' && this.hasAttribute(attr) && typeof ele !=='undefined') 96 | { 97 | 98 | Tracks.push({container:this.attributes,name:attr,element:ele,func:func}); 99 | } 100 | else 101 | return ERR_DOES_NOT_EXIST_CODE; 102 | 103 | }; 104 | 105 | //untrack an attribute that belongs to this object 106 | this.untrack=function(attr) { 107 | var invoker=this.constructor.name; //Common object through which this method was invoked - either Game or EntitySet or Entity 108 | //future use 109 | 110 | //stops tracking this.attribute's particular attribute of this particule object 111 | if (typeof attr !== 'undefined') 112 | { 113 | 114 | for (var i in Tracks) 115 | if (Tracks[i].container===this.attributes && Tracks[i].name==attr) delete Tracks[i]; 116 | 117 | } 118 | }; 119 | 120 | 121 | 122 | }; 123 | 124 | 125 | 126 | 127 | //The Main Game Function! var g=new Game(); this is what we need to get started! 128 | Game.prototype=new Common(); 129 | 130 | function Game(a_fps) { 131 | 132 | 133 | Common.call(this); 134 | 135 | if (typeof a_fps === 'undefined') 136 | a_fps=1;//default fps 137 | 138 | //PRIVATE variables 139 | var score=0; 140 | var pointsPerSecond=0; 141 | var pointsPerClick=0; 142 | var fps=a_fps; 143 | //var seconds=1; 144 | var Timers=[];//stores objects of timed functions 145 | var Flags=[];//stores flags 146 | 147 | 148 | //PRIVILEGED PUBLIC -> If you want to add your own variables, here is where you would do it : this.=0; accessed by game. 149 | 150 | this.sets=[];//Holds multiple ENTITY SETS -> eg. this can hold UPGRADES, ACHIEVEMENTS, INVENTORY..etc 151 | //accessed by game.entities. -> eg. game.sets.UPGRADES 152 | 153 | 154 | //ACCESSOR METHODS 155 | this.getFPS=function() { return fps; }; //get fps of game 156 | 157 | this.getScore = function() { return Math.ceil(score); }; //get score 158 | 159 | this.getPointsPerSecond=function() { return pointsPerSecond; }; //return the main pointsPerSecond that affects the score 160 | 161 | this.getPointsPerClick=function() { return pointsPerClick; }; //return the main pointsPerClick that affects the score 162 | 163 | this.getSets=function() { return this.sets; }; //returns all sets 164 | 165 | this.getSet=function(set_name) { //gets a particular set 166 | 167 | if (set_name in this.sets && typeof set_name !== 'undefined') 168 | return this.sets[set_name]; 169 | else 170 | { 171 | return ERR_DOES_NOT_EXIST_CODE; 172 | } 173 | 174 | }; 175 | 176 | //MUTATOR METHODS 177 | 178 | this.increaseScorePerSecond=function() { //TODO - make this private - doesn't make sense to have it public 179 | //increment the score per second 180 | score+=pointsPerSecond/fps; 181 | 182 | }; 183 | 184 | this.increaseScorePerClick=function() { 185 | //increment the score per click 186 | score+=pointsPerClick; 187 | // $('#money_value').html(game.getScore()) // -> we'll want a way to know which html element we track score in for quicker updates on low-FPS games -> integrate this with the attributes tracks system? 188 | 189 | 190 | }; 191 | 192 | this.addToScore=function(value) { 193 | //adds 'value' to score 194 | score+=value; 195 | 196 | 197 | }; 198 | 199 | this.addToPointsPerSecond=function(value) { 200 | //adds 'value' to pointsPerSecond 201 | pointsPerSecond+=value; 202 | }; 203 | 204 | this.addToPointsPerClick=function(value) { 205 | //adds 'value' to pointsPerClick 206 | pointsPerClick+=value; 207 | 208 | }; 209 | 210 | //end single-variable game functions 211 | 212 | 213 | 214 | this.addSet=function(n_name) { 215 | //adds a set to sets 216 | 217 | if (!(n_name instanceof EntitySet)) //if the passed parameter is not an entity set itself 218 | { 219 | 220 | this.sets[n_name]=new EntitySet(n_name);//create a new empty entity set with the name given 221 | return this.sets[n_name];//after adding a set, return it directly to the user for chaining/adding entities 222 | } 223 | else 224 | { //store the entity set 225 | this.sets[n_name.getName()]=n_name;//because the user wants to add a pre-existing EntitySet --> currently if you modify one, both get modified 226 | return this.sets[n_name.getName()];//return directly to user for chaining/adding entities 227 | } 228 | 229 | 230 | 231 | 232 | }; 233 | 234 | this.removeSet=function(n_name) { 235 | 236 | if (typeof n_name !== 'undefined' && (n_name in this.sets)) 237 | { 238 | delete this.sets[n_name]; 239 | return SUCC_CODE; 240 | 241 | } 242 | else 243 | return ERR_DOES_NOT_EXIST_CODE; 244 | 245 | }; 246 | 247 | //Clicker -> Makes an object clickable 248 | this.addClicker=function(identifier,func,params) 249 | { 250 | //TODO - make this more efficient.. possibly wrap a canvas element for bigger use-cases? Or offer a canvas option? 251 | 252 | //identifier of html element -> .class, #id ..etc 253 | //func -> function to call everytime this is clicked 254 | //params -> array of parameters 255 | 256 | if (this.isDefined(identifier) && this.isDefined(func))//make sure all arguments are defined 257 | { 258 | var list; 259 | if (this.isDefined(params) && params.constructor.name !== 'Array') //only one argument passed and it wasn't passed as an array 260 | { 261 | //this allows us to add a Clicker with a single parameter function without having to use an array :) 262 | list=[params]; 263 | params=list; 264 | } 265 | 266 | if (!this.isDefined(params))//empty params 267 | { 268 | list=[]; 269 | var params=[]; 270 | } 271 | 272 | 273 | $('body').on('click', identifier, function() { /* --supports dynamic html elements as well--*/ 274 | func.apply(null,params); 275 | }); 276 | } 277 | 278 | 279 | }; 280 | 281 | this.removeClicker=function(identifier) { 282 | 283 | $(identifier).off("click");//removes clickables 284 | 285 | }; 286 | var mouse={x:-1,y:-1}; 287 | var clickerTexts=0; 288 | this.addClickerText=function(text) { 289 | 290 | clickerTexts=clickerTexts>=1000?1:clickerTexts+1; 291 | //pure jquery function 292 | 293 | //create a dynamic html elment 294 | var id="cl_"+clickerTexts; 295 | $("body").append("
"); 296 | var particle=$("#"+id); 297 | particle.css({"position":"absolute","z-index":10000}); 298 | 299 | //add it to the body 300 | $("body").append(particle); 301 | 302 | //set text 303 | particle.html(text); 304 | 305 | 306 | $("body").mousemove(function(e) { 307 | mouse.x=e.pageX; 308 | mouse.y=e.pageY; 309 | }); 310 | var xOffset=Math.floor(Math.random()*30); 311 | 312 | particle.offset({left: (mouse.x - xOffset), top: (mouse.y-20)}); 313 | 314 | particle.animate({"top": "-=100px"}, 500, "linear", function() { 315 | 316 | $(this).remove();//get rid of it... too many divs == slow page 317 | }); 318 | 319 | }; 320 | 321 | 322 | this.size=function(thing) { 323 | //gets the size of the sets variable or attributes 324 | 325 | //use this to count sets or attributes as they're associative object arrays and therefore .length cannot be used on them 326 | var size=0; 327 | var keys=Object.keys(thing); 328 | for (var i in keys) 329 | size++; 330 | return size; 331 | 332 | }; 333 | 334 | //flags 335 | 336 | this.addFlag=function(flag) { 337 | 338 | if (!(flag in Flags)) 339 | { 340 | Flags[flag]=true; 341 | return true; 342 | } 343 | else 344 | return false; 345 | 346 | } 347 | 348 | this.checkFlag=function(flag) { 349 | 350 | if (flag in Flags) 351 | { 352 | 353 | return true; 354 | 355 | } 356 | else 357 | return false; 358 | 359 | } 360 | 361 | this.removeFlag=function(flag) { 362 | 363 | if (flag in Flags) 364 | delete Flags[flag]; 365 | 366 | } 367 | 368 | 369 | //main init 370 | 371 | this.init=function(options) { 372 | 373 | //add binders 374 | $("#clicker").on("click", this.increaseScorePerClick); 375 | 376 | 377 | }; 378 | 379 | //main play function - ultimately will implement web workers and delta timers 380 | 381 | this.play=function(func) { 382 | 383 | 384 | //just need to initialize the clickers for a bit 385 | for (var i=0;i<=3;i++) 386 | { 387 | 388 | this.addClickerText(""); 389 | 390 | } 391 | 392 | 393 | //------------------------------ 394 | var interval=1000/this.getFPS(); 395 | 396 | var last=new Date() - interval; 397 | var current; 398 | var missedFrames; 399 | 400 | function gameCode() { 401 | //maintain our timers 402 | for (var i in Timers) 403 | { 404 | 405 | var n=Timers[i].n, 406 | c=Timers[i].c, 407 | period=Timers[i].period, 408 | last_executed=Timers[i].last_executed, 409 | stopped=Timers[i].stopped, 410 | times_executed=Timers[i].times_executed; 411 | //func=Timers[i].func; 412 | 413 | if (stopped) 414 | continue; 415 | 416 | //add interval time passed so far in milliseconds 417 | last_executed+=interval; 418 | if (last_executed>=period && (!stopped || times_executed=n) //check if not continuous and it has executed the number of times required 427 | { 428 | 429 | stopped=true; 430 | } 431 | 432 | } 433 | 434 | 435 | Timers[i].last_executed=last_executed; 436 | //$("#log").html(Timers.length+"c: "+c+", period: "+period+"::"+Timers[i].last_executed); 437 | 438 | Timers[i].times_executed=times_executed; 439 | Timers[i].stopped=stopped; 440 | 441 | 442 | } 443 | //done with timers 444 | 445 | //maintain our tracks 446 | for (var i in Tracks) 447 | { 448 | if (typeof Tracks[i].func === 'undefined') 449 | { 450 | 451 | Tracks[i].func=function(value) { 452 | 453 | return value; 454 | }; 455 | 456 | } 457 | 458 | 459 | var text=Tracks[i].func.apply(null,[Tracks[i].container[Tracks[i].name]]); 460 | if (text === $(Tracks[i].element).html()) 461 | continue; 462 | $(Tracks[i].element).html(text); 463 | 464 | } 465 | //done with tracks 466 | 467 | //execute our functions 468 | if (typeof func !== 'undefined') func(); 469 | } 470 | 471 | (function iterate() { 472 | gameCode(); 473 | 474 | current=+new Date(); 475 | missedFrames=Math.round((current-last) / interval) - 1; 476 | 477 | while (missedFrames-- > 0) 478 | { 479 | gameCode(); 480 | } 481 | 482 | last=+new Date(); 483 | //setTimeout(iterate, interval); 484 | 485 | //if (!window.requestAnimFrame(iterate)) //fallback 486 | setTimeout(iterate,interval); //iterate at our own interval 487 | })(); 488 | 489 | 490 | 491 | /* 492 | setInterval(function() { 493 | //maintain our tracks 494 | for (i in Tracks) 495 | $(Tracks[i].element).html(Tracks[i].container[Tracks[i].name]); 496 | 497 | //execute our functions 498 | if (typeof func !== 'undefined') func(); 499 | 500 | }, 1000/this.getFPS()); 501 | */ 502 | }; 503 | 504 | 505 | this.addTimer=function(func,options) { 506 | 507 | /*OPTIONS: 508 | 509 | * n : number of times before stopped --> default is 1 510 | * c : [true/false] continuous --> default false 511 | * period : number of seconds between execution -> default 1 --> internally stored in milliseconds 512 | 513 | *default behavior: Runs once after 1 second and then stops 514 | */ 515 | if (this.isDefined(func) && this.isDefined(options)) 516 | { 517 | var n1,c1,period1; 518 | n1=this.isDefined(options.n)?options.n:1; 519 | c1=this.isDefined(options.c)?options.c:true; 520 | period1=this.isDefined(options.period)?options.period:1; //so by default it's executed once only in one second 521 | 522 | Timers.push({func:func, n:n1, c:c1, period:period1*1000, last_executed:0, stopped:false, times_executed:0}); 523 | return true; 524 | } 525 | else 526 | { 527 | return false; 528 | } 529 | 530 | }; 531 | 532 | 533 | }; 534 | 535 | 536 | 537 | 538 | 539 | 540 | //Entitities system 541 | /* 542 | EntitySet -> name, entities[] -> collection of Entity objects, this.length 543 | Entity -> name, attributes[] -> collection of attributes/objects 544 | 545 | 546 | 547 | 548 | */ 549 | EntitySet.prototype=new Common(); 550 | function EntitySet(n_name,n_attributes) { 551 | 552 | 553 | Common.call(this,n_attributes); 554 | 555 | //Private variables 556 | var name=n_name;//name of set 557 | var entities=[];//array of Entity objects -> entities.first_upgrade 558 | 559 | //public variables 560 | this.length=0; 561 | this.entities_save=(function() { return entities; })(); 562 | this.name_save=(function() { return name; })(); 563 | //functions 564 | 565 | //ACCESSORS 566 | 567 | this.size=function() { return this.length;} 568 | 569 | this.getName=function() { return name; }; 570 | 571 | this.getEntities=function() { return entities;}; 572 | this.getSet=function() { return this.getEntities(); }; //this needs to be deprecated with our next major version 573 | 574 | this.getEntity=function(n_name) { 575 | 576 | if (typeof n_name !== 'undefined' && (n_name in entities)) 577 | { 578 | return entities[n_name]; 579 | 580 | 581 | } 582 | else 583 | return ERR_DOES_NOT_EXIST_CODE; 584 | 585 | }; 586 | 587 | this.hasEntity=function(n_name) { 588 | 589 | return (n_name in this.getEntities()); 590 | 591 | 592 | }; 593 | 594 | 595 | //MUTATORS 596 | 597 | this.addEntity=function(EntityT,attr) { 598 | 599 | //this function adds an Entity and returns 1 if successful - 0 if not 600 | if (EntityT instanceof Entity && !(EntityT.getName() in entities) && typeof attr === 'undefined') //make sure you're adding an Entity that doesn't already exist - UNIQUE NAMES 601 | { 602 | //receiving an entity object 603 | entities[EntityT.getName()]=new Entity(EntityT.getName(),EntityT.getAttributes()); 604 | this.length++; 605 | return entities[EntityT.getName()];//return this entity in this EntitySet 606 | } 607 | else if (typeof attr === 'undefined' && !(EntityT instanceof Entity) && !(EntityT in entities)) //else no attributes were given but no entity was passed either, it's just a name that we make sure doesn't exist in the current set already 608 | { 609 | entities[EntityT]=new Entity(EntityT); 610 | this.length++; 611 | return entities[EntityT]; //return this entity 612 | 613 | 614 | } 615 | else if (typeof attr !== 'undefined' && !(EntityT in entities)) //this means that the user has passed a name AND attributes, instead of an entity itself 616 | { 617 | 618 | 619 | var en=new Entity(EntityT,attr); 620 | entities[en.getName()]=en; 621 | this.length++; 622 | return entities[en.getName()];//return this entity in this EntitySet 623 | 624 | } 625 | else 626 | return ERR_INVALID_PARAMS_CODE;//either it's not an entity type but the name exists, or it is but the name exists 627 | 628 | 629 | }; 630 | 631 | this.removeEntity=function(n_name) { 632 | 633 | if (typeof n_name !== 'undefined' && (n_name in entities)) 634 | { 635 | delete entities[n_name]; 636 | this.length-=1; 637 | return SUCC_CODE; 638 | 639 | } 640 | else 641 | return ERR_DOES_NOT_EXIST_CODE; 642 | 643 | }; 644 | 645 | 646 | 647 | 648 | }; 649 | 650 | 651 | 652 | 653 | 654 | //Entity -> essential building blocks of this whole system 655 | Entity.prototype=new Common(); 656 | function Entity(n_name,n_attributes) { 657 | 658 | 659 | 660 | if (typeof n_name !== 'undefined' && typeof n_attributes === 'undefined' && n_name.constructor.name=="Entity" ) //->only n_name is passed, check if it's entity 661 | { 662 | //copy constructor CODE NOW since we were passed an entity only 663 | Common.call(this,n_name.getAttributes()); 664 | var name=n_name.getName(); 665 | 666 | 667 | } 668 | else 669 | { 670 | 671 | var name=n_name;//name of Entity -- must be unique 672 | Common.call(this,n_attributes); 673 | } 674 | 675 | 676 | //accessor/mutators 677 | this.getName=function() { return name;}; 678 | 679 | }; 680 | 681 | 682 | 683 | //AttributeSet-> regular javascript objects that hold attributes -> extended with some prototype functions 684 | 685 | //create a simple container object to hold attributes with some helper functions 686 | function AttributeSet(n_attributes) { 687 | 688 | if (typeof n_attributes !== 'undefined') 689 | { 690 | var keys=Object.keys(n_attributes); 691 | for (var i in keys) 692 | { 693 | 694 | if (keys[i] in this) //probably a prototype method 695 | { 696 | 697 | return "SPECIAL KEY"; 698 | } 699 | else 700 | { 701 | this[keys[i]]=n_attributes[keys[i]]; 702 | } 703 | } 704 | } 705 | 706 | 707 | }; 708 | 709 | AttributeSet.prototype.getAttributes=function() { 710 | //returns a COPY, not the original, list of attributes 711 | var list=[]; 712 | var keys=Object.keys(this); 713 | for (var i in keys) 714 | { 715 | if (this.hasOwnProperty(keys[i])) 716 | list[keys[i]]=this[keys[i]]; 717 | 718 | } 719 | //returns a copy 720 | return list; 721 | 722 | 723 | }; 724 | 725 | AttributeSet.prototype.getAttribute=function(attr) { 726 | //prototype for getting an attribute 727 | if (typeof attr !== 'undefined' && this.hasOwnProperty(attr)) 728 | { 729 | return this[attr]; 730 | } 731 | else 732 | return ERR_DOES_NOT_EXIST_CODE; 733 | 734 | }; 735 | 736 | AttributeSet.prototype.hasAttribute=function(attr) { 737 | //checks if it has an attribute --> returns true or false 738 | return (typeof attr !== 'undefined' && (attr in this)); 739 | 740 | }; 741 | 742 | AttributeSet.prototype.setAttribute=function(attr,value) { 743 | 744 | if (typeof attr !== 'undefined' && typeof value !== 'undefined') //a valid attr and value have been provided 745 | { 746 | 747 | this[attr]=value; 748 | return this; 749 | } 750 | else 751 | return ERR_INVALID_PARAMS_CODE; 752 | 753 | }; 754 | 755 | AttributeSet.prototype.updateAttributes=function(n_attributes) { 756 | //adds/updates multiple attributes 757 | 758 | if (typeof n_attributes !== 'undefined') 759 | { 760 | var keys=Object.keys(n_attributes); 761 | for (var i in keys) 762 | { 763 | 764 | if (keys[i] in this) //probably a prototype method 765 | { 766 | 767 | return "SPECIAL KEY"; 768 | } 769 | else 770 | { 771 | this[keys[i]]=n_attributes[keys[i]]; 772 | } 773 | } 774 | } 775 | return this; 776 | 777 | } 778 | 779 | AttributeSet.prototype.addAttribute=function(attr,value,ele,func) { 780 | 781 | //incase someone accidentally does addAttribute instead of setAttribute because we have addEntity, addSet..etc 782 | 783 | //meant to track a value 784 | if (typeof attr !== 'undefined' && typeof value !== 'undefined') //a valid attr and value have been provided 785 | { 786 | 787 | this[attr]=value; 788 | 789 | //checking if the user wants to track this variable 790 | if (typeof ele !== 'undefined')//track it in this element 791 | { 792 | Tracks.push({container:this,name:attr,element:ele,func:func}); 793 | 794 | } 795 | 796 | return this; 797 | } 798 | else 799 | return ERR_DOES_NOT_EXIST_CODE; 800 | } 801 | 802 | 803 | 804 | 805 | AttributeSet.prototype.removeAttribute=function(attr) { 806 | 807 | if (typeof attr !=='undefined' && (attr in this)) 808 | { 809 | delete this[attr]; 810 | return SUCC_CODE; 811 | } 812 | else 813 | return ERR_DOES_NOT_EXIST_CODE+" OR "+ERR_INVALID_PARAMS_CODE; 814 | 815 | }; 816 | 817 | 818 | 819 | AttributeSet.prototype.size=function() { 820 | //get total number of attributes in this object 821 | var l=0; 822 | var keys=Object.keys(this); 823 | for (var i in keys) 824 | { 825 | 826 | if (this.hasOwnProperty(keys[i])) 827 | l++; 828 | 829 | } 830 | 831 | //l++; 832 | 833 | return l; 834 | 835 | }; 836 | 837 | //prototype- tracks a particular element in an html element 838 | AttributeSet.prototype.track=function(attr,ele,func) { 839 | 840 | if (typeof attr !== 'undefined' && this.hasAttribute(attr) && typeof ele !=='undefined') 841 | { 842 | 843 | Tracks.push({container:this,name:attr,element:ele,func:func}); 844 | } 845 | else 846 | return ERR_DOES_NOT_EXIST_CODE; 847 | 848 | }; 849 | 850 | //untrack an attribute that belongs to this object 851 | AttributeSet.prototype.untrack=function(attr) { 852 | 853 | 854 | //stops tracking this.attribute's particular attribute of this particule object 855 | if (typeof attr !== 'undefined') 856 | { 857 | 858 | for (var i in Tracks) 859 | if (Tracks[i].container===this && Tracks[i].name==attr) delete Tracks[i]; 860 | 861 | } 862 | }; 863 | 864 | 865 | 866 | 867 | 868 | //=== -------------------------------------------------------------------------------- /js/incrementalObject_v1.0backup.js: -------------------------------------------------------------------------------- 1 | //incremental stuff 2 | function Game(a_fps) { 3 | 4 | if (typeof a_fps === 'undefined') 5 | a_fps=30;//default fps 6 | 7 | //PRIVATE variables 8 | var score=0; 9 | var pointsPerSecond=1; 10 | var pointsPerClick=1; 11 | var fps=a_fps; 12 | 13 | 14 | //PRIVILEGED PUBLIC -> If you want to add your own variables, here is where you would do it : this.=0; accessed by game. 15 | 16 | this.sets=[];//Holds multiple ENTITY SETS -> eg. this can hold UPGRADES, ACHIEVEMENTS, INVENTORY..etc 17 | //accessed by game.entities. -> eg. game.sets.UPGRADES 18 | 19 | this.attributes=[];//holds additional attributes/variables 20 | 21 | 22 | //adds a set to sets 23 | this.addSet=function(n_name) { 24 | if (!(n_name instanceof EntitySet)) //if the passed parameter is not an entity set itself 25 | //create a new empty entity set with the name given 26 | 27 | this.sets[n_name]=new EntitySet(n_name); 28 | else 29 | { //store the entity set 30 | this.sets[n_name.getName()]=n_name; 31 | } 32 | 33 | 34 | }; 35 | 36 | //gets the size of the sets variable or attributes 37 | this.size=function(thing) { 38 | //use this to count sets or attributes as they're associative object arrays and therefore .length cannot be used on them 39 | var size=0; 40 | var keys=Object.keys(thing); 41 | for (i in keys) 42 | size++; 43 | return size; 44 | 45 | }; 46 | 47 | 48 | //ACCESSOR METHODS 49 | this.getFPS=function() { return fps; }; //get fps of game 50 | 51 | this.getScore = function() { return Math.ceil(score); }; //get score 52 | 53 | this.getPointsPerSecond=function() { return pointsPerSecond; }; //return the main pointsPerSecond that affects the score 54 | 55 | 56 | //MUTATOR METHODS 57 | this.increasePointsPerSecond=function() { 58 | //increment the pointsPerSecond 59 | pointsPerSecond+=0.5; 60 | 61 | }; 62 | 63 | this.increaseScorePerSecond=function() { 64 | //increment the score per second 65 | score+=pointsPerSecond/fps; 66 | 67 | }; 68 | 69 | this.increaseScorePerClick=function() { 70 | //increment the score per click 71 | score+=pointsPerClick; 72 | 73 | 74 | }; 75 | 76 | this.addToScore=function(value) { 77 | //adds 'value' to score 78 | score+=value; 79 | 80 | 81 | }; 82 | 83 | this.addToPointsPerSecond=function(value) { 84 | //adds 'value' to pointsPerSecond 85 | pointsPerSecond+=value; 86 | }; 87 | 88 | this.addToPointsPerClick=function(value) { 89 | //adds 'value' to pointsPerClick 90 | pointsPerClick+=value; 91 | 92 | }; 93 | }; 94 | 95 | Game.prototype.init=function() { 96 | 97 | 98 | //add binders 99 | $("#clicker").on("click", this.increaseScorePerClick); 100 | 101 | }; 102 | 103 | 104 | 105 | 106 | 107 | 108 | //upgrades/Entitys system 109 | 110 | function EntitySet(n_name) { 111 | 112 | var name=n_name;//name of set 113 | var entities=[];//array of Entity objects -> entities.first_upgrade 114 | 115 | //public variables 116 | this.length=0; 117 | 118 | //functions 119 | 120 | this.size=function() { return this.length;} 121 | 122 | this.getName=function() { 123 | 124 | return name; 125 | 126 | }; 127 | 128 | this.getSet=function() { 129 | //returns Entity set 130 | return entities; 131 | 132 | }; 133 | 134 | 135 | this.addEntity=function(EntityT) { 136 | //this function adds an Entity and returns 1 if successful - 0 if not 137 | 138 | if (EntityT instanceof Entity && !(EntityT.getName() in entities)) //make sure you're adding an Entity that doesn't already exist - UNIQUE NAMES 139 | { 140 | entities[EntityT.getName()]=EntityT; 141 | this.length++; 142 | return 1; 143 | } 144 | else 145 | return -999;//either it' snot an entity type, or it is but the name already exists 146 | 147 | 148 | }; 149 | 150 | 151 | }; 152 | 153 | function Entity(n_name,n_attributes) { 154 | 155 | var name=n_name;//name of Entity -- must be unique 156 | this.attributes=[]; 157 | 158 | //populate attributes 159 | var keys=Object.keys(n_attributes); 160 | for (i in keys)//get the keys 161 | this.attributes[keys[i]]=n_attributes[[keys[i]]]; // 162 | 163 | 164 | //accessor/mutators 165 | this.getName=function() { 166 | 167 | return name; 168 | 169 | }; 170 | 171 | this.getAttribute=function(attr) { 172 | if (attr in this.attributes) 173 | return this.attributes[attr]; 174 | else 175 | return -999; 176 | 177 | }; 178 | 179 | this.setAttribute=function(attr,value) { 180 | 181 | if (attr in this.attributes) 182 | this.attributes[attr]=value; 183 | 184 | }; 185 | 186 | }; 187 | 188 | 189 | //=== 190 | -------------------------------------------------------------------------------- /js/particleObject.js: -------------------------------------------------------------------------------- 1 | 2 | //particle object 3 | function Particle(x,y) { 4 | 5 | this.type="circle"; 6 | this.x=x; 7 | this.y=y; 8 | this.size=0.5; 9 | this.opacity=rand(0.5,10); 10 | this.moveSpeed=this.opacity/10 * 2; 11 | this.modifier=0; 12 | }; 13 | 14 | Particle.prototype.draw=function() { 15 | this.x-=(this.moveSpeed+this.modifier); 16 | if (this.x < 0) this.x=screenWidth; 17 | ctx.save(); 18 | ctx.beginPath(); 19 | ctx.globalAlpha=this.opacity/10; 20 | ctx.fillStyle="white"; 21 | ctx.arc(this.x,this.y,this.size,0,2*Math.PI,false); 22 | ctx.fill(); 23 | ctx.restore(); 24 | 25 | }; -------------------------------------------------------------------------------- /tutorials/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aldo111/incremental-game-engine-js/0e3a53301ff440203a4aac02d941955e9a777cb5/tutorials/.DS_Store -------------------------------------------------------------------------------- /tutorials/1/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Hello IncrementalJS w/v1.6 8 | 9 | 10 | 11 | 12 | 13 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | Points: 87 | 88 | 89 |
90 | 91 | Points Per Second: 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /tutorials/1/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Tutorials 8 | 9 | 10 | 11 | 162 | 163 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 |

Tutorial 1: Hello IncrementalJS

199 |
200 |
201 | Purpose 202 |
203 | 204 |
205 | To get started with IncrementalJS 206 |
207 | 208 |
What should you be able to do by the end of this tutorial?
209 |
210 | 211 |
    212 |
  • Initialize and run a very simple incremental game in minutes
  • 213 |
  • Add variables known as 'attributes' to your game
  • 214 |
  • Track attribute values in HTML elements - in real-time
  • 215 |
  • Add Click events to any HTML element on your page to do cool stuff
  • 216 |
  • Pat yourself on the back because you did great!
  • 217 |
218 |
219 |
220 | 221 |
222 | 223 | 224 | 225 |
226 | 227 |
228 | 1. Setting Up 229 |
230 |
231 | 1aStarting Web Page 232 |
233 | The IncrementalJS Library consists of Javascript objects that help you focus on your game logic with a structure to work with and some really useful features. Over the next few parts in this tutorial, we will examine what these features are and how they help! 234 |

235 | For this tutorial, let's use the following blank HTML template: 236 |
<!DOCTYPE HTML>
237 | 
238 | <html>
239 | 
240 | 	<head>
241 | 	
242 | 		<title>Hello IncrementalJS</title>
243 | 		
244 | 	</head>
245 | 	
246 | 	<body>
247 | 	
248 | 	
249 | 	
250 | 	</body>
251 | 	
252 | </html>
253 | 
254 |
1a. The HTML skeleton we want to start with!
255 | 256 | Now, the use of this library is directed towards those who, at the very least, have limited Javascript experience and assumes some HTML and CSS knowledge. 257 |
Regardless, if you are a complete beginner to HTML/CSS/Javascript, then here's a brief breakdown of the 3 using the human body as an analogy: 258 |
259 | For HTML/CSS/JS beginners 260 |
261 |
262 | HTML (HyperText Markup Language) - the code above - provides the basic skeleton/structure of the page

263 | CSS (Cascading Style Sheets) - we'll see examples later - provides the style/looks/visuals/formatting for the Skeleton written in HTML

264 | Javascript (the 'JS' in IncrementalJS) - a dynamic programming language for the web, in particular client-side (the browser/user's computer side/offline side) - provides dynamic functionality for our pages. 265 |

266 | So, in keeping with the body analogy, 267 |
HTML provides the skeleton and its components such as the arms, legs, head, eyes ..etc, 268 |
CSS makes the eyes look like eyes, the head look like a head, and so on 269 |
Javascript is the code nature embedded in our brains to do things with our different components, and lets our brain process information when we touch something 270 |
271 |
272 |
273 | 274 | 1b Files Required
275 |
276 | Alright so now, let's include the files we require. Currently, the only dependency/external file required by this library is jQuery to carry out certain functionality. It will not be required soon, but for now let's go ahead and include it. 277 |
<!DOCTYPE HTML>
278 | 
279 | <html>
280 | 
281 | 	<head>
282 | 	
283 | 		<title>Hello IncrementalJS</title>
284 | 		<script src="http://aldo111.github.io/incremental-game-engine-js/js/incrementalObject.js"></script>
285 | 		<script src="http://aldo111.github.io/incremental-game-engine-js/js/jquery.js"></script>
286 | 		
287 | 		<!--Our Javascript Code-->
288 | 		<script type="text/javascript">
289 | 		
290 | 		
291 | 		</script>
292 | 		
293 | 		
294 | 	</head>
295 | 	
296 | 	<body>
297 | 	
298 | 	
299 | 	
300 | 	</body>
301 | 	
302 | </html>
303 | 
304 | 305 |
1b. The files we need and script tags for our own javascript code
306 | 307 | As you can see, there is another <script> block, which is where all our Javascript code will go into! 308 |
309 | Note: Placement of Javascript in HTML 310 |
311 |
312 | Many like to place their main Javascript code at the end of the body tags. This is completely alright and normally doesn't make much of a difference in ordinary usage scenarios. It's typically done to let the relevant page elements load/render before getting to the javascript, and is helpful in animation heavy/dynamic pages. This can usually be taken care of, though, using window.onload or other methods such as document.onreadystatechange depending on your use-case and browser support. 313 | 314 | 315 |
316 |
317 |
318 | 319 | 1c Our Demo Setup
320 |
321 | 322 | We need some kind of idea to test this stuff with, right? So let's come up with a VERY simple demo, a standard 'Hello World' of sorts for Incremental Games, where all we do is Earn 1 point per click - and for 10 points we can buy an upgrade that gives us 2 points per second! 323 |

324 | Let's add the following HTML that consists of 325 |
    326 |
  • 2 buttons (one to earn points and one to buy the upgrade that allows us to get some points per second)
  • 327 |
  • 1 element to show our points, and
  • 328 |
  • 1 element to show how many points per second we earn
  • 329 |
330 | 331 |
<body>
332 | 
333 | 	Points: <span id="points"></span>
334 | 	<input type='button' id='earn' value='Earn Points'>
335 | 	
336 | 	<hr>
337 | 	
338 | 	Points Per Second: <span id="points_per_second"></span>
339 | 	<input type='button' id='getSome' value='Get Some!'>
340 | 
341 | 
342 | 
343 | </body>
344 | 
345 |
1c. Our View/Interface/Display setup
346 | 347 |

348 | Similarly, we need to setup our Javascript code.

349 | Most setups can simply be broken down into 3(maybe even 2 if you combine the first two) steps: 350 |
    351 |
  • Declaration - Declare and Include variables/scripts/functions/objects used
  • 352 |
    We've already included the 2 Javascript files we need.. in addition to that, we need a variable to store IncrementalJS' Game object, a variable to store our points, and a variable to store how many points we earn per second
    353 |
  • Initialization - Initialize all our variables and/or objects
  • 354 |
    We'll need a function where we can do all our initializations in one organized place
    355 |
  • Execution - Execute our main code.. in this case, our game loop
  • 356 |
    We'll need a function where we can write code that needs to be executed in every loop of the game
    357 |
358 |
359 | Let's also not forget that we actually have to invoke these functions in order for cool things to happen! 360 | 361 |
<!--Our Javascript Code-->
362 | <script type="text/javascript">
363 | 
364 | 	//Variable Declarations & Initializations
365 | 	var game;
366 | 	
367 | 	
368 | 	//the init() function initializes or sets up our game
369 | 	function init()
370 | 	{
371 | 		
372 | 		game=new Game();
373 | 		game.play(play);//Tells the Game() object's play() function that we want to execute the code in our play() function for every loop iteration in the game loop
374 | 		
375 | 	}
376 | 	
377 | 	//the play() function contains essential game code
378 | 	function play() 
379 | 	{
380 | 		
381 | 	}
382 | 	
383 | 	//this checks if the window has loaded - includes the document, and all objects/elements in it - and executes the function init() when it has
384 | 	window.onload=init;
385 | 
386 | </script>
387 | 
388 |
1c. Our Javascript Setup
389 | That's our lovely, elegant setup! And look, we also created our new Incremental Game object as well as executed our game loop - the game.play(play) kicks off our game loop!. 390 | 391 |
392 | Game() 393 |
394 |
395 | The Game() object is IncrementalJS' main object through which almost everything is done! Upon creating a new Game object as above, its internal variable, fps (denotes Frames Per Second - number of times play() is executed per second), is by default set to 1. You can however choose to use a different FPS by doing simply doing:
396 | game=new Game(30); //initializes to 30fps
Caution: If your game loop performs any numeric operations such as addition, you will want to take into account the FPS through game.getFPS() so that you don't increase/decrease values too fast within a particular period of time. We'll see an example near the end in our demo.


397 | The Game() object's play(...) function takes a function as an argument and it runs the game loop every 'FPS' times per second, where FPS is the FPS specified - it even runs in the background! 398 |
399 | 400 | But, where are the other two variables we mentioned? And what do we with play() ? When we refresh, we see nothing different than what we had before this javascript. So how do we make things work?
401 | For that, we need to look at two things: Attributes and Clickers 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 |
410 |
411 | 412 |

413 | 414 |
415 | 2. Attributes and Trackers 416 |
417 |
418 | 419 | 2aWhat are Attributes? 420 |
421 | 422 | If you've seen the Documentation (which you should), you'll see an object called AttributeSet and an object called Common. 423 |
424 | Common contains variables and functions that are common to and required by each Game, EntitySet, and Entity.
425 | But more specifically, it contains one variable called 'attributes', which is simply - an AttributeSet.
426 | AttributeSet is an empty javascript object with some helpful Prototype methods (core functions available to all AttributeSets). This stores 'attributes' or variables that we can keep track of in an organized manner in each type of object - whether in the context of Game, an EntitySet, or an Entity. 427 | 428 | 429 |
430 |
431 | 2bK, so AttributeSet is just a glorified object that stores my variables. Now what? How do I use it to make my game? 432 |
433 | 434 | :( .. Pretty simple: 435 |
436 | 
437 | //the init() function initializes or sets up our game
438 | function init()
439 | {
440 | 	//create Game() instance	
441 | 	game=new Game();
442 | 	
443 | 	//add attributes
444 | 	game.addAttribute("Points",0);
445 | 	game.addAttribute("PointsPerSecond",0);
446 | 	
447 | 	/* 
448 | 		I can also do the following:
449 | 	
450 | 			game.addAttribute("Points",0).addAttribute("PointsPerSecond",0); 
451 | 			
452 | 	
453 | 		Hurray for chaining! This works because addAttribute returns the AttributeSet itself
454 | 		So you can reuse its functions. There's a lot of chaining in IncrementalJS!
455 | 	*/
456 | 
457 | 	game.play(play);
458 | 	
459 | }
460 | 
461 | 
462 |
2b. Adding attributes
463 | 464 |
465 | AttributeSet/Common 466 |
467 |
468 | Other than addAttribute, there is also a setAttribute function which is used in the same exact way as addAttribute. Both can be used to update values or add new ones, but setAttribute is semantically used only to update an attribute, while addAttribute can be used to 'track' attributes in shorthand. 469 |

470 | In order to access an attribute, you can do any of the following:
471 |
    472 |
  • Object.getAttribute("name_of_attribute") - eg. game.getAttribute("Points")
  • 473 |
  • Object.attributes.name_of_attribute - eg. game.attributes.Points (only works when you have non-spaced attribute names)
  • 474 |
  • Object.attributes["name_of_attribute"] - eg. game.attributes["Points"] - for when you have spaces 475 |
476 |
477 | 478 | If you refresh now, do you see anything cool? Nope, because nothing's changed in our view! We don't even see a damn number!
479 | So how do we modify the view? It's simple, We kill the Batm- we use Trackers 480 | 481 | 482 | 483 |
484 |
485 | 2cTrackers 486 |
487 | Trackers are simply little ..cameras that watch your variables in the locker room as they change and display them in the HTML element of your choice!
488 | 489 | There are many different ways to 'track' attributes.. and you can further customize how you want each value to be displayed! 490 | 491 |
492 | //1. Primary way to track
493 | game.addAttribute("Points",0);
494 | game.track("Points","#points");
495 | 
496 | //2. Chaining - AttributeSets also have track/untrack methods
497 | game.addAttribute("Points",0).track("Points","#points");
498 | 
499 | //3. Short-Hand
500 | game.addAttribute("Points",0,"#points"); //note: this will only work with addAttribute, not setAttribute
501 | 
502 | //------CUSTOM DISPLAY------\\
503 | //Very cool extra feature - each of these tracking methods take an additional argument as a function
504 | //this function, should you supply one, should return the string you want to be displayed
505 | //in place of the tracked value - also note: the function receives the value as an argument, so have a parameter called 'value'
506 | //By default, in IncrementalJS, this function simply returns the tracked attribute value
507 | 
508 | game.track("Points","#points", function (value) {
509 | 	
510 | 	return Math.round(value); //will only display a rounded value
511 | });
512 | 
513 | game.addAttribute("Points",0,"#points",function (value) {
514 | 	
515 | 	return Math.round(value); //will only display a rounded value
516 | });
517 | 
518 | 
519 |
2c. The many ways by which you can track, and custom-display, attribute values
520 | 521 | Okay, that's kinda cool. So you're telling me I don't have to do another document.getElementById(".....").innerHTML?
522 | Yep! The only catch here, as you can see in the code, is that you need to supply the 'tag' that is associated with how you identify an element. So, if you're identifying an element by its id, like we are with our <span id="points">, then we provide a # (hash). If we want to identify by a class, we use a . prefix (.points). Otherwise, we just type the name of the element in (div, span, p, ..etc). 523 | 524 | 525 | Cool, so now let's use this in our little game? 526 |
Absolutely! 527 | 528 |
<!--Our Javascript Code-->
529 | <script type="text/javascript">
530 | 
531 | 	//Variable Declarations & Initializations
532 | 	var game;
533 | 	
534 | 	
535 | 	//the init() function initializes or sets up our game
536 | 	function init()
537 | 	{
538 | 		//create Game() instance	
539 | 		game=new Game();
540 | 		
541 | 		//add attributes
542 | 		game.addAttribute("Points",0).track("Points","#points");
543 | 		game.addAttribute("PointsPerSecond",0,"#points_per_second");
544 | 		
545 | 		
546 | 		
547 | 		game.play(play);
548 | 		
549 | 			
550 | 	}
551 | 	
552 | 	//the play() function contains essential game code
553 | 	function play() 
554 | 	{
555 | 		
556 | 		
557 | 	}
558 | 	
559 | 	//this checks if the window has loaded - includes the document, and all objects/elements in it - and executes the function init() when it has
560 | 	window.onload=init;
561 | 
562 | </script>
563 | 
564 |
2c. Our Javascript so far
565 | Go ahead, refresh your page! 566 |
567 | Great, I can now see 0s. But the buttons don't do anything? 568 |
Ah yes, for that, let's check out.. 569 | 570 | 571 |
572 | 573 | 574 | 575 | 576 | 577 |
578 | 579 |

580 | 581 |
582 | 3. Clickers 583 |
584 |
585 | 586 | 3aWhat are Clickers? 587 |
588 | Clickers are HTML elements that have been associated with a click event through the Game object! Only the Game() object comes with an addClicker(...) method.
589 | 590 |
591 |
592 | 3bHow do I use one 593 |
594 | Let's see, if we wanted to make our 'Earn Points' button clickable and actually earn us points, we can just do: 595 |
596 | //add clickers
597 | game.addClicker("#earn",function() { 
598 | 	game.attributes.Points+=2;
599 | });
600 | 
601 | 
602 | 
603 |
3b. How to use a clicker [Refer to the documentation for additional parameter]
604 | 605 | Essentially, you provide the identifier/class/name of the element you want to make clickable, and give it a function to execute on click. We provided an anonymous function function with our code that will henceforth always be executed whenever #earn is clicked. 606 | 607 | Great, click-event handling taken care of. What about the other button? 608 |
The syntax for addClicker stays the same, but the code inside our anonymous function will, obviously, be a bit more complex. 609 | 610 |
611 | game.addClicker("#getSome", function() {
612 | 	//this function also shows another way to access attributes
613 | 	var p=game.getAttribute("Points");
614 | 	var cost=10;
615 | 	var increase=2;
616 | 	
617 | 	if (p>=cost)
618 | 	{
619 | 		//we can buy
620 | 		p-=cost;
621 | 		game.setAttribute("Points",p);
622 | 		var pps=game.getAttribute("PointsPerSecond");
623 | 		pps+=increase;
624 | 		game.setAttribute("PointsPerSecond",pps);
625 | 	}
626 | 		
627 | 	
628 | 	
629 | 	
630 | });
631 | 
632 |
3b. Code to actually buy stuff - this also shows a different way to access attributes
633 | 634 |
635 | Great, so we have our clickers in place! Let's put it all together! 636 |
637 |
638 | 3cPutting things together 639 |
640 | 641 |
<script>
642 | //the init() function initializes or sets up our game
643 | function init()
644 | {
645 | 	//create Game() instance	
646 | 	game=new Game();
647 | 	
648 | 	//add attributes
649 | 	game.addAttribute("Points",0).track("Points","#points", function(value) { return value.toFixed(0); });
650 | 	game.addAttribute("PointsPerSecond",0,"#points_per_second");
651 | 	
652 | 	//add clickers
653 | 	game.addClicker("#earn",function() { 
654 | 		game.attributes.Points+=2;
655 | 	});
656 | 	
657 | 	game.addClicker("#getSome", function() {
658 | 		//this function also shows another way to access attributes
659 | 		var p=game.getAttribute("Points");
660 | 		var cost=10;
661 | 		var increase=2;
662 | 		
663 | 		if (p>=cost)
664 | 		{
665 | 			//we can buy
666 | 			p-=cost;
667 | 			game.setAttribute("Points",p);
668 | 			var pps=game.getAttribute("PointsPerSecond");
669 | 			pps+=increase;
670 | 			game.setAttribute("PointsPerSecond",pps);
671 | 		}
672 | 			
673 | 		
674 | 		
675 | 		
676 | 	});
677 | 	
678 | 	//play
679 | 	game.play(play);
680 | 	
681 | 		
682 | }
683 | </script>
684 | 
685 |
3c. Our Init function
686 | 687 | You'll notice I added an anonymous function to the track() method for the first attribute, Points. If you recall from the sub-section on trackers (2c), this is an optional function that takes in one parameter, the value of the attribute being tracked, and returns the way it should be displayed. I have simply set it to return no decimals, only the integer itself, in case I decide to change cost from 2 to some other decimal value. 688 |
689 | If you refresh your game and try playing it, you'll notice you can earn points and buy more 'Points Per Second'. However, nothing actually happens 'per second'. This is where our play() function comes in handy. 690 | 691 |
692 | //the play() function contains essential game code
693 | function play() 
694 | {
695 | 	
696 | 	//here we see another way to get/update attributes more quickly
697 | 	var g=game.attributes;
698 | 	g["Points"]+=g["PointsPerSecond"]/game.getFPS(); 
699 | 	//divide by FPS because we have to take into account the Frames Per Second when adding anything per Second,
700 | 	
701 | 	
702 | }
703 | 
704 | 
705 |
3c. the play() function - also demonstrating yet another way to access attributes
706 |
707 | Fairly straightforward, right?
708 | We're accessing the Points attribute directly and adding to it the PointsPerSecond attribute, since it does make sense. 709 | 710 | But wait, why are we dividing the points added per second by the game's FPS - the game's FPS is 1 by default, so it doesn't matter right? 711 |
712 | Yes, in its current state - the FPS of the game is 1 and so the division is unnecessary. But what if you decide to set the FPS to 10, or 15, or 30?
713 |
Let's do the math to see what happens if we exclude the divided-by-game.getFPS() and the FPS is 10 714 |
715 | Suppose the PPS (points per second) is 2. The play() loops runs 10 times (frames) per second.
716 | Expected Behaviour: In 1 second, the Points attribute should increase by 2.
717 | Actual Behaviour: In 1 second, the Points attribute increases by 20 per second, because 2 was added 10 times per second.
718 |
719 | Hence, in such operations, make sure you factor in the FPS, whether it is 30 or 1 (to be safe). By dividing the FPS here, we are basically adding up 10 parts of 2 in the span of 1 second. 1/10th of 2 is 1/5. So by adding 1/5 ten times to the Points attribute, we get 2 in one second!
720 | 721 | 10-15 FPS is a good choice because it also updates the tracked variables quicker. Currently, clicking on either button doesn't update the displayed corresponding attribute immediately - the trackers waits until the next loop iteration to update, so we would have to manually throw in a Javascript/HTML text manipulation in our click functions.
722 | Increasing the FPS would alleviate this problem at this scale. 723 | 724 | 725 | 726 |
727 | 728 |
729 | 730 |

731 | 732 |
733 | Final Code - Play with it and make it more interesting 734 |
735 |
736 | 737 |
<!DOCTYPE HTML>
738 | 
739 | <html>
740 | 
741 | 	<head>
742 | 	
743 | 		<title>Hello IncrementalJS</title>
744 | 		<script src="incremental-game-engine-js/js/incrementalObject.js"></script>
745 | 		<script src="http://aldo111.github.io/incremental-game-engine-js/js/jquery.js"></script>
746 | 		
747 | 		<!--Our Javascript Code-->
748 | 		<script type="text/javascript">
749 | 		
750 | 			//Variable Declarations & Initializations
751 | 			var game;
752 | 			
753 | 			
754 | 			//the init() function initializes or sets up our game
755 | 			function init()
756 | 			{
757 | 				//create Game() instance	
758 | 				game=new Game(30);
759 | 				
760 | 				//add attributes
761 | 				game.addAttribute("Points",0).track("Points","#points", function(value) { return value.toFixed(0); });
762 | 				game.addAttribute("PointsPerSecond",0,"#points_per_second");
763 | 				
764 | 				//play
765 | 				game.play(play);
766 | 				
767 | 				//add clickers
768 | 				game.addClicker("#earn",function() { 
769 | 					game.attributes.Points+=2;
770 | 					game.addClickerText("+2");//adds clicker/particle text - still under works!
771 | 				});
772 | 				
773 | 				game.addClicker("#getSome", function() {
774 | 					//this function also shows another way to access attributes
775 | 					var p=game.getAttribute("Points");
776 | 					var cost=10;
777 | 					var increase=2;
778 | 					
779 | 					if (p>=cost)
780 | 					{
781 | 						//we can buy
782 | 						p-=cost;
783 | 						game.setAttribute("Points",p);
784 | 						var pps=game.getAttribute("PointsPerSecond");
785 | 						pps+=increase;
786 | 						game.setAttribute("PointsPerSecond",pps);
787 | 					}
788 | 						
789 | 					
790 | 					
791 | 					
792 | 				});
793 | 				
794 | 				
795 | 				
796 | 					
797 | 			}
798 | 			
799 | 			//the play() function contains essential game code
800 | 			function play() 
801 | 			{
802 | 				
803 | 				//here we see another way to get/update attributes more quickly
804 | 				var g=game.attributes;
805 | 				g["Points"]+=g["PointsPerSecond"]/game.getFPS(); 
806 | 				//divide by FPS because we have to take into account the Frames Per Second when adding anything per Second, because this play() loop is execute game.getFPS() times per second!
807 | 				
808 | 				
809 | 			}
810 | 			
811 | 			//this checks if the window has loaded - includes the document, and all objects/elements in it - and executes the function init() when it has
812 | 			window.onload=init;
813 | 		
814 | 		</script>
815 | 		
816 | 		
817 | 	</head>
818 | 	
819 | 	<body>
820 | 	
821 | 		Points: <span id="points"></span>
822 | 		<input type='button' id='earn' value='Earn Points'>
823 | 		
824 | 		<hr>
825 | 		
826 | 		Points Per Second: <span id="points_per_second"></span>
827 | 		<input type='button' id='getSome' value='Get Some!'>
828 | 	
829 | 	
830 | 	
831 | 	</body>
832 | 	
833 | </html>
834 | 
835 | 836 | 837 |
838 | 839 | 840 |
841 | Wrap-Up 842 |
843 | 844 |
845 | So that's pretty much it! There are a lot more small-medium-big features, such as flags, timers for functions, particle/clickerTexts (I threw in a clickerText in the code above, it should popup when you click Earn Points) the other objects EntitySet and Entity - I will post a tutorial on these soon as well!

846 | I really hope, despite the length of this tutorial to convey the creation of a very simply test - you find this library useful and I welcome any and all suggestions! I encourage you to read the Documentation if you are interested in knowing about the other things and are willing to try experimenting with them!

847 | I previously made a game after v1.5, Descent so you are welcome to examine the Javascript portion of the source code, in particular the init() function, to see how EntitySets and/or Entities are used! 848 | 849 | 850 |
851 | 852 | 853 | 854 | 855 |
856 | 857 | 858 | 859 | 860 | 861 | 862 | 863 | 864 | 865 | 866 | -------------------------------------------------------------------------------- /tutorials/v1.1 Working Tutorial/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aldo111/incremental-game-engine-js/0e3a53301ff440203a4aac02d941955e9a777cb5/tutorials/v1.1 Working Tutorial/.DS_Store -------------------------------------------------------------------------------- /tutorials/v1.1 Working Tutorial/css/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aldo111/incremental-game-engine-js/0e3a53301ff440203a4aac02d941955e9a777cb5/tutorials/v1.1 Working Tutorial/css/.DS_Store -------------------------------------------------------------------------------- /tutorials/v1.1 Working Tutorial/css/incremental_style.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | * { 4 | 5 | margin:0; 6 | padding:0; 7 | -webkit-touch-callout: none; 8 | -webkit-user-select: none; 9 | -khtml-user-select: none; 10 | -moz-user-select: none; 11 | -ms-user-select: none; 12 | user-select: none; 13 | } 14 | 15 | 16 | body { 17 | width:100%; 18 | background-color:white; 19 | color:black; 20 | font-family:Georgia; 21 | 22 | } 23 | 24 | 25 | #available_houses { 26 | position:relative; 27 | width:100%; 28 | background-color:orange; 29 | min-height:100px; 30 | padding-top:10px; 31 | text-align:center; 32 | 33 | } 34 | 35 | #available_houses .house { 36 | 37 | width:80px; 38 | height:80px; 39 | border:2px solid black; 40 | background-color:white; 41 | opacity:0.8; 42 | border-radius:5px; 43 | margin:5px; 44 | display:inline-block; 45 | cursor:pointer; 46 | 47 | } 48 | 49 | #money { 50 | 51 | border:2px solid black; 52 | font-size:20pt; 53 | text-align:center; 54 | 55 | } 56 | 57 | header { 58 | 59 | background-color:orange; 60 | opacity:0.6; 61 | color:white; 62 | font-size:25pt; 63 | text-align:center; 64 | 65 | border-bottom:2px solid black; 66 | 67 | } 68 | 69 | #clicker { 70 | 71 | background-color:black; 72 | color:white; 73 | border:2px solid #00aaff; 74 | cursor:pointer; 75 | border-radius:5px; 76 | height:100px; 77 | width:200px; 78 | margin:0 auto; 79 | 80 | } 81 | 82 | #clicker:active, .house:active { 83 | 84 | background-color:#00aaff; 85 | 86 | } -------------------------------------------------------------------------------- /tutorials/v1.1 Working Tutorial/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Our First Game, Yay! 9 | 10 | 11 | 12 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 |
116 | GOLD HOUSE 117 |
118 |
119 |
120 |
121 | Money:
122 | 123 |
124 | Do your regular job 125 |
126 |
127 | Per Second:
128 | Per Click: 129 |
130 | 131 | 132 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /tutorials/v1.1 Working Tutorial/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Our First Game, Yay! 9 | 10 | 11 | 12 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | Template page 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /tutorials/v1.1 Working Tutorial/js/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aldo111/incremental-game-engine-js/0e3a53301ff440203a4aac02d941955e9a777cb5/tutorials/v1.1 Working Tutorial/js/.DS_Store -------------------------------------------------------------------------------- /tutorials/v1.1 Working Tutorial/js/incrementalObject.js: -------------------------------------------------------------------------------- 1 | //incremental stuff 2 | function Game(a_fps) { 3 | 4 | if (typeof a_fps === 'undefined') 5 | a_fps=30;//default fps 6 | 7 | //PRIVATE variables 8 | var score=0; 9 | var pointsPerSecond=0; 10 | var pointsPerClick=0; 11 | var fps=a_fps; 12 | 13 | 14 | //PRIVILEGED PUBLIC -> If you want to add your own variables, here is where you would do it : this.=0; accessed by game. 15 | 16 | this.sets=[];//Holds multiple ENTITY SETS -> eg. this can hold UPGRADES, ACHIEVEMENTS, INVENTORY..etc 17 | //accessed by game.entities. -> eg. game.sets.UPGRADES 18 | 19 | this.attributes=[];//holds additional attributes/variables 20 | 21 | 22 | //adds a set to sets 23 | this.addSet=function(n_name) { 24 | if (!(n_name instanceof EntitySet)) //if the passed parameter is not an entity set itself 25 | //create a new empty entity set with the name given 26 | 27 | this.sets[n_name]=new EntitySet(n_name); 28 | else 29 | { //store the entity set 30 | this.sets[n_name.getName()]=n_name; 31 | } 32 | 33 | 34 | }; 35 | 36 | //gets the size of the sets variable or attributes 37 | this.size=function(thing) { 38 | //use this to count sets or attributes as they're associative object arrays and therefore .length cannot be used on them 39 | var size=0; 40 | var keys=Object.keys(thing); 41 | for (i in keys) 42 | size++; 43 | return size; 44 | 45 | }; 46 | 47 | 48 | //ACCESSOR METHODS 49 | this.getFPS=function() { return fps; }; //get fps of game 50 | 51 | this.getScore = function() { return Math.ceil(score); }; //get score 52 | 53 | this.getPointsPerSecond=function() { return pointsPerSecond; }; //return the main pointsPerSecond that affects the score 54 | 55 | this.getPointsPerClick=function() { return pointsPerClick; }; //return the main pointsPerClick that affects the score 56 | 57 | 58 | //MUTATOR METHODS 59 | this.increasePointsPerSecond=function() { 60 | //increment the pointsPerSecond 61 | pointsPerSecond+=0.5; 62 | 63 | }; 64 | 65 | this.increaseScorePerSecond=function() { 66 | //increment the score per second 67 | score+=pointsPerSecond/fps; 68 | 69 | }; 70 | 71 | this.increaseScorePerClick=function() { 72 | //increment the score per click 73 | score+=pointsPerClick; 74 | 75 | 76 | }; 77 | 78 | this.addToScore=function(value) { 79 | //adds 'value' to score 80 | score+=value; 81 | 82 | 83 | }; 84 | 85 | this.addToPointsPerSecond=function(value) { 86 | //adds 'value' to pointsPerSecond 87 | pointsPerSecond+=value; 88 | }; 89 | 90 | this.addToPointsPerClick=function(value) { 91 | //adds 'value' to pointsPerClick 92 | pointsPerClick+=value; 93 | 94 | }; 95 | }; 96 | 97 | Game.prototype.init=function() { 98 | 99 | 100 | //add binders 101 | $("#clicker").on("click", this.increaseScorePerClick); 102 | 103 | }; 104 | 105 | 106 | 107 | 108 | 109 | 110 | //upgrades/Entitys system 111 | 112 | function EntitySet(n_name) { 113 | 114 | var name=n_name;//name of set 115 | var entities=[];//array of Entity objects -> entities.first_upgrade 116 | 117 | //public variables 118 | this.length=0; 119 | 120 | //functions 121 | 122 | this.size=function() { return this.length;} 123 | 124 | this.getName=function() { 125 | 126 | return name; 127 | 128 | }; 129 | 130 | this.getSet=function() { 131 | //returns Entity set 132 | return entities; 133 | 134 | }; 135 | 136 | 137 | this.addEntity=function(EntityT,attr) { 138 | //this function adds an Entity and returns 1 if successful - 0 if not 139 | 140 | if (EntityT instanceof Entity && !(EntityT.getName() in entities) && typeof attr === 'undefined') //make sure you're adding an Entity that doesn't already exist - UNIQUE NAMES 141 | { 142 | //receiving an entity object 143 | entities[EntityT.getName()]=EntityT; 144 | this.length++; 145 | return 1; 146 | } 147 | else if (typeof attr !== 'undefined') 148 | { 149 | //this means that the user has passed a name and attributes, instead of an entity itself 150 | var en=new Entity(EntityT,attr); 151 | entities[en.getName()]=en; 152 | this.length++; 153 | return 1; 154 | 155 | } 156 | else 157 | return -999;//either it' snot an entity type, or it is but the name already exists 158 | 159 | 160 | }; 161 | 162 | 163 | }; 164 | 165 | function Entity(n_name,n_attributes) { 166 | 167 | var name=n_name;//name of Entity -- must be unique 168 | this.attributes=n_attributes; 169 | 170 | 171 | //accessor/mutators 172 | this.getName=function() { 173 | 174 | return name; 175 | 176 | }; 177 | 178 | this.getAttributes=function() { 179 | 180 | return this.attributes; 181 | }; 182 | 183 | this.getAttribute=function(attr) { 184 | if (attr in this.attributes) 185 | return this.attributes[attr]; 186 | else 187 | return -999; 188 | 189 | }; 190 | 191 | this.setAttribute=function(attr,value) { 192 | 193 | if (attr in this.attributes) 194 | this.attributes[attr]=value; 195 | 196 | }; 197 | 198 | }; 199 | 200 | 201 | //=== 202 | --------------------------------------------------------------------------------