1. Trang chủ
  2. » Công Nghệ Thông Tin

Macromedia Flash MX Game Design Demystified phần 3 pot

38 253 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 38
Dung lượng 656,04 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Line-Line Collision Detection In this section we will discuss the equations for lines and for line segments, and how to tell when lines are intersecting.. Lines 3–5 create an object cal

Trang 1

Solving for the time is very difficult We must insert the equations for x1, y1, x2, and y2 We then square both sides of the equation (to get rid of the square root sign) What we are left with is a quadratic equation Quadratic equations have two solutions, which means that when we solve for the time, we will get two answers Conceptually we can see why in this case we will get two separate Imagine two circles moving toward each other At one time they will be touching on an edge As goes on, they will move through each other, but just as they are about to separate, they will be exactly at one point again The two times found by solving the quadratic equation give the two times that a collision can occur When we have our two answers, we look at the lower of the two times and discard the other one

By defining these constants,

If you are interested in seeing this math worked out more rigorously, check out

circ_circ_frame_independent.pdf in the Chapter05 directory on the CD It shows this

worked out manually

Solving Quadratic Equations

Any equation in which the variable has an exponent of 2 (and no other terms with a higher

exponent) is a quadratic equation For instance, a*t2+b*t+c = 0 is a quadratic equation All

quadratic equations have two solutions; this means there are two values for the variable for

the equation is valid The simplest example is x2 = 4 This is a quadratic equation with the two

solutions 2 and -2 There is a formula called the quadratic formula that is used to find the two

solutions Using a*t2+b*t+c = 0 as an example, here are the solutions for t:

and

In the circle-circle example given in this section, the quadratic equation was manipulated until

Trang 2

1. It defines an object for each movie clip to store information about that movie clip

2. It defines a function that updates the position of the movie clips in memory (not on the stage)

3. It defines a function that checks for collisions between any two balls (circles)

4. It defines a function that physically places the balls on the screen

5. It creates an onEnterFrame event to call all of these functions in every frame

Here is the ActionScript that defines the objects:

Next, we loop for each ball, create an object for it, and store information about that ball in its object Notice that we are giving the balls no starting speeds In lines 13–15 we assign starting velocities to the balls Then comes the following ActionScript:

Let's analyze an example Imagine that you are coding a game in which a ball bounces off a wall This ball

could be written in standard quadratic-equation form From there it is easy to solve

Now let's look at an example of this in ActionScript Open circle_circle2.fla from the

Chapter05 folder on the CD There are two movie clips on the stage, ball1 and ball2

its most fundamental level, the ActionScript used here performs all of the following

tasks:

Trang 3

be moving very fast Now imagine that on one frame the ball is not colliding with the wall, and on the next frame you detect that half of the ball is colliding with the wall When this happens, you do not want to update that ball's position on the stage to show this Rather, it is a good idea to update its position in memory to reflect where the ball should be and then render the ball on the screen So, if it is detected that the ball is

colliding with the wall (no matter how deep into the wall the ball is), then we should update the ball's

in memory so that the ball is just barely touching the wall At the end of the frame, we render the ball on screen, and it looks as if it is just barely touching the wall (which is what we want) In real life, a ball would move past the wall boundary

Next we create a function to render the balls onto the stage

This function simply sets the physical position of each movie clip using the value of the x and y position

variables on the object, which are xpos and ypos

Now (drum roll, please) we come to the function that handles the collision detection itself It's a fairly large function, but it follows exactly what we discussed about the logic for determining the collisions

Trang 4

With lines 24–26 we solve the quadratic equation In line 24 we set a variable called sqRoot whose value is equal to the square-root term in our solution to the quadratic equation (remember that there are two both of which contain the same square-root term) We set this as a variable so that it can be reused for solutions (lines 25 and 26) At this point, we have two times at which the balls will collide What follows in ActionScript (lines 27–36) is logic to determine if the time was in the past, the present, or the future If the time is in the past or the present, then it is less than or equal to 1, and a collision has occurred If the time the future (greater than 1), no collision has occurred If a collision has occurred, then we store the time at which this collision happened (using the whatTime variable) We will use this information in Chapter 6,

"Collision Reactions." Also, when a collision is detected, a variable called ballsCollided is set to true ballsCollided is true, a final if statement executes a trace action to let you know that a collision was detected

Generate a SWF to see this work

With this collision-detection script, you can determine when in the future a collision may happen When you solve the quadratic equation for time1 and time2, it tells you any time in the future when the balls will intersect, even if it is a million frames into the future

Looking more than one frame into the future is something I have not yet found a need for, but should a use come for it, we'll know how to do it!

Line-Line Collision Detection

In this section we will discuss the equations for lines and for line segments, and how to tell when lines are intersecting I have never encountered a situation in which I needed a collision-detection script for two lines, so we will just cover detection for two stationary lines

It may not be immediately obvious to you how—or where—this type of collision detection might come in

As an active member of many Flash user boards on the Internet, I frequently see the question of how to tell if two lines are intersecting The most important application of this that we will see is in circle-line collision detection One step in the process of detecting the collision of a circle and a line is to test to see if two lines intersecting

Trang 5

The Equation of a Line

Time once again to think back to your high school math class You may remember this equation:

y = m*x+b

where m is the slope of the line, and b is the y intercept (the spot where the line intersects the y-axis) This

the equation for a straight line The slope, m, is defined as the rise over the run of the line For instance, if

line is at a 45° angle, then the rise of the line equals the run, so the slope is 1 If you have a line that is

to horizontal, then its rise is less than the run, and therefore the slope is small—far less than 1 If the line exactly horizontal, then the rise is 0, and therefore the slope is also 0

Trang 6

If you know the slope and y intercept of a line, then you can draw that line Open draw_line.fla in the

Chapter05 directory on the CD You'll notice that there are no movie clips in this file The ActionScript it contains builds an object that represents the properties of a line (its slope and y intercept) and then draws

line using two functions Here are the first few lines of ActionScript in this file, which are used to build the object

Lines 3–5 create an object called line1 that holds the variables m (for the slope of the line) and b (for the y

It is a good programming practice to create a movie clip to hold lines drawn with

Flash's dynamic drawing tools Why? Because this procedure makes cleanup easier—

you can just remove the movie clip when needed For instance, if you create a

application (in which dynamically creating lines is a common occurrence), then you

most likely want a "clear screen" function It is much easier to remove one movie clip

that contains all of the drawn lines than to remove many individual lines Also, if all

lines had been drawn on the main timeline, then the cleanup would be all the more

difficult

If you are interested in learning more about Flash MX's new drawing Application

Programming Interface (API), check out the ActionScript Dictionary from the Help

menu in Flash

Trang 7

The function findY() was created to calculate the y position from the line object passed in and the x

(using the equation for the line y = m*x+b) After that, starting on line 5, we use the drawLine()

You need two points to draw a line, of course, and so this function chooses two x positions, finds the appropriate y positions from those, and draws a line between this pair of points On line 11 you see the moveTo() method This method is used to move the starting position of the Flash "pen" to the coordinates passed in (The Flash pen, sometimes called the virtual pen, is a place that you cannot see, with the coordinates (0,0), where Flash will start drawing if you were to call the drawing methods The moveTo()method only moves the position of the pen—it draws no lines There is a method called lineTo(), found in

17, that handles drawing the line It draws a line from the current pen position to the coordinates passed The final line is what calls the function This function call passes in a line1 object reference to the

() function The drawLine() function then uses this reference to access information on the object

It is important to note that all lines are infinite in length, although in this case we are showing only a the line in question A portion of a line is called a line segment

Intersecting Lines

All lines that are not parallel to each other intersect at some point, and any two lines that have the same are parallel So, to tell if two lines intersect, you simply compare their slopes If the slopes are not equal, they do intersect somewhere in space In this section, we're going to learn how to find out at what

any two lines intersect

Slope 1 Slope 2; therefore they intersect at some point

Trang 8

First, let's look for the point of intersection Say we have two lines whose equations are

y = m1*x+b1

and

y = m2*x+b2

At the point where these two lines intersect, the y value (in the equations above) is the same, and the x (in

equations above) is the same With this knowledge, we set the two equations equal and write:

m1*x+b1 = m2*x+b2

and we solve for x to get:

x = (b2-b1)/(m1-m2)

This is the x position at which the lines intersect To find the y position, simply stick this x value back into

either of the two line equations (I've chosen the first):

Open lines_intersecting.fla from the Chapter05 folder on the CD to see this in action

This file uses the same functions as we did in the previous example Also, since we

now dealing with two lines, we have created a second line object There is an

of a movie clip on the stage called dot that, when calculated, will be moved to the

point of intersection Here is the function that calculates the intersection

Trang 9

This function accepts two parameters, line_aand line_b, which are references to line objects It then the equation we derived above to find the x position of the intersection Once this x position is found, it is

plugged into the equation for the line represented by the line_a object to find the y position Then the dot

movie clip is placed on the stage using these two values When you test the movie, you will see that the appears over the intersection of the two lines

Determining If Two Line Segments Are Intersecting

This is an easy extension of what we have already accomplished in this section The technique we just introduced allows us to determine if two lines are intersecting To do this, we find the coordinates of the intersection between these lines as if they were not segments, and then check to see if this point falls within the boundaries of each segment It may not be obvious when something like this would be useful Without thinking very hard, I can only come up with one common use, but it's a big one It occurs when detecting a frame-independent collision between a circle and a line This is covered in detail in the next section

Lines intersect, but the segments do not; therefore there is no collision

Lines intersect, and so do the segments; therefore a collision is occurring

Trang 10

The findIntersection() function also has a major addition for our current purposes—it now checks the point of intersection to see if it is within the segment boundaries on both lines Here is the function:

Open line_segments_intersecting.fla in the Chapter05 directory After defining the

objects that represent the lines in this file, we add two variables, x1 and x2, that are

the boundaries of the line segment I modified the drawLine() function from the

same function in the previous example file to take the x1 and x2 boundaries of each

line and to find the y1 and y2 boundaries from them Here is the modified drawLine

() function

Trang 11

5

5 dot._y = y;

6

6 if ((x>=line_a.x1 && x<=line_a.x2)

|| (x<=line_a.x1 && x>=line_a.x2)

|| (y>=line_a.y1 && y<=line_a.y2)

|| (y<=line_a.y1 && y>=line_a.y2)) {

9 if ((x>=line_b.x1 && x<=line_b.x2)

|| (x<=line_b.x1 && x>=line_b.x2)

|| (y>=line_b.y1 && y<=line_b.y2)

|| (y<=line_b.y1 && y>=line_b.y2)) {

The first five lines of this function are identical to the findIntersection() function in the previous

What follows in the remainder of the function are conditional statements that check to see if the

point is within the boundaries of the segments Lines 6–8 check to see if the point is between the x

or between the y boundaries of line_a If it is, then the point lies on the segment Lines 9–11 do the same thing as 6–8, but for line_b If the point lies within the boundaries of both segments, then a trace action executed, letting you know that an intersection has been encountered

If you are really interested in point-line collisions, pay special attention to the final scripts developed in the section Using them, you'll be able to set the radius of a circle to 0, and thereby detect point-line collisions circle of radius 0 is a point)

Circle-Line Collision Detection

In this section we discuss frame-independent circle-line collision detection This operation has direct

to any game that involves a ball bouncing off (or rolling down) a banked wall or hill—games like pinball and miniature golf

We begin by discussing the logic needed to detect a collision between a circle and a line We are assuming the line is stationary and the circle is moving We are also assuming that a collision is not yet taking place detection begins (so if the ball is colliding with the line when the script starts, then the script will fail) In the previous section we developed a way to determine where two lines intersect We will use that here as well A ball in motion builds an imaginary line as it moves (its trajectory) We determine where this line of trajectory and the main line intersect Once this is found, we use trigonometry to figure out the precise spot at which circle collides with the line Then we find the point of collision on the line (where the circle touches the line) Finally, we look at the current position of the circle and figure out how long it will take for the circle to reach collision point If this result is less than or equal to one frame, then a collision has occurred

To recap, this is the process of frame-independent circle-line collision detection more concisely:

1 Determine the intersection point between the path of the circle and the line

2 Use trigonometry to find the coordinates of the circle when it initially collides with the line

3 Find the coordinates of the point of collision on the line itself

4. Calculate the number of frames it takes for the circle to move from its current position to

this collision position If this number is less than or equal to 1, then a collision has occurred.

You might have expected to see a section on point-line collision detection before

line collision detection I didn't include that technique for two reasons First, in my

experience, point-line collision detection is not very useful Second, unless you are

doing frame-independent collision detections, it's almost impossible that a point-line

collision will ever be detected

Trang 12

You have already seen how to accomplish what is in steps 1 and 4, in the sections above So before

an example FLA file, let's look at how to accomplish what is in steps 2 and 3

The results of step 1 show us where the path of the circle intersects the line This intersection point is where the center of the circle would touch the line if it were to make it this far along the path (After we add

reactions in the next chapter, the circle will not make it this far; it will have reacted and rebounded when its edge touched the line.) As you can see, this is not the point at which a collision first occurs If you were to the circle and slide it backward along its path until only one point intersected with the line, then you would have found the collision point We can find this point using trigonometry A right triangle is formed by the radius of the circle; the segment of the circle's path between the line-line intersection and the collision point; and the piece of the line that is between these two intersections

The angle gamma in the image above is the difference between the angle of the path of the ball and the

of the line Our goal in this step is to find the position of the circle when it first touches the line Remember, we're going to find this position by using some trigonometry Be sure to look at the image above to help you understand the relationships between the values we're using The length of the path segment, r, is equivalent

to radius/sin(gamma) We find this relationship by inspecting the right triangle and using the projection

information discussed in Chapter 3, "Trigonometry 101." This relationship tells us the length of that line segment With that information, we can use trigonometry again to find the position of the circle The x

of the circle at first collision is the x position of the line intersection of the path and line minus r*cos(theta)

And the y position of the circle at the first collision is the y position of the line intersection of the path and the

line minus r*sin(theta) (Theta is the angle that the path of the ball makes with the x-axis.)

In step 3, we are looking for the actual point where the circle touches the line—the point of contact In the previous step we found the point where the circle is when it touches the line, but not actually the point on circle that touches the line To find this point, we must imagine a line drawn from the center of the circle through the point of contact This is a line perpendicular to the line with which we are colliding We then the intersection between these two lines This point is what we are looking for We can compare this point the boundaries of the line segment to determine if the collision happened

There is only one thing we have not discussed in how to create the perpendicular line—the equation for that line We know the equation for the main line (it is stored in the line object), and we know that this new perpendicular to the main line A line perpendicular to another line has a slope that is the negative inverse

So if the main line has a slope of 3, then all lines perpendicular to it have a slope of –1/3

Trang 13

All perpendicular lines to this have a slope of –1/3

z An object called ball is created to hold information about ball1

z A function is created to make it easy to create lines on the stage An object is created for each line to store information about that line

z A function called getTempPositions() is created This function is not yet necessary for what we're going to do with this file However, when you later add gravity and collision reactions, this function

be more useful Its duty is to create a temporary position in memory of all moving objects It was

to handle updating positions due to gravitational, wind, or other external forces

z A function called render() takes the temporary position of each moving object and sets that as the position It then physically places the movie clips on the screen In this file we only have one moving object, so the function is quite simple and short

z A function called getFrames() handles the collision detection

z A function called bankCollisionDetect() was created to loop through all the lines on the screen call the getFrames() function for each line

z An onEnterFrame event calls getTempPositions(), bankCollisionDetect(), and render() in every frame

Wow—there are a lot of steps to this, but the result is something cool:

frame-independent collision detection! Let's look at an example Open circle_line.fla from the

Chapter05 folder on the CD There are two movie clips on the stage One of them has

an instance name of ball1 and will be the movie clip that represents a circle The

other movie clip does not have (or need) an instance name It is there so that we

use attachMovie() to create new instances of it It will contain a line that will be

drawn using ActionScript There is a lot of ActionScript in this file, more than 100

We are going to focus on describing the ActionScript in the getFrame() function

first, here is an overview of all the ActionScript for this example of circle-line

detection

Trang 14

Now let's look at the getFrame() function This function does several things:

1. Finds the intersection between the path of the ball and the line

2. Finds the position where the ball should be for initial contact

3. Determines the point of contact and compares that with the boundaries of the line segment

4. Calculates the number of frames it will take for the ball to reach the collision point

Steps 3 and 4 are not dependent on each other, and in this function they swap places Here is the

by now—they are what determine the intersection between the two lines

Now we move on to the ActionScript for step 2

4 //The difference between the angle of the line and

of the ball trajectory

In this step we want to find out where the ball should be (its x and y positions) when it first collides with the

line We do this by using the trigonometry described earlier The variable names are the same as described before and match the figure Lines 10 and 11 give us what we're looking for

We perform step 4 next, before step 3 Here is the ActionScript for this step

Trang 15

This step is refreshingly short Here we calculate the number of frames it will take the ball to get from its current position to the point at which it is colliding with the line Thinking back to the chapter on basic

we remember that distance = velocity*frames If we solve this equation for frames, we get frames =

distance/velocity So if we find the distance between the current position and the collision point, and the

velocity along that line, then we can find the number of frames it takes to get there! In line 2 we employ Pythagorean theorem yet again to obtain the distance In line 3 we use that same theorem one more time, find the velocity along the path Finally, in line 4, we get the number of frames by taking the ratio of and velocity

In step 4 we check the physical point of contact to see if it is within the boundaries of the line segment 1

8 if ((xa>tempLine.x1 && xa<tempLine.x2)

|| (xa<tempLine.x1 && xa>tempLine.x2)

|| ((ya>tempLine.y1 && ya<tempLine.y2)

|| (ya<tempLine.y1 && ya>tempLine.y2))) {

about it) and then, with that information, to see where this line intersects with the main line This

is the point of contact We know the slope of the main line, and we know that all lines perpendicular to it slope that is the negative inverse of its own Line 3 shows how we find the slope of the imaginary line Remembering that the equation for a line is y =m*x+b and remembering that we have the coordinates for

point on that line (the center of the circle), we can plug in the x, y, and m (slope) values to find b (the y

intercept) Line 4 shows this Now we have all the information we need about both lines, so we can find the intersection between them Lines 6 and 7 obtain the coordinates of the line intersection using the technique have used a few times now This code block ends with a conditional statement that compares this point intersection) with the boundaries of the line segment If the point falls within the boundaries, then nothing happens If this point (which is the intersection between the two lines) does not fall within the segment boundaries, then a collision did not happen and so frames is set to 1000 (something high) If the framesvariable value is less than or equal to 1 and the point of contact was within the boundaries of the line then the collision is valid The last line of code above returns the frames variable as the result of the The function that called the getFrames() function, bankCollisionDetect(), has the frames returned to and can then check to see if the frames are less than or equal to 1

We will see this again in the next chapter, Collision Reactions You are on your way to creating a game with advanced techniques!

Point-Rectangle Collision Detection

After what you have seen in this chapter so far, what remains is very simple to understand and apply (We not be including frame-independent collision-detection scripts in this or the next section.)

To see a more detailed representation of how the time (frames) can be found, see

line_ball_time_calculation.pdf in the Chapter05 directory

Trang 16

Since this is not frame-independent collision detection, point-rectangle collision detection is like taking

snapshots in time And if the point is going fast enough, it can move through the rectangle without a collision being detected

The logic for detecting a collision between a point and a rectangle is simple The position of the point is compared with the position of each wall of the rectangle If the point's x position is gr?ater than the x position

of the left wall and less than the x position of the rectangle's right wall, and the point's y position is greater

than the y position of the top wall (remember that the y-axis is inverted in Flash) and less than the y position

of the bottom wall, then a collision is occurring

You have seen this many times by now We create an object for each movie clip on the stage to store

information about that movie clip Notice that for the rectangle we are storing its position (its registration

is at the upper-left corner) as well as its width and height Next in the ActionScript are two functions, one for creating a temporary position of the point in memory and the other to position the movie clip on the stage will not list these functions here, since they are identical to what we have seen several times already Here is pointRectangleDetection(), the function that detects collisions between the point and the rectangle

Open point_rectangle.fla to see an example There are two movie clips on the stage,

point_clip1 and rectangle_clip1 The ActionScript creates an object to store the

information for the point and for the rectangle Then, in every frame, the point is

moved, and a check is performed to detect collisions Here is the ActionScript used to

create the objects

Trang 17

walls are assigned to variables Finally, in line 12, a conditional is started that checks to see if the x position

the point is greater than the left wall but less than the right wall, and that the y position of the point is

than the top wall and less than the bottom wall If this condition is met, then a collision is occurring, and a trace action is executed Finally (although this is not shown above), an onEnterFrame event calls

getTempPositions(), pointRectangleDetection(), and render() in every frame

Rectangle-Rectangle Collision Detection

Like point-rectangle collision detection, collision detection between two rectangles is easy to perform

Rectangle_a is colliding with rectangle_b if all of the following are true:

1 The x position of the right wall of rectangle_a is greater than the x position of the left wall of

Trang 18

Then, in line 15, an if statement uses the logic we mentioned above to determine if a collision is taking

It compares the positions of the walls in rectangle_a with the positions of the walls in rectangle_b If condition is met, then the rectangles are colliding and a trace action is executed

To see an example, open rectangle_rectangle.fla from the Chapter05 directory on the

CD The ActionScript in this file is very similar to the previous example, so we will

discuss the function that handles collision detection,

RectangleRectangleDetection() Here is the ActionScript:

I l@ve RuBoard

I l@ve RuBoard

Collision Detection with Advanced Shapes

In this chapter we have developed frame-independent collision-detection logic and scripts for circle-line collisions (or point-line collisions, if you set the radius to 0) This is much more powerful than you might With this knowledge, you can create simple or complicated shapes without any extra-fancy math For

think of an octagon Ordinarily you might not know how to detect a collision between a circle and an octagon Well, why not put eight lines together and run a detection script for each of those lines? Suddenly, circle-octagon collision detection is a very easy thing! The shape in question doesn't have to be regular, either; you can create a star shape, a triangle, or even the shape of a house; the detection works because each line is treated separately

Many shapes can be created with line segments Collision detection is performed on each line segment separately

Trang 19

There is one problem you may encounter: multiple collisions at once Imagine a rectangle shape and a ball colliding with the corner It is likely that your script will detect two separate collisions This is fine if you just want to know if a collision took place, but if you want to use a collision reaction (covered in the next chapter),

then which line should the circle react to? The answer is simple: Keep track of the frames variable for each collision The lowest one is the collision that occurred first You can then make the circle react to the

appropriate collision

If you are interested in developing your own collision-detection scripts for shapes not covered here (for instance, point-ellipse collisions), follow this simple formula:

1 List the conditions that must be met for a collision to take place

2 Figure out how to determine if each condition is met

You may have to pick up a book on geometry or trigonometry if you are looking for the equations that more complicated objects such as ellipses or toroids (doughnut shapes) See Appendix E for book

Collision detection is a fundamental requirement for most games, however simple they may be With what you've learned in this chapter, you can detect collisions between almost any two objects Combine all this knowledge with what you'll gain in the next chapter, and you will soon be creating advanced games like and billiards!

I l@ve RuBoard

I l@ve RuBoard

Points to Remember

z A collision occurs when two separate shapes share one or more points in space

z In Flash you can use two main types of programmatic collision detection: hitTest() and math

z Using math is considered the superior method of collision detection because in addition to confirming detections in the present, you may also be able to use it to determine the future time and location of a collision

z Limitations of hitTest() include its limited abilities with complex shapes, its close relationship to specific graphics or movie clips, and its dependence on frame rates

z Code-graphics independence is a liberating method of working with movie clips It uses objects to information about each movie clip Storing information in an object—separate from its actual interface element—is a good practice because it allows you to add or remove movie clips from the stage without losing the data

z You can use the Linkage feature to enable ActionScript to create an unlimited number of new instances

Ngày đăng: 12/08/2014, 21:20

TỪ KHÓA LIÊN QUAN