hitTestPoint with 'shapeFlag=true' doesn't work in AS3 - actionscript-3

I simply added a sprite in AS3:
Sprite myspr = new Sprite();
myspr.addChild(mybitmap);
addChild(myspr);
Then I added an event. I did hitTestPoint for checking mouse is over my sprite or not.
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseCheck);
private function mouseCheck(evt:MouseEvent):void {
var xx:int = stage.mouseX;
var yy:int = stage.mouseY;
if(myspr.hitTestPoint(xx, yy, true)) {
...
// I'm checking mouse over here.
}
evt.updateAfterEvent();
}
Problem is: hitTestPoint gives true when mouse comes to full boundary box. But it should give true only if mouse comes on transparent isometric sprite.
Is there a solution for this, thanks in advance.

this should help. You need pixel perfect detection.
Actionscript 3 pixel perfect collision. How to? (learning purposes)
http://www.freeactionscript.com/2011/08/as3-pixel-perfect-collision-detection/
http://www.anotherearlymorning.com/2009/07/pixel-perfect-collision-detection-in-actionscript-3/
http://old.troygilbert.com/2009/08/pixel-perfect-collision-detection-revisited/

There's a few ways I usually do hit testing.
1) The easiest way is to use a an already made class that you can find online. Some people much smarter than me have created complex classes that allow for much better pixel to pixel interaction. The ones listed by Paras are all good. The problem with these is, for newer users, it can be hard to understand all the code and how to implement them. Usually it is simple once you understand what is going on though. You just replace your hit test with the class file and then enter in the correct arguments.
2) Another method is to actually go into the symbol, create a new layer, and then draw a rectangle(just turn the alpha down to 0%) where you want the hit test to work. This may seem like a stupid method, after all we are just confined to a square once again. BUT, it will actually work MUCH better than you'd expect. Just draw the square maybe slightly smaller than the height and width of your character you're detecting the hit test on, and you should be good to go. Give it an instance name (the hit square that is) and then just perform the hitTest with that square instead of the actual sprite. It works wonderfully and is a very simple solution. For what you're explaining though, this sounds like it might not work. This method is more from a gamer standpoint. It looks good when attacking and getting hit by enemies, but isn't necessarily exact. Also, if you want to do this with two characters (maybe a large attack hitting an enemy) simply draw a hit box for both sprites. This is probably a little more basic than using a pre-made pixel perfect hit detection test, but it works extremely well and takes only a few minutes.

Related

Transparency issues with 3d particles and 3d models, libgdx

I got some strange issues with transparency and 3d particles. A short vid to illustrate:
https://youtu.be/ZHKI1X3MjhY
As you can see I have a 3d particle effect, fire burning. Inside it is a 3 model with no alpha blending and it shows just fine. then in the far distance there is a small skeleton (with blending and alphatest turned on) and it also shows just fine through the fire. Then I turn camera and look at the warrior skeleton and it just disappear and instead you see what is behind him. I turn camera again and the mage skeleton also vanishes, but you can see the trees a bit further away just fine and they have the exact same settings for blending and alpha test. If I move the character say 20 yards away it also starts showing through the fire effect.
So it seems to have something to do with distance from the 3d particle effect...
The 3d particle batch is an extended BillboardParticleBatch like this:
protected Renderable allocRenderable(){
BlendingAttribute ba=new BlendingAttribute(GL20.GL_SRC_ALPHA, GL20.GL_ONE,1f);
Renderable r = super.allocRenderable();
r.material = new Material( ba,
// new DepthTestAttribute(GL20.GL_LEQUAL, 0.0f, 0.5f, true),
// r.material.set(new FloatAttribute(FloatAttribute.AlphaTest, 0.0f),
TextureAttribute.createDiffuse(texture));
return r;
}
All the characters and the trees are created with following attributes:
if (alpha) {
FloatAttribute floatAttribute = new FloatAttribute(FloatAttribute.AlphaTest, 0.5f);
BlendingAttribute blendingAttribute = new BlendingAttribute(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA, 1f);
for (int i = 0; i < bulletEntity.modelInstance.materials.size; i++){
bulletEntity.modelInstance.materials.get(i).set(blendingAttribute);
bulletEntity.modelInstance.materials.get(i).set(floatAttribute);
}
}
The models are drawn first then the particles, I tried changing order but no difference. I have tried a lot of different setups for alphatest, depthtest and blendingattribute but can not find anything that works.
EDIT
I removed the Blending attribute from the 3d-models and now it looks as it should regarding the particle effect. However I need most materials on my character models to have blending set..
Anyone got any clue why this is happening when I enable blending?
I also tried to use the BillboardParticleBatch without extending it in case I had done something there but the effect then is even worse. All models with blending enabled appear in-front of the particle effect even though they stand behind it.
ModelBatch sorts your render calls (check this link, really, it is a must read), to avoid incorrect behavior (as you're experiencing). The actual sorting/rendering happens at the call to ModelBatch#end. By default it uses the DefaultRenderableSorter, which is a default implementation. Of course, because that implementation isn't aware of your scene, it might not fit exactly your needs.
The DefaultRenderableSorter tries to guess the location of each model based on their transformation matrix. Based on that location and the camera's location it will sort them so that:
First all opaque objects are rendered from front to back (because whatever is behind an opaque object isn't visible anyway, so that reduces unneeded calls to the fragment shader).
Secondly all transparent objects are rendered from back to front (because as soon as a transparent object is rendered then everything that is rendered after that and is behind it, will not be visible).
To decide whether an object is transparent, the BlendingAttribute#blended member is used. (So you could, if you really wanted to, set that member to false to force it to be treated (sorted) as if it was opaque)
So, the order in which you call ModelBatch#render is not necessarily the order in which they are actually executed. If you want to force to render whatever you've added to the batch in between, then call the ModelBatch#flush(). Of course, doing this a lot defeats some of the purpose of ModelBatch in the first place.
Instead you could implement your own RenderableSorter which has more knowledge about your scene and can therefor do a better job sorting than the default implementation. (however if flush() works for you and there's no other issue, then just flush might be the easiest solution for you).
That said, there a various other solutions you could try as well. E.g. the regions of the particles are fully transparent, so the fragment shader might as well discard those all together. Try adding FloatAttribute.AlphaTest with a value of 0.5f to the particles. If that messes with your blending then gradually reduce the value to e.g. 0.05f.
Also, you could add a DepthTestAttribute with depthMask set to false (new DepthTestAttribute(false)). This will prevent the particles from writing to the depth buffer. (but also might cause other things to show in front of the particles).

Moving text across screen smoothly

For a long time I've been searching for a solution to this problem, so I decided to post a tread instead when the search didn't clarify anything.
I have a textfield that is supposed to move across the screen. I've solved this by adding a speed to its x-value dynamically through an "enter-frame function". However, the movement is very "laggy" and consists of sudden "jumps" in the movement. I've tried a couple of possible solutions to this, all of them without luck.
embedding fonts
changing the textfield's antiAliasType
using BitmapData like this:
bmd = new BitmapData (myTextField.width, myTextField.height, true, 0);
bmd.draw (myTextField);
bm = new Bitmap (bmd);
bm.x = myTextField.x;
bm.y = myTextField.y;
bm.cacheAsBitmap = true;
bm.smoothing = true;
this.addChild(bm);`
And then moving the "bm" instance
None of these methods worked.
EDIT: By request, I am adding the relevant code for the actual movement of the text.
stage.addEventListener(Event.ENTER_FRAME, time);
private function time(evt:Event):void
{
bm.x-= textSpeed;
}
The variable textSpeed is defined as a public static var. Its value is 2.
*EDIT2: I've prepared a clean fla-file with nothing but moving text. The same lag occurs for me also here. The code is in the actions panel. Download link
the way Flash IDE works, is that setting the framerate is actually the 'maximum' framerate. That is, it doesn't force the animation to run at that rate - it can vary depending on the machine and available resources.
As far as I know, there's no way to force Flash to run at a certain framerate - the best way to make animations 'smooth' is to use Tween classes like TweenLite.
If you NEED to animate by incrementing position values, then I suggest making it time based instead, for example:
var fps = 24;
var moveTimer:Timer = new Timer(1000/fps);
moveTimer.addEventListener(TimerEvent.TIMER, onMoveTimer);
moveTimer.start();
function onMoveTimer(e:TimerEvent){
bm.x -= 1;
}
Again, this doesn't solve the smoothness of the animation, but it will be much more reliable across different machines than using enter frame.
Try increasing the framerate. Because you naturally try to read text as it animates, you can generally notice the gaps between frames at 24fps. Try setting stage.frameRate to 30, 48, or 60 (60 being the max) and see if that solves your issues. I've had similar issues with animating text in the past and increasing frame rate has fixed them.
I would also recommend only increasing it as needed. You are much more likely to drop frames with a higher frame rate (makes logical sense; each frame has less time to calculate as frame rate increases), so you might want to do something like:
stage.frameRate = 48;
// run animations here
stage.frameRate = 24; // in an Event.COMPLETE handler
That will make sure your animations are smooth while giving the rest of your application the best shot of running well on lesser devices. If you are running a lot of animations, you might consider keeping it elevated permanently.
You should also look into using the Greensock animation library (TweenLite/TweenMax) instead of Flash's built-in tweening. Greensock has a vastly superior API, both in terms of features and performances, especially on mobile.

How to implement camera without moving anything AS3?

I'm using physInjector and therefore cannot move clips containing my objects: The physical engine works incorrectly because of it.
I think about implementing something like a bitmap drawing a selected part of the stage on itself. How can it be done? I've read this Trying to capture stage area using BitmapData, but there the author copies its data from the stage, whereas I need the area outside it.
Besides, aren't there less resource-consuming solutions?
First, you may want to use a global Sprite to put your clips insde, like :
var a:Sprite = new Sprite();
a.addChild(myClip1);
a.addChild(myClip2);
...
Then, you should be able to move a.
If you don't, and your physic engine rely on Stage to work, you should probably try to fix it, or to understand better how it work so you can move your movieclips.
Redraw a BitmapData every frame will require a lot of CPU ressource, and you won't be able to interact with your clips. That's really not the best way to go.
x=-(player.mc.x-stage.stageWidth/2);
y=-(player.mc.y-stage.stageHeight/2);
if(canvas)
removeChild(canvas);
var bd:BitmapData=new BitmapData(stage.stageWidth,stage.stageHeight,false,0xFFFFFF);
bd.draw(stage);
trace(bd);
canvas=new Bitmap(bd);
addChild(canvas);
x=0;
y=0;
At PC it works fine. Don't know whether it is suitable for mobiles.
I also haven't tested the approach suggested by blue112 because in twitter of physinjector developer there are complaints about ANY moving of parent clip (https://twitter.com/reyco1/status/327107695670853632) and it is quite difficult to combine with my existing architecture.
Changing the globalOffsetX and globalOffsetY properties also didn't help

Need a hitTestPoint solution to replace hitTestObject

I need an as3 solution to this collision problem:
I have this code:
else if (objectArray[i].toString().indexOf("meandude") != -1) {
//if the object is a meandude and hits it, game over
if (projectileMC.hitTestObject(objectArray[i])) {
removeEventListener(Event.ENTER_FRAME,mainEnterFrame);loseGame();
which is using the bounding boxes of the projectileMC and meandude (hitTestObject). I'd like it so the center points of the projectileMC and meandude crossing registers the action instead (hitTestPoint). I tried to switch it myself, but I'm not getting it to work.
Thanks
Not clear what your precise problem is without seeing more of your code. But as a first guess I would think you want to solve the following problem:
Your hittest is not being triggered when your projectile hits the "meandude" when you use the hitTestObject.
And
You try to solve the problem by using the hitTestPoint instead?
The test might not trigger simple because your projectile is moving too fast. If the distance between XY_ThisFram before colisison and then XY_NextFrame is bigger than the size of of your "meandude" it won't ever collide. I suggest you don't use hitTestObject to do any collision in your game as it is not reliable, especially for fast moving display objects.
Flash doesn't have a good object-to-object hit test for the general case. If both projectileMC and meandude are bitmaps, you can try BitmapData.hitTest.

How do I create a simple on-mouse-click rotating object in flash

This question may get downvoted or go unanswered because it's not the greatest and incredible silly but anyway,
I'm taking an intro level Webanimation course this semester at UNI and had I know what their expectations are for our hand-in projects i would have never taken it up.
Basically the teacher taught us stuff to the extent of masking/tweening and very few mouse-event and basic function codes.
Now she is expecting us to make a god damn ENTIRE PIPE GAME. The one where there are a bunch of rotating pipes and you gotta rotate them in place before a timer runs out and then the water flows through them.
For this project I have to somehow figure out the following (even though she didn't teach any of this):
-creature a grid of rotate-able pipes (one mouse click I assume would do a 90 degree classic tween rotation of the object)
-creature some sort of logic hit-box value chain to make pipes decide when to fill with water (they fill with water (a.k.a turn blue inside as an animation) once they are connected to another water filled pipe, for example)
-creature multiple levels and a menu screen
-add a music track.
Now i know this site is for specific help only and you basically can't ask for help on an entire project, so for now if somebody could just help me out with the following:
How do I create a rotating pipe on mouseclick?
So I have my pipe movieclip created and I have my Mouse Event code ready but I don't have the faintest on how to make a tween within the pipe and connect it to the code so that it rotates on mouseclick.
So this far, let's say for one of the pipes, instance pipe_1, I want to do this:
pipe_1.addEventListener(MouseEvent.CLICK, fl_MouseClickHandler);
function fl_MouseClickHandler(event:MouseEvent):void
{
trace("Mouse clicked");
}
I also have the simple tween of rotation already created within the instance of the pipe, but dunno how to connect it to code.
I'm supposed to figure out what to put inside the function but I honestly have no clue. Hours of googling have come up with nothing either except a 12 dollar purchasable source code for an even more complicated pipe game.
I hope somebody can at least help a bit, and thanks.
The way to rotate a clip is via it's rotation property. It defaults to 0.
If you were set the rotation property of your tile to 90, you'd rotate your pipe tile 90 degrees.
for example :
pipe_1.rotation += 90;
A tween is a means of changing a property of a given DisplayObject over time. So what you want to do is tween your rotation property 90 degrees over time.
Here is a tutorial on Tweening - http://www.republicofcode.com/tutorials/flash/as3tweenclass/
I think it'd be more beneficial for you to take the time to learn about it, than to have me just write a few lines of code to solve your problem.
StackOverflow is a place where you can ask a question, AFTER you have tried something and have hit an issue.
I have provided you with the basic concept of what you need to do, and if you take the time to learn about tweening, you'll be able to achieve your goal rather simply.
There are also tweening libraries such as TweenLite and TweenMax that simplify tweening. Not sure if your class will allow you to use them, but worthwhile to check out for your own benefit.
You can find TweenLite here :
http://www.greensock.com/tweenlite/
Are you talking about a frame by frame tween? or tweening with code?
for frame by frame tweening, you can try to do this:
pipe_1.addEventListener(MouseEvent.CLICK, f1_MouseClickHandler);
function f1_MouseClickHandler(e:MouseEvent) {
pipe_1.gotoAndPlay(2); //if the tween starts at frame 2
}
For code tweening, just call the tween function inside that handler function