How Others Do It Version -5

13 posts

Flag Post

Okay in this thread we’re going to try to illustrate the dos and don’ts of spawning
hitboxes for games. If you’re out to make any kind of arcade style action game, in the likes of street fighter, final fight, streets of rage, splatterhouse, etc..
its very important to create the hitbox at the right place(s) at exactly the right frame(s), to make sure the punch your hero will throw hurts your enemy when it touches his face.

Ryu here will demonstrate what I’m talking about. http://i.imgur.com/c11dr.png

In a later post I’ll show my way of doing it, and why it sucks.

 
Flag Post

You can try making a simple editor that involves dragging the mouse and making rectangles over the sprite sheet and naming them; the “generate” buttons generate a json file that has all the rectangles data. The json is loaded at runtime and according to their information, your game engine does some simple math to use the information to detect collision.

 
Flag Post
Originally posted by qwerber:

You can try making a simple editor that involves dragging the mouse and making rectangles over the sprite sheet and naming them; the “generate” buttons generate a json file that has all the rectangles data. The json is loaded at runtime and according to their information, your game engine does some simple math to use the information to detect collision.

This, but depending on the complexity of your game, a separate tool may not even be necessary. Just add a Hitbox class and structure it something like:

public function Hitbox(animationName:String, frames:Array, hitboxRect:Rectangle){

Then in your character class add an addHitbox function or sommin. Or if you have a separate Animation class to control the frames, add it to that instead.

 
Flag Post

Well the current method I’m using involves putting the sprites all on one movieclip, in the same fashion you can view character animations in Fighters Factory. Managing the frames goes in two different functions like this.

var cFrame:int=1;

function manageFrames(frameStart:Number,frameEnd:Number):void
{
cFrame=currentFrame;

if(currentFrame < frameStart || currentFrame >= frameEnd)
gotoAndStop(frameStart);
else
nextFrame();

//trace(currentFrame);

};

function manageAttackFrames(frameStart:Number,frameEnd:Number):void
{
cFrame=currentFrame;

if(currentFrame == frameEnd)
attack=false;

if(currentFrame < frameStart || currentFrame >= frameEnd)
gotoAndStop(frameStart);
else
nextFrame();
}

would the function spawnHitBox() be written similar to this?

 
Flag Post

don’t think you should use frames at all; If you are using spritesheets, how come you are using movieclips? Are you perhaps using a mask?

 
Flag Post

Phase 1 – convert png/bmp into symbol
phase 2 – ctrl-b to break apart the spritesheet
Phase 3 – magic wand the pink out and slice up the symbol.
Phase 4 – paste the slice ups onto a new movieclip.
Phase 5 – PROFIT!

I find it MUUUUUCH easier than blitting.

I got it from here http://www.youtube.com/watch?v=lMQrshyK8_c&amp;list=PL1677E9A1DA9645A4&amp;index=1&amp;feature=plpp_video

 
Flag Post

I find it MUUUUUCH easier than blitting.

Phase 1 – convert png/bmp into symbol
phase 2 – ctrl-b to break apart the spritesheet
Phase 3 – magic wand the pink out and slice up the symbol.
Phase 4 – paste the slice ups onto a new movieclip.
Phase 5 – PROFIT!

how about:

Phase 1 – Load Sprite Sheet
Phase 2 – Give frame size and define animations in constructor
Phase 3 – Profit!

Not only is it easier to use, it’s faster in terms of performance too :)

If you want to use moveiclips, I suggest a mask.

 
Flag Post

Phase 1 – make a sprite sheet (regular more likely)
Phase 2 – create a list of BitmapData objects to be used out of the sprite sheet (and yes, define animations)
Phase 3 – use a single Bitmap object per instance, and stuff it with links to list of Phase 2
Phase 4 – make a lot of phase-3 objects, and make them run wild

PROFIT!!! Both memory-wise and performance-wise, even with display list, but can be used with blitting if the objects will use raw BitmapData pointers instead of Bitmaps

 
Flag Post

How do I do all this? Or for that matter how does ANY newcomer to flash do any of this?
Your methods may give better performance and memory (and yes PROFIT), but it will also give headaches and frustration.

In any case the animations are done and working and so long as you don’t delete the original bitmap from your library, you’re fine.
But please remember this topic is about hitboxes, not spritesheets.

 
Flag Post
Originally posted by FlashGrenade:

How do I do all this? Or for that matter how does ANY newcomer to flash do any of this?
Your methods may give better performance and memory (and yes PROFIT), but it will also give headaches and frustration.

Doing anything new gives headaches and frustration initially. When I made the jump from AS2 to AS3, lots of things were frustrating because of how different they were compared to my at-the-time AS2 comfort zone. Once I got used to them, the frustration went away and now, they are my comfort zone.

So yeah, all you really need to do is be willing to face that challenge and endure the frustration for a bit. Once the clouds lift, you’ll have gained a new skill and expanded your comfort zone.

Anyway, on topic:

1) Insert image into sprite (I haven’t used sprite sheets yet, but I will in my next project)
2) Define hit box boundaries automagically, based on inserted image. (I defaulted to 75% of the image’s size)
(1 & 2 all happen in the constructor)
3) Profit.

Pretty simple really, but this was for a pretty simple game.

 
Flag Post

I’d model each character as a collection of geometrical hit targets (number and size depending on the realism of contact I’m going for), probably circles and rectangles for a 2D fighting game. When you make the frame animation you also have to specify where some key points in the character are (e.g. head, shoulder, elbow, hand) so the hit geometry can be adjusted accordingly.

 
Flag Post

okay. i promised the original way i did hitboxes.
The original plan was to draw invisible hitboxes on top of the frames, and have the variables written on the timeline
as seen in the OP ryu pictue.

The hitbox class was defined as hitData. Which looked like this

	public class hitData {
		public var attackArea:Object;
		public var damage:int=0;
		public var effect:int=0;
		public var attackwidth:int= 0;
		
		/* Effects
		0 = no effect
		1 = knockdown
		2 = it sets you on fire
		*/
		public function hitData(attackBox:Object,myWidth:int, myDamage:int,myEffect:int) {
			trace("A hitData object was constructed");
			
			this.attackArea=attackBox;
			this.attackwidth = myWidth;
			this.damage=myDamage;
			this.effect=myEffect;
		}
		public function getAttackRegion():Object{
			var returnBox:Object=this.attackArea;
			return returnBox;
		}
		public function getWidth():int {
			return this.attackwidth;
		}
		public function getDamage():int {
			return this.damage;
		}
		public function getEffect():int {
			return this.effect;
		}
	}//class

For the record. It worked. But obviously it needs to be switched with something better.

 
Flag Post

Now for a much cleaner version

This has not been fully tested yet, BUT. this class is supposed to be able to be called externally and can be removed
on its own. Once its on the stage it runs a combat check function to see if its touching anything, and if it does deal the damage and remove itself.

public class spawnHitBox extends Shape {
	public var Player1:Hero;
	public var atkDamage:int=0;
	public var atkEffect:int=0;
	public var stageRef:Stage;	
		/* Effects
		0 = no effect can be used for grabbing purposes
		1 = knockdown
		2 = it sets you on fire
		3 = lightning damage
		4 = light damage
		5 = heavy damage
		*/
public function spawnHitBox(stage01:Stage,xSpot:int,ySpot:int,myWidth:int,myHeight:int,myDamage:int,myEffect:int) {
	
	this.stageRef=stage01;
	this.atkDamage=myDamage;
	this.atkEffect=myEffect;
	var container = new Sprite();
	container.graphics.lineStyle(1,0x00CCFF);
	container.graphics.beginFill(0x00CCFF);
	container.graphics.drawRect(xSpot,ySpot,myWidth,myHeight);
	container.graphics.endFill();
	stageRef.addChild(container);
	trace("A hitbox was constructed");
	stageRef.addEventListener(Event.ENTER_FRAME, combatCheck);		
}//function HitBox
		
public function removeSelf():void {
		
	if (stageRef.contains(this)) {
		stageRef.removeChild(this);
		stageRef.removeEventListener(Event.ENTER_FRAME, combatCheck);
	}
}//function removeSelf()

public function combatCheck():void {
trace("Combat check Start.");
			
if (this.hitTestObject(Player1)) {
		Player1.takeDamage(this.atkDamage,this.atkEffect);
		this.removeSelf();
		
}//if (this.hitTestObject(Player1))

for each (var oneEnemy:Enemy in enemyCharacters) {
	if (this.hitTestObject(oneEnemy)) {
		oneEnemy.takeDamage(this.atkDamage,this.atkEffect);
		this.removeSelf();
			
	}//if 
}//for each (var oneEnemy:Enemy in enemyCharacters)

for each (var breakable:BreakObject in breakableObjects) {
	if (this.hitTestObject(breakable)) {
		breakable.takeDamage(this.atkDamage,this.atkEffect);
		this.removeSelf();
	}//if 
}//for each (var breakable:BreakObject in breakableObjects) 
							
}//function combatCheck()
}//class