Colliding with a TYPE, make that TYPE run a function? [SOLVED]


(John Andersson) #1

Hi.

I have a sword class, and in that class I check for collisions with enemies.

		if (attacking)
		{
			if (collide("enemy", x, y, )
			{
				"enemy".takeDamage()
			}
			
			if (sprSword.frame == 6)
			{
				sprSword.play("idle");
				attacking = false;
			}
		}

I have one enemy so far, with the type “enemy”, and I have a function in that enemy class (takeDamage) which I want to run when the sword hits it. I am going to put a takeDamage func on every enemy. Obviously what I wrote doesn’t work, how can I fix it? :stuck_out_tongue: Thanks

NEW PROBLEM:

How do I make it so that when the hero collides with an enemy, if the enemy is an imp, then he will get damaged? And if it’s a guy, he won’t?


(Jonathan Stoler) #2

The collide() function returns a collided Entity.

So you can store the result of the collide() function as a variable, cast it as an Enemy, then call takeDamage().

var e:Enemy = collide("enemy", x, y) as Enemy;
if(e != null){
	e.takeDamage();
}

I recommend you read through FlashPunk’s documentation. It has a lot of great features and you’ll be able to solve problems a lot faster if you’re more familiar with how FlashPunk works.


(John Andersson) #3

but I don’t have a class called “Enemy”, it is called Imp. But I want to add more different classes of the type “enemy”, so I don’t have to copy paste that code for every different enemy class.

Because otherwise I need to make something like this

var e:Imp = collide(“enemy”, x, y) as Imp; if(e != null){ e.takeDamage(); }

var e:Guy = collide(“enemy”, x, y) as Guy; if(e != null){ e.takeDamage(); }

var b:Goblin = collide(“enemy”, x, y) as Goblin ; if(e != null){ e.takeDamage(); }

etc


(Jonathan Stoler) #4

In this case, I recommend you create a class, Enemy, and make Imp, Guy, Goblin, etc. subclasses of Enemy. Enemy should be a subclass of Entity.

Make sure your Enemy class has a takeDamage() method (you can leave it empty if you want or include some default behavior). Then, in each of your subclasses, override the takeDamage() method to do whatever you need for each type of enemy.


(John Andersson) #5

How exactly should I make them subclasses? I tried googling but couldn’t find an answer. And won’t this cause troubles since I’m adding enemies according to an XML file?

private function loadLevel(xml:Class):void { var rawData:ByteArray = new xml; var dataString:String = rawData.readUTFBytes(rawData.length); LevelData = new XML(dataString);

		var dataElement:XML;
	
		var dataListBackTiles:XMLList;
		var dataListFrontTiles:XMLList;
		var dataListSpawn:XMLList;
		var dataListWeaponDrop:XMLList;
		var dataListPushable:XMLList;
		var dataListImpSpawn:XMLList;

	
		dataListBackTiles = LevelData.Back.tile;
		dataListFrontTiles = LevelData.Front.tile;
		dataListPushable = LevelData.Entities.Pushable;
		dataListSpawn = LevelData.Entities.Spawn;
		dataListWeaponDrop = LevelData.Entities.WeaponDrop;
		dataListImpSpawn = LevelData.Entities.ImpSpawn;
		
		for each(dataElement in dataListBackTiles)	
		{
			_tiles.setTile(int(dataElement.@x), int(dataElement.@y), int(dataElement.@id));
		}
		
		//Walkable
		for each(dataElement in dataListFrontTiles)
		{		
			_tiles.setTile(int(dataElement.@x), int(dataElement.@y), int(dataElement.@id));
			_ground.setTile(int(dataElement.@x), int(dataElement.@y), dataElement.@id);
		}
			
		for each(dataElement in dataListSpawn)
		{
			FP.world.add(new Hero(new Point(int(dataElement.@x), int(dataElement.@y))));
		}

		for each(dataElement in dataListWeaponDrop)
		{
			FP.world.add(new WeaponDrop(new Point(int(dataElement.@x), int(dataElement.@y))));;
		}
		
		for each(dataElement in dataListPushable)
		{
			FP.world.add(new Pushable_Block_Wood(new Point(int(dataElement.@x), int(dataElement.@y))));;
		}
		
		for each(dataElement in dataListImpSpawn)
		{
			FP.world.add(new Imp(new Point(int(dataElement.@x), int(dataElement.@y))));;
		}
		
	}

How on earth would I make that work with subclasses? And how do I even make them subclasses? xD I also tried the documentation, but it didn’t say anything about “subclasses”

THanks :slight_smile:


(Jonathan Stoler) #6

You don’t need to change this XML code at all to support what I’m talking about.

As for subclasses, creating a subclass means making a new class that extends another class, something you’ve done for Worlds, Entities, and maybe more depending on your project.

For this particular project, all you need to do is create a new Enemy class that extends Entity and contains a method, takeDamage(), then edit all of your Imp, Goblin, etc. classes to extend Enemy rather than Entity. You’ll need to modify each of their respective takeDamage() methods to account for the fact that you’re now overriding the takeDamage() method from Enemy.


Take a look at Adobe’s ActionScript documentation for more information on how classes, subclasses, and object-oriented programming work. I recommend you read through all the links on that page to get a better understanding about programming in ActionScript.

If you’re curious about other concepts, there’s a long list of other topics off to the left. FlashPunk will handle a lot of these things for you (ie, sound, graphics) but things like Arrays and Strings will help you in almost any project.


(John Andersson) #7

You’re THE BEST. Now I can actually make new weapons and make them extend the weapon class too. YOU HELPED ME SO MUCH! :slight_smile: Thank you!!!

Although I have a new problem now xD


(Ultima2876) #8

What’s the new problem? :smiley: Maybe we can help.


(John Andersson) #9

:smiley:

How do I make it so that when the hero collides with an enemy, if the enemy is an imp, then he will get damaged? And if it’s a guy, he won’t? ^^

something like

//Collisions with enemies if (enemyCollision) { if (invincibilityCounter == 0) { //Imp if(enemyCollision IS of class IMP)

				if (enemyCollision.IMPCLASS.sprImp.currentAnim == "attack") //sprImp is the spritemap
				{
					if (enemyCollision.IMPCLASS.sprImp.index >= 6)
					{
						var damageTaken:Number = Imp.impStrength * armorReduction;
						var xLocation:Number = x + this.width / 2 - 10;
						var a:Number = x + this.width / 2;
						var b:Number = Math.floor(Math.random() * (1 + y + 10 - y)) + y;
						
						hp -= damageTaken;
						invincibilityCountDown = true;
						
						FP.world.add(new DamageShower(a, b, damageTaken, "0xFFFFFF"));
					}
				}
			}
		}

(Jonathan Stoler) #10

I might be confused about what you’re asking here, but if you have separate takeDamage() methods in each of your classes (so Imp.takeDamage() would be different than Guy.takeDamage()), then you can customize the behavior in each class, so when you tell the “enemy” to run takeDamage() it will perform the appropriate method for the class. In this case, Guy.takeDamage() would not actually cause damage, but Imp.takeDamage() would.


(John Andersson) #11

Oh, but I mean for the hero. So that HE takes damage depending on if it is an imp or not. So this isn’t about the sword class anymore, it’s about the hero class.


(Jonathan Stoler) #12

In that case, you can just add a property, enemyType, to your Enemy class, and have something like this in your Hero class after the collision check:

var e:Enemy = collide("enemy", x, y) as Enemy);
if(e != null){
	e.takeDamage();
	switch(e.enemyType){
		case "imp":
			// do something
			break;
		case "guy": break;
		default: break;
	}
}

(Ultima2876) #13

Or make a function dictionary if there are a lot of types.

private var _enemyCollisionFunctions: Object = new Object;

//constructor
public function myClassName(): void
{
  _enemyCollisionFunctions["imp"] = impCollisionFunction;
  _enemyCollisionFunctions["guy"] = guyCollisionFunction;
}

public override function update(): void
{
  var e:Enemy = collide("enemy", x, y) as Enemy);
  if(e != null && _enemyCollisionFunctions[e.enemyType] != null) {
    _enemyCollisionFunctions[e.enemyType](); //call the respective function
  }
}

private function impCollisionFunction(): void
{
  //do something
}

private function guyCollisionFunction(): void
{

}

This method has numerous advantages but the biggest is probably that you can later subclass your Hero class and override those functions for different functionality.


(Zachary Lewis) #14

Or, you can go even further and have the colliding type deal with the damage. Let’s also add an interface for extra OOP!

IDealsDamage

public interface IDealsDamage
{
  function dealDamage(target:Hero):void;
}

Imp

public class Imp extends Entity implements IDealsDamage
{
  public function Imp()
  {
    // Imps are enemies.
    type = "enemy";
  }

  public function dealDamage(target:Hero):void
  {
    // Imps just deal damage.
    target.health -= 2;
  }
}

Snake

public class Snake extends Entity implements IDealsDamage
{
  public function Snake()
  {
    // Snakes are enemies.
    type = "enemy";
  }

  public function dealDamage(target:Hero):void
  {
    // Snakes deal less damage, but also poison.
    target.health -= 1;
    target.poisoned = true;
  }
}

Cat

public class Cat extends Entity
{
  public function Cat()
  {
    // Cats are enemies.
    type = "enemy";
  }

  // Cats can't hurt people, bro.
}

GameWorld

public class GameWorld extends World
{
  private var _hero:Hero;

  override public function update():void
  {
    var collidingEntity:Entity = _hero.collide("enemy", _hero.x, _hero.y);

    if (collidingEntity != null)
    {
      // The hero has collided with an enemy.
      if (collidingEntity is IDealsDamage)
      {
        // The hero has collided with a damage dealer.
        IDealsDamage(collidingEntity).dealDamage(_hero);
      }
    }
  }
}

Now, whenever the hero collides with an Imp or a Snake, it will call dealDamage(), but if the hero collides with a Cat, no damage will be dealt. And that’s dope.


(John Andersson) #15

Thanks a lot guys! :slight_smile: I love you