Collision Check - actionscript-3

I'm trying to test for collision between bullets within a vector and enemies within another vector. I can access the data fine, but the problem lies in the actual detection of the collision. Funny thing is, it works perfectly when I use hitTestObject, so I don't see why this shouldn't be working. I might be overlooking something, but I'm having a hard time finding it.
Code:
for each(var i in eManager.enemyArray)
{
for each(var j in gManager.gunVector)
{
for each (var k in j.bManager.bulletVector)
{
// Basically using Pythagorean's theorem but with both sides squared
// to minimize any process-heavy operations
if(((i.x - k.x)*(i.x - k.x))+((i.y - k.y)*(i.y - k.y)) <= 4)
{
// Note that when this happens, the enemy dies
i.kill = true;
}
}
}
}

Whoops. Turns out that I was testing the collision between 2 points, not between a point and a shape. My mistake.

Related

As3: Not move through objects? How is the logic behind this?

I have a function where I can control my character.
I also have a movieclip on the stage called assassin_table.
I want to make it so that the character can't move in the table, a.k.a make the table work like a wall.
I have this code:
if(!this.hitTestObject(_root.assassin_table))
{
if(upKeyDown)
{
gotoAndStop(4);
y-=Math.cos(rotation/-180*Math.PI)*(mainSpeed +7);
x-=Math.sin(rotation/-180*Math.PI)*(mainSpeed +7);
}
if(!upKeyDown)
{
gotoAndStop(3);
}
}
However, if I touch the table, then I can't move at all.
I know it's because if(!this.hitTestObject(_root.assassin_table)), but I don't understand the logic behind NOT moving through objects. I'd much rather have a near pixel-perfect collision detection system, but since it's so hard to find any good info online which isn't confusing, I'll stick with hitTestObject for now :)
EDIT: Tried something, didn't really work that well.
if(!_root.assassinDead && !teleporting && this.currentFrame != 5)
{
if(this.hitbox.hitTestObject(_root.assassin_table))
{
_root.assassin_table.gotoAndStop(2);
if(this.x > _root.assassin_table.x)
{
trace("Can't move right");
canMoveRight = false;
}
if(this.x <_root.assassin_table.x)
{
trace("Can't move left");
canMoveLeft = false;
}
if(this.y > _root.assassin_table.y)
{
trace("Can't move up");
canMoveUp = false;
}
if(this.y < _root.assassin_table.y)
{
trace("Can't move down");
canMoveDown = false;
}
}
else
{
canMoveRight = true;
canMoveLeft = true;
canMoveUp = true;
canMoveDown = true;
}
}
This causes me to sometimes be able to walk through the table. I figure it's because my character can move in essentially every possible angle (since he's always facing the mouse and there are no tiles/grids).
How would I make it so that it would work with the advanced movement I have?
Moving up runs this:
y-=Math.cos(rotation/-180*Math.PI)*(mainSpeed +7);
x-=Math.sin(rotation/-180*Math.PI)*(mainSpeed +7);
And the rotation is decided by this:
this.rotation = Math.atan2((stage.mouseY - this.y), (stage.mouseX - this.x)) * 180/ Math.PI + 90;
You should seperate your hittest functions for four different moving directions.
I mean, you shouldn't use this "hitTestObject" stuff, that only returns a boolean value "true" or "false", and that's not going to work for you.
You need a function like "testPoint(player.x, player.y);" and returns the object at the given position, so you can implement it for your game like that
if (upKeyDown && testPoint(player.x, player.y - mainSpeed +7) == null) y-=Math.cos(rotation/-180*Math.PI)*(mainSpeed +7);
player.y - mainSpeed +7 // that checks for plus mainSpeed+7 because of trying to stop your player before it get stack inside object
Basically your logic flow should be like this:
Sample input (key press)
Move character
Check for collisions
If collision then move character to it's "outside" the object that it's touching
In your particular case, if your character is on the left of the table, and you're moving right, then first things first, you move your character. At your new position, check for any collisions. If you have a collection, then because you were moving from the left, we want to be on the left of the object that we colliding with, in this case the table, so we position our character to the left of the table.
The first part of that (checking if the character has hit the table) is called collision detection. Moving the character so that it's outside the bounds of the table is called collision response. Collision detection is a pretty big field and really depends on the type of game you're making; you can do grid-based, hit-test based (if you don't have a ton of objects), physics-based, math-based etc. Collision response can be anything and everything, depending on how you want to react to a collision - you can destroy the object (balloon on a spike), change its speed (character running through mud), bounce off it (ball off wall), or stop any further movement (character against wall).
To make things a bit easier:
Separate your systems - your input shouldn't be dependant on your collision for example. If the up key is down, just register that fact - what you do with it later (make your character move) is up to you
Separate your objects position in memory from its position on screen - this will let you move it around, react to collisions etc, and only when everything is good, update the graphics (stops things like graphics entering a wall only to jump out the next frame)
Solve for one axis at a time - e.g. collide on the x axis first, then the y
Pixel perfect collision is rarely needed :) Non-rotated boxes and circles will work a lot more than you'd think
Somewhat related - the shape of your object doesn't have to be the shape that you're colliding with - e.g. your table collision shape could just be a box; your character collision shape could just be a circle
Update
This causes me to sometimes be able to walk through the table
Assuming that we're going to collide our character and table as boxes, you need to take into account their sizes - i.e. we don't just compare the x values, but the right side of our character box against the left side of the table box etc. Something like:
// assumes objects have their anchor point in the top left - if its
// not the case, adjust as you see fit
if( char.x + char.width > table.x ) // right side of the char is overlapping the left side of the table
canMoveRight = false;
else if( char.x < table.x + table.width ) // left side of char vs right side of table
canMoveLeft = false;
// etc
When working with collisions, it's always nice to see the actual boxes, for debugging. Something like this:
var debug:Shape = new Shape;
debug.addEventListener( Event.ENTER_FRAME, function():void
{
debug.graphics.clear();
debug.graphics.lineStyle( 2.0, 0xff0000 );
// char (again assuming anchor point is top left)
debug.graphics.drawRect( char.x, char.y, char.width, char.height );
// table
debug.graphics.drawRect( table.x, table.y, table.width, table.height );
});
// add our debug. NOTE: make sure it's above everything
stage.addChild( debug );

ActionScript 3.0 HitTestObject on an Array

Good afternoon everyone!
I have a small problem in ActionScript 3.0 with hitTestObject.
I would like to chechk if my character hits a platform (I'm making a simple platform game.).
I have a platform object exproted for action script , and i add childs frim this to an array.
Until this point everything goes well, i can put them on stage etc.
I have written a cycle to chechk if my caharacter hits the platform but it doesn't works correctly. My character falls throught the first platforms and only stop's falling when it hits the last platform. (So for the last in the array it works well.)
And now here is this part from my code, i hope someone can help me with it. :)
import flash.events.Event;
import flash.geom.Rectangle;
stop();
var vy:Number=0;
var gv:Number=1;
var sebesseg:Number=4;
var jumped:Boolean=false;
var stay:Boolean=false;
var level:Array=new Array ;
var gravity:Number=2;
var velocity:Number=1.1;
var platform0:MovieClip=new platform ;
level.push(addChild(platform0));
level[0].x=200;
level[0].y=450;
var platform1:MovieClip=new platform ;
level.push(addChild(platform1));
level[1].x=700;
level[1].y=650;
var platform2:MovieClip=new platform ;
level.push(addChild(platform2));
level[2].x=1000;
level[2].y=800;
stage.addEventListener(Event.ENTER_FRAME, cameraFollowCharacter);
function cameraFollowCharacter(evt:Event) {
root.scrollRect=new Rectangle(PORK1_mc.x-(stage.stageWidth/2)+320,PORK1_mc.y-(stage.stageHeight/2)-50,stage.stageWidth,stage.stageHeight);
}
stage.addEventListener(KeyboardEvent.KEY_DOWN,gomb);
function gomb(k:KeyboardEvent):void {
trace(k);
if (k.keyCode==37) {
if (sebesseg==2) {
sebesseg=sebesseg+0;
} else {
sebesseg-=1;
}
} else if (k.keyCode==39) {
sebesseg+=1;
} else if (k.keyCode==Keyboard.ESCAPE) {
stop();
root.scrollRect=new Rectangle (stage.x,stage.y,stage.stageWidth,stage.stageHeight);
gotoAndStop(2);
} else if (k.keyCode==Keyboard.F1 && stay==false) {
stage.frameRate=0;
stay=true;
} else if (k.keyCode==Keyboard.F1 && stay==true) {
stage.frameRate=24;
stay=false;
}
}
stage.addEventListener(Event.ENTER_FRAME, megy);
function megy(e:Event):void {
PORK1_mc.x+=sebesseg;
gravity*=velocity;
PORK1_mc.y+=gravity;
//trace(velocity);
}
THIS PART IS THE PROBLEM, HITTESOBJECT ONLY WORKS FOR THE LAST PLATFORM
PORK1_mc.hitPork_mc this is my character (hitPork_mc is an invisible rectangle for better HitTestObject. So as i wrote my char. falls throught the platfroms until the last one, he falls on tha last and stops falling, so for the last platform in the array it works perfectly.
I wouldn't like to change a lot on my code, only on the hitTest part if its possible.
this.addEventListener(Event.ENTER_FRAME, handleEnterFrame);
function handleEnterFrame(e:Event):void {
for (var i:int = 0; i < level.length; i++) {
if (level[i].hitTestObject(PORK1_mc.hitPork_mc)) {
velocity=0;
} else {
velocity=1.1;
gravity=4;
}
}
}
Thanks for every help in advance!
With your original code, you do the following for each platform:
If there is a collision, set velocity to zero.
If not, set velocity to 1.1.
Since you do this in order, here's what happens when you collide with platform 1 but not 2 or 3:
The collision with 1 sets your velocity to zero.
The collision with 2 sets your velocity to 1.1.
The collision with 3 sets your velocity to 1.1.
Since these happen all in a row in the same frame, the end result is that your character never stops unless the collision is with platform 3.
By returning after setting velocity to zero, you are breaking out of the loop, preventing your collision work from being undone. What you are doing will work, but you can also do it another way which is less concise but may make more sense:
function handleEnterFrame(e:Event):void
{
var collided:Boolean = false; //This will record if you collided or not.
for (var i:int = 0; i < level.length; i++)
{
if (level[i].hitTestObject(PORK1_mc.hitPork_mc))
{
collided = true;
}
}
if(collided) velocity = 0;
else
{
velocity=1.1;
gravity=4;
}
}
Note that here we're not applying velocity and gravity inside the for loop because we don't want it to happen for each object we might collide with. Instead, we set it once, after we've determined if we collide with any objects.
This also helps show that you are setting gravity every frame you don't collide even though there doesn't seem to be any point at which you set it to zero; I suspect this is something you want to fix.

Splicing elements out of a Vector in a loop which goes through the same Vector (ActionScript 3)

I'm making a simple game and have a Vector full of enemies in order to do hit-checking on them from my "laser" object (it's a space shmup). Every laser loops through the Vector and checks if it's occluding the hit circle. The problem lies in when one laser destroys an enemy, the rest of the lasers try to also check the same Vector, only to go out of bounds since the enemy's already been spliced out and it's changed the size of the Vector.
for each (var enemy:Enemy in enemies){
var distanceX = this.x - enemy.x;
var distanceY = this.y - enemy.y;
var distance = Math.sqrt( (distanceX*distanceX) + (distanceY*distanceY) );
if (distance <= enemy.hitRadius) {
enemy.removeEnemy();
enemies.splice(enemies.indexOf(enemy),enemies.indexOf(enemy));
}
}
How would I go about collecting the index of individual elements in the Vector to be deleted, then only deleting them when every Laser object is finished its checking?
edit: here's my removeEnemy() function from my Enemy class, just in case:
public function removeEnemy(){
removeEventListener(Event.ENTER_FRAME, move);
parent.removeChild(this);
trace("removed Enemy", enemies.indexOf(this));
}
edit edit: I'm also getting a null reference pointer error to "parent" in my removeEnemy() function... but only sometimes. I have a feeling that if I fix one of these two problems, the other will also be fixed but I'm not sure.
I fixed it! The problem was actually in how I used the "splice()" method. Turns out that the second parameter isn't the end index of where to stop splicing, it's the number of elements to be spliced. So when I was trying to splice element 0, I wasn't splicing anything, and when I was trying to splice element 3, I was also splicing 4 and 5. I feel like such a dunce for not reading the API right and wasting a couple hours on this. Thanks to everyone who commented-- you guys helped me rule out what I thought the problem was.

AS3: Sprite following a Path in high speed

First of all sorry for some english mistakes. Portuguese is my first language(I am from Brazil)
Im trying to make a space game from scratch in AS3 and the way to move the ship is like in the game Air Traffic Chief.
I succeed at some point. But when the ship is very fast it start to shake and its not very smooth and clean as I want.
Here is what i have done: http://megaswf.com/s/2437744
As the code is very big so I pasted in pastebin: pastebin.com/1YVZ23WX
I also wrote some english documentation.
This is my first game and my first post here. I really hope you guys can help me.
Thanks in advance.
Edit:
As the code is very big i will try to clarify here.
When the user MouseDown and MouseMove the ship every coordinate is passed to an array.
When the user MouseUP this array is passed to a function that fix the array.
For example: If the distance between two coordinates is greater than 5px, the function creates a coordinate in the middle of the two coordinates.
if I take this function off the problem seen to be solved. But if the user move the mouse very slow it still happens. It also creates a problem that i was trying to solve with that function. as the distance of the two coordinates are very big when the ship arrive in one coordinate most of the line path disappear.
I uploaded a version without the function that fixes the array. http://megaswf.com/s/2437775
I think there is 2 ways for solving this problem
1- Try to fix the noise in the array of coordinates 2- Take off the function that create an coordinate between two points and try to fix the problem of the line path disappear.
Here is the 2 important functions:
this function moves the ship
private function mover():void
{
if (caminhoCoords[0]!=null) // caminhoCoords is the array that contain the path
{
var angulo:Number = Math.atan2(this.y - caminhoCoords[0][1], this.x - caminhoCoords[0][0]);
this.rotation = angulo / (Math.PI / 180);
this.x = this.x - velocidade * (Math.cos(angulo));
this.y = this.y - velocidade * (Math.sin(angulo));
var testex:Number = Math.abs(this.x - caminhoCoords[0][0]); //test to see the distance between the ship and the position in the array
var testey:Number = Math.abs(this.y - caminhoCoords[0][1]);
if (testey<=velocidade+2 && testex<=velocidade+2) // if is velocidade+2 close then go to the next coordnate
{
caminhoCoords.shift();
}
}
}
This function draw the line:
private function desenhaCaminho():void //draw the black Path
{
if(caminhoCoords.length>=1)
{
caminho.graphics.clear();
caminho.graphics.lineStyle(1, 0x000000, 1,true);
caminho.graphics.moveTo(caminhoCoords[0][0],caminhoCoords[0][1]);
for (var i:int = 1; i < caminhoCoords.length; i++)
{
caminho.graphics.lineTo(caminhoCoords[i][0], caminhoCoords[i][1]);
}
}else
{
caminho.graphics.clear();
}
}
Every time the ship arrive in one coordinate is take that coordinate off the array and redraw the array.
Is there a better way of doing that?
I believe if you set your registration point of the plane to the centre and use .snapto(path), it will improve the action.
Judging from just the look of the stuttering, I would guess you need to smooth out the "line" a fair bit. It's probably picking up a lot of noise in the line, which is then translated into the rotation of the plane. Either smooth out the rotation/position of the plane, or the line itself.

Ideas for jumping in 2D with Actionscript 3 [included attempt]

So, I'm working on the basics of Actionscript 3; making games and such.
I designed a little space where everything is based on location of boundaries, using pixel-by-pixel movement, etc.
So far, my guy can push a box around, and stops when running into the border, or when try to the push the box when it's against the border.
So, next, I wanted to make it so when I bumped into the other box, it shot forward; a small jump sideways.
I attempted to use this (foolishly) at first:
// When right and left borders collide.
if( (box1.x + box1.width/2) == (box2.x - box2.width/2) ) {
// Nine times through
for (var a:int = 1; a < 10; a++) {
// Adds 1, 2, 3, 4, 5, 4, 3, 2, 1.
if (a <= 5) {
box2.x += a; }
else {
box2.x += a - (a - 5)*2 } } }
Though, using this in the function I had for the movement (constantly checking for keys up, etc) does this all at once.
Where should I start going about a frame-by-frame movement like that? Further more, it's not actually frames in the scene, just in the movement.
This is a massive pile of garbage, I apologize, but any help would be appreciated.
try doing something like: (note ev.target is the box that you assigned the listener to)
var boxJumpDistance:Number = 0;
function jumpBox(ev:Event){
if (boxJumpDistance<= 5) {
ev.target.x += boxJumpDistance; }
else if(boxJumpDistance<=10){
ev.target.x += boxJumpDistance - (boxJumpDistance - 5)*2
}
else{
boxJumpDistance = 0;
ev.target.removeEventListener(Event.ENTER_FRAME, jumpBox);
}
}
then instead of running the loop, just add a listener:
box2.addEventListener(Event.ENTER_FRAME, jumpBox);
although this at the moment only works for a single box at a time (as it is only using one tracking variable for the speed), what you would really want to do is have that function internally to the box class, but im unsure how your structure goes. the other option would be to make an array for the boxes movement perhaps? loop through the array every frame. boxesMoveArray[1] >=5 for box 1, etc.