Home Tutorials Forums Articles Blogs Movies Library Employment Press
Old 07-23-2012, 07:02 PM   #1
santanoa
Dual Screen Empowered
 
santanoa's Avatar
 
Join Date: Jul 2010
Location: Israel
Posts: 258
Default [AS3] Hiding part of rotated rectangle

Hey guys,

I'm trying to simulate a light ray (which you can assume is just a rotated rectangle) hitting a wall (another rectangle, also could be rotated). I've gotten the collision detection working, but am not sure how to make the light 'stop' when it hits the wall. How would I 'cut off' the part of the light ray which is past the wall and only leave the first part visible?

Maybe something to do with masks, but I'm clueless.

Thanks again!

Last edited by santanoa; 07-24-2012 at 01:58 PM.
santanoa is offline   Reply With Quote
Old 07-28-2012, 02:07 PM   #2
-:)lauri
Senior Member
 
Join Date: Aug 2008
Location: Helsinki, Finland
Posts: 1,184
Default

Something like this might work:
ActionScript Code:
// create mask say "maskSprite" // check if circle is off the area on the right side if(ray.getBounds(this).right > rightEdge) {     // position mask sprite left to the edge value on the right     maskSprite.x = rightEdge;     // position mask sprite top to the top of the ray     maskSprite.x = ray.getBounds(this).top;     // set mask to the ray;     ray.mask = maskSprite; }
-:)lauri is offline   Reply With Quote
Old 07-29-2012, 06:23 PM   #3
santanoa
Dual Screen Empowered
 
santanoa's Avatar
 
Join Date: Jul 2010
Location: Israel
Posts: 258
Default

Thanks for the reply.

I like the way you are using the mask, but the problem is the both the light ray and the wall can be rotated at any angle. the ray is supposed to represent light being reflected by a mirror.

I have been thinking that I might be able to accomplish what I want by resizing the light ray so that it is slightly past where it hits the wall. For example, if the ray is hitting the wall's left edge, the ray's height will be modified so it is slightly to right of the left edge. The amount should be enough to account for rotating of the ray so that no corners show. Now I just need to figure out the math.
santanoa is offline   Reply With Quote
Old 07-29-2012, 11:13 PM   #4
-:)lauri
Senior Member
 
Join Date: Aug 2008
Location: Helsinki, Finland
Posts: 1,184
Default

The idea I'd try to implement here would be to draw filled parabola shape as full circle as needed and in right direction related to the ray object depending on how much the ray object is inside of "rightEdge" object. And then use the drawn parabola object as a mask of the ray object.

I haven't tested this code below yet but I have commented it so you may get at least the purpose of the lines of it.

ActionScript Code:
function createMask():void {     // number of points to project     // to the circumference of the     // ray object     var points:uint = 20     // angle step between each point     var step:Number = Math.PI * 2 / points;     // line object for drawing parabola     var line:Sprite = new Sprite();     // fill color for parabola     line.graphics.beginFill(0x000000);     // variable to save first point of     // the line of the parabola     var p:Point;     // loop trough points     for(var i:uint = 0; i < points; i++)     {         // new angle         var angle:Number = step * i;         // projects a point components from the         // registration point of the ray object to         // it's circumference         var dx:Number = ray.x + Math.cos(angle) * ray.width * .5;         var dy:Number = ray.y + Math.sin(angle) * ray.height * .5;                 // test if the projected point hit to the         // target "rightEdge" object         if(rightEdge.hitTestPoint(dx,dy,true));         {             // test if first point doesn't exist             if(!p)             {                 // move point to the first hit position                 line.graphics.moveTo(dx, dy);                 // save the coordinates                 p = new Point(dx, dy);             }             else             {                 // draw line on each iteration                 // of the loop                 line.graphics.lineTo(dx, dy);             }         }     }     // test if first point of the parabola exist     if(p)     {         // close line path         line.graphics.lineTo(p.x,p.y);         // stop filling         line.graphics.endFill();         // add parabola to the stage         addChild(line);         // mask ray object with the         //  parabola         ray.mask = line;     } }

Last edited by -:)lauri; 07-29-2012 at 11:22 PM.
-:)lauri is offline   Reply With Quote
Old 07-30-2012, 09:06 AM   #5
santanoa
Dual Screen Empowered
 
santanoa's Avatar
 
Join Date: Jul 2010
Location: Israel
Posts: 258
Default

Pretty cool code. Thanks for the comments, makes it really easy to understand
However, as you say, it projects the light ray onto a parabola, which changes its shape. I'd like to only cut off the part of the light ray which is past the wall.

Maybe if you use a similar idea, but instead draw a trapezoid around the light ray. 3 of the sides of the trapezoid would correspond to 3 sides of the ray. the fourth side would be at whatever angle the ray hits the wall.

Thanks again
santanoa is offline   Reply With Quote
Old 07-30-2012, 05:01 PM   #6
-:)lauri
Senior Member
 
Join Date: Aug 2008
Location: Helsinki, Finland
Posts: 1,184
Default

I made a small demo, with the parabola shape mask. In the demo the mask is now hiding only the hitting part of the shape, in which, contrary to example function above where the mask was hiding the opposite part of the shape. There's files in zip archive.

...and using trapezoid as I guess maybe you'd save the first hit point and the last hit point, define two other points and draw the mask through them.
-:)lauri is offline   Reply With Quote
Old 07-30-2012, 05:35 PM   #7
santanoa
Dual Screen Empowered
 
santanoa's Avatar
 
Join Date: Jul 2010
Location: Israel
Posts: 258
Default

Thanks so much! That demo is very impressive. I checked out your other demos: very cool. Unfortunately, I was unable to access the zip file. It says the page does not exist.

One question on the demo. I noticed it didn't work when it hit a corner of rightEdge. Is this do to a collision detection problem where it can't correctly identify the collision point?

You really are a life saver.
santanoa is offline   Reply With Quote
Old 07-30-2012, 07:05 PM   #8
-:)lauri
Senior Member
 
Join Date: Aug 2008
Location: Helsinki, Finland
Posts: 1,184
Default

Oh, sorry, my mistake. I added the zip file (implementation without the help option) to the server, now there should be the zip file.

Darn! I had an idea to do the script that shows only links that has some content to avoid "page doesn't exist" and such messages but for some reason haven't been yet inspired enough to do it
-:)lauri is offline   Reply With Quote
Old 07-30-2012, 07:57 PM   #9
-:)lauri
Senior Member
 
Join Date: Aug 2008
Location: Helsinki, Finland
Posts: 1,184
Default

Corners are problem in my demo. Its due the shortcut in the code I made. I'm applying a shorter a version from Emanuele Feronatos flashlight effect he used in his survival horror game tutorial (as2 with explanations, as3 practically with just the code).

While I have a single loop to detect just hits with the fixed distance from the registration point of the moving object, Feronato is using 2d loop to be able to use more dynamic lengths of the radii to detect also the shape of the object with which the moving object is intersecting. The technique in my example and in the tutorial is a bit rough but I believe with well optimized 2d loop algorithm it could be made useful at least in smaller apps.

I'm sure there are more sophisticated ways to think the problem but at the moment I don't know any.
-:)lauri is offline   Reply With Quote
Old 07-31-2012, 07:21 AM   #10
santanoa
Dual Screen Empowered
 
santanoa's Avatar
 
Join Date: Jul 2010
Location: Israel
Posts: 258
Default

Thanks for showing me that tutorial, it looks really good. It was fairly easy converting his example (which was radial) to a linear one. here's my code:

ActionScript Code:
package  {         import flash.display.MovieClip;     import flash.display.Sprite;     import flash.geom.Point;     import flash.events.Event;         public class Main extends MovieClip {                 var lightMask:Sprite         var wall:Sprite;                         public function Main() {             wall = new Sprite();             lightMask = new Sprite();             lightMask.x = 100, lightMask.y = 300;                         var g = wall.graphics;             g.beginFill(0xff0000);             g.drawRect(0,0,50,100);             g.endFill();             addChild(wall);             addChild(lightMask);             wall.x = 200, wall.y = 60;                                     addEventListener(Event.ENTER_FRAME,enterFrame);         }                 public function enterFrame(e) {             wall.rotation = -Math.atan2(mouseY-wall.y,mouseX-wall.x) * 180/Math.PI;             drawLight(lightMask,100,250,200,20);         }         //numLines - amount of vertical lines to draw (less makes light mure angular)         //lrWidth & lrHeight - dimensions of light         //sprite - sprite that you use to put light in         //checkNum - distance between each hitTest check (higher makes it more accurate)         public function drawLight(sprite,numLines,lrWidth,lrHeight,checkNum) {             var checkNumMin = checkNum;             var checkNumMax = 100;             var lineStep = lrWidth/numLines;             var checkStep = lrHeight/checkNum;             var g = sprite.graphics;             g.clear();             g.beginFill(0x000000,1);             g.lineStyle(0,0x000000);             g.moveTo(0,0);             for (var i = 0; i <= lrWidth; i += lineStep) {                 var hitX = i;                 var hitY = -lrHeight;                 checkNum = checkNumMin; //reset checkNum                 checkStep = lrHeight/checkNum;                 for (var j = 1; j <= checkNum; j++) {                     hitX = i;                     hitY = -checkStep * j;                     var hitPoint = sprite.localToGlobal(new Point(hitX,hitY));                     if (wall.hitTestPoint(hitPoint.x,hitPoint.y,true)) {                         if (checkNum < checkNumMax) { //first collision                             j = Math.floor((j-1)*checkNumMax/checkNum); //proportionally update j                             checkNum = checkNumMax; //make checkNum much higher because now you're close to a collision                             checkStep = lrHeight/checkNum; //update checkStep                                                     } else break;                         //found a collision. stop incrementing y and draw line to collision                     }                 }                 g.lineTo(hitX,hitY);             }             g.lineTo(lrWidth,0);             g.lineTo(0,0);             g.endFill();         }     }     }

I plan on using the lightMask as a mask for my lightRay. I'm concerned about efficiency though, since it'll be running every frame. Since I already have a collision detection class, I think I'll only run this code when there's actually a collision. Also, taking an idea from your code, I make checkNum much higher when close to a collision.

Thanks so much again. Tell me what you think

Last edited by santanoa; 07-31-2012 at 07:39 AM.
santanoa is offline   Reply With Quote
Reply


Thread Tools
Display Modes Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT. The time now is 09:08 PM.

///
Follow actionscriptorg on Twitter

 


Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Ad Management plugin by RedTyger
Copyright 2000-2013 ActionScript.org. All Rights Reserved.
Your use of this site is subject to our Privacy Policy and Terms of Use.