flash actionscript:
Brenda, You've hit upon one of the weaknesses of MovieClip.hitTest() -- and of course there are strengths and weaknesses to just about anything. An alternate approach is to measure the ball movie clip's _x and _y properties and compare them against fixed values that represent the position of the wall(s). In other words, if there's a vertical wall at 400 pixels (that is, its _x property is 400), then you can check if the ball's _x property is greater than or equal to 400. If true, then your ball has crossed the line. David stiller (at) quip (dot) net "Luck is the residue of good design."
I have a ball that is being hitTest against a wall. The ball increases in speed (pixels per frame) the longer it's on stage. Generally, the higher the number is that makes the ball move, the more likely it is to pass through the wall without the hitTest doing what it's supposed to do. I do believe I understand why this happens (has to finish it's current movement and sometimes that movement makes it go beyone the wall and therefore beyond the hitTest, right?). My question is, is there any way around this? Thanks!! Brenda
Hi David, sounds like a good alternative... although I do wish the hitTest behaved in such a way that it would trigger the minute it touched the opposing object irregardless of what point the moving object is in it's current movement. Oh well... maybe in a future version. Thank you for your reply!! Brenda
Well in order to ensure that the ball hits the wall and doesn't go past the wall you would have to make a prediction on the where the ball is going to get drawn next. You should know how fast the ball is going and then know if it going to go past the wall in advance. If it is indeed going to go past you can simply make it hit the wall and then turn around. HitTest will be completely useless to you in this case though. Although I guess if you aren't planning on using too much dynamic stuff you could just hardcode the values like David suggested. --Nick
Personally, I prefer the 'sub-sampling' method: you do multiple incremental hitTests per frame. This way you can have comlex and odd shaped objects and collisions still are easy. NOTE: if all you want to do is detect wether the ball has hit the edge of the screen, the comparison method is MUCH more efficient.
Hi Nick and beally, thank you for your replies. Beally, how do you set up incremental hit tests? Would you do this by placing it in an onEnterFrame function? I like your idea, I'm just not all too sure how to approach it. Thanks... Brenda P.S. Also, when you say 'comparison' method do you mean checking to see if the x (or y) axis of the ball is equal to the x (or y) axis of the other object?
You could do something like this: checkHitAgainst(ballInstance,wallInstance) function checkHitAgainst(someMC,hitObj){ for(i=0;someMC._parent['watcher'+i]!=undefined;i++){} someMC._parent.createEmptyMovieClip('watcher'+i,someMC._parent.getNextHighestDe pth()); _root['watcher'+i].onEnterFrame = function(){ oldx = thisx; oldy = thisy; thisx = someMC._x; thisy = someMC._y; if(thisx!=oldx ||thisy!=oldy){ trace('change!'); with (this){ moveTo(oldx,oldy); lineTo(thisx,thisy); } if(this.hitTest(hitObj)){ trace('hit!'); //Do something here! } } } }
NS- is getNextHighestDepth() an MX 2004 method? very useful it would be, but can't find it in my documentation (MX, not '04). 'B' I'm sure NSurveyers works great, but if you don't understand it(like me :-) stick this on a movieclip, and create a movie clip on _root instance name: 'collided_mc'. onClipEvent (load) { speed=5; b=_root.ball xTarget=random(550); yTarget=random(400); } onClipEvent (enterFrame) { //basic 2D 360 degree game movement, based on angle and speed angle=-Math.atan2((_x-xTarget),(_y-yTarget))/(Math.PI/180);//get angle xSpeed = speed*Math.sin(angle*(Math.PI/180));//calculate X,Y movement ySpeed = speed*Math.cos(angle*(Math.PI/180)); //SUBSAMPLE COLLISION DETECTION sampleRate=1;//distance between each sample(hitTest) sub_xSpeed = (xSpeed/(speed/sampleRate));//calculate hitTest interval distance sub_ySpeed = (ySpeed/(speed/sampleRate)); for(sub_i=1 ; sub_i<=speed ; sub_i+=sampleRate){ _x += sub_xSpeed;//move forward one step _y -= sub_ySpeed; if(_root.collide_mc.hitTest(_x,_y,true)){//if no collision detected _x -= sub_xSpeed*1.1;//move back one step, with slight buffer _y += sub_ySpeed*1.1; break;//stop movement } } }
For my script, all I have done, is have a movieclip see when the balls x or y coordinate change. Then I have the old coordinate plotted and the new coordinate plotted using the mc's drawing methods. Next, I saw if that line 'touched' the wall.
It is, except I don' t use MX 2004. It returns the next highest depth found in a movieclip. Here's an alternative: MovieClip.prototype.getNextHighestDepth = function() { var max = -1661992961; for (var stuff in this) { if(this[stuff].getDepth()!=undefined){ max = Math.max(max, this[stuff].getDepth()); } } return max+1; };
Ah, interesting, I'll have to try it out, because if(this.hitTest(hitObj)) I think will hitTest two bounding boxes, which won't work for the level, and even though you have a line, it doesn't hitTest along the line, it hitTests a box around the line. getNextHighestDepth - nice! I just tried something like that, and I'm curious, why do you start at that massive negative depth instead of 0? Is there a built in range depth like that?
I realized that it would be the bounding boxes. I was planning to use a for loop to calculate each point on the line, but I believe that, it will slow down the flash player, because it would need to check on each enterFrame. I guess I could just add that for loop inside the if(this.hitTest(hitObj)){...} I used that seemingly random number, because I'm pretty sure it's one lower than the lowest depth. I figured it out, by doing: createEmptyMovieClip('someMC',-10000000000000); trace(someMC.getDepth()); And my script for getNextHighestDepth might be wrong. So, if you really want a working way, upgrade to 2004.
beally and NSurveyor, thank you so much for your replies. I will try both of your methods out and see which one works better for what I'm trying to accomplish. Thanks again!!
For my script, you'd probably want to use this function instead: function checkHitAgainst(someMC, hitObj) { for (i=0; someMC._parent['watcher'+i] != undefined; i++) { } someMC._parent.createEmptyMovieClip('watcher'+i, someMC._parent.getNextHighestDepth()); _root['watcher'+i].onEnterFrame = function() { oldx = thisx; oldy = thisy; thisx = someMC._x; thisy = someMC._y; if (thisx != oldx || thisy != oldy) { trace("change!"); with (this) { moveTo(oldx, oldy); lineTo(thisx, thisy); } if (this.hitTest(hitObj)) { dist = Math.sqrt(Math.pow(oldx-thisx, 2)+Math.pow(oldy-thisy, 2)); distH = thisx-oldx; distV = thisy-oldy; for (i=0; i<=dist; i++) { px = oldx+distH/i; py = oldy+distV/i; if (hitObj.hitTest(px, py)) { trace("hit!"); break; //Do something here! } } } } }; }
Don't see what you're looking for? Try a search.
|