├── wav
├── 1.wav
├── 2.wav
├── 3.wav
├── 4.wav
├── 5.wav
├── 6.wav
└── s1.wav
├── NotCourierSans.otf
├── README.md
├── .gitattributes
├── index.html
├── .gitignore
├── game.js
├── lib.js
├── circles_2.js
└── circles.js
/wav/1.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARE/circles/master/wav/1.wav
--------------------------------------------------------------------------------
/wav/2.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARE/circles/master/wav/2.wav
--------------------------------------------------------------------------------
/wav/3.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARE/circles/master/wav/3.wav
--------------------------------------------------------------------------------
/wav/4.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARE/circles/master/wav/4.wav
--------------------------------------------------------------------------------
/wav/5.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARE/circles/master/wav/5.wav
--------------------------------------------------------------------------------
/wav/6.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARE/circles/master/wav/6.wav
--------------------------------------------------------------------------------
/wav/s1.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARE/circles/master/wav/s1.wav
--------------------------------------------------------------------------------
/NotCourierSans.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARE/circles/master/NotCourierSans.otf
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Circles
2 | =======
3 |
4 | My Ludum Dare 26 entry. Just clone and open `index.html` in your browser or go to https://are1000.github.com/circles/index.html.
5 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 | *.sln merge=union
7 | *.csproj merge=union
8 | *.vbproj merge=union
9 | *.fsproj merge=union
10 | *.dbproj merge=union
11 |
12 | # Standard to msysgit
13 | *.doc diff=astextplain
14 | *.DOC diff=astextplain
15 | *.docx diff=astextplain
16 | *.DOCX diff=astextplain
17 | *.dot diff=astextplain
18 | *.DOT diff=astextplain
19 | *.pdf diff=astextplain
20 | *.PDF diff=astextplain
21 | *.rtf diff=astextplain
22 | *.RTF diff=astextplain
23 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | circles v2
5 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #################
2 | ## Eclipse
3 | #################
4 |
5 | *.pydevproject
6 | .project
7 | .metadata
8 | bin/
9 | tmp/
10 | *.tmp
11 | *.bak
12 | *.swp
13 | *~.nib
14 | local.properties
15 | .classpath
16 | .settings/
17 | .loadpath
18 |
19 | # External tool builders
20 | .externalToolBuilders/
21 |
22 | # Locally stored "Eclipse launch configurations"
23 | *.launch
24 |
25 | # CDT-specific
26 | .cproject
27 |
28 | # PDT-specific
29 | .buildpath
30 |
31 |
32 | #################
33 | ## Visual Studio
34 | #################
35 |
36 | ## Ignore Visual Studio temporary files, build results, and
37 | ## files generated by popular Visual Studio add-ons.
38 |
39 | # User-specific files
40 | *.suo
41 | *.user
42 | *.sln.docstates
43 |
44 | # Build results
45 | [Dd]ebug/
46 | [Rr]elease/
47 | *_i.c
48 | *_p.c
49 | *.ilk
50 | *.meta
51 | *.obj
52 | *.pch
53 | *.pdb
54 | *.pgc
55 | *.pgd
56 | *.rsp
57 | *.sbr
58 | *.tlb
59 | *.tli
60 | *.tlh
61 | *.tmp
62 | *.vspscc
63 | .builds
64 | *.dotCover
65 |
66 | ## TODO: If you have NuGet Package Restore enabled, uncomment this
67 | #packages/
68 |
69 | # Visual C++ cache files
70 | ipch/
71 | *.aps
72 | *.ncb
73 | *.opensdf
74 | *.sdf
75 |
76 | # Visual Studio profiler
77 | *.psess
78 | *.vsp
79 |
80 | # ReSharper is a .NET coding add-in
81 | _ReSharper*
82 |
83 | # Installshield output folder
84 | [Ee]xpress
85 |
86 | # DocProject is a documentation generator add-in
87 | DocProject/buildhelp/
88 | DocProject/Help/*.HxT
89 | DocProject/Help/*.HxC
90 | DocProject/Help/*.hhc
91 | DocProject/Help/*.hhk
92 | DocProject/Help/*.hhp
93 | DocProject/Help/Html2
94 | DocProject/Help/html
95 |
96 | # Click-Once directory
97 | publish
98 |
99 | # Others
100 | [Bb]in
101 | [Oo]bj
102 | sql
103 | TestResults
104 | *.Cache
105 | ClientBin
106 | stylecop.*
107 | ~$*
108 | *.dbmdl
109 | Generated_Code #added for RIA/Silverlight projects
110 |
111 | # Backup & report files from converting an old project file to a newer
112 | # Visual Studio version. Backup files are not needed, because we have git ;-)
113 | _UpgradeReport_Files/
114 | Backup*/
115 | UpgradeLog*.XML
116 |
117 |
118 |
119 | ############
120 | ## Windows
121 | ############
122 |
123 | # Windows image file caches
124 | Thumbs.db
125 |
126 | # Folder config file
127 | Desktop.ini
128 |
129 |
130 | #############
131 | ## Python
132 | #############
133 |
134 | *.py[co]
135 |
136 | # Packages
137 | *.egg
138 | *.egg-info
139 | dist
140 | build
141 | eggs
142 | parts
143 | bin
144 | var
145 | sdist
146 | develop-eggs
147 | .installed.cfg
148 |
149 | # Installer logs
150 | pip-log.txt
151 |
152 | # Unit test / coverage reports
153 | .coverage
154 | .tox
155 |
156 | #Translations
157 | *.mo
158 |
159 | #Mr Developer
160 | .mr.developer.cfg
161 |
162 | # Mac crap
163 | .DS_Store
164 |
--------------------------------------------------------------------------------
/game.js:
--------------------------------------------------------------------------------
1 | function GameController(game, opts) {
2 | var options = opts || {},
3 | self = this;
4 | EmptyElement.call(this, opts);
5 |
6 | this.current = null;
7 | this.currentName = "";
8 | this.levels = {};
9 | this.add = function(name, lvl) {
10 | if (lvl instanceof GameLevel) {
11 | this.levels[name] = lvl;
12 | }
13 | };
14 |
15 | this.create = function(name, opts) {
16 | this.levels[name] = new GameLevel(opts);
17 | }
18 |
19 | this.score = 0;
20 | this.waves = 0;
21 |
22 | game.controllers.game = this;
23 |
24 | this.load = function(lvl, game, res, cb) {
25 | if (lvl in this.levels) {
26 | this.reset(game);
27 | this.current = this.levels[lvl];
28 | this.currentName = lvl;
29 | this.waves = this.current.waves;
30 |
31 | if (this.current._descriptor) {
32 | this.current._reload();
33 | game.elements.push.apply(game.elements, this.current.elements);
34 | } else {
35 | for (var index = 0; index < this.current.elements.length; index += 2) {
36 | var cls = this.current.elements[index],
37 | args = this.current.elements[index + 1];
38 | game.add(new cls(args));
39 | }
40 | }
41 |
42 | game.provide(res);
43 | if (cb) cb(game.elements);
44 | }
45 | };
46 |
47 | this.reset = function(game) {
48 | this.score = 0;
49 | this.waves = 0;
50 | game.elements.filter(function(element) {
51 | return [ WaveElement, NoteElement, TextElement, BlockerElement ].some(function(cls) {
52 | return element instanceof cls;
53 | });
54 | }).forEach(function(element) {
55 | game.remove(element);
56 | });
57 | };
58 |
59 | this.wasPressed = false;
60 |
61 | this.emitWave = function(opts, game) {
62 | var waven = new WaveElement(opts);
63 | waven.on('update', function(time, game) {
64 | if (this.alpha > 0) this.collidingWith(game, NoteElement, function(note) {
65 | note.hit(this.alpha, this, game, function(score) {
66 | self.score += score;
67 | });
68 |
69 | });
70 | });
71 | game.add(waven);
72 | }
73 |
74 | this.on('update', function(time, game) {
75 | var mouse = game.controllers.mouse;
76 | if (!this.wasPressed && mouse.pressed && this.waves > 0) {
77 | var isfree = game.get(BlockerElement).some(function(el) {
78 | return game.buffer.isPointInPath(el.path, mouse.x, mouse.y, 'evenodd');
79 | });
80 |
81 | if (!isfree) {
82 | var wave = new WaveElement({ brightness: 100, x: mouse.x, y: mouse.y, force: self.current.wavesPower, speed: self.current.wavesSpeed });
83 | wave.on('update', function(time, game) {
84 |
85 | if (this.alpha > 0) this.collidingWith(game, NoteElement, function(note) {
86 |
87 | note.hit(this.alpha, this, game, function(score) {
88 | self.score += score;
89 | });
90 | });
91 | });
92 |
93 |
94 | game.add(wave);
95 | this.waves--;
96 |
97 | this.wasPressed = true;
98 | }
99 | } else if (this.wasPressed && !game.controllers.mouse.pressed) {
100 | this.wasPressed = false;
101 | }
102 |
103 | if (32 in game.controllers.keyboard) {
104 | self.load.call(self, self.currentName, game, game.resources)
105 | }
106 |
107 |
108 | if (this.current !== null) {
109 | if (this.score >= this.current.score)
110 | self.load.call(self, self.current.nextLvl, game, game.resources);
111 |
112 | }
113 | });
114 |
115 | this.on('draw', function(ctx, game) {
116 | var mouse = game.controllers.mouse;
117 | ctx.lineWidth = 1;
118 | ctx.strokeStyle = '#ffffff';
119 | ctx.beginPath();
120 | var wavesLeft = (Math.PI * 2);
121 | if (self.current) wavesLeft *= (self.waves / self.current.waves);
122 |
123 | ctx.lineWidth = 2;
124 | ctx.arc(mouse.x, mouse.y, 5, 0, wavesLeft);
125 | ctx.moveTo(mouse.x, mouse.y);
126 | ctx.stroke();
127 |
128 | ctx.beginPath();
129 | ctx.lineWidth = 1;
130 | ctx.arc(mouse.x, mouse.y, 1, 0, Math.PI*2);
131 | ctx.stroke();
132 | });
133 | }
134 |
135 |
136 | var game = new Circles({ output: 'game-cont' }),
137 | gameController = new GameController(game, {}),
138 | background = new BackgroundElement({ hue: 5, saturation: 100, brightness: ZERO }),
139 | title = new TextElement({ brightness: 100, text: "circles", x: 100, y: 100 });
140 |
141 | new MouseController(game);
142 | new KeyboardController(game);
143 |
144 | var lvl_start = new GameLevel({ score: 1, waves: 100, power: 25, next: '1', elements: [
145 | FadingOutTextElement, { x: 50, y: 50, text: 'Circles', font: 'Minimal', fontSize: 50, step: 0.001, brightness: 100, update: function(time, game) { this.centerX(game); } },
146 | TextElement, { x: 330, y: 270, text: 'This is a note.', font: 'Minimal', fontSize: 16, brightness: 100 },
147 | NoteElement, { x: 320, y: 240, hits: 1, score: 1, resources: [ 'note1' ], brightness: 50, hue: 2, saturation: 100 }
148 | ] });
149 |
150 | var lvl_1 = new GameLevel({ score: 5, waves: 5, power: 50, next: '2', elements: [
151 | TextElement, { x: 200, y: 270, text: 'This is a pentatonic scale.', font: 'Minimal', fontSize: 16, brightness: 100 },
152 | NoteElement, { x: 160, y: 240, hits: 1, score: 1, resources: [ 'note1' ], brightness: 50, hue: 0, saturation: 100 },
153 | NoteElement, { x: 240, y: 240, hits: 1, score: 1, resources: [ 'note2' ], brightness: 50, hue: 15, saturation: 100 },
154 | NoteElement, { x: 320, y: 240, hits: 1, score: 1, resources: [ 'note3' ], brightness: 50, hue: 30, saturation: 100 },
155 | NoteElement, { x: 400, y: 240, hits: 1, score: 1, resources: [ 'note4' ], brightness: 50, hue: 45, saturation: 100 },
156 | NoteElement, { x: 480, y: 240, hits: 1, score: 1, resources: [ 'note5' ], brightness: 50, hue: 60, saturation: 100 }
157 | ] });
158 |
159 | var lvl_2 = new GameLevel({ score: 8, waves: 8, power: 50, speed: 100, next: '3', elements: [
160 | BlockerElement, { x: 120, y: 200, width: 360, height: 80, alpha: 0.7, brightness: 10, hue: 0, saturation: 50, path: function(path, mode) {
161 | mode.rectOut(path);
162 | } },
163 | TextElement, { x: 120, y: 300, text: 'No new waves allowed on the red field!', font: 'Minimal', fontSize: 16, brightness: 100 },
164 | NoteElement, { x: 160, y: 240, hits: 1, score: 1, resources: [ 'note1' ], brightness: 50, hue: 0, saturation: 100 },
165 | NoteElement, { x: 200, y: 240, hits: 1, score: 1, resources: [ 'note5' ], brightness: 50, hue: 60, saturation: 100 },
166 | NoteElement, { x: 240, y: 240, hits: 1, score: 1, resources: [ 'note4' ], brightness: 50, hue: 45, saturation: 100 },
167 | NoteElement, { x: 280, y: 240, hits: 1, score: 1, resources: [ 'note3' ], brightness: 50, hue: 30, saturation: 100 },
168 | NoteElement, { x: 320, y: 240, hits: 1, score: 1, resources: [ 'note5' ], brightness: 50, hue: 60, saturation: 100 },
169 | NoteElement, { x: 360, y: 240, hits: 1, score: 1, resources: [ 'note4' ], brightness: 50, hue: 45, saturation: 100 },
170 | NoteElement, { x: 400, y: 240, hits: 1, score: 1, resources: [ 'note1' ], brightness: 50, hue: 0, saturation: 100 },
171 | NoteElement, { x: 440, y: 240, hits: 1, score: 1, resources: [ 'note2' ], brightness: 50, hue: 15, saturation: 100 },
172 |
173 | ] });
174 |
175 | var lvl_3 = new GameLevel({ score: 4, waves: 4, power: 50, speed: 100, next: '4', elements: [
176 | BlockerElement, { x: 300, y: 220, radius: 20, fill: 'nonzero', alpha: 0.7, brightness: 10, hue: 0, saturation: 50, path: function(path, mode) {
177 | mode.circleOut(path);
178 | }, update: function(time, game) {
179 | var dx = game.controllers.mouse.x - this.x,
180 | dy = game.controllers.mouse.y - this.y,
181 | dist = Math.sqrt(dx*dx + dy*dy);
182 |
183 | if (dist > this.radius) {
184 | dx /= Math.log10(dist);
185 | dy /= Math.log10(dist);
186 |
187 | dx /= 3;
188 | dy /= 3;
189 |
190 | this.x += dx;
191 | this.y += dy;
192 | } else {
193 | this.x = game.controllers.mouse.x;
194 | this.y = game.controllers.mouse.y;
195 | }
196 |
197 | this.path = new Path2D();
198 | this.paths.circleOut(this.path);
199 | } },
200 | NoteElement, { x: 40, y: 40, hits: 1, score: 1, resources: [ 'note1' ], brightness: 50, hue: 0, saturation: 100 },
201 | NoteElement, { x: 600, y: 40, hits: 1, score: 1, resources: [ 'note5' ], brightness: 50, hue: 60, saturation: 100 },
202 | NoteElement, { x: 40, y: 440, hits: 1, score: 1, resources: [ 'note4' ], brightness: 50, hue: 45, saturation: 100 },
203 | NoteElement, { x: 600, y: 440, hits: 1, score: 1, resources: [ 'note3' ], brightness: 50, hue: 30, saturation: 100 }
204 | ] });
205 |
206 |
207 | game.add(background, title);
208 | game.add(gameController);
209 |
210 | gameController.add('start', lvl_start);
211 | gameController.add('1', lvl_1);
212 | gameController.add('2', lvl_2);
213 | gameController.add('3', lvl_3);
214 | gameController.create('4', { score: 4, waves: 2, power: 80, speed: 40, next: '5', elements: [
215 | NoteElement, { disabled: true, id: 'n1', x: 100, y: 100, hits: 1, score: 1, resources: ['note1'], brightness: 50, hue: 0, saturation: 100 },
216 | NoteTransElement, { id: 'n2', target: 'n1', x: 400, y: 100, hits: 1, score: 1, resources: ['note1'], brightness: 50, hue: 0, saturation: 100 },
217 | NoteTransElement, { disabled: true, id: 'n3', target: 'n3', x: 100, y: 170, hits: 1, score: 1, resources: ['note1'], brightness: 50, hue: 0, saturation: 100 },
218 | NoteElement, { x: 400, y: 170, hits: 1, score: 1, resources: ['note1'], brightness: 50, hue: 0, saturation: 100 },
219 | NoteEventElement, { x: 400, y: 400, hits: -1, score: 0, resources: ['hihat1'], brightness: 50, hue: 320, saturation: 100, event: function(force, wave, game) {
220 | var self = this;
221 | game.get(NoteElement).forEach(function(note) {
222 | if (note !== self) {
223 | if (note.disabled) note.disabled = false;
224 | else note.disabled = true;
225 | note.force = 0.1;
226 | }
227 | });
228 | }, descriptor: function() {
229 | this.on('draw', function(ctx, game) {
230 |
231 | ctx.strokeStyle = this.getColor();
232 | ctx.beginPath();
233 | ctx.moveTo(this.x - 4, this.y - 4);
234 | ctx.lineTo(this.x + this.width + 4, this.y - 4);
235 | ctx.lineTo(this.x + this.width + 4, this.y +this.height+ 4);
236 | ctx.lineTo(this.x- 4, this.y +this.height+ 4);
237 | ctx.closePath();
238 |
239 | ctx.stroke();
240 | });
241 | }}
242 | ] });
243 |
244 | game.load({ hihat1: './wav/s1.wav', note1: './wav/5.wav', note2: './wav/4.wav', note3: './wav/3.wav', note4: './wav/2.wav', note5: './wav/1.wav' }, function(res) {
245 |
246 |
247 | game.start();
248 |
249 | gameController.load('start', game, res);
250 | });
251 |
252 |
--------------------------------------------------------------------------------
/lib.js:
--------------------------------------------------------------------------------
1 | function rgbToHex(r, g, b) {
2 | return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
3 | }
4 | owl = (function() {
5 |
6 | // the re-usable constructor function used by clone().
7 | function Clone() {}
8 |
9 | // clone objects, skip other types.
10 | function clone(target) {
11 | if ( typeof target == 'object' ) {
12 | Clone.prototype = target;
13 | return new Clone();
14 | } else {
15 | return target;
16 | }
17 | }
18 |
19 |
20 | // Shallow Copy
21 | function copy(target) {
22 | if (typeof target !== 'object' ) {
23 | return target; // non-object have value sematics, so target is already a copy.
24 | } else {
25 | var value = target.valueOf();
26 | if (target != value) {
27 | // the object is a standard object wrapper for a native type, say String.
28 | // we can make a copy by instantiating a new object around the value.
29 | return new target.constructor(value);
30 | } else {
31 | // ok, we have a normal object. If possible, we'll clone the original's prototype
32 | // (not the original) to get an empty object with the same prototype chain as
33 | // the original. If just copy the instance properties. Otherwise, we have to
34 | // copy the whole thing, property-by-property.
35 | if ( target instanceof target.constructor && target.constructor !== Object ) {
36 | var c = clone(target.constructor.prototype);
37 |
38 | // give the copy all the instance properties of target. It has the same
39 | // prototype as target, so inherited properties are already there.
40 | for ( var property in target) {
41 | if (target.hasOwnProperty(property)) {
42 | c[property] = target[property];
43 | }
44 | }
45 | } else {
46 | var c = {};
47 | for ( var property in target ) c[property] = target[property];
48 | }
49 |
50 | return c;
51 | }
52 | }
53 | }
54 |
55 | // Deep Copy
56 | var deepCopiers = [];
57 |
58 | function DeepCopier(config) {
59 | for ( var key in config ) this[key] = config[key];
60 | }
61 | DeepCopier.prototype = {
62 | constructor: DeepCopier,
63 |
64 | // determines if this DeepCopier can handle the given object.
65 | canCopy: function(source) { return false; },
66 |
67 | // starts the deep copying process by creating the copy object. You
68 | // can initialize any properties you want, but you can't call recursively
69 | // into the DeeopCopyAlgorithm.
70 | create: function(source) { },
71 |
72 | // Completes the deep copy of the source object by populating any properties
73 | // that need to be recursively deep copied. You can do this by using the
74 | // provided deepCopyAlgorithm instance's deepCopy() method. This will handle
75 | // cyclic references for objects already deepCopied, including the source object
76 | // itself. The "result" passed in is the object returned from create().
77 | populate: function(deepCopyAlgorithm, source, result) {}
78 | };
79 |
80 | function DeepCopyAlgorithm() {
81 | // copiedObjects keeps track of objects already copied by this
82 | // deepCopy operation, so we can correctly handle cyclic references.
83 | this.copiedObjects = [];
84 | thisPass = this;
85 | this.recursiveDeepCopy = function(source) {
86 | return thisPass.deepCopy(source);
87 | }
88 | this.depth = 0;
89 | }
90 | DeepCopyAlgorithm.prototype = {
91 | constructor: DeepCopyAlgorithm,
92 |
93 | maxDepth: 256,
94 |
95 | // add an object to the cache. No attempt is made to filter duplicates;
96 | // we always check getCachedResult() before calling it.
97 | cacheResult: function(source, result) {
98 | this.copiedObjects.push([source, result]);
99 | },
100 |
101 | // Returns the cached copy of a given object, or undefined if it's an
102 | // object we haven't seen before.
103 | getCachedResult: function(source) {
104 | var copiedObjects = this.copiedObjects;
105 | var length = copiedObjects.length;
106 | for ( var i=0; i this.maxDepth ) {
163 | throw new Error("Exceeded max recursion depth in deep copy.");
164 | }
165 |
166 | // It's now safe to let the deepCopier recursively deep copy its properties.
167 | deepCopier.populate(this.recursiveDeepCopy, source, result);
168 |
169 | this.depth--;
170 |
171 | return result;
172 | }
173 | };
174 |
175 | // entry point for deep copy.
176 | // source is the object to be deep copied.
177 | // maxDepth is an optional recursion limit. Defaults to 256.
178 | function deepCopy(source, maxDepth) {
179 | var deepCopyAlgorithm = new DeepCopyAlgorithm();
180 | if ( maxDepth ) deepCopyAlgorithm.maxDepth = maxDepth;
181 | return deepCopyAlgorithm.deepCopy(source);
182 | }
183 |
184 | // publicly expose the DeepCopier class.
185 | deepCopy.DeepCopier = DeepCopier;
186 |
187 | // publicly expose the list of deepCopiers.
188 | deepCopy.deepCopiers = deepCopiers;
189 |
190 | // make deepCopy() extensible by allowing others to
191 | // register their own custom DeepCopiers.
192 | deepCopy.register = function(deepCopier) {
193 | if ( !(deepCopier instanceof DeepCopier) ) {
194 | deepCopier = new DeepCopier(deepCopier);
195 | }
196 | deepCopiers.unshift(deepCopier);
197 | }
198 |
199 | // Generic Object copier
200 | // the ultimate fallback DeepCopier, which tries to handle the generic case. This
201 | // should work for base Objects and many user-defined classes.
202 | deepCopy.register({
203 | canCopy: function(source) { return true; },
204 |
205 | create: function(source) {
206 | if ( source instanceof source.constructor ) {
207 | return clone(source.constructor.prototype);
208 | } else {
209 | return {};
210 | }
211 | },
212 |
213 | populate: function(deepCopy, source, result) {
214 | for ( var key in source ) {
215 | if ( source.hasOwnProperty(key) ) {
216 | result[key] = deepCopy(source[key]);
217 | }
218 | }
219 | return result;
220 | }
221 | });
222 |
223 | // Array copier
224 | deepCopy.register({
225 | canCopy: function(source) {
226 | return ( source instanceof Array );
227 | },
228 |
229 | create: function(source) {
230 | return new source.constructor();
231 | },
232 |
233 | populate: function(deepCopy, source, result) {
234 | for ( var i=0; i>> 0) + 2);
5 | };
6 |
7 | CanvasRenderingContext2D.prototype.clear = function() {
8 | this.save();
9 | this.clearRect(0, 0, this.canvas.width, this.canvas.height);
10 | this.restore();
11 | };
12 |
13 | Number.prototype.clamp = function(min, max) {
14 | return Math.min(Math.max(this, min), max);
15 | };
16 |
17 | function Circles(opts) {
18 | var options = opts || {},
19 | self = this;
20 |
21 | this.canvas = { output: document.createElement('canvas'),
22 | buffer: document.createElement('canvas') };
23 |
24 | this.buffer = this.canvas.buffer.getContext('2d');
25 | this.output = this.canvas.output.getContext('2d');
26 |
27 | this.width = this.canvas.buffer.width = this.canvas.output.width = options.width || 640;
28 | this.height = this.canvas.buffer.height = this.canvas.output.height = options.height || 480;
29 |
30 | if (options.output) document.getElementById(options.output).appendChild(this.canvas.output);
31 |
32 | this.controllers = {};
33 |
34 | this.elements = [];
35 |
36 | this.add = function() {
37 | this.elements.push.apply(this.elements, arguments);
38 | };
39 |
40 | this.remove = function(element) {
41 | var index = this.elements.indexOf(element);
42 | if (index >= 0) this.elements.splice(index, 1);
43 | };
44 |
45 | this.get = function(cls) {
46 | return this.elements.filter(function(el) { return el instanceof cls; });
47 | };
48 |
49 | this.resources = {};
50 |
51 | this.load = function(resources, cb) {
52 | var resLoaded = 0,
53 | resCount = 0,
54 | loaded = false;
55 |
56 | for (var src in resources) {
57 | resCount++;
58 | }
59 |
60 | for (var src in resources) {
61 | var ext = resources[src].ext();
62 | var evt = 'onload';
63 | if (ext === 'png') this.resources[src] = new Image();
64 | else if (ext === 'wav' || ext === 'mp3') {
65 | this.resources[src] = new Audio();
66 | evt = 'oncanplaythrough';
67 | }
68 |
69 |
70 | this.resources[src][evt] = function(){
71 | if (++resLoaded >= resCount) {
72 | if (loaded === false) {
73 | cb(self.resources);
74 | loaded = true;
75 | }
76 | }
77 | };
78 | this.resources[src].src = resources[src];
79 | }
80 | };
81 |
82 | this.provide = function(resources) {
83 | this.elements.forEach(function(element) {
84 | element.provide(resources);
85 | });
86 | };
87 |
88 | this.time = { initialized: false,
89 | start: 0,
90 | current: 0,
91 | elapsed: 0,
92 | ticks: 0,
93 | lastTick: 0,
94 | lastTickDuration: 0 };
95 |
96 | this.update = function() {
97 | this.elements.forEach(function(element) {
98 | element.update(self.time, self);
99 | });
100 | };
101 |
102 | this.draw = function() {
103 | this.elements.forEach(function(element) {
104 | element.draw(self.buffer, self);
105 | });
106 | };
107 |
108 | this.start = this.loop = function() {
109 | requestAnimFrame(self.loop);
110 |
111 | if (!self.time.initialized) {
112 | self.time.initialized = true;
113 | self.time.start = performance.now();
114 | self.time.lastTick = self.time.current = performance.now();
115 | self.time.elapsed = self.time.current - self.time.start;
116 | self.time.ticks++;
117 | self.time.lastTickDuration = self.time.current - self.time.lastTick;
118 | } else {
119 | self.time.lastTick = self.time.current;
120 | self.time.current = performance.now();
121 | self.time.elapsed = self.time.current - self.time.start;
122 | self.time.ticks++;
123 | self.time.lastTickDuration = self.time.current - self.time.lastTick;
124 | }
125 |
126 |
127 |
128 | self.update();
129 | self.draw();
130 |
131 | self.output.drawImage(self.canvas.buffer, 0, 0);
132 | };
133 | }
134 |
135 |
136 | function MouseController(game) {
137 | var self = this;
138 |
139 | this.x = -1000;
140 | this.y = -1000;
141 | this.wasPressed = false;
142 | this.pressed = false;
143 | this.present = false;
144 |
145 |
146 | game.canvas.output.addEventListener('mousemove', function(evt) {
147 | var rect = game.canvas.output.getBoundingClientRect();
148 | self.x = Math.round(evt.clientX - rect.left);
149 | self.y = Math.round(evt.clientY - rect.top);
150 |
151 | self.present = true;
152 | });
153 |
154 | game.canvas.output.addEventListener('mousedown', function(evt) {
155 | self.pressed = true;
156 | self.present = true;
157 | });
158 |
159 | game.canvas.output.addEventListener('mouseup', function(evt) {
160 | self.pressed = false;
161 | self.present = true;
162 | });
163 |
164 | game.canvas.output.addEventListener('mouseleave', function(evt) {
165 | self.present = false;
166 | });
167 |
168 | game.canvas.output.addEventListener('mouseenter', function(evt) {
169 | self.present = true;
170 | });
171 |
172 | game.controllers.mouse = this;
173 | }
174 |
175 | function KeyboardController(game) {
176 | var self = this;
177 |
178 | window.addEventListener('keyup', function(evt) {
179 | delete self[evt.keyCode];
180 | });
181 |
182 | window.addEventListener('keydown', function(evt) {
183 | self[evt.keyCode] = true;
184 | });
185 |
186 | game.controllers.keyboard = this;
187 | }
188 |
189 | var ZERO = 0.0001,
190 | STOP = Math.random() * 999999999;
191 |
192 | function EmptyElement(opts) {
193 | var options = opts || {},
194 | self = this;
195 |
196 | this.x = options.x || 0;
197 | this.y = options.y || 0;
198 | this.width = options.width || 0;
199 | this.height = options.height || 0;
200 |
201 | this.collisions = {};
202 | this.collisions.point = function(x, y) {
203 | return x >= this.x && x <= this.x + this.width && y >= this.y && y <= this.y + this.height;
204 | };
205 |
206 | this._update = [];
207 | this._draw = [];
208 |
209 | this.on = function(action, cb) {
210 | if (action in this && ('_'+action) in this) this['_'+action].push(cb);
211 | };
212 |
213 |
214 | this.register = function(evt) {
215 | this['_'+evt] = [];
216 | this[evt] = function() {
217 | for (var index = 0; index < this['_'+evt].length; index++) {
218 | var callback = this['_'+evt][index];
219 | var result = callback.apply(self, Array.prototype.slice.call(arguments));
220 | if (result === STOP) break;
221 | }
222 | };
223 | };
224 |
225 | this.update = function(time, game) {
226 | for (var index = 0; index < this._update.length; index++) {
227 | var callback = this._update[index];
228 | var result = callback.call(self, time, game);
229 | if (result === STOP) break;
230 | }
231 | };
232 |
233 | this.draw = function(ctx, game) {
234 | for (var index = 0; index < this._draw.length; index++) {
235 | var callback = this._draw[index];
236 | var result = callback.call(self, ctx, game);
237 | if (result === STOP) break;
238 | }
239 | };
240 |
241 | if (options.update) this.on('update', options.update);
242 | if (options.draw) this.on('draw', options.draw);
243 |
244 | if (options.descriptor) options.descriptor.call(this);
245 |
246 |
247 | this.provide = function(resources) {
248 | if (this._resources) {
249 | this.resources = {};
250 | this._resources.forEach(function(resource){
251 | self.resources[resource] = resources[resource];
252 | });
253 | }
254 | }
255 | }
256 |
257 | function ColorExtension(opts) {
258 | var options = opts || {},
259 | self = this;
260 |
261 | this.hue = options.hue || 0;
262 | this.saturation = options.saturation || 0;
263 | this.brightness = options.brightness || 0;
264 | this.alpha = options.alpha || 1;
265 |
266 | this.getColor = function(h, s, b, a) {
267 | return 'hsla(' + (h || this.hue) + ', ' + (s || this.saturation) + '%, ' + (b || this.brightness) + '%, ' + (a || this.alpha) + ')';
268 | };
269 | }
270 |
271 | function ResourceExtension(opts) {
272 | var options = opts || {},
273 | self = this;
274 |
275 | this._resources = opts.resources || [];
276 | }
277 |
278 | function BackgroundElement(opts) {
279 | var options = opts || {},
280 | self = this;
281 | EmptyElement.call(this, opts);
282 | ColorExtension.call(this, opts);
283 |
284 | this.on('draw', function(ctx, game) {
285 | ctx.fillStyle = 'hsl(' + this.hue + ', ' + this.saturation + '%, ' + this.brightness + '%)';
286 | ctx.fillRect(0, 0, game.width, game.height);
287 | });
288 | }
289 |
290 | function TextElement(opts) {
291 | var options = opts || {},
292 | self = this;
293 | EmptyElement.call(this, opts);
294 | ColorExtension.call(this, opts);
295 |
296 | this.text = options.text || "";
297 | this.font = options.font || 'Courier New';
298 | this.fontSize = options.fontSize || 12;
299 |
300 | this.centerX = function(game) {
301 | this.x = game.width / 2 - this.measure(game.buffer, this.text) / 2;
302 | };
303 |
304 | this.centerY = function(game) {
305 | this.y = game.height / 2 - this.fontSize / 2;
306 | };
307 |
308 | this.measure = function(ctx, text) {
309 | ctx.font = this.getFont();
310 | return ctx.measureText(text).width;
311 | };
312 |
313 | this.getFont = function() {
314 | return this.fontSize + 'px ' + this.font;
315 | };
316 |
317 | this.on('draw', function(ctx, game) {
318 | ctx.font = this.getFont();
319 | ctx.fillStyle = this.getColor();
320 | ctx.fillText(this.text, this.x, this.y);
321 | });
322 | }
323 |
324 | function FadingOutTextElement(opts) {
325 | var options = opts || {},
326 | self = this;
327 | TextElement.call(this, opts);
328 |
329 | this.step = options.step || 0.01;
330 |
331 | this.refresh = function(lvl) {
332 | this.alpha = lvl || 1;
333 | };
334 |
335 | this.on('update', function(time, game) {
336 | if (this.alpha > 0) this.alpha -= this.step;
337 | else this.alpha = 0;
338 | });
339 | }
340 |
341 | FadingOutTextElement.prototype = TextElement.prototype;
342 |
343 | function NoteElement(opts) {
344 | var options = opts || {},
345 | self = this;
346 | EmptyElement.call(this, opts);
347 | ColorExtension.call(this, opts);
348 | ResourceExtension.call(this, opts);
349 |
350 | this.width = this.height = options.size || 5;
351 | this.resourceName = this._resources[0] || '';
352 |
353 | this.score = options.score || 0;
354 | this._hits = options.hits || 0;
355 | this.hits = options.hits || 0;
356 |
357 | this.id = options.id || '';
358 |
359 | this.force = false;
360 | this.disabled = options.disabled || false;
361 |
362 | this.register('hit');
363 | this.register('hitSuccess');
364 |
365 | this.on('hit', function(force, wave, game, cb) {
366 | if ((this.hits > 0 || this.hits === -1) && this.force === false && this.disabled === false) {
367 | this.hitSuccess(force, wave, game, cb);
368 | return this.score;
369 | } else {
370 | return false;
371 | }
372 | });
373 |
374 | this.on('hitSuccess', function(force, wave, game, cb) {
375 | if (this.hits > 0) this.hits--;
376 | this.resources[this.resourceName].volume = force;
377 | this.resources[this.resourceName].currentTime = 0;
378 | this.resources[this.resourceName].play();
379 | this.force = force;
380 | cb(this.score);
381 | });
382 |
383 | this.on('update', function(time, game) {
384 | if (this.force) this.force -= this.force/3;
385 | if (this.force < 0.01) this.force = false;
386 | });
387 |
388 | this.on('draw', function(ctx, game) {
389 | if (this.force || this.hits === 0 || this.disabled) {
390 | ctx.fillStyle = this.getColor(undefined, ZERO);
391 | ctx.fillRect(this.x - this.force*8, this.y - this.force*8, this.width + this.force*16, this.height + this.force*16);
392 | } else {
393 | ctx.fillStyle = this.getColor();
394 | ctx.fillRect(this.x, this.y, this.width, this.height);
395 | }
396 | });
397 | }
398 |
399 | function NoteEventElement(opts) {
400 | var options = opts || {},
401 | self = this;
402 | NoteElement.call(this, opts);
403 |
404 | this.on('hitSuccess', opts.event);
405 |
406 | }
407 |
408 | NoteEventElement.prototype = NoteElement.prototype;
409 |
410 | function NoteEmitElement(opts) {
411 | var options = opts || {},
412 | self = this;
413 | NoteElement.call(this, opts);
414 |
415 | this.on('hitSuccess', function(force, wave, game, cb) {
416 | game.controllers.game.emitWave({ brightness: 100, x: self.x+self.width/2, y: self.y+self.height/2, force: wave.force, speed: wave.speed }, game);
417 | });
418 |
419 | }
420 |
421 | NoteEmitElement.prototype = NoteElement.prototype;
422 |
423 | function NoteTransElement(opts) {
424 | var options = opts || {},
425 | self = this;
426 | NoteElement.call(this, opts);
427 |
428 | this.id = options.id || '';
429 | this.target = options.target || '';
430 |
431 | this.on('hitSuccess', function(force, wave, game, cb) {
432 | game.get(NoteElement).filter(function(note) {
433 | return note.id === self.target;
434 | }).forEach(function(targets) {
435 | console.log(targets);
436 | game.controllers.game.emitWave({ brightness: 100, x: targets.x+targets.width/2, y: targets.y+targets.height/2, force: wave.force, speed: wave.speed }, game);
437 | });
438 | });
439 | }
440 |
441 | NoteTransElement.prototype = NoteElement.prototype;
442 |
443 | function WaveElement(opts) {
444 | var options = opts || {},
445 | self = this;
446 | EmptyElement.call(this, opts);
447 | ColorExtension.call(this, opts);
448 |
449 | this.force = opts.force || 50;
450 | this.speed = opts.speed || 10;
451 | this.elapsed = 0;
452 | this.radius = 0;
453 |
454 | this.disabled = false;
455 |
456 | this.collisions.point = function(x, y, margin) {
457 | var dx = self.x - x,
458 | dy = self.y - y;
459 |
460 | var dist = Math.sqrt(dx*dx + dy*dy);
461 | var abs = Math.abs(dist - self.radius);
462 |
463 | return abs < margin;
464 | };
465 |
466 | this.collidingWith = function(game, cls, cb) {
467 | return game.elements.filter(function(element) {
468 | if (element instanceof cls) {
469 | var center = { x: element.x + element.width/2, y: element.y + element.height/2 };
470 | var margin = self.radius - ((self.elapsed - game.time.lastTickDuration) / 1000 * self.speed);
471 | if (self.collisions.point(center.x, center.y, margin)) {
472 | cb.call(self, element, margin, Math.sqrt(Math.pow(self.x - element.x, 2) + Math.pow(self.y - element.y, 2)));
473 | }
474 | }
475 | });
476 | };
477 |
478 | this.on('update', function(time, game) {
479 | if (!this.disabled) {
480 | this.elapsed += time.lastTickDuration;
481 | this.radius = this.elapsed / 1000 * this.speed;
482 |
483 | var alpha = this.radius / this.force;
484 |
485 | if (alpha > 1) { this.disabled = true; this.alpha = 0; }
486 | else {
487 | this.alpha = 1 - alpha;
488 | }
489 | } else {
490 | game.remove(self);
491 | }
492 | });
493 |
494 | this.on('draw', function(ctx, game) {
495 | if (!this.disabled) {
496 | ctx.strokeStyle = this.getColor();
497 | ctx.beginPath();
498 | ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
499 | ctx.stroke();
500 | }
501 | });
502 | }
503 |
504 | function BlockerElement(opts) {
505 | var options = opts || {},
506 | self = this;
507 | EmptyElement.call(this, opts);
508 | ColorExtension.call(this, opts);
509 |
510 | this.radius = options.radius || 0;
511 | this.fill = options.fill || 'evenodd';
512 |
513 | this.path = new Path2D();
514 |
515 | this.paths = {
516 | circularIn: function(path) {
517 | path.moveTo(0, 0);
518 | path.lineTo(game.width, 0);
519 | path.lineTo(game.width, this.y);
520 | path.lineTo(this.x + this.radius, this.y);
521 | path.arc(this.x, this.y, this.radius, 0, Math.PI*2);
522 | path.lineTo(game.width, this.y);
523 | path.lineTo(game.width, game.height);
524 | path.lineTo(0, game.height);
525 | path.closePath();
526 | },
527 | circleOut: function(path) {
528 | path.moveTo(self.x, self.y);
529 | path.lineTo(self.x+self.radius, self.y);
530 | path.arc(self.x, self.y, self.radius, 0, Math.PI*2-0.001);
531 | path.closePath();
532 | },
533 | rectOut: function(path) {
534 | path.moveTo(self.x, self.y);
535 | path.lineTo(self.x+self.width, self.y);
536 | path.lineTo(self.x+self.width, self.y+self.height);
537 | path.lineTo(self.x, self.y+self.height);
538 | path.closePath();
539 | }
540 | }
541 |
542 | if (options.path) options.path(this.path, this.paths);
543 |
544 |
545 |
546 | this.on('draw', function(ctx, game) {
547 | ctx.save();
548 |
549 | ctx.fillStyle = this.getColor();
550 | ctx.fill(this.path, this.fill);
551 |
552 | ctx.restore();
553 | });
554 | }
555 |
556 | function GameLevel(opts) {
557 | var options = opts || {},
558 | self = this;
559 |
560 | this.elements = options.elements || [];
561 | this.score = options.score || 1;
562 | this.waves = options.waves || -1;
563 | this.wavesPower = options.power || 50;
564 | this.wavesSpeed = options.speed || 20;
565 | this.nextLvl = options.next || '';
566 |
567 |
568 | if (options.descriptor) {
569 | this.elements = [];
570 | options.descriptor.call(this, this.elements);
571 | this._descriptor = true;
572 | this._descriptorF = options.descriptor;
573 |
574 | this._reload = function() {
575 | this._descriptorF.call(self);
576 | }
577 | }
578 | }
579 |
580 |
--------------------------------------------------------------------------------
/circles.js:
--------------------------------------------------------------------------------
1 | window.requestAnimFrame = (function(){
2 | return window.requestAnimationFrame ||
3 | window.webkitRequestAnimationFrame ||
4 | window.mozRequestAnimationFrame ||
5 | function( callback ){
6 | window.setTimeout(callback, 1000 / 60);
7 | };
8 | })();
9 |
10 |
11 | function CirclesGame (width, height) {
12 | this.width = width;
13 | this.height = height;
14 | this.canvas = document.createElement("canvas");
15 | this.canvas.width = this.width;
16 | this.canvas.height = this.height;
17 | this.buffer = this.canvas.getContext("2d");
18 | this.ocanvas = null;
19 | this.output = null;
20 |
21 | this.fps = 60;
22 | this.looptime = 0;
23 | this.settings = {};
24 |
25 | this.SetScene = function (canvasId) {
26 | this.ocanvas = document.getElementById(canvasId);
27 | this.ocanvas.width = this.width;
28 | this.ocanvas.height = this.height;
29 | this.output = this.ocanvas.getContext("2d");
30 | return this.ocanvas;
31 | }
32 |
33 | this.DrawScene = function (shift_x, shift_y) {
34 | this.output.globalAlpha = 0.75;
35 | this.output.drawImage(this.canvas,shift_x,shift_y);
36 |
37 | /*var imgd = this.buffer.getImageData(0, 0, 640, 480);
38 | var data = imgd.data;
39 |
40 | for (var i = 0, n = data.length; i < n; i += 4) {
41 |
42 | // generating random color coefficients
43 | var randColor1 = 0.6 + Math.random() * 0.4;
44 | var randColor2 = 0.6 + Math.random() * 0.4;
45 | var randColor3 = 0.6 + Math.random() * 0.4;
46 |
47 | // assigning random colors to our data
48 | data[i] = data[i]*randColor1; // green
49 | data[i+1] = data[i+1]*randColor2; // green
50 | data[i+2] = data[i+2]*randColor3; // blue
51 | }
52 | var newcont = document.createElement("canvas");
53 | newcont.width = 640;
54 | newcont.height = 480;
55 | var abba = newcont.getContext("2d");
56 | abba.putImageData(imgd, 0, 0);
57 |
58 | this.output.drawImage(newcont,0,0);*/
59 |
60 |
61 | }
62 |
63 | this.ClearBuffer = function () {
64 | this.buffer.save();
65 | var old = this.buffer.fillStyle= "#000000";
66 | this.buffer.fillRect(0,0,this.canvas.width,this.canvas.height);
67 | this.buffer.restore();
68 | }
69 |
70 | this.Logic = function () {
71 |
72 | }
73 |
74 | }
75 |
76 | //USER INPUT *************
77 | function mouse(obj, evt) {
78 | var rect = obj.getBoundingClientRect();
79 | return {
80 | x: evt.clientX - rect.left,
81 | y: evt.clientY - rect.top
82 | };
83 | }
84 |
85 | var keyboard = {};
86 | addEventListener("keydown", function (e) {
87 | keyboard[e.keyCode] = true;
88 | }, false);
89 | addEventListener("keyup", function (e) {
90 | delete keyboard[e.keyCode];
91 | }, false);
92 | //************************
93 |
94 | var game = new CirclesGame(640,480);
95 | game.SetScene("circles");
96 |
97 |
98 | //*****************GLOBAL SETTINGS**************
99 | game.buffer.shadowBlur = 20;
100 | game.buffer.shadowColor = "rgba(255,255,255,0.4)";
101 | game.buffer.webkitImageSmoothingEnabled = true;
102 | game.fps = 60;
103 |
104 | const TYPE_NOTE = 1;
105 | const TYPE_EMIT = 2;
106 | const TYPE_ABSR = 3;
107 | const TYPE_TIME = 4;
108 | const TYPE_RESE = 5;
109 | const TYPE_LABE = 6;
110 | const TYPE_ANCH = 7
111 |
112 | const CURR_WAVE = 0;
113 | const CURR_EMIT = 1;
114 | //-----------------GLOBAL SETTINGS-------------
115 |
116 | //****************GAME OBJECTS*******************
117 | var cursor = {
118 | x: 0,
119 | y: 0,
120 | pressed: false,
121 | current: 0
122 | }
123 |
124 | const colors = randomColors(64);
125 |
126 | function randomColors(total) {
127 | var i = 360 / (total - 1); // distribute the colors evenly on the hue range
128 | var r = []; // hold the generated colors
129 | for (var x=0; x0) {
303 | Settings.wavesLeft--;
304 | Settings.gameElements.circle.push(new Circle(mousevn.x, mousevn.y, Settings.cursorSize, 1));
305 | }
306 | break;
307 | case CURR_EMIT:
308 | if(Settings.emittersLeft>0) {
309 | Settings.emittersLeft--;
310 | Settings.gameElements.block.push(new Block(mousevn.x, mousevn.y, 0, TYPE_EMIT, {blocked: false, cycle: 1, wave: 1, once: true}));
311 | }
312 | break;
313 | }
314 | }
315 | }
316 | game.ocanvas.ontouchstart = function (e) {
317 | var mousevn = mouse(this,e);
318 | if(Settings.wavesLeft>0) {
319 | Settings.wavesLeft--;
320 | Settings.gameElements.circle.push(new Circle(mousevn.x, mousevn.y, Settings.cursorSize, 1));
321 | }
322 | cursor.pressed = true;
323 | }
324 | game.ocanvas.onmouseup = function (e) {
325 | cursor.pressed = false;
326 | }
327 | game.ocanvas.ontouchend = function (e) {
328 | cursor.pressed = false;
329 | }
330 | game.ocanvas.oncontextmenu = function (e) {
331 | return false;
332 | }
333 | //KEYBOARD#####################################
334 | if(32 in keyboard) {
335 | Settings.LoadLevel(Levels[Settings.levelNumber]);
336 | Settings.multiplerScore = 1;
337 | Settings.bufferScore = 0;
338 | }
339 |
340 | if(49 in keyboard) cursor.current = CURR_WAVE;
341 | else if (50 in keyboard) cursor.current = CURR_EMIT;
342 | //REST%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
343 |
344 |
345 |
346 |
347 | for (i in Settings.gameElements.circle) {
348 | if (Settings.gameElements.circle[i]!=null) {
349 | game.buffer.save();
350 | game.buffer.beginPath();
351 | game.buffer.strokeStyle="#fff";
352 | game.buffer.globalAlpha= Settings.gameElements.circle[i].opacity;
353 | game.buffer.arc(Settings.gameElements.circle[i].x,Settings.gameElements.circle[i].y,Settings.gameElements.circle[i].r,0,2*Math.PI);
354 | game.buffer.stroke();
355 | game.buffer.restore();
356 |
357 | for (n in Settings.gameElements.block) {
358 | var distance = Math.sqrt(Math.pow(Settings.gameElements.block[n].x - Settings.gameElements.circle[i].x,2) + Math.pow(Settings.gameElements.block[n].y- Settings.gameElements.circle[i].y,2))-Settings.gameElements.circle[i].r-Settings.gameElements.block[n].r;
359 | switch (Settings.gameElements.block[n].type) {
360 | case TYPE_NOTE:
361 | if (distance<0.5&&distance>-0.5&&!Settings.gameElements.block[n].settings.blocked&&Settings.goal>0) {
362 | Settings.gameElements.block[n].settings.audio.volume = ((Settings.gameElements.circle[i].opacity>=0.2) ? Settings.gameElements.circle[i].opacity : 0.2);
363 | Settings.gameElements.block[n].settings.audio.currentTime = 0;
364 | Settings.gameElements.block[n].settings.audio.play();
365 | Settings.gameElements.block[n].settings.isplay = true;
366 | $('body').stop().animate({backgroundColor: Settings.gameElements.block[n].settings.color},500);
367 | if(Settings.gameElements.block[n].settings.once) Settings.gameElements.block[n].settings.blocked = true;
368 | if(Settings.gameElements.block[n].settings.goalable) Settings.goal--;
369 | }
370 | break;
371 | case TYPE_EMIT:
372 | if (distance<0.5&&distance>-0.5&&!Settings.gameElements.block[n].settings.blocked&&Settings.gameElements.block[n].settings.cycle>=1){
373 | console.log("H");
374 | Settings.gameElements.circle.push(new Circle(Settings.gameElements.block[n].x,Settings.gameElements.block[n].y,Settings.gameElements.block[n].settings.wave,1));
375 | if(Settings.gameElements.block[n].settings.once) Settings.gameElements.block[n].settings.blocked = true;
376 | else Settings.gameElements.block[n].settings.cycle = 0;
377 | }
378 | break;
379 | case TYPE_ANCH:
380 | if (distance<0.5&&distance>-0.5){
381 | Settings.LoadLevel(Levels[Settings.gameElements.block[n].settings.level]);
382 | }
383 | break;
384 | }
385 | }
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 | if (Settings.gameElements.circle[i].cycle > 0) {
395 | Settings.gameElements.circle[i].cycle-=Settings.gameElements.circle[i].step;
396 | Settings.gameElements.circle[i].r++;
397 | Settings.gameElements.circle[i].opacity -=Settings.gameElements.circle[i].step/100;
398 | if (Settings.gameElements.circle[i].opacity <= 0) Settings.gameElements.circle[i].opacity = 0;
399 | } else if (Settings.gameElements.circle[i].cycle <= 0) {
400 | Settings.gameElements.circle[i] = null;
401 | }
402 | }
403 | };
404 |
405 | for (n in Settings.gameElements.block) {
406 | game.buffer.save();
407 | switch (Settings.gameElements.block[n].type) {
408 | case TYPE_NOTE:
409 | if(Settings.gameElements.block[n].settings.blocked) game.buffer.fillStyle = "#999999";
410 | else {
411 | game.buffer.fillStyle = colors[Settings.gameElements.block[n].x%colors.length];
412 | Settings.gameElements.block[n].settings.color = game.buffer.fillStyle;
413 | }
414 | if (Settings.gameElements.block[n].settings.isplay) {
415 | game.buffer.fillRect(Settings.gameElements.block[n].x-2,Settings.gameElements.block[n].y-2,4,4);
416 | Settings.gameElements.block[n].settings.isplay = false;
417 | } else {
418 | game.buffer.fillRect(Settings.gameElements.block[n].x-4,Settings.gameElements.block[n].y-4,8,8);
419 | }
420 | break;
421 | case TYPE_LABE:
422 | var distance = Math.abs(Settings.gameElements.block[n].x-cursor.x)+Math.abs(Settings.gameElements.block[n].y-cursor.y);
423 | Settings.gameElements.block[n].settings.opacity = 0.7;
424 | game.buffer.globalAlpha = Settings.gameElements.block[n].settings.opacity;
425 | game.buffer.fillStyle = "white";
426 | game.buffer.font = Settings.gameElements.block[n].settings.size+"px Minimal";
427 | game.buffer.textBaseline = "top";
428 | game.buffer.textAlign = "center";
429 | game.buffer.fillText(Settings.gameElements.block[n].settings.text,Settings.gameElements.block[n].x,Settings.gameElements.block[n].y);
430 | break;
431 | case TYPE_ANCH:
432 | game.buffer.fillStyle = "yellow";
433 | game.buffer.strokeStyle = "cyan";
434 | game.buffer.beginPath();
435 | game.buffer.rect(Settings.gameElements.block[n].x-2,Settings.gameElements.block[n].y-2,4,4);
436 | game.buffer.fill();
437 | game.buffer.lineWidth = 1;
438 | game.buffer.stroke();
439 | break;
440 | case TYPE_EMIT:
441 | if(!Settings.gameElements.block[n].settings.once) {
442 | game.buffer.beginPath();
443 | if(Settings.gameElements.block[n].settings.cycle<1) Settings.gameElements.block[n].settings.cycle += Settings.gameElements.block[n].settings.speed/100;
444 | else Settings.gameElements.block[n].settings.cycle = 1;
445 | game.buffer.fillStyle="white";
446 | game.buffer.strokeStyle = 'white';
447 | game.buffer.lineWidth = 2;
448 | game.buffer.arc(Settings.gameElements.block[n].x, Settings.gameElements.block[n].y, 5, 0, 2 * Math.PI*Settings.gameElements.block[n].settings.cycle, false);
449 | game.buffer.stroke();
450 | } else {
451 | if(Settings.gameElements.block[n].settings.blocked) {
452 | game.buffer.beginPath();
453 | game.buffer.fillStyle="#888888";
454 | game.buffer.strokeStyle = '#888888';
455 | game.buffer.lineWidth = 1;
456 | game.buffer.rect(Settings.gameElements.block[n].x-2, Settings.gameElements.block[n].y-2, 4, 4);
457 | game.buffer.stroke();
458 | game.buffer.fill();
459 | } else {
460 | game.buffer.beginPath();
461 | game.buffer.fillStyle="white";
462 | game.buffer.strokeStyle = 'white';
463 | game.buffer.lineWidth = 1;
464 | game.buffer.rect(Settings.gameElements.block[n].x-3, Settings.gameElements.block[n].y-3, 6, 6);
465 | game.buffer.stroke();
466 | game.buffer.fill();
467 | }
468 | }
469 | break;
470 | }
471 |
472 |
473 | game.buffer.restore();
474 | }
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 | Settings.Check();
484 |
485 |
486 | game.buffer.save();
487 | if (90 in keyboard) {
488 | game.buffer.save();
489 | game.buffer.beginPath();
490 | game.buffer.strokeStyle="red";
491 | game.buffer.globalAlpha= 0.2;
492 | game.buffer.arc(cursor.x,cursor.y,100/Settings.cursorSize,0,2*Math.PI);
493 | game.buffer.stroke();
494 | game.buffer.restore();
495 | }
496 |
497 | var quan = 1;
498 | game.buffer.fillStyle = "white";
499 |
500 |
501 | if(cursor.current==CURR_WAVE) {
502 | game.buffer.lineWidth = 2;
503 | quan = Settings.wavesLeft/Levels[Settings.levelNumber].wavesLeft;
504 | game.buffer.beginPath();
505 | game.buffer.strokeStyle=game.buffer.fillStyle;
506 | game.buffer.arc(cursor.x,cursor.y,5,0,2*Math.PI*quan);
507 | game.buffer.stroke();
508 | game.buffer.beginPath();
509 | game.buffer.strokeStyle=game.buffer.fillStyle;
510 | if(cursor.pressed) {
511 | game.buffer.lineWidth = 2;
512 | } else {
513 | game.buffer.lineWidth = 1;
514 | }
515 | game.buffer.arc(cursor.x,cursor.y,1,0,2*Math.PI);
516 | game.buffer.fill();
517 | game.buffer.stroke();
518 | }
519 | else if (cursor.current==CURR_EMIT) {
520 | quan = Settings.emittersLeft/Levels[Settings.levelNumber].emittersLeft;
521 | game.buffer.beginPath();
522 | game.buffer.strokeStyle=game.buffer.fillStyle;
523 | game.buffer.rect(cursor.x-4,cursor.y-4,8,8);
524 | game.buffer.stroke();
525 | game.buffer.fillRect(cursor.x-4,cursor.y-4,8*quan,8);
526 | }
527 |
528 | game.buffer.textBaseline = "top";
529 | game.buffer.textAlign = "center";
530 | game.buffer.shadowBlur = 0;
531 | game.buffer.fillStyle="white";
532 | game.buffer.font="60px Minimal";
533 |
534 | if(Fader.fade>0) {
535 | Fader.fade-=0.5;
536 | Fader.opac = Fader.fade/100;
537 | game.buffer.globalAlpha = Fader.opac;
538 | game.buffer.fillText(Settings.levelName,320,80);
539 | game.buffer.font="12px Minimal";
540 | game.buffer.fillText(Settings.levelDesc,320,50);
541 | }
542 |
543 | game.buffer.textBaseline = "top";
544 | game.buffer.textAlign = "left";
545 | game.buffer.shadowBlur = 0;
546 | game.buffer.fillStyle="white";
547 | game.buffer.globalAlpha = 0.9;
548 | game.buffer.font="60px Minimal";
549 | game.buffer.fillText(Settings.levelNumber,20,0);
550 |
551 | game.buffer.textBaseline = "bottom";
552 | game.buffer.textAlign = "right";
553 |
554 | game.buffer.save();
555 | game.buffer.font="14px Minimal";
556 | if(Settings.goal<33) {
557 | for (var i = 0; i < Settings.goal; i++) {
558 | game.buffer.fillStyle = "white";
559 | game.buffer.fillRect(i*20,game.canvas.height-5,20,3);
560 | }
561 | game.buffer.fillText(Settings.goal,Settings.goal*20,game.canvas.height);
562 | } else {
563 | for (var i = 0; i < Settings.goal; i++) {
564 | game.buffer.fillStyle = "white";
565 | game.buffer.fillRect(game.canvas.width/Settings.goal*i,game.canvas.height-5,game.canvas.width/Settings.goal,3);
566 | }
567 | game.buffer.fillText(Settings.goal,game.canvas.width,game.canvas.height);
568 | }
569 |
570 | game.buffer.restore();
571 |
572 | game.buffer.restore();
573 | game.DrawScene(0, 0, true);
574 | game.ClearBuffer();
575 | //game LOGIC HERE
576 | }
577 |
578 | //Settings.LoadLevel(0);
579 | game.Logic();
--------------------------------------------------------------------------------