Jump to content

Collision

From OpenBOR
(Redirected from Bbox.meta tag)

Collision boxes tell OpenBOR (or any other game engine) what portions of an entity are able to hit or get hit and what areas of a level are walls or platforms. In OpenBOR these boxes are geometric cubes the engine continuously compares to each other – whenever two or more cubes overlap, that’s a collision and the engine will react accordingly.

Depending on the type of collision box, it will have other properties that tell the engine how to handle the collision event. This article focuses on Attack (hitting with attacks) and Body (Receiving attacks and taking up space). Walls and platforms work on a similar principal and are covered in level design.

Multiple Boxes

OpenBOR supports multiple collision boxes per frame, up to 64 of each type. To define a second box of any type, add collision.index {index} with your desired index and then define a set of properties for the next box. You may use any integer value from 0 - 63 for {index}. All subsequent collision box properties below collision.index {index} now act on the new index.

You can repeat this process to add a third box, a forth box, and so on. To adjust or disable the boxes, again use collision.index {index} to define which box you wish to act on, then disable or adjust the box properties as you would a single occurrence.

When two or more attack boxes overlap a body box or body boxes, OpenBOR will acknowledge a single collision with the lowest index attack and body boxes taking priority.

Tip: Don’t get carried away with multiple boxes. Collision boxes are meant to describe practical contact areas, not trace literal sprite pixels. Even high precision versus fighters like Street Fighter and King of Fighters typically use only two or three body boxes and one attack box. Beat em’ ups and action games almost invariably use only one of each outside of edge cases.

Take the following two examples. The first is an unfortunately real amateur design with impressive-looking but needlessly wasteful boxes. This is not precise collision – it is a pointless flex. In game, it will likely feel janky and inconsistent.

Eight times the work - half the precision.

Now observe this design – a professional example straight from Capcom’s Capcom vs. SNK series. It uses only the minimum needed: broad, readable body coverage and a clear attack area. That is not just more optimal – it is mechanically stronger in play.

The pros know.

Attack

Attacks hit and presumably cause damage to other entities. To define an attack, add the necessary attack commands from list below immediately before the frame. In most cases you only need the basic dimensions and damage value. The other attack properties are optional and most are disabled by default.

Once defined, an attack remains active throughout remainder of the animation unless you redefine it. To disable an attack, add attack 0 or attack none before a frame.

Command List

Command Default Description
attack.block.cost 0 Amount attack removes from target’s guardpoints when blocked.
attack.block.penetrate 0 If this meets or exceeds target’s block threshold, target cannot block attack.
attack.counter 0 If 1+, this attack treats target’s attack boxes as body boxes. If both attacks have counter value, highest value has priority.
attack.coordinates 0 0 0 0 0 0 Shortcut for setting all basic coordinates in a single line: x, y, width, height, depth background, depth foreground.

Note: All 0 disables the collision box. If any other values are defined and both z depth values are 0 or undefined, they will be replaced with a default value of grabdistance setting / 3 + 1. Assuming the Grabdistance default of 36, this gives the box a depth of 13 pixels in each direction.

attack.damage.force 0 Value deducted from target’s hit points.
attack.damage.land.force 0 If attack causes a fall, value deducted from target’s hit points on landing.
attack.damage.land.mode 0 If attack causes knockdown, target’s projectile status and landing ability. Projectile status has no effect if target’s fall animations do not have an attack box.
  • 0 – Normal fall. Target’s attack boxes are disabled until landing.
  • 1 – Target’s attack boxes are enabled in projectile mode until landing, meaning target will hit its allies.
  • 2 – Same as 1. Additionally, if player controlled targets have LAND animation available, they may play it on landing and nullify land force by holding Up + Jump.
attack.damage.lethal.disable 0 If true, attack cannot reduce target’s hit points below 1.
attack.damage.recursive.force 0 Amount deducted from target’s hitpoints on each recursive tick. See Recursive Damage.
attack.damage.recursive.index 0 Index ID applied to recursive damage. See Recursive Damage.
attack.damage.recursive.mode 0 How recursive damage applies to target’s hit points or magic points. See Recursive Damage.
attack.damage.recursive.tag 0 Creator defined value ignored by native engine logic. See Recursive Damage.
attack.damage.recursive.time 0 How long in elapsed time the recursive damage effect will last. See Recursive Damage.
attack.damage.recursive.rate 0 How long in elapsed time between each tick of recursive damage. See Recursive Damage.
attack.damage.steal 0 If true, attack.damage.force is added to attacking entity’s hit points.
attack.damage.type 1 Attacking type. Works with target’s defense values and reacting animations. Accepts following values:
  • Any 1+ number. For legacy compatibility, attacks are NOT 0 indexed. If you provide a value of 0, 1 is used instead.
  • Blast
  • Burn
  • Freeze
  • Shock
  • Steal

See Attack Types for details.

attack.effect.block.flash.model None Name of model to spawn when target blocks attack.
attack.effect.block.sound.path None Path to sound file that plays when target blocks attack.
attack.effect.hit.flash.layer.adjust 0 Added to global layer adjustment of flash spawn drawing layer. See Hit Effects.
attack.effect.hit.flash.layer.source 0 Added to global hit flash layer source value for controlling source of flash spawn drawing layer. See Hit Effects.
attack.effect.hit.flash.model None Name of model to spawn when attack hits target. If undefined, the global flash model spawns.
attack.effect.hit.flash.disable 0 If true, no model spawns when attack hits target.
attack.effect.hit.sound.path None Path to sound file that plays when attack hits target.
attack.ground.mode 0 Ability to hit fallen targets on the ground.
  • 0 - Attack cannot hit lying targets.
  • 1 - Attack can hit lying targets.
  • 2 - Attack only hits lying targets.
collision.index 0 Used for multiple attack boxes on one animation frame. 0 is the first attack box. 1 is the second, and so on. Place this immediately before other properties to have them act on that index. See multiple collision boxes for details.
attack.map.index 0
  • If 1+, target entity switches to this palette index. For example, if hit by attack.map.index 3, the target switches to palette 3 if available.
  • If -1, target applies its freeze palette.

You can also use one of following named indexes. If the defending target has a matching named palette index defined, it will apply that palette index.

  • burn
  • freeze
  • ko
  • shock
attack.map.time 0 Elapsed time to maintain attack.map.index effect. Target reverts to previous palette afterward.
attack.position.x 0 X position of attack box, starting from far left of image. Positive integers move right, negative moves left.
attack.position.y 0 Y position of attack box, starting from far top image. Positive integers move down, negative moves up.
attack.reaction.fall.force 0 Amount deducted from target’s knockdowncount. If this value is 1+ and target’s knockdowncount is 0, target is knocked down. Note the knock down check is made immediately after deduction, so if the target has a knockdowncount of 1 and is hit attack with attack.reaction.fall.force 1, the target falls.


Note: Default knockdowncount is 0, so unless the target is set up with a specific knockdowncount or some other means to resist falling, setting this value to any causes knockdown.

attack.reaction.fall.velocity.x 1.2 X axis toss velocity applied to target if attack knocks it down.
attack.reaction.fall.velocity.y 3.0 Y axis toss velocity applied to target if attack knocks it down.
attack.reaction.fall.velocity.z 0.0 Z axis toss velocity applied to target if attack knocks it down.
attack.reaction.freeze.mode 0 Freeze effect.
  • 0 – No freeze effect.
  • 1 – Target freezes in place.
attack.reaction.freeze.time 0 Elapsed time to maintain attack.reaction.freeze.mode effect.
attack.reaction.invincible.time 0 Elapsed time target is invincible to subsequent hits.


Note: 0 is allowed and is the default property value. However, the engine will substitute a 0 value with 40 when applying the invincibility time. The legacy fastattack command works by setting this property to 10.

attack.reaction.pain.disable 0 If true, target does not play a reaction animation when hit by attack.
attack.reaction.pause.time 0 Elapsed time target and attacker pause (freeze) when attack hits.
attack.reaction.reposition.direction None Force target to face specific direction when attack hits.
  • Left – Target faces left.
  • Opposite – Target faces opposite direction of attacker.
  • None – No direction adjustment.
  • Same – Target faces same direction as attacker.
  • Right – Target faces right.
  • Toward – Face toward attacker position.
  • Away – Face away from attacker position.
attack.reaction.reposition.distance 0 Horizontal distance between attacker and target when applying attack.reaction.reposition.mode.
attack.reaction.reposition.mode 0 Horizontal position adjustment when attack hits and does not knock down.
  • 0 – None.
  • 1 - Target moves to attacker.
  • 2 - Target and attacker move to each other, splitting distance.
attack.seal.cost 0 If 1+, this is maximum allowed MP cost target for target specials. For example, if target is hit with seal 10, the target may only use specials that cost 10 MP or less each.
attack.seal.time 0 Elapsed time to apply attack.seal.cost.
attack.size.x 0 X size in pixels, moving right from attack.position.x.
attack.size.y 0 Y size in pixels, moving down from attack.position.y.
attack.size.z.background grabdistance setting / 3 + 1 Z size in pixels, moving further from player’s viewpoint from entity position.

Note: For legacy compatibility, it is impossible to set a 0 value using native text. If you do, it is replaced with the default value.

attack.size.z.foreground grabdistance setting / 3 + 1 Z size in pixels, moving toward player’s viewpoint from entity position.
Note: For legacy compatibility, it is impossible to set a 0 value using native text. If you do, it is replaced with the default value.
attack.staydown.rise.time 0 Elapsed time added to target’s risetime if knocked down.
attack.staydown.attack.time 0 Elapsed time before target can use its RISEATTACK animation if knocked down.

Note: Normally, RISEATTACK is available immediately after a knockdown.

attack.tag 0 Creator defined integer ignored by engine logic. Note: Subject to removal on completion of meta_data feature.

Example

Single

This example defines a single attack box that knocks down and does 10 points of damage, then closes the box on the subsequent frame. Notice only the necessary properties are defined. Order is irrelevant.

attack.position.x 58
attack.position.y 90
attack.size.x 92
attack.size.y 25
attack.reaction.fall.force 1
attack.reaction.pause.time 10
attack.damage.force 15
attack.effect.hit.flash.model flash_fatal_fury

frame data/chars/terry/atk_j_side_kick_c_1.png

attack none

frame data/chars/terry/atk_j_side_kick_c_1.png
Terry Bogard attacks with a typical hit box.

Multiple

This example takes advantage of multiple boxes to place a more accurate attack area around Ryu’s leg. The second box has an index of 1. Since we didn’t bother to define an index for the first box, it gets a default index of 0. Unless the target is really close, we want the contact area (and thus flash spawns) to be around Ryu’s foot, so we let it have the default index of 0 to give it higher priority over 1. The attack definitions are otherwise identical to single boxes. On the following frame, we close both the attack boxes.

attack.damage.force 12
attack.effect.hit.flash.model flash_fatal_fury
attack.reaction.fall.force 1
attack.reaction.pause.time 12
attack.position.x 138
attack.position.y 44
attack.size.x 32
attack.size.y 26

collision.index 1

attack.damage.force 12
attack.effect.hit.flash.model flash_fatal_fury
attack.reaction.fall.force 1
attack.reaction.pause.time 12
attack.position.x 112
attack.position.y 61
attack.size.x 33
attack.size.y 25

frame data/chars/ryu/20_3.png

collision.index 0
attack none

collision.index 1
attack none

frame data/chars/ryu/20_4.png
Two boxes are better than one?
Take it on the chin!

Tip: As noted above, it is usually an anti-pattern to try and trace collision over the sprite too closely - the multiple box example here is just to demonstrate the principal. In most cases, best practice is to add a body box for head and torso rather than more attack boxes.

Body

Body boxes detect incoming attacks. If an entity doesn’t have a body box on a given frame, it can’t detect attacks and is effectively invincible from conventional hits. Defining a body box is nearly identical to attack boxes, except body boxes are far simpler as they have fewer properties.

To end a body box, add bbox 0 or bbox none before a frame.

Command Default Description
bbox.effect.hit.flash.layer.adjust 0 Added to global layer adjustment of flash spawn drawing layer. See Hit Effects.
bbox.effect.hit.flash.layer.source 0 Added to global hit flash layer source value for controlling source of flash spawn drawing layer. See Hit Effects.
bbox.defense None At time of writing, no function. This is a feature in progress that will allow setting up defense properties for individual body boxes.
bbox.meta_data None At time of writing, no function. This is an in progress feature to allow unlimited storage of creator defined data.
bbox.meta_tag 0 Creator defined integer ignored by engine logic. Note: Subject to removal on completion of meta_data feature.
bbox.position.x 0 X position of body box, starting from far left of image. Positive integers move right, negative moves left.
bbox.position.y 0 Y position of body box, starting from top of image. Positive integers move down, negative moves up.
bbox.size.x 0 X size in pixels, moving right from body.position.x.
bbox.size.y 0 Y size in pixels, moving down from body.position.y
bbox.size.z.background 0 Z size in pixels, moving further from player’s viewpoint from entity position.
bbox.size.z.foreground 0 Z size in pixels, moving toward player’s viewpoint from entity position.

Example

Single

This example defines a single body box to detect hits.

bbox.position.x 66
bbox.position.y 49
bbox.size.x 38
bbox.size.y 98

Multiple

This example takes advantage of multiple boxes to place a more accurate hit area area area around Ryu. The second box has an index of 1, and the third an index of 2. Since we didn’t bother to define an index for the first box, it gets a default index of 0. Unless the target is really close, we want the contact area (and thus flash spawns) to prioritize Ryu’s head, then body, so we place the lower indexed boxes in order from head to feet. The body definitions are otherwise identical to single boxes.

bbox.position.x 78
bbox.position.y 48
bbox.size.x 25
bbox.size.y 21

collision.index 1

bbox.position.x 67
bbox.position.y 57
bbox.size.x 35
bbox.size.y 51

collision.index 2

bbox.position.x 62
bbox.position.y 103
bbox.size.x 47
bbox.size.y 46

frame data/chars/ryu/idle_0.png

collision.index 0
bbox none

collision.index 1
bbox none

frame data/chars/ryu/idle_1.png

Advanced

Hit Placement

Each time a collision occurs, OpenBOR records the location and several other data points into a structure called lasthit. This is then used for items like the native flash effects. Lasthit is available as a system variable and as local vars in didhit and takedamage scripts.

Hit location is the calculated center point where the respective collision boxes overlap on each Axis.

OpenBOR places a flash effect on the centroid by default, but also exposes the coordinates for creator use.

Legacy Attack

Legacy attack boxes use a single attack command with multiple parameters. Additional parameters are available through separate commands we call “Supplements”. Most legacy attack commands sanitize time inputs into cetiseconds, whereas modern commands accept raw elapsed time values.

Note: Legacy attack commands are depreciated and will not receive further updates.It is highly recommended any new projects utilize the current attack box commands.

Base commands

Attack

Default legacy attack box. Other than {#}, you cannot omit an optional parameter and use any other parameters rightward. For example, if you want to include a {pausetime} value, you must also include {power}, {block}, and {noflash}.

attack{#} {x} {y} {right} {down} {damage} {power} {block} {noflash} {pausetime} {z}
  • {#} – See attack.damage.type (numbers only). {#} is part of the command name, no spaces. As an example, if you wanted an attack type 2, you would write attack2 {x} {y} .... Optional. If omitted, defaults to 1.
  • {x} – See attack.position.x.
  • {y} – See attack.position.y.
  • {right} – See attack.size.x.
  • {down} – See attack.size.y.
  • {damage} – See attack.damage.force.
  • {power} – Optional. See attack.reaction.fall.force.
  • {block} – Optional. See attack.block.penetrate.
  • {noflash} – Optional. See attack.effect.hit.flash.disable.
  • {pausetime} – Optional. See attack.reaction.pause.time.
  • {z} – Optional. See attack.size.z.1 and attack.size.z.2. Legacy Z affects both directions.

Blast

Same as Attack other than following:

blast {x} {y} {right} {down} {damage} {block} {noflash} {pausetime} {z} 
  • attack.damage.type = Blast. Note blast type does nothing on its own and defaults to type 1 reactions.
  • attack.reaction.fall.force = 1.
  • attack.reaction.fall.velocity.x = is 2.083.
  • attack.damage.mode = 1.

Burn

Same as Attack other than the following:

Burn {x} {y} {right} {down} {damage} {knockdown} {block} {noflash} {pausetime} {z}
  • attack.damage.type = Burn.

shock

Same as attack# other than the following:

shock {x} {y} {right} {down} {damage} {knockdown} {block} {noflash} {pausettime} {z} 
  • attack.damage.type = Shock.

Freeze

Same as Attack other than the following:

freeze {x} {y} {right} {down} {damage} {time} {block} {noflash} {pausetime} {z} 
  • attack.damage.type = Freeze. Note freeze type does nothing on its own and defaults to type 1 reactions.
  • attack.reaction.freeze.mode = 1.
  • {time} – Time in centiseconds to remain frozen.
  • attack.map.index = 1.

Steal

Same as Attack other than the following:

steal {x} {y} {right} {down} {damage} {knockdown} {block} {noflash} {pausetime} {z}
  • attack.damage.type = Steal. Note steal type does nothing on its own and defaults to type 1 reactions.
  • attack.damage.steal = 1.

Supplements

grabin

grabin {type} {distance}
  • {type} – See attack.reposition.mode.
  • {distance} – See attack.reposition.distance.

Fastattack 1

When enabled, applies a static value of attack.reaction.invincible.time 10.

Forcedirection

forcedirection {dir}
  • {dir} – See attack.reposition.direction.

Damageonlanding

damageonlanding {value} {type} 
  • {value} – See attack.damage.land.force.
  • {type} – See attack.damage.land.mode.

Dropv

dropv {height} {speedx} {speedz}
  • {height} – See attack.reaction.fall.velocity.y.
  • {speedx} – See attack.reaction.fall.velocity.x.
  • {speedz} – See attack.reaction.fall.velocity.z.

Nokill

nokill {bool}
  • {bool} – See attack.damage.lethal.disable.

stun {int}

  • {int} – See attack.reaction.freeze.mode.

Seal

seal {time} {energy} 
  • {time} – Time in centiseconds to stay under seal effect.
  • {energy} – See attack.seal.cost.

Forcemap

forcemap {map} {time}
  • {map} – See attack.map.index.
  • {time} – Time in centiseconds to keep forcemap.

Noreflect

noreflect {bi} 

{bi} – See attack.reaction.pain.disable.

Jugglecost

jugglecost {int} 
  • This command limits juggling ability of the attackbox.
  • Juggling means attacking falling opponents (assuming they are vulnerable while falling). It doesn’t matter if the attackbox knocks down or not cause juggling always knock down opponent.
  • This command is used in conjunction with ‘jugglepoints’ (see Header Data above).
  • The command works like this:
    • If attackbox hits opponent whose ‘jugglepoints’ is higher than or equal with ‘jugglecost’, the attack will connect. At this condition, opponent’s ‘jugglepoints’ will be subtracted by that ‘jugglecost’. This drops ‘jugglepoints’ which limits juggling ability. If attackbox hits opponent whose ‘jugglepoints’ is lower than ‘jugglecost’, the attack will not connect. At this condition, opponent’s ‘jugglepoints’ will remain the same.

OTG

OTG {bi}

{bi} – See attack.ground.mode.

Guardcost

guardcost {int} 

{int} – See attack.block.cost.

  • Defines how much ‘guardpoints’ will be subtracted from opponent if they block this attack.

DOT

DOT {Index} {Time} {Mode} {Force} {Rate} 
  • {index} – See attack.damage.recursive.index.
  • {time} – See attack.damage.recursive.time.
  • {mode} – See attack.damage.recursive.mode.
  • {force} – See attack.damage.recursive.force.
  • {rate} – See attack.damage.recursive.rate.

Staydown

staydown {rise} {riseattack} 

{rise} – See attack.staydown.rise.time.

{riseattack} – See attack.staydown.attack.time.

Legacy Body

Legacy body box commands are nearly identical to legacy attack box commands in format.

Note: As with legacy attack commands,legacy body commands are depreciated and will not receive further updates. It is highly recommended any new projects utilize the current body box commands.

body {x} {y} {width} {height} {depth back} {depth front}

  • {x} – See body.position.x.
  • {y} – See body.position.y.
  • {width} – See body.size.x.
  • {height} – See body.size.y.
  • {depth back} – See body.size.depth.back.
  • {depth front} – See body.size.depth.front. If omitted, {depth back} sets depth in both directions.

bboxz {depth back} {depth front} – See body.size.depth.back and body.size.depth.front