Collision not working


#1

Hello,

i have an issue with collision detection in a tower defense game. I have the collision detection in my Enemy class and it should detect when hitting a directional tile to change direction. The think is it is not detecting anything and what is more annoying is that when i put the detection code in the directional tile class it is working. But by doing that i have other issued to deal with so i would prefer it in the Enemy class since it is easier to work with and more logical. This is the directional tile class:

public class directBlock extends Entity {
  private var blockImg:Image;
  
  public var directType:String;
  
  public function directBlock(type:String, xVal:int, yVal:int) {
    blockImg = new Image(new BitmapData(C.TILE_WIDTH, C.TILE_HEIGHT, false, 0x111111));
    
    x = xVal;
    y = yVal;
    
    directType = type;
    
    setHitboxTo(blockImg);
    
    type = "directBlock";
    
    layer = C.LAYER_DIRECT_BLOCK;
    
    graphic = blockImg;
  }
}

And this is my Enemy class:

public class Enemy extends Entity {
  public var xSpeed:int; //how fast it's going horizontally
  public var ySpeed:int; //how fast it's going vertically
  public var maxSpeed:int = C.MAX_ENEMY_SPEED; //how fast it can possibly go
  
  private var enemyImg:Image;
  
  public function Enemy(initDir:String, xVal:int, yVal:int) {
    var sprite:Sprite = new Sprite;
    sprite.graphics.beginFill(0xFF0000);
    sprite.graphics.drawCircle(12.5,12.5,5);
    sprite.graphics.endFill();
    var bd:BitmapData = new BitmapData(C.TILE_WIDTH, C.TILE_HEIGHT, true, 0);
          bd.draw(sprite);
    enemyImg = new Image(bd);
    
    mask = new Pixelmask(enemyImg.getBuffer());
    
    switch (initDir) {
      case C.U: //up
        xSpeed = 0;
        ySpeed = -maxSpeed;
        break;
      case C.D: //down
        xSpeed = 0;
        ySpeed = maxSpeed;
        break;
      case C.R: //right
        xSpeed = maxSpeed;
        ySpeed = 0;
        break;
      case C.L: //left
        xSpeed = -maxSpeed;
        ySpeed = 0;
        break;
      default:
        xSpeed = 0;
        ySpeed = 0;
        break;
    }
    
    x = xVal;
    y = yVal;
    
    layer = C.LAYER_ENEMY;
    
    type = "enemy";
    
    graphic = enemyImg;
  }
  
  override public function update():void {
    x += xSpeed * FP.elapsed;
    y += ySpeed * FP.elapsed;
    
    var d:directBlock = collide("directBlock", x, y) as directBlock;
    
    if (d) {
      changeDirection(d.directType);
    }
  }

  private function changeDirection(newDir:String):void {
    switch (newDir) {
      case C.U: //up
        xSpeed = 0;
        ySpeed = -maxSpeed;
        break;
      case C.D: //down
        xSpeed = 0;
        ySpeed = maxSpeed;
        break;
      case C.R: //right
        xSpeed = maxSpeed;
        ySpeed = 0;
        break;
      case C.L: //left
        xSpeed = -maxSpeed;
        ySpeed = 0;
        break;
      default:
        break;
    }
  }
}

Their layers are equal and the C.TILE_WIDTH and C.TILE_HEIGHT are both 25 pixels.


(Martí Angelats i Ribera) #2

Have you created the function Image.getBuffer()? Because I can’t find it anywhere.

So the line

mask = new Pixelmask(enemyImg.getBuffer());

should be

mask = new Pixelmask(bd);

You may want to try cfhanging the Pixelmask for a Hitbox for testing porpuses. Also use the trace on the returned instance of the collision to know if it collided.


Also, be sure that you are making the directBlock to have a correct type


If after that it’s not working try downloading the lastest FP version from the GitHub repository.


#3

I have created the getBuffer() function in the Image.as class from Flashpunk a while back for another project, to use Pixelmask with Spritesheets, if memory serves right. Didn’t have a problem with that, it works fine in all the other stuff i did. This is the getBuffer() function:

public function getBuffer():BitmapData { return _buffer; }

And tried with Pixelmask, double checked everything, traced everything doesn’t work. collide(“directBlock”, x, y) returns null all the time.


(Martí Angelats i Ribera) #4

Try downloading the lastest version of FP, using HitBox, and making tests using collidePoint.


#5

Downloaded the latest version and tweaked the Enemy class to this:

public class Enemy extends Entity {
	public var xSpeed:int; //how fast it's going horizontally
	public var ySpeed:int; //how fast it's going vertically
	public var maxSpeed:int = C.MAX_ENEMY_SPEED; //how fast it can possibly go
	
	private var enemyImg:Image;
	
	private var dirArray:Array = new Array();
	
	public function Enemy(initDir:String, xVal:int, yVal:int, a:Array) {
		var sprite:Sprite = new Sprite;
		sprite.graphics.beginFill(0xFF0000);
		sprite.graphics.drawCircle(12.5,12.5,5);
		sprite.graphics.endFill();
		var bd:BitmapData = new BitmapData(C.TILE_WIDTH, C.TILE_HEIGHT, true, 0);
        bd.draw(sprite);
		enemyImg = new Image(bd);
		
		dirArray = a;
		
		//mask = new Pixelmask(enemyImg.getBuffer());
		setHitboxTo(enemyImg);
		
		switch (initDir) {
			case C.U: //up
				xSpeed = 0;
				ySpeed = -maxSpeed;
				break;
			case C.D: //down
				xSpeed = 0;
				ySpeed = maxSpeed;
				break;
			case C.R: //right
				xSpeed = maxSpeed;
				ySpeed = 0;
				break;
			case C.L: //left
				xSpeed = -maxSpeed;
				ySpeed = 0;
				break;
			default:
				xSpeed = 0;
				ySpeed = 0;
				break;
		}
		
		x = xVal;
		y = yVal;
		
		layer = C.LAYER_ENEMY;
		
		type = "enemy";
		
		graphic = enemyImg;
	}
	
	override public function update():void {
		x += xSpeed * FP.elapsed;
		y += ySpeed * FP.elapsed;
		/*
		var d:directBlock = collide("directBlock", x, y) as directBlock;
		trace(d);
		if (d) {
			changeDirection(d.directType);
		}
		*/
		//var sign:int = n < 0 ? -1 : 1;
		for each (var d:directBlock in dirArray) {
			var checkColl:Boolean = false;
			if (ySpeed < 0) 
				checkColl = collidePoint(x, y, d.x, d.y); //does not work
			else 
				checkColl = collidePoint(d.x, d.y, x, y); //works
			if (checkColl) {
				changeDirection(d.directType);
			}
		}
	}

	private function changeDirection(newDir:String):void {
		switch (newDir) {
			case C.U: //up
				xSpeed = 0;
				ySpeed = -maxSpeed;
				break;
			case C.D: //down
				xSpeed = 0;
				ySpeed = maxSpeed;
				break;
			case C.R: //right
				xSpeed = maxSpeed;
				ySpeed = 0;
				break;
			case C.L: //left
				xSpeed = -maxSpeed;
				ySpeed = 0;
				break;
			default:
				break;
		}
	}
}

I gave the enemy an array with all the directional blocks and then tried to use collidePoint() to check if they collide, but only one works collidePoint(d.x, d.y, x, y) which, from my limited knowledge i admit, means that it detects when the directional block collides with the enemy but the other way around it doesn’t work. Also I used this tutorial :http://www.flashgametuts.com/tutorials/as3/how-to-create-a-tower-defense-game-in-as3-part-3/ to make this but i translated it into flashpunk, i just used the same level array to create the basic level and see if everything works. I checked the enemy collision with a turret which works. I will try to check if it works with a normal road block which it just occured to me i didn’t check, but the problem with directional blocks persists.

Edit: Wow, so collide(“roadBlock”, x, y) in the Enemy class up;date function works, it returns a roadBlock entity. This is the roadBlock class:

public function roadBlock() {

	roadImg = new Image(new BitmapData(C.TILE_WIDTH, C.TILE_HEIGHT, false, 0x111111));
		
	setHitboxTo(roadImg);
		
	type = "roadBlock";
		
	layer = C.LAYER_ROAD_BLOCK;
		
	graphic = roadImg;
}

Why does that work but the directional block which is just the same thing, only with the x and y values in the constructor which in this case are set before added to the world in the world entity?


(Martí Angelats i Ribera) #6

I think you didn’t get the idea of using collidePoint. The idea was the following (testing only):

//TestingWorld.as
package 
{
	/**
	 * ...
	 * @author Copying
	 */
	public class TestingWorld extends World
	{
		
		public function TestingWorld() 
		{
			
		}
		
		override public function begin():void
		{
			add(new DirectBlock(C.L));
			trace(collidePoint(1, 1));
		}
	}

}
//DirectBlock.as
package 
{
	/**
	 * ...
	 * @author Copying
	 */
	public class DirectBlock extends Entity
	{
		public var directType:String;
		
		public function DirectBlock(type:String, x:Number = 0, y:Number = 0) 
		{
			var blockImg:Image = new Image(new BitmapData(C.TILE_WIDTH, C.TILE_HEIGHT, false, 0x111111));
			super(x, y, blockImg);
			layer = C.LAYER_DIRECT_BLOCK;
			
			setHitboxTo(blockImg);
			
			this.type = "directBlock";
			
			directType = type;
		}
	}

}

Using this you shoudl get the entity traced. Do the same with the Enemy (but remember that you’ll have to use higher numbers). Then post if it works.

PS: The classes are usually started with Uppercase. Also remember that you can use the this inside a class (no need for things called xVal or yVal simply use this.x = x)