A Flash Developer Resource Site

Results 1 to 7 of 7

Thread: [CS3] hitTestPoint help in platformer

  1. #1
    Junior Member
    Join Date
    Jul 2008
    Posts
    4

    [CS3] hitTestPoint help in platformer

    I'm trying to create a platformer character object that I can use over and over again. I've tried revising this several times now, and I can't get hitTestPoint to work reliably trying to land after jumping-- sometimes I'll end up where I want to be, sometimes I'll be slightly lower than I should be, sometimes I'll fall through the ground and never stop. Is this logic correct? I've added a "for" statement to check for a collision everytime a pixel is moved, and it still doesn't work. My level is actually drawn out as line objects and layed out on integer x,y coordinates, so I'm at a loss. Any ideas?

    Code:
    package
    {
    	import flash.events.*;
    	import flash.display.*;
    	import flash.ui.Keyboard;
    	import flash.geom.*;
    	import World;
    	import Ob;
    	
    	public class MoveCharacter extends MovieClip
    	{
    		public var xspeed:Number;
    		public var yspeed:Number;
    		public var gravity:Number;
    		public var ylimit:Number;
    		public static var level:Ob;
    		public var world:World;
    		
    		private var jump:Number;
    		
    		private var hitwalll:Boolean = false;
    		private var hitwallr:Boolean = false;
    		private var hitwallt:Boolean = false;
    		private var hitwallb:Boolean = false;
    		
    		private var pressup:Boolean = false;
    		private var jumping:Boolean = false;
    		private var walkl:Boolean = false;
    		private var walkr:Boolean = false;
    		private var crouch:Boolean = false;
    		
    		private var irun:Number = 0;
    		private var ijump:Number = 0;
    		private var icollide:Number = 0;
    					
    		public function MoveCharacter()
    		{
    			this.addEventListener(Event.ADDED_TO_STAGE, onStageReady)
    			function onStageReady(e:Event):void
    			{
    				removeEventListener(Event.ADDED_TO_STAGE, onStageReady);
    				trace("MoveCharacter defined and initialized");
    		
    				level = new Ob();
    				world = new World();
    				stage.addChild(world);
    				world.x = 0; world.y = 0;
    				stage.addChild(level);
    				level.x = -2000; level.y = -1825;
    			
    				stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
    				stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
    				stage.addEventListener(Event.ENTER_FRAME, moveAround);
    			
    				function keyDownHandler(event:KeyboardEvent):void
    				{
    					switch (event.keyCode)
    					{
    						case Keyboard.UP:
    							pressup = true;
    							break;
    						case Keyboard.DOWN:
    							crouch =  true;
    							break;
    						case Keyboard.LEFT:
    							walkl = true;
    							break;
    						case Keyboard.RIGHT:
    							walkr = true;
    							break;
    					}
    				}
    				function keyUpHandler(event:KeyboardEvent):void
    				{
    					switch (event.keyCode)
    					{
    						case Keyboard.UP:
    							pressup = false;
    							break;
    						case Keyboard.DOWN:
    							crouch =  false;
    							break;
    						case Keyboard.LEFT:
    							walkl = false;
    							break;
    						case Keyboard.RIGHT:
    							walkr = false;
    							break;
    					}
    				}
    				function moveAround(event:Event):void
    				{
    					var thiswidth:Number = width;
    					var thisheight:Number = height;
    					var thisx:Number = x;
    					var thisy:Number = y;
    					var pointtop:Point = new Point(Math.round(thisx), Math.round(thisy) - Math.round((thisheight / 2))); 
    					var pointbottom:Point = new Point (Math.round(thisx), Math.round(thisy) + Math.round((thisheight / 2)));
    					var pointleft:Point = new Point (Math.round(thisx) - Math.round((thiswidth / 2)), Math.round(thisy));
    					var pointright:Point =	new Point (Math.round(thisx) + Math.round((thiswidth / 2)), Math.round(thisy));
    					
    					if (level.hitTestPoint(pointright.x, pointright.y, true) == true)
    					{
    						hitwallr = true;
    					}
    					if (level.hitTestPoint(pointleft.x, pointleft.y, true) == true)
    					{
    						hitwalll = true;
    					}
    					if (level.hitTestPoint(pointtop.x, pointtop.y, true) == true)
    					{
    						hitwallt = true;
    					}
    					
    					if (walkr)
    					{
    						if(!jumping)
    						{
    							if (irun == 0 || irun >= 12)
    							{
    								gotoAndPlay(3);
    								irun = 0;
    							}
    						irun++;
    						}
    						scaleX= 1;
    						if (!hitwallr)
    						{
    							level.x-=xspeed;
    						}
    						hitwallr = false;
    					}
    					
    					else if(walkl)
    					{
    						if(!jumping)
    						{
    							if (irun == 0 || irun >= 12)
    							{
    								gotoAndPlay(3);
    								irun = 0;
    							}
    						irun++;
    						}
    						scaleX= -1;
    						if (!hitwalll)
    						{
    							level.x+=xspeed;
    						}
    						hitwalll = false;
    					}
    					else 
    					{
    						if (!jumping)
    						{
    							gotoAndStop(3);
    						}
    					}
    					
    					if(pressup && !jumping)
    					{
    						jumping = true;
    						yspeed = 15;
    						ylimit =Math.round( -1*(yspeed * 1.5));
    						gravity = 1;
    						level.y += yspeed;
    					}
    					else if (jumping)
    					{						
    						jump = yspeed - gravity;
    				
    						if (jump < ylimit)
    						{
    							jump = ylimit;
    						}
    						for (icollide=0; icollide <= Math.abs(jump); icollide++)
    						{
    							trace(jump);
    							if (jump >= 0)
    							{
    								if (level.hitTestPoint(pointbottom.x, pointbottom.y, true) == true)
    								{
    									hitwallb = true;
    									jumping = false;
    									gotoAndStop(3);
    									trace("hit");
    									return;
    								}
    									level.y+=1;
    									trace(level.y);
    							}
    							else if (jump < 0)
    							{
    								if (level.hitTestPoint(pointbottom.x, pointbottom.y, true) == true)
    								{
    									hitwallb = true;
    									jumping = false;
    									gotoAndStop(3);
    									trace("hit");
    									return;
    								}
    									level.y -=1;
    									trace(level.y);
    							}
    						}
    						if (ijump == 0 || ijump >= 12)
    						{
    							gotoAndPlay(15);
    							ijump = 0;
    						}
    							ijump++;
    							gravity++;
    					}
    				}
    			}
    		}
    	}
    }

  2. #2
    Junior Member
    Join Date
    Jul 2008
    Posts
    4
    Any ideas? I still can't make heads or tails of this. It's like hitTestPoint doesn't work reliably.

  3. #3
    Senior Member tonypa's Avatar
    Join Date
    Jul 2001
    Location
    Estonia
    Posts
    8,227
    Problems with hittest normally arise when speed increases. In theory when you move the point by 1 pixel, it will work perfectly. However, in games you very rarely move something by 1 pixel, the speed could be for example 10 pixels. While the collision is detected at final position, it skips all the points between last and new position. If you have wall of 8 pixels, it can be skipped easily.

  4. #4
    Junior Member
    Join Date
    Jul 2008
    Posts
    4
    I'm currently checking the collision at every single vertical pixel movement, using a "for" loop every frame. I've tried other methods, such as checking every frame, despite yspeed increases, as you've described above, and that just yielded worse results. As it stands now, the character will reliably hit the ground, except when jumping to a different leveled platform (higher or lower), and that will work perfectly about 25% of the time, well enough 50%, and infinite fall about 25%. Is the only solution to have my character jump slower, so collision testing might become more reliable?

    Code:
    for (icollide=0; icollide <= Math.abs(jump); icollide++)
    						{
    							trace(jump);
    							if (jump >= 0)
    							{
    								if (level.hitTestPoint(pointbottom.x, pointbottom.y, true) == true)
    								{
    									hitwallb = true;
    									jumping = false;
    									gotoAndStop(3);
    									trace("hit");
    									return;
    								}
    									level.y+=1;
    									trace(level.y);
    							}
    							else if (jump < 0)
    							{
    								if (level.hitTestPoint(pointbottom.x, pointbottom.y, true) == true)
    								{
    									hitwallb = true;
    									jumping = false;
    									gotoAndStop(3);
    									trace("hit");
    									return;
    								}
    									level.y -=1;
    									trace(level.y);
    							}
    						}

  5. #5
    Senior Member tonypa's Avatar
    Join Date
    Jul 2001
    Location
    Estonia
    Posts
    8,227
    I have never managed to get hittest work well enough for platform game (thats why I prefer tiles). Anyway, are you using only 1 point? If that is the center point of char then it may even work but whole game looks weird as most chars do not look like points. By doing hittest with char center, it can move half its width or height into walls.

  6. #6
    Junior Member
    Join Date
    Jun 2008
    Posts
    18
    4 points can be used to get rough hittest. One for each side. Also when character is falling it will skip more pixels and yield in error.

  7. #7
    Junior Member
    Join Date
    Jul 2008
    Posts
    4
    I'm using 4 points and checking collision every 1px on a level designed on integer coordinates, but hittestpoint simply doesn't seem to be reliable. I've decided to abandon movieclip collision detection methods, and use bitmaps with hittest. Seems to be just one of the many reasons to do this.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center