• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Deflection Angle

Level 12
Joined
Mar 28, 2005
Messages
160

Introduction

I was asked about stuff bouncing off other stuff a while back, and posted a script of which I couldn't recall the source, and which I wasn't sure how functioned.
To that end, I decided I wanted my own script for doing this, one that I understood, and could manipulate in the future to my needs.

Description


Code:
A missile (or some other assumingly circular object) is traveling along minding its own business.
From out of nowhere comes a building, or perhaps some other projectile, or maybe even a wall out ahead.
Preferably in a somewhat realistic fashion.
If such a collision were to take place, and the missile interacts in an [U]elastic[/U] fashion,
what should be its new and improved, direction of travel?

JASS:
// Returns angle in radians
function GetDeflectionAngle takes unit missile, unit target returns real
    return 2.*Atan2(GetUnitY(target)-GetUnitY(missile),GetUnitX(target)-GetUnitX(missile))+bj_PI-GetUnitFacing(missile)*bj_DEGTORAD
endfunction

// Wrapper, returns angle in degrees
function GetDeflectionAngleDeg takes unit missile, unit target returns real
    return bj_RADTODEG*GetDeflectionAngle(missile,target)
endfunction

We are presumably colliding a missile with some static object. You can always replace the target with a set of x and y coordinates, or some other projectile.

It's important to note, however, that this is entirely dependant upon the direction the missile is traveling, which I assume is its facing. If this is not the case, update the script to account for this irregularity.

On a second and equally important note, the first function returns the angle in radians, whereas the wrapper returns the angle in degrees. Remember that, it's important!!!

Lastly, a word from the wise, for aesthetics sake, don't update your projectiles facing, its slow and ugly. Simply create a new one at the correct angle in its place.

Simple enough.
Feel free to stop reading here, and just start your collisions. :goblin_yeah:

========================================

Then again, if you are feeling bold, try the rest on for size:

Given what we know about deflections, we can see that so long as our entity collides with some flat surface, given we know the angular relationship between the two (incident angle), we can determine the exiting (accidental) angle.

Well, we don't have a flat surface. We have a building, or something like it. Additionally, however, we have a center position, or an x and y coordinate system, for our target, the direction our missile is traveling (its facing), and the angle between it and the target its interacting with (which we can calculate using simple trigonometry).

We are therefore going to assume that at some distance out from our center point (collision radius), the missile is interacting with a flat surface. A silly assumption, I know, but it's the only one that works.

Ok, now the goal is to eventually determine our accidental angle (B in the picture), which is directly related to the incidental angle

Ergo, if we can calculate our incidental angle, we will be able to calculate our accidental angle. Easy enough, pretty much pie infact, with some simple arithmetic and geometry.

First, we need a flat surface. Well, in fact, we don't really need the surface, simply it's surface normal, which for our purposes is the angle between the missile and the building:
JASS:
bj_RADTODEG*Atan2(GetUnitY(target)-GetUnitY(missile),GetUnitX(target)-GetUnitX(missile))

This provides us with the WC3 world angle between these two entities, which is the angle perpendicular to our interaction "surface".

Now the difference between the surface normal and the missile traveling angle is our incident angle:
JASS:
angle-face

This can be negative, in fact, it needs to be, considering we're working on the positive direction (in other words, clockwise about our WC3 world), so don't fret.

Now that we have this difference, doubling it will give us the difference between the incident and accident angles, since they are both equally spaced apart from the surface normal:
JASS:
2.*(angle-face)

Not so fast, yes this is the difference between the two, but we can't simply add this to our current direction angle to give us the new direction, that won't work at all.

We are bouncing off of and moving in the opposite direction from the target. Therefore our new angle is going to be in the opposite direction of the current:
JASS:
face+180.

There are 360 degrees in a circle, +180 will give us the opposite direction.

Now that we have our opposite direction, adding the multiple of our surface/incident difference will give us the new angle of deflection:
JASS:
face+180.+(2.*(angle-face))

Using simple algebra, this can be further optimized through expansion, into the following form:

JASS:
face+180.+(2.*(angle-face))=face+180.+2.*angle-2.*face
=-face+180.+2.*angle //or,
=2.*angle+180.-face


***
Let's do a simple example on a sheet of paper, go ahead, take one out, I'll wait......

Our missile is traveling at 45 degrees, and when it interacts with the building they are at a 90-degree angle. Draw a compass, label the axis. Draw a dot somewhere, facing 45 degrees, and draw another at a 90-degree angle from the first.

JASS:
ang=90.
face=45.

=face+180.+(2.*(angle-face))
=45.+180.+(2.*(90.-45.))
=225.+(2.*45.)
=225.+90.
=315. degrees

Draw a line directed outward from your first dot at a 315-degree angle. Looks pretty good, no? Well, thats the idea, I knew you'd see things my way.

Enjoy,
Hulk3
 
Last edited by a moderator:
Level 10
Joined
Jun 26, 2005
Messages
236
Your arithmetic can be simplified:

JASS:
face+180.+(2.*(angle-face)) = face+180.+2.*angle - 2.*face
                            = -face+180.+2.*angle //OR, Neater:
                            = 2.*angle+180.-face
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
Your arithmetic can be simplified:

JASS:
face+180.+(2.*(angle-face)) = face+180.+2.*angle - 2.*face
                            = -face+180.+2.*angle //OR, Neater:
                            = 2.*angle+180.-face

I have tested this in Excel and can confirm. In fact it can be written as:

JASS:
2 * angle + 180 - face //The "." is not needed unless avoiding floor division
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
Instead of 180 it would be bj_PI. But that's the only change aside from also turning the "facing" angle into radians.

The . turns the value into a real, else it is treated as an integer. Integers function more quickly than reals, making it a bit more efficient. On top, it's easier to read, quicker to type and lovingly reduces the map file size by the most insignificant amount.

This will display 0.5:

JASS:
BJDebugMsg(I2S(0.25 * 2))
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
@Adiktuz, I moved this to the tutorial submissions a long while ago.

@emjlr3 If you link to the tutorial from your signature instead of using a picture it will attract people to use it. Signatures, if made to look nice, are a good eye-catcher.

I suggest doing the primary function in radians and doing a wrapper function with degrees.

JASS:
function GetDeflectionAngle takes unit missile, unit target returns real
    return 2 * Atan2(GetUnitY(target) - GetUnitY(missile), GetUnitX(target) - GetUnitX(missile)) + bj_PI - GetUnitFacing(missile) * bj_DEGTORAD
endfunction
 
function GetDeflectionAngleDeg takes unit missile, unit target returns real
    return bj_RADTODEG * GetDeflectionAngle(missile, target)
endfunction
 
Level 4
Joined
Feb 18, 2009
Messages
18
im new to jass and still learning about it... how do i get this system to work properly in my map?
I am assuming that it takes more than just miporting the code into my map and expect it to work, so do i need to create some sort of trigger and a custom script to get the code or ?
 
Top