Compare commits

...

224 commits

Author SHA1 Message Date
Karl Pannek
e6089687ed 2025 update! 2025-07-15 20:05:12 +02:00
1df7258b56 Upgrade socket.io to 2.x 2017-11-06 22:17:33 +01:00
Karl
1bb9539530 adds fixme comment about object.assign for merging 2016-10-28 17:46:39 +02:00
logsol
45ea2dfba3 Fixes some bugs from bulk renaming singleton object variables
Related to #128
2016-10-10 23:41:25 +02:00
logsol
91e0e7af3f Makes singleton variable name of QuerySelector lowercase
When we require a singleton, its instance name should be named
by lowercase, since it is not a class.

Fixes #128
2016-10-10 23:17:16 +02:00
logsol
5b3bfd4370 Makes singleton variable name of OptionsHelper lowercase
When we require a singleton, its instance name should be named
by lowercase, since it is not a class.

Relates to #128
2016-10-10 23:11:18 +02:00
logsol
05c4e4de81 Refactoring of Options. Renamed to OptionsHelper
Because that is what it is.
2016-10-10 23:10:43 +02:00
logsol
ce01c8888e Makes singleton variable name of PointerLockManager lowercase
When we require a singleton, its instance name should be named
by lowercase, since it is not a class.

Relates to #128
2016-10-10 22:42:22 +02:00
logsol
3cb2e39a18 Makes singleton variable name of NotificationCenter lowercase
When we require a singleton, its instance name should be named
by lowercase, since it is not a class.

Relates to #128
2016-10-10 22:11:55 +02:00
logsol
ffc55a204a Makes singleton object variable names of DomController first letter lowercase
When we require a singleton, its instance name should be named
by lowercase, since it is not a class.

Relates to #128
2016-10-10 21:50:03 +02:00
logsol
875a40185e Increases score limit back to a higher value
It had been reduced to 1 for testing.
2016-10-10 20:15:41 +02:00
logsol
8fc1fb5d4e Adds newly generated github API token to "unavailable game" page 2016-10-09 22:00:46 +02:00
logsol
b798e6acac Adds forward walking on shift
The state of the shift modifier is now distributed across the
network. Walking speeds and animation states are being updated
according to it.

Fixes #130
2016-10-09 19:56:06 +02:00
logsol
062402db58 Adds NotificationCenter exception when triggering unknown topic
If you forget to add a certain topic to the Nc, you will
now get an Exception with a meaningful message.
2016-10-09 19:27:10 +02:00
logsol
dba743cd7b Updates obsolete/broken way of clearing fingerprints
When a user leaves the channel, some items need to be cleared of
their fingerprints (lastTouchedBy). This feature was broken
because it used the this.gameObjects pool which was no longer in
use.

The channel GameController now triggers an event to which all
items are subscribed to and if it is triggered, all items with that
users fingerprints clear themselves off those.

Fixes #170
2016-10-09 12:46:07 +02:00
logsol
3a5af058ef Prevents adding damage after round has ended
Because it created double round endings, which led to crashes.
Also moved inBetweenRound state from PlayerController to GameController.
2016-10-01 19:12:52 +02:00
logsol
c068592915 Makes world in Engine private
And some refactoring.
2016-10-01 19:09:52 +02:00
logsol
8641a2dc0b On destroy unsubscribe missing GameObjects from render event
fixes #71
2016-10-01 16:51:43 +02:00
logsol
8b8093b771 Stops sending gameCommands between beginRound and clientReady
Listen for beginRound control command
to set client to be unready again
so it can load its new level without getting
any gameCommands like worldUpdate
2016-10-01 16:08:01 +02:00
logsol
016c48ec3b During first worldUpdate set doll positions after spawning players
Otherwise we get a warning.
2016-10-01 14:01:12 +02:00
logsol
a5f828a861 Adds NETWORK_LOG_FILTER setting to incoming network messages 2016-10-01 13:43:37 +02:00
logsol
fc7866f11e Hides playercontroller within player
In order to not provide deep exposure to PlayerController,
we refactored it so that it is not visible anymore outside Player.

Also we renamed isInBetweenGames to inBetweenRounds.

Moved creation of PlayerController from GameController(s) to
The channel Player and client Me.
2016-10-01 12:19:02 +02:00
logsol
8d8a55cc8c adds core analyzer script which generates the core/channel/client method overview of a class 2016-08-29 00:33:59 +02:00
logsol
c87997c774 fixes #147, fixes #136, is related to but doesnt entirely complete #144 2016-08-28 22:40:25 +02:00
logsol
502cf72a7e fixes #157 2016-08-28 13:24:27 +02:00
Jeena
f35b9f5ba9 fixed flip for RubeDoll 2015-08-02 17:22:41 +02:00
Jeena
0b8d885d48 Merge branch 'master' into subbodies 2015-08-02 16:06:57 +02:00
Jeena
a8adbcf140 fixes position state update and removes dev graphs for better fps 2015-08-02 16:06:32 +02:00
logsol
0edde06d67 only adds lastMovedBy when there was no damage - fixes #99 2015-08-02 11:38:45 +02:00
logsol
e370adf746 worldupdate subbody repositioning - #99 2015-06-29 01:29:57 +02:00
Jeena
2e01a093fc first step of rotating limbs in RubeDoll 2015-06-28 16:26:52 -07:00
logsol
db95465208 fixed a bug in gangsta level 2015-06-29 01:24:05 +02:00
logsol
7cd4cc702b should fix a bug happening on live deployment 2015-06-28 20:11:28 +02:00
logsol
eb29a00012 only adds lastMovedBy when there was no damage - fixes #108 2015-06-28 19:44:26 +02:00
logsol
b46c309dbe Merge branch 'master' of github.com:logsol/chuck.js 2015-06-28 19:11:46 +02:00
logsol
71db5a8a81 removes flashsocket - fixes #117 2015-06-28 19:11:37 +02:00
Karl
8f7be70407 adds video image 2015-06-28 17:06:52 +02:00
logsol
bcecddd5bd added current milestone url to not_available overview 2015-06-22 12:04:33 +02:00
logsol
318b09ca49 adds warning too many recordings. fixes #132 2015-06-22 11:58:13 +02:00
logsol
8e9ce62e19 merges from rubedoll 2015-06-22 00:22:00 +02:00
logsol
07dad646cf new system for synchronizing game objects. fixes #74 2015-06-22 00:14:17 +02:00
logsol
3ef3a6abf9 Merge branch 'ragdoll' of github.com:logsol/chuck.js into ragdoll 2015-05-11 11:12:21 +02:00
logsol
5b68f7e2b6 improving rube doll flipping behaviour and positioning 2015-05-11 11:10:30 +02:00
logsol
f1197b3045 added swapMeshes method to swap textures of 2 meshes 2015-05-11 11:10:30 +02:00
logsol
7115292384 added possibility to not debug-draw sensor shapes 2015-05-11 11:10:30 +02:00
logsol
cb23c1fb05 centered rubedoll head 2015-05-11 11:10:30 +02:00
logsol
8e70eedbce added setting to switch off pointer lock filter 2015-05-11 11:10:30 +02:00
logsol
fb3ac40d17 implemented rubedoll direction flip and added meshIndex (z) swapping capability. #151 2015-05-11 11:10:30 +02:00
logsol
da7e0758bb changed box2d calculation config #158 2015-05-11 11:10:30 +02:00
logsol
2dea240a4b implemented rube doll to appear when dying 2015-05-11 11:10:30 +02:00
logsol
cd956b8a28 fixed a few bugs - rube loader was manipulating the json, which resulted in coordinates flipping every second time 2015-05-11 11:10:30 +02:00
logsol
ca1ca7635b implemented rubedoll level item (not after dying yet) 2015-05-11 11:10:30 +02:00
logsol
1546136303 rebuilt skateboard without joints 2015-05-11 11:10:30 +02:00
logsol
287b5e0e18 added skateboard to debug 2015-05-11 11:10:29 +02:00
logsol
da62339a95 rebuilt skateboard without joints 2015-05-11 11:09:24 +02:00
logsol
97da7770d0 repaired debug view (offsetting) 2015-05-11 11:09:24 +02:00
logsol
6d8609b475 improving rube doll flipping behaviour and positioning 2015-05-06 20:15:22 +02:00
logsol
ec7ce459cb added swapMeshes method to swap textures of 2 meshes 2015-05-06 20:13:13 +02:00
logsol
1db8de34df added possibility to not debug-draw sensor shapes 2015-05-06 20:11:12 +02:00
logsol
8da2d48643 centered rubedoll head 2015-05-04 14:02:53 +02:00
logsol
413f5424c2 added setting to switch off pointer lock filter 2015-05-04 14:01:23 +02:00
Logsol
6233588e63 cleared items of player fingerprints (lastMovedBy). fixes #92 2015-05-03 12:45:35 +02:00
logsol
a5f45ffef6 implemented rubedoll direction flip and added meshIndex (z) swapping capability. #151 2015-04-29 00:04:17 +02:00
logsol
0da744f5fd changed box2d calculation config #158 2015-04-28 15:50:45 +02:00
logsol
b3fbf34cf7 implemented rube doll to appear when dying 2015-04-28 14:57:22 +02:00
logsol
c4fcb2fabf fixed a few bugs - rube loader was manipulating the json, which resulted in coordinates flipping every second time 2015-04-28 14:56:29 +02:00
logsol
432efccdeb merged from master 2015-04-28 11:57:36 +02:00
logsol
bd7edc779e removed the piano for our test session 2015-04-23 19:06:33 +02:00
logsol
c67ff78aa0 implemented rubedoll level item (not after dying yet) 2015-04-20 21:20:56 +02:00
logsol
b12bf2bb0c rebuilt skateboard without joints 2015-04-20 16:00:07 +02:00
logsol
09eaf1a85c added skateboard to debug 2015-04-20 15:59:07 +02:00
logsol
8f5ee0b247 rebuilt skateboard without joints 2015-04-20 15:58:41 +02:00
logsol
39c8f76a13 repaired debug view (offsetting) 2015-04-20 15:31:25 +02:00
Jeena
545e051598 make better gangsta level fixes #114 2015-04-19 19:04:02 +02:00
Jeena
ed35071fff fixes enemy stat update 2015-04-19 18:13:53 +02:00
Jeena
a66a327386 fixes the sending and rendering of game stats 2015-04-19 17:31:41 +02:00
Jeena
cad112419d fixes initial level positioning 2015-04-19 16:06:23 +02:00
Jeena
aaa1db4468 hides default layers while loading level 2015-04-19 12:33:45 +02:00
Jeena
a22fbcbbc8 removed console logs 2015-04-19 11:23:19 +02:00
Jeena
0592e2524d added gangsta level and tried to fix on new level 2015-04-12 18:08:11 +02:00
Jeena
3283f97f07 added production2 to ecosystem 2015-04-02 23:02:51 +02:00
Jeena
5a4cec5ae8 added production2 fixes #125 2015-04-02 23:01:02 +02:00
Jeena
aff23e8de0 better handling of dangerousnes, etc. fixes #107 2015-04-02 22:49:43 +02:00
Jeena
46f14c22c6 made fast objects bullets, fixes #126 2015-04-02 21:27:13 +02:00
logsol
f9d97c5a47 trying a new approach to calculating damager 2015-04-02 19:35:10 +02:00
Jeena
16826b174a fixed debug view and ragdoll start positioning 2015-03-16 01:50:41 +01:00
Jeena
b6d979fe7c Merge branch 'recording' 2015-03-15 21:07:45 +01:00
Jeena
c88afc8b4c fixes #112 finished recorder 2015-03-15 21:06:44 +01:00
Jeena
dfa71bc8e5 added ASSERT, fixed #103 2015-03-15 16:51:38 +01:00
Jeena
55eff36f34 added semicolon because of jslint 2015-03-15 13:41:10 +01:00
Jeena
51e719b509 added semicolon because of jslint 2015-03-15 13:39:51 +01:00
logsol
69a3213df8 added deep console log to show last message, fixed bug with / in recording path 2015-03-13 14:48:26 +01:00
logsol
5a8783f29e merge 2015-03-12 22:22:59 +01:00
Jeena
1408b6addd first version of recorder 2015-03-12 22:17:34 +01:00
logsol
d36e89bacd Added a new level #114 2015-03-12 19:57:47 +01:00
logsol
bbd143eae0 decreased jumping height a bit, was still too high i think 2015-03-12 19:57:05 +01:00
logsol
b3ee560c02 still level loader bug (only allowed square sized maps) 2015-03-12 19:56:14 +01:00
logsol
d975792ebd added a couple of items 2015-03-12 19:55:26 +01:00
logsol
f467aa393a found bug in level loader 2015-03-12 19:53:08 +01:00
logsol
feca76f677 #79 added possibility to add non-colliding tile layers from tiled editor 2015-03-12 11:11:16 +01:00
logsol
61e66f5796 fixed #97 chuck stops when he shouldnt, also removed f/g for handActionRequestLeft and Right, since we don't need it for DebugDraw anymore. 2015-03-10 14:42:54 +01:00
logsol
5f5fec5b10 added optimizer scripts and some code style improvements 2015-03-09 04:56:28 +01:00
logsol
6b472dc134 added max user and refactored coordinator/serveruser a bit fixes #105 2015-03-03 23:43:15 +01:00
logsol
ccd146f01b changed file names (github milestone widget) 2015-03-03 19:47:37 +01:00
logsol
9e906857a2 changed file names (github milestone widget) 2015-03-03 19:47:19 +01:00
logsol
65d79b110a added cool milestone widget to not_available page 2015-03-03 19:37:46 +01:00
logsol
67507333c4 added ping histograph and made disconnect clear with page reload. fixes #104 fixes #122 2015-03-03 15:34:43 +01:00
logsol
6f5c24dd9c added a small bot script and the possibility to trigger Nc from Chuck.inspector 2015-03-03 15:33:51 +01:00
logsol
6149b6c47b fixed a small bug regarding suicide and killedByItem 2015-03-02 19:55:24 +01:00
logsol
5eeb120799 added chart.js path to build-profile of production env 2015-03-02 19:48:05 +01:00
logsol
b52c16836c added not available site to show for error 502 Bad Gateway (when game is not running) 2015-03-02 17:52:48 +01:00
logsol
5007ab5b02 better feedback on killing. fixes #109 2015-03-02 00:13:21 +01:00
Jeena
5d70170ed9 first version of recorder 2015-03-01 19:32:31 +01:00
Jeena
81f5990e0c fixes #96 j.m_collideConnected crash 2015-03-01 16:37:06 +01:00
Jeena
90a282cbd0 fixed exception to error instead of log 2015-03-01 16:36:12 +01:00
Jeena
9f32562a8d cleaning up after #36 2015-03-01 16:35:22 +01:00
Jeena
f4c7d9edeb cleanup debug canvas #36 2015-03-01 15:09:14 +01:00
Jeena
8dacc83f7a fixed #36 debug draw working 2015-03-01 14:54:56 +01:00
Jeena
15a267f250 hidden debug printout of layers 2015-03-01 14:54:37 +01:00
Jeena
58d5a859fe added chart.js dependency 2015-03-01 10:30:56 +01:00
logsol
20a974124e added new debug draw 2015-02-28 21:27:42 +01:00
logsol
13af9ecb9c worked a bit on menu top bar 2015-02-28 19:57:05 +01:00
logsol
60eae208a2 Added PointerLockManagement, Fixed layer positioning, added fps chart. fixes #120, fixes #121, fixes #123 2015-02-27 18:44:30 +01:00
logsol
8d0989844c improved maps 2015-02-27 18:40:03 +01:00
logsol
3138509a57 added current channel user playing to list. fixes #106 2015-02-22 19:30:37 +01:00
Jeena
e452399caf added menuBar 2015-02-22 18:39:35 +01:00
logsol
d7025ffd67 adapted fps meter 2015-02-22 17:57:16 +01:00
Jeena
550d14fbef fixed #110 rewrite of tab-view and better fonts 2015-02-22 17:36:06 +01:00
logsol
06351e5828 reenabled all maps 2015-02-19 18:52:57 +01:00
Jeena
e404ad3598 fixes #78 revisited weight handycap 2015-02-15 01:38:16 +01:00
Jeena
b6d67a0581 fixes #98 revisit throwing 2015-02-14 19:28:52 +01:00
Jeena
21f948e2b4 Workaround for PIXI going black after 4 renderers 2015-02-14 19:28:18 +01:00
Jeena
a340501dc2 removed objects with joints because of #99 2015-02-14 15:01:53 +01:00
logsol
ea3a802af9 Finetuned quickstart 2015-02-07 16:35:56 +01:00
logsol
d2a49ebdc6 Finetuned quickstart 2015-02-07 16:33:49 +01:00
logsol
ac69077e8a disabled spectator doll - was falling forever 2015-02-07 16:16:28 +01:00
logsol
93680e3286 fixed movieclip speed/fps bug. fixes #35 2015-02-07 15:37:40 +01:00
logsol
5caa21f453 fixed item throw interface of ragdoll fixes #93 2015-02-07 14:30:55 +01:00
logsol
15e4b2825f Added SpriteSheet support to chuck animations (finished) 2015-01-14 17:45:55 +01:00
logsol
dbde25f76e Added SpriteSheet support to chuck animations 2015-01-14 17:31:38 +01:00
logsol
c6add97a38 cleaned up image folder a bit 2015-01-13 13:29:26 +01:00
logsol
809a622cd9 bugfix throwing exception 2014-12-28 20:34:45 +01:00
logsol
4f3a53ca53 fixed #91 crash after round end 2014-12-27 22:35:26 +01:00
logsol
b92cce88f2 changing back dev deploy to master 2014-12-26 23:58:42 +01:00
logsol
b152053d18 fixed fullscreen swiper 2014-12-26 23:53:44 +01:00
logsol
af0fb2ef6e set production log level of socket io 2014-12-26 23:53:32 +01:00
logsol
ece260e80e fixed drop error. added carrier velocity, bugfix 2014-12-25 15:06:36 +01:00
logsol
197c4072c1 fixed drop error. added carrier velocity 2014-12-25 15:00:10 +01:00
Jeena
7aa417dfc8 Merge branch 'master' into controls 2014-12-25 12:56:48 +01:00
logsol
73086e3c15 deployment stuff 2014-12-25 11:54:06 +01:00
logsol
950402a76e Merge branch 'master' into controls 2014-12-25 11:46:48 +01:00
logsol
9986143dc2 splitted ecosystem config 2014-12-25 11:46:31 +01:00
logsol
28bedbc594 merged master 2014-12-25 02:40:51 +01:00
logsol
c1ee3df3f9 development stuff 2014-12-25 02:40:12 +01:00
logsol
37b6875f5a Merge branch 'master' into controls 2014-12-25 02:31:56 +01:00
logsol
e55b64e3e9 deployment stuff 2014-12-25 02:31:41 +01:00
logsol
9b2e9b9f4e Merge branch 'master' into controls 2014-12-25 02:29:10 +01:00
logsol
d8a49779ae deployment stuff 2014-12-25 02:10:13 +01:00
logsol
a0731d8afd deployment stuff 2014-12-25 02:05:29 +01:00
logsol
300f6e4ae3 set up pm2 deployment 2014-12-25 02:02:26 +01:00
logsol
d24ab60756 added angular throwing 2014-12-25 00:33:00 +01:00
logsol
9100215ceb Merge branch 'master' into controls 2014-12-22 02:43:57 +01:00
logsol
340f05b8d9 fixed some bugs related to use strict 2014-12-22 02:43:12 +01:00
logsol
1f8f0ef6e1 merged from master (use strict) 2014-12-22 02:00:40 +01:00
logsol
2b186be8af use strict; fixes #83 2014-12-22 01:43:21 +01:00
logsol
a4637978ee deleted wrong file 2014-12-22 00:32:38 +01:00
logsol
b886728bf5 deleted wrong file 2014-12-22 00:28:47 +01:00
logsol
005913dae9 restructured scripts for building and some improvements 2014-12-21 23:16:35 +01:00
logsol
c33e9f62b9 moved build stuff 2014-12-21 23:16:35 +01:00
logsol
58b83f7297 updated pixi to v2 2014-12-21 23:16:35 +01:00
logsol
8dbc088813 restructured scripts for building and some improvements 2014-12-21 23:02:27 +01:00
logsol
74134a53af moved build stuff 2014-12-21 20:28:00 +01:00
logsol
c704e31beb Added gzip support #82 bugfix 2014-12-21 19:40:00 +01:00
logsol
c52fc549e1 Added gzip support #82 2014-12-21 19:39:49 +01:00
logsol
3b43119d93 Compile and minimize code #82 2014-12-21 19:39:03 +01:00
logsol
f02230c50c updated pixi to v2 2014-12-21 19:32:18 +01:00
logsol
a5b3d2f671 Added gzip support #82 bugfix 2014-12-20 05:39:35 +01:00
logsol
f29883d47f Added gzip support #82 2014-12-20 05:30:22 +01:00
logsol
6f288f00b5 Compile and minimize code #82 2014-12-20 04:31:37 +01:00
logsol
0a0b3e8849 added simple mode 2014-12-09 15:55:28 +01:00
logsol
1e233efbea Added Swiper drawing 2014-12-08 19:36:14 +01:00
Jeena
cf2182676b Throwing with Swiper, working but needs to be refined. No angulat verlocity yet. 2014-12-07 00:57:05 +01:00
Jeena
6d9d02615a added pointer locking and viewport moving 2014-12-06 20:20:49 +01:00
logsol
072e984215 fixed health bar 2014-11-30 15:19:02 +01:00
logsol
c1a756050f added ghost layer, fixed arrow 2014-11-30 15:06:02 +01:00
logsol
81ccdaa127 cleanup 2014-11-30 13:43:22 +01:00
Jeena
4dd529e663 Merge branch 'layers' 2014-11-16 01:23:42 +01:00
Jeena
1bdc798540 first stab at background audio 2014-11-16 01:22:58 +01:00
Jeena
2e67ea0d47 added transparent longon background 2014-11-16 01:20:59 +01:00
logsol
f9e46b4491 added backgrounds to stones level 2014-11-16 00:03:51 +01:00
Jeena
be3da8d2a5 preloading all image layer images 2014-11-15 23:47:20 +01:00
Jeena
85867f92af working paralax (not for zoom) 2014-11-15 23:28:03 +01:00
Jeena
357ef181d9 centered images in image layers 2014-11-15 17:37:16 +01:00
Jeena
9c9db8ca8c loading graphic layers works with right order 2014-11-15 17:02:27 +01:00
Jeena
522b5092f5 changed 'collision' to 'tiles' layer name in levels 2014-11-15 13:17:41 +01:00
logsol
a70ca6d8fb working layers - still needs parallax support 2014-08-31 17:50:55 +02:00
Jeena
222fd09f3f non working layers 2014-08-30 16:27:05 +02:00
Jeena
57135f3acc more layer work 2014-08-30 16:02:41 +02:00
logsol
b5c70687d8 moved some classes, added layer manager 2014-08-30 14:47:31 +02:00
logsol
1d3ad16a07 layer bugfixing 2014-08-30 10:29:58 +02:00
Jeena
d29c64385d added layers 2014-07-27 17:21:37 +02:00
Jeena
7c783d19e8 Refactored abstract method creation 2014-07-27 13:03:40 +02:00
logsol
1a71fa38f9 added background, still needs parallax style scrolling though! - fixes #89 2014-07-23 23:43:36 +02:00
logsol
a58beb58d1 added player arrow to me fixes #76 2014-07-18 17:34:17 +02:00
Jeena
8f2cf11e38 finished shirt color, fixes #77 2014-07-12 20:49:42 +02:00
Jeena
a5c1c05bb4 fixes the fullscreen zoom bug 2014-07-12 17:44:57 +02:00
Jeena
1a6d8effad Moved menu to require.js style, ref #77 2014-07-12 17:31:18 +02:00
Jeena
2213a50623 colorfull shirts 2014-07-12 16:23:17 +02:00
logsol
40cdf9867e added notification center call for adding filters to meshes 2014-07-12 12:15:59 +02:00
logsol
460aa9678d Merge branch 'shirt' of github.com:logsol/chuck.js into shirt 2014-07-07 23:35:47 +02:00
Jeena
9a7b485324 first draft of opengl filter 2014-07-07 23:34:45 +02:00
logsol
ac27da1e31 added zooming with +, - and 0 2014-07-07 23:32:11 +02:00
Jeena
f6de53c5ed first draft of opengl filter 2014-07-03 23:09:09 +02:00
Jeena
cc8cf6c5f9 sort maps in api 2014-07-03 20:35:12 +02:00
Jeena
1c0bedee06 deactivated special Skateboard for now 2014-07-03 20:28:36 +02:00
Jeena
6bc9b7e32b api getMaps for create channel 2014-07-03 20:28:18 +02:00
Jeena
a837d2099c menu fixes 2014-06-29 00:52:32 +02:00
Jeena
2343049227 changed this to self because of #65 hope this helps 2014-06-29 00:14:56 +02:00
Jeena
e74c7b8219 changed style and clearTimeout 2014-06-29 00:04:43 +02:00
Jeena
9e6c42f221 removed game.html, fixes #85 2014-06-28 23:43:58 +02:00
logsol
b86052e93b added first draft of a new level 2014-06-15 03:05:47 +02:00
Jeena
ebf167107a implemented holding arm. fixes #75 2014-06-14 18:37:21 +02:00
logsol
03cb005372 fixed arm animations 2014-06-14 15:08:23 +02:00
logsol
c891982d49 cleaned up character animations, added holding arm graphic #75 2014-06-14 13:07:55 +02:00
1028 changed files with 64211 additions and 8252 deletions

3
.gitignore vendored
View file

@ -3,4 +3,5 @@ node_modules/
.DS_Store
lab/audio/
lab/filter/
static/items/rube/*-backups
static/items/rube/*-backups
build/

View file

@ -2,8 +2,10 @@ chuck.js
========
Physical JavaScript Action Browser Multiplayer Game - it will be awesome!
[![Foo](http://25.media.tumblr.com/8249dcd3bdb176686421d1914937db1c/tumblr_mzc1ejGxNC1ry8awho1_400.png)](http://chuck-game.tumblr.com/ "Screenshot of chuck.js - click to visit our development blog!")
<a href="http://chuck-game.tumblr.com/about" title="Play the chuck trailer" target="_blank">
<img src="https://cloud.githubusercontent.com/assets/692826/8396811/3369df82-1db6-11e5-939f-5ceeba64d802.png">
</a>
Follow the development at http://chuck-game.tumblr.com/

View file

@ -1,92 +1,74 @@
define([
'http',
'node-static',
'Server/Api'
'express',
'http',
'path',
'Server/Api',
'fs'
],
function (http, nodeStatic, Api) {
function (express, http, path, Api, fs) {
"use strict";
function HttpServer (options, coordinator) {
options.port = options.port || 1234;
options.caching = typeof options.caching != 'undefined' ? options.caching : 3600;
options.rootDirectory = options.rootDirectory || './';
this.server = null;
this.api = new Api(coordinator);
this.app = express();
this.server = http.createServer(this.app);
this.init(options);
}
HttpServer.prototype.init = function (options) {
var self = this;
var app = this.app;
var fileServer = new nodeStatic.Server(options.rootDirectory, { cache: options.caching });
// Serve static files
app.use('/static', express.static(path.join(options.rootDirectory, 'static')));
app.use('/app', express.static(path.join(options.rootDirectory, 'app')));
this.server = http.createServer(
function (req, res) {
var fullBody = '';
req.addListener('data', function(chunk) { // doesn't work on Jeenas computer without this
fullBody += chunk.toString();
});
// Serve index.html at root
app.get('/', function(req, res) {
res.sendFile(path.resolve(options.rootDirectory, 'static/html/index.html'));
});
req.addListener('error', function(err) {
console.log('');
});
req.addListener('end', function () {
switch(true) {
case req.url == '/':
fileServer.serveFile('./static/html/index.html', 200, {}, req, res);
console.checkpoint('HTTP Server serves index');
break;
case req.url == '/game.html':
fileServer.serveFile('./static/html/game.html', 200, {}, req, res);
console.checkpoint('HTTP Server serves game');
break;
case req.url == '/client.js':
fileServer.serveFile('./client.js', 200, {}, req, res);
break;
case req.url == '/require.js':
fileServer.serveFile('./node_modules/requirejs/require.js', 200, {}, req, res);
break;
case req.url == '/screenfull.js':
fileServer.serveFile('./node_modules/screenfull/dist/screenfull.js', 200, {}, req, res);
break;
case req.url == '/api':
self.api.handleCall(fullBody);
var status = self.api.isError ? 400 : 200;
res.writeHead(status, {"Content-Type": self.api.getContentType()});
res.end(self.api.getOutput());
self.api.isError = false;
break;
case new RegExp(/^\/app/).test(req.url):
fileServer.serve(req, res, function () {
self.handleFileError(res)
});
break;
case new RegExp(/^\/static/).test(req.url):
fileServer.serve(req, res, function () {
self.handleFileError(res)
});
break;
default:
self.handleFileError(res);
break;
}
});
// Serve client.js and minified version
app.get('/client.js', function(req, res) {
if (process.env.NODE_ENV === 'production' && fs.existsSync(path.resolve(options.rootDirectory, 'build/client.min.js'))) {
res.sendFile(path.resolve(options.rootDirectory, 'build/client.min.js'));
} else {
res.sendFile(path.resolve(options.rootDirectory, 'client.js'));
}
);
});
app.get('/client.min.js', function(req, res) {
res.sendFile(path.resolve(options.rootDirectory, 'build/client.min.js'));
});
// Serve require.js, screenfull.js, chart.js from node_modules
app.get('/require.js', function(req, res) {
res.sendFile(path.resolve(options.rootDirectory, 'node_modules/requirejs/require.js'));
});
app.get('/screenfull.js', function(req, res) {
res.sendFile(path.resolve(options.rootDirectory, 'static/vendor/screenfull.js'));
});
app.get('/chart.js', function(req, res) {
// Chart.js v4 uses 'dist/chart.umd.js'
res.sendFile(path.resolve(options.rootDirectory, 'node_modules/chart.js/dist/chart.umd.js'));
});
// API endpoint
app.post('/api', express.text({type: '*/*'}), function(req, res) {
self.api.handleCall(req.body);
var status = self.api.isError ? 400 : 200;
res.status(status).type(self.api.getContentType()).send(self.api.getOutput());
self.api.isError = false;
});
// 404 handler
app.use(function(req, res) {
res.status(404).send('<h1>404 not ... found</h1>');
});
this.server.once('error', function(err) {
if(err.code == 'EADDRINUSE') {
@ -97,7 +79,6 @@ function (http, nodeStatic, Api) {
});
this.server.listen(options.port);
console.checkpoint('start HTTP server');
}
@ -105,10 +86,5 @@ function (http, nodeStatic, Api) {
return this.server;
}
HttpServer.prototype.handleFileError = function (res) {
res.writeHead(404, {'Content-Type': 'text/html'});
res.end('<h1>404 not ... found</h1>');
}
return HttpServer;
});

View file

@ -4,29 +4,23 @@ define([
function (io) {
function Socket (server, options, coordinator) {
options.logLevel = typeof options.logLevel != 'undefined'
? options.logLevel
: 0;
this.coordinator = coordinator;
this.socket = io.listen(server);
"use strict";
function Socket (server, options, coordinator) {
this.coordinator = coordinator;
this.io = io(server, {
// No more 'log level' or 'transports' in v4
// Add any v4-compatible options here if needed
});
this.init(options);
}
Socket.prototype.init = function (options) {
var self = this;
this.socket.configure('development', function () {
this.set('log level', options.logLevel);
});
this.socket.on('connection', function (user) {
this.io.on('connection', function (socket) {
console.checkpoint('socket receiving connection');
self.onConnection(user);
self.onConnection(socket);
});
console.checkpoint('start Socket Listener');
}

View file

@ -0,0 +1,783 @@
{
"allowSleep" : true,
"autoClearForces" : true,
"body" :
[
{
"angle" : 0,
"angularVelocity" : 0,
"awake" : true,
"fixture" :
[
{
"density" : 1,
"filter-groupIndex" : -55,
"friction" : 0.2,
"name" : "fixture3",
"polygon" :
{
"vertices" :
{
"x" :
[
0.04692989960312843,
0.04692989960312843,
-0.04693000018596649,
-0.04693000018596649
],
"y" :
[
-0.1895969957113266,
0.1895969957113266,
0.1895969957113266,
-0.1895969957113266
]
}
}
}
],
"linearVelocity" : 0,
"massData-I" : 0.0004525936674326658,
"massData-center" :
{
"x" : -5.029141902923584e-08,
"y" : 0
},
"massData-mass" : 0.03559110686182976,
"name" : "upperLeftArm",
"position" :
{
"x" : -0.1165359988808632,
"y" : 0.9012569785118103
},
"type" : 2
},
{
"angle" : 0,
"angularVelocity" : 0,
"awake" : true,
"fixture" :
[
{
"density" : 1,
"filter-groupIndex" : -55,
"friction" : 0.2,
"name" : "fixture2",
"polygon" :
{
"vertices" :
{
"x" :
[
0.1366278976202011,
0.1366278976202011,
-0.1360991001129150,
-0.1360991001129150
],
"y" :
[
-0.3788780868053436,
0.3830279111862183,
0.3830279111862183,
-0.3788780868053436
]
}
}
}
],
"linearVelocity" : 0,
"massData-I" : 0.01134084537625313,
"massData-center" :
{
"x" : 0.0002643987536430359,
"y" : 0.002074912190437317
},
"massData-mass" : 0.2077923566102982,
"name" : "chest",
"position" :
{
"x" : 0.0007875636219978333,
"y" : 0.7995355725288391
},
"type" : 2
},
{
"angle" : 0,
"angularVelocity" : 0,
"awake" : true,
"fixture" :
[
{
"circle" :
{
"center" :
{
"x" : -0.01561669446527958,
"y" : 0.004700659774243832
},
"radius" : 0.2268356680870056
},
"density" : 0.2204959988594055,
"filter-groupIndex" : -55,
"friction" : 0.2,
"name" : "fixture1"
}
],
"linearVelocity" : 0,
"massData-I" : 0.0009264730615541339,
"massData-center" :
{
"x" : -0.01561669446527958,
"y" : 0.004700659774243832
},
"massData-mass" : 0.03564291819930077,
"name" : "head",
"position" :
{
"x" : 0.02309736609458923,
"y" : 1.497289657592773
},
"type" : 2
},
{
"angle" : 0,
"angularVelocity" : 0,
"awake" : true,
"fixture" :
[
{
"density" : 1,
"filter-groupIndex" : -55,
"friction" : 0.2,
"name" : "fixture3",
"polygon" :
{
"vertices" :
{
"x" :
[
0.04693000018596649,
0.04693000018596649,
-0.04693005979061127,
-0.04693005979061127
],
"y" :
[
-0.1159216761589050,
0.1159217953681946,
0.1159217953681946,
-0.1159216761589050
]
}
}
}
],
"linearVelocity" : 0,
"massData-I" : 0.0001134485355578363,
"massData-center" :
{
"x" : -2.980232238769531e-08,
"y" : 5.960464477539062e-08
},
"massData-mass" : 0.02176084183156490,
"name" : "lowerRightArm",
"position" :
{
"x" : 0.1183081120252609,
"y" : 0.6842151284217834
},
"type" : 2
},
{
"angle" : 0,
"angularVelocity" : 0,
"awake" : true,
"fixture" :
[
{
"density" : 1,
"filter-groupIndex" : -55,
"friction" : 0.2,
"name" : "fixture3",
"polygon" :
{
"vertices" :
{
"x" :
[
0.07039500027894974,
0.07039500027894974,
-0.07039500027894974,
-0.07039500027894974
],
"y" :
[
-0.09294360131025314,
0.1277720034122467,
0.1277720034122467,
-0.09294360131025314
]
}
}
}
],
"linearVelocity" : 0,
"massData-I" : 0.0001869037223514169,
"massData-center" :
{
"x" : 0,
"y" : 0.01741420105099678
},
"massData-mass" : 0.03107454814016819,
"name" : "lowerLeftLeg",
"position" :
{
"x" : -0.03829947486519814,
"y" : 0.09799569845199585
},
"type" : 2
},
{
"angle" : 0,
"angularVelocity" : 0,
"awake" : true,
"fixture" :
[
{
"density" : 1,
"filter-groupIndex" : -55,
"friction" : 0.2,
"name" : "fixture3",
"polygon" :
{
"vertices" :
{
"x" :
[
0.04693000763654709,
0.04693000763654709,
-0.04692991077899933,
-0.04692991077899933
],
"y" :
[
-0.1159216761589050,
0.1159217953681946,
0.1159217953681946,
-0.1159216761589050
]
}
}
}
],
"linearVelocity" : 0,
"massData-I" : 0.0001134483172791079,
"massData-center" :
{
"x" : 4.842877032729120e-08,
"y" : 5.960464477539062e-08
},
"massData-mass" : 0.02176081016659737,
"name" : "lowerLeftArm",
"position" :
{
"x" : -0.1165381968021393,
"y" : 0.6842151284217834
},
"type" : 2
},
{
"angle" : 0,
"angularVelocity" : 0,
"awake" : true,
"fixture" :
[
{
"density" : 1,
"filter-groupIndex" : -55,
"friction" : 0.2,
"name" : "fixture3",
"polygon" :
{
"vertices" :
{
"x" :
[
0.04693000018596649,
0.04693000018596649,
-0.04693010076880455,
-0.04693010076880455
],
"y" :
[
-0.1895969957113266,
0.1895969957113266,
0.1895969957113266,
-0.1895969957113266
]
}
}
}
],
"linearVelocity" : 0,
"massData-I" : 0.0004525947733782232,
"massData-center" :
{
"x" : -5.029141902923584e-08,
"y" : 0
},
"massData-mass" : 0.03559118881821632,
"name" : "upperRightArm",
"position" :
{
"x" : 0.1183080002665520,
"y" : 0.9012569785118103
},
"type" : 2
},
{
"angle" : 0,
"angularVelocity" : 0,
"awake" : true,
"fixture" :
[
{
"density" : 1,
"filter-groupIndex" : -55,
"friction" : 0.2,
"name" : "fixture3",
"polygon" :
{
"vertices" :
{
"x" :
[
0.07039496302604675,
0.07039496302604675,
-0.07039486616849899,
-0.07039486616849899
],
"y" :
[
-0.1890522241592407,
0.1890524625778198,
0.1890524625778198,
-0.1890522241592407
]
}
}
}
],
"linearVelocity" : 0,
"massData-I" : 0.0007221315754577518,
"massData-center" :
{
"x" : 4.842877388000488e-08,
"y" : 1.192092895507812e-07
},
"massData-mass" : 0.05323329567909241,
"name" : "upperRightLeg",
"position" :
{
"x" : 0.03859551250934601,
"y" : 0.3325110077857971
},
"type" : 2
},
{
"angle" : 0,
"angularVelocity" : 0,
"awake" : true,
"fixture" :
[
{
"density" : 1,
"filter-groupIndex" : -55,
"friction" : 0.2,
"name" : "fixture3",
"polygon" :
{
"vertices" :
{
"x" :
[
0.07039505988359451,
0.07039505988359451,
-0.07039495557546616,
-0.07039495557546616
],
"y" :
[
-0.1890522241592407,
0.1890524625778198,
0.1890524625778198,
-0.1890522241592407
]
}
}
}
],
"linearVelocity" : 0,
"massData-I" : 0.000722132739610970,
"massData-center" :
{
"x" : 5.215406417846680e-08,
"y" : 1.192092824453539e-07
},
"massData-mass" : 0.05323336645960808,
"name" : "upperLeftLeg",
"position" :
{
"x" : -0.03829947486519814,
"y" : 0.3325110077857971
},
"type" : 2
},
{
"angle" : 0,
"angularVelocity" : 0,
"awake" : true,
"fixture" :
[
{
"density" : 1,
"filter-groupIndex" : -55,
"friction" : 0.2,
"name" : "fixture3",
"polygon" :
{
"vertices" :
{
"x" :
[
0.07039500027894974,
0.07039500027894974,
-0.07039490342140198,
-0.07039490342140198
],
"y" :
[
-0.09294389933347702,
0.1276109963655472,
0.1276109963655472,
-0.09294389933347702
]
}
}
}
],
"linearVelocity" : 0,
"massData-I" : 0.0001864968799054623,
"massData-center" :
{
"x" : 4.842877032729120e-08,
"y" : 0.01733354665338993
},
"massData-mass" : 0.03105190023779869,
"name" : "lowerRightLeg",
"position" :
{
"x" : 0.03859551250934601,
"y" : 0.09799569845199585
},
"type" : 2
}
],
"collisionbitplanes" :
{
"names" :
[
"bitplane1",
"bitplane2",
"bitplane3",
"bitplane4",
"bitplane5",
"bitplane6",
"bitplane7",
"bitplane8",
"bitplane9",
"bitplane10",
"bitplane11",
"bitplane12",
"bitplane13",
"bitplane14",
"bitplane15",
"bitplane16",
"bitplane17",
"bitplane18",
"bitplane19",
"bitplane20",
"bitplane21",
"bitplane22",
"bitplane23",
"bitplane24",
"bitplane25",
"bitplane26",
"bitplane27",
"bitplane28",
"bitplane29",
"bitplane30",
"bitplane31",
"bitplane32"
]
},
"continuousPhysics" : true,
"gravity" :
{
"x" : 0,
"y" : -10
},
"joint" :
[
{
"anchorA" :
{
"x" : 0.0003538504242897034,
"y" : 0.07107692956924438
},
"anchorB" :
{
"x" : 0.0003536641597747803,
"y" : -0.1459649801254272
},
"bodyA" : 3,
"bodyB" : 6,
"enableLimit" : true,
"enableMotor" : false,
"jointSpeed" : 0,
"lowerLimit" : 0.01745329238474369,
"maxMotorTorque" : 1,
"motorSpeed" : 0,
"name" : "joint1",
"refAngle" : 0,
"type" : "revolute",
"upperLimit" : 1.919862151145935
},
{
"anchorA" :
{
"x" : -0.0007802955806255341,
"y" : -0.1484909951686859
},
"anchorB" :
{
"x" : -0.0007801018655300140,
"y" : 0.08614099025726318
},
"bodyA" : 8,
"bodyB" : 4,
"enableLimit" : true,
"enableMotor" : false,
"jointSpeed" : 0,
"lowerLimit" : 0.01745329238474369,
"maxMotorTorque" : 1,
"motorSpeed" : 0,
"name" : "joint7",
"refAngle" : 0,
"type" : "revolute",
"upperLimit" : 2.443460941314697
},
{
"anchorA" :
{
"x" : -0.004979588091373444,
"y" : -0.1506859958171844
},
"anchorB" :
{
"x" : -0.005973689258098602,
"y" : 0.08482310175895691
},
"bodyA" : 7,
"bodyB" : 9,
"enableLimit" : true,
"enableMotor" : false,
"jointSpeed" : 0,
"lowerLimit" : 0.01745329238474369,
"maxMotorTorque" : 1,
"motorSpeed" : 0,
"name" : "joint8",
"refAngle" : 0,
"type" : "revolute",
"upperLimit" : 2.443460941314697
},
{
"anchorA" :
{
"x" : -0.06799955666065216,
"y" : -0.3021813035011292
},
"anchorB" :
{
"x" : -0.02891255542635918,
"y" : 0.1648437976837158
},
"bodyA" : 1,
"bodyB" : 8,
"enableLimit" : true,
"enableMotor" : false,
"jointSpeed" : 0,
"lowerLimit" : -0.7853981852531433,
"maxMotorTorque" : 1,
"motorSpeed" : 0,
"name" : "joint6",
"refAngle" : 0,
"type" : "revolute",
"upperLimit" : 1.570796370506287
},
{
"anchorA" :
{
"x" : 0.06260262429714203,
"y" : -0.3029872477054596
},
"anchorB" :
{
"x" : 0.02294230461120605,
"y" : 0.1640380322933197
},
"bodyA" : 1,
"bodyB" : 7,
"enableLimit" : true,
"enableMotor" : false,
"jointSpeed" : 0,
"lowerLimit" : -0.7853981852531433,
"maxMotorTorque" : 1,
"motorSpeed" : 0,
"name" : "joint5",
"refAngle" : 0,
"type" : "revolute",
"upperLimit" : 1.570796370506287
},
{
"anchorA" :
{
"x" : 0.1179294362664223,
"y" : 0.2464744448661804
},
"anchorB" :
{
"x" : 0.0004089996218681335,
"y" : 0.1447530388832092
},
"bodyA" : 1,
"bodyB" : 6,
"enableLimit" : false,
"enableMotor" : false,
"jointSpeed" : 0,
"lowerLimit" : -2.268928050994873,
"maxMotorTorque" : 1,
"motorSpeed" : 0,
"name" : "joint2",
"refAngle" : 0,
"type" : "revolute",
"upperLimit" : 3.141592741012573
},
{
"anchorA" :
{
"x" : -0.1188285648822784,
"y" : 0.2521644234657288
},
"anchorB" :
{
"x" : -0.001505002379417419,
"y" : 0.1504430174827576
},
"bodyA" : 1,
"bodyB" : 0,
"enableLimit" : false,
"enableMotor" : false,
"jointSpeed" : 0,
"lowerLimit" : -2.268928050994873,
"maxMotorTorque" : 1,
"motorSpeed" : 0,
"name" : "joint3",
"refAngle" : 0,
"type" : "revolute",
"upperLimit" : 3.141592741012573
},
{
"anchorA" :
{
"x" : 0.0008554458618164062,
"y" : -0.1461489796638489
},
"anchorB" :
{
"x" : 0.0008557140827178955,
"y" : 0.07089227437973022
},
"bodyA" : 0,
"bodyB" : 5,
"enableLimit" : true,
"enableMotor" : false,
"jointSpeed" : 0,
"lowerLimit" : -1.919862151145935,
"maxMotorTorque" : 1,
"motorSpeed" : 0,
"name" : "joint4",
"refAngle" : 0,
"type" : "revolute",
"upperLimit" : 0.01745329238474369
},
{
"anchorA" :
{
"x" : 0.02210754156112671,
"y" : 0.4607425332069397
},
"anchorB" :
{
"x" : -0.02544101513922215,
"y" : -0.2591779232025146
},
"bodyA" : 1,
"bodyB" : 2,
"enableLimit" : true,
"enableMotor" : false,
"jointSpeed" : 0,
"lowerLimit" : -0.6981316804885864,
"maxMotorTorque" : 0,
"motorSpeed" : 0,
"name" : "joint9",
"refAngle" : 0,
"type" : "revolute",
"upperLimit" : 1.221730470657349
}
],
"positionIterations" : 3,
"stepsPerSecond" : 60.0,
"subStepping" : false,
"velocityIterations" : 8,
"warmStarting" : true
}

View file

@ -3,11 +3,13 @@
"Lib/Utilities/NotificationCenter",
"Game/Channel/User",
"Lib/Utilities/Protocol/Helper",
"Lib/Utilities/Options",
"Lib/Utilities/OptionsHelper",
"Game/Config/Settings"
],
function (GameController, Nc, User, ProtocolHelper, Options, Settings) {
function (GameController, nc, User, ProtocolHelper, optionsHelper, Settings) {
"use strict";
function Channel (pipeToServer, options) {
@ -17,24 +19,25 @@
this.users = {};
this.pipeToServer = pipeToServer;
this.levelListIndex = -1;
this.gameController = null;
this.options = options = Options.merge(options, {
this.options = options = optionsHelper.merge(options, {
levelUids: Settings.CHANNEL_DEFAULT_LEVELS
});
// Notification Center
Nc.on(Nc.ns.channel.events.round.end, this.onEndRound, this);
Nc.on(Nc.ns.channel.events.controlCommand.channel, function (message) {
nc.on(nc.ns.channel.events.round.end, this.onEndRound, this);
nc.on(nc.ns.channel.events.controlCommand.channel, function (message) {
ProtocolHelper.applyCommand(message.data, self);
});
Nc.on(Nc.ns.channel.to.client.gameCommand.broadcast, this.broadcastGameCommand, this);
Nc.on(Nc.ns.channel.to.client.controlCommand.broadcast, this.broadcastControlCommand, this);
//Nc.on(Nc.ns.channel.to.client.gameCommand.broadcastExcept, this.broadcastGameCommandExcept, this);
//Nc.on(Nc.ns.channel.to.client.controlCommand.broadcastExcept, this.broadcastControlCommandExcept, this);
nc.on(nc.ns.channel.to.client.gameCommand.broadcast, this.broadcastGameCommand, this);
nc.on(nc.ns.channel.to.client.controlCommand.broadcast, this.broadcastControlCommand, this);
//nc.on(nc.ns.channel.to.client.gameCommand.broadcastExcept, this.broadcastGameCommandExcept, this);
//nc.on(nc.ns.channel.to.client.controlCommand.broadcastExcept, this.broadcastControlCommandExcept, this);
this.beginRound();
console.checkpoint('channel ' + this.name + ' created');
console.checkpoint("channel " + this.name + " created");
setTimeout(function() {
if(Object.keys(self.users).length < 1) {
@ -53,7 +56,7 @@
if(this.gameController) {
this.gameController.destroy();
delete this.gameController;
this.gameController = null;
}
var gameControllerOptions = {
@ -79,6 +82,7 @@
Channel.prototype.onEndRound = function() {
var self = this;
this.gameController.endRound();
this.broadcastControlCommand("endRound", true);
console.checkpoint("End Round (" + this.name + ") - Begin Round in " + Settings.CHANNEL_END_ROUND_TIME + " seconds");
@ -99,23 +103,23 @@
};
if(!this.gameController.level || !this.gameController.level.isLoaded) {
var token = Nc.on(Nc.ns.core.game.events.level.loaded, function() {
var token = nc.on(nc.ns.core.game.events.level.loaded, function() {
self.sendJoinSuccess(options);
this.users[options.id].sendControlCommand("beginRound", clientGameControllerOptions);
Nc.off(token);
self.users[options.id].sendControlCommand("beginRound", clientGameControllerOptions);
nc.off(token);
});
} else {
self.sendJoinSuccess(options);
this.sendJoinSuccess(options);
this.users[options.id].sendControlCommand("beginRound", clientGameControllerOptions);
}
}
};
Channel.prototype.sendJoinSuccess = function(options) {
var user = new User(options.id, options);
var joinedUsers = [];
for(var userId in this.users) {
joinedUsers.push(this.users[userId].options)
joinedUsers.push(this.users[userId].options);
}
var levelUid = null;
@ -125,23 +129,22 @@
this.users[user.id] = user;
var options = {
options = {
user: user.options,
joinedUsers: joinedUsers,
levelUid: levelUid
};
//Nc.trigger('user/' + user.id + "/joinSuccess", options);
//nc.trigger("user/" + user.id + "/joinSuccess", options);
user.sendControlCommand("joinSuccess", options);
Nc.trigger(Nc.ns.channel.events.user.joined, user);
nc.trigger(nc.ns.channel.events.user.joined, user);
this.broadcastControlCommandExcept("userJoined", user.options, user);
};
Channel.prototype.onReleaseUser = function (userId) {
var self = this;
var user = this.users[userId];
Nc.trigger(Nc.ns.channel.events.user.left, userId);
nc.trigger(nc.ns.channel.events.user.left, userId);
delete this.users[userId];
this.broadcastControlCommand("userLeft", userId);
@ -158,7 +161,7 @@
}
}, Settings.CHANNEL_DESTRUCTION_TIME * 1000);
}
}
};
Channel.prototype.destroy = function() {
console.checkpoint("channel (" + this.name + ") destroyed");
@ -172,7 +175,7 @@
for(var id in this.users) {
this.users[id].sendControlCommand(command, options);
}
}
};
Channel.prototype.broadcastControlCommandExcept = function (command, options, exceptUser) {
for(var id in this.users) {
@ -180,13 +183,13 @@
this.users[id].sendControlCommand(command, options);
}
}
}
};
Channel.prototype.broadcastGameCommand = function (command, options) {
for(var id in this.users) {
this.users[id].sendGameCommand(command, options);
}
}
};
Channel.prototype.broadcastGameCommandExcept = function (command, options, exceptUser) {
for(var id in this.users) {
@ -194,7 +197,7 @@
this.users[id].sendGameCommand(command, options);
}
}
}
};
return Channel;

View file

@ -4,6 +4,8 @@ define([
function (Parent) {
"use strict";
function Detector () {
Parent.call(this);
}

View file

@ -5,7 +5,9 @@ define([
"Game/Config/Settings"
],
function(Parent, Nc, Parser, Settings) {
function(Parent, nc, Parser, Settings) {
"use strict";
function PlayerController(player) {
@ -33,31 +35,34 @@ function(Parent, Nc, Parser, Settings) {
};
PlayerController.prototype.handActionRequest = function(options) {
if (options) this.player.handActionRequest(options.x, options.y);
options.x = parseFloat(options.x) || 0.0;
options.y = parseFloat(options.y) || 0.0;
options.av = parseFloat(options.av) || 0.0;
if (options) this.player.handActionRequest(options);
};
PlayerController.prototype.suicide = function() {
this.player.suicide();
};
PlayerController.prototype.mePositionStateUpdate = function(update) {
PlayerController.prototype.mePositionStateOverride = function(update) {
if(!this.player.doll) {
console.warn('me state update, even though doll does not exist');
return;
if(!this.player.isSpawned()) {
// if someone still falls but is dead on the server already
return;
}
var difference = {
x: Math.abs(update.p.x - this.player.doll.body.GetPosition().x),
y: Math.abs(update.p.y - this.player.doll.body.GetPosition().y)
}
};
if(difference.x < Settings.PUNKBUSTER_DIFFERENCE_METERS
&& difference.y < Settings.PUNKBUSTER_DIFFERENCE_METERS) {
if(difference.x < Settings.PUNKBUSTER_DIFFERENCE_METERS &&
difference.y < Settings.PUNKBUSTER_DIFFERENCE_METERS) {
this.player.doll.updatePositionState(update);
} else {
// HARD UPDATE FOR SELF
console.log(this.player.user.options.nickname + ' is cheating.')
console.log(this.player.user.options.nickname + " is cheating.");
var body = this.player.doll.body;
@ -66,7 +71,7 @@ function(Parent, Nc, Parser, Settings) {
lv: body.GetLinearVelocity()
};
Nc.trigger(Nc.ns.channel.to.client.user.gameCommand.send + this.player.id, 'positionStateReset', options);
nc.trigger(nc.ns.channel.to.client.user.gameCommand.send + this.player.id, "positionStateReset", options);
}
};

View file

@ -2,39 +2,40 @@ define([
"Game/Core/GameController",
"Game/Channel/Physics/Engine",
"Game/Config/Settings",
"Game/Channel/Control/PlayerController",
"Lib/Utilities/RequestAnimFrame",
"Lib/Utilities/NotificationCenter",
"Lib/Vendor/Box2D",
"Game/Channel/Player",
"Game/Channel/GameObjects/GameObject",
"Game/Channel/GameObjects/Doll",
"Game/Channel/GameObjects/Items/RagDoll"
"Game/Channel/GameObjects/Items/RubeDoll"
],
function (Parent, PhysicsEngine, Settings, PlayerController, requestAnimFrame, Nc, Box2D, Player, GameObject, Doll, RagDoll) {
function (Parent, PhysicsEngine, Settings, requestAnimFrame, nc, Box2D, Player, GameObject, Doll, RubeDoll) {
"use strict";
function GameController (options) {
this.animationTimeout = null;
this.worldUpdateTimeout = null;
this.spawnTimeouts = [];
this.roundHasEnded = false;
Parent.call(this, options);
this.ncTokens = this.ncTokens.concat([
Nc.on(Nc.ns.channel.events.user.joined, this.onUserJoined, this),
Nc.on(Nc.ns.channel.events.user.left, this.onUserLeft, this),
Nc.on(Nc.ns.channel.events.user.level.reset, this.onResetLevel, this),
Nc.on(Nc.ns.channel.events.user.client.ready, this.onClientReady, this),
Nc.on(Nc.ns.core.game.events.level.loaded, this.onLevelLoaded, this),
Nc.on(Nc.ns.channel.events.game.player.killed, this.onPlayerKilled, this),
nc.on(nc.ns.channel.events.user.joined, this.onUserJoined, this),
nc.on(nc.ns.channel.events.user.left, this.onUserLeft, this),
nc.on(nc.ns.channel.events.user.level.reset, this.onResetLevel, this),
nc.on(nc.ns.channel.events.user.client.ready, this.onClientReady, this),
nc.on(nc.ns.core.game.events.level.loaded, this.onLevelLoaded, this),
nc.on(nc.ns.channel.events.game.player.killed, this.onPlayerKilled, this),
]);
console.checkpoint('starting game controller for channel (' + options.channelName + ')');
}
GameController.prototype = Object.create(Parent.prototype);
GameController.prototype.update = function () {
@ -57,15 +58,28 @@ function (Parent, PhysicsEngine, Settings, PlayerController, requestAnimFrame, N
this.createPlayer(user);
}
GameController.prototype.onUserLeft = function (userId) {
var player = this.players[userId];
this.clearItemsOfPlayerFingerPrints(player);
Parent.prototype.onUserLeft.call(this, userId);
};
GameController.prototype.clearItemsOfPlayerFingerPrints = function(player) {
nc.trigger(nc.ns.channel.events.game.player.clearFingerPrints, player);
};
GameController.prototype.createPlayer = function(user) {
var player = Parent.prototype.createPlayer.call(this, user);
player.setPlayerController(new PlayerController(player))
var revealedGameController = {
isInBetweenRounds: this.isInBetweenRounds.bind(this)
};
var player = Parent.prototype.createPlayer.call(this, user, revealedGameController);
user.setPlayer(player);
};
GameController.prototype.onPlayerKilled = function(player, killedByPlayer) {
if(killedByPlayer.stats.score >= this.options.scoreLimit) {
Nc.trigger(Nc.ns.channel.events.round.end);
nc.trigger(nc.ns.channel.events.round.end);
} else {
this.spawnPlayer(player, Settings.RESPAWN_TIME);
}
@ -81,8 +95,6 @@ function (Parent, PhysicsEngine, Settings, PlayerController, requestAnimFrame, N
var spawnTimeout = setTimeout(function() {
player.spawn(spawnPoint.x, spawnPoint.y);
// put it into
self.gameObjects.animated.push(player);
var options = {
id: player.id,
@ -90,7 +102,7 @@ function (Parent, PhysicsEngine, Settings, PlayerController, requestAnimFrame, N
y: spawnPoint.y
};
Nc.trigger(Nc.ns.channel.to.client.gameCommand.broadcast, "spawnPlayer", options);
nc.trigger(nc.ns.channel.to.client.gameCommand.broadcast, "spawnPlayer", options);
var i = self.spawnTimeouts.indexOf(spawnTimeout);
self.spawnTimeouts.splice(i, 1);
@ -105,17 +117,18 @@ function (Parent, PhysicsEngine, Settings, PlayerController, requestAnimFrame, N
var update = this.getWorldUpdateObject(false);
if(Object.getOwnPropertyNames(update).length > 0) {
Nc.trigger(Nc.ns.channel.to.client.gameCommand.broadcast, 'worldUpdate', update);
nc.trigger(nc.ns.channel.to.client.gameCommand.broadcast, "worldUpdate", update);
}
this.worldUpdateTimeout = setTimeout(this.updateWorld.bind(this), Settings.NETWORK_UPDATE_INTERVAL);
}
};
GameController.prototype.getWorldUpdateObject = function(getSleeping) {
getSleeping = getSleeping || false;
var update = {};
/*
var body = this.physicsEngine.world.GetBodyList();
do {
if((getSleeping || body.IsAwake()) && body.GetType() === Box2D.Dynamics.b2Body.b2_dynamicBody) {
@ -123,22 +136,33 @@ function (Parent, PhysicsEngine, Settings, PlayerController, requestAnimFrame, N
if (userData instanceof GameObject) {
var gameObject = userData;
update[gameObject.uid] = {
p: body.GetPosition(),
a: body.GetAngle(),
lv: body.GetLinearVelocity(),
av: body.GetAngularVelocity()
};
if(gameObject instanceof Doll) {
update[gameObject.uid].as = gameObject.getActionState();
update[gameObject.uid].laxy = gameObject.lookAtXY;
var updateData = gameObject.getUpdateData();
if (updateData) {
update[gameObject.uid] = updateData;
}
}
}
} while (body = body.GetNext());
*/
for (var uid in this.worldUpdateObjects) {
var gameObject = this.worldUpdateObjects[uid];
if (!(gameObject instanceof GameObject)) {
console.warn('Cant find object ' + uid + ' in worldUpdateObjects pool (channel side), here is the object:');
console.log(gameObject);
continue;
}
var updateData = gameObject.getUpdateData(getSleeping);
if (updateData) {
update[gameObject.uid] = updateData;
}
}
return update;
};
@ -147,7 +171,7 @@ function (Parent, PhysicsEngine, Settings, PlayerController, requestAnimFrame, N
var spawnedPlayers = [];
for(var id in this.players) {
var player = this.players[id];
if(player.isSpawned) {
if(player.isSpawned()) {
var options = {
id: id,
@ -166,23 +190,36 @@ function (Parent, PhysicsEngine, Settings, PlayerController, requestAnimFrame, N
return spawnedPlayers;
};
GameController.prototype.getRuntimeItems = function() {
var objects = []
GameController.prototype._getRuntimeItems = function() {
for (var i = 0; i < this.gameObjects.animated.length; i++) {
if(this.gameObjects.animated[i] instanceof RagDoll) {
var object = this.gameObjects.animated[i];
var options = object.options;
options.x = object.getPosition().x;
options.y = object.getPosition().y;
objects.push({
uid: object.uid,
options: object.options
});
var runtimeItems = [];
for (var uid in this.worldUpdateObjects) {
if(this.worldUpdateObjects[uid] instanceof RubeDoll) {
var object = this.worldUpdateObjects[uid];
runtimeItems.push(object);
}
};
}
return runtimeItems;
};
return objects;
GameController.prototype.gatherRuntimeItemsForWorldUpdate = function() {
var infos = [];
var runtimeItems = this._getRuntimeItems();
// On the other side this is using the level.createItem mechanism to
// create the RubeDoll from its ItemSettings
for (var i = 0; i < runtimeItems.length; i++) {
var object = runtimeItems[i];
var options = object.options;
options.x = object.getPosition().x;
options.y = object.getPosition().y;
infos.push({
uid: object.uid,
options: object.options
});
}
return infos;
};
GameController.prototype.onClientReady = function(userId) {
@ -191,21 +228,34 @@ function (Parent, PhysicsEngine, Settings, PlayerController, requestAnimFrame, N
var options = {
spawnedPlayers: this.getSpawnedPlayersAndTheirPositions(),
worldUpdate: this.getWorldUpdateObject(true),
runtimeItems: this.getRuntimeItems(),
runtimeItems: this.gatherRuntimeItemsForWorldUpdate(),
userId: userId
}
};
Nc.trigger(Nc.ns.channel.to.client.user.gameCommand.send + userId, "clientReadyResponse", options);
nc.trigger(nc.ns.channel.to.client.user.gameCommand.send + userId, "clientReadyResponse", options);
this.spawnPlayer(player, 0);
};
GameController.prototype.endRound = function() {
this.roundHasEnded = true;
for(var id in this.players) {
this.players[id].setInBetweenRounds(true);
}
};
GameController.prototype.isInBetweenRounds = function() {
return this.roundHasEnded;
};
// FIXME: remove this method
GameController.prototype.onResetLevel = function(userId) {
console.log('OH NO!!! ON RESET LEVEL IS CALLED AND RESPAWNES PLAYERS');
Parent.prototype.onResetLevel.call(this);
Nc.trigger(Nc.ns.channel.to.client.gameCommand.broadcast, "resetLevel", true);
nc.trigger(nc.ns.channel.to.client.gameCommand.broadcast, "resetLevel", true);
for (var key in this.players) {
this.spawnPlayer(this.players[key]);
}
@ -219,6 +269,11 @@ function (Parent, PhysicsEngine, Settings, PlayerController, requestAnimFrame, N
clearTimeout(this.spawnTimeouts[i]);
};
var runtimeItems = this._getRuntimeItems();
for (var i = 0; i < runtimeItems.length; i++) {
runtimeItems[i].destroy();
}
Parent.prototype.destroy.call(this);
};

View file

@ -2,10 +2,13 @@ define([
"Game/Core/GameObjects/Doll",
"Game/Channel/GameObjects/Item",
"Lib/Vendor/Box2D",
"Lib/Utilities/NotificationCenter"
"Lib/Utilities/NotificationCenter",
"Lib/Utilities/Assert"
],
function (Parent, Item, Box2D, Nc) {
function (Parent, Item, Box2D, nc, Assert) {
"use strict";
function Doll(physicsEngine, uid, player) {
Parent.call(this, physicsEngine, uid, player);
@ -13,12 +16,14 @@ function (Parent, Item, Box2D, Nc) {
Doll.prototype = Object.create(Parent.prototype);
Doll.prototype.findCloseItem = function(x, y) {
Doll.prototype.findCloseItem = function(x) {
var self = this;
function findItem(array) {
for (var i = 0; i < array.length; i++) {
var item = array[i];
if(item.isGrabbingAllowed(this.player)) {
if(item.isGrabbingAllowed(self.player)) {
return item;
}
}
@ -29,7 +34,7 @@ function (Parent, Item, Box2D, Nc) {
} else {
return findItem(this.reachableItems.right);
}
}
};
Doll.prototype.onImpact = function(isColliding, fixture) {
var self = this;
@ -42,47 +47,73 @@ function (Parent, Item, Box2D, Nc) {
var item = otherBody.GetUserData();
if(item instanceof Item) {
var itemVelocity = item.body.GetLinearVelocity();
var itemMass = item.body.GetMass();
//var itemMass = item.body.GetMass();
var ownVelocity = this.body.GetLinearVelocity();
var b2Math = Box2D.Common.Math.b2Math;
var absItemVelocity = b2Math.AbsV(itemVelocity)
var max = 1;
var absItemVelocity = b2Math.AbsV(itemVelocity);
var min = 1;
var damage = 0;
if(absItemVelocity.x > max || absItemVelocity.y > max) {
if(absItemVelocity.x > min || absItemVelocity.y > min) {
if(item.lastMoved && item.lastMoved.player != this.player) {
var damageVector = b2Math.SubtractVV(itemVelocity, ownVelocity);
damageVector.Abs();
damageVector.Multiply(0.7);
damageVector.Multiply(itemMass * 1.3);
var damage = damageVector.Length();
damage *= item.options.danger ? item.options.danger : 1;
var player = item.lastMoved.player;
var collision = b2Math.SubtractVV(itemVelocity, ownVelocity);
// Tested max velocity banana: 50
var velocityDamage = collision.Length() / 50;
// Max weight of piano: 15
var weightDamage = item.options.weight / 15;
// Max danger of knife: 3
var dangerDamage = item.options.danger / 3;
// + 0.5 and / 2: offsetting for lower velocity impact
// * 300: tested imperically by throwing piano from deadly height
// * 80: tested imperically by throwing knife fast
damage = (velocityDamage + 0.5) * (weightDamage * 300 + dangerDamage * 80) / 2;
var lastMovedPlayer = item.lastMoved.player;
var callback = function() {
self.player.addDamage(damage, player);
}
self.player.addDamage(damage, lastMovedPlayer, item);
};
Nc.trigger(Nc.ns.channel.engine.worldQueue.add, callback)
nc.trigger(nc.ns.channel.engine.worldQueue.add, callback);
}
}
item.setLastMovedBy(this.player);
// only set lastMovedBy if player wasn't hurt by collision
if (damage === 0) {
item.setLastMovedBy(this.player);
}
}
}
}
}
};
Doll.prototype.updatePositionState = function(update) {
if(!this.isAnotherPlayerNearby()) {
Assert.number(update.p.x, update.p.y);
Assert.number(update.lv.x, update.lv.y);
this.body.SetAwake(true);
this.body.SetPosition(update.p);
this.body.SetLinearVelocity(update.lv);
}
};
Doll.prototype.getUpdateData = function(getSleeping) {
var updateData = Parent.prototype.getUpdateData.call(this, getSleeping);
if(updateData) {
updateData.as = this.getActionState();
updateData.laxy = this.lookAtXY;
}
return updateData;
};
return Doll;

View file

@ -1,9 +1,39 @@
define([
"Game/Core/GameObjects/GameObject"
"Game/Core/GameObjects/GameObject",
"Lib/Vendor/Box2D"
],
function(Parent) {
function (Parent, Box2D) {
return Parent;
"use strict";
function GameObject(physicsEngine, uid) {
Parent.call(this, physicsEngine, uid);
}
GameObject.prototype = Object.create(Parent.prototype);
GameObject.prototype.getUpdateData = function(getSleeping) {
if (!this.body) {
return null;
}
if (this.body.GetType() === Box2D.Dynamics.b2Body.b2_staticBody) {
return null;
}
if (!getSleeping && !this.body.IsAwake()) {
return null;
}
return {
p: this.body.GetPosition(),
a: this.body.GetAngle(),
lv: this.body.GetLinearVelocity(),
av: this.body.GetAngularVelocity()
};
}
return GameObject;
});

View file

@ -1,17 +1,27 @@
define([
"Game/Core/GameObjects/Item"
"Game/Core/GameObjects/Item",
"Lib/Utilities/NotificationCenter",
],
function (Parent) {
function (Parent, nc) {
"use strict";
function Item(physicsEngine, uid, options) {
Parent.call(this, physicsEngine, uid, options);
this.heldByPlayers = [];
this.lastMoved = null;
this.ncTokens = (this.ncTokens || []).concat([
nc.on(nc.ns.channel.events.game.player.clearFingerPrints, this.clearOfPlayerFingerPrints, this)
]);
}
Item.prototype = Object.create(Parent.prototype);
Item.prototype.getLastMovedBy = function() {
return this.lastMoved;
}
Item.prototype.setLastMovedBy = function(player) {
@ -19,14 +29,14 @@ function (Parent) {
this.lastMoved = {
player: player,
timestamp: new Date()
}
};
} else {
this.lastMoved = null;
}
};
Item.prototype.isGrabbingAllowed = function(player) {
return this.heldByPlayers.length == 0;
Item.prototype.isGrabbingAllowed = function(player) { // jshint unused:false
return this.heldByPlayers.length === 0;
};
Item.prototype.beingGrabbed = function(player) {
@ -38,7 +48,7 @@ function (Parent) {
}
};
Item.prototype.isReleasingAllowed = function(player) {
Item.prototype.isReleasingAllowed = function(player) { // jshint unused:false
return true;
};
@ -54,6 +64,13 @@ function (Parent) {
}
};
Item.prototype.clearOfPlayerFingerPrints = function(player) {
if (this.getLastMovedBy() && this.getLastMovedBy().player === player) {
console.checkpoint('Removing fingerprints from ' + this.options.image);
this.setLastMovedBy(null);
}
};
Item.prototype.onCollisionChange = function(isColliding, fixture) {
if(isColliding) {
@ -79,8 +96,7 @@ function (Parent) {
}
}
}
}
};
return Item;

View file

@ -4,7 +4,9 @@ define([
"Lib/Utilities/NotificationCenter"
],
function (Parent, Settings, Nc) {
function (Parent, Settings, nc) {
"use strict";
function RagDoll(physicsEngine, uid, options) {
this.scheduledForDestruction = false;
@ -33,7 +35,7 @@ function (Parent, Settings, Nc) {
var self = this;
this.scheduledForDestruction = true;
this.destructionTimeout = setTimeout(function() {
Nc.trigger(Nc.ns.channel.to.client.gameCommand.broadcast, 'removeGameObject', {
nc.trigger(nc.ns.channel.to.client.gameCommand.broadcast, 'removeGameObject', {
type: 'animated',
uid: self.uid
});

View file

@ -1,9 +0,0 @@
define([
"Game/Core/GameObjects/Items/Rube"
],
function (Parent) {
return Parent;
});

View file

@ -0,0 +1,79 @@
define([
"Game/Core/GameObjects/Items/RubeDoll",
"Game/Config/Settings",
"Lib/Utilities/NotificationCenter"
],
function (Parent, Settings, nc) {
"use strict";
function RubeDoll(physicsEngine, uid, options) {
this.scheduledForDestruction = false;
this.destructionTimeout = null;
Parent.call(this, physicsEngine, uid, options);
}
RubeDoll.prototype = Object.create(Parent.prototype);
RubeDoll.prototype.beingGrabbed = function(player) {
Parent.prototype.beingGrabbed.call(this, player);
if(this.scheduledForDestruction) {
clearTimeout(this.destructionTimeout);
}
};
RubeDoll.prototype.beingReleased = function(player) {
Parent.prototype.beingReleased.call(this, player);
if(this.scheduledForDestruction) {
this.delayedDestroy();
}
};
RubeDoll.prototype.delayedDestroy = function() {
var self = this;
this.scheduledForDestruction = true;
this.destructionTimeout = setTimeout(function() {
nc.trigger(nc.ns.channel.to.client.gameCommand.broadcast, 'removeGameObject', {
type: 'animated',
uid: self.uid
});
self.destroy();
}, Settings.RAGDOLL_DESTRUCTION_TIME * 1000);
};
RubeDoll.prototype.getUpdateData = function(getSleeping) {
var updateData = Parent.prototype.getUpdateData.call(this, getSleeping);
// if parent is asleep it sends null, to do no update
if(!updateData) {
return updateData;
}
// adding limb update data
var limbUpdateData = {};
for(var name in this.limbs) {
limbUpdateData[name] = {
p: this.limbs[name].GetPosition(),
a: this.limbs[name].GetAngle(),
lv: this.limbs[name].GetLinearVelocity(),
av: this.limbs[name].GetAngularVelocity()
};
}
updateData['limbs'] = limbUpdateData;
return updateData;
}
RubeDoll.prototype.destroy = function() {
if(this.scheduledForDestruction) {
clearTimeout(this.destructionTimeout);
}
Parent.prototype.destroy.call(this);
};
return RubeDoll;
});

View file

@ -4,6 +4,8 @@ define([
function (Parent) {
"use strict";
return Parent;
});

View file

@ -4,10 +4,12 @@ define([
"fs"
],
function (Parent, Settings, fs) {
function (Parent, Settings, FileSystem) {
function Level (uid, engine, gameObjects) {
Parent.call(this, uid, engine, gameObjects);
"use strict";
function Level (uid, engine) {
Parent.call(this, uid, engine);
}
Level.prototype = Object.create(Parent.prototype);
@ -15,7 +17,7 @@ function (Parent, Settings, fs) {
Level.prototype.loadLevelDataFromPath = function (path, callback) {
// overwriting parent
fs.readFile(path, "utf8", function (err, data) {
FileSystem.readFile(path, "utf8", function (err, data) {
if (err) throw err;
callback(JSON.parse(data));
});

View file

@ -4,6 +4,8 @@ define([
function (Parent) {
"use strict";
return Parent;
});

View file

@ -1,55 +1,147 @@
define([
"Lib/Utilities/NotificationCenter",
"Game/Channel/Channel"
"Game/Channel/Channel",
"Game/Config/Settings",
"fs"
],
function (Nc, Channel) {
function (nc, Channel, Settings, fs) {
"use strict";
function PipeToServer (process) {
var self = this;
this.channel = null;
this.process = process;
this.recordingFileName = null;
Nc.on(Nc.ns.channel.to.server.controlCommand.send, this.send, this);
nc.on(nc.ns.channel.to.server.controlCommand.send, this.send, this);
process.on('message', function (message, handle) {
process.on("message", this.onProcessMessage.bind(this));
}
if(message.data.hasOwnProperty('CREATE')) {
self.channel = new Channel(self, message.data.options);
} else if (message.data.hasOwnProperty('KILL')) {
self.channel.destroy();
} else {
self.onMessage(message);
PipeToServer.prototype.onProcessMessage = function (message, handle) { // jshint unused:false
if(message.data.hasOwnProperty("CREATE")) {
this.channel = new Channel(this, message.data.options);
message.data.options.playingFileName = Settings.CHANNEL_PLAY_RECORDING;
if(message.data.options.playingFileName) {
var self = this;
setTimeout(function() {
console.log(message.data.options.playingFileName);
self.play(message.data.options.playingFileName);
}, 2000); // giving channel time to set everything up
}
if(Settings.CHANNEL_RECORD_SESSION) {
this.recordingFileName = Settings.CHANNEL_RECORDING_PATH +
this.channel.name +
"-" +
(new Date()).toISOString() +
"-" +
message.data.options.levelUids.join("_") +
".log";
if(!fs.existsSync(Settings.CHANNEL_RECORDING_PATH)) {
fs.mkdirSync(Settings.CHANNEL_RECORDING_PATH);
}
setInterval(this.recordWorldUpdate.bind(this), 1000);
console.checkpoint("Started recording to: " + this.recordingFileName);
}
});
}
} else if (message.data.hasOwnProperty("KILL")) {
this.channel.destroy();
} else {
this.onMessage(message);
if(Settings.CHANNEL_RECORD_SESSION && this.channel && this.channel.name) {
var m = JSON.stringify(message);
var timestamp = Date.now();
var line = "m" + timestamp + m + "\n";
fs.appendFile(this.recordingFileName, line, function (err) {
if (err) throw err;
});
}
}
};
PipeToServer.prototype.send = function (recipient, data) {
var message = {
recipient: recipient,
data: data
}
};
this.process.send(message);
};
PipeToServer.prototype.onMessage = function (message) {
switch(message.recipient) {
case 'channel':
Nc.trigger(Nc.ns.channel.events.controlCommand.channel, message);
case "channel":
nc.trigger(nc.ns.channel.events.controlCommand.channel, message);
break;
default:
Nc.trigger(Nc.ns.channel.events.controlCommand.user + message.recipient, message);
nc.trigger(nc.ns.channel.events.controlCommand.user + message.recipient, message);
break;
}
}
};
PipeToServer.prototype.play = function(playingFileName) {
var self = this;
var data = fs.readFileSync(Settings.CHANNEL_RECORDING_PATH + playingFileName);
var lines = data.toString().split("\n");
var start = 0;
for (var i = 0; i < lines.length; i++) {
// bind message variable
(function() {
var line = lines[i];
if(line.length > 0) {
var type = line.substring(0, 1);
var time = parseInt(line.substring(1, Date.now().toString().length + 1), 10);
if(i === 0) {
start = time;
}
time -= start;
var jsonString = line.substring(Date.now().toString().length + 1);
var message = JSON.parse(jsonString);
setTimeout(function() {
console.log(line);
if(type == "m") {
self.onProcessMessage(message, null);
} else if(type == "w") {
if(self.channel.gameController) {
self.channel.gameController.onWorldUpdate(message);
}
}
}, time);
}
})();
}
};
PipeToServer.prototype.recordWorldUpdate = function() {
if(this.channel.gameController) {
var update = this.channel.gameController.getWorldUpdateObject(true);
var worldUpdate = JSON.stringify(update);
var timestamp = Date.now();
var line = "w" + timestamp + worldUpdate + "\n";
fs.appendFile(this.recordingFileName, line, function (err) {
if (err) throw err;
});
}
};
PipeToServer.prototype.destroy = function() {
this.send('coordinator', {destroy:this.channel.name});
this.send("coordinator", {destroy:this.channel.name});
this.process.exit(0);
};

View file

@ -1,17 +1,22 @@
define([
"Game/Core/Player",
"Lib/Utilities/NotificationCenter"
"Lib/Utilities/NotificationCenter",
"Game/Channel/Control/PlayerController"
],
function (Parent, Nc) {
function (Parent, nc, PlayerController) {
"use strict";
function Player(id, physicsEngine, user) {
Parent.call(this, id, physicsEngine, user);
function Player(id, physicsEngine, user, revealedGameController) {
Parent.call(this, id, physicsEngine, user, revealedGameController);
this.playerController = new PlayerController(this);
}
Player.prototype = Object.create(Parent.prototype);
Player.prototype.handActionRequest = function(x, y) {
Player.prototype.handActionRequest = function(options) {
if(!this.doll) return false;
var item = null;
@ -20,30 +25,26 @@ function (Parent, Nc) {
if (isHolding) {
item = this.holdingItem;
} else {
item = this.doll.findCloseItem(x, y);
item = this.doll.findCloseItem(options.x);
}
if(item) {
this.handAction(x, y, isHolding, item);
this.handAction(options, isHolding, item);
}
}
};
Player.prototype.handAction = function(x, y, isHolding, item) {
Player.prototype.handAction = function(options, isHolding, item) {
var options = {
playerId: this.id,
itemUid: item.uid
}
options.playerId = this.id;
options.itemUid = item.uid;
if (isHolding) {
// throw
if(item.isReleasingAllowed()) {
this.throw(x, y, item);
this.throw(options, item);
options.action = "throw";
options.x = x;
options.y = y;
Nc.trigger(Nc.ns.channel.to.client.gameCommand.broadcast, "handActionResponse", options);
nc.trigger(nc.ns.channel.to.client.gameCommand.broadcast, "handActionResponse", options);
}
} else {
// grab
@ -51,26 +52,34 @@ function (Parent, Nc) {
this.grab(item);
options.action = "grab";
Nc.trigger(Nc.ns.channel.to.client.gameCommand.broadcast, "handActionResponse", options);
nc.trigger(nc.ns.channel.to.client.gameCommand.broadcast, "handActionResponse", options);
}
}
};
Player.prototype.suicide = function() {
this.addDamage(100, this);
if(this.isSpawned()) {
this.addDamage(100, this, null);
}
};
Player.prototype.addDamage = function(damage, enemy) {
Player.prototype.addDamage = function(damage, enemy, byItem) {
// Prevent stats change (kills) after round has ended
if (this.revealedGameController.isInBetweenRounds()) {
return;
}
this.stats.health -= damage;
if(this.stats.health < 0) this.stats.health = 0;
if(this.stats.health <= 0) {
if(enemy != this) enemy.score();
this.kill(enemy);
} else {
this.broadcastStats();
this.kill(enemy, byItem);
}
this.broadcastStats(enemy);
};
Player.prototype.spawn = function(x, y) {
@ -79,19 +88,19 @@ function (Parent, Nc) {
this.broadcastStats();
};
Player.prototype.kill = function(killedByPlayer) {
Player.prototype.kill = function(killedByPlayer, byItem) {
this.stats.deaths++;
var ragDollId = this.stats.deaths;
Parent.prototype.kill.call(this, killedByPlayer, ragDollId);
this.broadcastStats();
Nc.trigger(Nc.ns.channel.to.client.gameCommand.broadcast, "playerKill", {
nc.trigger(nc.ns.channel.to.client.gameCommand.broadcast, "playerKill", {
playerId: this.id,
killedByPlayerId: killedByPlayer.id,
ragDollId: ragDollId
ragDollId: ragDollId,
item: byItem ? byItem.options.name : "Suicide"
});
Nc.trigger(Nc.ns.channel.events.game.player.killed, this, killedByPlayer); // sends endround
nc.trigger(nc.ns.channel.events.game.player.killed, this, killedByPlayer); // sends endround
if(this.ragDoll) {
this.ragDoll.delayedDestroy();
@ -100,17 +109,21 @@ function (Parent, Nc) {
Player.prototype.score = function() {
this.stats.score++;
this.broadcastStats();
};
Player.prototype.broadcastStats = function() {
Nc.trigger(Nc.ns.channel.to.client.gameCommand.broadcast, "updateStats", {
Player.prototype.broadcastStats = function(enemy) {
nc.trigger(nc.ns.channel.to.client.gameCommand.broadcast, "updateStats", {
playerId: this.id,
stats: this.stats
});
if(enemy && enemy != this) {
nc.trigger(nc.ns.channel.to.client.gameCommand.broadcast, "updateStats", {
playerId: enemy.id,
stats: enemy.stats
});
}
};
return Player;

View file

@ -5,7 +5,7 @@ define([
"Lib/Utilities/Protocol/Parser",
],
function(Parent, Nc, ProtocolHelper, ProtocolParser) {
function(Parent, nc, ProtocolHelper, ProtocolParser) {
function User(id, options) {
Parent.call(this, id, options);
@ -14,15 +14,15 @@ function(Parent, Nc, ProtocolHelper, ProtocolParser) {
this.isReady = false;
var self = this;
Nc.on(Nc.ns.channel.to.client.user.controlCommand.joinSuccess + this.id, function(options) {
nc.on(nc.ns.channel.to.client.user.controlCommand.joinSuccess + this.id, function(options) {
self.sendControlCommand("joinSuccess", options);
});
Nc.on(Nc.ns.channel.events.controlCommand.user + this.id, function(message) {
nc.on(nc.ns.channel.events.controlCommand.user + this.id, function(message) {
ProtocolHelper.applyCommand(message.data, self);
});
Nc.on(Nc.ns.channel.to.client.user.gameCommand.send + this.id, function(command, options) {
nc.on(nc.ns.channel.to.client.user.gameCommand.send + this.id, function(command, options) {
self.sendGameCommand(command, options);
});
@ -44,10 +44,10 @@ function(Parent, Nc, ProtocolHelper, ProtocolParser) {
} // FIXME: move this to Protocol helper as a function
if(command.hasOwnProperty("resetLevel")) {
Nc.trigger(Nc.ns.channel.events.user.level.reset, this.id);
nc.trigger(nc.ns.channel.events.user.level.reset, this.id);
} else if(command.hasOwnProperty("clientReady")) {
this.isReady = true;
Nc.trigger(Nc.ns.channel.events.user.client.ready, this.id);
nc.trigger(nc.ns.channel.events.user.client.ready, this.id);
} else {
this.player.playerController.applyCommand(command);
}
@ -61,7 +61,17 @@ function(Parent, Nc, ProtocolHelper, ProtocolParser) {
var recipient = this.id;
var data = ProtocolHelper.encodeCommand(command, options);
Nc.trigger(Nc.ns.channel.to.server.controlCommand.send, recipient, data);
/**
* Listen for beginRound control command
* to set client to be unready again
* so it can load its new level without getting
* any gameCommands like worldUpdate
*/
if(command == "beginRound") {
this.isReady = false;
}
nc.trigger(nc.ns.channel.to.server.controlCommand.send, recipient, data);
};
User.prototype.sendGameCommand = function(command, options) {

View file

@ -0,0 +1,38 @@
define([
],
function () {
"use strict";
function AudioPlayer(path) {
this.audio = new Audio(path);
this.audio.loop = true;
this.audio.volume = 0.1;
this.audio.addEventListener('timeupdate', function(){
var buffer = 1
if(this.currentTime > this.duration - buffer) {
this.currentTime = 1
this.play()
}
}, false);
}
AudioPlayer.prototype.play = function() {
//this.audio.play();
//this.doPlay = true;
}
AudioPlayer.prototype.stop = function() {
//this.audio.stop();
//this.doPlay = false;
};
AudioPlayer.prototype.destroy = function() {
this.stop();
};
return AudioPlayer;
});

View file

@ -4,6 +4,8 @@ define([
function (Parent) {
"use strict";
function Detector () {
Parent.call(this);
}

View file

@ -0,0 +1,21 @@
define([
"Lib/Utilities/NotificationCenter"
],
function (nc) {
function Input(playerController) {
this.playerController = playerController;
this.x = null;
this.y = null
}
Input.prototype.onXyChange = function(x, y) {
this.x = x;
this.y = y;
this.playerController.setXY(this.x, this.y);
}
return Input;
});

View file

@ -1,47 +0,0 @@
define([
"Game/Client/Control/Input/XyInput",
"Game/Client/View/DomController",
"Game/Config/Settings",
"Lib/Utilities/NotificationCenter"
],
function (Parent, DomController, Settings, Nc) {
function MouseInput() {
Parent.call(this);
this.init();
}
MouseInput.prototype = Object.create(Parent.prototype);
MouseInput.prototype.init = function() {
var canvas = null;
var self = this;
canvas = DomController.getCanvas();
canvas.onmousemove = function(e){
// -1 +1 +1 +1 xy scaling should
// -1 -1 +1 -1 be like this
var x = (((e.clientX - this.offsetLeft) / Settings.STAGE_WIDTH) * 2) - 1;
var y = (((Settings.STAGE_HEIGHT - (e.clientY - this.offsetTop)) / Settings.STAGE_HEIGHT) * 2) -1;
self.onXyChange(x, y);
}
canvas.onmousedown = function(e) {
var x = (((e.clientX - this.offsetLeft) / Settings.STAGE_WIDTH) * 2) - 1;
var y = (((Settings.STAGE_HEIGHT - (e.clientY - this.offsetTop)) / Settings.STAGE_HEIGHT) * 2) -1;
Nc.trigger(Nc.ns.client.input.handAction.request, x, y);
}
};
return MouseInput;
});

View file

@ -1,20 +0,0 @@
define([
"Lib/Utilities/NotificationCenter"
],
function (Nc) {
function XyInput() {
this.x = null;
this.y = null
}
XyInput.prototype.onXyChange = function(x, y) {
this.x = x;
this.y = y;
Nc.trigger(Nc.ns.client.input.xy.change, x, y);
}
return XyInput;
});

View file

@ -1,10 +1,11 @@
define([
"Game/Client/Control/Input/XyInput",
"Game/Config/Settings",
"Lib/Utilities/NotificationCenter"
"Game/Client/Control/Input",
"Game/Config/Settings"
],
function (Parent, Settings, Nc) {
function (Parent, Settings) {
"use strict";
function GamepadInput(playerController) {
this.playerController = playerController;
@ -36,7 +37,7 @@ function (Parent, Settings, Nc) {
var y = -this.gamepad.axes[3];
// Looking direction
this.playerController.xyInput.onXyChange(x, y);
this.onXyChange(x, y);
// Pointer finger holding item
var holdingPressure = this.gamepad.axes[5];

View file

@ -0,0 +1,231 @@
define([
"Game/Client/Control/Input",
"Game/Client/Control/KeyboardInput",
"Game/Client/View/DomController",
"Game/Config/Settings",
"Game/Client/Control/Swiper"
],
function (Parent, KeyboardInput, domController, Settings, Swiper) {
"use strict";
function KeyboardAndMouse(playerController) {
Parent.call(this);
this.x = 0;
this.y = 0;
this.mousePosition = {x:0,y:0};
this.modifier = false;
this.swiper = null;
this.lastLookDirection = 1;
this.keys = {
w:87,
a:65,
s:83,
d:68,
f:70,
g:71,
k:75,
up: 38,
left: 37,
down: 40,
right: 39,
space: 32,
tab: 9,
shift: 16,
plus: 187,
plusfx: 171,
minus: 189,
minusfx: 173,
zero: 48
};
this.playerController = playerController;
this.keyboardInit();
this.mouseInit();
}
KeyboardAndMouse.prototype = Object.create(Parent.prototype);
KeyboardAndMouse.prototype.keyboardInit = function() {
this.keyboardInput = new KeyboardInput();
var self = this;
function bind2Pc(methodName) {
return self.playerController[methodName].bind(self.playerController);
}
this.keyboardInput.registerKey(this.keys.a, this.moveLeft.bind(this), this.stop.bind(this));
this.keyboardInput.registerKey(this.keys.left, this.moveLeft.bind(this), this.stop.bind(this));
this.keyboardInput.registerKey(this.keys.d, this.moveRight.bind(this), this.stop.bind(this));
this.keyboardInput.registerKey(this.keys.right, this.moveRight.bind(this), this.stop.bind(this));
this.keyboardInput.registerKey(this.keys.w, bind2Pc('jump'), bind2Pc('jumpStop'));
this.keyboardInput.registerKey(this.keys.up, bind2Pc('jump'), bind2Pc('jumpStop'));
this.keyboardInput.registerKey(this.keys.space, bind2Pc('jump'), bind2Pc('jumpStop'));
this.keyboardInput.registerKey(this.keys.plus, bind2Pc('zoomIn'));
this.keyboardInput.registerKey(this.keys.plusfx, bind2Pc('zoomIn'));
this.keyboardInput.registerKey(this.keys.minus, bind2Pc('zoomOut'));
this.keyboardInput.registerKey(this.keys.minusfx, bind2Pc('zoomOut'));
this.keyboardInput.registerKey(this.keys.zero, bind2Pc('zoomReset'));
this.keyboardInput.registerKey(this.keys.tab, bind2Pc('showInfo'), bind2Pc('hideInfo'));
this.keyboardInput.registerKey(this.keys.k, bind2Pc('suicide'));
this.keyboardInput.registerKey(
this.keys.shift,
this.activateModifier.bind(this),
this.deactivateModifier.bind(this)
);
};
KeyboardAndMouse.prototype.moveLeft = function() {
if (!this.modifier) {
this.lastLookDirection = -1;
this.onXyChange(this.lastLookDirection * Settings.VIEWPORT_LOOK_AHEAD, 0);
}
this.playerController.moveLeft();
};
KeyboardAndMouse.prototype.moveRight = function() {
if (!this.modifier) {
this.lastLookDirection = 1;
this.onXyChange(this.lastLookDirection * Settings.VIEWPORT_LOOK_AHEAD, 0);
}
this.playerController.moveRight();
};
KeyboardAndMouse.prototype.stop = function(e) {
var isMovingLeft = this.keyboardInput.getKeyByKeyCode(this.keys.a).getActive()
|| this.keyboardInput.getKeyByKeyCode(this.keys.left).getActive();
var isMovingRight = this.keyboardInput.getKeyByKeyCode(this.keys.d).getActive()
|| this.keyboardInput.getKeyByKeyCode(this.keys.right).getActive();
if (isMovingLeft) {
this.moveLeft();
return;
}
if (isMovingRight) {
this.moveRight();
return;
}
this.playerController.stop();
};
KeyboardAndMouse.prototype.mouseInit = function() {
var canvas = domController.getCanvas();
var self = this;
canvas.onmousedown = function(e) {
self.mousePosition = {x:0,y:0};
if(!self.playerController.player.isHoldingSomething()) {
var options = {
x: self.x,
y: self.y,
av: 0
};
self.playerController.handActionRequest(options);
} else {
self.swiper = new Swiper();
self.draw({
movementX: 0,
movementY: 0
});
}
}
canvas.onmousemove = function(e) {
if (self.swiper) {
self.draw(e);
} else if(self.modifier) {
self.updateViewport(e);
}
}
canvas.onmouseup = function(e) {
if(self.swiper) {
var options = self.swiper.swipeEnd(e.x, e.y);
self.playerController.handActionRequest(options);
self.swiper = null;
}
}
};
KeyboardAndMouse.prototype.updateViewport = function(e) {
// -1 +1 +1 +1 xy scaling should
// -1 -1 +1 -1 be like this
var movementX = e.movementX ||
e.mozMovementX ||
e.webkitMovementX ||
0;
var movementY = e.movementY ||
e.mozMovementY ||
e.webkitMovementY ||
0;
this.x += movementX / Settings.VIEWPORT_SPEED_FACTOR;
if(this.x > 1) {
this.x = 1;
}
if(this.x < -1) {
this.x = -1;
};
this.y -= movementY / Settings.VIEWPORT_SPEED_FACTOR;
if(this.y > 1) {
this.y = 1;
}
if(this.y < -1) {
this.y = -1;
}
this.lastLookDirection = this.x >= 0 ? 1 : -1;
this.onXyChange(this.x, this.y);
};
KeyboardAndMouse.prototype.draw = function(e) {
var movementX = e.movementX ||
e.mozMovementX ||
e.webkitMovementX ||
0;
var movementY = e.movementY ||
e.mozMovementY ||
e.webkitMovementY ||
0;
this.mousePosition.x += movementX;
this.mousePosition.y += movementY;
this.swiper.swipe(this.mousePosition.x, -this.mousePosition.y);
};
KeyboardAndMouse.prototype.activateModifier = function() {
this.modifier = true;
this.playerController.activateModifier();
};
KeyboardAndMouse.prototype.deactivateModifier = function() {
this.modifier = false;
this.x = this.lastLookDirection * Settings.VIEWPORT_LOOK_AHEAD;
this.y = 0;
this.onXyChange(this.x, this.y);
this.playerController.deactivateModifier();
};
return KeyboardAndMouse;
});

View file

@ -1,4 +1,9 @@
define(function () {
define([
],
function () {
"use strict";
function Key () {
this._active = false;

View file

@ -4,50 +4,47 @@ define([
function (Key) {
function KeyboardInput (playerController) {
this._registry = {};
this._playerController = playerController;
function KeyboardInput () {
this.registry = {};
this.init();
}
KeyboardInput.prototype.init = function () {
// Using window is ok here because it only runs in the browser
window.onkeydown = this._onKeyDown.bind(this);
window.onkeyup = this._onKeyUp.bind(this);
window.onkeydown = this.onKeyDown.bind(this);
window.onkeyup = this.onKeyUp.bind(this);
}
KeyboardInput.prototype.registerKey = function (keyCode, onKeyDown, onKeyUp) {
var key = new Key();
if(onKeyDown) key.setKeyDownFunction(onKeyDown);
if(onKeyUp) key.setKeyUpFunction(onKeyUp);
this._registry[keyCode] = key;
this.registry[keyCode] = key;
}
KeyboardInput.prototype._getKeyByKeyCode = function (keyCode) {
return this._registry[keyCode];
KeyboardInput.prototype.getKeyByKeyCode = function (keyCode) {
return this.registry[keyCode];
}
KeyboardInput.prototype._onKeyDown = function (e) {
var key = this._getKeyByKeyCode(e.keyCode);
KeyboardInput.prototype.onKeyDown = function (e) {
var key = this.getKeyByKeyCode(e.keyCode);
if (key && !key.getActive()) {
var callback = key.getKeyDownFunction();
if(callback) this._playerController[callback]();
key.setActive(true);
if(callback) callback();
}
// Prevent tab from changing focus
if(e.keyCode == 9) return false;
}
KeyboardInput.prototype._onKeyUp = function (e) {
var key = this._getKeyByKeyCode(e.keyCode);
KeyboardInput.prototype.onKeyUp = function (e) {
var key = this.getKeyByKeyCode(e.keyCode);
if (key && key.getActive()) {
var callback = key.getKeyUpFunction();
if(callback) this._playerController[callback]();
key.setActive(false);
if(callback) callback();
}
// Prevent tab from changing focus

View file

@ -1,137 +1,124 @@
define([
"Game/Core/Control/PlayerController",
"Game/Client/Control/KeyboardInput",
"Game/Client/Control/Input/MouseInput",
"Lib/Utilities/NotificationCenter",
"Game/Client/Control/Input/GamepadInput",
"Game/Client/Control/Inputs/KeyboardAndMouse",
"Game/Client/Control/Inputs/Gamepad",
"Game/Client/PointerLockManager"
],
function (Parent, KeyboardInput, MouseInput, Nc, GamepadInput) {
function (Parent, nc, KeyboardAndMouse, Gamepad, pointerLockManager) {
"use strict";
function PlayerController (me) {
Parent.call(this, me);
this.keyboardInput = new KeyboardInput(this);
this.xyInput = new MouseInput(this);
this.gamepadInput = new GamepadInput(this);
this.ncTokens = [
Nc.on(Nc.ns.client.input.xy.change, this.setXY, this),
Nc.on(Nc.ns.client.input.handAction.request, this.handActionRequest, this)
];
var keys = {
w:87,
a:65,
s:83,
d:68,
f:70,
g:71,
k:75,
up: 38,
left: 37,
down: 40,
right: 39,
space: 32,
tab: 9
}
this.init(keys);
this.keyboardAndMouse = new KeyboardAndMouse(this);
this.gamepad = new Gamepad(this);
}
PlayerController.prototype = Object.create(Parent.prototype);
PlayerController.prototype.update = function() {
Parent.prototype.update.call(this);
this.gamepadInput.update();
this.gamepad.update();
};
PlayerController.prototype.init = function (keys) {
this.keyboardInput.registerKey(keys.a, 'moveLeft', 'stop');
this.keyboardInput.registerKey(keys.left, 'moveLeft', 'stop');
this.keyboardInput.registerKey(keys.d, 'moveRight', 'stop');
this.keyboardInput.registerKey(keys.right, 'moveRight', 'stop');
this.keyboardInput.registerKey(keys.w, 'jump', 'jumpStop');
this.keyboardInput.registerKey(keys.up, 'jump', 'jumpStop');
this.keyboardInput.registerKey(keys.space, 'jump', 'jumpStop');
this.keyboardInput.registerKey(keys.tab, 'showInfo', 'hideInfo');
this.keyboardInput.registerKey(keys.f, 'handActionLeft');
this.keyboardInput.registerKey(keys.g, 'handActionRight');
this.keyboardInput.registerKey(keys.k, 'suicide');
}
PlayerController.prototype.moveLeft = function () {
if (!this.isPlayerInputAllowed()) return;
Parent.prototype.moveLeft.call(this);
Nc.trigger(Nc.ns.client.to.server.gameCommand.send, 'moveLeft');
nc.trigger(nc.ns.client.to.server.gameCommand.send, 'moveLeft');
}
PlayerController.prototype.moveRight = function () {
if (!this.isPlayerInputAllowed()) return;
Parent.prototype.moveRight.call(this);
Nc.trigger(Nc.ns.client.to.server.gameCommand.send, 'moveRight');
nc.trigger(nc.ns.client.to.server.gameCommand.send, 'moveRight');
}
// always allow to stop, to prevent endless running
PlayerController.prototype.stop = function () {
Parent.prototype.stop.call(this);
Nc.trigger(Nc.ns.client.to.server.gameCommand.send, 'stop');
nc.trigger(nc.ns.client.to.server.gameCommand.send, 'stop');
}
PlayerController.prototype.jump = function () {
if (!this.isPlayerInputAllowed()) return;
Parent.prototype.jump.call(this);
Nc.trigger(Nc.ns.client.to.server.gameCommand.send, 'jump');
nc.trigger(nc.ns.client.to.server.gameCommand.send, 'jump');
}
// always allow to stop.
PlayerController.prototype.jumpStop = function () {
Parent.prototype.jumpStop.call(this);
Nc.trigger(Nc.ns.client.to.server.gameCommand.send, 'jumpStop');
nc.trigger(nc.ns.client.to.server.gameCommand.send, 'jumpStop');
}
PlayerController.prototype.setXY = function(x, y) {
if (!this.isPlayerInputAllowed()) return;
var options = {x:x, y:y};
Parent.prototype.lookAt.call(this, options);
Nc.trigger(Nc.ns.client.to.server.gameCommand.send, 'lookAt', options);
};
PlayerController.prototype.handActionLeft = function() {
this.handActionRequest(-0.5, 0.5);
};
PlayerController.prototype.handActionRight = function() {
this.handActionRequest(0.5, 0.5);
nc.trigger(nc.ns.client.to.server.gameCommand.send, 'lookAt', options);
};
PlayerController.prototype.suicide = function() {
Nc.trigger(Nc.ns.client.to.server.gameCommand.send, "suicide");
if (!this.isPlayerInputAllowed()) return;
nc.trigger(nc.ns.client.to.server.gameCommand.send, "suicide");
};
PlayerController.prototype.handActionRequest = function(x, y) {
var options = {x:x, y:y};
Nc.trigger(Nc.ns.client.to.server.gameCommand.send, "handActionRequest", options);
PlayerController.prototype.handActionRequest = function(options) {
if (!this.isPlayerInputAllowed()) return;
nc.trigger(nc.ns.client.to.server.gameCommand.send, "handActionRequest", options);
};
PlayerController.prototype.showInfo = function() {
Nc.trigger(Nc.ns.client.game.gameInfo.toggle, true);
if (!this.isPlayerInputAllowed()) return;
nc.trigger(nc.ns.client.game.gameStats.toggle, true);
};
PlayerController.prototype.hideInfo = function() {
Nc.trigger(Nc.ns.client.game.gameInfo.toggle, false);
if (!this.isPlayerInputAllowed()) return;
nc.trigger(nc.ns.client.game.gameStats.toggle, false);
};
PlayerController.prototype.destroy = function() {
Nc.offAll(this.ncTokens);
Parent.prototype.destroy.call(this);
PlayerController.prototype.zoomIn = function() {
if (!this.isPlayerInputAllowed()) return;
nc.trigger(nc.ns.client.game.zoomIn, true);
};
PlayerController.prototype.zoomOut = function() {
if (!this.isPlayerInputAllowed()) return;
nc.trigger(nc.ns.client.game.zoomOut, false);
};
PlayerController.prototype.zoomReset = function() {
if (!this.isPlayerInputAllowed()) return;
nc.trigger(nc.ns.client.game.zoomReset, false);
};
PlayerController.prototype.activateModifier = function() {
if (!this.isPlayerInputAllowed()) return;
Parent.prototype.activateModifier.call(this);
nc.trigger(nc.ns.client.to.server.gameCommand.send, "activateModifier");
};
PlayerController.prototype.deactivateModifier = function() {
if (!this.isPlayerInputAllowed()) return;
Parent.prototype.deactivateModifier.call(this);
nc.trigger(nc.ns.client.to.server.gameCommand.send, "deactivateModifier");
};
/*
* Client overwrite - allow player input if PointerLock is locked to canvas
* and is not in between games
*/
PlayerController.prototype.isPlayerInputAllowed = function() {
return pointerLockManager.isLocked()
&& Parent.prototype.isPlayerInputAllowed.call(this);
};
return PlayerController;
});

View file

@ -0,0 +1,175 @@
define([
"Lib/Utilities/NotificationCenter",
],
function (nc) {
var MAX_LENGTH = 200;
var MIN_LENGTH = 5;
function Swiper() {
this.points = [];
this.angleSum = 0;
this.lengthSum = 0;
this.finished = false;
}
Swiper.prototype.swipe = function(x, y) {
if(this.finished) return;
var points = this.points;
// Check if swipe is long enough to count
if(points.length >= 1) {
var lastPoint = points[points.length-1];
var a = Math.abs(x) - Math.abs(lastPoint.x);
var b = Math.abs(y) - Math.abs(lastPoint.y);
var currentLength = Math.sqrt(a * a + b * b); // Pythagoras -> hypotenuse
if(currentLength < MIN_LENGTH) return;
}
points.push({x:x, y:y});
if(points.length >= 2) {
this.updateLengthSum(currentLength);
if(this.points.length >= 3) {
this.updateAngleSum(currentLength);
}
}
var i = points.length - 1;
nc.trigger(nc.ns.client.view.swiper.swipe, points[i].x, points[i].y);
}
Swiper.prototype.updateLengthSum = function(currentLength) {
var points = this.points;
var i = points.length - 1;
var lengthSum = this.lengthSum + Math.abs(currentLength);
if(lengthSum > MAX_LENGTH) {
var diff = lengthSum - MAX_LENGTH;
var ratio = (currentLength - diff) / currentLength;
// Offset triangle to origin
var x0 = points[i].x - points[i-1].x;
var y0 = points[i].y - points[i-1].y;
// Multiply with ratio and offset back
var clippedX = x0 * ratio + points[i-1].x;
var clippedY = y0 * ratio + points[i-1].y;
points[i].x = clippedX;
points[i].y = clippedY;
this.finished = true;
lengthSum = MAX_LENGTH;
}
this.lengthSum = lengthSum;
};
Swiper.prototype.updateAngleSum = function(currentLength) {
var points = this.points;
var i = points.length - 1;
// last two lines
var vectors = [
{
x: points[i].x - points[i-1].x,
y: points[i].y - points[i-1].y
},
{
x: points[i-2].x - points[i-1].x,
y: points[i-2].y - points[i-1].y
}
];
var yx = vectors[0].y * vectors[1].x;
var xy = vectors[0].x * vectors[1].y;
var direction = 0;
if(yx > xy) {
direction = -1;
} else if (yx < xy) {
direction = 1;
}
var dotProduct = vectors[0].x
* vectors[1].x
+ vectors[0].y
* vectors[1].y;
var lastLength = Math.sqrt(
Math.pow(vectors[1].x, 2)
+ Math.pow(vectors[1].y, 2)
);
var angle = 180 - (Math.acos((dotProduct / (currentLength * lastLength)) % 1) * 180 / Math.PI);
angle *= direction;
if(!isNaN(parseFloat(angle)) && direction != 0) {
this.angleSum += angle;
}
};
Swiper.prototype.swipeEnd = function(x, y) {
var angularVelocity = this.angleSum;
var length = this.lengthSum;
if (this.points.length < 1) {
return {
x: 0,
y: 0,
av: 0
}
}
var p0x = this.points[0].x;
var p0y = this.points[0].y;
var sumx = 0;
var sumy = 0;
nc.trigger(nc.ns.client.view.swiper.end);
for(var i=0, count = this.points.length; i < count; i++) {
var p = this.points[i];
sumx += p.x - p0x;
sumy += p.y - p0y;
}
var direction = {
x: sumx / count,
y: sumy / count
};
var larger = Math.abs(direction.x) > Math.abs(direction.y) ? direction.x : direction.y;
direction.x /= Math.abs(larger);
direction.y /= Math.abs(larger);
this.angleSum = 0;
this.lengthSum = 0;
this.points = [];
this.finished = false;
return {
x: direction.x * length / 100,
y: direction.y * length / 100,
av: angularVelocity / 100
}
}
Swiper.prototype.destroy = function() {
for (var i = 0; i < this.ncTokens.length; i++) {
nc.off(this.ncTokens[i]);
};
};
return Swiper;
});

View file

@ -11,16 +11,16 @@ define([
"Game/Client/GameObjects/Doll",
"Game/Client/View/DomController",
"Lib/Utilities/Protocol/Helper",
"Game/Client/Me"
"Game/Client/Me",
"Game/Client/AudioPlayer",
"Game/Client/PointerLockManager",
"Lib/Utilities/Assert",
"Lib/Utilities/Exception"
],
function (Parent, Box2D, PhysicsEngine, ViewManager, PlayerController, Nc, requestAnimFrame, Settings, GameObject, Doll, DomController, ProtocolHelper, Me) {
function (Parent, Box2D, PhysicsEngine, ViewManager, PlayerController, nc, requestAnimFrame, Settings, GameObject, Doll, domController, ProtocolHelper, Me, AudioPlayer, pointerLockManager, Assert, Exception) {
if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}
"use strict";
function GameController (options) {
@ -28,11 +28,12 @@ function (Parent, Box2D, PhysicsEngine, ViewManager, PlayerController, Nc, reque
this.view = ViewManager.createView();
this.me = null;
this.animationRequestId = null;
this.audioPlayer = null;
Parent.call(this, options);
this.ncTokens = this.ncTokens.concat([
Nc.on(Nc.ns.client.game.gameInfo.toggle, this.toggleInfo, this)
nc.on(nc.ns.client.game.gameStats.toggle, this.toggleGameStats, this)
]);
}
@ -40,60 +41,52 @@ function (Parent, Box2D, PhysicsEngine, ViewManager, PlayerController, Nc, reque
GameController.prototype.getMe = function () {
return this.me;
}
};
GameController.prototype.update = function () {
Parent.prototype.update.call(this);
DomController.statsBegin();
this.animationRequestId = requestAnimFrame(this.update.bind(this));
this.physicsEngine.update();
if(this.me) {
this.me.update();
this.mePositionStateUpdate();
this.mePositionStateOverride();
}
for (var i = 0; i < this.gameObjects.animated.length; i++) {
this.gameObjects.animated[i].render();
}
nc.trigger(nc.ns.client.game.events.render);
this.view.render();
domController.fpsStep();
};
DomController.statsEnd();
}
GameController.prototype.mePositionStateUpdate = function() {
if(this.me.isPositionStateUpdateNeeded()) {
Nc.trigger(Nc.ns.client.to.server.gameCommand.send, "mePositionStateUpdate", this.me.getPositionStateUpdate());
GameController.prototype.mePositionStateOverride = function() {
if(this.me.isPositionStateOverrideNeeded()) {
nc.trigger(
nc.ns.client.to.server.gameCommand.send,
"mePositionStateOverride",
this.me.getPositionStateOverride()
);
}
};
GameController.prototype.onClientReadyResponse = function(options) {
if (options.worldUpdate) {
this.onWorldUpdate(options.worldUpdate);
}
var i;
if (options.runtimeItems) {
for (var i = 0; i < options.runtimeItems.length; i++) {
for (i = 0; i < options.runtimeItems.length; i++) {
var itemDef = options.runtimeItems[i];
var alreadyExists = false;
for (var i = 0; i < this.gameObjects.animated.length; i++) {
if(this.gameObjects.animated[i].uid == itemDef.uid) {
alreadyExists = true;
break;
}
};
if(!alreadyExists) {
var item = this.level.createItem(itemDef.uid, itemDef.options);
if(!this.getItemByUid(itemDef.uid)) {
// When creating from synchronization we need to bring it into level format (px)
itemDef.options.x *= Settings.RATIO;
itemDef.options.y *= Settings.RATIO;
this.level.createItem(itemDef.uid, itemDef.options);
console.log("Creating runtime Item: ", itemDef.options.name, itemDef.uid)
}
};
}
}
this.setMe();
@ -101,43 +94,51 @@ function (Parent, Box2D, PhysicsEngine, ViewManager, PlayerController, Nc, reque
this.clientIsReady = true; // needs to stay before onSpawnPlayer
if (options.spawnedPlayers) {
for(var i = 0; i < options.spawnedPlayers.length; i++) {
for(i = 0; i < options.spawnedPlayers.length; i++) {
this.onSpawnPlayer(options.spawnedPlayers[i]);
}
}
if (options.worldUpdate) { // needs to stay after onSpawnPlayer otherwise others doll will not be there
this.onWorldUpdate(options.worldUpdate);
}
//this.audioPlayer = new AudioPlayer(Settings.AUDIO_PATH + "city.mp3");
//this.audioPlayer.play();
};
GameController.prototype.onWorldUpdate = function (updateData) {
var body = this.physicsEngine.world.GetBodyList();
do {
var userData = body.GetUserData();
if (userData instanceof GameObject) {
var gameObject = userData;
if(updateData[gameObject.uid]) {
var update = updateData[gameObject.uid];
/*
if (gameObject instanceof Doll) {
if(gameObject === this.me.doll) {
this.me.setLastServerPositionState(update);
if(!this.me.acceptPositionStateUpdateFromServer()) {
continue; // this is to ignore own doll updates from world update
}
}
gameObject.setActionState(update.as);
gameObject.lookAt(update.laxy.x, update.laxy.y);
}
TODO :
- remove this
- overwrite setUpdateData inside client / Me with an empty function
body.SetAwake(true);
body.SetPosition(update.p);
body.SetAngle(update.a);
body.SetLinearVelocity(update.lv);
body.SetAngularVelocity(update.av);
}
GameController.prototype.onWorldUpdateGameObject = function(body, gameObject, update) {
if(gameObject === this.me.doll) {
this.me.setLastServerPositionState(update);
if(!this.me.acceptPositionStateUpdateFromServer()) {
return; // this is to ignore own doll updates from world update
}
} while (body = body.GetNext());
}
Parent.prototype.onWorldUpdateGameObject.call(this, body, gameObject, update);
};
*/
GameController.prototype.onRemoveGameObject = function(options) {
};
GameController.prototype.updateGameObject = function (gameObject, gameObjectUpdate) {
if(gameObject === this.me.doll) {
this.me.setLastServerPositionState(gameObjectUpdate);
if(!this.me.acceptPositionStateUpdateFromServer()) {
return; // this is to ignore own doll updates from world update
}
}
Parent.prototype.updateGameObject.call(this, gameObject, gameObjectUpdate);
}
GameController.prototype.createMe = function(user) {
@ -146,9 +147,8 @@ function (Parent, Box2D, PhysicsEngine, ViewManager, PlayerController, Nc, reque
};
GameController.prototype.setMe = function() {
this.me.setPlayerController(new PlayerController(this.me));
this.view.setMe(this.me);
}
};
GameController.prototype.onGameCommand = function(message) {
ProtocolHelper.applyCommand(message, this);
@ -174,78 +174,35 @@ function (Parent, Box2D, PhysicsEngine, ViewManager, PlayerController, Nc, reque
playerId: playerId
});
}
}
};
GameController.prototype.onHandActionResponse = function(options) {
var player = this.players[options.playerId];
var item = null;
for (var i = 0; i < this.gameObjects.animated.length; i++) {
var currentItem = this.gameObjects.animated[i];
if(currentItem.uid == options.itemUid) {
item = currentItem;
break;
}
};
var item = this.getItemByUid(options.itemUid);
if(item) {
if(options.action == "throw") {
player.throw(options.x, options.y, item);
player.throw(options, item);
} else if(options.action == "grab") {
player.grab(item);
}
} else {
console.warn("Item for joint can not be found locally. " + options.itemUid)
console.warn("Item for joint can not be found locally. " + options.itemUid);
}
};
GameController.prototype.onUpdateStats = function(options) {
var player = this.players[options.playerId];
if(!player) {
throw new Exception("No player with id: " + options.playerId);
}
player.setStats(options.stats);
// FIXME: move to canvas later
if(player == this.me) {
DomController.setHealth(player.stats.health);
}
};
GameController.prototype.onPlayerKill = function(options) {
var player = this.players[options.playerId];
var killedByPlayer = this.players[options.killedByPlayerId];
player.kill(killedByPlayer, options.ragDollId);
};
GameController.prototype.onPositionStateReset = function(options) {
this.me.resetPositionState(options);
};
GameController.prototype.onRemoveGameObject = function(options) {
var object = null;
for (var i = 0; i < this.gameObjects[options.type].length; i++) {
if(this.gameObjects[options.type][i].uid == options.uid) {
object = this.gameObjects[options.type][i];
break;
}
}
if(object) {
//this.onGameObjectRemove(options.type, object);
object.destroy();
} else {
console.warn("GameObject for removal can not be found locally. " + options.uid);
}
};
GameController.prototype.loadLevel = function (path) {
Parent.prototype.loadLevel.call(this, path);
}
GameController.prototype.toggleInfo = function(show) {
var playersArray = [];
for (var key in this.players) {
playersArray.push(this.players[key]);
};
}
var sortedPlayers = playersArray.sort(function(a,b) {
if(a.stats.score > b.stats.score) return -1;
@ -257,48 +214,66 @@ function (Parent, Box2D, PhysicsEngine, ViewManager, PlayerController, Nc, reque
return 0;
});
function pad(string, max, alignLeft) {
string = string.substring(0, max - 1);
nc.trigger(nc.ns.client.view.gameStats.update, sortedPlayers);
};
var spaces = new Array( max - string.length + 1 ).join(" ");
if(alignLeft) {
return string + spaces;
} else {
return spaces + string;
}
}
GameController.prototype.onPlayerKill = function(options) {
var player = this.players[options.playerId];
var killedByPlayer = this.players[options.killedByPlayerId];
player.kill(killedByPlayer, options.ragDollId);
var string = "" +
pad("#", 2, false) + " " +
pad("Name", 12, true) +
pad("Score", 6, false) +
pad("Deaths", 7, false) +
pad("Health", 7, false) +
"\n-----------------------------------\n";
nc.trigger(nc.ns.client.view.gameStats.kill, {
victim: {
name: player.user.options.nickname,
isMe: player === this.me
},
killer: {
name: killedByPlayer.user.options.nickname,
isMe: killedByPlayer === this.me
},
item: options.item
});
};
var lines = [];
sortedPlayers.forEach(function(player, i) {
var name = player.getNickname();
lines.push(
pad("" + (i + 1) + ".", 2, false) + " " +
pad(name, 12, true) +
pad("" + player.stats.score, 6, false) +
pad("" + player.stats.deaths, 7, false) +
pad("" + parseInt(player.stats.health, 10), 7, false)
);
}, this);
GameController.prototype.onPositionStateReset = function(options) {
this.me.resetPositionState(options);
};
string += lines.join("\n");
GameController.prototype.loadLevel = function (path) {
Parent.prototype.loadLevel.call(this, path);
};
this.view.toggleInfo(show, string);
GameController.prototype.onLevelLoaded = function () {
pointerLockManager.update(null, {start:true});
};
GameController.prototype.toggleGameStats = function(show) {
nc.trigger(nc.ns.client.view.gameStats.toggle, show);
};
GameController.prototype.beginRound = function() {
this.me.setInBetweenRounds(false);
};
GameController.prototype.endRound = function() {
this.me.setInBetweenRounds(true);
this.toggleGameStats(true);
};
GameController.prototype.destroy = function() {
if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}
cancelAnimationFrame(this.animationRequestId);
Parent.prototype.destroy.call(this);
//this.audioPlayer.destroy();
this.view.destroy();
};

View file

@ -2,12 +2,17 @@ define([
"Game/Core/GameObjects/Doll",
"Game/Config/Settings",
"Lib/Utilities/NotificationCenter",
"Lib/Utilities/Exception"
"Lib/Utilities/Exception",
"Lib/Utilities/ColorConverter",
"Game/Client/View/Abstract/Layer",
],
function (Parent, Settings, Nc, Exception) {
function (Parent, Settings, nc, Exception, ColorConverter, Layer) {
"use strict";
function Doll(physicsEngine, uid, player) {
function Doll(physicsEngine, uid, player) {
this.layerId = Layer.ID.SPAWN;
this.animationDef = {
"stand": [1,1],
"walk": [2,28],
@ -20,31 +25,71 @@ function (Parent, Settings, Nc, Exception) {
"run": [104,126]
}
this.animatedMeshes = {};
this.lastStep = Date.now();
this.animatedMeshesContainer = {
withArms: {},
withoutArms: {}
};
this.animatedMeshes = this.animatedMeshesContainer.withArms;
this.headMesh = null;
this.holdingArmMesh = null;
var converter = new ColorConverter();
this.primaryColor = converter.getColorByName(player.getNickname());
Parent.call(this, physicsEngine, uid, player);
}
Doll.prototype = Object.create(Parent.prototype);
Doll.prototype.setActionState = function(state) {
Doll.prototype.setActionState = function(state, force) {
if(this.actionState == state) return;
if(!force && this.actionState == state) return;
if(!state) throw new Exception("action state is undefined");
if(this.animatedMeshes[this.actionState]) {
Nc.trigger(Nc.ns.client.view.mesh.update, this.animatedMeshes[this.actionState], { visible: false });
nc.trigger(
nc.ns.client.view.mesh.update,
this.layerId,
this.animatedMeshesContainer.withArms[this.actionState],
{ visible: false }
);
nc.trigger(
nc.ns.client.view.mesh.update,
this.layerId,
this.animatedMeshesContainer.withoutArms[this.actionState],
{ visible: false }
);
}
Parent.prototype.setActionState.call(this, state);
Nc.trigger(Nc.ns.client.view.mesh.update, this.animatedMeshes[this.actionState], { visible: true });
nc.trigger(
nc.ns.client.view.mesh.update,
this.layerId,
this.animatedMeshes[this.actionState],
{
visible: true,
xScale: this.lookDirection
}
);
}
Doll.prototype.createMesh = function() {
var self = this;
var setShirtColor = function (mesh) {
nc.trigger(nc.ns.client.view.mesh.addFilter, self.layerId, mesh, 'colorRangeReplace', {
minColor: 0x3b4a31,
maxColor: 0x657f54,
newColor: self.primaryColor,
brightnessOffset: 0.56
});
}
// Body
var padF = function(n) {
@ -55,53 +100,101 @@ function (Parent, Settings, Nc, Exception) {
var self = this;
for (var key in this.animationDef) {
var start = this.animationDef[key][0];
var end = this.animationDef[key][1];
var arms = ["withArms", "withoutArms"];
for (var j = 0; j < arms.length; j++) {
var arm = arms[j];
for (var key in this.animationDef) {
var start = this.animationDef[key][0];
var end = this.animationDef[key][1];
var texturePaths = [];
for (var i = start; i <= end; i++) {
texturePaths.push(
Settings.GRAPHICS_PATH
+ Settings.GRAPHICS_SUBPATH_CHARACTERS
+ this.characterName
//+ "/Animation/WithoutArms/ChuckAnimationsWithoutArms0"
+ "/Animation/WithArms/ChuckAnimations0"
+ padF(i)
+ ".png"
);
var texturePaths = [];
for (var i = start; i <= end; i++) {
/*
// Multiple File Animations
texturePaths.push(
Settings.GRAPHICS_PATH
+ Settings.GRAPHICS_SUBPATH_CHARACTERS
+ this.characterName
+ "/Animation/" + arm.toUpperCaseFirstChar() + "/ChuckAnimations0"
+ padF(i)
+ ".png"
);
*/
// Single File Animations (animation names from chuck_sheet.json, use option fromFrame=true)
texturePaths.push(
"Chuck" + arm.toUpperCaseFirstChar() + "0" + padF(i) + ".png"
);
}
var callback = function(mesh) {
self.animatedMeshesContainer[arm][key] = mesh;
nc.trigger(nc.ns.client.view.mesh.add, self.layerId, mesh);
setShirtColor(mesh);
};
nc.trigger(nc.ns.client.view.animatedMesh.create, this.layerId, texturePaths, callback, {
visible: false,
pivot: {
x: 0,
y: 40 * 4
},
xScale: 0.25,
yScale: 0.25,
anchor: {
x: 0.5,
y: 0
},
fromFrame: true
});
}
var callback = function(mesh) {
self.animatedMeshes[key] = mesh;
Nc.trigger(Nc.ns.client.view.mesh.add, mesh);
};
Nc.trigger(Nc.ns.client.view.animatedMesh.create, texturePaths, callback, {
visible: false,
pivot: {
x: 35/2 * 4,
y: 40 * 4
},
width: 35,
height: 40
});
}
};
// Head
var texturePath = Settings.GRAPHICS_PATH + "Characters/Chuck/head.png";
var callback = function (mesh) {
self.headMesh = mesh;
Nc.trigger(Nc.ns.client.view.mesh.add, mesh);
nc.trigger(nc.ns.client.view.mesh.add, self.layerId, mesh);
}
Nc.trigger(Nc.ns.client.view.mesh.create, texturePath, callback, {
nc.trigger(nc.ns.client.view.mesh.create, this.layerId, texturePath, callback, {
pivot: {
x: 5,
y: 12
},
width: 10,
height: 12
height: 12,
anchor: {
x: 0,
y: 0
}
});
// Holding arm
texturePath = Settings.GRAPHICS_PATH + "Characters/Chuck/holdingArm.png";
var callback = function (mesh) {
self.holdingArmMesh = mesh;
nc.trigger(nc.ns.client.view.mesh.add, self.layerId, mesh);
setShirtColor(mesh);
}
nc.trigger(nc.ns.client.view.mesh.create, this.layerId, texturePath, callback, {
visible: false,
pivot: {
//x: 35/2 * 4,
x: 0,
y: 40 * 4
},
width: 35,
height: 40,
anchor: {
x: 0.5,
y: 0
}
});
}
@ -113,18 +206,28 @@ function (Parent, Settings, Nc, Exception) {
if(oldLookDirection != this.lookDirection) {
for(var key in this.animatedMeshes) {
Nc.trigger(Nc.ns.client.view.mesh.update,
nc.trigger(nc.ns.client.view.mesh.update,
this.layerId,
this.animatedMeshes[key],
{
xScale: this.lookDirection
}
);
}
nc.trigger(nc.ns.client.view.mesh.update,
this.layerId,
this.holdingArmMesh,
{
xScale: this.lookDirection
}
);
}
var angle = Math.atan2(this.lookAtXY.x, this.lookAtXY.y) / 2 - 0.7855 * this.lookDirection; // 0.7855 = 45°
Nc.trigger(Nc.ns.client.view.mesh.update,
nc.trigger(nc.ns.client.view.mesh.update,
this.layerId,
this.headMesh,
{
xScale: this.lookDirection,
@ -133,35 +236,70 @@ function (Parent, Settings, Nc, Exception) {
);
}
Doll.prototype.grab = function(item) {
Parent.prototype.grab.call(this, item);
this.animatedMeshes = this.animatedMeshesContainer.withoutArms;
this.setActionState(this.actionState, true);
nc.trigger(nc.ns.client.view.mesh.update, this.layerId, this.holdingArmMesh, { visible: true });
};
Doll.prototype.throw = function(item, options) {
Parent.prototype.throw.call(this, item, options);
this.animatedMeshes = this.animatedMeshesContainer.withArms;
this.setActionState(this.actionState, true);
nc.trigger(nc.ns.client.view.mesh.update, this.layerId, this.holdingArmMesh, { visible: false });
};
Doll.prototype.destroy = function () {
for (var key in this.animatedMeshes) {
Nc.trigger(Nc.ns.client.view.mesh.remove, this.animatedMeshes[key]);
nc.trigger(nc.ns.client.view.mesh.remove, this.layerId, this.animatedMeshes[key]);
}
Nc.trigger(Nc.ns.client.view.mesh.remove, this.headMesh);
nc.trigger(nc.ns.client.view.mesh.remove, this.layerId, this.headMesh);
Parent.prototype.destroy.call(this);
}
Doll.prototype.render = function() {
if(this.actionState) {
Nc.trigger(Nc.ns.client.view.mesh.update,
var stepLength = (Date.now() - this.lastStep);
this.lastStep = Date.now();
// compare current framerate to wanted and get factor
// (stepLength / 60) * 2
// * 2 to scale to flash fps
var factor = stepLength / 30;
nc.trigger(nc.ns.client.view.mesh.update,
this.layerId,
this.animatedMeshes[this.actionState],
{
x: this.body.GetPosition().x * Settings.RATIO,
y: this.body.GetPosition().y * Settings.RATIO,
rotation: this.body.GetAngle()
animationSpeed: factor
//rotation: this.body.GetAngle()
}
);
Nc.trigger(Nc.ns.client.view.mesh.update,
nc.trigger(nc.ns.client.view.mesh.update,
this.layerId,
this.headMesh,
{
x: this.body.GetPosition().x * Settings.RATIO,
y: this.body.GetPosition().y * Settings.RATIO - this.height + this.headHeight
}
)
nc.trigger(nc.ns.client.view.mesh.update,
this.layerId,
this.holdingArmMesh,
{
x: this.body.GetPosition().x * Settings.RATIO,
y: this.body.GetPosition().y * Settings.RATIO
}
)
}
}

View file

@ -4,7 +4,9 @@ define([
"Lib/Utilities/NotificationCenter"
],
function (Parent, Exception, Nc) {
function (Parent, Exception, nc) {
"use strict";
function GameObject(physicsEngine, uid) {
Parent.call(this, physicsEngine, uid);
@ -25,7 +27,7 @@ function (Parent, Exception, Nc) {
GameObject.prototype.createMesh = function() {
throw new Exception('Abstract method GameObject.createMesh not overwritten');
};
return GameObject;
});

View file

@ -1,13 +1,21 @@
define([
"Game/Core/GameObjects/Item",
"Game/Config/Settings",
"Lib/Utilities/NotificationCenter"
"Lib/Utilities/NotificationCenter",
"Game/Client/View/Abstract/Layer"
],
function (Parent, Settings, Nc) {
function (Parent, Settings, nc, Layer) {
"use strict";
function Item(physicsEngine, uid, options) {
this.layerId = Layer.ID.ITEM;
Parent.call(this, physicsEngine, uid, options);
this.ncTokens = this.ncTokens.concat([
nc.on(nc.ns.client.game.events.render, this.render, this)
]);
}
Item.prototype = Object.create(Parent.prototype);
@ -22,10 +30,11 @@ function (Parent, Settings, Nc) {
var callback = function(mesh) {
self.mesh = mesh;
Nc.trigger(Nc.ns.client.view.mesh.add, mesh);
nc.trigger(nc.ns.client.view.mesh.add, self.layerId, mesh);
}
Nc.trigger(Nc.ns.client.view.mesh.create,
nc.trigger(nc.ns.client.view.mesh.create,
this.layerId,
texturePath,
callback,
{
@ -40,13 +49,14 @@ function (Parent, Settings, Nc) {
};
Item.prototype.destroy = function() {
Nc.trigger(Nc.ns.client.view.mesh.remove, this.mesh);
nc.trigger(nc.ns.client.view.mesh.remove, this.layerId, this.mesh);
Parent.prototype.destroy.call(this);
};
Item.prototype.render = function() {
Nc.trigger(Nc.ns.client.view.mesh.update,
nc.trigger(nc.ns.client.view.mesh.update,
this.layerId,
this.mesh,
{
x: this.body.GetPosition().x * Settings.RATIO,
@ -62,7 +72,8 @@ function (Parent, Settings, Nc) {
Parent.prototype.flip.call(this, direction);
if(oldFlipDirection != direction) {
Nc.trigger(Nc.ns.client.view.mesh.update,
nc.trigger(nc.ns.client.view.mesh.update,
this.layerId,
this.mesh,
{
xScale: direction

View file

@ -2,12 +2,16 @@ define([
"Game/Core/GameObjects/Items/RagDoll",
"Game/Core/GameObjects/Item",
"Game/Config/Settings",
"Lib/Utilities/NotificationCenter"
"Lib/Utilities/NotificationCenter",
"Game/Client/View/Abstract/Layer"
],
function (Parent, CoreItem, Settings, Nc) {
function (Parent, CoreItem, Settings, nc, Layer) {
"use strict";
function RagDoll(physicsEngine, uid, options) {
this.layerId = Layer.ID.SPAWN;
this.limbMeshes = {};
this.baseMeshName = "chest";
this.characterName = "Chuck";
@ -36,10 +40,11 @@ function (Parent, CoreItem, Settings, Nc) {
self.limbMeshes[name] = mesh;
}
Nc.trigger(Nc.ns.client.view.mesh.add, mesh);
nc.trigger(nc.ns.client.view.mesh.add, self.layerId, mesh);
}
Nc.trigger(Nc.ns.client.view.mesh.create,
nc.trigger(nc.ns.client.view.mesh.create,
this.layerId,
texturePath + name + ".png",
callback,
{
@ -59,7 +64,8 @@ function (Parent, CoreItem, Settings, Nc) {
if(this.limbs) {
for(var name in this.limbMeshes) {
if(this.limbs[name]) {
Nc.trigger(Nc.ns.client.view.mesh.update,
nc.trigger(nc.ns.client.view.mesh.update,
this.layerId,
this.limbMeshes[name],
{
x: this.limbs[name].GetPosition().x * Settings.RATIO,
@ -79,7 +85,8 @@ function (Parent, CoreItem, Settings, Nc) {
CoreItem.prototype.flip.call(this, direction);
if(oldFlipDirection != direction) {
Nc.trigger(Nc.ns.client.view.mesh.update,
nc.trigger(nc.ns.client.view.mesh.update,
this.layerId,
this.mesh,
{
xScale: direction
@ -87,7 +94,8 @@ function (Parent, CoreItem, Settings, Nc) {
);
for (var name in this.limbMeshes) {
Nc.trigger(Nc.ns.client.view.mesh.update,
nc.trigger(nc.ns.client.view.mesh.update,
this.layerId,
this.limbMeshes[name],
{
xScale: direction
@ -100,7 +108,7 @@ function (Parent, CoreItem, Settings, Nc) {
RagDoll.prototype.destroy = function() {
for (var name in this.limbMeshes) {
Nc.trigger(Nc.ns.client.view.mesh.remove, this.limbMeshes[name]);
nc.trigger(nc.ns.client.view.mesh.remove, this.layerId, this.limbMeshes[name]);
};
Parent.prototype.destroy.call(this);

View file

@ -1,26 +0,0 @@
define([
"Game/Core/GameObjects/Items/Rube"
],
function (Parent) {
function Rube(physicsEngine, uid, options) {
Parent.call(this, physicsEngine, uid, options);
}
Rube.prototype = Object.create(Parent.prototype);
Rube.prototype.createMesh = function() {
};
Rube.prototype.destroy = function() {
};
Rube.prototype.render = function() {
}
Rube.prototype.flip = function(direction) {
};
return Rube;
});

View file

@ -0,0 +1,254 @@
define([
"Game/Core/GameObjects/Items/RubeDoll",
"Game/Client/View/Abstract/Layer",
"Game/Config/Settings",
"Lib/Utilities/NotificationCenter",
],
function (Parent, Layer, Settings, nc) {
"use strict";
function RubeDoll(physicsEngine, uid, options) {
this.primaryColor = options.primaryColor;
var limbOptions = {};
limbOptions.chest = {
width: 6,
height: 18,
x: 0,
y: 0
};
limbOptions.head = {
width: 10,
height: 12,
x: 0,
y: - limbOptions.chest.height / 2 - 7
};
limbOptions.upperLeftLeg = {
width: 5,
height: 8,
x: -2,
y: limbOptions.chest.height / 2
};
limbOptions.upperRightLeg = {
width: 5,
height: 8,
x: 2,
y: limbOptions.chest.height / 2
};
limbOptions.lowerLeftLeg = {
width: 5,
height: 4,
x: -2,
y: limbOptions.chest.height / 2 + limbOptions.upperLeftLeg.height
};
limbOptions.lowerRightLeg = {
width: 5,
height: 4,
x: 2,
y: limbOptions.chest.height / 2 + limbOptions.upperRightLeg.height
};
limbOptions.upperLeftArm = {
width: 4,
height: 8,
x: -2,
y: -limbOptions.chest.height / 2
};
limbOptions.upperRightArm = {
width: 4,
height: 8,
x: 2,
y: -limbOptions.chest.height / 2
};
limbOptions.lowerLeftArm = {
width: 4,
height: 5,
x: -2,
y: -limbOptions.chest.height / 2 + limbOptions.upperLeftArm.height
};
limbOptions.lowerRightArm = {
width: 4,
height: 5,
x: 2,
y: -limbOptions.chest.height / 2 + limbOptions.upperRightArm.height
};
this.limbOptions = limbOptions;
this.layerId = Layer.ID.SPAWN;
this.limbMeshes = {};
this.baseMeshName = "chest";
this.characterName = "Chuck";
this.lastFlipDirection = -options.direction || 1;
Parent.call(this, physicsEngine, uid, options);
}
RubeDoll.prototype = Object.create(Parent.prototype);
RubeDoll.prototype.createMesh = function() {
this.createLimbMesh("lowerRightLeg");
this.createLimbMesh("upperRightLeg");
this.createLimbMesh("lowerRightArm");
this.createLimbMesh("upperRightArm");
this.createLimbMesh("chest");
this.createLimbMesh("head");
this.createLimbMesh("lowerLeftLeg");
this.createLimbMesh("upperLeftLeg");
this.createLimbMesh("lowerLeftArm");
this.createLimbMesh("upperLeftArm");
};
RubeDoll.prototype.createLimbMesh = function(name) {
var self = this;
var texturePath = Settings.GRAPHICS_PATH
+ Settings.GRAPHICS_SUBPATH_CHARACTERS + ""
+ this.characterName + '/';
var callback = function(mesh) {
if(name == self.baseMeshName) {
self.mesh = mesh;
}
self.limbMeshes[name] = mesh;
nc.trigger(nc.ns.client.view.mesh.add, self.layerId, mesh);
// setting shirt color
nc.trigger(nc.ns.client.view.mesh.addFilter, self.layerId, mesh, "colorRangeReplace", {
minColor: 0x3b4a31,
maxColor: 0x6d855d,
newColor: self.primaryColor,
brightnessOffset: 0.56
});
};
nc.trigger(nc.ns.client.view.mesh.create,
this.layerId,
texturePath + name + ".png",
callback,
{
width: this.limbOptions[name].width,
height: this.limbOptions[name].height,
pivot: {
x: this.limbOptions[name].width / 2,
y: this.limbOptions[name].height / 2
}
}
);
};
RubeDoll.prototype.destroy = function() {
for (var name in this.limbMeshes) {
nc.trigger(nc.ns.client.view.mesh.remove, this.layerId, this.limbMeshes[name]);
};
Parent.prototype.destroy.call(this);
};
RubeDoll.prototype.render = function() {
//Parent.prototype.render.call(this);
nc.trigger(nc.ns.client.view.mesh.update,
this.layerId,
this.mesh,
{
x: this.body.GetPosition().x * Settings.RATIO,
y: this.body.GetPosition().y * Settings.RATIO,
rotation: this.body.GetAngle()
}
);
if(this.limbs) {
for(var name in this.limbMeshes) {
if(this.limbs[name]) {
nc.trigger(nc.ns.client.view.mesh.update,
this.layerId,
this.limbMeshes[name],
{
x: this.limbs[name].GetPosition().x * Settings.RATIO,
y: this.limbs[name].GetPosition().y * Settings.RATIO,
rotation: this.limbs[name].GetAngle()
}
);
}
}
}
};
RubeDoll.prototype.flip = function(direction) {
Parent.prototype.flip.call(this, direction);
// flipping depth of right body side arm/leg images with left
if (this.lastFlipDirection != direction) { // FIXME : this is a bit broken.
this.lastFlipDirection = direction;
nc.trigger(nc.ns.client.view.mesh.swapMeshIndexes,
this.layerId,
this.limbMeshes["lowerRightLeg"],
this.limbMeshes["lowerLeftLeg"]
);
nc.trigger(nc.ns.client.view.mesh.swapMeshIndexes,
this.layerId,
this.limbMeshes["upperRightLeg"],
this.limbMeshes["upperLeftLeg"]
);
nc.trigger(nc.ns.client.view.mesh.swapMeshIndexes,
this.layerId,
this.limbMeshes["lowerRightArm"],
this.limbMeshes["lowerLeftArm"]
);
nc.trigger(nc.ns.client.view.mesh.swapMeshIndexes,
this.layerId,
this.limbMeshes["upperRightArm"],
this.limbMeshes["upperLeftArm"]
);
// swap short images
nc.trigger(nc.ns.client.view.mesh.swapMeshes,
this.layerId,
this.limbMeshes["upperRightLeg"],
this.limbMeshes["upperLeftLeg"]
);
}
// x flipping has to happen after (see swapMeshes)
if(this.limbs) {
for(var name in this.limbMeshes) {
if(this.limbs[name]) {
nc.trigger(nc.ns.client.view.mesh.update,
this.layerId,
this.limbMeshes[name],
{
xScale: direction,
}
);
}
}
}
};
return RubeDoll;
});

View file

@ -3,6 +3,8 @@ define([
],
function (Parent) {
"use strict";
function SpectatorDoll(physicsEngine, uid) {
Parent.call(this, physicsEngine, uid);

View file

@ -1,12 +1,16 @@
define([
"Game/Core/GameObjects/Tile",
"Game/Config/Settings",
"Lib/Utilities/NotificationCenter"
"Lib/Utilities/NotificationCenter",
"Game/Client/View/Abstract/Layer"
],
function (Parent, Settings, Nc) {
function (Parent, Settings, nc, Layer) {
"use strict";
function Tile(physicsEngine, uid, options) {
this.layerId = Layer.ID.TILE;
Parent.call(this, physicsEngine, uid, options);
}
@ -27,10 +31,11 @@ function (Parent, Settings, Nc) {
var callback = function(mesh) {
self.mesh = mesh;
Nc.trigger(Nc.ns.client.view.mesh.add, mesh);
nc.trigger(nc.ns.client.view.mesh.add, self.layerId, mesh);
}
Nc.trigger(Nc.ns.client.view.mesh.create,
nc.trigger(nc.ns.client.view.mesh.create,
this.layerId,
texturePath,
callback,
{
@ -45,13 +50,14 @@ function (Parent, Settings, Nc) {
};
Tile.prototype.destroy = function() {
Nc.trigger(Nc.ns.client.view.mesh.remove, this.mesh);
nc.trigger(nc.ns.client.view.mesh.remove, this.layerId, this.mesh);
Parent.prototype.destroy.call(this);
};
Tile.prototype.render = function() {
Nc.trigger(Nc.ns.client.view.mesh.update,
nc.trigger(nc.ns.client.view.mesh.update,
this.layerId,
this.mesh,
{
x: this.body.GetPosition().x * Settings.RATIO,

View file

@ -2,13 +2,20 @@ define([
"Game/Core/Loader/Level",
"Game/Config/Settings",
"Lib/Utilities/NotificationCenter",
"Lib/Vendor/Pixi"
"Lib/Vendor/Pixi",
"Game/Client/View/Abstract/Layer"
],
function (Parent, Settings, Nc, PIXI) {
function (Parent, Settings, nc, PIXI, AbstractLayer) {
"use strict";
function Level (uid, engine, gameObjects) {
Parent.call(this, uid, engine, gameObjects);
this.levelSize = {
width: 0,
height: 0
}
}
Level.prototype = Object.create(Parent.prototype);
@ -17,13 +24,13 @@ function (Parent, Settings, Nc, PIXI) {
var self = this;
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if(xhr.readyState == 4) {
if(xhr.status == 200) {
self.loadAssets(JSON.parse(xhr.responseText), callback);
} else {
console.error("Ajax error: " + xhr.status + " " + xhr.statusText)
}
if(xhr.readyState == 4) {
if(xhr.status == 200) {
self.loadAssets(JSON.parse(xhr.responseText), callback);
} else {
console.error("Ajax error: " + xhr.status + " " + xhr.statusText)
}
}
}
xhr.open("GET", path, true);
xhr.send(null);
@ -39,7 +46,7 @@ function (Parent, Settings, Nc, PIXI) {
loader.onComplete = function() { callback(levelData); };
loader.onProgress = function() {
var progress = parseInt(100 / numPaths * ++count, 10) + 1;
Nc.trigger(Nc.ns.client.view.preloadBar.update, progress);
nc.trigger(nc.ns.client.view.preloadBar.update, progress);
}
loader.load();
};
@ -55,28 +62,42 @@ function (Parent, Settings, Nc, PIXI) {
return n;
}
var characterNames = ["Chuck"];
var animationSets = ["WithArms"];//, "WithArms"];
/*
// Single File Animations Preloading
var animationSets = ["WithArms", "WithoutArms"];
var addition = "";
for (var i = 0; i < characterNames.length; i++) {
var characterName = characterNames[i];
for (var j = 1; j <= 126; j++) {
for (var k = 0; k < animationSets.length; k++) {
var animationSet = animationSets[k];
addition = animationSet == "WithoutArms" ? "WithoutArms" : "";
paths.push(
Settings.GRAPHICS_PATH
+ Settings.GRAPHICS_SUBPATH_CHARACTERS
+ characterName
+ "/Animation/"
+ animationSet
+ "/ChuckAnimations" + addition + "0"
+ "/ChuckAnimations0"
+ padF(j)
+ ".png"
);
};
};
};
*/
var characterNames = ["Chuck"];
var characterName = characterNames[0];
paths.push(
Settings.GRAPHICS_PATH
+ Settings.GRAPHICS_SUBPATH_CHARACTERS
+ characterName
+ "/Animation/"
+ "/TexturePacker"
+ "/chuck_sheet.json"
);
paths.push(
Settings.GRAPHICS_PATH
@ -88,5 +109,24 @@ function (Parent, Settings, Nc, PIXI) {
return paths;
};
Level.prototype.setupLayer = function(options, behind, referenceId) {
Parent.prototype.setupLayer.call(this, options, behind, referenceId);
var parallaxSpeed = 0.0; // default parallax
if (options.properties && options.properties.parallaxSpeed) {
parallaxSpeed = parseFloat(options.properties.parallaxSpeed);
}
nc.trigger(
nc.ns.client.view.layer.createAndInsert,
options.layerId,
{
parallaxSpeed: parallaxSpeed,
levelSize: this.levelSize
},
behind,
referenceId
);
};
return Level;
});

View file

@ -1,16 +1,32 @@
define([
"Game/Core/Loader/TiledLevel",
"Game/Config/Settings"
"Game/Config/Settings",
"Lib/Utilities/NotificationCenter",
],
function (Parent, Settings) {
function (Parent, Settings, nc) {
"use strict";
function TiledLevel(uid, engine, gameObjects) {
Parent.call(this, uid, engine, gameObjects);
function TiledLevel(uid, engine) {
this.layerId = "background";
Parent.call(this, uid, engine);
}
TiledLevel.prototype = Object.create(Parent.prototype);
TiledLevel.prototype.setup = function(levelData) {
var tilesLayerData = this.getLayer(levelData, "tiles");
this.levelSize = {
width: tilesLayerData.width * Settings.TILE_SIZE,
height: tilesLayerData.height * Settings.TILE_SIZE
};
nc.trigger(nc.ns.client.view.layer.levelSizeUpdate, this.levelSize);
Parent.prototype.setup.call(this, levelData);
};
TiledLevel.prototype.getAssetPaths = function(levelData) {
var paths = Parent.prototype.getAssetPaths.call(this, levelData);
@ -40,12 +56,100 @@ function (Parent, Settings) {
paths.push(texturePath);
};
// FIXME: Get background image
for (var i = 0; i < levelData.layers.length; i++) {
var layer = levelData.layers[i];
if (layer.type == "imagelayer") {
paths.push(Settings.MAPS_PATH + layer.image);
}
};
return paths;
}
TiledLevel.prototype.setupLayer = function(options, behind, referenceId) {
var self = this;
Parent.prototype.setupLayer.call(this, options, behind, referenceId);
// So far only one image per layer is possible because of Tiled editor
if (options.type == "imagelayer") {
var texturePath = Settings.MAPS_PATH + options.image;
var callback = function(mesh) {
nc.trigger(nc.ns.client.view.mesh.add, options.layerId, mesh);
nc.trigger(nc.ns.client.view.mesh.update, options.layerId, mesh, {
x: 0,//self.levelData.width * Settings.TILE_SIZE / 2,
y: 0,//self.levelData.height * Settings.TILE_SIZE / 2,
pivot: {
x: mesh.texture.width / 2,
y: mesh.texture.height / 2
},
xScale: 1,
yScale: 1
});
}
nc.trigger(nc.ns.client.view.mesh.create,
options.layerId,
texturePath,
callback,
{
alpha: options.opacity
}
);
}
// Adding tiles without collision
else if (options.type == "tilelayer" && options.name != "tiles") {
this.createNonCollidingTiles(options);
}
};
TiledLevel.prototype.createNonCollidingTiles = function(options) {
var data = options.data;
var tilesOptions = [];
for (var i = 0; i < data.length; i++) {
var gid = data[i];
if(gid === 0) continue;
var imagePath = this.getTileImagePath(gid);
var parts = imagePath.split("/");
var tileType = parts[parts.length - 1].split(".")[0].split("")
var callback = function(mesh) {
nc.trigger(nc.ns.client.view.mesh.add, options.layerId, mesh);
}
nc.trigger(nc.ns.client.view.mesh.create,
options.layerId,
Settings.MAPS_PATH + imagePath,
callback,
{
width: Settings.TILE_SIZE,
height: Settings.TILE_SIZE,
x: (i % options.width) * Settings.TILE_SIZE,
y: parseInt(i / options.width , 10) * Settings.TILE_SIZE,
}
);
}
}
TiledLevel.prototype.getLayer = function(levelData, name) {
for (var i = 0; i < levelData.layers.length; i++) {
if(levelData.layers[i].name === name) {
return levelData.layers[i];
}
}
throw "Layer '" + name + "' not found.";
};
return TiledLevel;
});

View file

@ -1,28 +1,60 @@
define([
"Game/Client/Player",
"Game/Config/Settings"
"Game/Config/Settings",
"Lib/Utilities/NotificationCenter",
"Lib/Utilities/Assert",
"Game/Client/Control/PlayerController",
],
function (Parent, Settings) {
function (Parent, Settings, nc, Assert, PlayerController) {
"use strict";
function Me(id, physicsEngine, user) {
Parent.call(this, id, physicsEngine, user);
// View uses this to calculate center position
this.lookAtXY = {
x: Settings.VIEWPORT_LOOK_AHEAD,
y: 0
};
this.lastServerPositionState = {
p: {
x: 0,
y: 0
}
};
this.arrowMesh = null;
this.createAndAddArrow();
this.playerController = new PlayerController(this);
}
Me.prototype = Object.create(Parent.prototype);
Me.prototype.lookAt = function(x, y) {
this.lookAtXY = {
x: x,
y: y
};
Parent.prototype.lookAt.call(this, x, y);
};
Me.prototype.getLookAt = function() {
return {
x: this.lookAtXY.x,
y: this.lookAtXY.y
};
};
Me.prototype.setLastServerPositionState = function(update) {
this.lastServerPositionState = update;
};
Me.prototype.isPositionStateUpdateNeeded = function() {
// Checks if client should send out its position to server
Me.prototype.isPositionStateOverrideNeeded = function() {
if(!this.doll) {
return false;
@ -35,20 +67,20 @@ function (Parent, Settings) {
var difference = {
x: Math.abs(this.lastServerPositionState.p.x - this.doll.body.GetPosition().x),
y: Math.abs(this.lastServerPositionState.p.y - this.doll.body.GetPosition().y)
}
};
if(difference.x > Settings.ME_STATE_MAX_DIFFERENCE_METERS
|| difference.y > Settings.ME_STATE_MAX_DIFFERENCE_METERS) {
if(difference.x > Settings.ME_STATE_MAX_DIFFERENCE_METERS ||
difference.y > Settings.ME_STATE_MAX_DIFFERENCE_METERS) {
return true;
}
return false;
};
Me.prototype.getPositionStateUpdate = function() {
Me.prototype.getPositionStateOverride = function() {
return {
p: this.doll.body.GetPosition().Copy(),
lv: this.doll.body.GetLinearVelocity().Copy()
}
};
};
Me.prototype.acceptPositionStateUpdateFromServer = function() {
@ -57,10 +89,39 @@ function (Parent, Settings) {
};
Me.prototype.resetPositionState = function(options) {
Assert.number(options.p.x, options.p.y);
Assert.number(options.lv.x, options.lv.y);
this.doll.body.SetPosition(options.p);
this.doll.body.SetLinearVelocity(options.lv);
};
Me.prototype.createAndAddArrow = function() {
var self = this;
var position = this.getPosition();
var options = {
x: position.x * Settings.RATIO,
y: position.y * Settings.RATIO,
};
var callback = function(arrowMesh) {
self.arrowMesh = arrowMesh;
};
nc.trigger(nc.ns.client.view.playerArrow.createAndAdd, callback, options);
};
Me.prototype.render = function() {
Parent.prototype.render.call(this);
var position = this.getPosition();
var options = {
x: position.x * Settings.RATIO,
y: position.y * Settings.RATIO,
};
nc.trigger(nc.ns.client.view.playerArrow.update, this.arrowMesh, options);
};
return Me;
});

View file

@ -7,9 +7,14 @@ define([
"Game/Client/View/DomController"
],
function (ProtocolHelper, GameController, User, Nc, Settings, DomController) {
function (ProtocolHelper, GameController, User, nc, Settings, domController) {
function Networker (socketLink) {
"use strict";
function Networker (socketLink, channelName, nickname) {
this.channelName = channelName;
this.nickname = nickname;
this.socketLink = socketLink;
this.gameController = null;
this.users = {};
@ -20,33 +25,47 @@ function (ProtocolHelper, GameController, User, Nc, Settings, DomController) {
var self = this;
this.socketLink.on('message', function (message) {
var m = JSON.parse(message)
if(Settings.NETWORK_LOG_INCOMING) {
if (message.indexOf('worldUpdate') == -1 && message.indexOf('pong') == -1) {
if(Settings.NETWORK_LOG_INCOMING) {
var shouldBeFiltered = false;
var keyword;
for (var i = 0; i < Settings.NETWORK_LOG_FILTER.length; i++) {
keyword = Settings.NETWORK_LOG_FILTER[i];
if(message.search(keyword) != -1) {
shouldBeFiltered = true;
break;
}
};
if(!shouldBeFiltered) {
console.log('INCOMING', message);
}
}
ProtocolHelper.applyCommand(message, self);
});
Nc.on(Nc.ns.client.to.server.gameCommand.send, this.sendGameCommand, this);
Nc.on(Nc.ns.core.game.events.level.loaded, this.onLevelLoaded, this);
nc.on(nc.ns.client.to.server.gameCommand.send, this.sendGameCommand, this);
nc.on(nc.ns.core.game.events.level.loaded, this.onLevelLoaded, this);
domController.setNick(nickname);
}
// Socket callbacks
Networker.prototype.onConnect = function () {
console.log('connected.')
var channel = JSON.parse(localStorage["channel"]);
var player = JSON.parse(localStorage["player"]);
if(channel.name) {
if(this.channelName) {
var options = {
channelName: channel.name,
nickname: player.nickname
channelName: this.channelName,
nickname: this.nickname
}
this.sendCommand('join', options);
domController.setConnected(true);
} else {
alert("Error: no channel name");
window.location.href = "/";
}
}
@ -55,7 +74,7 @@ function (ProtocolHelper, GameController, User, Nc, Settings, DomController) {
//if(this.gameController) this.gameController.destruct();
//this.gameController = null;
console.log('disconnected. game destroyed. no auto-reconnect');
document.body.style.backgroundColor = '#aaaaaa';
domController.setConnected(false);
}
Networker.prototype.onJoinSuccess = function (options) {
@ -74,18 +93,21 @@ function (ProtocolHelper, GameController, User, Nc, Settings, DomController) {
}
Networker.prototype.onJoinError = function(options) {
// alert(options.message);
alert(options.message);
window.location.href = "/";
};
Networker.prototype.onLevelLoaded = function() {
/*
this.gameController.createMe(this.users[this.meUserId]);
for (var userId in this.users) {
if(this.meUserId != userId) {
this.gameController.createPlayer(this.users[userId]);
}
}
}*/
this.gameController.onLevelLoaded();
this.sendGameCommand("clientReady");
};
@ -107,23 +129,18 @@ function (ProtocolHelper, GameController, User, Nc, Settings, DomController) {
this.socketLink.send(message);
if(Settings.NETWORK_LOG_OUTGOING) {
if(Settings.NETWORK_LOG_FILTER.length > 0) {
var shouldBeFiltered = false;
var keyword;
var shouldBeFiltered = false;
var keyword;
for (var i = 0; i < Settings.NETWORK_LOG_FILTER.length; i++) {
keyword = Settings.NETWORK_LOG_FILTER[i];
if(message.search(keyword) != -1) {
shouldBeFiltered = true;
break;
}
};
if(!shouldBeFiltered) {
console.log('OUTGOING', message);
for (var i = 0; i < Settings.NETWORK_LOG_FILTER.length; i++) {
keyword = Settings.NETWORK_LOG_FILTER[i];
if(message.search(keyword) != -1) {
shouldBeFiltered = true;
break;
}
} else {
};
if(!shouldBeFiltered) {
console.log('OUTGOING', message);
}
}
@ -157,12 +174,16 @@ function (ProtocolHelper, GameController, User, Nc, Settings, DomController) {
}
Networker.prototype.onGameCommand = function(message) {
this.gameController.onGameCommand(message);
if (this.gameController) {
this.gameController.onGameCommand(message);
} else {
console.warn("Networker.onGameCommand: this.gameController is undefined", message);
}
}
Networker.prototype.onPong = function(timestamp) {
var ping = (Date.now() - parseInt(timestamp, 10));
DomController.setPing(ping);
domController.setPing(ping);
setTimeout(this.ping.bind(this), 1000);
};
@ -170,14 +191,23 @@ function (ProtocolHelper, GameController, User, Nc, Settings, DomController) {
if(this.gameController) {
this.gameController.destroy();
delete this.gameController;
}
this.gameController = new GameController(options);
this.gameController.createMe(this.users[this.meUserId]);
for (var userId in this.users) {
if(this.meUserId != userId) {
this.gameController.createPlayer(this.users[userId]);
}
}
this.gameController.beginRound();
};
Networker.prototype.onEndRound = function() {
this.gameController.toggleInfo(true);
this.gameController.endRound();
};
return Networker;

View file

@ -3,17 +3,21 @@ define([
"Game/Config/Settings",
"Game/Client/View/DomController",
"Lib/Vendor/Box2D",
"Lib/Utilities/NotificationCenter"
"Lib/Utilities/NotificationCenter",
"Game/Client/View/Pixi/DebugDraw",
"Game/Client/View/Pixi/Layers/Debug"
],
function (Parent, Settings, DomController, Box2D, Nc) {
function (Parent, Settings, domController, Box2D, nc, DebugDraw, debugLayer) {
"use strict";
function Engine () {
Parent.call(this);
this.debugMode = false;
Nc.on(Nc.ns.client.view.debugMode.toggle, this.onToggleDebugMode, this);
nc.on(nc.ns.client.view.debugMode.toggle, this.onToggleDebugMode, this);
}
Engine.prototype = Object.create(Parent.prototype);
@ -21,19 +25,19 @@ function (Parent, Settings, DomController, Box2D, Nc) {
Engine.prototype.onToggleDebugMode = function(debugMode) {
this.debugMode = debugMode;
if(this.debugMode && !this.debugDraw) {
if(!this.debugDraw) {
this.setupDebugDraw();
}
debugLayer.container.visible = this.debugMode;
};
Engine.prototype.setupDebugDraw = function () {
var debugSprite = DomController.getDebugCanvas().getContext("2d");
// set debug draw
this.debugDraw = new Box2D.Dynamics.b2DebugDraw();
this.debugDraw = new DebugDraw();
this.debugDraw.SetSprite(debugSprite);
this.debugDraw.SetSprite(debugLayer.graphics);
this.debugDraw.SetDrawScale(Settings.RATIO);
this.debugDraw.SetFillAlpha(0.5);
this.debugDraw.SetLineThickness(1.0);
@ -49,7 +53,7 @@ function (Parent, Settings, DomController, Box2D, Nc) {
);
this.world.SetDebugDraw(this.debugDraw);
}
};
Engine.prototype.update = function () {
Parent.prototype.update.call(this);
@ -57,7 +61,7 @@ function (Parent, Settings, DomController, Box2D, Nc) {
if(this.debugMode) {
this.world.DrawDebugData();
}
}
};
return Engine;
})
});

View file

@ -4,15 +4,21 @@ define([
"Game/Config/Settings"
],
function (Parent, Nc, Settings) {
function (Parent, nc, Settings) {
"use strict";
function Player(id, physicsEngine, user) {
function Player(id, physicsEngine, user, isMe) {
Parent.call(this, id, physicsEngine, user);
this.playerInfoView = null;
this.playerInfoViewVisibleTimeout = null;
this.playerInfoViewVisible = false;
this.healthBarView = null;
this.healthBarViewVisibleTimeout = null;
this.healthBarViewVisible = false;
this.initHealthBar();
this.ncTokens = (this.ncTokens || []).concat([
nc.on(nc.ns.client.game.events.render, this.render, this)
]);
}
Player.prototype = Object.create(Parent.prototype);
@ -29,36 +35,36 @@ function (Parent, Nc, Settings) {
Player.prototype.initHealthBar = function() {
var self = this;
this.playerInfoViewVisible = false;
this.healthBarViewVisible = false;
var options = {
x: 100,
y: 100,
healthFactor: this.stats.health / 100,
visible: this.playerInfoViewVisible
visible: this.healthBarViewVisible
};
var callback = function(playerInfoView) {
self.playerInfoView = playerInfoView;
var callback = function(healthBarView) {
self.healthBarView = healthBarView;
}
Nc.trigger(Nc.ns.client.view.playerInfo.createAndAdd, callback, options);
nc.trigger(nc.ns.client.view.healthBar.createAndAdd, callback, options);
};
Player.prototype.onHealthChange = function() {
if(this.stats.health != 100) {
this.setPlayerInfoVisible(true);
this.setHealthBarVisible(true);
}
};
Player.prototype.spawn = function(x, y) {
Parent.prototype.spawn.call(this, x, y);
this.setPlayerInfoVisible(false);
this.setHealthBarVisible(false);
};
Player.prototype.setPlayerInfoVisible = function(visible) {
Player.prototype.setHealthBarVisible = function(visible) {
var self = this;
this.playerInfoViewVisible = visible;
if(this.playerInfoViewVisibleTimeout) clearTimeout(this.playerInfoViewVisibleTimeout);
this.healthBarViewVisible = visible;
if(this.healthBarViewVisibleTimeout) clearTimeout(this.healthBarViewVisibleTimeout);
if(visible) {
var position = this.getPosition();
@ -67,44 +73,45 @@ function (Parent, Nc, Settings) {
x: position.x * Settings.RATIO,
y: position.y * Settings.RATIO,
healthFactor: this.stats.health / 100,
visible: this.playerInfoViewVisible
visible: this.healthBarViewVisible
};
Nc.trigger(Nc.ns.client.view.playerInfo.update, this.playerInfoView, options);
nc.trigger(nc.ns.client.view.healthBar.update, this.healthBarView, options);
this.playerInfoViewVisibleTimeout = setTimeout(function() {
self.playerInfoViewVisible = false;
Nc.trigger(Nc.ns.client.view.playerInfo.update, self.playerInfoView, {visible: self.playerInfoViewVisible});
this.healthBarViewVisibleTimeout = setTimeout(function() {
self.healthBarViewVisible = false;
nc.trigger(nc.ns.client.view.healthBar.update, self.healthBarView, {visible: self.healthBarViewVisible});
}, Settings.HEALTH_DISPLAY_TIME * 1000);
} else {
Nc.trigger(Nc.ns.client.view.playerInfo.update, this.playerInfoView, {visible: this.playerInfoViewVisible});
nc.trigger(nc.ns.client.view.healthBar.update, this.healthBarView, {visible: this.healthBarViewVisible});
}
};
Player.prototype.getNickname = function() {
return this.user.options.nickname;
};
Player.prototype.render = function() {
if(this.doll) {
this.doll.render();
}
if(this.playerInfoViewVisible) {
if(this.healthBarViewVisible) {
var position = this.getPosition();
var options = {
healthFactor: this.stats.health / 100,
x: position.x * Settings.RATIO,
y: position.y * Settings.RATIO,
}
Nc.trigger(Nc.ns.client.view.playerInfo.update, this.playerInfoView, options);
nc.trigger(nc.ns.client.view.healthBar.update, this.healthBarView, options);
}
};
Player.prototype.isHoldingSomething = function() {
return !!this.holdingItem;
};
Player.prototype.destroy = function() {
clearTimeout(this.playerInfoViewVisibleTimeout);
Nc.trigger(Nc.ns.client.view.playerInfo.remove, this.playerInfoView);
clearTimeout(this.healthBarViewVisibleTimeout);
nc.trigger(nc.ns.client.view.healthBar.remove, this.healthBarView);
nc.off(this.ncTokens);
Parent.prototype.destroy.call(this);
};

View file

@ -0,0 +1,53 @@
define([
"Lib/Utilities/QuerySelector",
"Lib/Utilities/NotificationCenter"
],
function (qs, nc) {
"use strict";
function PointerLockManager() {
this.canvas = qs.$("#canvas");
this.listeners = [];
if (!document) {
throw new Error("Using PointerLockManager, but window.document is not defined.");
}
document.addEventListener('pointerlockchange', this.update.bind(this), false);
document.addEventListener('mozpointerlockchange', this.update.bind(this), false);
document.addEventListener('webkitpointerlockchange', this.update.bind(this), false);
this.ncTokens = [
nc.on(nc.ns.client.pointerLock.request, this.request, this)
];
}
PointerLockManager.prototype.request = function() {
var canvas = this.canvas;
canvas.requestPointerLock = canvas.requestPointerLock ||
canvas.mozRequestPointerLock ||
canvas.webkitRequestPointerLock;
// Ask the browser to lock the pointer
canvas.requestPointerLock();
}
// called by the browser event and others
PointerLockManager.prototype.update = function(e, options) {
options = options ? options : {};
nc.trigger(nc.ns.client.pointerLock.change, this.isLocked(), options);
};
PointerLockManager.prototype.isLocked = function() {
return document.pointerLockElement === this.canvas ||
document.mozPointerLockElement === this.canvas ||
document.webkitPointerLockElement === this.canvas;
};
return new PointerLockManager();
});

View file

@ -0,0 +1,67 @@
define([
"Lib/Utilities/Abstract",
"Lib/Utilities/NotificationCenter"
],
function (Abstract, nc) {
"use strict";
function Layer(name, options) {
this.name = name;
this.parallaxSpeed = options.parallaxSpeed || 0;
this.zoom = {
current: window.innerWidth / 600,
target: window.innerWidth / 600
};
this.position = {
current: { x: 0, y: 0},
target: { x: 0, y: 0}
};
if(options.levelSize) {
this.position.current.x = -options.levelSize.width / 2;
this.position.current.y = -options.levelSize.height / 2;
}
this.ncTokens = [];
}
Object.defineProperty(Layer, 'ID', {
value: {
TILE: 'tile',
ITEM: 'item',
SPAWN: 'spawnpoints'
}
});
Abstract.prototype.addMethod.call(Layer, 'show');
Abstract.prototype.addMethod.call(Layer, 'hide');
Abstract.prototype.addMethod.call(Layer, 'createMesh', ['texturePath', 'callback', 'options']);
Abstract.prototype.addMethod.call(Layer, 'createAnimatedMesh', ['texturePaths', 'callback', 'options']);
Abstract.prototype.addMethod.call(Layer, 'addMesh', ['mesh']);
Abstract.prototype.addMethod.call(Layer, 'removeMesh', ['mesh']);
Abstract.prototype.addMethod.call(Layer, 'updateMesh', ['mesh', 'options']);
Abstract.prototype.addMethod.call(Layer, 'render', ['centerPosition']);
Layer.prototype.getName = function() {
return this.name;
};
Layer.prototype.setPosition = function(centerPosition) {
this.position.target.x = centerPosition.x;
this.position.target.y = centerPosition.y;
};
Layer.prototype.setZoom = function(z) {
this.zoom.target = z;
};
Layer.prototype.destroy = function() {
for (var i = 0; i < this.ncTokens.length; i++) {
nc.off(this.ncTokens[i]);
};
};
return Layer;
});

View file

@ -0,0 +1,106 @@
define([
"Lib/Utilities/Abstract",
"Game/Client/View/DomController",
"Game/Config/Settings",
"Lib/Utilities/Exception",
"Lib/Utilities/NotificationCenter"
],
function (Abstract, domController, Settings, Exception, nc) {
"use strict";
function AbstractView () {
this.me = null;
this.canvas = null;
this.debugMode = false;
this.ncTokens = [
nc.on(nc.ns.client.view.display.change, this.onDisplaySizeChange, this),
nc.on(nc.ns.client.view.debugMode.toggle, this.onToggleDebugMode, this),
nc.on(nc.ns.client.game.zoomIn, this.onZoomIn, this),
nc.on(nc.ns.client.game.zoomOut, this.onZoomOut, this),
nc.on(nc.ns.client.game.zoomReset, this.onZoomReset, this),
nc.on(nc.ns.client.view.preloadBar.update, this.onUpdateLoader, this),
];
}
Abstract.prototype.addMethod.call(AbstractView, 'render');
Abstract.prototype.addMethod.call(AbstractView, 'addFilter', ['mesh', 'options']);
Abstract.prototype.addMethod.call(AbstractView, 'removeFilter', ['mesh', 'options']);
Abstract.prototype.addMethod.call(AbstractView, 'setCameraPosition', ['x', 'y']);
Abstract.prototype.addMethod.call(AbstractView, 'onZoomIn');
Abstract.prototype.addMethod.call(AbstractView, 'onZoomOut');
Abstract.prototype.addMethod.call(AbstractView, 'onZoomReset');
Abstract.prototype.addMethod.call(AbstractView, 'toggleInfo', ['show', 'string']);
Abstract.prototype.addMethod.call(AbstractView, 'onUpdateLoader', ['progress']);
AbstractView.prototype.isWebGlEnabled = function () {
try {
return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'experimental-webgl' );
} catch(e) {
return false;
}
}
AbstractView.prototype.initCanvas = function (canvas) {
this.canvas = canvas;
domController.initCanvas(canvas);
}
AbstractView.prototype.setMe = function(player) {
this.me = player;
};
/*
AbstractView.prototype.calculateCameraPosition = function() {
var reference = this.me.getPosition();
var pos = {};
pos.x = reference.x;
pos.y = reference.y;
pos.x = pos.x * Settings.RATIO;
pos.y = -(pos.y * Settings.RATIO);
pos.x += this.me.playerController.xyInput.x * Settings.STAGE_WIDTH / 4;
pos.y += this.me.playerController.xyInput.y * Settings.STAGE_HEIGHT / 4;
return pos;
};
*/
AbstractView.prototype.onDisplaySizeChange = function(isFullScreen) {
/*
if (!isFullScreen) {
Settings.STAGE_WIDTH = 600;
Settings.STAGE_HEIGHT = 400;
} else {
// FIXME: Create FIXME meme (dumb and dumber)
// FIXME: don't overwrite Settings
Settings.STAGE_WIDTH = window.innerWidth;
Settings.STAGE_HEIGHT = window.innerHeight;
}
*/
Settings.STAGE_WIDTH = window.innerWidth;
Settings.STAGE_HEIGHT = window.innerHeight;
};
AbstractView.prototype.onToggleDebugMode = function(debugMode) {
if(debugMode) {
//this.setCameraPosition(-Settings.STAGE_WIDTH / 2, -Settings.STAGE_HEIGHT / 2);
}
this.debugMode = debugMode;
};
AbstractView.prototype.destroy = function() {
for (var i = 0; i < this.ncTokens.length; i++) {
nc.off(this.ncTokens[i]);
};
};
return AbstractView;
});

View file

@ -1,91 +1,168 @@
define([
'Game/Config/Settings',
'Lib/Utilities/NotificationCenter',
"Lib/Vendor/Stats",
"Lib/Vendor/Screenfull"
"Game/Config/Settings",
"Lib/Utilities/NotificationCenter",
"Lib/Vendor/Screenfull",
"Game/Client/View/Graph",
"Game/Client/PointerLockManager"
],
function (Settings, Nc, Stats, Screenfull) {
function (Settings, nc, Screenfull, Graph, pointerLockManager) {
"use strict";
function DomController() {
this.canvas = document.getElementById("canvas");
this.debugCanvas = null;
this.canvas = null;
this.stats = null;
this.ping = null;
this.nickContainer = null;
this.fpsContainer = null;
this.devToolsContainer = null;
this.frames = 0;
Nc.on(Nc.ns.client.view.events.ready, this.initDevTools, this);
this.canvas = document.getElementById("canvas");
this.initDevTools();
}
DomController.prototype.initDevTools = function() {
var self = this;
var li, button, label;
// create dev tools container
this.devToolsContainer = document.createElement("div");
this.devToolsContainer.id = "devtools";
document.body.appendChild(this.devToolsContainer);
this.devToolsContainer = document.getElementById("menuBar");
// create Fullscreen
var p = document.createElement("p");
var button = document.createElement("button");
button.innerHTML = "Fullscreen";
// create back to menu button
li = document.createElement("li");
li.id = "back-to-menu";
button = document.createElement("button");
button.innerHTML = "Menu";
button.onclick = function() {
if(Screenfull.enabled) {
Screenfull.request(self.canvas);
}
}
p.appendChild(button);
this.devToolsContainer.appendChild(p);
window.location.href="/";
};
li.appendChild(button);
this.devToolsContainer.appendChild(li);
window.onresize = function() {
if(Screenfull.enabled) {
Nc.trigger(Nc.ns.client.view.fullscreen.change, Screenfull.isFullscreen);
// create user name
li = document.createElement("li");
label = document.createElement("label");
label.appendChild(document.createTextNode("?"));
li.appendChild(label);
this.devToolsContainer.appendChild(li);
this.nickContainer = label;
// create fps label with updater
li = document.createElement("li");
label = document.createElement("label");
label.id = "label-fps";
li.appendChild(label);
this.devToolsContainer.appendChild(li);
this.fpsContainer = label;
/*
// create new fps meter
li = document.createElement("li");
var fpsCanvas = document.createElement("canvas");
fpsCanvas.id = "graph-fps";
fpsCanvas.width = "100";
fpsCanvas.height = "27";
li.appendChild(fpsCanvas);
this.devToolsContainer.appendChild(li);
this.fpsGraph = new Graph(fpsCanvas.getContext("2d"), true);
this.fpsGraph.onUpdate(function(value){
self.fpsContainer.innerHTML = "FPS:" + value;
var color,
alpha = 0.8;
if (value >= 50) {
color = "rgba(136, 209, 018, " + alpha + ")";
} else if (value > 25) {
color = "rgba(204, 114, 018, " + alpha + ")";
} else {
color = "rgba(224, 018, 018, " + 1 + ")";
}
}
return color;
});
// create new ping meter
li = document.createElement("li");
var pingCanvas = document.createElement("canvas");
pingCanvas.id = "graph-fps";
pingCanvas.width = "100";
pingCanvas.height = "27";
li.appendChild(pingCanvas);
this.devToolsContainer.appendChild(li);
this.pingGraph = new Graph(pingCanvas.getContext("2d"), false, {
scaleOverride: false,
scaleStartValue: 0,
scaleStepWidth: 0,
scaleSteps: 0
});
*/
setInterval(function() {
self.fpsContainer.innerHTML = "FPS:" + self.frames;
self.frames = 0;
}, 1000);
// create Ping: container
this.ping = document.createElement("span");
this.devToolsContainer.appendChild(this.ping);
li = document.createElement("li");
this.ping = document.createElement("label");
li.appendChild(this.ping);
this.devToolsContainer.appendChild(li);
// create FPS stats
this.stats = new Stats();
this.stats.setMode(0);
this.devToolsContainer.appendChild(this.stats.domElement);
// create debug mode
var label = document.createElement("label");
li = document.createElement("li");
label = document.createElement("label");
var checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.onclick = function(e) {
Nc.trigger(Nc.ns.client.view.debugMode.toggle, e.target.checked);
self.getDebugCanvas().style.display = e.target.checked ? "" : "none";
}
nc.trigger(nc.ns.client.view.debugMode.toggle, e.target.checked);
};
label.appendChild(checkbox);
label.appendChild(document.createTextNode("Debug"));
this.devToolsContainer.appendChild(label);
li.appendChild(label);
this.devToolsContainer.appendChild(li);
// create health
this.health = document.createElement("span");
this.health.innerHTML = "Health: 100";
p = document.createElement("p");
p.appendChild(this.health);
this.devToolsContainer.appendChild(p);
// create Fullscreen
li = document.createElement("li");
li.id = "fullscreen";
button = document.createElement("button");
button.innerHTML = "Fullscreen";
button.onclick = function() {
if(Screenfull.enabled) {
pointerLockManager.request();
Screenfull.request(self.canvas);
}
};
li.appendChild(button);
this.devToolsContainer.appendChild(li);
// FIXME : isn't this a weird place for this?
window.onresize = function() {
nc.trigger(nc.ns.client.view.display.change);
};
};
DomController.prototype.statsBegin = function() {
if(this.stats) {
this.stats.begin();
}
DomController.prototype.setNick = function (nick) {
this.nickContainer.innerHTML = nick;
};
DomController.prototype.statsEnd = function() {
if(this.stats) {
this.stats.end();
}
DomController.prototype.fpsStep = function() {
this.frames++;
// this.fpsGraph.step();
};
DomController.prototype.setPing = function(ping) {
this.ping.innerHTML = "Ping: " + ping;
this.ping.innerHTML = "Ping:" + ping;
// this.pingGraph.addValue(ping);
};
DomController.prototype.getCanvasContainer = function () {
@ -96,31 +173,32 @@ function (Settings, Nc, Stats, Screenfull) {
} else {
throw 'Canvas Container missing: #' + Settings.CANVAS_DOM_ID;
}
}
};
DomController.prototype.getCanvas = function () {
return this.canvas;
}
};
DomController.prototype.initCanvas = function (canvas) {
Nc.trigger(Nc.ns.client.view.fullscreen.change, Screenfull.isFullscreen);
}
nc.trigger(nc.ns.client.view.display.change, Screenfull.isFullscreen);
};
DomController.prototype.getDebugCanvas = function () {
if(!this.debugCanvas) {
var canvas = document.createElement('canvas');
canvas.width = Settings.STAGE_WIDTH;
canvas.height = Settings.STAGE_HEIGHT;
this.debugCanvas = canvas;
this.getCanvasContainer().appendChild(canvas);
DomController.prototype.setConnected = function(connected) {
if(connected) {
document.body.style.backgroundColor = '';
} else {
document.body.style.backgroundColor = '#aaaaaa';
this.ping.innerHTML = "Disconnected. ".replace(/ /g, '&nbsp;');
this.ping.style.color = "#ff0000";
/*
self = this;
setTimeout(function(){self.ping.innerHTML = "Reload Page...".replace(/ /g, '&nbsp;');}, 3000);
setTimeout(function(){self.ping.innerHTML = "Reload in 3...".replace(/ /g, '&nbsp;');}, 6000);
setTimeout(function(){self.ping.innerHTML = "Reload in 2...".replace(/ /g, '&nbsp;');}, 7000);
setTimeout(function(){self.ping.innerHTML = "Reload in 1...".replace(/ /g, '&nbsp;');}, 8000);
setTimeout(function(){self.ping.innerHTML = "Reload now. ".replace(/ /g, '&nbsp;'); location.reload(); }, 9000);
*/
}
return this.debugCanvas;
}
DomController.prototype.setHealth = function(health) {
this.health.innerHTML = "Health: " + parseInt(health, 10);
};

View file

@ -0,0 +1,99 @@
define([
"Lib/Vendor/Chart"
],
function (Chart) {
"use strict";
function Graph(ctx, isStepCounter, newOptions) {
var numberOfGraphBars = 25;
var empty = new Array(numberOfGraphBars);
for (var i = empty.length - 1; i >= 0; i--) empty[i] = -1;
var data = {
labels: empty,
datasets: [
{
label: "no label",
fillColor: "rgba(220,220,220,1)",
strokeColor: "rgba(220,220,220,1)",
highlightFill: "rgba(220,220,220,1)",
data: empty
},
]};
var options = {
showScale: false,
scaleShowLabels: false,
showTooltips: false,
animation: false,
scaleBeginAtZero : true,
scaleShowGridLines : false,
scaleShowHorizontalLines: true,
scaleShowVerticalLines: true,
barShowStroke : false,
barStrokeWidth : 0,
barValueSpacing : 0,
barDatasetSpacing : 0,
responsive: false,
scaleBackdropPaddingY : 10,
scaleOverride: true,
scaleStartValue: 0,
scaleStepWidth: 1,
scaleSteps: 60
}
if (newOptions) {
if (newOptions.scaleOverride) options.scaleOverride = newOptions.scaleOverride;
if (newOptions.scaleStartValue) options.scaleStartValue = newOptions.scaleStartValue;
if (newOptions.scaleSteps) options.scaleSteps = newOptions.scaleSteps;
if (newOptions.scaleStepWidth) options.scaleStepWidth = newOptions.scaleStepWidth;
}
this.chart = new Chart(ctx).Bar(data, options);
this.stepCounter = 0;
this.currentValue = 0;
this.updateFunction = function(value){};
var self = this;
if (isStepCounter) {
setInterval(function(){
self.addValue(null);
}, 1000);
}
}
Graph.prototype.addValue = function (value) {
value = value ? value : this.stepCounter;
this.chart.addData( [value], "" );
this.currentValue = value;
this.stepCounter = 0;
var color = this.updateFunction(this.currentValue);
color = color ? color : "rgba(136, 209, 018, 1)"; // green
this.chart.datasets[0].bars[this.chart.datasets[0].bars.length-1].fillColor = color;
this.chart.removeData();
this.chart.update();
}
Graph.prototype.step = function() {
this.stepCounter++;
};
Graph.prototype.getCurrentValue = function() {
return this.currentValue;
};
Graph.prototype.onUpdate = function(f) {
this.updateFunction = f;
};
return Graph;
});

View file

@ -0,0 +1,183 @@
define([
"Lib/Utilities/NotificationCenter",
"Lib/Utilities/Exception",
"Game/Client/View/Pixi/Layer"
],
function (nc, Exception, Layer) {
"use strict";
function LayerManager(container, me) {
this.layers = [];
this.container = container;
this.ncTokens = [
nc.on(nc.ns.client.view.layer.createAndInsert, this.createAndInsert, this),
nc.on(nc.ns.client.view.mesh.create, this.createMesh, this),
nc.on(nc.ns.client.view.animatedMesh.create, this.createAnimatedMesh, this),
nc.on(nc.ns.client.view.mesh.add, this.addMesh, this),
nc.on(nc.ns.client.view.mesh.remove, this.removeMesh, this),
nc.on(nc.ns.client.view.mesh.update, this.updateMesh, this),
nc.on(nc.ns.client.view.mesh.addFilter, this.addFilter, this),
nc.on(nc.ns.client.view.mesh.removeFilter, this.removeFilter, this),
nc.on(nc.ns.client.view.mesh.swapMeshIndexes, this.swapMeshIndexes, this),
nc.on(nc.ns.client.view.mesh.swapMeshes, this.swapMeshes, this)
];
}
LayerManager.prototype.render = function(centerPosition, zoom) {
for (var i = 0; i < this.layers.length; i++) {
var layer = this.layers[i];
layer.render(centerPosition, zoom);
}
};
/*
* If no referenceId is given, the layer is inserted in the far background (behind=true)
* or in the foreground (behind=false/null)
*/
LayerManager.prototype.createAndInsert = function(id, options, behind, referenceId) {
var layer = new Layer(id, options);
this.insert(layer, behind, referenceId);
};
LayerManager.prototype.insert = function(newlayer, behind, referenceId) {
var referenceIndex = -1;
behind = !!behind;
if (referenceId) {
for(var i = 0; i < this.layers.length; i++) {
var layer = this.layers[i];
if (layer.getName() === referenceId) {
referenceIndex = i;
break;
}
}
if (referenceIndex === -1) {
throw new Exception('Reference Layer (' + referenceId + ') could not be found');
}
} else {
referenceIndex = behind ? 0 : this.container.children.length;
}
var layerIndex = behind ? referenceIndex : referenceIndex + 1;
this.layers.splice(layerIndex, 0, newlayer);
this.rearrangeLayers();
};
LayerManager.prototype.rearrangeLayers = function() {
var layer;
for (var i = this.layers.length - 1; i >= 0; i--) {
layer = this.layers[i];
if (this.container.children.indexOf(layer.getContainer()) !== -1) {
this.container.removeChild(layer.getContainer());
}
};
if (this.container.children.length !== 0) {
console.warn('Unmanaged stuff in container... ', this.container.children);
//throw new Exception('Unmanaged dirt in container... ');
}
for (var i = 0; i < this.layers.length; i++) {
layer = this.layers[i];
this.container.addChildAt(layer.getContainer(), i);
};
};
LayerManager.prototype.getLayerById = function(id) {
for (var i = 0; i < this.layers.length; i++) {
var layer = this.layers[i];
if (layer.getName() === id) {
return layer;
}
};
return null;
};
/* Delegate methods */
LayerManager.prototype.delegate = function() {
var methodName = arguments[0];
var layerId = arguments[1];
var layer = this.getLayerById(layerId);
if (!layer) {
throw new Exception('Layer (' + layerId + ') does not exist.');
}
var args = arguments;
Array.prototype.splice.call(args, 0, 2);
layer[methodName].apply(layer, args);
};
LayerManager.prototype.createMesh = function() {
var args = arguments;
Array.prototype.splice.call(args, 0, 0, 'createMesh')
this.delegate.apply(this, args);
};
LayerManager.prototype.createAnimatedMesh = function() {
Array.prototype.splice.call(arguments, 0, 0, 'createAnimatedMesh')
this.delegate.apply(this, arguments);
};
LayerManager.prototype.addMesh = function() {
Array.prototype.splice.call(arguments, 0, 0, 'addMesh')
this.delegate.apply(this, arguments);
};
LayerManager.prototype.removeMesh = function() {
Array.prototype.splice.call(arguments, 0, 0, 'removeMesh')
this.delegate.apply(this, arguments);
};
LayerManager.prototype.updateMesh = function() {
Array.prototype.splice.call(arguments, 0, 0, 'updateMesh')
this.delegate.apply(this, arguments);
};
LayerManager.prototype.addFilter = function() {
Array.prototype.splice.call(arguments, 0, 0, 'addFilter')
this.delegate.apply(this, arguments);
};
LayerManager.prototype.removeFilter = function() {
Array.prototype.splice.call(arguments, 0, 0, 'removeFilter')
this.delegate.apply(this, arguments);
};
LayerManager.prototype.swapMeshIndexes = function() {
Array.prototype.splice.call(arguments, 0, 0, 'swapMeshIndexes')
this.delegate.apply(this, arguments);
};
LayerManager.prototype.swapMeshes = function() {
Array.prototype.splice.call(arguments, 0, 0, 'swapMeshes')
this.delegate.apply(this, arguments);
};
LayerManager.prototype.destroy = function() {
for (var i = 0; i < this.ncTokens.length; i++) {
nc.off(this.ncTokens[i]);
};
for (var i = this.layers.length - 1; i >= 0; i--) {
var layer = this.layers[i];
layer.destroy();
};
};
return LayerManager;
});

View file

@ -0,0 +1,22 @@
define([
'Game/Config/Settings',
'Lib/Utilities/NotificationCenter',
"Lib/Vendor/Stats",
"Lib/Vendor/Screenfull"
],
function (Settings, nc, Stats, Screenfull) {
"use strict";
function Mesh() {
}
Mesh.prototype.render = function() {
};
return Mesh;
});

View file

@ -0,0 +1,91 @@
define([
"Lib/Vendor/Pixi"
],
function (PIXI) {
"use strict";
var Parent = PIXI.AbstractFilter;
function ColorRangeReplaceFilter() {
Parent.call(this);
this.passes = [this];
// set the uniforms
this.uniforms = {
minColor: {type: '3fv', value: [0,0,0]},
maxColor: {type: '3fv', value: [0,0,0]},
newColor: {type: '3fv', value: [0,0,0]},
brightnessOffset: {type: '1f', value: 0}
};
this.fragmentSrc = [
'precision mediump float;',
'varying vec2 vTextureCoord;',
'varying vec4 vColor;',
'uniform sampler2D uSampler;',
'uniform vec3 minColor;',
'uniform vec3 maxColor;',
'uniform vec3 newColor;',
'uniform float brightnessOffset;',
'void main(void) {',
' vec4 pixel = texture2D(uSampler, vTextureCoord);',
' if(pixel.x >= minColor.x && pixel.y >= minColor.y && pixel.z >= minColor.z',
' && pixel.w == 1.0',
' && pixel.x <= maxColor.x && pixel.y <= maxColor.y && pixel.z <= maxColor.z) {',
' pixel.rgb = mix(pixel.rgb, vec3(0.2126*pixel.r + 0.7152*pixel.g + 0.0722*pixel.b), 1.0);', // desaturate to gray
' pixel.rgb += brightnessOffset;',
' pixel.rgb *= newColor;',
' }',
' gl_FragColor = pixel;',
'}'
];
}
ColorRangeReplaceFilter.prototype = Object.create(Parent.prototype);
ColorRangeReplaceFilter.prototype.constructor = ColorRangeReplaceFilter;
Object.defineProperty(ColorRangeReplaceFilter.prototype, 'minColor', {
get: function() {
return PIXI.rgb2hex(this.uniforms.minColor.value);
},
set: function(value) {
this.uniforms.minColor.value = PIXI.hex2rgb(value);
}
});
Object.defineProperty(ColorRangeReplaceFilter.prototype, 'maxColor', {
get: function() {
return PIXI.rgb2hex(this.uniforms.maxColor.value);
},
set: function(value) {
this.uniforms.maxColor.value = PIXI.hex2rgb(value);
}
});
Object.defineProperty(ColorRangeReplaceFilter.prototype, 'newColor', {
get: function() {
return PIXI.rgb2hex(this.uniforms.newColor.value);
},
set: function(value) {
this.uniforms.newColor.value = PIXI.hex2rgb(value);
}
});
Object.defineProperty(ColorRangeReplaceFilter.prototype, 'brightnessOffset', {
get: function() {
return this.uniforms.brightnessOffset.value;
},
set: function(value) {
this.uniforms.brightnessOffset.value = value;
}
});
return ColorRangeReplaceFilter;
});

View file

@ -0,0 +1,179 @@
define([
"Lib/Vendor/Box2D"
],
function (Box2D) {
"use strict";
var Parent = Box2D.Dynamics.b2DebugDraw;
function DebugDraw() {
Parent.call(this);
this.m_drawScale = 1;
}
DebugDraw.prototype = Object.create(Parent.prototype);
DebugDraw.prototype.setColor = function(color) {
this.m_ctx.debugColor = color.color;
this.m_ctx.debugFillAlpha = this.m_fillAlpha;
this.m_ctx.lineStyle(1, this.m_ctx.debugColor, this.m_alpha);
};
DebugDraw.prototype.SetSprite = function(sprite) {
this.m_ctx = sprite;
this.m_sprite = {
graphics: {
clear: function () {
sprite.clear();
sprite.lineStyle(1, 0xffffff, 0.8);
}
}
};
this.m_ctx.beginPath = function() {
this.beginFill(this.debugColor, this.debugFillAlpha);
};
this.m_ctx.closePath = function() {
this.endFill();
};
this.m_ctx.fill = function() {
this.endFill();
};
this.m_ctx.stroke = function() {
// do nothing
};
this.m_ctx.arc = function(x, y, radius, startingAngle, endingAngle, counterClockwise) {
this.drawCircle(x, y, radius);
}
};
DebugDraw.prototype.DrawPolygon = function (vertices, vertexCount, color) {
this.setColor(color);
Parent.prototype.DrawPolygon.call(this, arguments);
};
DebugDraw.prototype.DrawSolidPolygon = function (vertices, vertexCount, color) {
this.setColor(color);
Parent.prototype.DrawSolidPolygon.apply(this, arguments);
};
DebugDraw.prototype.DrawCircle = function (center, radius, color) {
this.setColor(color);
Parent.prototype.DrawCircle.apply(this, arguments);
};
DebugDraw.prototype.DrawSolidCircle = function (center, radius, axis, color) {
this.setColor(color);
Parent.prototype.DrawSolidCircle.apply(this, arguments);
};
DebugDraw.prototype.DrawSegment = function (p1, p2, color) {
this.setColor(color);
Parent.prototype.DrawSegment.apply(this, arguments);
};
DebugDraw.prototype.DrawTransform = function (xf) {
this.setColor(0xff0000);
Parent.prototype.DrawTransform.apply(this, arguments);
};
/*
DebugDraw.prototype.DrawPolygon = function (vertices, vertexCount, color) {
if (!vertexCount) return;
var s = this.m_ctx;
var drawScale = this.m_drawScale;
s.beginPath();
s.strokeStyle = this._color(color.color, this.m_alpha);
s.moveTo(vertices[0].x * drawScale, vertices[0].y * drawScale);
for (var i = 1; i < vertexCount; i++) {
s.lineTo(vertices[i].x * drawScale, vertices[i].y * drawScale);
}
s.lineTo(vertices[0].x * drawScale, vertices[0].y * drawScale);
s.closePath();
s.stroke();
};
DebugDraw.prototype.DrawSolidPolygon = function (vertices, vertexCount, color) {
if (!vertexCount) return;
var s = this.m_ctx;
var drawScale = this.m_drawScale;
s.beginPath();
s.strokeStyle = this._color(color.color, this.m_alpha);
s.fillStyle = this._color(color.color, this.m_fillAlpha);
s.moveTo(vertices[0].x * drawScale, vertices[0].y * drawScale);
for (var i = 1; i < vertexCount; i++) {
s.lineTo(vertices[i].x * drawScale, vertices[i].y * drawScale);
}
s.lineTo(vertices[0].x * drawScale, vertices[0].y * drawScale);
s.closePath();
s.fill();
s.stroke();
};
DebugDraw.prototype.DrawCircle = function (center, radius, color) {
if (!radius) return;
var s = this.m_ctx;
var drawScale = this.m_drawScale;
s.beginPath();
s.strokeStyle = this._color(color.color, this.m_alpha);
s.arc(center.x * drawScale, center.y * drawScale, radius * drawScale, 0, Math.PI * 2, true);
s.closePath();
s.stroke();
};
DebugDraw.prototype.DrawSolidCircle = function (center, radius, axis, color) {
if (!radius) return;
var s = this.m_ctx,
drawScale = this.m_drawScale,
cx = center.x * drawScale,
cy = center.y * drawScale;
s.moveTo(0, 0);
s.beginPath();
s.strokeStyle = this._color(color.color, this.m_alpha);
s.fillStyle = this._color(color.color, this.m_fillAlpha);
s.arc(cx, cy, radius * drawScale, 0, Math.PI * 2, true);
s.moveTo(cx, cy);
s.lineTo((center.x + axis.x * radius) * drawScale, (center.y + axis.y * radius) * drawScale);
s.closePath();
s.fill();
s.stroke();
};
DebugDraw.prototype.DrawSegment = function (p1, p2, color) {
var s = this.m_ctx,
drawScale = this.m_drawScale;
s.strokeStyle = this._color(color.color, this.m_alpha);
s.beginPath();
s.moveTo(p1.x * drawScale, p1.y * drawScale);
s.lineTo(p2.x * drawScale, p2.y * drawScale);
s.closePath();
s.stroke();
};
DebugDraw.prototype.DrawTransform = function (xf) {
var s = this.m_ctx,
drawScale = this.m_drawScale;
s.beginPath();
s.strokeStyle = this._color(0xff0000, this.m_alpha);
s.moveTo(xf.position.x * drawScale, xf.position.y * drawScale);
s.lineTo((xf.position.x + this.m_xformScale * xf.R.col1.x) * drawScale, (xf.position.y + this.m_xformScale * xf.R.col1.y) * drawScale);
s.strokeStyle = this._color(0xff00, this.m_alpha);
s.moveTo(xf.position.x * drawScale, xf.position.y * drawScale);
s.lineTo((xf.position.x + this.m_xformScale * xf.R.col2.x) * drawScale, (xf.position.y + this.m_xformScale * xf.R.col2.y) * drawScale);
s.closePath();
s.stroke();
};
*/
return DebugDraw;
});

View file

@ -0,0 +1,206 @@
define([
"Lib/Vendor/Pixi",
"Lib/Utilities/NotificationCenter",
"Game/Config/Settings",
"Lib/Utilities/ColorConverter"
],
function (PIXI, nc, Settings, ColorConverter) {
"use strict";
function GameStats(view) {
this.style = {
borderWidth: 3,
padding: 20,
colors: {
background: 0x000000,
text: "red",
headline: "#880000",
border: 0xAA0000
},
line: {
height: 16,
spacing: 5
},
fontSize: 12
};
this.view = view;
this.container = new PIXI.DisplayObjectContainer();
var blurFilter = new PIXI.BlurFilter();
blurFilter.blurX = 12;
blurFilter.blurY = 12;
var grayFilter = new PIXI.GrayFilter();
grayFilter.gray = 0.85;
this.filters = [blurFilter, grayFilter];
this.background = new PIXI.Graphics();
this.background.alpha = 0.7;
this.container.addChild(this.background);
this.dialog = new PIXI.DisplayObjectContainer();
this.container.addChild(this.dialog);
this.graphics = new PIXI.Graphics();
/*
gameContainer
filters
container
background
dialog
graphics
playerColor
headline
line
*/
this.container.visible = false;
this.sortedPlayers = [];
this.ncTokens = [
nc.on(nc.ns.client.view.gameStats.toggle, this.toggle, this),
nc.on(nc.ns.client.view.gameStats.update, this.update, this)
];
}
GameStats.prototype.getInfoContainer = function() {
return this.container;
};
GameStats.prototype.toggle = function(show) {
if(show) {
this.redraw();
// show stats with filters
this.container.visible = true;
this.view.addFilters(this.filters);
this.filters.forEach(function(filter) { filter.dirty = true; });
} else {
this.container.visible = false;
this.view.removeFilters(this.filters);
}
}
GameStats.prototype.update = function(sortedPlayers) {
this.sortedPlayers = sortedPlayers;
this.redraw();
};
GameStats.prototype.redraw = function() {
this.background.clear();
this.graphics.clear();
this.dialog.removeChildren();
// redraw background
this.background.beginFill(this.style.colors.background);
this.background.drawRect(0, 0, Settings.STAGE_WIDTH, Settings.STAGE_HEIGHT);
this.background.endFill();
// redraw text and graphics
var string = "" +
" #".pad(7, true) + " " +
"Name".pad(12, true) +
"Score".pad(6, false) +
"Deaths".pad(7, false) +
"Health".pad(9, false) + " ";
var line = new PIXI.Text(string, {
font: "normal " + this.style.fontSize + "px 'Joystix'",
fill: this.style.colors.headline
});
line.position = new PIXI.Point(0, 0);
this.dialog.addChild(line);
this.drawPlayers(this.sortedPlayers);
var x = Settings.STAGE_WIDTH / 2 - this.dialog.getBounds().width / 2,
y = Settings.STAGE_HEIGHT / 2 - (this.sortedPlayers.length + 1) * (this.style.line.height + this.style.line.spacing) / 2;
this.dialog.position = new PIXI.Point(x, y);
this.dialog.addChild(this.graphics);
};
GameStats.prototype.drawPlayers = function(sortedPlayers) {
sortedPlayers.forEach(function(player, i) {
this.drawPlayer(player, i + 1);
this.drawPlayerGraphics(player, i + 1)
}, this);
};
GameStats.prototype.drawPlayer = function(player, i) {
var string = (i + ". ").pad(7, false) + " " +
player.getNickname().pad(12, true) +
("" + player.stats.score).pad(6, false) +
("" + player.stats.deaths).pad(7, false) +
("" /* + parseInt(player.stats.health, 10)*/).pad(9, false) + " ";
var line = new PIXI.Text(string, {
font: "normal " + this.style.fontSize + "px 'Joystix'",
fill: this.style.colors.text
});
line.position = new PIXI.Point(
0,
i * (this.style.line.height + this.style.line.spacing)
);
this.dialog.addChild(line);
};
GameStats.prototype.drawPlayerGraphics = function(player, i) {
var converter = new ColorConverter();
// draw shirt color
this.graphics.beginFill(converter.getColorByName(player.getNickname()));
this.graphics.drawRect(
50,
i * (this.style.line.height + this.style.line.spacing),
this.style.line.height,
this.style.line.height
);
// draw health bar
var height = this.style.line.height / 2,
width = height * 7,
borderWidth = 2,
offsetX = 360,
offsetY = (i * (this.style.line.height + this.style.line.spacing)) + ((this.style.line.height - height) / 2);
this.graphics.beginFill(0x000000);
this.graphics.drawRect(offsetX, offsetY, width, height);
this.graphics.endFill();
if(player.stats.health > 0) {
var color = player.stats.health / 100 < Settings.CRITICAL_HEALTH_THRESHOLD
? 0xFF0000
: 0x00FF00;
this.graphics.beginFill(color);
this.graphics.drawRect(
offsetX + borderWidth,
offsetY + borderWidth,
width * player.stats.health / 100 - 2 * borderWidth,
height - 2 * borderWidth
);
this.graphics.endFill();
}
};
GameStats.prototype.destroy = function() {
for (var i = 0; i < this.ncTokens.length; i++) {
nc.off(this.ncTokens[i]);
};
};
return GameStats;
});

View file

@ -0,0 +1,322 @@
define([
"Game/Client/View/Abstract/Layer",
"Lib/Vendor/Pixi",
"Game/Client/View/Pixi/ColorRangeReplaceFilter",
"Game/Config/Settings",
"Lib/Utilities/ColorConverter",
"Lib/Utilities/NotificationCenter"
],
function (Parent, PIXI, ColorRangeReplaceFilter, Settings, ColorConverter, nc) {
"use strict";
function Layer (name, options) {
Parent.call(this, name, options);
this.container = new PIXI.DisplayObjectContainer();
this.container.x = 0;
this.container.y = 0;
this.static = false;
this.levelSize = {
width: 0,
height: 0
}
this.ncTokens = this.ncTokens.concat([
nc.on(nc.ns.client.view.layer.levelSizeUpdate, this.onLevelSizeUpdate, this)
]);
if (Settings.SHOW_LAYER_INFO) {
var self = this;
var g = new PIXI.Graphics();
var converter = new ColorConverter();
var c = converter.getColorByName(name);
var fontSize = 12;
var textOptions = {
font: "normal " + fontSize + "px 'Joystix'",
fill: "#" + c.toString(16),
};
var t = new PIXI.Text(name, textOptions);
var y = 0;
switch (name) {
case "ghost": y++;
case "item": y++;
case "tile": y++;
case "spawn": y=y;
}
t.position = new PIXI.Point(0, fontSize * y);
g.lineStyle (1, c, 1);
g.drawRect (0, 0, 100 + y, 100 + y);
setTimeout(function(){
self.container.addChild(t);
self.container.addChild(g);
}, 500);
}
}
Layer.prototype = Object.create(Parent.prototype);
Layer.prototype.onLevelSizeUpdate = function(levelSize) {
this.levelSize = levelSize;
};
Layer.prototype.getAvailableMeshFilters = function() {
return {
"blur": PIXI.BlurFilter,
"desaturate": PIXI.GrayFilter,
"pixelate": PIXI.PixelateFilter,
"colorRangeReplace": ColorRangeReplaceFilter,
};
};
Layer.prototype.getContainer = function() {
return this.container;
};
Layer.prototype.show = function() {
this.container.visible = true;
};
Layer.prototype.hide = function() {
this.container.visible = false;
};
Layer.prototype.addMesh = function(mesh) {
this.container.addChild(mesh);
};
Layer.prototype.removeMesh = function(mesh) {
this.container.removeChild(mesh);
};
Layer.prototype.swapMeshIndexes = function(meshA, meshB) {
var indexA = this.container.getChildIndex(meshA);
var indexB = this.container.getChildIndex(meshB);
this.container.setChildIndex(meshA, indexB);
this.container.setChildIndex(meshB, indexA);
};
Layer.prototype.swapMeshes = function(meshA, meshB) {
var textureA = meshA.texture;
var textureB = meshB.texture;
meshA.setTexture(textureB);
meshA.onTextureUpdate();
meshA.scale.x = 1;
meshA.scale.y = 1;
meshB.setTexture(textureA);
meshB.onTextureUpdate();
meshB.scale.x = 1;
meshB.scale.y = 1;
};
Layer.prototype.createMesh = function (texturePath, callback, options) {
var texture = (options && options.fromFrame)
? PIXI.Texture.fromFrame(texturePath)
: PIXI.Texture.fromImage(texturePath);
var mesh = new PIXI.Sprite(texture);
if(options) this.updateMesh(mesh, options);
callback(mesh);
};
Layer.prototype.createAnimatedMesh = function (texturePaths, callback, options) {
var textures = [];
for (var i = 0; i < texturePaths.length; i++) {
var texture = (options && options.fromFrame)
? PIXI.Texture.fromFrame(texturePaths[i])
: PIXI.Texture.fromImage(texturePaths[i]);
texture.width = options.width;
texture.height = options.height;
//PIXI.texturesToUpdate.push(texture);
textures.push(texture);
}
var mesh = new PIXI.MovieClip(textures);
if(options) this.updateMesh(mesh, options);
mesh.animationSpeed = 0.5;
mesh.play();
callback(mesh);
}
Layer.prototype.updateMesh = function(mesh, options) {
if (options.x) mesh.position.x = options.x;
if (options.y) mesh.position.y = options.y;
if (options.rotation) mesh.rotation = options.rotation;
if (options.alpha) mesh.alpha = options.alpha;
if (options.width) mesh.width = options.width;
if (options.height) mesh.height = options.height;
if (options.xScale) mesh.width = Math.abs(mesh.width) * options.xScale;
if (options.yScale) mesh.scale.y = options.yScale;
if (options.visible === true || options.visible === false) mesh.visible = options.visible;
if (options.pivot) mesh.pivot = new PIXI.Point(options.pivot.x, options.pivot.y);
if (options.anchor) mesh.anchor = options.anchor;
if (options.animationSpeed) mesh.animationSpeed = options.animationSpeed;
};
Layer.prototype.addFilter = function(mesh, filterName, options) {
// use game container if mesh null
if(mesh === null) {
}
if (!this.getAvailableMeshFilters().hasOwnProperty(filterName)) {
throw new Exception('Filter ' + filterName + ' is not available');
}
var MeshFilter = this.getAvailableMeshFilters()[filterName];
var filter = new MeshFilter();
switch (filterName) {
case 'desaturate':
if (options.amount) filter.gray = options.amount;
break;
case 'blur':
if (options.blurX) filter.blurX = options.blurX;
if (options.blurY) filter.blurY = options.blurY;
break;
case 'colorRangeReplace':
if (options.minColor) filter.minColor = options.minColor;
if (options.maxColor) filter.maxColor = options.maxColor;
if (options.newColor) filter.newColor = options.newColor;
if (options.brightnessOffset) filter.brightnessOffset = options.brightnessOffset;
break;
case 'pixelate':
if (options.sizeX) filter.size.x = options.sizeX;
if (options.sizeY) filter.size.y = options.sizeY;
break;
default:
break;
}
var filters = mesh.filters;
if(!filters) {
filters = [];
} else {
// ensure uniqueness of filter by name
this.removeFilter(mesh, filterName);
}
filters.push(filter);
mesh.filters = filters;
};
Layer.prototype.removeFilter = function(mesh, filterName) {
var filters = mesh.filters;
if(!filters) {
return;
}
// FIXME this should throw an error i think since "options" is not defined here
// maybe we never actually call this method?
var MeshFilter = this.getAvailableMeshFilters()[options.filter];
filters = filters.filter(function(filter){
return !filter instanceof MeshFilter;
});
mesh.filters = filter;
};
Layer.prototype.render = function(centerPosition, zoom) {
this.setPosition(centerPosition);
this.setZoom(zoom);
// Zoom
var zoomStep = (this.zoom.target - this.zoom.current) * Settings.CAMERA_GLIDE / 100;
this.zoom.current += zoomStep;
this.container.scale.x = this.zoom.current;
this.container.scale.y = this.container.scale.x;
/*
// we would need another zoom state,
// to separate fixed zooming (by window size)
// and user zoom by +/-/0 keys
// this snippet would zoom the layers by its parallax
// so further away layers would not zoom as much.
var zoomParallax = this.parallaxSpeed == 0
? 1
: this.parallaxSpeed < 0
? (1 + this.parallaxSpeed)
: this.parallaxSpeed + 1000;
var newZoomTarget = 1 + Math.log(this.zoom.target+2) * (zoomParallax)
console.log(newZoomTarget)
this.container.scale.x = newZoomTarget;
this.container.scale.y = newZoomTarget;
// Later, this would need to be added as well:
this.container.x *= newZoomTarget;
this.container.y *= newZoomTarget;
*/
// Position
if (!this.static) {
var posXStep = (this.position.target.x - this.position.current.x) * Settings.CAMERA_GLIDE / 100;
this.position.current.x += posXStep;
var posYStep = (this.position.target.y - this.position.current.y) * Settings.CAMERA_GLIDE / 100;
this.position.current.y += posYStep;
// Add here to set 0,0 not in the center of the map but the level origin in the top left
// FIXME: use a different kind of flag than "name"
if (this.name == "spawn"
|| this.name == "tile"
|| this.name == "item"
|| this.name == "ghost"
|| this.name == "swiper"
|| this.parallaxSpeed == 0) {
this.container.x = this.position.current.x;
this.container.y = this.position.current.y;
} else {
var x = this.position.current.x + this.levelSize.width / 2;
this.container.x = x - x * -this.parallaxSpeed;
var y = this.position.current.y + this.levelSize.height / 2;
this.container.y = y - y * -this.parallaxSpeed;
}
this.container.x *= this.zoom.current;
this.container.y *= this.zoom.current;
this.container.x += Settings.STAGE_WIDTH / 2;
this.container.y += Settings.STAGE_HEIGHT / 2;
}
};
return Layer;
});

View file

@ -0,0 +1,20 @@
define([
"Game/Client/View/Pixi/Layer",
"Lib/Vendor/Pixi",
],
function (Parent, PIXI) {
"use strict";
function Debug() {
Parent.call(this, "debug", 0.00000001);
this.graphics = new PIXI.Graphics();
this.container.addChild(this.graphics);
}
Debug.prototype = Object.create(Parent.prototype);
return new Debug();
});

View file

@ -0,0 +1,119 @@
define([
"Game/Client/View/Pixi/Layer",
"Lib/Vendor/Pixi",
"Lib/Utilities/NotificationCenter",
"Game/Config/Settings"
],
function (Parent, PIXI, nc, Settings) {
"use strict";
function Ghost() {
Parent.call(this, "ghost", {parallaxSpeed: 0});
this.ncTokens = this.ncTokens.concat([
nc.on(nc.ns.client.view.layer.levelSizeUpdate, this.onLevelSizeUpdate, this),
nc.on(nc.ns.client.view.playerArrow.createAndAdd, this.onCreateAndAddPlayerArrow, this),
nc.on(nc.ns.client.view.playerArrow.update, this.onUpdatePlayerArrow, this),
nc.on(nc.ns.client.view.healthBar.createAndAdd, this.onCreateAndAddHealthBar, this),
nc.on(nc.ns.client.view.healthBar.update, this.onUpdateHealthBar, this),
nc.on(nc.ns.client.view.healthBar.remove, this.onRemoveHealthBar, this),
]);
}
Ghost.prototype = Object.create(Parent.prototype);
Ghost.prototype.onLevelSizeUpdate = function(levelSize) {
this.position.current.x = -levelSize.width / 2;
this.position.current.y = -levelSize.height / 2;
};
Ghost.prototype.onCreateAndAddPlayerArrow = function(callback, options) {
var arrow = new PIXI.Graphics();
arrow.visible = false;
this.container.addChild(arrow);
var width = 10,
height = 10;
arrow.beginFill(0xffffff, 0.4);
arrow.lineStyle(0, 0x000000);
arrow.moveTo(0, 0);
arrow.lineTo(width, 0);
arrow.lineTo(width / 2, height);
arrow.endFill();
arrow.pivot = new PIXI.Point(width/2, height/2);
arrow.visible = true;
this.onUpdatePlayerArrow(arrow, options);
callback(arrow);
};
Ghost.prototype.onUpdatePlayerArrow = function(arrow, options) {
var offsetX = 0,
offsetY = -55,
x = offsetX + options.x,
y = offsetY + options.y;
var target = new PIXI.Point(x, y);
arrow.position.x += (target.x -arrow.position.x) * Settings.ARROW_GLIDE / 1.5 / 100;
arrow.position.y += (target.y -arrow.position.y) * Settings.ARROW_GLIDE / 100;
var angle = -Math.atan2(arrow.position.x - x, arrow.position.y - options.y);
angle += 0.785398163 * 4;
arrow.rotation = angle;
};
// Player Info
Ghost.prototype.onCreateAndAddHealthBar = function(callback, options) {
var healthBar = new PIXI.Graphics();
this.container.addChild(healthBar);
this.onUpdateHealthBar(healthBar, options);
callback(healthBar);
};
Ghost.prototype.onUpdateHealthBar = function(healthBar, options) {
var width = 14,
height = 2,
borderWidth = 1,
offsetX = -8,
offsetY = -52;
if(typeof options.healthFactor != 'undefined') {
healthBar.clear();
healthBar.beginFill(0x000000);
healthBar.lineStyle(borderWidth, 0x000000);
healthBar.drawRect(0, 0, width, height);
healthBar.endFill();
if(options.healthFactor > 0) {
var color = 0x00FF00;
if(options.healthFactor < Settings.CRITICAL_HEALTH_THRESHOLD) color = 0xFF0000;
healthBar.beginFill(color);
healthBar.lineStyle(0, 0x000000);
healthBar.drawRect(borderWidth, borderWidth, width * options.healthFactor, height);
healthBar.endFill();
}
}
if (options.x && options.y) healthBar.position = new PIXI.Point(offsetX + options.x, offsetY + options.y);
if (options.visible === true || options.visible === false) healthBar.visible = options.visible;
};
Ghost.prototype.onRemoveHealthBar = function(healthBar) {
this.container.removeChild(healthBar);
};
return Ghost;
});

View file

@ -0,0 +1,63 @@
define([
"Game/Client/View/Pixi/Layer",
"Lib/Vendor/Pixi",
"Lib/Utilities/NotificationCenter",
"Game/Config/Settings"
],
function (Parent, PIXI, nc, Settings) {
"use strict";
function Messages() {
Parent.call(this, "messages", {parallaxSpeed:-1});
this.ncTokens = this.ncTokens.concat([
nc.on(nc.ns.client.view.gameStats.kill, this.onKill, this)
]);
this.mainTextOptions = {
font: "normal 22px 'Joystix'",
fill: "#cc0000",
stroke: "rgba(0,0,0,0.8)",
strokeThickness: 6
};
this.mainText = new PIXI.Text("", this.mainTextOptions);
this.container.addChild(this.mainText);
this.mainText.visible = false;
}
Messages.prototype = Object.create(Parent.prototype);
Messages.prototype.onKill = function(options) {
var killer = options.killer.isMe ? "You" : options.killer.name;
var victim = options.victim.isMe
? options.killer.isMe
? "Yourself"
: "You"
: options.victim.name;
var text = killer + " killed " + victim + " with " + options.item;
this.mainText.setText(text);
this.mainText.setStyle(this.mainTextOptions);
this.mainText.position = new PIXI.Point(-this.mainText.width / 2, (Settings.STAGE_HEIGHT / 4) -this.mainText.height / 2);
this.mainText.visible = true;
var self = this;
setTimeout(function(){
self.mainText.visible = false;
}, Settings.SCORE_MESSAGE_TIMEOUT);
}
Messages.prototype.render = function(centerPosition, zoom) {
Parent.prototype.render.call(this, centerPosition, 1);
}
return Messages;
});

View file

@ -0,0 +1,57 @@
define([
"Game/Client/View/Pixi/Layer",
"Lib/Vendor/Pixi",
"Lib/Utilities/NotificationCenter",
"Game/Config/Settings"
],
function (Parent, PIXI, nc, Settings) {
function Swiper() {
Parent.call(this, "swiper", {parallaxSpeed:0});
this.static = true;
this.ncTokens = this.ncTokens.concat([
nc.on(nc.ns.client.view.swiper.swipe, this.swipe, this),
nc.on(nc.ns.client.view.swiper.end, this.end, this)
]);
this.sprite = new PIXI.Graphics();
this.container.addChild(this.sprite);
this.end();
}
Swiper.prototype = Object.create(Parent.prototype);
Swiper.prototype.swipe = function(x, y) {
var offset = {
x: Settings.STAGE_WIDTH / 2 / this.zoom.current,
y: Settings.STAGE_HEIGHT / 2 / this.zoom.current,
}
this.sprite.moveTo(offset.x + this.last.x, offset.y + this.last.y);
this.last.x = x;
this.last.y = -y;
this.sprite.lineTo(offset.x + this.last.x, offset.y + this.last.y);
};
Swiper.prototype.end = function(x, y) {
this.sprite.clear();
this.sprite.lineStyle(2, 0xffffff);
this.sprite.alpha = 0.5;
this.last = {
x: 0,
y: 0
}
};
return Swiper;
});

317
app/Game/Client/View/Pixi/View.js Executable file
View file

@ -0,0 +1,317 @@
define([
"Game/Client/View/Abstract/View",
"Game/Client/View/DomController",
"Lib/Vendor/Pixi",
"Game/Config/Settings",
"Lib/Utilities/NotificationCenter",
"Lib/Utilities/Exception",
"Game/Client/View/Pixi/GameStats",
"Game/Client/View/LayerManager",
"Game/Client/View/Pixi/Layers/Ghost",
"Game/Client/View/Pixi/Layers/Swiper",
"Game/Client/PointerLockManager",
"Game/Client/View/Pixi/Layers/Debug",
"Game/Client/View/Pixi/Layers/Messages"
],
function (Parent, domController, PIXI, Settings, nc, Exception, GameStats, LayerManager, Ghost, Swiper, pointerLockManager, Debug, Messages) {
"use strict";
function PixiView () {
Parent.call(this);
this.xyz = Math.random()
this.layerManager = null;
this.stage = null;
this.container = null;
this.infoContainer = null;
this.loader = null;
this.currentZoom = Settings.ZOOM_DEFAULT;
this.clickToEnable = null;
this.init();
this.ncTokens = this.ncTokens.concat([
nc.on(nc.ns.client.pointerLock.change, this.onPointerLockChange, this),
nc.on(nc.ns.core.game.events.level.loaded, this.showDefaultLayers, this)
]);
PIXI.scaleModes.DEFAULT = PIXI.scaleModes.NEAREST;
}
PixiView.prototype = Object.create(Parent.prototype);
PixiView.prototype.init = function () {
var rendererOptions = {
view: domController.getCanvas(),
antialiasing: false,
transparent: false,
resolution: 1
}
if(Settings.USE_WEBGL) {
PIXI.WebGLRenderer.glContextId = 0;
this.renderer = new PIXI.WebGLRenderer(Settings.STAGE_WIDTH, Settings.STAGE_HEIGHT, rendererOptions);
console.log('WebGLRenderer');
} else {
this.renderer = new PIXI.CanvasRenderer(Settings.STAGE_WIDTH, Settings.STAGE_HEIGHT, rendererOptions);
console.warn('CanvasRenderer - not using WebGL!');
}
this.onDisplaySizeChange(false);
this.stage = new PIXI.Stage(0x333333);
this.container = new PIXI.DisplayObjectContainer();
this.stage.addChild(this.container);
this.layerManager = new LayerManager(this.container, this.me);
this.initLoader();
this.initCanvas(this.renderer.view);
this.initPointerLockView();
// Tab Overlay (not using layer manager, cause of filters)
this.gameStats = new GameStats(this);
this.stage.addChild(this.gameStats.getInfoContainer());
this.ghostLayer = new Ghost();
this.ghostLayer.hide();
this.layerManager.insert(this.ghostLayer, false);
this.swiperLayer = new Swiper();
this.swiperLayer.hide()
this.layerManager.insert(this.swiperLayer, false);
this.debugLayer = Debug;
this.debugLayer.hide();
this.layerManager.insert(this.debugLayer, false);
this.messagesLayer = new Messages();
this.messagesLayer.hide();
this.layerManager.insert(this.messagesLayer, false);
this.render();
}
PixiView.prototype.showDefaultLayers = function() {
this.ghostLayer.show();
this.swiperLayer.show()
this.debugLayer.show();
this.messagesLayer.show();
};
PixiView.prototype.render = function () {
if (this.me) {
this.layerManager.render(this.calculateCenterPosition(), this.currentZoom);
}
this.renderer.render(this.stage);
}
PixiView.prototype.initPointerLockView = function() {
if (!Settings.ENABLE_POINTER_LOCK_FILTER) return;
var blurFilter = new PIXI.BlurFilter();
blurFilter.blurX = 42 * this.currentZoom;
blurFilter.blurY = 42 * this.currentZoom;
var pixelFilter = new PIXI.PixelateFilter();
pixelFilter.pixelSize = 10 * this.currentZoom ;
var grayFilter = new PIXI.GrayFilter();
grayFilter.gray = 0.99;
this.pointerLockFilters = [pixelFilter, grayFilter];
this.clickToEnable = new PIXI.Text("Click to start playing.");
this.clickToEnable.visible = false;
this.stage.addChild(this.clickToEnable)
};
PixiView.prototype.onPointerLockChange = function(isLocked, options) {
if (!Settings.ENABLE_POINTER_LOCK_FILTER) return;
if(isLocked) {
this.removeFilters(this.pointerLockFilters);
this.clickToEnable.visible = false;
this.onZoomReset();
} else {
if(!options || options.start !== true) {
this.clickToEnable.setText("Click to continue playing.");
}
this.clickToEnable.setStyle({
font: "normal " + (14 * this.currentZoom) + "px 'Joystix'",
fill: "#ffffff",
stroke: "rgba(0,0,0,0.8)",
strokeThickness: 6 * this.currentZoom
});
this.addFilters(this.pointerLockFilters);
this.pointerLockFilters.forEach(function(filter) { filter.dirty = true; });
this.clickToEnable.position = new PIXI.Point(Settings.STAGE_WIDTH / 2 - this.clickToEnable.width / 2, Settings.STAGE_HEIGHT / 2 - this.clickToEnable.height / 2)
this.clickToEnable.visible = true;
this.onZoomReset();
this.currentZoom *= 0.9;
}
};
PixiView.prototype.removeFilters = function(filters) {
if(this.container && this.container.filters && this.container.filters.length) {
for (var i = this.container.filters.length - 1; i >= 0; i--) {
for (var j = filters.length - 1; j >= 0; j--) {
if (filters[j] === this.container.filters[i]) {
this.container.filters.splice(i, 1);
}
}
}
// weird bug, filters.length cant be 0, must be set to null
if(this.container.filters.length < 1) {
this.container.filters = null;
}
}
};
PixiView.prototype.addFilters = function(filters) {
if (filters.length < 1) return;
if (!this.container) {
return;
}
if (!this.container.filters) {
/*
* slice does a copy, which is important here -
* otherwise this.pointerLockFilters will be manipulated too on remove.
*/
this.container.filters = filters.slice();
return;
}
for (var i = 0; i < filters.length; i++) {
this.container.filters.push(filters[i]);
}
};
PixiView.prototype.calculateCenterPosition = function() {
var target = this.me.getHeadPosition();
var centerPosition = {x: target.x, y: target.y};
centerPosition.x *= Settings.RATIO * -1;
centerPosition.y *= Settings.RATIO * -1;
var lookAt = this.me.getLookAt();
centerPosition.x -= lookAt.x * 600 / 4;
centerPosition.y += lookAt.y * 400 / 4;
return centerPosition;
};
PixiView.prototype.onDisplaySizeChange = function(isFullScreen) {
Parent.prototype.onDisplaySizeChange.call(this, isFullScreen);
this.renderer.resize(window.innerWidth, window.innerHeight);
this.currentZoom = window.innerWidth / 600;
pointerLockManager.update(null, {}); // only to reposition clickToEnable text
};
PixiView.prototype.initLoader = function() {
this.loader = new PIXI.Graphics();
this.stage.addChild(this.loader);
this.onUpdateLoader(0);
};
PixiView.prototype.onUpdateLoader = function(progress) {
var width = 200,
height = 5,
borderWidth = 1;
if(progress < 100) {
this.loader.clear();
this.loader.beginFill(0x000000);
this.loader.lineStyle(borderWidth, 0x000000);
this.loader.drawRect(0, 0, width, height);
this.loader.endFill();
if(progress > 0) {
var color = 0xFF0FA3;
this.loader.beginFill(color);
this.loader.lineStyle(0, 0x000000);
this.loader.drawRect(borderWidth, borderWidth, width * progress / 100, height);
this.loader.endFill();
}
this.loader.position = new PIXI.Point(
Settings.STAGE_WIDTH / 2 - width / 2 - borderWidth,
Settings.STAGE_HEIGHT / 2 - height / 2 - borderWidth
);
}
this.loader.visible = progress < 100;
};
PixiView.prototype.onZoomIn = function() {
if(this.currentZoom + Settings.ZOOM_FACTOR <= Settings.ZOOM_MAX) {
this.currentZoom += Settings.ZOOM_FACTOR;
}
};
PixiView.prototype.onZoomOut = function() {
//if(this.currentZoom - Settings.ZOOM_FACTOR > window.innerWidth / 600) {
this.currentZoom -= Settings.ZOOM_FACTOR;
//}
};
PixiView.prototype.onZoomReset = function() {
this.currentZoom = window.innerWidth / 600;
};
PixiView.prototype.getTexturesFromFrame = function(textureNames) {
var textures = [];
for (var i = 0; i < textureNames.length; i++) {
textures.push(PIXI.Texture.fromFrame(textureNames[i]));
};
return textures;
};
PixiView.prototype.destroy = function() {
this.layerManager.destroy(); // also calls all layers destroy
for (var i = 0; i < this.stage.children.length; i++) {
this.stage.removeChild(this.stage.children[i]);
}
this.renderer.render(this.stage);
this.renderer.destroy();
delete this.renderer;
Parent.prototype.destroy.call(this);
};
return PixiView;
});

View file

@ -1,11 +1,12 @@
define([
"Game/Client/View/Views/AbstractView",
"Game/Client/View/DomController",
"Game/Client/View/Abstract/View",
"Lib/Vendor/Three",
"Game/Config/Settings"
],
function (Parent, DomController, Three, Settings) {
function (Parent, Three, Settings) {
"use strict";
function ThreeView () {
Parent.call(this);

View file

@ -1,22 +1,24 @@
define([
"Game/Config/Settings",
"Lib/Utilities/Exception",
"Game/Client/View/Views/AbstractView",
//"Game/Client/View/Views/ThreeView",
"Game/Client/View/Views/PixiView",
"Game/Client/View/Abstract/View",
//"Game/Client/View/Three/View",
"Game/Client/View/Pixi/View",
"Lib/Utilities/NotificationCenter"
],
function (Settings, Exception, AbstractView, PixiView, Nc) {
function (Settings, Exception, AbstractView, PixiView, nc) {
"use strict";
var ViewManager = {};
ViewManager.createView = function() {
var view = null
switch(Settings.VIEW_CONTROLLER) {
case 'Three':
view = new ThreeView();
break;
//case 'Three':
// view = new ThreeView();
// break;
case 'Pixi':
view = new PixiView();
break;
@ -36,8 +38,6 @@ function (Settings, Exception, AbstractView, PixiView, Nc) {
throw new Exception("In the view", Settings.VIEW_CONTROLLER + 'View', "this.setCanvas(canvas) has not been called with a valid HTMLCanvasElement!");
}
Nc.trigger(Nc.ns.client.view.events.ready, view);
return view;
}

View file

@ -1,165 +0,0 @@
define([
"Game/Client/View/DomController",
"Game/Config/Settings",
"Lib/Utilities/Exception",
"Lib/Utilities/NotificationCenter"
],
function (DomController, Settings, Exception, Nc) {
function AbstractView () {
this.me = null;
this.canvas = null;
this.debugMode = false;
this.ncTokens = [
Nc.on(Nc.ns.client.view.mesh.create, this.createMesh, this),
Nc.on(Nc.ns.client.view.animatedMesh.create, this.createAnimatedMesh, this),
Nc.on(Nc.ns.client.view.mesh.add, this.addMesh, this),
Nc.on(Nc.ns.client.view.mesh.remove, this.removeMesh, this),
Nc.on(Nc.ns.client.view.mesh.update, this.updateMesh, this),
Nc.on(Nc.ns.client.view.fullscreen.change, this.onFullscreenChange, this),
Nc.on(Nc.ns.client.view.debugMode.toggle, this.onToggleDebugMode, this),
Nc.on(Nc.ns.client.view.playerInfo.createAndAdd, this.onCreateAndAddPlayerInfo, this),
Nc.on(Nc.ns.client.view.playerInfo.update, this.onUpdatePlayerInfo, this),
Nc.on(Nc.ns.client.view.playerInfo.remove, this.onRemovePlayerInfo, this),
Nc.on(Nc.ns.client.view.preloadBar.update, this.onUpdateLoader, this),
];
}
AbstractView.prototype.isWebGlEnabled = function () {
try {
return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'experimental-webgl' );
} catch(e) {
return false;
}
}
AbstractView.prototype.initCanvas = function (canvas) {
this.canvas = canvas;
DomController.initCanvas(canvas);
}
AbstractView.prototype.loadPlayerMesh = function(player) {
throw new Exception('Abstract Function loadPlayerMesh not overwritten');
};
AbstractView.prototype.loadMeshes = function(objects) {
throw new Exception('Abstract Function loadMeshes not overwritten');
};
AbstractView.prototype.render = function () {
throw new Exception('Abstract Function render not overwritten');
}
AbstractView.prototype.createMesh = function (texturePath, callback, options) {
throw new Exception('Abstract Function createMesh not overwritten');
}
AbstractView.prototype.createAnimatedMesh = function (texturePaths, callback, options) {
throw new Exception('Abstract Function createAnimatedMesh not overwritten');
}
AbstractView.prototype.addMesh = function(mesh) {
throw new Exception('Abstract Function addMesh not overwritten');
};
AbstractView.prototype.removeMesh = function(mesh) {
throw new Exception('Abstract Function removeMesh not overwritten');
};
AbstractView.prototype.updateMesh = function(mesh, options) {
throw new Exception('Abstract Function updateMesh not overwritten');
};
AbstractView.prototype.setMe = function(player) {
this.me = player;
};
AbstractView.prototype.addPlayer = function(player) {
throw new Exception('Abstract Function addPlayer not overwritten');
};
AbstractView.prototype.removPlayer = function(player) {
throw new Exception('Abstract Function removPlayer not overwritten');
};
AbstractView.prototype.setCameraPosition = function (x, y) {
throw new Exception('Abstract Function setCameraPosition not overwritten');
}
AbstractView.prototype.calculateCameraPosition = function() {
var reference = this.me.getPosition();
var pos = {};
pos.x = reference.x;
pos.y = reference.y;
pos.x = pos.x * Settings.RATIO;
pos.y = -(pos.y * Settings.RATIO);
pos.x += this.me.playerController.xyInput.x * Settings.STAGE_WIDTH / 4;
pos.y += this.me.playerController.xyInput.y * Settings.STAGE_HEIGHT / 4;
return pos;
};
AbstractView.prototype.setCameraZoom = function (z) {
throw new Exception('Abstract Function setCameraZoom not overwritten');
};
AbstractView.prototype.onFullscreenChange = function(isFullScreen) {
if (!isFullScreen) {
Settings.STAGE_WIDTH = 600;
Settings.STAGE_HEIGHT = 400;
} else {
// FIXME: Create FIXME meme (dumb and dumber)
// FIXME: don't overwrite Settings
Settings.STAGE_WIDTH = window.innerWidth;
Settings.STAGE_HEIGHT = window.innerHeight;
}
};
AbstractView.prototype.onToggleDebugMode = function(debugMode) {
if(debugMode) {
this.setCameraPosition(-Settings.STAGE_WIDTH / 2, -Settings.STAGE_HEIGHT / 2);
}
this.debugMode = debugMode;
};
AbstractView.prototype.toggleInfo = function(show, string) {
throw new Exception('Abstract Function showInfo not overwritten');
};
AbstractView.prototype.onCreateAndAddPlayerInfo = function(options) {
throw new Exception('Abstract Function onCreateAndAddPlayerInfo not overwritten');
};
AbstractView.prototype.onUpdatePlayerInfo = function(playerInfo, options) {
throw new Exception('Abstract Function onUpdatePlayerInfo not overwritten');
};
AbstractView.prototype.onRemovePlayerInfo = function(playerInfo) {
throw new Exception('Abstract Function onRemovePlayerInfo not overwritten');
};
AbstractView.prototype.onUpdateLoader = function(progress) {
throw new Exception('Abstract Function onUpdateLoader not overwritten');
};
AbstractView.prototype.destroy = function() {
for (var i = 0; i < this.ncTokens.length; i++) {
Nc.off(this.ncTokens[i]);
};
};
return AbstractView;
});

View file

@ -1,320 +0,0 @@
define([
"Game/Client/View/Views/AbstractView",
"Game/Client/View/DomController",
"Lib/Vendor/Pixi",
"Game/Config/Settings",
"Lib/Utilities/NotificationCenter"
],
function (Parent, DomController, PIXI, Settings, Nc) {
function PixiView () {
Parent.call(this);
this.movableObjects = [];
this.stage = null;
this.container = null;
this.infoContainer = null;
this.infoFilters = [];
this.infoBox = null;
this.loader = null;
this.init();
this.pixi = PIXI;
PIXI.scaleModes.DEFAULT = PIXI.scaleModes.NEAREST;
}
PixiView.prototype = Object.create(Parent.prototype);
PixiView.prototype.init = function () {
var transparent = false;
var antialias = true;
var canvas = DomController.getCanvas();
if(Settings.USE_WEBGL) {
this.renderer = new PIXI.WebGLRenderer(Settings.STAGE_WIDTH, Settings.STAGE_HEIGHT, canvas, transparent, antialias);
console.log('WebGLRenderer')
} else {
this.renderer = new PIXI.CanvasRenderer(Settings.STAGE_WIDTH, Settings.STAGE_HEIGHT, canvas, transparent, antialias);
console.log('CanvasRenderer - not using WebGL!')
}
this.stage = new PIXI.Stage(0x333333);
this.initCamera();
this.initInfo();
this.initLoader();
this.initCanvas(this.renderer.view);
}
PixiView.prototype.render = function () {
if(this.me) {
var pos = this.calculateCameraPosition();
this.setCameraPosition(pos.x, pos.y);
}
this.renderer.render(this.stage);
}
// Meshes
PixiView.prototype.addMesh = function(mesh) {
this.container.addChild(mesh);
};
PixiView.prototype.removeMesh = function(mesh) {
this.container.removeChild(mesh);
};
PixiView.prototype.createMesh = function (texturePath, callback, options) {
var texture = PIXI.Texture.fromImage(texturePath);
var mesh = new PIXI.Sprite(texture);
if(options) this.updateMesh(mesh, options);
callback(mesh);
}
PixiView.prototype.createAnimatedMesh = function (texturePaths, callback, options) {
var textures = [];
for (var i = 0; i < texturePaths.length; i++) {
var texture = PIXI.Texture.fromImage(texturePaths[i]);
texture.width = options.width;
texture.height = options.height;
PIXI.texturesToUpdate.push(texture);
textures.push(texture);
}
var mesh = new PIXI.MovieClip(textures);
if(options) this.updateMesh(mesh, options);
mesh.animationSpeed = 0.5;
mesh.play();
callback(mesh);
}
PixiView.prototype.updateMesh = function(mesh, options) {
if (options.x) mesh.position.x = options.x;
if (options.y) mesh.position.y = options.y;
if (options.rotation) mesh.rotation = options.rotation;
if (options.width) mesh.width = options.width;
if (options.height) mesh.height = options.height;
if (options.xScale) mesh.width = Math.abs(mesh.width) * options.xScale;
if (options.yScale) mesh.scale.y = options.yScale;
if (options.visible === true || options.visible === false) mesh.visible = options.visible;
if (options.pivot) mesh.pivot = new PIXI.Point(options.pivot.x, options.pivot.y);
}
// Camera
PixiView.prototype.initCamera = function () {
this.container = new PIXI.DisplayObjectContainer();
this.stage.addChild(this.container);
}
PixiView.prototype.calculateCameraPosition = function() {
var zoom = this.container.scale.x;
var target = this.me.getHeadPosition();
target.x *= -Settings.RATIO * zoom;
target.y *= -Settings.RATIO * zoom;
target.x -= this.me.playerController.xyInput.x * Settings.STAGE_WIDTH / 4;
target.y += this.me.playerController.xyInput.y * Settings.STAGE_HEIGHT / 4;
var pos = this.getCameraPosition();
pos.x += (target.x -pos.x) * Settings.CAMERA_GLIDE / 100;
pos.y += (target.y -pos.y) * Settings.CAMERA_GLIDE / 100;
return pos;
};
PixiView.prototype.setCameraPosition = function (x, y) {
if(!this.debugMode) {
this.container.position.x = x + Settings.STAGE_WIDTH / 2;
this.container.position.y = y + Settings.STAGE_HEIGHT / 2;
}
};
PixiView.prototype.getCameraPosition = function () {
var pos = this.container.position;
pos.x = pos.x - Settings.STAGE_WIDTH / 2;
pos.y = pos.y - Settings.STAGE_HEIGHT / 2;
return pos;
};
PixiView.prototype.setCameraZoom = function (z) {
this.container.scale.x = z;
this.container.scale.y = z;
};
PixiView.prototype.onFullscreenChange = function(isFullScreen) {
Parent.prototype.onFullscreenChange.call(this, isFullScreen);
if(isFullScreen) {
this.renderer.resize(window.innerWidth, window.innerHeight);
this.setCameraZoom(window.innerWidth / 600);
} else {
this.renderer.resize(600, 400);
this.setCameraZoom(1);
}
};
// Info Overlay
PixiView.prototype.initInfo = function() {
this.infoContainer = new PIXI.DisplayObjectContainer();
this.stage.addChild(this.infoContainer);
var blurFilter = new PIXI.BlurFilter();
blurFilter.blurX = 12;
blurFilter.blurY = 12;
var grayFilter = new PIXI.GrayFilter();
grayFilter.gray = 0.85;
this.infoFilters = [blurFilter, grayFilter];
this.infoText = new PIXI.Text("", {font: "normal 20px monospace", fill: "red", align: "center"});
this.infoBox = new PIXI.Graphics();
this.infoBox.alpha = 0.7;
this.infoContainer.addChild(this.infoBox);
this.infoContainer.addChild(this.infoText);
this.infoContainer.visible = false;
};
PixiView.prototype.toggleInfo = function(show, string) {
if(show) {
this.infoText.setText(string);
this.infoText.updateText();
this.infoText.dirty = false;
var x = Settings.STAGE_WIDTH / 2 - this.infoText.width / 2,
y = Settings.STAGE_HEIGHT / 2 - this.infoText.height / 2;
this.infoText.position = new PIXI.Point(x, y);
var borderWidth = 3;
var padding = 20;
this.infoBox.clear();
this.infoBox.beginFill(0x000000);
this.infoBox.lineStyle(borderWidth, 0xAA0000);
this.infoBox.drawRect(0, 0, this.infoText.width - borderWidth + 2 * padding * 2, this.infoText.height - borderWidth + 2 * padding);
this.infoBox.endFill();
this.infoBox.position.x = this.infoText.position.x + borderWidth/2 - padding * 2;
this.infoBox.position.y = this.infoText.position.y + borderWidth/2 - padding;
this.infoContainer.visible = true;
this.container.filters = this.infoFilters;
this.infoFilters.forEach(function(filter) { filter.dirty = true; });
} else {
this.infoText.setText("...");
this.infoContainer.visible = false;
this.container.filters = null;
}
};
// Player Info
PixiView.prototype.onCreateAndAddPlayerInfo = function(callback, options) {
var playerInfo = new PIXI.Graphics();
this.container.addChild(playerInfo);
this.onUpdatePlayerInfo(playerInfo, options);
callback(playerInfo);
};
PixiView.prototype.onUpdatePlayerInfo = function(playerInfo, options) {
var width = 14,
height = 2,
borderWidth = 1,
offsetX = -8,
offsetY = -52;
if(typeof options.healthFactor != 'undefined') {
playerInfo.clear();
playerInfo.beginFill(0x000000);
playerInfo.lineStyle(borderWidth, 0x000000);
playerInfo.drawRect(0, 0, width, height);
playerInfo.endFill();
if(options.healthFactor > 0) {
var color = 0x00FF00;
if(options.healthFactor < 0.30) color = 0xFF0000;
playerInfo.beginFill(color);
playerInfo.lineStyle(0, 0x000000);
playerInfo.drawRect(borderWidth, borderWidth, width * options.healthFactor, height);
playerInfo.endFill();
}
}
if (options.x && options.y) playerInfo.position = new PIXI.Point(offsetX + options.x, offsetY + options.y);
if (options.visible === true || options.visible === false) playerInfo.visible = options.visible;
};
PixiView.prototype.onRemovePlayerInfo = function(playerInfo) {
this.container.removeChild(playerInfo);
};
PixiView.prototype.initLoader = function() {
this.loader = new PIXI.Graphics();
this.stage.addChild(this.loader);
this.onUpdateLoader(0);
};
PixiView.prototype.onUpdateLoader = function(progress) {
var width = 200,
height = 5,
borderWidth = 1;
if(progress < 100) {
this.loader.clear();
this.loader.beginFill(0x000000);
this.loader.lineStyle(borderWidth, 0x000000);
this.loader.drawRect(0, 0, width, height);
this.loader.endFill();
if(progress > 0) {
var color = 0xFF0FA3;
this.loader.beginFill(color);
this.loader.lineStyle(0, 0x000000);
this.loader.drawRect(borderWidth, borderWidth, width * progress / 100, height);
this.loader.endFill();
}
this.loader.position = new PIXI.Point(
Settings.STAGE_WIDTH / 2 - width / 2 - borderWidth,
Settings.STAGE_HEIGHT / 2 - height / 2 - borderWidth
);
}
this.loader.visible = progress < 100;
};
PixiView.prototype.destroy = function() {
for (var i = 0; i < this.stage.children.length; i++) {
this.stage.removeChild(this.stage.children[i]);
}
this.renderer.render(this.stage);
Parent.prototype.destroy.call(this);
};
return PixiView;
});

View file

@ -1,7 +1,14 @@
define(function() {
define([
],
function () {
"use strict";
var ItemSettings = {
// weight is a number between 0.1 for very light and 10 for very heavy
"Default":
{
"category": "",
@ -15,7 +22,7 @@ define(function() {
"rotation": "0",
"bounce": "0",
"grabAngle": "-1.5",
"danger": "1",
"danger": "0",
"bodyType": "dynamic",
},
@ -25,7 +32,7 @@ define(function() {
"image": "chest.png",
"type": "ragdoll",
"weight": "5",
"weight": "7",
"width": "6",
"height": "12",
@ -200,7 +207,7 @@ define(function() {
"category": "kitchen",
"image": "fridge.gif",
"weight": "10",
"weight": "5",
"width": "31",
"height": "53",
@ -213,11 +220,12 @@ define(function() {
"category": "kitchen",
"image": "microwave.gif",
"weight": "3.6",
"weight": "4.6",
"width": "19",
"height": "12",
"grabAngle": "-0.1",
"danger": "2",
},
"Coffeemachine":
@ -240,12 +248,24 @@ define(function() {
"height": "9",
},
"Table":
{
"category": "kitchen",
"image": "table.gif",
"weight": "3.5",
"width": "60",
"height": "21",
"grabAngle": "-0.2",
},
"Banana":
{
"category": "kitchen",
"image": "banana.gif",
"weight": "1",
"weight": "3",
"width": "5",
"height": "9",
@ -315,6 +335,45 @@ define(function() {
"grabAngle": "-0.2",
},
"Couch":
{
"category": "livingroom",
"image": "couch.gif",
"weight": "7",
"width": "50",
"height": "29",
"bounce": "3",
"grabAngle": "-0.2",
},
"Cactus":
{
"category": "livingroom",
"image": "cactus.gif",
"weight": "2.5",
"width": "17",
"height": "31",
"danger": "1.9",
"grabAngle": "-0.2",
},
"Piano":
{
"category": "livingroom",
"image": "piano.gif",
"weight": "10",
"width": "66",
"height": "48",
"grabAngle": "-0.2",
},
"Bible":
{
"category": "livingroom",
@ -352,21 +411,19 @@ define(function() {
},
"Rube":
"RubeDoll":
{
"category": "kitchen",
"image": "banana.gif",
// "type": "rube",
"weight": "1",
"width": "5",
"weight": "3",
"width": "15",
"height": "9",
"grabAngle": "0.5",
"type": "rubedoll",
"grabAngle": "0.001", // seems to be a bug, that 0 does not work!
}
}
};
return ItemSettings;
});

View file

@ -1,50 +1,68 @@
define(function() {
define([
],
function () {
"use strict";
var Settings = {
STAGE_WIDTH: 600,
STAGE_HEIGHT: 400,
ZOOM_FACTOR: 0.8,
ZOOM_DEFAULT: 1,
ZOOM_MAX: 10,
// BOX2D INITIALATORS
BOX2D_WORLD_AABB_SIZE: 3000,
BOX2D_ALLOW_SLEEP: true,
BOX2D_GRAVITY: 26,
BOX2D_VELOCITY_ITERATIONS: 5,
BOX2D_POSITION_ITERATIONS: 5,
BOX2D_VELOCITY_ITERATIONS: 20,
BOX2D_POSITION_ITERATIONS: 10, // 200/100 created problems (awful teleporting when repositioning joints)
BOX2D_TIME_STEP: 1 / 60,
// PATHS
GRAPHICS_PATH: 'static/img/',
GRAPHICS_SUBPATH_ITEMS: 'Items/',
GRAPHICS_SUBPATH_CHARACTERS: 'Characters/',
GRAPHICS_SUBPATH_TILES: 'Tiles/',
MAPS_PATH: 'static/maps/tiled/',
GRAPHICS_PATH: "static/img/",
GRAPHICS_SUBPATH_ITEMS: "Items/",
GRAPHICS_SUBPATH_CHARACTERS: "Characters/",
GRAPHICS_SUBPATH_TILES: "Tiles/",
MAPS_PATH: "static/maps/tiled/",
AUDIO_PATH: "static/sounds/",
CHANNEL_RECORDING_PATH: "recordings/",
CHANNEL_PLAY_RECORDING: false, //"Varberg-2015-03-15T23:10:29.316Z-stones.log",
RATIO: 21, //35
// original tile size is 25 but we want it to resize to 20
ORIGINAL_TILE_SIZE: 25,
TILE_SIZE: 20,
CAMERA_IS_ORTHOGRAPHIC: true,
CAMERA_GLIDE: 12, // % of the way per frame
VIEW_CONTROLLER: 0 ? 'Three' : 'Pixi',
CAMERA_GLIDE: 6, // % of the way per frame
VIEW_CONTROLLER: 0 ? "Three" : "Pixi",
ARROW_GLIDE: 30, // % of the way per frame
SHOW_LAYER_INFO: false,
ENABLE_POINTER_LOCK_FILTER: true,
// GAME PLAY
WALK_SPEED: 4,
RUN_SPEED: 8,
FLY_SPEED: 6.2,
JUMP_SPEED: 20,
JUMP_STOP_DAMPING_FACTOR: 0.5,
MAX_THROW_FORCE: 18 * 3.5,
MAX_THROW_ANGULAR_VELOCITY: 0,
JUMP_SPEED: 16,
JUMP_STOP_DAMPING_FACTOR: 0.4,
MAX_THROW_FORCE: 28,
MAX_THROW_ANGULAR_VELOCITY: 3,
MAX_RUNNING_WEIGHT: 9,
RESPAWN_TIME: 5,
HEALTH_DISPLAY_TIME: 2,
RAGDOLL_DESTRUCTION_TIME: 20,
CRITICAL_HEALTH_THRESHOLD: 0.3,
RAGDOLL_DESTRUCTION_TIME: 10,
VIEWPORT_SPEED_FACTOR: 640,
VIEWPORT_LOOK_AHEAD: 0.1,
SCORE_MESSAGE_TIMEOUT: 3500,
// restitution: bouncyness, friction: rubbing, density: mass
TILE_FRICTION: 0.99,
TILE_RESTITUTION: 0.1,
PLAYER_DENSITY: 3.68,
PLAYER_DENSITY: 12.2, //3.68,
PLAYER_FRICTION: 5,
PLAYER_MOTION_FRICTION: 0.1,
PLAYER_RESTITUTION: 0.0,
@ -56,27 +74,29 @@ define(function() {
ITEM_LINEAR_DAMPING: 0.02,
// BROWSER
CANVAS_DOM_ID: 'canvasContainer',
IS_BROWSER_ENVIRONMENT: typeof window !== 'undefined',
CANVAS_DOM_ID: "canvasContainer",
IS_BROWSER_ENVIRONMENT: typeof window !== "undefined",
USE_WEBGL: true,
// NETWORKING
NETWORK_UPDATE_INTERVAL: 70,
CHANNEL_DESTRUCTION_TIME: 30,
NETWORK_UPDATE_INTERVAL: 70, // in milliseconds
NETWORK_LOG_INCOMING: false,
NETWORK_LOG_OUTGOING: false,
NETWORK_LOG_FILTER: ['ping', 'pong', 'worldUpdate', 'lookAt'],
NETWORK_LOG_FILTER: ["ping", "pong", "worldUpdate", "lookAt"],
// CHANNEL
CHANNEL_END_ROUND_TIME: 4, //10,
CHANNEL_DEFAULT_MAX_USERS: 40,
CHANNEL_DEFAULT_SCORE_LIMIT: 10,
CHANNEL_DEFAULT_LEVELS: ['stones2', 'debug', 'stones2', 'debug'],
CHANNEL_MAX_USERS: 20,
CHANNEL_DESTRUCTION_TIME: 0.5 * 60,
CHANNEL_END_ROUND_TIME: 20, //10,
CHANNEL_DEFAULT_MAX_USERS: 10,
CHANNEL_DEFAULT_SCORE_LIMIT: 5,
CHANNEL_DEFAULT_LEVELS: ["debug"],
CHANNEL_RECORD_SESSION: false,
// ME STATE
ME_STATE_MAX_DIFFERENCE_METERS: 1,
PUNKBUSTER_DIFFERENCE_METERS: 1
}
};
Settings.TILE_RATIO = Settings.ORIGINAL_TILE_SIZE / Settings.TILE_SIZE;

View file

@ -4,6 +4,8 @@ define([
function (Box2D) {
"use strict";
function Detector () {
this.listener = new Box2D.Dynamics.b2ContactListener();
this.listener.BeginContact = this.beginContact.bind(this);

View file

@ -1,20 +1,21 @@
define(function () {
define([
],
function () {
function PlayerController (player) {
this.player = player;
this._shift;
this._isJumping;
this._walkingDirectionStatus = 0;
}
PlayerController.prototype.moveLeft = function () {
if(!this.isPlayerInputAllowed()) return;
this.player.move(-1);
this._walkingDirectionStatus = -1;
}
PlayerController.prototype.moveRight = function () {
if(!this.isPlayerInputAllowed()) return;
this.player.move(1);
this._walkingDirectionStatus = 1;
}
@ -25,7 +26,7 @@ define(function () {
}
PlayerController.prototype.jump = function () {
this._isJumping = true;
if(!this.isPlayerInputAllowed()) return;
this.player.jump();
}
@ -34,15 +35,31 @@ define(function () {
}
PlayerController.prototype.lookAt = function (options) {
if(!this.isPlayerInputAllowed()) return;
if(options) this.player.lookAt(options.x, options.y);
}
PlayerController.prototype.activateModifier = function() {
if (!this.isPlayerInputAllowed()) return;
this.player.activateModifier();
};
PlayerController.prototype.deactivateModifier = function() {
if (!this.isPlayerInputAllowed()) return;
this.player.deactivateModifier();
};
PlayerController.prototype.update = function () {
if(this._walkingDirectionStatus != 0) {
this.player.move(this._walkingDirectionStatus);
}
}
// Default behaviour - may be needed later?
PlayerController.prototype.isPlayerInputAllowed = function() {
return true;
};
PlayerController.prototype.destroy = function() {
// extend if necessary
};

View file

@ -4,24 +4,28 @@ define([
"Game/" + GLOBALS.context + "/Player",
"Lib/Utilities/NotificationCenter",
"Game/" + GLOBALS.context + "/GameObjects/Doll",
"Game/" + GLOBALS.context + "/GameObjects/GameObject",
"Game/" + GLOBALS.context + "/GameObjects/Item",
"Lib/Utilities/Assert",
],
function (PhysicsEngine, TiledLevel, Player, Nc, Doll) {
function (PhysicsEngine, TiledLevel, Player, nc, Doll, GameObject, Item, Assert) {
"use strict";
function GameController (options) {
this.options = options;
this.players = {};
this.level = null;
this.gameObjects = null;
this.resetGameObjects();
this.worldUpdateObjects = {};
this.physicsEngine = new PhysicsEngine();
this.physicsEngine.setCollisionDetector();
this.ncTokens = [
Nc.on(Nc.ns.core.game.gameObject.add, this.onGameObjectAdd, this),
Nc.on(Nc.ns.core.game.gameObject.remove, this.onGameObjectRemove, this)
nc.on(nc.ns.core.game.worldUpdateObjects.add, this.onWorldUpdateObjectAdd, this),
nc.on(nc.ns.core.game.worldUpdateObjects.remove, this.onWorldUpdateObjectRemove, this)
];
this.loadLevel(options.levelUid);
@ -33,46 +37,61 @@ function (PhysicsEngine, TiledLevel, Player, Nc, Doll) {
// extend for both sides if necessary
};
GameController.prototype.resetGameObjects = function() {
this.gameObjects = {
fixed: [],
animated: []
};
GameController.prototype.onWorldUpdateObjectAdd = function(object) {
this.worldUpdateObjects[object.uid] = object;
};
GameController.prototype.onGameObjectAdd = function(type, object) {
this.gameObjects[type].push(object);
};
GameController.prototype.onGameObjectRemove = function(type, object) {
var i = this.gameObjects[type].indexOf(object);
if(i>=0) this.gameObjects[type].splice(i, 1);
GameController.prototype.onWorldUpdateObjectRemove = function(object) {
delete this.worldUpdateObjects[object.uid];
};
GameController.prototype.getPhysicsEngine = function () {
return this.physicsEngine;
}
};
GameController.prototype.getItemByUid = function(uid) {
// FIXME : maybe divide this into a dedicated item pool?
return this.worldUpdateObjects[uid];
};
GameController.prototype.loadLevel = function (levelUid) {
if (this.level) {
this.level.destroy();
this.resetGameObjects();
this.worldUpdateObjects = {};
}
this.level = new TiledLevel(levelUid, this.physicsEngine, this.gameObjects);
this.level = new TiledLevel(levelUid, this.physicsEngine);
};
/*
* This is now in core, because the recorder/player
* uses the world update mechanism on the channel side
*/
GameController.prototype.onWorldUpdate = function (updateData) {
for (var uid in updateData) {
var gameObject = this.worldUpdateObjects[uid];
if (!(gameObject instanceof GameObject)) {
console.warn('Can\'t find object ' + uid + ' in worldUpdateObjects pool:', Object.keys(this.worldUpdateObjects));
continue;
}
this.updateGameObject(gameObject, updateData[uid]);
}
};
GameController.prototype.updateGameObject = function(gameObject, gameObjectUpdate) {
gameObject.setUpdateData(gameObjectUpdate);
}
GameController.prototype.onResetLevel = function() {
this.loadLevel(this.level.uid);
};
/*
GameController.prototype.userJoined = function (user) {
this.players[user.id] = this.createPlayer(user);
}
*/
GameController.prototype.onUserLeft = function (userId) {
var player = this.players[userId];
if(!player) {
@ -82,47 +101,34 @@ function (PhysicsEngine, TiledLevel, Player, Nc, Doll) {
player.destroy();
delete this.players[userId];
}
};
GameController.prototype.createPlayer = function(user) {
var player = new Player(user.id, this.physicsEngine, user);
GameController.prototype.createPlayer = function(user, revealedGameController) {
var player = new Player(user.id, this.physicsEngine, user, revealedGameController);
this.players[user.id] = player;
return player;
};
GameController.prototype.destroy = function () {
for(var player in this.players) {
// this.players[player].destroy();
// FIXME:
// commented out for now, because players are in gameObjects array.
// try using a real gameobject for the health bar
this.players[player].destroy();
}
for (var i = 0; i < this.ncTokens.length; i++) {
Nc.off(this.ncTokens[i]);
};
// FIXME ns.client in core?
nc.trigger(nc.ns.client.game.events.destroy);
/*
* Contents of gameObject: Players, Items, Tiles, RagDolls
* No Dolls.
*/
for (var key in this.gameObjects) {
for (var i = 0; i < this.gameObjects[key].length; i++) {
var gameObject = this.gameObjects[key][i];
gameObject.destroy();
};
};
this.gameObjects = {
fixed: [],
animated: []
};
// Testing after destroy if worldUpdateObjects is empty
// events.game.destroy -> gameobjects.destroy() -> nc.trigger(worldUpdateObjects.remove)
if(Object.keys(this.worldUpdateObjects).length > 0) {
console.warn('Not all worldUpdateObjects have been removed... ', Object.keys(this.worldUpdateObjects));
}
this.physicsEngine.destroy();
}
this.worldUpdateObjects = null;
nc.off(this.ncTokens);
};
return GameController;
});

View file

@ -1,13 +1,17 @@
define([
"Game/" + GLOBALS.context + "/GameObjects/GameObject",
"Lib/Utilities/Exception",
"Lib/Vendor/Box2D",
"Game/Config/Settings",
"Game/" + GLOBALS.context + "/Collision/Detector",
"Game/" + GLOBALS.context + "/GameObjects/Item",
"Lib/Utilities/NotificationCenter"
"Lib/Utilities/NotificationCenter",
"Lib/Utilities/Assert"
],
function (Parent, Box2D, Settings, CollisionDetector, Item, Nc) {
function (Parent, Exception, Box2D, Settings, CollisionDetector, Item, nc, Assert) {
"use strict";
function Doll (physicsEngine, uid, player) {
@ -24,8 +28,8 @@ function (Parent, Box2D, Settings, CollisionDetector, Item, Nc) {
this.standing = false;
this.moveDirection = 0;
this.lookDirection = 0;
this.legs;
this.footSensor;
this.legs = null;
this.footSensor = null;
this.actionState = null;
this.lookAtXY = { x:0, y:0 };
this.reachableItems = {
@ -36,11 +40,12 @@ function (Parent, Box2D, Settings, CollisionDetector, Item, Nc) {
this.holdingJoint = null;
this.holdingItem = null;
this.ragDoll = {head: null, body: null};
this.ragDoll = {head: null, body: null}; // FIXME: wtf is this? can we remove it?
this.createFixtures();
this.body.SetActive(false);
nc.trigger(nc.ns.core.game.worldUpdateObjects.add, this);
}
Doll.prototype = Object.create(Parent.prototype);
@ -56,6 +61,10 @@ function (Parent, Box2D, Settings, CollisionDetector, Item, Nc) {
};
Doll.prototype.createFixtures = function () {
Assert.number(this.width, this.height);
Assert.number(this.reachDistance);
Assert.number(this.areaSize);
var self = this;
var fixtureDef = new Box2D.Dynamics.b2FixtureDef();
@ -64,13 +73,15 @@ function (Parent, Box2D, Settings, CollisionDetector, Item, Nc) {
fixtureDef.restitution = Settings.PLAYER_RESTITUTION;
var headShape = new Box2D.Collision.Shapes.b2CircleShape();
headShape.SetRadius(this.width / 2 / Settings.RATIO);
var radius = this.width / 2 / Settings.RATIO;
headShape.SetRadius(radius);
headShape.SetLocalPosition(new Box2D.Common.Math.b2Vec2(0, -(this.height - (this.width / 2)) / Settings.RATIO));
fixtureDef.shape = headShape;
fixtureDef.isSensor = false;
fixtureDef.userData = {
onCollisionChange: this.onImpact.bind(this)
}
};
this.body.CreateFixture(fixtureDef);
@ -103,7 +114,7 @@ function (Parent, Box2D, Settings, CollisionDetector, Item, Nc) {
fixtureDef.userData = {
onCollisionChange: this.onFootSensorDetection.bind(this)
}
};
this.footSensor = this.body.CreateFixture(fixtureDef);
@ -122,7 +133,7 @@ function (Parent, Box2D, Settings, CollisionDetector, Item, Nc) {
onCollisionChange: function(isColliding, fixture) {
self.onFixtureWithinReach(isColliding, "left", fixture);
}
}
};
this.body.CreateFixture(fixtureDef);
var grabSensorRightShape = new Box2D.Collision.Shapes.b2PolygonShape();
@ -141,7 +152,7 @@ function (Parent, Box2D, Settings, CollisionDetector, Item, Nc) {
onCollisionChange: function(isColliding, fixture) {
self.onFixtureWithinReach(isColliding, "right", fixture);
}
}
};
this.body.CreateFixture(fixtureDef);
@ -160,7 +171,7 @@ function (Parent, Box2D, Settings, CollisionDetector, Item, Nc) {
fixtureDef.userData = {
onCollisionChange: function(isColliding, fixture) {
var userData = fixture.GetBody().GetUserData()
var userData = fixture.GetBody().GetUserData();
if(userData instanceof Doll) {
var doll = userData;
var i = self.nearbyDolls.indexOf(doll);
@ -175,28 +186,29 @@ function (Parent, Box2D, Settings, CollisionDetector, Item, Nc) {
}
}
}
}
};
this.body.CreateFixture(fixtureDef);
}
};
Doll.prototype.setActionState = function(state) {
this.actionState = state;
}
};
Doll.prototype.getActionState = function() {
return this.actionState;
}
};
Doll.prototype.isWalking = function() {
return ["walk", "walkback", "run"].indexOf(this.actionState) >= 0;
}
};
Doll.prototype.spawn = function (x, y) {
Assert.number(x, y);
this.body.SetPosition(new Box2D.Common.Math.b2Vec2(x / Settings.RATIO, y / Settings.RATIO));
this.body.SetActive(true);
this.setActionState("fall");
}
};
Doll.prototype.getHeadPosition = function() {
var pos = this.body.GetPosition();
@ -209,19 +221,21 @@ function (Parent, Box2D, Settings, CollisionDetector, Item, Nc) {
Doll.prototype.setFriction = function (friction) {
if(!friction) friction = -1;
Assert.number(friction);
if (this.legs.GetFriction() != friction) {
this.legs.SetFriction(friction);
}
}
};
Doll.prototype.move = function (direction) {
Doll.prototype.move = function (direction, modifierActivated) {
this.moveDirection = direction;
var speed;
var isHoldingHeavyItem = this.holdingItem && this.holdingItem.options.weight > Settings.MAX_RUNNING_WEIGHT;
switch(true) {
case direction == this.lookDirection && this.isStanding() && !isHoldingHeavyItem:
case direction == this.lookDirection && this.isStanding() && !isHoldingHeavyItem && !modifierActivated:
speed = Settings.RUN_SPEED;
break;
@ -242,13 +256,15 @@ function (Parent, Box2D, Settings, CollisionDetector, Item, Nc) {
this.setFriction(Settings.PLAYER_MOTION_FRICTION);
this.body.SetAwake(true);
Assert.number(speed, direction);
var vector = new Box2D.Common.Math.b2Vec2(speed * direction, this.body.GetLinearVelocity().y);
this.body.SetLinearVelocity(vector);
if(this.isStanding()) {
if(this.moveDirection == this.lookDirection) {
if(isHoldingHeavyItem) {
if(isHoldingHeavyItem || modifierActivated) {
this.setActionState("walk");
} else {
this.setActionState("run");
@ -258,7 +274,7 @@ function (Parent, Box2D, Settings, CollisionDetector, Item, Nc) {
this.setActionState("walkback");
}
}
}
};
Doll.prototype.stop = function () {
this.moveDirection = 0;
@ -270,20 +286,20 @@ function (Parent, Box2D, Settings, CollisionDetector, Item, Nc) {
vector.x *= Settings.JUMP_STOP_DAMPING_FACTOR;
this.body.SetLinearVelocity(vector);
}
}
};
Doll.prototype.jump = function () {
if (this.isStanding()) {
this.body.SetAwake(true);
var vector = new Box2D.Common.Math.b2Vec2(0, -Settings.JUMP_SPEED);
this.body.SetLinearVelocity(vector);
this.setStanding(false);
this.setActionState("jump");
}
}
};
Doll.prototype.jumpStop = function () {
if (!this.isStanding() ) {
@ -294,17 +310,17 @@ function (Parent, Box2D, Settings, CollisionDetector, Item, Nc) {
this.body.SetLinearVelocity(vector);
}
}
}
};
Doll.prototype.setStanding = function (isStanding) {
if (this.standing == isStanding) return;
this.standing = isStanding;
if(isStanding) this.setActionState("stand");
}
};
Doll.prototype.isStanding = function () {
return this.standing;
}
};
Doll.prototype.lookAt = function(x, y) {
var oldLookDirection = this.lookDirection;
@ -338,9 +354,12 @@ function (Parent, Box2D, Settings, CollisionDetector, Item, Nc) {
}
var bodyPosition = this.body.GetPosition();
Assert.number(this.width, this.height);
Assert.number(this.lookDirection);
var handPosition = new Box2D.Common.Math.b2Vec2(
bodyPosition.x + ((this.width / 2 / Settings.RATIO) * this.lookDirection),
bodyPosition.y - this.height / 3 * 2 / Settings.RATIO // 2/3 of the body height
bodyPosition.y - this.height / 4 * 2 / Settings.RATIO // 2/3 of the body height
);
this.holdingItem.reposition(handPosition, this.lookDirection);
@ -352,19 +371,31 @@ function (Parent, Box2D, Settings, CollisionDetector, Item, Nc) {
}
};
Doll.prototype.throw = function(item, x, y) {
this.body.GetWorld().DestroyJoint(this.holdingJoint);
Doll.prototype.throw = function(item, options) {
if(this.holdingJoint) {
this.body.GetWorld().DestroyJoint(this.holdingJoint);
} else {
// log stack if we called throw without a holdingJoint
var w = new Error("Throwing without a holdingJoint");
console.error(w.message + "\n" + w.stack);
}
this.holdingJoint = null;
this.holdingItem = null;
item.throw(x, y);
var dollVelocity = {
x: this.body.GetLinearVelocity().x,
y: this.body.GetLinearVelocity().y
};
item.throw(options, dollVelocity);
};
Doll.prototype.isAnotherPlayerNearby = function() {
return this.nearbyDolls.length > 0;
};
Doll.prototype.onFootSensorDetection = function(isColliding, fixture) {
Doll.prototype.onFootSensorDetection = function(isColliding, fixture) { // jshint unused:false
var self = this;
@ -401,9 +432,9 @@ function (Parent, Box2D, Settings, CollisionDetector, Item, Nc) {
self.setStanding(false);
}
}
}
};
Doll.prototype.onImpact = function(isColliding, fixture) {
Doll.prototype.onImpact = function(isColliding, fixture) { // jshint unused:false
// overwrite if necessary
};
@ -421,7 +452,7 @@ function (Parent, Box2D, Settings, CollisionDetector, Item, Nc) {
this.reachableItems[side].splice(i, 1);
}
}
}
};
Doll.prototype.getVelocities = function() {
return {
@ -432,7 +463,7 @@ function (Parent, Box2D, Settings, CollisionDetector, Item, Nc) {
Doll.prototype.update = function() {
if (this.body.GetLinearVelocity().x == 0 && this.isWalking()) {
if (this.body.GetLinearVelocity().x === 0 && this.isWalking()) {
this.stop();
}
@ -441,7 +472,16 @@ function (Parent, Box2D, Settings, CollisionDetector, Item, Nc) {
}
};
Doll.prototype.setUpdateData = function(update) {
Parent.prototype.setUpdateData.call(this, update);
this.setActionState(update.as);
this.lookAt(update.laxy.x, update.laxy.y);
};
Doll.prototype.destroy = function() {
nc.trigger(nc.ns.core.game.worldUpdateObjects.remove, this);
Parent.prototype.destroy.call(this);
};

View file

@ -1,16 +1,24 @@
define([
"Lib/Vendor/Box2D",
"Lib/Utilities/Exception"
"Lib/Utilities/Exception",
"Lib/Utilities/Assert",
"Lib/Utilities/NotificationCenter"
],
function (Box2D, Exception) {
function (Box2D, Exception, Assert, nc) {
"use strict";
function GameObject(physicsEngine, uid) {
this.uid = uid;
var def = this.getBodyDef();
def.userData = this;
this.body = physicsEngine.getWorld().CreateBody(def);
this.body = physicsEngine.createBody(def);
this.ncTokens = (this.ncTokens || []).concat([
nc.on(nc.ns.client.game.events.destroy, this.destroy, this)
]);
}
GameObject.prototype.getBodyDef = function() {
@ -18,11 +26,14 @@ function (Box2D, Exception) {
};
GameObject.prototype.destroy = function() {
if(this.body instanceof Box2D.Dynamics.b2Body) {
this.body.GetWorld().DestroyBody(this.body);
} else {
throw new Exception("can not destroy body");
}
nc.off(this.ncTokens);
};
GameObject.prototype.getBody = function() {
@ -32,6 +43,20 @@ function (Box2D, Exception) {
GameObject.prototype.getPosition = function() {
return this.body.GetPosition().Copy();
};
GameObject.prototype.setUpdateData = function(update) {
Assert.number(update.p.x, update.p.y);
Assert.number(update.a);
Assert.number(update.lv.x, update.lv.y);
Assert.number(update.av);
this.body.SetAwake(true);
this.body.SetPosition(update.p);
this.body.SetAngle(update.a);
this.body.SetLinearVelocity(update.lv);
this.body.SetAngularVelocity(update.av);
};
return GameObject;

View file

@ -1,13 +1,16 @@
define([
"Game/" + GLOBALS.context + "/GameObjects/GameObject",
"Lib/Vendor/Box2D",
"Lib/Utilities/Options",
"Lib/Utilities/OptionsHelper",
"Game/Config/Settings",
"Lib/Utilities/Exception",
"Lib/Utilities/NotificationCenter"
"Lib/Utilities/NotificationCenter",
"Lib/Utilities/Assert"
],
function (Parent, Box2D, Options, Settings, Exception, Nc) {
function (Parent, Box2D, optionsHelper, Settings, Exception, nc, Assert) {
"use strict";
function Item(physicsEngine, uid, options) {
@ -23,25 +26,28 @@ function (Parent, Box2D, Options, Settings, Exception, Nc) {
y: parseFloat(options.y)
};
this.options = Options.merge(floatOptions, options);
this.options = optionsHelper.merge(floatOptions, options);
if(!this.options.category) {
// FIXME add more validation
console.warn('item category empty (' + this.options.name + ')' );
//console.warn('item category empty (' + this.options.name + ')' );
}
Parent.call(this, physicsEngine, uid);
this.createFixture();
this.body.ResetMassData();
this.flipDirection = 1;
if (this.body.GetMass() < 1) {
this.body.SetBullet(true);
}
Nc.trigger(Nc.ns.core.game.gameObject.add, 'animated', this);
nc.trigger(nc.ns.core.game.worldUpdateObjects.add, this);
}
Item.prototype = Object.create(Parent.prototype);
Item.prototype.getBodyDef = function() {
Assert.number(this.options.x, this.options.y);
var bodyDef = new Box2D.Dynamics.b2BodyDef();
bodyDef.type = Box2D.Dynamics.b2Body.b2_dynamicBody;
bodyDef.position.x = this.options.x / Settings.RATIO;
@ -49,14 +55,18 @@ function (Parent, Box2D, Options, Settings, Exception, Nc) {
bodyDef.angle = 0;
return bodyDef;
}
};
Item.prototype.getFixtureDef = function() {
Assert.number(this.options.width, this.options.height);
Assert.number(this.options.weight);
Assert.number(this.options.bounce);
var itemShape;
var w = this.options.width / Settings.RATIO;
var h = this.options.height / Settings.RATIO;
if(this.options.type == 'circle'){
if(this.options.type == "circle") {
var r = (w + h) / 4 ;
itemShape = new Box2D.Collision.Shapes.b2CircleShape();
itemShape.SetRadius(r);
@ -66,25 +76,19 @@ function (Parent, Box2D, Options, Settings, Exception, Nc) {
itemShape.SetAsOrientedBox(w / 2, h / 2, new Box2D.Common.Math.b2Vec2(0, -(h/2)));
}
var fixtureDef = new Box2D.Dynamics.b2FixtureDef();
fixtureDef.shape = itemShape;
var offset = 4,
factor = 80;
var density = ((this.options.weight + offset) / this.options.width / this.options.height) * factor;
fixtureDef.density = density;
fixtureDef.density = this.options.weight;
fixtureDef.friction = Settings.ITEM_FRICTION;
fixtureDef.restitution = this.options.bounce
? this.options.bounce / 10
: Settings.ITEM_RESTITUTION;
fixtureDef.restitution = this.options.bounce ? this.options.bounce / 10 : Settings.ITEM_RESTITUTION;
fixtureDef.isSensor = false;
fixtureDef.userData = {
onCollisionChange: this.onCollisionChange.bind(this)
}
};
return fixtureDef;
};
@ -92,7 +96,7 @@ function (Parent, Box2D, Options, Settings, Exception, Nc) {
Item.prototype.createFixture = function () {
var fixtureDef = this.getFixtureDef();
this.body.CreateFixture(fixtureDef);
}
};
Item.prototype.flip = function(direction) {
this.flipDirection = direction;
@ -100,48 +104,61 @@ function (Parent, Box2D, Options, Settings, Exception, Nc) {
// FIXME: implement body flip if necessary
};
Item.prototype.beingGrabbed = function(player) {
Item.prototype.beingGrabbed = function(player) { // jshint unused:false
// overwrite if necessary
};
Item.prototype.beingReleased = function(player) {
Item.prototype.beingReleased = function(player) { // jshint unused:false
// overwrite if necessary
};
Item.prototype.onCollisionChange = function(isColliding, fixture, info) {
Item.prototype.onCollisionChange = function(isColliding, fixture, info) { // jshint unused:false
// overwrite if necessary
};
Item.prototype.reposition = function(handPosition, direction) {
Assert.number(handPosition.x, handPosition.y);
Assert.number(direction);
Assert.number(this.options.width);
Assert.number(this.options.grabAngle);
this.body.SetAwake(true);
var position = new Box2D.Common.Math.b2Vec2(
handPosition.x + ((this.options.width / Settings.RATIO / 2) * direction),
handPosition.y
)
);
this.body.SetPosition(position);
this.body.SetAngle((this.options.grabAngle || 0.0) * direction);
this.flip(direction);
this.body.SetAngle((this.options.grabAngle || 0) * direction);
};
Item.prototype.getGrabPoint = function() {
return this.body.GetWorldCenter();
};
Item.prototype.throw = function(x, y) {
var body = this.body;
Item.prototype.throw = function(options, carrierVelocity) {
this.accelerateBody(this.body, options, carrierVelocity);
};
Item.prototype.accelerateBody = function(body, options, carrierVelocity) {
Assert.number(this.options.weight);
Assert.number(carrierVelocity.x, carrierVelocity.y);
Assert.number(options.x, options.y);
Assert.number(options.av);
body.SetAwake(true);
var vector = new Box2D.Common.Math.b2Vec2(
x * Settings.MAX_THROW_FORCE / this.options.weight,
-y * Settings.MAX_THROW_FORCE / this.options.weight
);
this.body.SetLinearVelocity(vector);
var x = options.x * Settings.MAX_THROW_FORCE / this.options.weight + carrierVelocity.x;
var y = -options.y * Settings.MAX_THROW_FORCE / this.options.weight + carrierVelocity.y;
var vector = new Box2D.Common.Math.b2Vec2(x, y);
body.SetLinearVelocity(vector);
body.SetAngularVelocity(Settings.MAX_THROW_ANGULAR_VELOCITY * x);
var av = -options.av * Settings.MAX_THROW_ANGULAR_VELOCITY;
body.SetAngularVelocity(av);
};
Item.prototype.destroy = function() {
Nc.trigger(Nc.ns.core.game.gameObject.remove, 'animated', this);
nc.trigger(nc.ns.core.game.worldUpdateObjects.remove, this);
Parent.prototype.destroy.call(this);
};

View file

@ -2,10 +2,15 @@ define([
"Game/" + GLOBALS.context + "/GameObjects/Item",
"Lib/Vendor/Box2D",
"Game/Config/Settings",
"Lib/Utilities/NotificationCenter"
"Lib/Utilities/NotificationCenter",
"Lib/Utilities/Assert",
"Lib/Utilities/OptionsHelper",
"Game/Config/ItemSettings",
],
function (Parent, Box2D, Settings, Nc) {
function (Parent, Box2D, Settings, nc, Assert, optionsHelper, ItemSettings) {
"use strict";
function RagDoll(physicsEngine, uid, options) {
@ -90,18 +95,17 @@ function (Parent, Box2D, Settings, Nc) {
// FIXME
var ragdollOptions = optionsHelper.merge(ItemSettings.RagDoll, ItemSettings.Default);
options = optionsHelper.merge(options, ragdollOptions);
Parent.call(this, physicsEngine, uid, options);
//this.createSensor();
this.limbs = {};
this.addHead();
this.addLimb(
"upperLeftLeg",
this.body,
@ -133,7 +137,6 @@ function (Parent, Box2D, Settings, Nc) {
this.addLimb(
"upperLeftArm",
this.body,
@ -161,6 +164,7 @@ function (Parent, Box2D, Settings, Nc) {
0,
options.limbs.upperRightArm.height / 2
);
}
RagDoll.prototype = Object.create(Parent.prototype);
@ -181,10 +185,14 @@ function (Parent, Box2D, Settings, Nc) {
var bodyDef = Parent.prototype.getBodyDef.call(this);
bodyDef.linearDamping = Settings.PLAYER_LINEAR_DAMPING;
bodyDef.type = Box2D.Dynamics.b2Body.b2_dynamicBody;
bodyDef.position.y -= this.options.height / 2 / Settings.RATIO; // position it on top of ground
return bodyDef;
};
RagDoll.prototype.getFixtureDef = function() {
Assert.number(this.options.limbs.chest.width, this.options.limbs.chest.height);
var fixtureDef = Parent.prototype.getFixtureDef.call(this);
fixtureDef.density = Settings.PLAYER_DENSITY;
fixtureDef.friction = Settings.PLAYER_FRICTION;
@ -204,6 +212,8 @@ function (Parent, Box2D, Settings, Nc) {
};
RagDoll.prototype.createSensor = function() {
Assert.number(this.options.width, this.options.height);
var w = this.options.width / Settings.RATIO;
var h = this.options.height / Settings.RATIO;
@ -216,14 +226,18 @@ function (Parent, Box2D, Settings, Nc) {
fixtureDef.userData = {
onCollisionChange: this.onCollisionChange.bind(this)
}
};
this.body.CreateFixture(fixtureDef);
};
RagDoll.prototype.addHead = function() {
Assert.number(this.options.x, this.options.y);
Assert.number(this.options.limbs.head.x, this.options.limbs.head.y);
Assert.number(this.options.limbs.head.width);
var x = this.options.x + this.options.limbs.head.x,
y = this.options.y + this.options.limbs.head.y;
y = this.options.y + this.options.limbs.head.y - this.options.height / 2; // position it on top of ground;
var bodyDef = new Box2D.Dynamics.b2BodyDef();
bodyDef.type = Box2D.Dynamics.b2Body.b2_dynamicBody;
@ -268,8 +282,13 @@ function (Parent, Box2D, Settings, Nc) {
};
RagDoll.prototype.addLimb = function(name, connectTo, xOffset, yOffset) {
Assert.number(xOffset, yOffset);
Assert.number(this.options.x, this.options.y);
Assert.number(this.options.limbs[name].x, this.options.limbs[name].y);
Assert.number(this.options.limbs[name].width, this.options.limbs[name].height);
var x = this.options.x + this.options.limbs[name].x,
y = this.options.y + this.options.limbs[name].y;
y = this.options.y + this.options.limbs[name].y - this.options.height / 2; // position it on top of ground;;
var bodyDef = new Box2D.Dynamics.b2BodyDef();
bodyDef.linearDamping = Settings.PLAYER_LINEAR_DAMPING;
@ -320,6 +339,10 @@ function (Parent, Box2D, Settings, Nc) {
};
RagDoll.prototype.reposition = function(handPosition, direction) {
Assert.number(this.options.limbs.head.x, this.options.limbs.head.y);
Assert.number(this.options.grabAngle);
Assert.number(direction);
Parent.prototype.reposition.call(this, handPosition, direction);
var chestPosition = this.body.GetPosition();
@ -327,30 +350,25 @@ function (Parent, Box2D, Settings, Nc) {
var position = new Box2D.Common.Math.b2Vec2(
chestPosition.x + this.options.limbs.head.x / Settings.RATIO,
chestPosition.y + this.options.limbs.head.y / Settings.RATIO
)
);
this.limbs.head.SetPosition(position);
this.limbs.head.SetAngle((this.options.grabAngle || 0) * direction);
this.limbs.head.SetAngle((this.options.grabAngle || 0.0) * direction);
};
RagDoll.prototype.throw = function(x, y) {
Parent.prototype.throw.call(this, x, y);
var limbDampingFactor = 1;
RagDoll.prototype.throw = function(options, carrierVelocity) {
Parent.prototype.throw.call(this, options, carrierVelocity);
for(var name in this.limbs) {
var body = this.limbs[name];
body.SetAwake(true);
var vector = new Box2D.Common.Math.b2Vec2(
x * Settings.MAX_THROW_FORCE * limbDampingFactor / this.options.weight,
-y * Settings.MAX_THROW_FORCE * limbDampingFactor / this.options.weight
);
body.SetLinearVelocity(vector);
// body.SetAngularVelocity(Settings.MAX_THROW_ANGULAR_VELOCITY * x);
this.accelerateBody(body, options, carrierVelocity);
}
};
RagDoll.prototype.setVelocities = function(options) {
Assert.number(options.linearVelocity.x, options.linearVelocity.y);
Assert.number(options.angularVelocity);
this.body.SetLinearVelocity(options.linearVelocity);
this.body.SetAngularVelocity(options.angularVelocity);
for(var name in this.limbs) {
@ -360,7 +378,6 @@ function (Parent, Box2D, Settings, Nc) {
RagDoll.prototype.destroy = function() {
Nc.trigger(Nc.ns.core.game.gameObject.remove, 'animated', this);
var world = this.body.GetWorld();
for (var name in this.limbs) {

View file

@ -5,6 +5,8 @@ define([
],
function (Parent, Box2D, Settings) {
"use strict";
function RagDoll(physicsEngine, uid, options) {
Parent.call(this, physicsEngine, uid, options);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,223 @@
define([
"Game/" + GLOBALS.context + "/GameObjects/Item",
"Lib/Vendor/RubeLoader",
"Lib/Vendor/Box2D",
"Game/Config/Settings",
"Lib/Utilities/Assert",
"Lib/Utilities/NotificationCenter",
"Lib/Utilities/Matrix",
"json!Game/Asset/RubeDoll.json" // using requirejs json loader plugin
],
function (Parent, RubeLoader, Box2D, Settings, Assert, nc, Matrix, RubeDollJson) {
"use strict";
function RubeDoll(physicsEngine, uid, options) {
Assert.number(options.x, options.y);
this.rubeLoader = null;
this.body = null;
this.limbs = {};
this.joints = null;
this.limits = [];
var chest = null;
this.rubeLoader = new RubeLoader(RubeDollJson, physicsEngine.getWorldForRubeLoader());
this.loadRubeDollFromScene(options);
Parent.call(this, physicsEngine, uid, options);
physicsEngine.destroyBody(this.body);
this.body = this.limbs.chest;
delete this.limbs.chest;
this.body.SetUserData(this);
this.flip(options.direction || 1);
}
RubeDoll.prototype = Object.create(Parent.prototype);
RubeDoll.prototype.loadRubeDollFromScene = function(options) {
var scene = this.rubeLoader.getScene();
for (var i in scene.bodies) {
var body = scene.bodies[i];
var position = body.GetPosition().Copy();
position.Add(new Box2D.Common.Math.b2Vec2(
options.x / Settings.RATIO,
options.y / Settings.RATIO
));
body.SetPosition(position);
this.limbs[body.name] = body;
// code snipped possibly needed for filtering between doll and rubedoll while holding
//var filterData = new Box2D.Dynamics.b2FilterData();
//filterData.groupIndex = -66;
//if(body.name != "head" && body.name != "chest") {
// for (var fixture = body.GetFixtureList(); fixture; fixture = fixture.GetNext()) {
// fixture.SetFilterData(filterData);
// }
//}
}
this.joints = scene.joints;
var count = 0;
for (var i in this.joints) {
this.limits[i] = {
lower: this.joints[i].GetLowerLimit(),
upper: this.joints[i].GetUpperLimit(),
};
/*
this.joints[i].EnableLimit(false);
if(count < 4 && this.joints[i] instanceof Box2D.Dynamics.Joints.b2RevoluteJoint) {
console.log(i);
} else {
body.GetWorld().DestroyJoint(this.joints[i]);
}
count++;
*/
}
};
RubeDoll.prototype.getFixtureDef = function() {
var fixtureDef = new Box2D.Dynamics.b2FixtureDef();
fixtureDef.shape = new Box2D.Collision.Shapes.b2CircleShape();
return fixtureDef;
};
RubeDoll.prototype.flip = function(direction) {
var oldFlipDirection = this.flipDirection;
Parent.prototype.flip.call(this, direction);
if(oldFlipDirection != direction) {
for (var i in this.joints) {
var joint = this.joints[i];
var limits = this.limits[i];
if (joint instanceof Box2D.Dynamics.Joints.b2RevoluteJoint) {
if (direction > 0) {
joint.SetLimits(limits.lower, limits.upper);
continue;
}
var a1 = limits.lower * -1;
var a2 = limits.upper * -1;
if (a2 > a1) {
joint.SetLimits(a1, a2);
} else {
joint.SetLimits(a2, a1);
}
// joint.SetAngle(joint.GetAngle() * -1);
}
}
}
};
RubeDoll.prototype.reposition = function(handPosition, direction) {
var oldPosition = this.getPosition();
var oldAngle = this.body.GetAngle();
var oldDirection = this.flipDirection;
// calls flip() at the end of Parent reposition()
Parent.prototype.reposition.call(this, handPosition, direction);
var differenceAngle = oldAngle - this.body.GetAngle();
//this.body.SetLinearVelocity(new Box2D.Common.Math.b2Vec2(0, 0));
var offset = Box2D.Common.Math.b2Math.SubtractVV(this.getPosition(), oldPosition);
var grabAngle = (this.options.grabAngle || 0.001);
for(var key in this.limbs) {
var limb = this.limbs[key];
// Setting position offset first (floor to hand)
var position = limb.GetPosition().Copy();
position.Add(offset);
limb.SetPosition(position);
// grabing local point to "rotate" around (x, y position transform only)
var localPoint = this.body.GetLocalPoint(limb.GetPosition().Copy());
// create rotation matrix from chest rotation difference
var mat = Box2D.Common.Math.b2Mat22.FromAngle(differenceAngle);
// matrix multiplication with local limb position
position = Box2D.Common.Math.b2Math.MulTMV(mat, localPoint);
// translating back to global position
var globalPoint = this.body.GetWorldPoint(position);
limb.SetPosition(globalPoint);
// relative limb rotating by chest rotation difference
var d = (oldDirection == direction) ? -1 : 1;
limb.SetAngle((limb.GetAngle() - differenceAngle) * d);
//limb.SetType(Box2D.Dynamics.b2Body.b2_staticBody);
//limb.SetLinearVelocity(new Box2D.Common.Math.b2Vec2(0, 0));
}
};
RubeDoll.prototype.setVelocities = function(options) {
Assert.number(options.linearVelocity.x, options.linearVelocity.y);
Assert.number(options.angularVelocity);
this.body.SetLinearVelocity(options.linearVelocity);
this.body.SetAngularVelocity(options.angularVelocity);
for(var name in this.limbs) {
this.limbs[name].SetLinearVelocity(options.linearVelocity);
}
};
RubeDoll.prototype.getPosition = function() {
return this.body.GetPosition().Copy();
};
RubeDoll.prototype.getHeadPosition = function() {
return this.limbs.head.GetPosition().Copy();
};
RubeDoll.prototype.setUpdateData = function(update) {
Parent.prototype.setUpdateData.call(this, update);
/*
for(var name in update.limbs) {
Assert.number(update.limbs[name].p.x, update.limbs[name].p.y);
Assert.number(update.limbs[name].a);
Assert.number(update.limbs[name].lv.x, update.limbs[name].lv.y);
Assert.number(update.limbs[name].av);
this.limbs[name].SetAwake(true);
this.limbs[name].SetPosition(update.limbs[name].p);
this.limbs[name].SetAngle(update.limbs[name].a);
this.limbs[name].SetLinearVelocity(update.limbs[name].lv);
this.limbs[name].SetAngularVelocity(update.limbs[name].av);
}
*/
}
RubeDoll.prototype.destroy = function() {
var world = this.body.GetWorld();
for (var name in this.limbs) {
world.DestroyBody(this.limbs[name]);
}
Parent.prototype.destroy.call(this);
};
return RubeDoll;
});

View file

@ -1,30 +1,125 @@
define([
"Game/" + GLOBALS.context + "/GameObjects/Item",
"Lib/Vendor/Box2D",
"Game/Config/Settings"
"Game/Config/Settings",
"Lib/Utilities/Assert"
],
function (Parent, Box2D, Settings) {
function (Parent, Box2D, Settings, Assert) {
"use strict";
function Skateboard(physicsEngine, uid, options) {
Parent.call(this, physicsEngine, uid, options);
}
Skateboard.prototype = Object.create(Parent.prototype);
Skateboard.prototype.createFixture = function () {
Assert.number(this.options.width, this.options.height);
Assert.number(this.options.weight);
var deckShape = new Box2D.Collision.Shapes.b2PolygonShape();
var w = this.options.width / Settings.RATIO;
var h = 2 / Settings.RATIO;
deckShape.SetAsOrientedBox(w / 2, h / 2, new Box2D.Common.Math.b2Vec2(0, -(4.5 / Settings.RATIO)));
var fixtureDef = new Box2D.Dynamics.b2FixtureDef();
fixtureDef.shape = deckShape;
var offset = 4,
factor = 80;
var density = ((this.options.weight + offset) / this.options.width / this.options.height) * factor;
fixtureDef.density = density;
fixtureDef.friction = Settings.ITEM_FRICTION;
fixtureDef.restitution = 0.2;
fixtureDef.isSensor = false;
this.body.CreateFixture(fixtureDef);
this.addWheel(
-8,
-2.5
);
this.addWheel(
7,
-2.5
);
};
Skateboard.prototype.addWheel = function(x, y) {
Assert.number(x, y);
var bodyDef = new Box2D.Dynamics.b2BodyDef();
bodyDef.type = Box2D.Dynamics.b2Body.b2_dynamicBody;
bodyDef.position.x = x / Settings.RATIO;
bodyDef.position.y = y / Settings.RATIO;
bodyDef.angle = 0;
var wheelShape = new Box2D.Collision.Shapes.b2CircleShape();
wheelShape.SetRadius(2.5 / Settings.RATIO);
wheelShape.SetLocalPosition(new Box2D.Common.Math.b2Vec2(x / Settings.RATIO, y / Settings.RATIO));
var fixtureDef = new Box2D.Dynamics.b2FixtureDef();
var offset = 4,
factor = 80;
var density = ((0.1 + offset) / 3 / 3) * factor;
fixtureDef.density = density;
fixtureDef.shape = wheelShape;
fixtureDef.restitution = 0.2;
fixtureDef.isSensor = false;
fixtureDef.friction = 0.0005;
this.body.CreateFixture(fixtureDef);
};
Skateboard.prototype.flip = function(direction) {
this.flipDirection = direction;
};
return Skateboard;
});
/*
define([
"Game/" + GLOBALS.context + "/GameObjects/Item",
"Lib/Vendor/Box2D",
"Game/Config/Settings",
"Lib/Utilities/Assert"
],
function (Parent, Box2D, Settings, Assert) {
"use strict";
function Skateboard(physicsEngine, uid, options) {
Parent.call(this, physicsEngine, uid, options);
this.wheels = [
this.addWheel(
options.x + 8,
options.y - 1.5
),
this.addWheel(
options.x - 8,
options.y - 1.5
)
this.addWheel(
options.x + 8,
options.y - 1.5
),
this.addWheel(
options.x - 8,
options.y - 1.5
)
];
}
Skateboard.prototype = Object.create(Parent.prototype);
Skateboard.prototype.createFixture = function () {
Assert.number(this.options.width, this.options.height);
Assert.number(this.options.weight);
var deckShape = new Box2D.Collision.Shapes.b2PolygonShape();
var w = this.options.width / Settings.RATIO;
@ -43,17 +138,18 @@ function (Parent, Box2D, Settings) {
fixtureDef.isSensor = false;
this.body.CreateFixture(fixtureDef);
}
};
Skateboard.prototype.addWheel = function(x, y) {
Assert.number(x, y);
var bodyDef = new Box2D.Dynamics.b2BodyDef();
var bodyDef = new Box2D.Dynamics.b2BodyDef();
bodyDef.type = Box2D.Dynamics.b2Body.b2_dynamicBody;
bodyDef.position.x = x / Settings.RATIO;
bodyDef.position.y = y / Settings.RATIO;
bodyDef.angle = 0;
var wheelShape = new Box2D.Collision.Shapes.b2CircleShape();
var wheelShape = new Box2D.Collision.Shapes.b2CircleShape();
wheelShape.SetRadius(1.5 / Settings.RATIO);
wheelShape.SetLocalPosition(new Box2D.Common.Math.b2Vec2(0, 0));
@ -64,18 +160,23 @@ function (Parent, Box2D, Settings) {
fixtureDef.density = density;
fixtureDef.shape = wheelShape;
fixtureDef.isSensor = false;
fixtureDef.friction = 0;
var wheelBody = this.body.GetWorld().CreateBody(bodyDef);
wheelBody.CreateFixture(fixtureDef);
var revoluteJointDef = new Box2D.Dynamics.Joints.b2RevoluteJointDef();
revoluteJointDef.enableMotor = false;
//var revoluteJointDef = new Box2D.Dynamics.Joints.b2RevoluteJointDef();
var revoluteJointDef = new Box2D.Dynamics.Joints.b2WeldJointDef();
//revoluteJointDef.enableMotor = false;
revoluteJointDef.Initialize(this.body, wheelBody, wheelBody.GetWorldCenter());
this.body.GetWorld().CreateJoint(revoluteJointDef);
// FIXME this means, that we will have bodies in the world, which must not be
// updated (wheels) because they are always connected to a body which will be updated.
revoluteJointDef.Initialize(this.body, wheelBody, wheelBody.GetWorldCenter());
var j = this.body.GetWorld().CreateJoint(revoluteJointDef);
// FIXME this means, that we will have bodies in the world, which must not be
// updated (wheels) because they are always connected to a body which will be updated.
return wheelBody;
};
@ -85,18 +186,13 @@ function (Parent, Box2D, Settings) {
// FIXME: implement body flip if necessary
};
Skateboard.prototype.throw = function(x, y) {
Parent.prototype.throw.call(this, x, y);
Skateboard.prototype.throw = function(options, carrierVelocity) {
Parent.prototype.throw.call(this, options, carrierVelocity);
for (var i = 0; i < this.wheels.length; i++) {
var body = this.wheels[i];
body.SetAwake(true);
var vector = new Box2D.Common.Math.b2Vec2(
x * Settings.MAX_THROW_FORCE / this.options.weight,
-y * Settings.MAX_THROW_FORCE / this.options.weight
);
body.SetLinearVelocity(vector);
this.accelerateBody(body, options, carrierVelocity);
}
};
@ -110,4 +206,5 @@ function (Parent, Box2D, Settings) {
return Skateboard;
});
});
*/

View file

@ -4,9 +4,11 @@ define([
],
function (Parent, Box2D) {
"use strict";
function SpectatorDoll(physicsEngine, uid, player) {
Parent.call(this, physicsEngine, uid);
//Parent.call(this, physicsEngine, uid);
}
SpectatorDoll.prototype = Object.create(Parent.prototype);
@ -31,6 +33,9 @@ function (Parent, Box2D) {
SpectatorDoll.prototype.update = function() {
};
SpectatorDoll.prototype.destroy = function() {
};
return SpectatorDoll;

View file

@ -3,22 +3,25 @@ define([
"Lib/Vendor/Box2D",
"Game/Config/Settings",
"Lib/Utilities/Exception",
"Lib/Utilities/NotificationCenter"
"Lib/Utilities/NotificationCenter",
"Lib/Utilities/Assert"
],
function (Parent, Box2D, Settings, Exception, Nc) {
function (Parent, Box2D, Settings, Exception, nc, Assert) {
"use strict";
function Tile(physicsEngine, uid, options) {
this.options = options;
Parent.call(this, physicsEngine, uid);
this.createPhysicTile(this.options);
Nc.trigger(Nc.ns.core.game.gameObject.add, 'fixed', this);
}
Tile.prototype = Object.create(Parent.prototype);
Tile.prototype.getBodyDef = function() {
Assert.number(this.options.x, this.options.y);
Assert.number(this.options.r);
var bodyDef = new Box2D.Dynamics.b2BodyDef();
bodyDef.type = Box2D.Dynamics.b2Body.b2_staticBody;
@ -27,7 +30,7 @@ function (Parent, Box2D, Settings, Exception, Nc) {
bodyDef.angle = (this.options.r || 0) * 90 * Math.PI / 180;
return bodyDef;
}
};
Tile.prototype.createPhysicTile = function (tile) {
var vertices = this.createVertices(tile);
@ -41,7 +44,7 @@ function (Parent, Box2D, Settings, Exception, Nc) {
fixtureDef.restitution = Settings.TILE_RESTITUTION;
fixtureDef.isSensor = false;
this.body.CreateFixture(fixtureDef);
}
};
Tile.prototype.createVertices = function (tile) {
var vs = [];
@ -102,22 +105,17 @@ function (Parent, Box2D, Settings, Exception, Nc) {
default:
throw new Exception("Tile Creation - no shape given");
break;
}
return vs;
}
};
Tile.prototype.mkArg = function (multiplier) {
return Settings.TILE_SIZE / 2 / Settings.RATIO * multiplier;
}
};
Tile.prototype.addVec = function (vs, m1, m2) {
return vs.push(new Box2D.Common.Math.b2Vec2(this.mkArg(m1), this.mkArg(m2)));
}
Tile.prototype.destroy = function() {
Nc.trigger(Nc.ns.core.game.gameObject.remove, 'fixed', this);
};
return Tile;

View file

@ -2,14 +2,17 @@ define([
"Game/Config/Settings",
"Lib/Vendor/Box2D",
"Lib/Utilities/NotificationCenter",
"Lib/Utilities/Abstract",
"Game/" + GLOBALS.context + "/Collision/Detector",
"Game/" + GLOBALS.context + "/GameObjects/Tile",
"Game/" + GLOBALS.context + "/GameObjects/Item",
"Game/" + GLOBALS.context + "/GameObjects/Items/Skateboard",
"Game/" + GLOBALS.context + "/GameObjects/Items/RagDoll",
"Game/" + GLOBALS.context + "/GameObjects/Items/Rube"
"Game/" + GLOBALS.context + "/GameObjects/Items/RubeDoll"
], function (Settings, Box2D, Nc, CollisionDetector, Tile, Item, Skateboard, RagDoll, Rube) {
], function (Settings, Box2D, nc, Abstract, CollisionDetector, Tile, Item, Skateboard, RagDoll, RubeDoll) {
"use strict";
function Level (uid, engine) {
this.uid = uid;
@ -17,87 +20,83 @@ define([
this.levelObject = null;
this.isLoaded = false;
this.load(this.uid);
this.spawnPoints = null;
}
Level.prototype.load = function (uid) {
var self = this;
var path = Settings.MAPS_PATH + uid + ".json"
this.loadLevelDataFromPath(path, function(levelData) {
self.levelData = levelData;
self.createTiles();
self.createItems();
self.isLoaded = true;
Nc.trigger(Nc.ns.core.game.events.level.loaded);
// FIXME: check if theres a security hazard here (user injected path)
var path = Settings.MAPS_PATH + uid + ".json";
this.loadLevelDataFromPath(path, function (levelData) {
self.setup(levelData);
});
}
};
Level.prototype.setup = function(levelData) { // jshint unused:false
this.isLoaded = true;
nc.trigger(nc.ns.core.game.events.level.loaded);
};
Level.prototype.createItems = function(options) {
for (var i = 0; i < options.length; i++) {
var uid = "item-" + i;
this.createItem(uid, options[i]);
}
};
Level.prototype.createItem = function(uid, options) {
switch(options.type) {
case 'skateboard':
case "skateboard":
return new Skateboard(this.engine, uid, options);
case 'ragdoll':
case "ragdoll":
return new RagDoll(this.engine, uid, options);
case 'rube':
return new Rube(this.engine, uid, options);
case "rubedoll":
return new RubeDoll(this.engine, uid, options);
default:
return new Item(this.engine, uid, options);
}
};
Level.prototype.createTiles = function(options) {
for (var i = 0; i < options.length; i++) {
new Tile(this.engine, "tile-" + i, options[i]);
}
};
Level.prototype.createSpawnPoints = function(points) {
this.spawnPoints = points;
};
Level.prototype.setupLayer = function(options, behind, referenceId) { // jshint unused:false
// will be extended (so far only in client)
};
Level.prototype.createContainer = function(options) { // jshint unused:false
// nothing to do here yet, in the future perhaps synchronize day/night graphics
};
Level.prototype.getRandomSpawnPoint = function() {
throw new Error("Level not loaded.");
if(!this.spawnPoints) {
return {
x: 150 + Math.random() * 300,
y: -500
};
}
var size = this.spawnPoints.length;
var object = this.spawnPoints[parseInt(Math.random() * (size -1), 10)];
return {
x: 150 + Math.random() * 300,
y: -500
x: object.x / Settings.TILE_RATIO,
y: object.y / Settings.TILE_RATIO
};
};
Level.prototype.destroy = function () {
/*
for (var key in this.gameObjects) {
for (var i = 0; i < this.gameObjects[key].length; i++) {
this.gameObjects[key][i].destroy();
}
}
*/
this.isLoaded = false;
}
/* Extended by TiledLevel
Level.prototype.createTiles = function () {
if (!this.levelData || !this.levelData.tiles || this.levelData.tiles.length < 1) {
throw "Level: Can't create physic tiles, no tiles found";
}
var tiles = this.levelData.tiles;
for (var i = 0; i < tiles.length; i++) {
var options = tiles[i];
//options.m = this.tileAtPositionExists(options.x, options.y - 1) ? "Soil" : "GrassSoil";
options.m = "Soil";
//this.gameObjects.fixed.push(
new Tile(this.engine, "tile-" + i, options);
//);
}
}
*/
/* Extended by TiledLevel
Level.prototype.createItems = function() {
if (!this.levelData || !this.levelData.items) {
return;
}
var items = this.levelData.items;
for (var i = 0; i < items.length; i++) {
var options = items[i];
var uid = "item-" + i;
var item = this.createItem(uid, options);
//this.gameObjects.animated.push(item);
};
};
*/
return Level;
})
});

View file

@ -3,115 +3,191 @@ define([
"Game/Config/Settings",
"Game/Config/ItemSettings",
"Lib/Vendor/Box2D",
"Lib/Utilities/Options",
"Lib/Utilities/OptionsHelper",
"Lib/Utilities/Exception",
"Lib/Utilities/NotificationCenter",
"Lib/Utilities/Assert",
"Game/Client/View/Abstract/Layer",
"Game/" + GLOBALS.context + "/Collision/Detector",
"Game/" + GLOBALS.context + "/GameObjects/Tile",
"Game/" + GLOBALS.context + "/GameObjects/Item",
"Game/" + GLOBALS.context + "/GameObjects/Items/Skateboard",
], function (Parent, Settings, ItemSettings, Box2D, Options, Exception, CollisionDetector, Tile, Item, Skateboard) {
], function (Parent, Settings, ItemSettings, Box2D, optionsHelper, Exception, nc, Assert, AbstractLayer, CollisionDetector, Tile, Item, Skateboard) {
// Public
"use strict";
function TiledLevel (path, engine) {
this.layerMapping = {
tiles: this.createTiles.bind(this),
items: this.createItems.bind(this),
spawnpoints: this.createSpawnPoints.bind(this)
//collision: this.createTiles.bind(this), collision renamed to tiles
};
this.levelData = null;
Parent.call(this, path, engine);
}
TiledLevel.prototype = Object.create(Parent.prototype);
TiledLevel.prototype.createTiles = function () {
if (!this.levelData) {
throw "Level: Can't create level, nothing found";
TiledLevel.prototype.setup = function(levelData) {
this.levelData = levelData;
var spawnpointsExists = levelData.layers.some(function(o) {
return o.name == AbstractLayer.ID.SPAWN;
});
if (!spawnpointsExists) {
console.warn("No layerMapping for level file layer: " + layerOptions.name);
return;
}
var collisionLayer = this.getLayer(this.levelData, "collision");
if(collisionLayer) {
for (var i = 0; i < collisionLayer.data.length; i++) {
var gid = collisionLayer.data[i];
if(gid === 0) continue;
var imagePath = this.getTileImagePath(gid);
var parts = imagePath.split("/");
var tileType = parts[parts.length - 1].split(".")[0].split("");
// FIXME rename s to shape, r to rotation etc.
var options = {
s: parseInt(tileType[0], 10),
r: parseInt(tileType[1], 10),
t: imagePath,
x: i % collisionLayer.width,
y: parseInt(i / collisionLayer.height , 10)
}
//this.gameObjects.fixed.push(
new Tile(this.engine, "tile-" + i, options);
//);
function getLayerId(name, i) {
var mapping = {
tiles: AbstractLayer.ID.TILE,
items: AbstractLayer.ID.ITEM,
spawnpoints: AbstractLayer.ID.SPAWN
};
if(mapping[name]) {
return mapping[name];
}
} else {
console.warn("Level: No collision Layer given");
return "layer-" + i + "-" + name;
}
}
TiledLevel.prototype.createItems = function() {
var objects = this.getLayer(this.levelData, "items").objects;
var spawnpointsFound = false,
lastLayerId = null;
// from spawnpoints to background
for (var i = levelData.layers.length - 1; i >= 0; i--) {
var layerOptions = levelData.layers[i];
layerOptions.z = i;
layerOptions.layerId = getLayerId(layerOptions.name, i);
if (layerOptions.name == AbstractLayer.ID.SPAWN) {
spawnpointsFound = true;
}
if (!spawnpointsFound) {
continue;
}
// Setting up spawnpoints and then all layers behind it
this.setupLayer(layerOptions, true, lastLayerId);
if(this.layerMapping[layerOptions.name]) {
this.layerMapping[layerOptions.name](layerOptions);
}
lastLayerId = layerOptions.layerId;
}
spawnpointsFound = false; // reset (used in mkLayer)
lastLayerId = AbstractLayer.ID.SPAWN;
// from spawnpoints to foreground
for (var i = 0; i < levelData.layers.length; i++) {
var layerOptions = levelData.layers[i];
layerOptions.z = i;
layerOptions.layerId = getLayerId(layerOptions.name, i);
if (layerOptions.name == AbstractLayer.ID.SPAWN) {
spawnpointsFound = true;
continue;
}
if (!spawnpointsFound) {
continue;
}
// Setting up all layers before
this.setupLayer(layerOptions, false, lastLayerId);
if(this.layerMapping[layerOptions.name]) {
this.layerMapping[layerOptions.name](layerOptions);
}
lastLayerId = layerOptions.layerId;
}
Parent.prototype.setup.call(this, levelData);
};
TiledLevel.prototype.createTiles = function(options) {
var data = options.data;
var tilesOptions = [];
for (var i = 0; i < data.length; i++) {
var gid = data[i];
if(gid === 0) continue;
var imagePath = this.getTileImagePath(gid);
var parts = imagePath.split("/");
var tileType = parts[parts.length - 1].split(".")[0].split("");
// FIXME rename s to shape, r to rotation etc.
var tileOptions = {
s: parseInt(tileType[0], 10),
r: parseInt(tileType[1], 10),
t: imagePath,
x: i % options.width,
y: parseInt(i / options.width , 10)
};
tilesOptions.push(tileOptions);
}
Parent.prototype.createTiles.call(this, tilesOptions);
};
TiledLevel.prototype.createItems = function(options) {
var objects = options.objects;
var itemsOptions = [];
for (var i = 0; i < objects.length; i++) {
var object = objects[i];
options = this.gatherOptions(objects[i]);
itemsOptions.push(options);
}
var options = this.gatherOptions(object);
Parent.prototype.createItems.call(this, itemsOptions);
};
var uid = "item-" + i;
var item = this.createItem(uid, options);
//this.gameObjects.animated.push(item);
};
TiledLevel.prototype.createSpawnPoints = function(options) {
var points = options.objects.map(function(o) {
return { x: o.x, y: o.y };
});
Parent.prototype.createSpawnPoints.call(this, points);
};
TiledLevel.prototype.gatherOptions = function(tiledObject) {
var options = {};
var options = this.getDefaultItemSettingsByName(tiledObject.name);
options.name = tiledObject.name;
options.rotation = tiledObject.rotation;
options.width = tiledObject.width / Settings.TILE_RATIO;
options.height = tiledObject.height / Settings.TILE_RATIO;
options.x = (tiledObject.x + tiledObject.width / 2) / Settings.TILE_RATIO;
options.x = (tiledObject.x + options.width / 2) / Settings.TILE_RATIO;
options.y = (tiledObject.y + options.height / 2) / Settings.TILE_RATIO;
if (!options.width) options.width = undefined;
if (!options.height) options.height = undefined;
var defaultOptions = this.getDefaultItemSettingsByName(options.name);
options = Options.merge(options, defaultOptions);
//options = Options.merge(tiledObject.properties, options);
// FIXME: check RAD vs. DEG for options.rotation = tiledObject.rotation;
return options;
};
TiledLevel.prototype.getDefaultItemSettingsByName = function(name) {
if(!name) {
throw new Exception('Item name cannot be be empty');
throw new Exception("Item name cannot be be empty");
}
if(ItemSettings[name] === undefined) {
throw new Exception('Item name (' + name + ') cannot be found in item list');
throw new Exception("Item name (" + name + ") cannot be found in item list");
}
var options = ItemSettings.Default;
options = Options.merge(ItemSettings[name], options);
return options;
return optionsHelper.merge(ItemSettings[name], ItemSettings.Default);
};
TiledLevel.prototype.getTileImagePath = function(gid) {
@ -122,35 +198,7 @@ define([
return tileset.tiles["" + (gid - offset)].image;
}
}
}
TiledLevel.prototype.getRandomSpawnPoint = function() {
if(!this.levelData) {
return Parent.prototype.getRandomSpawnPoint.call(this);
} else {
var spawnLayer = this.getLayer(this.levelData, "spawnpoints");
var size = spawnLayer.objects.length;
var object = spawnLayer.objects[parseInt(Math.random() * (size -1), 10)];
return {
x: object.x / Settings.TILE_RATIO,
y: object.y / Settings.TILE_RATIO
}
}
};
TiledLevel.prototype.getLayer = function(levelData, name) {
for (var i = 0; i < levelData.layers.length; i++) {
if(levelData.layers[i].name === name) {
return levelData.layers[i];
}
}
throw "Layer '" + name + "' not found.";
};
return TiledLevel;
})
});

View file

@ -5,7 +5,9 @@ define([
"Lib/Utilities/NotificationCenter"
],
function (Settings, Box2D, CollisionDetector, Nc) {
function (Settings, Box2D, CollisionDetector, nc) {
"use strict";
function Engine () {
this.world = new Box2D.Dynamics.b2World(
@ -13,33 +15,30 @@ function (Settings, Box2D, CollisionDetector, Nc) {
Settings.BOX2D_ALLOW_SLEEP
);
this.world.SetWarmStarting(true);
this.ground = null;
this.lastStep = Date.now();
this.worldQueue = [];
this.ncTokens = [
Nc.on(Nc.ns.channel.engine.worldQueue.add, this.addToWorldQueue, this)
nc.on(nc.ns.channel.engine.worldQueue.add, this.addToWorldQueue, this)
];
}
Engine.prototype.getWorld = function () {
return this.world;
}
Engine.prototype.getGround = function () {
return this.ground;
}
Engine.prototype.setCollisionDetector = function () {
var detector = new CollisionDetector();
this.world.SetContactListener(detector.getListener());
}
Engine.prototype.getWorldForRubeLoader = function() {
return this.world;
};
Engine.prototype.createBody = function (bodyDef) {
var body = this.world.CreateBody(bodyDef);
if(!this.ground) this.ground = body;
return body;
return this.world.CreateBody(bodyDef);
}
Engine.prototype.destroyBody = function (body) {
return this.world.DestroyBody(body);
}
Engine.prototype.addToWorldQueue = function(callback) {
@ -63,8 +62,8 @@ function (Settings, Box2D, CollisionDetector, Nc) {
}
Engine.prototype.destroy = function() {
nc.offAll(this.ncTokens);
delete this.world;
Nc.offAll(this.ncTokens);
};

View file

@ -1,16 +1,19 @@
define([
"Game/" + GLOBALS.context + "/GameObjects/Doll",
"Game/" + GLOBALS.context + "/Control/PlayerController",
"Game/Config/Settings",
"Lib/Utilities/NotificationCenter",
"Lib/Utilities/Exception",
"Lib/Utilities/ColorConverter",
"Game/" + GLOBALS.context + "/GameObjects/SpectatorDoll",
"Game/" + GLOBALS.context + "/GameObjects/Items/RagDoll"
"Game/" + GLOBALS.context + "/GameObjects/Items/RubeDoll"
],
function (Doll, PlayerController, Settings, nc, Exception, ColorConverter, SpectatorDoll, RubeDoll) {
function (Doll, Settings, Nc, Exception, SpectatorDoll, RagDoll) {
"use strict";
function Player (id, physicsEngine, user) {
function Player (id, physicsEngine, user, revealedGameController) {
this.stats = {
health: 100,
deaths: 0,
@ -19,18 +22,23 @@ function (Doll, Settings, Nc, Exception, SpectatorDoll, RagDoll) {
this.user = user;
this.physicsEngine = physicsEngine;
this.playerController = null;
this.playerController = null; // pre-initialise with null, because client/players don't get one
this.doll;
this.id = id;
this.isSpawned = false;
this.spawned = false;
this.holdingItem = null;
this.inBetweenRounds = true;
this.spectatorDoll = new SpectatorDoll(this.physicsEngine, "spectatorDoll-" + this.id, this);
Nc.trigger(Nc.ns.core.game.gameObject.add, 'animated', this);
this.revealedGameController = revealedGameController;
this.modifierActivated = false;
}
Player.prototype.getNickname = function() {
return this.user.options.nickname;
};
Player.prototype.getActiveDoll = function() {
if(this.isSpawned) {
if(this.spawned) {
return this.doll;
} else if (this.ragDoll) {
return this.ragDoll;
@ -41,9 +49,13 @@ function (Doll, Settings, Nc, Exception, SpectatorDoll, RagDoll) {
Player.prototype.spawn = function (x, y) {
this.doll = new Doll(this.physicsEngine, "doll-" + this.id, this);
this.doll.spawn(x, y);
this.isSpawned = true;
this.spawned = true;
}
Player.prototype.isSpawned = function() {
return this.spawned;
};
Player.prototype.getPosition = function () {
return this.getActiveDoll().getPosition();
}
@ -54,54 +66,73 @@ function (Doll, Settings, Nc, Exception, SpectatorDoll, RagDoll) {
Player.prototype.move = function (direction) {
if(!this.isSpawned) return false;
this.doll.move(direction);
if(!this.spawned) return false;
this.doll.move(direction, this.modifierActivated);
}
Player.prototype.stop = function () {
if(!this.isSpawned) return false;
if(!this.spawned) return false;
this.doll.stop();
}
Player.prototype.jump = function () {
if(!this.isSpawned) return false;
if(!this.spawned) return false;
this.doll.jump();
}
Player.prototype.jumpStop = function () {
if(!this.isSpawned) return false;
if(!this.spawned) return false;
this.doll.jumpStop();
}
Player.prototype.lookAt = function (x, y) {
if(!this.isSpawned) return false;
if(!this.spawned) return false;
// FIXME implement spectator movement here
this.doll.lookAt(x, y);
}
Player.prototype.activateModifier = function () {
if(!this.spawned) return false;
this.modifierActivated = true;
}
Player.prototype.deactivateModifier = function () {
if(!this.spawned) return false;
this.modifierActivated = false;
}
Player.prototype.grab = function(item) {
if(!this.isSpawned) return false;
if(!this.spawned) return false;
this.doll.grab(item);
item.beingGrabbed(this);
this.holdingItem = item;
};
Player.prototype.throw = function(x, y, item) {
if(!this.isSpawned) return false;
this.doll.throw(item, x, y);
Player.prototype.throw = function(options, item) {
if(!this.spawned) return false;
this.doll.throw(item, options);
item.beingReleased(this);
this.holdingItem = null;
};
Player.prototype.kill = function(killedByPlayer, ragDollId) {
if(!this.isSpawned) return false;
if(!this.spawned) return false;
// FIXME: do something better then just respawn in GameController
if(this.holdingItem) {
this.throw(0, 0, this.holdingItem)
var options = {
x: 0,
y: 0,
av: 0
};
this.throw(options, this.holdingItem)
}
// prepare for creating the ragdoll
var converter = new ColorConverter();
var primaryColor = converter.getColorByName(this.getNickname());
var options = {
x: this.getPosition().x * Settings.RATIO,
y: this.getPosition().y * Settings.RATIO,
@ -110,21 +141,23 @@ function (Doll, Settings, Nc, Exception, SpectatorDoll, RagDoll) {
image: "chest.png",
name: "RagDoll",
rotation: 0,
type: "ragdoll",
type: "rubedoll",
weight: 3,
width: 5,
height: 12
height: 12,
primaryColor: primaryColor,
direction: this.doll.lookDirection
};
var ragDoll = new RagDoll(this.physicsEngine, "ragDoll-" + this.id + "-" + ragDollId, options);
ragDoll.setVelocities(this.doll.getVelocities());
var rubeDoll = new RubeDoll(this.physicsEngine, "rubeDoll-" + this.id + "-" + ragDollId, options);
rubeDoll.setVelocities(this.doll.getVelocities());
this.isSpawned = false;
this.spawned = false;
this.doll.destroy();
this.doll = null;
this.ragDoll = ragDoll;
this.ragDoll = rubeDoll;
};
Player.prototype.update = function () {
@ -140,16 +173,23 @@ function (Doll, Settings, Nc, Exception, SpectatorDoll, RagDoll) {
Player.prototype.destroy = function () {
Nc.trigger(Nc.ns.core.game.gameObject.remove, 'animated', this);
// FIXME add destroy nc hook
if(this.holdingItem) {
this.throw(0, 0, this.holdingItem);
var options = {
x: 0,
y: 0,
av: 0
};
this.throw(options, this.holdingItem);
}
this.spectatorDoll.destroy();
// doll destoys itself at the end cause its a gameobject
// but on userLeft, the player has to destroy it.
if(this.doll) {
this.doll.destroy();
this.doll.destroy();
}
if(this.playerController) {
@ -157,9 +197,13 @@ function (Doll, Settings, Nc, Exception, SpectatorDoll, RagDoll) {
}
}
Player.prototype.setPlayerController = function(playerController) {
this.playerController = playerController;
}
Player.prototype.setInBetweenRounds = function(inBetweenRounds) {
this.inBetweenRounds = inBetweenRounds;
};
Player.prototype.isInBetweenRounds = function() {
return this.inBetweenRounds;
};
return Player;
});

View file

@ -1,4 +1,7 @@
define(function () {
define([
],
function () {
function User (id, options) {
this.id = id;

View file

@ -0,0 +1,20 @@
define([
"Lib/Utilities/Exception"
],
function (Exception) {
"use strict";
function Abstract() {
}
Abstract.prototype.addMethod = function(methodName, params) {
this.prototype[methodName] = function() {
throw new Exception("Abstract method", this, methodName + "(" + params.join(', ') + ") not overwritten.");
}
}
return Abstract;
});

View file

@ -0,0 +1,21 @@
define([
"Lib/Utilities/Exception"
],
function (Exception) {
"use strict";
var Assert = {};
Assert.number = function() {
for (var i = 0; i < arguments.length; i++) {
if(isNaN(parseFloat(arguments[i]))) {
throw new Exception("Assert: not a number ", JSON.stringify(arguments));
}
}
};
return Assert;
});

View file

@ -0,0 +1,22 @@
define([
"Lib/Utilities/Core/Extensions"
],
function (Parent) {
//"use strict";
console.checkpoint = function (s) {
console.log(" \033[32mbeep - \033[0m" + s);
}
console.warn = function (s) {
console.log(" \033[33mwarn - \033[0m" + s);
}
console.error = function (s) {
console.log(" \033[31merror - \033[0m" + s);
}
});

View file

@ -0,0 +1,8 @@
define([
"Lib/Utilities/Core/Extensions"
],
function (Parent) {
"use strict";
});

View file

@ -0,0 +1,83 @@
define([
"Lib/Vendor/CryptoJS"
],
function (CryptoJS) {
"use strict";
function ColorConverter() {
this.sin = 0;
var palette = [
0x634c72,
0x724c5e,
0x787950,
0x507971,
0x506a79,
0x8c423c,
0x557e4a,
0x436785,
0xa62423,
0x427f87,
0x472e1a,
0x4d667c,
0x2a3c49,
0x7c7e2b,
0x3b3c21,
0x263c27,
0x7e897e,
0xb55014,
0x978c32,
0x739137,
0x46824f,
0x19b0b4,
0x1c1eb1,
0xccb206,
0x433e20,
0x201a13,
0x145396,
0x313d08,
0xb7a345,
0xdc168a,
0x310505,
0x051631,
];
/*
var element, color;
var start = 5;
var step = 4;
var max = 16;
for(var r=start; r<max; r+=step) {
for(var g=start; g<max; g+=step) {
for(var b=start; b<max; b+=step) {
color = r.toString(16)
+ r.toString(16)
+ g.toString(16)
+ g.toString(16)
+ b.toString(16)
+ b.toString(16);
palette.push(parseInt(color, 16));
}
}
}*/
this.palette = palette;
}
ColorConverter.prototype.getColorByName = function(name) {
name = CryptoJS.MD5(name).toString();
var ac = 0;
for(var c = 0; c < name.length; c++) {
ac += name.charCodeAt(c) * 3;
}
return this.palette[ac % this.palette.length];
}
return ColorConverter;
});

View file

@ -0,0 +1,24 @@
define([
],
function () {
"use strict";
String.prototype.toUpperCaseFirstChar = function () {
var f = this.charAt(0).toUpperCase();
return f + this.substr(1);
}
String.prototype.pad = function (max, alignLeft) {
var string = this.substring(0, max - 1);
var spaces = new Array( max - string.length + 1 ).join(" ");
if(alignLeft) {
return string + spaces;
} else {
return spaces + string;
}
}
});

View file

@ -17,7 +17,8 @@ function() {
this.message = message.join(" ");
Error.call(this, this.message);
var e = Error.call(this, this.message);
console.error(e.stack);
}
Exception.prototype = Object.create(Error.prototype);

View file

@ -1,26 +0,0 @@
define([
],
function() {
String.prototype.toUpperCaseFirstChar = function () {
var f = this.charAt(0).toUpperCase();
return f + this.substr(1);
}
if(GLOBALS.context == "Channel") {
console.checkpoint = function (s) {
console.log(' \033[32mbeep - \033[0m' + s);
}
console.warn = function (s) {
console.log(' \033[33mwarn - \033[0m' + s);
}
console.error = function (s) {
console.log(' \033[31merror - \033[0m' + s);
}
}
});

334
app/Lib/Utilities/Matrix.js Normal file
View file

@ -0,0 +1,334 @@
define([
],
/*
Stolen from Pixi V2
*/
function () {
"use strict";
/**
* The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis.
*
* @class Point
* @constructor
* @param x {Number} position of the point on the x axis
* @param y {Number} position of the point on the y axis
*/
var Point = function(x, y)
{
/**
* @property x
* @type Number
* @default 0
*/
this.x = x || 0;
/**
* @property y
* @type Number
* @default 0
*/
this.y = y || 0;
};
/**
* Creates a clone of this point
*
* @method clone
* @return {Point} a copy of the point
*/
Point.prototype.clone = function()
{
return new Point(this.x, this.y);
};
/**
* Sets the point to a new x and y position.
* If y is omitted, both x and y will be set to x.
*
* @method set
* @param [x=0] {Number} position of the point on the x axis
* @param [y=0] {Number} position of the point on the y axis
*/
Point.prototype.set = function(x, y)
{
this.x = x || 0;
this.y = y || ( (y !== 0) ? this.x : 0 ) ;
};
// constructor
Point.prototype.constructor = Point;
/**
* @author Mat Groves http://matgroves.com/ @Doormat23
*/
/**
* The Matrix class is now an object, which makes it a lot faster,
* here is a representation of it :
* | a | b | tx|
* | c | d | ty|
* | 0 | 0 | 1 |
*
* @class Matrix
* @constructor
*/
var Matrix = function()
{
/**
* @property a
* @type Number
* @default 1
*/
this.a = 1;
/**
* @property b
* @type Number
* @default 0
*/
this.b = 0;
/**
* @property c
* @type Number
* @default 0
*/
this.c = 0;
/**
* @property d
* @type Number
* @default 1
*/
this.d = 1;
/**
* @property tx
* @type Number
* @default 0
*/
this.tx = 0;
/**
* @property ty
* @type Number
* @default 0
*/
this.ty = 0;
};
/**
* Creates a Matrix object based on the given array. The Element to Matrix mapping order is as follows:
*
* a = array[0]
* b = array[1]
* c = array[3]
* d = array[4]
* tx = array[2]
* ty = array[5]
*
* @method fromArray
* @param array {Array} The array that the matrix will be populated from.
*/
Matrix.prototype.fromArray = function(array)
{
this.a = array[0];
this.b = array[1];
this.c = array[3];
this.d = array[4];
this.tx = array[2];
this.ty = array[5];
};
/**
* Creates an array from the current Matrix object.
*
* @method toArray
* @param transpose {Boolean} Whether we need to transpose the matrix or not
* @return {Array} the newly created array which contains the matrix
*/
Matrix.prototype.toArray = function(transpose)
{
if(!this.array) this.array = new Float32Array(9);
var array = this.array;
if(transpose)
{
array[0] = this.a;
array[1] = this.b;
array[2] = 0;
array[3] = this.c;
array[4] = this.d;
array[5] = 0;
array[6] = this.tx;
array[7] = this.ty;
array[8] = 1;
}
else
{
array[0] = this.a;
array[1] = this.c;
array[2] = this.tx;
array[3] = this.b;
array[4] = this.d;
array[5] = this.ty;
array[6] = 0;
array[7] = 0;
array[8] = 1;
}
return array;
};
/**
* Get a new position with the current transformation applied.
* Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering)
*
* @method apply
* @param pos {Point} The origin
* @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input)
* @return {Point} The new point, transformed through this matrix
*/
Matrix.prototype.apply = function(pos, newPos)
{
newPos = newPos || new Point();
newPos.x = this.a * pos.x + this.c * pos.y + this.tx;
newPos.y = this.b * pos.x + this.d * pos.y + this.ty;
return newPos;
};
/**
* Get a new position with the inverse of the current transformation applied.
* Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input)
*
* @method applyInverse
* @param pos {Point} The origin
* @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input)
* @return {Point} The new point, inverse-transformed through this matrix
*/
Matrix.prototype.applyInverse = function(pos, newPos)
{
newPos = newPos || new Point();
var id = 1 / (this.a * this.d + this.c * -this.b);
newPos.x = this.d * id * pos.x + -this.c * id * pos.y + (this.ty * this.c - this.tx * this.d) * id;
newPos.y = this.a * id * pos.y + -this.b * id * pos.x + (-this.ty * this.a + this.tx * this.b) * id;
return newPos;
};
/**
* Translates the matrix on the x and y.
*
* @method translate
* @param {Number} x
* @param {Number} y
* @return {Matrix} This matrix. Good for chaining method calls.
**/
Matrix.prototype.translate = function(x, y)
{
this.tx += x;
this.ty += y;
return this;
};
/**
* Applies a scale transformation to the matrix.
*
* @method scale
* @param {Number} x The amount to scale horizontally
* @param {Number} y The amount to scale vertically
* @return {Matrix} This matrix. Good for chaining method calls.
**/
Matrix.prototype.scale = function(x, y)
{
this.a *= x;
this.d *= y;
this.c *= x;
this.b *= y;
this.tx *= x;
this.ty *= y;
return this;
};
/**
* Applies a rotation transformation to the matrix.
* @method rotate
* @param {Number} angle The angle in radians.
* @return {Matrix} This matrix. Good for chaining method calls.
**/
Matrix.prototype.rotate = function(angle)
{
var cos = Math.cos( angle );
var sin = Math.sin( angle );
var a1 = this.a;
var c1 = this.c;
var tx1 = this.tx;
this.a = a1 * cos-this.b * sin;
this.b = a1 * sin+this.b * cos;
this.c = c1 * cos-this.d * sin;
this.d = c1 * sin+this.d * cos;
this.tx = tx1 * cos - this.ty * sin;
this.ty = tx1 * sin + this.ty * cos;
return this;
};
/**
* Appends the given Matrix to this Matrix.
*
* @method append
* @param {Matrix} matrix
* @return {Matrix} This matrix. Good for chaining method calls.
*/
Matrix.prototype.append = function(matrix)
{
var a1 = this.a;
var b1 = this.b;
var c1 = this.c;
var d1 = this.d;
this.a = matrix.a * a1 + matrix.b * c1;
this.b = matrix.a * b1 + matrix.b * d1;
this.c = matrix.c * a1 + matrix.d * c1;
this.d = matrix.c * b1 + matrix.d * d1;
this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx;
this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty;
return this;
};
/**
* Resets this Matix to an identity (default) matrix.
*
* @method identity
* @return {Matrix} This matrix. Good for chaining method calls.
*/
Matrix.prototype.identity = function()
{
this.a = 1;
this.b = 0;
this.c = 0;
this.d = 1;
this.tx = 0;
this.ty = 0;
return this;
};
return Matrix;
});

View file

@ -4,8 +4,10 @@ define([
function (Exception) {
"use strict";
function populate(obj, path) {
path = path || "Nc.ns";
path = path || "nc.ns";
for(var key in obj) {
if(!obj.hasOwnProperty(key)) continue;
if(obj[key] === null) {
@ -21,35 +23,56 @@ function (Exception) {
this.topics = {};
this.subUid = -1;
var i = 0;
this.ns = {
client: {
pointerLock: {
request: null,
change: null
},
view: {
layer: {
createAndInsert: null,
levelSizeUpdate: null
},
mesh: {
create: null,
add: null,
remove: null,
update: null
update: null,
addFilter: null,
removeFilter: null,
swapMeshIndexes: null,
swapMeshes: null
},
animatedMesh: {
create: null
},
playerInfo: {
healthBar: {
createAndAdd: null,
remove: null,
update: null
},
playerArrow: {
createAndAdd: null,
update: null
},
preloadBar: {
update: null
},
fullscreen: {
display: {
change: null
},
debugMode: {
toggle: null
},
events: {
ready: null
gameStats: {
toggle: null,
kill: null,
update: null
},
swiper: {
swipe: null,
end: null
}
},
input: {
@ -61,9 +84,16 @@ function (Exception) {
}
},
game: {
gameInfo: {
events: {
render: null,
destroy: null
},
gameStats: {
toggle: null
}
},
zoomIn: null,
zoomOut: null,
zoomReset: null
},
to: {
server: {
@ -75,9 +105,9 @@ function (Exception) {
},
core: {
game: {
gameObject: {
worldUpdateObjects: {
add: null,
remove: null
remove: null,
},
events: {
level: {
@ -107,8 +137,10 @@ function (Exception) {
},
game: {
player: {
killed: null
}
killed: null,
clearFingerPrints: null
},
}
},
engine: {
@ -162,17 +194,20 @@ function (Exception) {
};
populate(this.ns);
}
NotificationCenter.prototype.validate = function(topic) {
if (topic === undefined) {
throw new Exception("Topic not registered in nc. See stack trace.");
}
if (typeof topic === 'object') {
throw new Exception("Topic bad format " + JSON.stringify(topic));
}
if (topic.indexOf("Nc.ns") !== 0) {
throw new Exception("Topic bad format, does not begin with Nc.ns. : " + topic);
if (topic.indexOf("nc.ns") !== 0) {
throw new Exception("Topic bad format, does not begin with nc.ns. : " + topic);
}
};
@ -181,7 +216,7 @@ function (Exception) {
this.validate(topic);
if (!this.topics[topic]) {
console.warn("No such topic " + topic + ". Could not trigger. arguments: " + arguments.join);
//console.warn("No such topic " + topic + ". Could not trigger. arguments: " + arguments.join);
}
var args = Array.prototype.slice.call(arguments, 1);
@ -214,18 +249,24 @@ function (Exception) {
NotificationCenter.prototype.off = function (token) {
if(token && token.constructor === Array) {
this.offAll(token);
return;
}
for(var m in this.topics) {
if (this.topics[m]) {
for(var i = 0, j = this.topics[m].length; i < j; i++) {
if (this.topics[m][i].token === token) {
this.topics[m].splice(i, 1);
return token;
return;
}
}
}
}
}
// should be treated as a private function - use nc.off(Array);
NotificationCenter.prototype.offAll = function (tokens) {
for (var i = 0; i < tokens.length; i++) {
this.off(tokens[i]);

View file

@ -3,19 +3,22 @@ define([
],
function (Exception) {
"use strict";
function Options() {
function OptionsHelper() {
}
Options.prototype.merge = function(options, preset) {
// FIXME we could actually use Object.assign() for merging here
OptionsHelper.prototype.merge = function(options, preset) {
if(!preset && !options) {
throw new Exception("Options requires objects");
throw new Exception("OptionsHelper requires objects");
}
if(preset.constructor !== Object && options.constructor !== Object) {
throw new Exception("Options requires objects");
throw new Exception("OptionsHelper requires objects");
}
if(!preset || preset.constructor !== Object) {
@ -41,7 +44,7 @@ function (Exception) {
if(options[key].constructor !== Object) {
preset[key] = options[key];
} else {
preset[key] = Options.prototype.merge.call(this, options[key], preset[key]);
preset[key] = OptionsHelper.prototype.merge.call(this, options[key], preset[key]);
}
}
}
@ -49,6 +52,6 @@ function (Exception) {
return preset;
}
return new Options();
});
return new OptionsHelper();
});

View file

@ -5,6 +5,8 @@ define([
function (Parser, Exception) {
"use strict";
var Helper = {}
Helper.encodeCommand = function (command, options) {

View file

@ -3,6 +3,8 @@ define([
function () {
"use strict";
var Parser = {};
Parser.encode = function (message) {

Some files were not shown because too many files have changed in this diff Show more