Dynamic Tentacle Class


(Marko Cetinic) #1

Hi guys.

I created a small Tentacle class which follows given entity (mouse x,y in this case). It is also able to detect collision. You can see the example here

package
{
	import flash.geom.Point;
	import net.flashpunk.Entity;
	import net.flashpunk.FP;
	import net.flashpunk.utils.Draw;
	import net.flashpunk.utils.Input;
	import net.flashpunk.utils.Key;
	
	/**
	 * ...
	 * @author Marko Cetinic
	 */
	public class Tentacle extends Entity
	{	
		public static const TYPE:String = "tentacle";
		public static const TENTICLE_COLOR:uint = 0xCDBE7A;
		    		
		protected var _target:Entity;
		
		protected var _distance:int;
		protected var _maxDistance:int;
		
		protected var _speed:int;
		
		protected var _waveHeight:int;
		protected var _maxWaveHeight:int;
		
		protected var _waveLenght:int;
		protected var _maxWaveLenght:int;
		
		protected var _tentacleRadius:int;
		
		/**
             * Tentacle growt direction. +1 to grow out, -1 to shrink
		 * 
		 * @see changeGrowthDirection()
           */
		protected var _growthDirection:int=1;
		
		protected var _tentacleArr:Array;
		
		/**
         * Helper x coordinate point
		 * 
		 * @see returnSineWavePoint()
          */
		private var _x:int;
		
		/**
         * Helper y coordinate point
		 * 
		 * @see returnSineWavePoint()
         */
		private var _y:int;
		
		/**
		 * Tentacle class constructor.
		 *
		 * @param target Tearget to hit with tentacle.
		 * @param distance Tentacle distance.
		 * @param speed Tentcle creation speed.
		 * @param tentacleRadius Tentacle elem radius.
		 * @param waveHeight Amplitude or Wave height.
		 * @param waveLength Period or Wave length.
		 *
		 */		
		public function Tentacle(target:Entity, distance:int, speed:int=2, waveHeight:int=6, waveLenght:int=20, tentacleRadius:int=5)
		{
			super();
			
			this._target = target;
			
			this._speed = speed;
			
			this._maxDistance = distance;
			this._maxDistance = _maxDistance / _speed;
			this._distance = 0;
			
			this._waveHeight = waveHeight;
			this._maxWaveHeight = this._waveHeight;
			
			this._waveLenght = waveLenght;
			this._maxWaveLenght = this._waveLenght;
			
			this._tentacleRadius = tentacleRadius;
		}
		
		/**
		 * Change the growth direction of tentacle
		 */
		public function changeGrowthDirection():void 
		{
			this._growthDirection *= -1;
		}
		
		/**
		 * Check for any tenticle collison.
		 * 
		 * @param	entity Entity that could collide with tenticle.
		 * @return  TRUE if enitiy collides with tenticle, else FALSE.
		 */
		public function checkForCollision(entity:Entity):Boolean
		{			
			for each(var collisionElem:Entity in this._tentacleArr)
				if (collisionElem.collideTypes(entity.type, collisionElem.x, collisionElem.y) != null)
				{
					return true;
					break;
				}
			
			return false;
		}
		/**
		 * Returns sinus wave tentacle point. ( y = A * sin(B/x) + yInit ).
		 *
		 * @param speed Speed of the entity movement.
		 * @param waveHeight Amplitude or Wave height.
		 * @param waveLength Period or Wave length.
		 * @param waveLength Y coordinate starting position
		 * 
		 * @return New sinus wave point.
		 *
		 */
		protected function returnSineWavePoint(speed:int, waveHeight:int, waveLength:int, yStartPosition:int):Point
		{
			this._x += speed;
			this._y = (waveHeight * Math.sin(this._x / waveLength)) + yStartPosition;
			
			var followX:int = this._target.x + this._target.halfWidth;
			var followY:int = this._target.y + this._target.halfHeight;
			
			var deltaX:int = followX - this.x;
			var deltaY:int = followY - this.y;
			
			var bearing:int = Math.atan2(deltaY, deltaX) * 180 / Math.PI;
			
			var rotation:Number = bearing * Math.PI / 180;
			
			var rX:int = Math.cos(rotation) * (this._x - this.x) - Math.sin(rotation) * (this._y - this.y) + this.x;
			var rY:int = Math.sin(rotation) * (this._x - this.x) + Math.cos(rotation) * (this._y - this.y) + this.y;
			
			return new Point(rX, rY);
		}
		
		override public function render():void
		{	
			super.render();
			
			var collisionEntity:Entity;
			
			//remove all tenticle entites from the last render
			for each(collisionEntity in _tentacleArr)
				this.world.remove(collisionEntity);
			
			_tentacleArr = new Array;
			
			//Draw new tentacle
			var sineWavePoint:Point;
			
			for (var theta:Number = 0; theta < this._distance; theta += 1)
			{
				sineWavePoint = returnSineWavePoint(this._speed, this._waveHeight, this._waveLenght, this.y);
				
				Draw.circlePlus(sineWavePoint.x, sineWavePoint.y, this._tentacleRadius, 0xC8B188, 1, true, 1);
				
				if (theta % (this._tentacleRadius * 2) == 0)
				{	
					collisionEntity = new Entity;
					
					collisionEntity.x = sineWavePoint.x;
					collisionEntity.y = sineWavePoint.y;
			
					collisionEntity.setHitbox(this._tentacleRadius * 2, this._tentacleRadius * 2, this._tentacleRadius, this._tentacleRadius);

					_tentacleArr.push(collisionEntity);
			
					this.world.add(collisionEntity);
				}
			}

			//If players X position smaller than max distance start shrinking the tentacle
			if (this._distance >= this._maxDistance || this._distance < 0)
				this._growthDirection *= -1;
			
			if (this._distance < 0)
			{
				this._waveHeight = Math.random() * this._maxWaveHeight + this._maxWaveHeight - 3;
				this._waveLenght = Math.random() * this._maxWaveLenght + this._maxWaveLenght - 2;
			}
			
			this._distance += this._growthDirection;
			
			//helpers for returnSineWavePoint function
			this._x = this.x;
			this._y = this.y;
		}
	}
}