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

Building XNA 2.0 Games- P5 ppt

30 300 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 30
Dung lượng 1,04 MB

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

Nội dung

We’ll put in two buttons to swap the current part with the one on the previous or next layer, using a function named Game1.SwapParts: if DrawButton700, y, 1, mouseState.X, mouseState.Y,

Trang 1

So far, we’re iterating through all images for each texture, getting the source and

destina-tion rectangles so that we can draw them in a neat row on the bottom of the screen Of course,

the special case with weapons is coming right up:

With the correct source and destination rectangles, we draw the image But since we have

the destination rectangle, we might as well check if the mouse location is within the rectangle

Assuming we add a call to DrawPalette() and DrawCursor() at the end of Game1.Draw()

somewhere, we’ll be treated to the result shown in Figure 5-6 Also, be sure to set mouseClick to

false at the end of the Draw() method

Trang 2

Figure 5-6 Icon palette

The Parts List

We’ll use the icon palette to specify which image index each part uses The parts list will allow

us to manipulate our composited character in a way similar to a layer-heavy image-editing approach We’ll be able to select a part to manipulate, move parts up and down the list (like Send to Bottom and Bring to Top in layer ordering), and delete parts We do this in a method called Game1.DrawPartsList(), as follows:

Trang 3

We’ll put in two buttons to swap the current part with the one on the previous or next

layer, using a function named Game1.SwapParts():

if (DrawButton(700, y, 1, mouseState.X, mouseState.Y, mouseClick))

We’ll put some makeshift buttons next to the swap buttons to modify the parts One of these is

to mirror parts For the mirror button, we’ll use an (n) for normal and an (m) for mirrored

Part part = charDef.Frames[selFrame].Parts[selPart];

Because scaling leaves all sorts of openings for things to go terribly wrong in artistic

consis-tency, we’ll put in a button next to the selected part to reset the scale, denoted with an (r) We’ll

also add a part delete button, marked with an (x)

Trang 4

Earlier in Draw(), add a line to draw the character:

DrawCharacter(new Vector2(400f, 450f), 2f, FACE_RIGHT, selFrame,

Trang 5

Figure 5-7 Parts list

It’s the classic swap algorithm, t = i; i = j; j = t, but it’s applied to two objects, so we store the

references temporarily, rather than storing the values themselves

Moving, Rotating, and Scaling Parts

Now we can specify part icons, but we can’t move them, so we can only end up with a head,

arms, and legs in a heap on the floor, which isn’t what we’re really going for We need to be able

to manipulate parts We allow that with the following code:

int xM = mouseState.X - preState.X;

int yM = mouseState.Y - preState.Y;

Trang 6

We’re now able to move, rotate, and scale parts, so we can finally get a look at what we’re shooting for with this character format Take a look at our guy in Figure 5-8, which should give you a much better idea of what we’re creating.

Trang 7

Figure 5-8 Our hero (assembled)

The Frames List

The character you see in Figure 5-8 is one frame If we’re going to have animation, we’ll need a

series of frames Figure 5-8 could be idle1 Then we would need idle2, idle3, and so on

Let’s create a frames list in Game1.DrawFramesList():

for (int i = frameScroll; i < frameScroll + 20; i++)

Remember how we edited text in the map editor? We’re using a similar system here We

use the class-level variable editingMode to keep track of which field we’re editing, and then

Trang 8

from Game1.Update(), we call UpdateKeys(), which may call PressKey() We can basically copy the code over from MapEditor, with a few changes, which we’ll get to soon

Next to the selected frame, we’ll draw a little add frame button, denoted with an (a) Clicking this button will add a reference to this frame to the selected animation

if (text.DrawClickText(720, y, "(a)",

mouseState.X, mouseState.Y, mouseClick))

{

Animation animation = charDef.Animations[selAnim]; for (int j = 0; j < animation.KeyFrames.Length; j++) {

KeyFrame keyFrame = animation.KeyFrames[j]; if (keyFrame.FrameRef == -1) {

keyFrame.FrameRef = i; keyFrame.Duration = 1;

break; }

}

}

}

else {

if (text.DrawClickText(600, y, i.ToString() + ": " + charDef.Frames[i].Name, mouseState.X, mouseState.Y, mouseClick)) {

When selecting a frame, two things happen If the frame’s name was empty, we copy the previously selected frame to the current frame This isn’t very intuitive, but it works Also, we make the currently selected frame’s name editable if (selFrame != i) {

if (String.IsNullOrEmpty(charDef.Frames[i].Name)) CopyFrame(selFrame, i); selFrame = i; editingText = EDITING_FRAME_NAME; }

}

}

}

}

Trang 9

Finally, we allow our list to be scrolled.

We can now create several frames of animation, as shown in Figure 5-9

Figure 5-9 The frames list

Let’s take a little look at Game1.PressKey() In MapEditor, we would evaluate editMode, copy

an appropriate string into a temporary string, work with that temporary string, and then copy

the string back All that we change here is where we’re copying that string to and from:

Trang 10

Also, we use a nonintuitive method for copying frames: if the user selects a frame that has

a blank name (that is, a fresh, unused frame under typical circumstances), the previously selected frame will be copied onto the new one using the CopyFrame() method Here’s Game1.CopyFrame():private void CopyFrame(int src, int dest)

{

Frame keySrc = charDef.Frames[src];

Frame keyDest = charDef.Frames[dest];

keyDest.Name = keySrc.Name;

Trang 11

for (int i = 0; i < keyDest.Parts.Length; i++)

{

Part srcPart = keySrc.Parts[i];

Part destPart = keyDest.Parts[i];

We iterate through the source frame’s part array, copying all part fields to the destination

frame’s part array

Next, we’ll implement our animations and keyframes lists

The Animations List

The animations list will be fairly simple We’ll draw a list of all animations at the top-left side

of the window If the user clicks an animation, its name becomes editable and it becomes

the selected animation The list is scrollable as well, so we use the variable animScroll

There’s not much more to it than that As usual, we put this in its own function named

Trang 12

if (DrawButton(170, 5, 1, mouseState.X, mouseState.Y, (mouseState.LeftButton == ButtonState.Pressed)) && animScroll > 0)

animScroll ;

if (DrawButton(170, 200, 2, mouseState.X, mouseState.Y, (mouseState.LeftButton == ButtonState.Pressed)) && animScroll <

charDef.Animations.Length - 15) animScroll++;

The Keyframes List

The keyframes list is more of the same, with a bit of a hassle thrown in for good measure We’ll implement functionality to allow the user to modify keyframe durations, allowing us to fine-tune animation pacing We put this in a function called Game1.DrawKeyFramesList()

for (int i = keyFrameScroll; i < keyFrameScroll + 13; i++)

Trang 13

if (DrawButton(170, 250, 1, mouseState.X, mouseState.Y, (mouseState.LeftButton ==

ButtonState.Pressed)) && keyFrameScroll > 0)

keyFrameScroll ;

if (DrawButton(170, 410, 2, mouseState.X, mouseState.Y, (mouseState.LeftButton ==

ButtonState.Pressed)) && keyFrameScroll <

charDef.Animations[selAnim].KeyFrames.Length - 13) keyFrameScroll++;

An Onionskin Effect

Moving back to our character-drawing call, we can implement a really simple onionskin effect

with our editor An onionskin effect is where you can see a translucent version of neighboring

frames of animation layered over the current frame However, ours won’t be exactly correct,

because the effect will operate only on neighboring frames as they appear in the frames list

Trang 14

Figure 5-10 Animations list, keyframes list, and onionskin

Playback Preview

It’s finally time to implement that preview character we’ve been talking about

We’re using a class-level integer, curKey, for the current keyframe However, keyframes point to frame references from our frames list, and if keyframes are blank, their frame reference will be -1 We’re going to try to account for all of this here

Trang 15

int fref = charDef.Animations[selAnim].KeyFrames[curKey].FrameRef;

Animation animation = charDef.Animations[selAnim];

KeyFrame keyframe = animation.KeyFrames[curKey];

Trang 16

We’re using an arbitrary time value for duration ticks, where one tick equals one-thirtieth

of a second This is because it’s easier to work in small, standard units when every change of duration involves clicking a tiny + or –

Figure 5-11 shows our preview in action

Figure 5-11 Animation preview

Loading and Saving

If you’ve been following along, you probably aren’t too happy with the fact that each time you debug CharacterEditor, you must create a new character from scratch That means it’s time to implement loading and saving We’ll create a Read() and Write() function in CharDef Here’s the Write() function:

Trang 17

public void Write()

String[] scripts = keyframe.Scripts ;

for (int s = 0; s < scripts.Length; s++)

Trang 18

string[] scripts = keyframe.Scripts;

for (int s = 0; s < scripts.Length; s++)

Trang 19

Now we just need to make some buttons in Game1.Draw() Fortunately, we brought

DrawButton() over from MapEditor, so it’s a pretty simple implementation:

if (DrawButton(200, 5, 3, mouseState.X, mouseState.Y, mouseClick))

We now have saving and loading functionality in a Spartan-yet-functional interface, all

shown in Figure 5-12 We haven’t implemented keyframe script editing, but we’ll get to that

once we start fleshing out the rest of the game

Trang 20

Figure 5-12 Save, load, and path

Conclusion

In this chapter, we put together a robust, ugly character editor in a hurry We discussed our hierarchical character format, created some classes to implement the structure, and built an editor around it

We now have a fairly functional character editor in place, to go with our fairly functional map editor, so we can finally start working on the actual game And as we’ve said before, the nice aspect of these crazy tools is that there won’t be too much to actually do to create the game now that we have them

Trang 21

■ ■ ■

Bringing It to the Game

The Payoff

Well, here we are Six chapters in, and we’re finally making something we can play And isn’t

that the whole reason we got into this? (It certainly wasn’t for the money!)

In this chapter, we’ll get a rough idea of the game and also implement a scripting system

to afford deeper animation interactivity

We’re taking this in two chunks: first create our rudimentary game engine, and then create

scripting By the time you’re finished with this chapter, you’ll have a very slick-looking start to

Zombie Smashers XNA

Building the Game

To put together our game, we’ll need to set up our environment, and then get to coding

Specif-ically, we’ll do the following:

• Create a new project in our game’s solution

• Copy over and change the map and character classes

• Load our map and character

• Create a new character class to control game functionality for an individual character

• Implement simple movement and collision detection

So, let’s get started with a new ZombieSmashers project

Trang 22

Creating a New Project: ZombieSmashers

Create a new Windows Game (2.0) called ZombieSmashers in our ever-growing ZombieSmashers solution Again, by putting most of our code into a single solution, we can leverage the quick-access capabilities of Visual Studio to easily reference and use code in adjacent projects (Although,

in this case, we’re going to make enough changes to our map and character classes to warrant copying them over to the project, rather than referencing them.)

Tip Referencing, rather than copying, code makes your projects more flexible One way you can do this is

to link files across projects and solutions To do this, right-click the project in Solution Explorer, select Add Existing Item, and browse to the file you wish to link to Instead of clicking the Add button, select the down arrow next to it and select Add As Link This way, the file will show up and compile in the project, but it won’t actually be copied over This is a great way to manage files for projects that are cross-platform, because it allows you to change code based on the platform for which it is being developed

Copy the MapClasses folder from the MapEditor solution and the Character folder (renaming it CharClasses) from CharacterEditor to the ZombieSmashers solution folder In ZombieSmashers

in Solution Explorer, include the MapClasses and CharClasses folders

Next, manually change the namespaces in all of the copied classes from MapEditor and CharEditor, respectively, to ZombieSmashers Also, create a Character class in the CharClasses folder We’ll use this class to encapsulate all logic and drawing functionality for a game char-acter This is where we’ll be doing the majority of the work for this chapter

From here, copy all of the art assets into the Content project From MapEditor, we’re taking maps1.png From CharacterEditor, we’re taking legs1.png, torso1.png, head1.png, and weapon1.png We’ll also take 1x1.bmp, Arial.spritefont, and icons.dds for good measure

We also need the data files we created: guy.zmx and map.zmx Move those to the ZombieSmashers project, in the folders data/chars and data/maps, respectively Make sure to include these files

in your solution and specify Copy If Newer

Finally, we need the map segment definition data Copy maps.zdx from MapEditor into the data folder You should end up with a project organized as shown in Figure 6-1

From here, we can start coding by modifying our map classes to work with the new game Unfortunately, we’ll be doing quite a bit of jumping around; hopefully, nothing will get lost in the shuffle!

Trang 23

Figure 6-1 ZombieSmashers project

A Random Numbers Class

We’re going to be using a ton of randomization from the game, so let’s make a nice class, in the

project root, to help us out We need only a class-level static Random object, which we’ll use from

within various classes we create, and some methods that we can throw some number ranges at

and expect random values in return

public static class Rand

{

private static Random random;

public static Random Random{

get { return random; }

private set { random = value; }

}

Trang 24

public static Vector2 GetRandomVector2(float xMin, float xMax,

float yMin, float yMax)

instan-Modifying the Map Functionality

We will now make some changes to the map functions, so the map is better suited for game play We’ll adjust its look and feel, and add some helper functions

Map Look and Feel

We need to change some of how the map moves and renders, because in a game, a map looks and feels quite different than in an editor In an editor, you want to see a quick, rough overview

of how the game will look, with the ability to change as much on the map as possible For instance, in the editor, we drew the map in a zoomed-out fashion to give a wide view on the map We don’t want to do this for the players, because we want to get them close in on the action For now, we will draw the map at two times the zoom level of the map editor This is simple enough Just remove this line from the Map.Draw() function:

Ngày đăng: 01/07/2014, 22:20

TỪ KHÓA LIÊN QUAN

w