- uploading 1.1 in tags
[mootools.git] / Misc / Physics.js
blob1ff88ceaf7afcb3965602ce10ce38c9a20cb4587
1 var Physics = new Class({\r
2 \r
3         options: {\r
4                 onComplete: Class.empty,\r
5                 onStart: Class.empty,\r
6                 onStep: Class.empty,\r
7                 gravity: 1,\r
8                 restitution: 0.6,\r
9                 friction: 0.9,\r
10                 unit: 'px',\r
11                 fps: 30,\r
12                 airFriction: false,\r
13                 blockers: []\r
14         },\r
16         initialize: function(element, container, options){\r
17                 this.setOptions(options);\r
18                 this.element = $(element);\r
19                 this.container = $(container);\r
20                 this.velocity = {'x': 0, 'y': 0};\r
21                 this.position = {};\r
22                 this.oldPosition = {};\r
23                 this.oldVelocity = {};\r
24                 this.position.x = this.oldPosition.x = this.element.getStyle('left').toInt();\r
25                 this.position.y = this.oldPosition.y = this.element.getStyle('top').toInt();\r
26                 this.blockers = $$(this.options.blockers);\r
27         },\r
28         step: function(){\r
29                 this.oldPosition.x = this.position.x;\r
30                 this.oldPosition.y = this.position.y;\r
31                 this.fireEvent('onStep');\r
32                 this.velocity.y += this.options.gravity;\r
33                 this.position.x += this.velocity.x;\r
34                 this.position.y += this.velocity.y;\r
35                 var onGround = false;\r
36                 var element = {};\r
37                 var container = {};\r
38                 element.width = this.element.offsetWidth;\r
39                 element.height = this.element.offsetHeight;\r
40                 element.top = this.position.y;\r
41                 element.left = this.position.x;\r
42                 element.right = element.left + element.width;\r
43                 element.bottom = element.top + element.height;\r
44                 container.width = this.container.offsetWidth;\r
45                 container.height = this.container.offsetHeight;\r
46                 this.blockers.each(function(blocker){\r
47                         var collision = false;\r
48                         var block = {};\r
49                         block.left = blocker.getStyle('left').toInt();\r
50                         block.right = block.left + blocker.offsetWidth;\r
51                         block.top = blocker.getStyle('top').toInt();\r
52                         block.bottom = block.top + blocker.offsetHeight;\r
53                         if (element.right > block.left && element.left < block.right && element.bottom > block.top && element.top < block.bottom){ //collision area\r
54                                 if (element.top < block.top && this.velocity.y > 0){ //touches top part of the blocker\r
55                                         this.position.y = block.top - element.height;\r
56                                         this.velocity.y *= -this.options.restitution;\r
57                                         if (!this.options.airFriction) this.velocity.x *= this.options.friction;\r
58                                         collision = true;\r
59                                         blocker.fireEvent('collisionTop', this.element);\r
60                                         onGround = true;\r
61                                 } else if (element.bottom > block.bottom && this.velocity.y < 0){ //touches bottom part of the blocker\r
62                                         this.position.y = block.bottom;\r
63                                         this.velocity.y *= -this.options.restitution;\r
64                                         collision = true;\r
65                                         blocker.fireEvent('collisionBottom', this.element);\r
66                                 } else if (element.left < block.left && this.velocity.x > 0){ //touches left part of the blocker\r
67                                         this.position.x = block.left - element.width;\r
68                                         this.velocity.x *= -this.options.restitution;\r
69                                         collision = true;\r
70                                         blocker.fireEvent('collisionLeft');\r
71                                 } else if (element.right > block.right && this.velocity.x < 0){ //touches right part of the blocker\r
72                                         this.position.x = block.right;\r
73                                         this.velocity.x *= -this.options.restitution;\r
74                                         collision = true;\r
75                                         blocker.fireEvent('collisionRight', this.element);\r
76                                 }\r
77                         }\r
78                         if (collision) blocker.fireEvent('collision', this.element);\r
79                 }, this);\r
80                 if (this.position.y + element.height > container.height){ //touches bottom\r
81                         this.position.y = container.height - element.height;\r
82                         this.velocity.y *= -this.options.restitution;\r
83                         if (!this.options.airFriction) this.velocity.x *= this.options.friction;\r
84                         onGround = true;\r
85                         this.container.fireEvent('collisionBottom', this.element);\r
86                 }\r
87                 if (onGround) {\r
88                         this.onGround = true;\r
89                         this.element.fireEvent('ground');\r
90                 } else {\r
91                         this.element.fireEvent('air');\r
92                         this.onGround = false;\r
93                 }\r
94                 if (this.position.y < 0){ //touches top\r
95                         this.position.y = 0;\r
96                         this.velocity.y *= -this.options.restitution;\r
97                         this.onTop = true;\r
98                 } else {\r
99                         this.onTop = false;\r
100                 }\r
101                 if (this.position.x + element.width > container.width){ //touches right\r
102                         this.position.x = container.width - element.width;\r
103                         this.velocity.x *= -this.options.restitution;\r
104                         this.onRight = true;\r
105                 } else {\r
106                         this.onRight = false;\r
107                 }\r
108                 if (this.position.x < 0){ //touches left\r
109                         this.position.x = 0;\r
110                         this.velocity.x *= -this.options.restitution;\r
111                         this.onLeft = true;\r
112                 } else {\r
113                         this.onLeft = false;\r
114                 }\r
115                 if (this.options.airFriction){\r
116                         this.velocity.y *= this.options.friction;\r
117                         this.velocity.x *= this.options.friction;\r
118                 }\r
119                 this.element.setStyles({\r
120                         'left': this.position.x,\r
121                         'top': this.position.y\r
122                 });\r
123         },\r
125         start: function(){\r
126                 this.fireEvent('onStart');\r
127                 this.timer = this.step.periodical(Math.round(1000/this.options.fps), this);\r
128                 return this;\r
129         },\r
131         force: function(velx, vely){\r
132                 this.position.x = this.element.getStyle('left').toInt();\r
133                 this.position.y = this.element.getStyle('top').toInt();\r
134                 this.velocity.x += velx;\r
135                 this.velocity.y += vely;\r
136         },\r
138         stop: function(){\r
139                 this.timer = $clear(this.timer);\r
140                 this.fireEvent('onComplete');\r
141         }\r
143 });\r
145 Physics.implement(new Events);\r
146 Physics.implement(new Options);