How do I stop my character moving through objects with actionscript 3? - actionscript-3

I am new to flash and want to make it so when my character hits an object, they won't go through it, but still maintains control after they have hit it. I want it to be a solid object from all 4 points (top, left, right, bottom) of the object. Here is what I have been experimenting with...
function hitsTheObject(e:Event)
{
if (myCharacter.hitTestObject(Ball_mc))
{
gravity = 0
hitObject = true
}
if (dIsDown == true && hitObject == true)
myCharacter.x -=10
}
The first if statement works, though the second one turns off the dIsDown button I have coded. Any thoughts?
Edit: Basically I want the character to hit an object and for it to block the character, as if it was a wall.

Lewis, you're best bet is point collision. Here's some links to help you think it through and start off: http://www.wildbunny.co.uk/blog/2011/12/14/how-to-make-a-2d-platform-game-part-2-collision-detection/ and http://www.anotherearlymorning.com/2009/07/pixel-perfect-collision-detection-in-actionscript-3/

Check out my collision engine, it supports continuous/bullet collisions: https://github.com/Murplyx/AAE---Axis-Aligned-Engine

Related

as3 hittestobject not working, dont understand why

the collision not working i cant understand why, i put collision movieclips in the object and it doesnt seem to recognise one of the but does with the other, sorry for the confusing way of stating the problem if you play the game you will understand. im open to changing the way collision works too as long as it works ill be super happy
I'll try to explain. When You click "Down" or "Up" hero (box_MC) collide with both doors "Top_Door" and "Bottom_Door". Inside "bang" function at first checking collision with "Bottom_Door", so, hero always go down (.y += 100) and second condition (Top_Door) never will be true. How to fix this? Add variable var lastAction:String;. This variable will store last action: "up" or "down". Inside "down_MC_P" function initialize this variable by "down". Inside "up_MC_P" — "up". Next, replace the first condition to this if (box_MC.hitTestObject(cycle[i].Bottom_Door) && lastAction == "down") and second: if(box_MC.hitTestObject(cycle[i].Top_Door) && lastAction == "up"). That's all.

Actionscript 3- Random movement on stage? Also, Boundaries?

I'm trying to code something where there are creatures running back and forth, up and down across the stage, and I the player, have to try to go up to them, and pick them up. There are also boundaries on stage-
The map constraints- a big rectangle box is easy enough to accomplish. I've done this.
The boundaries within the map, which are also rectangles, but instead of bouncing the player back INSIDE the rectangle, I'm trying to do the opposite- keep the player out of it.
My code for it looks like this as of now:
//Conditions that check if player/monsters are hittesting the boxes (rocks
//and stuff), then if correct, bounce them away. Following code excludes
//the monsters for simplicity.
if((mcPlayer.x - aBounceBox[b].x) < 0 && mcPlayer.y <= (aBounceBox[b].y + aBounceBox[b].height/2) && mcPlayer.y >= (aBounceBox[b].y - aBounceBox[b].height/2))
{
mcPlayer.x = aBounceBox[b].x - aBounceBox[b].width/2 - mcPlayer.width/2;
}
//Duplicate above code for right side of box here
if((mcPlayer.y - (aBounceBox[b].y + aBounceBox[b].height/2)) < 0 && (mcPlayer.x + mcPlayer.width/2) > (aBounceBox[b].x - aBounceBox[b].width/2) && (mcPlayer.x - mcPlayer.width/2) < (aBounceBox[b].x + aBounceBox[b].width/2))
{
mcPlayer.y = aBounceBox[b].y + aBounceBox[b].height/2;
}
//Duplicate above code for Upper boundary of box here
The above doesn't work very well because the code to bounce for the left and right sides of the box conflicts with the upper and lower parts of the box I'm hit-testing for. Any ideas how to do that smoothly?
Also, another problem I am having is the pathing for the monsters in the game. I'm trying to get them to do the following:
Move around "organically", or a little randomly- move a little, stop. If they encounter a boundary, they'd stop and move, elsewhere. Not concerned where to, as long as they stop moving into rocks and trees, things like that.
Not overlap as much as possible as the move around on stage.
To push each other apart if they are overlapping, although I'd like to allow them to overlap very slightly.
I'm building that code slowly, but I thought I'd just ask if anyone has any ideas on how to do that.
To answer your first question, you may try to implement a new class/object which indicates the xy-offset between two display objects. In order to illustrate the idea more clearly, you can have a function similar to this:
public function getOffset(source:DisplayObject, target:DisplayObject):Object {
var dx:Number = target.x - source.x;
var dy:Number = target.y - source.y;
return { x:dx, y:dy };
}
Check if the hero character is colliding with another object first by hitTestObject(displayObj) of DisplayObject class. Proceed if the result is true.
Suppose you pass in your hero character as the source object, and another obstacle as the target object,
var offset:Object = getOffset(my_hero.mc, some_obstacle.mc);
After getting the resulting offset values, compare the magnitude (absolute value) of offset.x and offset.y. The outcome can be summarized as follows:
Let absDx be Math.abs(offset.x), absDy be Math.abs(offset.y),
absDx < absDy
offset.y < 0, target is above source
offset.y > 0, target is below source
absDx > absDy
offset.x < 0, target is to the left of source
offset.x > 0, target is to the right of source
absDx == absDy
refer to one of the above cases, doesn't really matter
Then you can update the position of your hero character according to different situations.
For your second question concerning implementing a very simple AI algorithm for your creatures, you can make use of the strategy above for your creatures to verify if they collide with any other stuff or not. If they do collide, assign them other directions of movement, or even simpler, just flip the signs(+/-) of their velocities and they will travel in opposite directions.
It is easier to implement simple algorithms first. Once it is working, you can apply whatever enhancements you like afterwards. For example, change directions when reaching junctions or per 3 seconds etc.

Collisions detected after the MovieClip was removed

Okay, so let's say I have "ball" MovieClips that collide against a "wall" MovieClip.
if ( !ball.hitTestObject(wall) ) {
// If they didn't find any obstacle keep falling.
ball.y++;
}
Then I remove the wall, and the balls keep colliding against a wall that I cannot see. No ball moves, not the ones that were there, neither the new ones.
case Keyboard.K: removeChild(wall); break;
What am I missing or doing wrong?
Thanks in advance.
removeChild only removes the instance from the display list, display list has nothing to do with game logic actually... you have to either disable your movieclip with a boolean (if you later want to use it then you can enable it) or null the reference, but beware of nulling your reference, because if you try to access it after nulling, you get an error, so you might want to check that if your wall is whether null or not before checking your collision.
if(wall!=null){
if ( !ball.hitTestObject(wall) ) {
// If they didn't find any obstacle keep falling.
ball.y++;
}
}
...
case Keyboard.K:
removeChild(wall);
wall = null;
break;

How do I HitTest two rotating objects properly? (A way to avoid bounding boxes)

I took an intro level flash course in college this semester and our final task was to make a mini-flash game.
I had to make a pipe-dream type game where there are a number of levels, and in each level you have to align the pipes so that the water flows and then you can pass to the next level.
I successfully made the first level, but upon making the second level,
where I placed a lot of curved pipes (by curved pipes I mean the attached image: ![Curved Pipe]: (http://imgur.com/mwpXAMn) )
I discovered that the method I use to decide when a level is complete is not working properly.
I was using HitTestObject, basically, I was testing whether 2 objects, Pipe_1, and Pipe_2, were intersecting. If all pipes intersected in the correct way, then procession to the next level is granted.
The problem with this I discovered is that flash has bounding boxes for movie clips you make, and that HitestObject uses bounding boxes to test for hits. Therefore, when you rotate a leftpipe so that it does not touch a straight pipe on screen, the bounding boxes still touch and it returns "collision" when in fact it is not actually touching on screen.
I looked up and found that you can use HitTestPoint but I can't figure out how to somehow make dynamic variables (that change upon rotation of object) that store one or two specific points on the leftpipe, say the two ends of it.
Once If I figure out how to get these values into a variable correctly, then I can figure out how to do HitTestpoint.
Also, I know of the LocaltoGlobal function but no matter what I try it keeps coming up with:
"Scene 1, Layer 'Layer 1', Frame 1, Line 30 1118: Implicit coercion of a value with static type Object to a possibly unrelated type flash.geom:Point."
meaning I don't know the correct code to store an x and a y coordinate as dynamic variables.
edit: ok since a person asked, I hunted this piece of code off the web and this is the one I was trying to play around with but to no avail:
How to use HitTest for 2 rectangles, r1 is rectangle 1 r2 is rectangle 2.
var r1width:Number = 135.0; //width of retangle 1 whith rotation 0
var r2width:Number = 93.0; //width of retangle 2 whith rotation 0
var p1:Object = {x:(r1width/2), y:(r1width/2)};
var p2:Object = {x:(-r1width/2), y:(r1width/2)};
var p3:Object = {x:(-r1width/2), y:(-r1width/2)};
var p4:Object = {x:(r1width/2), y:(-r1width/2)};
r1.localToGlobal(p1);
r1.localToGlobal(p2);
r1.localToGlobal(p3);
r1.localToGlobal(p4);
var p5:Object = {x:(r2width/2), y:(r2width/2)};
var p6:Object = {x:(-r2width/2), y:(r2width/2)};
var p7:Object = {x:(-r2width/2), y:(-r2width/2)};
var p8:Object = {x:(r2width/2), y:(-r2width/2)};
r2.localToGlobal(p5);
r2.localToGlobal(p6);
r2.localToGlobal(p7);
r2.localToGlobal(p8);
if((r2.hitTest(p1.x, p1.y, true))||(r2.hitTest(p2.x, p2.y, true))||(r2.hitTest(p3.x,
p3.y, true))||(r2.hitTest(p4.x, p4.y, true)))
{
trace('collision');
}
if((r1.hitTest(p5.x, p5.y, true))||(r1.hitTest(p6.x, p6.y, true))||(r1.hitTest(p7.x,
p7.y, true))||(r1.hitTest(p8.x, p8.y, true)))
{
trace('collision');
}
I did not write this code and it does not work. I'm not sure what "Object" is because I've never used it before, I'm assuming in this case it's sort of acting like a coordinate pair.
Also, this code is to hittest 2 rectangles, whereas I'm using an L-shaped pipe, so the x/y calculation would be quite different I imagine.
This code above gives the same error that I posted before:
Implicit coercion of a value with static type Object to a possibly unrelated type flash.geom:Point.
and it gives it first on line r1.localToGlobal(p1);
Instead of using Object, you need to use Point like so:
var p1:Point = new Point(r1width/2, r1width/2);

Animation flickering problem

This is the game loop in my code and the drawing code:
float frames_per_second = 60;
display_timer = al_create_timer(1/frames_per_second);
queue = al_create_event_queue();
al_register_event_source(queue, al_get_timer_event_source(display_timer));
al_start_timer(display_timer);
while(!end_game)
{
ALLEGRO_EVENT event;
al_wait_for_event(queue, &event);
if(event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) break;
if(event.any.source == al_get_timer_event_source(display_timer))
{update_display();}
update_input();
}
void update_display()
{
al_clear_to_color(al_map_rgb(255, 255,255));
draw_objects(); //this is just an al_draw_bitmap() call
al_flip_display();
}
The animation created by moving objects on screen flickers, I'm surprised by this since I write to the back buffer of the screen thus I expect double buffering. What can I do to correct the flickering? Thanks.
Unrelated to the problem, you can check a timer by looking for the ALLEGRO_EVENT_TIMER event. You can use event.timer.source to check which timer it is, if you have more than one.
I think the main problem here is that you are drawing the graphics at 60fps but you are updating the input at an unlimited rate. This is actually backwards. You want to update the input at a fixed rate. You can draw the graphics as often as you like... although it makes no sense to update the graphics if nothing has changed.
So it should look something more like:
if(event.type == ALLEGRO_EVENT_TIMER)
{
update_input();
update_display();
}
However, this does not implement frame skipping if things get too slow. What you should do is set up the timer in a dedicated queue (that contains no other event sources). Then as long as there are events sitting in that dedicated timer queue, update the input.
Then update the display, assuming you've processed at least one tick. So you may, if things get too slow, do multiple input updates per drawn frame.