Collision detection for loop problem, only one array item tested? - actionscript-3

[I apologise if this isn't really an in depth question, but I wanted to solve this once and for all]
I was trying to get look into quadtrees, but already ran into trouble getting collision detection without any optimization working properly. Did a search and found a pretty neat example:
http://wonderfl.net/c/kyLx
(onenterframeC part mostly)
Trying to imitate this, it won't work the same.
Only some collisions are detected between particular objects. When the objects are not moving it seems to work alot better for some reason.
I really can't figure out whats the problem, the code is essentially the same as the sample. I did not blindy copy pasted it, I understands whats happening except for this part:
if (j <= i)
continue;
J would never become bigger that I right? The line also completely removes any working collisions for me.
Here is what I did:
[view result here: http://martinowullems.com/collision.swf
Main class
package
{
import com.martino.objects.Square;
import com.martino.world.TestWorld;
import flash.display.MovieClip;
import flash.events.Event;
import net.hires.debug.Stats;
/**
* ...
* #author Martino Wullems
*/
public class CollisionTest extends MovieClip
{
var world:TestWorld;
public function CollisionTest()
{
addEventListener(Event.ADDED_TO_STAGE, onStage);
}
private function onStage(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, onStage);
SetupWorld();
addChild(new Stats());
}
private function SetupWorld():void
{
world = new TestWorld();
addChild(world);
addObjects(50);
}
private function addObjects(amount:int):void
{
for (var i:int = 0; i < amount; ++i) {
var square:Square = new Square(14);
world.addObject(square);
square.x = Math.random() * stage.stageWidth;
square.y = Math.random() * stage.stageHeight;
square.speedX = (Math.random() * 1) + 1;
square.speedY = (Math.random() * 1) + 1;
}
}
}
}
TestWorld
package com.martino.world
{
import com.martino.objects.Ball;
import com.martino.objects.CollisionObject;
import flash.display.MovieClip;
import flash.events.Event;
/**
* ...
* #author Martino Wullems
*/
public class TestWorld extends MovieClip
{
public var objects:Array;
public function TestWorld()
{
initWorld();
}
private function initWorld():void
{
objects = new Array();
addEventListener(Event.ENTER_FRAME, loopWorld);
}
private function loopWorld(e:Event):void
{
for (var i:int = 0; i < objects.length; i++) {
MoveObject(objects[i]);
CheckCollision(i, objects[i]);
}
}
private function CheckCollision(i:int, object:CollisionObject):void
{
//for (var j:int = i + 1; i < objects.length; j++) {
for (var j:int = 0; j < objects.length; j++) {
//if (j <= i)
//continue;
var objectB:CollisionObject = objects[j];
//hittest
if (object.hitTestObject(objectB)) {
object.isHit = true;
objectB.isHit = true;
}else {
object.isHit = false;
objectB.isHit = false;
}
/////////////////
// CHECK X Y //
////////////////
/*if (object.x + object.width < objectB.x) {
} else if (object.x > objectB.x + objectB.width) {
object.isHit = objectB.isHit = false;
} else if (object.y + object.height < objectB.y) {
object.isHit = objectB.isHit = false;
} else if (object.y > objectB.y + objectB.height) {
object.isHit = objectB.isHit = false;
} else {
object.isHit = objectB.isHit = true;
}*/
object.debugDraw();
objectB.debugDraw();
}
}
private function MoveObject(object:CollisionObject):void
{
object.x += object.speedX;
object.y += object.speedY;
////////////////////
//check boundaries//
////////////////////
if (object.x > stage.stageWidth)
{
object.speedX *= -1;
}else if (object.x < 0)
{
object.speedX *= -1;
}else if (object.y > stage.stageHeight)
{
object.speedY *= -1;
}else if (object.y < 0)
{
object.speedY *= -1;
}
}
public function addObject(object:CollisionObject):void
{
objects.push(object);
addChild(object);
}
}
}
CollisionObject
package com.martino.objects
{
import flash.display.Sprite;
import flash.events.MouseEvent;
/**
* ...
* #author Martino Wullems
*/
public class CollisionObject extends Sprite
{
public var size:int;
public var speedX:int = 0;
public var speedY:int = 0;
public var graphic:Sprite;
var sleeping:Boolean = false;
public var isHit:Boolean = false;
public function CollisionObject()
{
addEventListener(MouseEvent.MOUSE_DOWN, grab);
addEventListener(MouseEvent.MOUSE_UP, letGo);
}
private function grab(e:MouseEvent):void
{
startDrag();
speedX = 0;
speedY = 0;
}
private function letGo(e:MouseEvent):void
{
stopDrag();
}
public function Collision():void{
}
//////////////////////
// setter and getter//
//////////////////////
public function set isHit(value:Boolean):void {
_isHit = value;
graphic.visible = _isHit;
hitGraphic.visible = !_isHit;
}
public function get isHit():Boolean {
return _isHit;
}
}
}
Square
package com.martino.objects
{
import flash.display.Sprite;
/**
* ...
* #author Martino Wullems
*/
public class Square extends CollisionObject
{
public var hitGraphic:Sprite;
public function Square(Size:int)
{
size = Size;
drawSquare();
}
private function drawSquare():void
{
graphic = new Sprite();
graphic.graphics.beginFill(0xFF0000);
graphic.graphics.drawRect(0, 0, size, size);
graphic.graphics.endFill();
addChild(graphic);
hitGraphic = new Sprite();
hitGraphic.graphics.beginFill(0x0066FF);
hitGraphic.graphics.drawRect(0, 0, size, size);
hitGraphic.graphics.endFill();
addChild(hitGraphic);
hitGraphic.visible = false;
}
override public function Collision():void {
trace("I collided with a friend (inside joke)");
}
public override function debugDraw():void {
if (isHit) {
graphic.visible = false;
hitGraphic.visible = true;
}else {
graphic.visible = true;
hitGraphic.visible = false;
}
}
}
}
Any help would greatly be appreciated, want to get further on this !
EDIT: Changed some stuff, there is progress but stuff still is unclear to me !
Changed some things in TestWorld.as:
package com.martino.world
{
import com.martino.objects.Ball;
import com.martino.objects.CollisionObject;
import flash.display.MovieClip;
import flash.events.Event;
/**
* ...
* #author Martino Wullems
*/
public class TestWorld extends MovieClip
{
public var objects:Array;
public function TestWorld()
{
initWorld();
}
private function initWorld():void
{
objects = new Array();
addEventListener(Event.ENTER_FRAME, loopWorld);
}
private function loopWorld(e:Event):void
{
var object:*;
for (var i:int = 0; i < objects.length; i++) {
MoveObject(objects[i]);
//CheckCollision(i);// doesn't work here for some reason [case 1]
}
CheckCollision(0); //[case 2]
}
private function CheckCollision(i:int):void
{
//test collision
for (var i:int = 0; i < objects.length; i++){ //only use in case 2
var elementA:CollisionObject;
var elementB:CollisionObject;
elementA = objects[i];
for (var j:int = i + 1; j < objects.length; j++) {
if (j <= i){
continue; //j resets each I loop and therefor sets collision to false while it could be true
}
elementB = objects[ j ]// as ObjSprite;
if (elementA.hitTestObject(elementB)) {
elementA.isHit = elementB.isHit = true;
}
}
} //[case 2]
}
private function MoveObject(object:CollisionObject):void
{
object.x += object.vx;
object.y += object.vy;
////////////////////
//check boundaries//
////////////////////
if (object.x > stage.stageWidth)
{
object.vx *= -1;
}else if (object.x < 0)
{
object.vx *= -1;
}else if (object.y > stage.stageHeight)
{
object.vy *= -1;
}else if (object.y < 0)
{
object.vy *= -1;
}
object.isHit = false;// where do we check when it isn't colliding? this seems messy!
}
public function addObject(object:CollisionObject):void
{
objects.push(object);
addChild(object);
}
}
}
Also added a setter and getter in collisionobject (so section before the edit).
Not sure why I can't put the checkcollision inside the loop on the enter frame function? (when I do no collisions are shown). And placing "isHit = false" inside moveobjects to reset a check for a hit also seems pretty messy.
I can't seem to find out when the objects aren't colliding to reset them I guess.
Making an else statement on the hittest to check if there is no collision doesn't work, seems logical since there could be collisions with more than just 2 items in the hittestcheck.
Any idea's ?

I had to look at the original source to understand this. It is below, for reference.
This line
if (j <= i) continue;
is a permutation check; it basically makes sure that each combination only gets checked once, instead of multiple times. However, for this, you need to have two For loops - an inner one and an outer one.
You've done the same thing with the following line:
for (var j:int = i + 1; i < objects.length; j++) {
Try using that for loop instead of the one that starts from zero. Leave the "if j <= i" line commented, though. I think that will solve your problem. (Those two statements can't coexist in this loop; if used together, they'll cause the problems you're describing.)
Good luck.
Original source from website:
for (i = 0; i < myrects.length; i++) {
elementA = myrects[ i ] as ObjMyRect;
for (j = 0; j < myrects.length; j++) {
if (j <= i)
continue;
elementB = myrects[ j ] as ObjMyRect;
if (elementA.rect.x + elementA.rect.width < elementB.rect.x) {
} else if (elementA.rect.x > elementB.rect.x + elementB.rect.width) {
} else if (elementA.rect.y + elementA.rect.height < elementB.rect.y) {
} else if (elementA.rect.y > elementB.rect.y + elementB.rect.height) {
} else {
elementA.isHit = elementB.isHit = true;
}
}
}
(For what it's worth, I think that this guy's code actually checks objects against themselves for collision - he should change the "if j <= i" line to "if j < i". You solved this problem with your original for loop.)

Couple of things, after looking at his code, and reviewing your code.
This part IS necessary to make sure you don't waste time going through the loop and re-checking items that have already been compared.
if (j <= i)
continue;
Imagine you have 3 items in the array, and compare item 3 to item 0. Then you compare item 3 to item 1, and item 3, to item 2. THEN you compare item 2 to... item 3? You've already done that. You want to compare item 2 to anything lesser than itself so you avoid duplicates.
Your code is close to his, but you've swapped out his version of the hitTest (which uses position + dimension) with the already-defined hitTestObject. I'm only seeing one hit-test on the first square. Something seems off in that... I'd drop some trace statements in there and see what's up.
Last, when you uncomment his code, does it work?

Related

ActionScript 3 - Error #1010: A term is undefined and has no properties

When testing my project, I got this error :
TypeError: Error #1010: A term is undefined and has no properties. firegame.as:115]
at firegame/checkhitammo()[..\Desktop\Flash\firegame.as:115
at firegame/mainloop()[..Desktop\Flash\firegame.as:77
I don't understand why and if I change the if statement to something simple it's all work fine.
This is my code :
package {
import flash.display.*;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.Event;
public class firegame extends MovieClip {
var tiger:Tiger = new Tiger();
var enemys:Array = new Array();
var scorea:Number = 0;
var ammoleft:Number = 0;
var ammo:Array = new Array();
var setint:Timer = new Timer(110);
var setenemy:Timer = new Timer(980);
var newenemy:Number;
var hitcheck:Array = new Array();
var totallength:Number;
public function firegame() {
startgame();
}
public function startgame() {
addplayer();
stage.addEventListener(MouseEvent.MOUSE_MOVE, moveplayer);
stage.addEventListener(MouseEvent.MOUSE_DOWN, shotfire);
stage.addEventListener(MouseEvent.MOUSE_UP, shotfirestop);
setint.addEventListener(TimerEvent.TIMER, shotfirestart);
setenemy.addEventListener(TimerEvent.TIMER, addenemy);
stage.addEventListener(Event.ENTER_FRAME, mainloop);
setenemy.start();
}
public function addplayer():void {
tiger.y = 200;
tiger.x = 507;
addChild(tiger);
}
public function moveplayer(e:MouseEvent):void {
tiger.y = mouseY;
tiger.x = 507;
}
public function shotfire(e:MouseEvent):void {
setint.start();
}
public function shotfirestop(e:MouseEvent):void {
setint.stop();
}
public function shotfirestart(e:TimerEvent):void {
var fire:Fire = new Fire();
fire.x = 460;
fire.y = mouseY;
addChild(fire);
ammoleft -= 1;
ammo.push(fire);
}
public function addenemy(e:TimerEvent):void {
var enemy:Enemy = new Enemy();
enemy.x = 0;
enemy.y = Math.floor(Math.random() * (370 - 30) + 30);
addChild(enemy);
enemys.push(enemy);
}
public function mainloop(e:Event):void {
setscoreandammo();
moveammo();
moveenemy();
checkhitammo();
}
public function moveammo():void {
for (var i:int = 0; i < ammo.length; i++) {
ammo[i].x -= 15;
if (ammo[i].x < -30) {
removeChild(ammo[i]);
ammo[i] = null;
ammo.splice(i, 1);
}
}
}
public function moveenemy():void {
for (var b:int = 0; b < enemys.length; b++) {
enemys[b].x += 5;
if (enemys[b].x > 590) {
removeChild(enemys[b]);
enemys[b] = null;
enemys.splice(b, 1);
}
}
}
public function setscoreandammo():void {
score.text = String(scorea);
leftammo.text = String(ammoleft);
}
public function checkhitammo():void {
for (var i:int = ammo.length; i >= 0; i--) {
for (var b:int = enemys.length; b >= 0; b--) {
if (ammo[i].hitTestObject(enemys[b])) { // <--- this is the line where the error is fired
removeChild(ammo[i]);
ammo[i] = null;
ammo.splice(i, 1);
removeChild(enemys[b]);
enemys[b] = null;
enemys.splice(b, 1);
scorea += 50;
break;
}
}
}
}
}
}
Your specific problem is right here...
public function checkhitammo():void {
for (var i:int = ammo.length; i >= 0; i--) {
for (var b:int = enemys.length; b >= 0; b--) {
...you are starting the counters i and b with the length of the array, instead of the position of the last index. It should read...
public function checkhitammo():void {
for (var i:int = ammo.length - 1; i >= 0; i--) {
for (var b:int = enemys.length - 1; b >= 0; b--) {
That is, the length is 1-based, and positions are 0-based
first of all, all your for loops only has increment by 1 you may want to use like this
for (var i in ammo) {
for (var b in enemys) {
you just have to loop through array until something happens and break out of loop to make sure it doesn't check twice.
in this line
if (ammo[i].hitTestObject(enemys[b])) {
the error says program cannot find object in the array list, since it's just array it does not throw error like null pointer exception
if you swap ammo with enemys you will see that hitTestObject is trying to access a null object
and you don't really need to call this
ammo[i] = null;
since its already being removed

Creat Boundaries

Hello Everyone again :) I'm having an issue with boundaries actually about creating boundaries. In my stage I got 2 mc's names : Dispenser and Puller. Dispenser creating particles and puller is pulling them. I just need to set a boundary like a path.
But i couldn't so asking for your help :)
Bdw the code is from this site : http://www.freeactionscript.com/?s=puller&x=0&y=0
package
{
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
public class Main extends Sprite
{
// you can play around with these
private var particlesTotal:Number = 50;
private var particleSpeed:Number = 10;
private var particleFadeoutSpeed:Number = .0175;
// don't change these
private var particlesCurrent:Number = 0;
private var particlesArray:Array;
private var radians:Number;
private var _sayac:uint;
public function Main():void
{
init();
}
private function init():void
{
radians = 180 / Math.PI;
particlesArray = [];
addEventListener(Event.ENTER_FRAME, onEnterFrameLoop);
dispenser_mc.addEventListener(MouseEvent.MOUSE_DOWN, onThingDown);
puller_mc.addEventListener(MouseEvent.MOUSE_DOWN, onThingDown);
dispenser_mc.addEventListener(MouseEvent.MOUSE_UP, onThingUp);
puller_mc.addEventListener(MouseEvent.MOUSE_UP, onThingUp);
}
private function onThingDown(event:MouseEvent):void
{
event.currentTarget.startDrag();
}
private function onThingUp(event:MouseEvent):void
{
event.currentTarget.stopDrag();
}
private function createParticle(target1:MovieClip, target2:MovieClip):void
{
if(particlesTotal <= particlesCurrent)
{
return;
}
particlesCurrent++;
var tempParticle:Particle = new Particle();
tempParticle.x = (target1.x - target1.width / 2) + (Math.random() * target1.width);
tempParticle.y = (target1.y - target1.height / 2) + (Math.random() * target1.height);
tempParticle.rotation = Math.random()*360;
tempParticle.rot = Math.atan2(target1.y - target2.y, target1.x - target2.x);
tempParticle.xSpeed = Math.cos(tempParticle.rot) * radians / particleSpeed;
tempParticle.ySpeed = Math.sin(tempParticle.rot) * radians / particleSpeed;
tempParticle.mass = tempParticle.width / 2 + tempParticle.height / 2;
particlesArray.push(tempParticle);
addChild(tempParticle);
}
private function updateParticle():void
{
for (var i = 0; i < particlesArray.length; i++)
{
var tempParticle:MovieClip = particlesArray[i];
tempParticle.x -= tempParticle.xSpeed;
tempParticle.y -= tempParticle.ySpeed;
tempParticle.alpha -= particleFadeoutSpeed;
// I know i can set boundries here but idk how to so :)
if(tempParticle.hitTestObject(puller_mc))
{
destroyParticle(tempParticle);
_sayac++;
trace(_sayac);
}
else if (tempParticle.alpha <= 0)
{
destroyParticle(tempParticle);
}
else if (tempParticle.x < 0)
{
destroyParticle(tempParticle);
}
else if (tempParticle.x > stage.stageWidth)
{
destroyParticle(tempParticle);
}
else if (tempParticle.y < 0)
{
destroyParticle(tempParticle);
}
else if (tempParticle.y > stage.stageHeight)
{
destroyParticle(tempParticle);
}
}
}
private function destroyParticle(particle:MovieClip):void
{
for (var i = 0; i < particlesArray.length; i++)
{
var tempParticle:MovieClip = particlesArray[i];
if (tempParticle == particle)
{
particlesCurrent--;
particlesArray.splice(i,1);
removeChild(tempParticle);
}
}
}
private function onEnterFrameLoop(event:Event):void
{
createParticle(dispenser_mc, puller_mc);
updateParticle();
}
}
}
actually there is no boundary in this code. let me explain the main parts of this code for you:
this is the most important part:
tempParticle.rot = Math.atan2(target1.y - target2.y, target1.x - target2.x);
tempParticle.xSpeed = Math.cos(tempParticle.rot) * radians / particleSpeed;
tempParticle.ySpeed = Math.sin(tempParticle.rot) * radians / particleSpeed;
rot is the angle to reach the puller.
xSpeed is how much the particle should go to right  every frame to reach the puller.
ySpeed is how much the particle should go to down every frame to reach the puller.
and in updateParticle function, the partcle will move, according to xSpeed and ySpeed.
so the correct xSpeed and YSpeed will cause particles to go straight.not a boundary !
I   h ☻ p e   I explained good and ,
I   h ☺ p e   this helps !

Error: Call to a possibly undefined method crearNotaS through a reference with static type Class

I'm new at programming and I'm working on a 'minigame' for my career.
I'm getting this error, hope someone can help me out.
public class Notas
{
public var stage:Stage;
public var velocidad:int = 5;
public var i:int = 0;
public var notaS:Array = new Array(16);
public var notaD:Array = new Array(16);
public function Notas(escenario:Stage)
{
stage = escenario;
}
public function Inicializar():void
{
crearNotaS(0xFFFFFF, 30, 10, 0, 0);
}
public function Destruir():void
{
if (notaS[i].y < 720)
{
for (i = 0; i < notaS.length; i++)
{
stage.removeChild(notaS[i])
}
}
}
public function Mover():void
{
notaS[i].y += velocidad;
}
public function drawRect(color:uint, ancho:int, alto:int, x:int, y:int):Sprite
{
var dj:Sprite = new Sprite();
dj.graphics.beginFill(color,1);
dj.graphics.drawRect(0,0,ancho,alto);
dj.graphics.endFill();
dj.x = x;
dj.y = y;
return(dj);
}
public function asignarNotas():void
{
notaS[0] = 1
}
public function crearNotaS(color:int, ancho:int, alto:int, x:int, y:int):void
{
var contador:int = 0;
for (i = 0; i < notaS.length; i++)
{
if (notaS[i] == 1 && i == 0)
{
notaS[i] = drawRect(color, ancho, alto, x, y);
stage.addChild(notaS[i]);
notaS[i].y = -alto / 2;
}
else if (notaS[i] == 1 && i > 0)
{
for (j = i; j < notaS.length; j++)
{
contador = i - j
notaS[i] = drawRect(color, ancho, alto, x, notaS[j].y + alto * contador);
stage.addChild(notaS[i]);
return;
}
}
}
}
}
Its supposed to create a array of squares (only if the content of the index is a 1, if it is a 0 then it won't create the square there.) one on top of each other and then move them all down, like a guitar hero.
Probably the way im doing it isn't proper but well, its the 1st thing i'm doing on my own...
ActionScript is an object oriented Language. Classes are supposed to be objects too and when you want to access their methods you either need to make an instance of them first or make sure the target function is of type "Static", which has limitations of its own.
This is all about core concepts which you need to know before running your code. I suggest taking a look at some tutorials about classes. This might be a good start:
Tutorial: Understanding Classes in AS3 Part 1
But about your code. It misses some imports and variable definitions, not a major flaw though. Im able to run your code. I will attach a zip file containing the AS3 AIR project which i created to test the code: Test Project
You could do this yourself in couple of steps:
Create an As3 project in the IDE of your choice. (I use FlashDevelop)
Declare the variable of type YourClass (Notas) which holds instance of your class
before using functions of your class make an instance of your class and store it in the variable.
viola, use public methods and properties of your class by accessing the variable you created.
this is the main function:
package
{
import flash.display.Sprite;
/**
* ...
* #author tkiafar
*/
public class Main extends Sprite
{
private var _not:Notas;
public function Main():void
{
if (stage) {
_not = new Notas(this.stage);
_not.asignarNotas();
_not.Inicializar();
}
}
}
}
this is your class that resides in the main package (beside main.as):
package
{
import flash.display.Sprite;
import flash.display.Stage;
public class Notas
{
public var stage:Stage;
public var velocidad:int = 5;
public var i:int = 0;
public var j:int = 0;
public var notaS:Array = new Array(16);
public var notaD:Array = new Array(16);
public function Notas(escenario:Stage)
{
stage = escenario;
}
public function Inicializar():void
{
crearNotaS(0xFF00FF, 30, 10, 0, 0);
}
public function Destruir():void
{
if (notaS[i].y < 720)
{
for (i = 0; i < notaS.length; i++)
{
stage.removeChild(notaS[i])
}
}
}
public function Mover():void
{
notaS[i].y += velocidad;
}
public function drawRect(color:uint, ancho:int, alto:int, x:int, y:int):Sprite
{
var dj:Sprite = new Sprite();
dj.graphics.beginFill(color, 1);
dj.graphics.drawRect(0, 0, ancho, alto);
dj.graphics.endFill();
dj.x = x;
dj.y = y;
return (dj);
}
public function asignarNotas():void
{
notaS[0] = 1
}
public function crearNotaS(color:int, ancho:int, alto:int, x:int, y:int):void
{
var contador:int = 0;
for (i = 0; i < notaS.length; i++)
{
if (notaS[i] == 1 && i == 0)
{
notaS[i] = drawRect(color, ancho, alto, x, y);
stage.addChild(notaS[i]);
notaS[i].y = -alto / 2;
}
else if (notaS[i] == 1 && i > 0)
{
for (j = i; j < notaS.length; j++)
{
contador = i - j
notaS[i] = drawRect(color, ancho, alto, x, notaS[j].y + alto * contador);
stage.addChild(notaS[i]);
return;
}
}
}
}
}
}
after all i have some suggestions:
seperate the array that contains control indexes and the one that contains sprites.
avoid making variables public. in your case there is no need for accessing them outside your class, but if you need to make them accessible, use getters/setters. google "getters/setters in as3".
invent some naming standards of your own. google "rules of naming in as3".

How can I set the damage level of enemy

Thanks in advance...
I am having little bit doubt in my logic for setting the Damage level to the enemy in game. Following is my Enemy Class
package scripts.enemy
{
import flash.display.MovieClip;
import flash.events.*;
import flash.display.Stage;
public class Enemy1 extends MovieClip
{
private var BG:MovieClip;
private var speed:Number = 0.5;
private var ease:Number = .005;
private var rad:Number = 57.2957795;
public function Enemy1(BG:MovieClip) : void
{
var RandomX:Array = new Array(-150,-200,-250,-300,-350,-400,-450,-500,-550,150,200,250,300,350,400,450,500,550);
var RandomY:Array = new Array(-150,-200,-250,-300,-350,-400,150,200,250,300,350,400);
var r:int = (Math.random() * 18);
var s:int = (Math.random() * 12);
x = RandomX[r];
y = RandomY[s];
this.BG = BG;
addEventListener(Event.ENTER_FRAME, moveEnemy); //false, 0, true);.
}
private function moveEnemy(e:Event):void
{
var dx:Number = x - 10;
var dy:Number = y - 10;
this.x -= dx * ease;
this.y -= dy * ease;
this.rotation = (Math.atan2(dy,dx) * rad) + 180;
}
}
}
And Here is some of code that giving me trouble from my Main class
// ......... Function for Checking the Collision between Bullet And Enemy...........
private function checkCollision(mc:MovieClip):Boolean
{
var test:Point = mc.localToGlobal( new Point());
for (var i = 0; i < enemies1.length; i++)
{
tempEnemy1 = enemies1[i];
if (kill == true)
{
if (tempEnemy1.hitTestPoint(test.x,test.y,true))
{
enemies1.splice(i, 1);
bg_mc.removeChild(tempEnemy1);
createDead(Dead1,deadArray1,tempEnemy1.x,tempEnemy1.y,tempEnemy1.rotation);
Score += 10;
Scr_txt.text = String(Score);
bugsKill += 1;
kill = false;
return true;
}
}
}
if (Level >= 2)
{
for (var j = 0; j < enemies2.length; j++)
{
tempEnemy2 = enemies2[j];
if (kill == true)
{
if (tempEnemy2.hitTestPoint(test.x,test.y,true))
{
bug2HitCount -= 1;
if (bug2HitCount == 0)
{
enemies2.splice(j, 1);
bg_mc.removeChild(tempEnemy2);
createDead(Dead2,deadArray2,tempEnemy2.x,tempEnemy2.y,tempEnemy2.rotation);
Score += 20;
Scr_txt.text = String(Score);
bugsKill += 1;
kill = false;
//bug2HitCount = bug2HitRate;
return true;
}
kill = false;
return true;
}
}
}
}
return false;
}
private function removeElement(removeList:Array):void
{
for (var i = 0; i < removeList.length; i++)
{
bg_mc.removeChild(removeList[i]);
}
}
//...........Function Checking the Collission Between Bunker And Enemy..............
private function collideEnemy(deadArray:Array,enemyArray:Array,rate:Number):void
{
var enemy:MovieClip;
for (var i = 0; i < enemyArray.length; i++)
{
enemy = enemyArray[i];
if (enemy.hitTestObject(bunker_mc))
{
life_mc.scaleX -= rate;
if (life_mc.scaleX <= 0.05)
{
stage.removeEventListener(Event.ENTER_FRAME,updateCollission);
Timer1.stop();
Mouse.show();
stage.removeEventListener(MouseEvent.MOUSE_UP,mouseUpFun);
stage.removeEventListener(Event.ENTER_FRAME,updateStage);
stage.removeEventListener(MouseEvent.MOUSE_DOWN,mouseDownFun);
(player.parent).removeChild(player);
(bunker_mc.parent).removeChild(bunker_mc);
(life_mc.parent).removeChild(life_mc);
(sniper_mc.parent).removeChild(sniper_mc);
removeElement(bullets);
EndFun();
gunFire = false;
gotoAndStop("end");
Level = 1;
}
}
}
}
//...........function of Timer Complete Event.....................
private function TimerEnd(e:TimerEvent):void
{
EndBug();
gotoAndStop("end");
}
//...........function of Timer Complete Event.....................
private function EndBug():void
{
HelpTimer = new Timer(1000,1);
HelpTimer.addEventListener(TimerEvent.TIMER_COMPLETE,HelpFun);
HelpTimer.start();
stage.removeEventListener(Event.ENTER_FRAME,updateStage);
stage.removeEventListener(Event.ENTER_FRAME,updateCollission);
function HelpFun(Event:TimerEvent)
{
stage.removeEventListener(MouseEvent.MOUSE_UP,mouseUpFun);
stage.removeEventListener(MouseEvent.MOUSE_DOWN,mouseDownFun);
gunFire = false;
bg_mc.removeChild(player);
bg_mc.removeChild(bunker_mc);
(life_mc.parent).removeChild(life_mc);
bg_mc.removeChild(sniper_mc);
EndFun();
Score = 0;
Level += 1;
totalBugs += 5;
}
}
//..................Function for ending the Game And removing the Reamining Enemies.................
private function EndFun():void
{
Mouse.show();
removeElement(dustArray);
if (Level == 1)
{
removeElement(enemies1);
removeElement(deadArray1);
gotoAndStop("level2");
}
if (Level == 2)
{
removeElement(enemies1);
removeElement(deadArray1);
removeElement(enemies2);
removeElement(deadArray2);
gotoAndStop("level3");
}
if (Level == 3)
{
......
}
.....................
.....................
}
}
}
In this code I have added a new type of Enemy in Level 2 and I have also written code for its HitTest property..In which each enemy of level 2 requires more than 1 bullet to kill.. But when I shoot a bullet to one enemy and then I shoot another bullet to another enemy of same type the another enemy gets killed. It means that the second enemy is getting killed in only 1 single bullet.. So how can I solve this issue..?
Please Help.. Thanks in advance..
The problem in your code lies within the checkCollision function. It basically goes over the first for loop and ignores the second. But it's best if you just assign the enemies health by adding a health parameter within your Enemy class and have each bullet decrease their health by 1. That way, you can just go through your array and remove any enemies that reach 0 health.
EDIT: I just looked over your code again and realized it's the bug2HitCount that's screwing everything up.

Can anyone help with the collision detect for my platformer? (Actionscript 3.0)

Im currently working on making a flash platformer engine...but my collision detect needs some serious help. Whenever my character 'jumps', and lands on the collision object, he goes about halfway through it for a split second, then goes back to the top (where I want him to be). If I continue to jump multiple times, the shadow of him, if you will, that appears for a split second goes further and further into the collision object, eventually making him fall all the way through it. Here's the code for my main class, and if you need me to clarify anything, please ask.
package {
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.display.Stage;
import Player;
import HitObject;
public class TestGame extends MovieClip {
private var _hitObject:HitObject;
private var _player:Player;
private var _leftArrow:Boolean;
private var _rightArrow:Boolean;
private var _upArrow:Boolean;
private var _hit:Boolean;
private var _fall:Boolean;
private var _jump:Boolean = true;
private var _velR:Number = 0;
private var _velL:Number = 0;
private var _scale:Number = .1;
private var _jumpCount:Number = 0;
private var _i:Number = .5;
private var _i2:Number = 7;
private var _i3:Number = 0;
private var _adjustHit:Number;
private var _jumpRL:Number;
private var _jumpVel:Number;
public function TestGame() {
_hitObject = new HitObject();
_player = new Player();
addChild(_hitObject);
addChild(_player);
_hitObject.x = (stage.width * 0.5) + 50;
_hitObject.y = (stage.height * 0.5) + 150;
_hitObject.scaleY = 3;
_hitObject.alpha = .5;
_player.scaleX = _scale;
_player.scaleY = _scale;
_player.x += 200;
_player.y += 250;
stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
}
private function enterFrameHandler(e:Event) {
if(_player.hitTestObject(_hitObject)) {
_adjustHit = _hitObject.y - _hitObject.height/2 - _player.height/2;
_player.y = _adjustHit;
_hit = true;
_jump = false;
if(_i3 > 8) {
_jump = true;
}
_jumpCount = 0;
_i2 = 7;
_fall = false;
_i3++;
}
else if(!_player.hitTestObject(_hitObject) && !_upArrow) {
_fall = true;
}
if(_fall) {
_player.y += _i;
_i += .5;
if(_i < 3) {
_i = 3;
}
_hit = false;
}
if(_upArrow && _hit && _jump) {
if(_velR > 0) {
_jumpRL = _velR;
_jumpVel = _velR;
}
else if(_velL > 0) {
_jumpRL = -_velL;
_jumpVel = _velL;
}
else {
_jumpVel = 1;
if(_player.scaleX == .1) {
_jumpRL = 1;
}
else {
_jumpRL = -1;
}
}
_player.y -= _i2 + _jumpVel/2;
_player.x += _jumpRL/2;
_jumpCount += _i2;
_i2 -= .5;
_fall = false;
if(_i2 < -3) {
_jumpCount = 61;
}
if(_jumpCount > 60) {
_i2 = 7;
_jump = false;
_fall = true;
_jumpCount = 0;
}
_i3 = 0;
}
if(_rightArrow) {
_player.startRun();
_player.scaleX = _scale;
_velL = 0;
_player.x += _velR;
if(_velR < 20) {
_velR += 2;
}
if(_velR > 20) {
_velR = 20;
}
}
else if(_leftArrow) {
_player.startRun();
_player.scaleX = -_scale;
_velR = 0;
_player.x -= _velL;
if(_velL < 20) {
_velL += 2;
}
if(_velL > 20) {
_velL = 20;
}
}
if(_velR > 0) {
_player.x += _velR;
_velR -= .7;
}
else if(_velL > 0) {
_player.x -= _velL;
_velL -= .7;
}
if(_velR < 0 || _velL < 0) {
_velR = 0;
_velL = 0;
}
}
private function keyDownHandler(e:KeyboardEvent):void {
if(e.keyCode == 39) {
_rightArrow = true;
}
if(e.keyCode == 37) {
_leftArrow = true;
}
if(e.keyCode == 38) {
_upArrow = true;
}
}
private function keyUpHandler(e:KeyboardEvent):void {
_upArrow = false;
_rightArrow = false;
_leftArrow = false;
}
}
}
For anyone having this problem, make sure you are applying a force in response to collision in addition to repositioning out of collision. This case sounds like maybe the velocity is being compounded by gravity, meaning you keep moving the object back but it's velocity isn't being zeroed out, so it moves further and further into the floor with each update step.
Applying normal force will cancel gravity and fix this.
If you just want easy-to-use collision detection, take a look at the Collision Detection Kit for Actionscript 3. I've used it before and it beats every other collision detection framework I've ever used.
From what you have said it sounds like at time 't' the player has not hit the object as yet but at time 't+1' the player has moved 10px (for example) so now appears stuck in the object until your collision handler moves the player to the correct spot.
Also with the jumping up and down perhaps the player has not been moved back correctly after a collision before his position increments which is why over time the player eventually falls through if you keep jumping.
Be careful about comparing numbers. I see a if (_player.scaleX == .1). Numbers in AS3 are called Floating Point numbers in other languages. Due to the way Floating Point numbers are handled by the computer they can give misleading results. Sometimes a value like 1.0 is really 0.999998 and if thats the case a compare statement will always fail.
As a tip you might want to change some of the values to CONST as you have a lot of hardcoded values, some which are related and could be changed easier by making them a CONST.