1 /** 2 * The Render Engine 3 * 2D platformer mover 4 * 5 * @fileoverview A transform component for movement around a tile map as a "platformer". 6 * 7 * @author: Brett Fattori (brettf@renderengine.com) 8 * 9 * @author: $Author: bfattori $ 10 * @version: $Revision: 1555 $ 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.components.transform.PlatformMover2D", 37 "requires":[ 38 "R.components.Transform2D", 39 "R.math.Math2D", 40 "R.struct.RayInfo" 41 ] 42 }); 43 44 /** 45 * @class A transform component to move around a tile map like the old "platformer" games 46 * 47 * @param name {String} Name of the component 48 * @param tileMap {R.resources.types.TileMap} The tile map to move around in 49 * @param priority {Number} Between 0.0 and 1.0, with 1.0 being highest 50 * 51 * @extends R.components.Transform2D 52 * @constructor 53 * @description Creates a transform component. 54 */ 55 R.components.transform.PlatformMover2D = function () { 56 "use strict"; 57 return R.components.Transform2D.extend(/** @scope R.components.transform.PlatformMover2D.prototype */{ 58 59 tileMap:null, 60 moveVec:null, 61 gravity:null, 62 tileSize:null, 63 64 /** @private */ 65 constructor:function (name, tileMap, priority) { 66 this.base(name, priority || 1.0); 67 this.tileMap = tileMap; 68 this.moveVec = R.math.Vector2D.create(0, 0); 69 this.gravity = R.math.Vector2D.create(0, 0.2); 70 if (tileMap instanceof R.resources.types.TileMap) { 71 this.tileSize = Math.max(tileMap.getBaseTile().getBoundingBox().w, 72 tileMap.getBaseTile().getBoundingBox().h); 73 } 74 }, 75 76 destroy:function () { 77 this.moveVec.destroy(); 78 this.gravity.destroy(); 79 this.base(); 80 }, 81 82 /** 83 * Releases the component back into the pool for reuse. See {@link PooledObject#release} 84 * for more information. 85 */ 86 release:function () { 87 this.base(); 88 this.tileMap = null; 89 this.moveVec = null; 90 this.tileSize = null; 91 }, 92 93 setTileMap:function (tileMap) { 94 if (!tileMap.getBaseTile()) { 95 return; 96 } 97 98 this.tileMap = tileMap; 99 this.tileSize = Math.max(tileMap.getBaseTile().getBoundingBox().w, 100 tileMap.getBaseTile().getBoundingBox().h); 101 }, 102 103 getTileMap:function () { 104 return this.tileMap; 105 }, 106 107 getTileSize:function () { 108 return this.tileSize; 109 }, 110 111 getMoveVector:function () { 112 return this.moveVec; 113 }, 114 115 setMoveVector:function (ptOrX, y) { 116 this.moveVec.set(ptOrX, y); 117 }, 118 119 getGravity:function () { 120 return this.gravity; 121 }, 122 123 setGravity:function (xOrPt, y) { 124 this.gravity.set(xOrPt, y); 125 }, 126 127 /** 128 * This method is called by the game object to run the component, 129 * updating its state. 130 * 131 * @param renderContext {R.rendercontexts.AbstractRenderContext} The context the component will render within. 132 * @param time {Number} The global engine time 133 * @param dt {Number} The delta between the world time and the last time the world was updated 134 * in milliseconds. 135 */ 136 execute:function (renderContext, time, dt) { 137 if (this.tileMap) { 138 var bBox = this.getGameObject().getBoundingBox(), oldPos = R.clone(this.getPosition()), 139 newPos = R.clone(oldPos), testPt = R.clone(bBox.getCenter()), 140 mNormal = R.clone(this.moveVec).normalize(), rayInfo, 141 dir = R.math.Vector2D.create(0, 0); 142 143 // If movement along the X coordinate isn't zero, we want to test for collisions along the axis. 144 // We'll cast a ray in the direction of movement, one tile width long, from the center of the 145 // bounding box 146 if (this.moveVec.x != 0) { 147 // We want to cast a ray along the X axis of movement 148 testPt.setX((newPos.x + testPt.x) + (bBox.getHalfWidth() * mNormal.x)); 149 dir.set(this.moveVec.x, 0).normalize().mul(this.tileSize); 150 rayInfo = R.struct.RayInfo.create(testPt, dir); 151 152 R.resources.types.TileMap.castRay(this.tileMap, rayInfo, renderContext); 153 154 // There's something in the direction of horizontal movement, can't go that way 155 if (rayInfo.shape) { 156 this.moveVec.setX(0); 157 newPos.x -= rayInfo.data.x; 158 } 159 160 rayInfo.destroy(); 161 } 162 163 // Add in gravity 164 if (!this.gravity.equals(R.math.Vector2D.ZERO)) { 165 this.moveVec.add(this.gravity); 166 167 // We'll cast two rays, one from the left side of the bounding box, 168 // the other from the right. If either collides, zero out gravity. 169 // -- First one 170 testPt.set(newPos.x + 1, newPos.y + bBox.h); 171 dir.set(this.moveVec).normalize().mul(3); 172 rayInfo = R.struct.RayInfo.create(testPt, dir); 173 174 R.resources.types.TileMap.castRay(this.tileMap, rayInfo, renderContext); 175 176 // If a collision occurs, stop gravity and adjust position 177 if (rayInfo.shape) { 178 this.moveVec.setY(0); 179 newPos.y -= rayInfo.data.y; 180 } else { 181 // -- Second one 182 testPt.set(newPos.x + bBox.w - 1, newPos.y + bBox.h); 183 rayInfo = R.struct.RayInfo.create(testPt, dir); 184 R.resources.types.TileMap.castRay(this.tileMap, rayInfo, renderContext); 185 if (rayInfo.shape) { 186 this.moveVec.setY(0); 187 newPos.y -= rayInfo.data.y; 188 } 189 } 190 191 rayInfo.destroy(); 192 } 193 194 this.setPosition(newPos.add(this.moveVec)); 195 196 dir.destroy(); 197 oldPos.destroy(); 198 newPos.destroy(); 199 testPt.destroy(); 200 } 201 202 this.base(renderContext, time, dt); 203 } 204 205 }, { /** @scope R.components.transform.PlatformMover2D.prototype */ 206 207 /** 208 * Get the class name of this object 209 * @return {String} "R.components.transform.PlatformMover2D" 210 */ 211 getClassName:function () { 212 return "R.components.transform.PlatformMover2D"; 213 } 214 215 }); 216 }