1 /**
  2  * The Render Engine
  3  * Fixture object
  4  *
  5  * @fileoverview A fixture is a box which either defines a solid area or a trigger.
  6  *
  7  * @author: Brett Fattori (brettf@renderengine.com)
  8  *
  9  * @author: $Author: bfattori@gmail.com $
 10  * @version: $Revision: 1562 $
 11  *
 12  * Copyright (c) 2011 Brett Fattori (brettf@renderengine.com)
 13  *
 14  * Permission is hereby granted, free of charge, to any person obtaining a copy
 15  * of this software and associated documentation files (the "Software"), to deal
 16  * in the Software without restriction, including without limitation the rights
 17  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 18  * copies of the Software, and to permit persons to whom the Software is
 19  * furnished to do so, subject to the following conditions:
 20  *
 21  * The above copyright notice and this permission notice shall be included in
 22  * all copies or substantial portions of the Software.
 23  *
 24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 25  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 27  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 28  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 29  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 30  * THE SOFTWARE.
 31  *
 32  */
 33 
 34 // The class this file defines and its required classes
 35 R.Engine.define({
 36     "class":"R.objects.Fixture",
 37     "requires":[
 38         "R.objects.Object2D",
 39         "R.components.Render",
 40         "R.math.Point2D",
 41         "R.math.Rectangle2D"
 42     ]
 43 });
 44 
 45 /**
 46  * @class A fixture is a simple rectangular area used to define either
 47  *             a solid area, or a trigger for a callback.
 48  * @param rect {R.math.Rectangle2D} The box which defines the area of the fixture
 49  *    @param visible {Boolean} <code>true</tt> to render a visible rectangle for the fixture
 50  * @constructor
 51  * @extends R.objects.Object2D
 52  */
 53 R.objects.Fixture = function () {
 54     return R.objects.Object2D.extend({
 55 
 56         editing:false,
 57         boxRect:null,
 58         type:null,
 59         action:null,
 60         visible:false,
 61 
 62         /** @private */
 63         constructor:function (rect, visible) {
 64             this.base("Fixture");
 65             this.editing = false;
 66             this.visible = visible;
 67             this.setPosition(R.math.Point2D.create(rect.getTopLeft()));
 68             rect.setTopLeft(0, 0);
 69             this.setBoundingBox(rect);
 70             this.type = R.objects.Fixture.TYPE_COLLIDER;
 71             this.action = "";
 72         },
 73 
 74         /**
 75          * Get the properties object for this collision box.
 76          * @return {Object}
 77          */
 78         getProperties:function () {
 79             var self = this;
 80             var prop = this.base(self);
 81             return $.extend(prop, {
 82                 "Width":[function () {
 83                     return self.boxRect.get().w;
 84                 }, function (i) {
 85                     self.setWidth(i);
 86                 }, true],
 87                 "Height":[function () {
 88                     return self.boxRect.get().h;
 89                 }, function (i) {
 90                     self.setHeight(i);
 91                 }, true],
 92                 "Type":[function () {
 93                     return self.type == R.objects.Fixture.TYPE_COLLIDER ? "TYPE_COLLIDER" : "TYPE_TRIGGER";
 94                 }, function (i) {
 95                     self.setType(i == "TYPE_COLLIDER" ? R.objects.Fixture.TYPE_COLLIDER : R.objects.Fixture.TYPE_TRIGGER);
 96                 }, false],
 97                 "Action":[function () {
 98                     return self.action.substring(0, 25);
 99                 }, typeof LevelEditor !== "undefined" && self.type == R.objects.Fixture.TYPE_TRIGGER ?
100                 { "editor":function () {
101                     LevelEditor.showScriptDialog(this, "Action", self.action);
102                 }, "fn":function (i) {
103                     self.setAction(i);
104                 } } : null,
105                     (typeof LevelEditor !== "undefined" && self.type == R.objects.Fixture.TYPE_TRIGGER)]
106             });
107         },
108 
109         /**
110          * Update the player within the rendering context.  This draws
111          * the shape to the context, after updating the transform of the
112          * object.  If the player is thrusting, draw the thrust flame
113          * under the ship.
114          *
115          * @param renderContext {R.rendercontexts.AbstractRenderContext} The rendering context
116          * @param time {Number} The engine time in milliseconds
117          * @param dt {Number} The delta between the world time and the last time the world was updated
118          *          in milliseconds.
119          */
120         update:function (renderContext, time, dt) {
121             renderContext.pushTransform();
122             this.base(renderContext, time, dt);
123 
124             if (this.visible) {
125                 var color = this.type == R.objects.Fixture.TYPE_COLLIDER ? "0,255,255" : "255,0,0";
126 
127                 if (this.editing) {
128                     renderContext.setFillStyle("rgba(" + color + ",0.85)");
129                 } else {
130                     renderContext.setFillStyle("rgba(" + color + ",0.4)");
131                 }
132 
133                 renderContext.drawFilledRectangle(this.boxRect);
134 
135                 if (this.editing) {
136                     renderContext.setLineStyle("white");
137                     renderContext.setLineWidth(2);
138                 } else {
139                     renderContext.setLineWidth(1);
140                 }
141 
142                 renderContext.drawText(this.boxRect.topLeft(), this.type == R.objects.Fixture.TYPE_COLLIDER ?
143                     "solid" : "trigger");
144                 renderContext.drawRectangle(this.boxRect);
145             }
146 
147             renderContext.popTransform();
148         },
149 
150         /**
151          * Get the type of collision box object being represented.
152          * @return {Number}
153          */
154         getType:function () {
155             return this.type;
156         },
157 
158         /**
159          * Set the type of collision box this will be.
160          * @param type {Number} One of either: {@link #TYPE_COLLIDER} or {@link #TYPE_TRIGGER}.
161          */
162         setType:function (type) {
163             this.type = type;
164             if (type == R.objects.CollisionBox.TYPE_TRIGGER) {
165                 this.setName("TriggerBlock");
166             } else {
167                 this.setName("CollisionBlock");
168             }
169         },
170 
171         /**
172          * Sets the script which will be called when the block is triggered.
173          * @param action {String} The action script
174          */
175         setAction:function (action) {
176             this.action = action;
177         },
178 
179         /**
180          * Set the size of the collision box
181          * @param width {Number} The width of the box in pixels
182          * @param height {Number} The height of the box in pixels
183          */
184         setBoxSize:function (width, height) {
185             this.boxRect.setDims(width, height);
186             this.setBoundingBox(this.boxRect);
187         },
188 
189         /**
190          * Set the width of the collision box
191          * @param width {Number} The width of the box in pixels
192          */
193         setWidth:function (width) {
194             this.boxRect.setWidth(width);
195             this.setBoundingBox(this.boxRect);
196         },
197 
198         /**
199          * Set the height of the collision box
200          * @param height {Number} The height of the box in pixels
201          */
202         setHeight:function (height) {
203             this.boxRect.setHeight(height);
204             this.setBoundingBox(this.boxRect);
205         },
206 
207         /**
208          * Set the editing mode of the object, used by the LevelEditor
209          * @private
210          */
211         setEditing:function (state) {
212             this.editing = state;
213         },
214 
215         /**
216          * Queried by the LevelEditor to determine if an object is editable
217          * @private
218          */
219         isEditable:function () {
220             return true;
221         },
222 
223         /**
224          * Set the visibility state of the fixture.
225          * @param state {Boolean}
226          * @private
227          */
228         setVisible:function (state) {
229             this.visible = state;
230         }
231 
232     }, /** @scope R.objects.Fixture.prototype */{ // Static
233         /**
234          * Get the class name of this object
235          * @return The string <tt>R.objects.Fixture</tt>
236          * @type String
237          */
238         getClassName:function () {
239             return "R.objects.Fixture";
240         },
241 
242         /**
243          * This type of box impedes movement through it
244          * @type {Number}
245          */
246         TYPE_COLLIDER:1,
247 
248         /**
249          * This type of box triggers an action
250          * @type {Number}
251          */
252         TYPE_TRIGGER:2
253     });
254 
255 }