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

C++ Programming for Games Module I phần 9 pps

39 287 0
Tài liệu đã được kiểm tra trùng lặp

Đ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 39
Dung lượng 606,94 KB

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

Nội dung

The first class which we build will model a mathematical vector, which is an essential tool for 3D computer graphics and 3D game programming.. In 3D computer graphics programming and man

Trang 1

Write a program that does the following:

1 Ask the user to enter up to a line of text and store it in a string s

2 Transform each alphabetical character in s into its lowercase form If a character is not an

alphabetical character—do not modify it

3 Output the lowercase string to the console window

Your program output should look like this:

Enter a string: Hello, World!

Lowercase string = hello, world!

Press any key to continue

6.10.4 Palindrome

Dictionary.com defines a palindrome as follows: “A word, phrase, verse, or sentence that reads the same

backward or forward For example: A man, a plan, a canal, Panama!” For our purposes, we will

generalize and say that a palindrome can be any string that reads the same backwards or forwards and does not have to form a real word or sentence Thus, some simpler examples may be:

“abcdedcba”

“C++C”

“ProgrammingnimmargorP”

Write a program that does the following:

1 Asks the user to enter up to a line of text and store it in a string s

2 Tests if the string s is a palindrome

3 If s is a palindrome then output “s is a palindrome” else output “s is not a palindrome.”

Your program output should look like this:

Enter a string: Hello, World!

Hello, World! is not a palindrome

Press any key to continue

Another sample out

Enter a string: abcdedcba

abcdedcba is a palindrome

Press any key to continue

put:

Trang 2

Chapter 7

Operator Overloading

Trang 3

Introduction

In the previous chapter, we saw that we could access a character in a std::string object using the bracket operator ([]) Moreover, we also saw that we could add two std::strings together using the addition operator (+) and that we could use the relational operators (==, !=, <, etc) with std::string

objects as well So it appears that we can use (some) C++ operators with std::string We may assume that perhaps these operators are defined for every class However, a quick test verifies that this

is not the case:

The above code yields the errors:

C2676: binary '*' : 'Fraction' does not define this operator or a conversion to a type acceptable to the predefined operator

C2676: binary '>' : 'Fraction' does not define this operator or a conversion to a type acceptable to the predefined operator

Why can std::string use the C++ operators but we cannot? We actually can, but the functionality is

not available by default We have to define (or overload) these C++ operators in our class definitions

These overloaded operators are defined similarly to regular class methods, and they specify what the operator does in the context of the particular class in which it is being overloaded For example, what

Trang 4

does it mean to multiply two Fractions? We know from basic math that to multiply two fractions we multiply the numerators and the denominators Thus, we would overload the multiplication operator for

Fraction and give an implementation like so:

Fraction Fraction:: operator *( const Fraction& rhs)

{

P.mNumerator = mNumerator * rhs.mNumerator;

P.mDenominator = mDenominator * rhs.mDenominator;

return P; // return the fraction product

}

With operator overloading we can make our user-defined types behave very similarly to the C++ built-in types (e.g., float, int) Indeed, one of the primary design goals of C++ was for user-defined types to behave similarly to built-in C++ types

The rest of this chapter describes operator overloading in detail by looking at two different class examples The first class which we build will model a mathematical vector, which is an essential tool for 3D computer graphics and 3D game programming

However, before proceeding, note that operator overloading is not recommended for every class; you should only use operator overloading if it makes the class easier and more natural to work with Do not overload operators and implement them with non-intuitive and confusing behavior To illustrate an extreme case: You should not overload the ‘+’ operator such that it performs a subtraction operation, as this kind of behavior would be very confusing

Chapter Objectives

• Learn how to overload the arithmetic operators

• Discover how to overload the relational operators

• Overload the conversion operators

• Understand the difference between deep copies and shallow copies

• Find out how to overload the assignment operator and copy constructor to perform deep copies

7.1 Vector Mathematics

In this section we discuss the mathematics of vectors, in order to understand what they are (the data) and what we can do with them (the methods) Clearly we need to know this information if we are to model a vector in C++ with a class

In 3D computer graphics programming (and many other fields for that matter), you will use a vector to

model quantities that consist of a magnitude and a direction Examples of such quantities are physical

Trang 5

forces (forces are applied in a certain direction and have a strength or magnitude associated with them), and velocities (speed and direction)

Geometrically, we represent a vector as a directed line segment—Figure 7.1 The direction of the line segment describes the vector direction and the length of the line segment describes the magnitude of the vector

Figure7.1: Geometric interpretation of a vector

Note that vectors describe a direction and magnitude, but they say nothing about location Therefore,

we are free to choose a convenient location from which they originate In particular, for solving problems, it is convenient to define all vectors such that their “tails” originate from the origin of the working coordinate system, as seen in Figure 7.2

Figure 7.2: A vector with its tail fixed at the origin Observe that by specifying the coordinates of the vector’s tail we

can control its magnitude and direction

Trang 6

Thus we can describe a vector analytically by merely specifying the coordinates of its “head.” This motivates the following structural representation of a 3D vector:

What follows is a description of important vector operations For now, we do not need to worry about the detailed understanding of this math or why it is this way; rather, our goal is simply to understand the vector operation descriptions well enough to implement C++ methods which perform these operations

Note: The Game Mathematics and Graphics Programming with DirectX 9 Part I courses at Game Institute explain vectors in detail

Throughout this discussion we restrict ourselves to 3D vectors Let ur= u x, u y, u z and

z y

x

u = = u z =v z

: The sum of two vectors is found by adding corresponding components:

z z y y x x z y x z y

u v

Example:

4,1,613,32,511,3,53,2,

1 + − = + − + = −

=

+ q

Trang 7

Geometrically, we add two vectors ur +vr by parallel translating vr so that its tail is coincident with the head of ur and then the sum ur +vr is the vector that originates at the tail of ur and terminates at the head

of vr Figure 7.3 illustrates

Figure 7.3: Vector addition We translate vr so that its tail coincides with ur Then the sum ur +vr is the vector from

the tail of ur to the head of translated vr

A key observation to note regarding parallel translation of a vector is that the length and direction of the vector is preserved; that is, translating a vector parallel to itself does not change its properties and therefore it is legal to parallel transport them around for visualization

Vector Subtraction:

The difference between two vectors is found by subtracting corresponding components:

z z y y x x z y x z y

u v

Example:

( )3, 3 1 4, 5, 22

,511,3,53,2,

Trang 8

Figure 7.4: Vector subtraction We view vector subtraction as the sum ur−vr =ur+( )−vr So first we negate vr and

then translate vr so that its tail coincides with ur Then ur+( )−vr is the vector originating from the tail of ur and

terminating at the head of vr

Observe that subtraction can be viewed as an addition; that is, ur−vr=ur+( )−vr , where negating a vector

flips its direction

Scalar Multiplication:

A vector can be multiplied by a scalar, which modifies the magnitude of the vector but not its direction

To multiply a vector by a scalar we multiply each vector component by the scalar:

3 2 1 3

2

v k

Example:

( ) ( ) ( )1, 32, 33 3, 6, 93

3,2,13

3pr= = =

As the name implies, scalar multiplication scales the length of a vector Figure 7.5 shows some examples

Trang 9

Figure 7.5: Scalar multiplication Multiplying a vector by a scalar changes the magnitude of the vector A negative

scalar flips the direction

2 2

2

12 + 2 + 2 =

=

pr

Geometrically, the magnitude of a vector is its length—see Figure 7.6

Figure 7.6: Vector magnitude The magnitude of a vector is its length

Normalizing a Vector:

Trang 10

Normalizing a vector makes its length equal to 1.0 We call this a unit vector and denote it by putting a

“hat” on it (e.g., ) We normalize a vector by scalar multiplying the vector by the reciprocal of its magnitude:

vˆr

v v

vr =ˆ r r

Example:

143142,1413,2,1141

The Dot Product:

The dot product of two vectors is the sum of the products of corresponding components:

z z y y x x z y x z y

u v

1,3,53,2,

1 ⋅ − = + − + = − + =

=

⋅ q

p rr

Observe that this vector product returns a scalar—not a vector

The dot product of a vector vr with a unit vector nˆr evaluates to the magnitude of the projection of vr

onto , as Figure 7.7 shows nˆr

Trang 11

Figure 7.7: The dot product of a vector vr with a unit vector nˆr evaluates to the magnitude of the projection of vr onto

We can get the actual projected vector

nˆr vr n by scaling nˆr by that magnitude

Given the magnitude of the projection of vr onto nˆr , the actual projected vector is: vrn =( )vr⋅nrˆ rnˆ, which

makes sense: vr⋅ returns the magnitude of tnˆr he projection, and nˆr is the unit vector along which the

projection lies Therefore, to get the projected vector we sim ly scale the unit vector p nˆr by the

magnitude of the projection

Sometimes we will want the vector vr⊥ perpendicular to the projected vector (Figure 7.8) Using our geometric interpretation of vector subtraction we see that

n

vr

n

v v

Trang 12

7.2 A Vector Class

Our goal now is to design a class that represents a 3D vector We know how to describe a 3D vector (with an ordered triplet of coordinates) and we also know what operators are defined for vectors (from the preceding section); that is, what things we can do with vectors (methods) Based on this, we define the following class:

Vector3( float coords[3]);

Vector3( float x, float y, float z);

bool equals( const Vector3& rhs);

Vector3 add( const Vector3& rhs);

Vector3 sub( const Vector3& rhs);

Vector3 mul( float scalar);

Note: Why do we keep the data public even though the general rule is that data should always be

private? There are two reasons The first is practical: typically, vector components need to be accessed quite frequently by outside code, so it would be cumbersome to have to go through accessor functions Second, there is no real data to protect; that is, a vector can take on any value for its components, so there is nothing we would want to restrict

The data members are obvious—a coordinate value for each axis, which thereby describes a 3D vector The methods are equally obvious—most come straight from our discussion of vector operations from the

Trang 13

previous section But how should we implement these methods? Let us now take a look at the implementation of these methods one-by-one

7.2.1 Constructors

We provide three constructors The first one, with no parameters, creates a default vector, which we

define to be the null vector The null vector is defined to have zero for all of its components The

second constructor constructs a vector based on a three-element input array Element [0] will contain the x-component; element [1] will contain the y-component; and element [2] will contain the z-component The last constructor directly constructs a vector out of the three passed-in components The implementations for these constructors are trivial:

which calls vector (this vector) is equal to the vector passed into the parameter; otherwise, it returns

false Recall that two vectors are equal if and only if their corresponding components are equal

bool Vector3::equals( const Vector3& rhs)

ethod we specified was the equals method The equals m

// Return true if the corresponding c

Trang 14

7.2.3 Addition and Subtraction

We next implement two methods to perform vector addition and subtraction Recall that we add two vectors by adding corresponding components, and that we subtract two vectors by subtracting corresponding components The following implementations do exactly that, and return the sum or differe

Vector3 Vector3::add( const Vector3& rhs)

Vector3 Vector3::mul( float scalar)

Trang 15

v v

vr =ˆ r r

Translating this math into code yields:

void Vector3::normalize()

{

// Get 'this' vector's length

float len = length();

// Divide each component by the length

mX /= len;

mY /= len;

mZ /= len;

}

7.2.7 The Dot Product

The last method, which is mathematical in nature, implements the dot product Translating the following mathematical formula results in the code seen below:

z z y y x x z y x z y

u v

Trang 16

7.2.8 Conversion to float Array

The conversion method toFloatArray does not correspond to a mathematical vector operation Rather,

it returns a pointer to the three-element float representation of the calling object (this) Why would

we ever want to convert our Vector3 representation to a three-element float array representation? A good example might be if we were using the OpenGL 3D rendering library This library has no idea about Vector3, and instead expects vector parameters to be passed in using a three-element float

array representation Providing a method to convert our Vector3 object to a three-element floatarray would allow us to use the Vector3 class seamlessly with OpenGL

Trang 17

7.2.11 Example: Vector3 in Action

Let us now look at a driver program, which uses our Vector3 class

Program 7.1: Using the Vector3 class

Trang 18

float dotP = u.dot(w);

cout << "u.dot(w) = " << dotP;

// Part 6: Convert to array representation

float * vArray = v.toFloatArray();

// Print out each element and verify it matches the

// Part 7: Create a new vector and have user specify its

// components, then print the vector

cout << "Input vector " << endl;

Trang 19

Press any key to continue

The code in Program 7.1 is pretty straightforward, so we will only briefly summarize it In Part 1, we have:

float coords[3] = {1.0f, 2.0f, 3.0f};

Vector3 u;

Vector3 v(coords);

Vector3 w(-5.0f, 2.0f, 0.0f);

Here, we construct three different vectors using the different constructors we have defined The vector u

takes no parameters and is constructed with the default constructor The second vector v uses the array constructor; that is, we pass a three-element array where element [0] specifies the x-component, element [1] specifies the y-component, and element [2] specifies the z-component Lastly, the vector w is constructed using the constructor in which we can directly specify the x-, y-, and z-components

Part 2 of the code simply prints each vector to the console window In this way, we can check the program output to verify that the vectors were indeed constructed with the values we specified

cout << "v.length() = " << v.length() << endl;

Here we call the length function for v, which will return the length of v Because v was just normalized, the length should be equal to 1 A quick check at the resulting output confirms that the length is indeed one

on, and then prints the sum

t();

add method returns the sum, which we store in

Ngày đăng: 05/08/2014, 09:45

TỪ KHÓA LIÊN QUAN