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

Building XNA 2.0 Games- P6 pptx

30 263 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

Tiêu đề Building XNA 2.0 Games - P6 PPTX
Trường học University of XYZ
Chuyên ngành Game Development / Software Engineering
Thể loại Lecture Notes
Năm xuất bản 2023
Thành phố Sample City
Định dạng
Số trang 30
Dung lượng 621,12 KB

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

Nội dung

public void UpdateGameTime gameTime { float et = floatgameTime.ElapsedGameTime.TotalSeconds; #region Update Animation Animation animation = charDef.Animations[Anim]; KeyFrame keyFram

Trang 1

Note In-line code is code that is kept in one place, rather than componentized into methods and/or

classes It is not a great idea in terms of organization, but can be useful for optimizing memory usage

Updating the Animation

We’re basically copying and pasting the Update() code from Game1 in CharacterEditor to Character,

with a few changes We’ll remove any functionality to determine whether the animation preview

is playing We’ll also change some of the field names to make a bit more sense in the context

However, the core logic remains unchanged: update the frame index until we can’t update it

anymore, and then loop back to the beginning

public void Update(GameTime gameTime)

{

float et = (float)gameTime.ElapsedGameTime.TotalSeconds;

#region Update Animation

Animation animation = charDef.Animations[Anim];

KeyFrame keyFrame = animation.KeyFrames[AnimFrame];

Updating the Location

To update the location, we’ll simply add the trajectory, multiplied by Game1.frameTime, to the

character’s current location If the character’s state is STATE_GROUNDED and the character’s x

trajectory is not zero, reduce the trajectory by Game1.friction If the character is airborne, the

y trajectory’s value will be increased by Game1.gravity, giving him a nice airborne arc

Trang 2

#region Update Location By Trajectory

Vector2 pLoc = new Vector2(Location.X, Location.Y);

• Airborne state collision:

• Check horizontal collisions (moving left or right into walls)

• Check vertical collisions:

• Landing on ledge?

• Landing on collision cell?

• Grounded state collision:

• Check horizontal collisions

• Check to make sure the character still has ground below him:

• Falling off ledge?

• Falling off collision cell?

Trang 3

Let’s look at the code We’ll be using a few tiny functions, which will be defined in a few pages,

but based on the preceding outline and their names, their purpose should be pretty obvious

#region Collision detection

To check whether our character has landed on a ledge, we’ll do the following:

• Make sure our character is moving downward (trajectory.Y > 0.0f)

• Iterate through map ledges

• Check map ledges where the number of nodes is > 1

• Store the ledge section the character is over or under as s

• Store the ledge section the character was over or under before his location was updated as ts

• If s or ts is -1, the character isn’t and wasn’t over or under the ledge; otherwise, do this:

• Store the interpolated y value for the character’s current location as fY

• Store the interpolated y value for the character’s previous location as tfY

• If the character’s previous y location is <= tfY and the character’s current location is

>= fY, this means the character is attempting to pass through the ledge in this current

Update() Land him!

Figure 6-3 shows a few scenarios

Figure 6-3 Ledge landing scenario The grayed figures represent the character’s previous location

for each scenario; the black figures represent the current locations.

Trang 4

Here’s the code for landing on a ledge:

#region Land on ledge

if (trajectory.Y > 0.0f)

{

for (int i = 0; i < 16; i++) {

if (map.GetLedgeTotalNodes(i) > 1) {

int ts = map.GetLedgeSec(i, pLoc.X); int s = map.GetLedgeSec(i, Location.X); float fY; float tfY; if (s > -1 && ts > -1) {

tfY = map.GetLedgeYLoc(i, s, pLoc.X); fY = map.GetLedgeYLoc(i, s, Location.X); if (pLoc.Y <= tfY && Location.Y >= fY) {

if (trajectory.Y > 0.0f) { Location.Y = fY; ledgeAttach = i; Land(); }

}

else

if (map.GetLedgeFlags(i) == LedgeFlags.Solid && Location.Y >= fY) {

Location.Y = fY; ledgeAttach = i; Land(); }

}

}

}

}

#endregion

We’ll use a much simpler algorithm to detect whether a character has landed on a collision cell If the location at the character’s feet occupies a collision cell, we’ll move the character’s

y location to the top of that cell and land him

Trang 5

#region Land on col

With the grounded character, instead of checking to see if he has landed on something,

we check to see if he has fallen off something If he is attached to a ledge, we check only if

GetLedgeSec() returns -1, meaning there is no section for the character’s current x location, or

the character is not on a ledge If the character is still on a ledge, we update his y location to the

interpolated value we get from GetLedgeYLoc()

#region Grounded State

Likewise, if the character is not attached to a ledge, we’ll check to see if he has a collision

cell below him If not, he falls off

Trang 6

if (!map.checkCol(new Vector2(loc.X, loc.Y + 15f)))

#region Key input

if (animName == "idle" || animName == "run")

Trang 7

An airborne player can move either left or right for now—violating some physics in the

name of game play Pressing Left or Right on the gamepad while in midair nudges the

trajec-tory slightly left or right

That concludes the massive Update() function You might want to organize it differently,

but regions work well enough for the time being

New Character Functions

We’ve thrown a couple more functions into the mix, so let’s define them before moving on

CheckXCol()

To simplify movement, we check x movement collisions separately from y movement We’ve

defined a function for this CheckXCol() checks whether the character location overlaps a collision

cell on the left or right (with the location padded by 25f) and returns the character’s x location

to pLoc.X if so We’ll eventually use a padding value that’s a function of the character’s scale, so

larger characters won’t overlap collision cells

private void CheckXCol(Map map, Vector2 pLoc)

Trang 8

The function FallOff() is called when a grounded character realizes that he no longer has ground below him, which could occur if he was on a collision cell or a ledge He gets set to airborne state, has his animation set to fly, and has his y trajectory reset

private void FallOff()

char-scripting—and honestly, we just want to see something cool soon

Now it’s time to make a Draw() function

Drawing the Character

We’ll be reusing the drawing code from CharacterEditor We’ll just move it into Character and modify it slightly

For starters, we don’t need all of the parameters; the SpriteBatch is enough (everything else is now a class-level field)

public void Draw(SpriteBatch spriteBatch)

Trang 9

float rotation = part.rotation;

Vector2 location = part.location * scale + loc

We can remove the line that changes the color for preview mode

bool flip = false;

Everything else can be left the way it was There are a few inherent changes going on where

we didn’t actually need to modify the code, such as loc and face now being class-level fields

Texture Loading

Remember how we declared our character textures as statics? We can also make a static function

to load them in Character, which we’ll call from Game1

internal static void LoadTextures(ContentManager content)

Trang 10

public void DoInput(int index)

Trang 11

Character Definition

Before we start bringing everything together in Game1, we’ll declare a new enumerator for use in

CharDef For now, we’ll just plan on using one for Guy and one for Zombie Add a new file called

CharacterType.cs with the following enumerator:

There will be more later on (what fun would our game be without bosses?), but this will

serve our purposes for now One of the nice things about using an enumeration like this is that

we do not need to worry about redefining or defining different character types By using a strong

name in our code, we get around the actual values pertaining to each type

Go ahead and add a new public field to the CharDef class that references this enumerator:

public CharacterType CharType = CharacterType.Guy;

Setting Things in Motion

We have set up our Character and Map classes Now it’s time to set them in motion We’ll be

keeping a Map object and array of Character objects, which we’ll update and draw from Game1

We’ll start with class-level objects:

Map map;

Texture2D[] mapsTex = new Texture2D[1];

Character[] character = new Character[16];

CharDef[] charDef = new CharDef[16];

There were a few fields that we used in Character and Map that we said we would have in

Game1, such as frameTime, the amount of time elapsed since the last Update(), scroll, and the

game camera location We’ll also add gravity and friction, which Character takes into account

when updating the character’s location

public static float frameTime = 0f;

public static Vector2 scroll = new Vector2();

public const float gravity = 900f;

public const float friction = 1000f;

GraphicsDeviceManager graphics;

SpriteBatch spriteBatch;

Trang 12

To initialize, we’ll do some hard-coding We’ll instantiate Map, read map, read our guy CharDef, and instantiate a new Character at location 100, 100 Notice how we’re using CharacterType.Guy twice to refer to the guy CharDef.

protected override void Initialize()

Next, we load the game content:

protected override void LoadContent()

{

spriteBatch = new SpriteBatch(GraphicsDevice);

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

Trang 13

We’re updating scroll to loosely follow the player—we want the top-left corner of the

camera to be at –400, –400 of the player’s location By updating scroll by the difference between

the current scroll location and our goal location, we end up with a camera that sort of springs

to its goal location

Last but not least, it’s time to draw! As we said earlier, we won’t draw the map all at

once—we’ll draw layers 0 and 1; then draw the characters, effects, and so on; then draw map

layer 2; and, finally, draw the HUD For now, we’ll leave out the HUD (don’t have one),

parti-cles, and stuff (don’t have those either), and draw only one character

protected override void Draw(GameTime gameTime)

That should do it! Let’s run it Figure 6-4 shows where we are at this point

We’ve done a bit of work so far, but this is the first time we have something we can actually

play with Of course, the amount of stuff we can do is pretty limited: move left, move right, jump,

and run into invisible walls at each side

Trang 14

Figure 6-4 Zombie Smashers at last!

Adding a Background Image

Now cornflower blue is great, but adding a background image will really make our game slicker and start setting the mood We’ll use a starry night on a blue gradient Image back1.png is shown in Figure 6-5 Add this image to the solution’s gfx folder.Next, add the following to the class level of Game1:

Texture2D[] mapBackTex = new Texture2D[1];

And then in LoadContent(), add this:

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

Trang 15

Figure 6-5 Our background image

And then in the beginning of the method, we’ll draw the background with the following

code We also declare a new class-level constant, LAYER_BACK, and set it equal to zero

sprite.Begin(SpriteBlendMode.AlphaBlend);

if (startLayer == LAYER_BACK)

{

float xLim = GetXLim();

float yLim = GetYLim();

Vector2 targ = new Vector2(

Trang 16

We also need to add two more methods: GetXLim() and GetYLim() We’ll use these to get the horizontal and vertical limits for the scroll vector

public float GetXLim()

This brings us back again to Game1, where we create a class-level variable:

private static Vector2 screenSize = new Vector2();

public static Vector2 ScreenSize{

get { return screenSize; }

set { screenSize = value; }

new Vector2(400f, 400f)) - Scroll) * frameTime * 20f;

float xLim = map.GetXLim();

float yLim = map.GetYLim();

if (scroll.X < 0f) scroll.X = 0f;

if (scroll.X > xLim) scroll.X = xLim;

if (scroll.Y < 0f) scroll.Y = 0f;

if (scroll.Y > yLim) scroll.Y = yLim;

Now we should have a camera that doesn’t slip off the edge of the map and a nice, starry night background You should end up with what you see in Figure 6-6 If you don’t, that means something went terribly wrong

Trang 17

Figure 6-6 Background image in action!

Moody, right? We are now looking good, and we’ve officially completed the first part of the

chapter Wouldn’t it be nice if our character could be just slightly more expressive?

Super Simple Scripting

What we want to add is the ability to define not only how the character can be animated, but

how several different animations work together in conjunction You can consider an

anima-tion to be a person running and another animaanima-tion to be the stopping moanima-tion Scripting will

allow us to define that the stopping animation comes after the player has ended the running

animation, thus giving the player a more realistic set of motions In this case, we want to be

able to have our character attack, fire his pistol, and string together attacks into complex combos

We’re definitely not going to hard-code this; we need a scripting system

To add the scripting, we will do the following:

• Design a scripting language

• Implement script editing in CharacterEditor

• Create some classes in ZombieSmashers to process and run scripts

• Add scripts to our Guy character

Trang 18

The Scripting Language

Our character-scripting system will be very basic For each keyframe in an animation, there will

be up to four associated script commands We’ll use commands for tasks such as the following:

• Navigating frames

• Switching animations

• Sliding and jumping

The syntax for scripting language is as simple as this:

command parameter

We’ll have commands that look like setanim attack2 and goto 3.

Adding Script Editing to the Character Editor

We’ll start by editing CharacterEditor to allow us to edit keyframe scripts First, let’s declare

a class-level variable to know which script line we’re editing We’ll also want to modify the EditingMode enumeration to know when we are modifying the script

Trang 19

Remember the functionality we used to allow text editing? We check the editing mode,

grab the appropriate string, edit it, and restore it to the appropriate variable We’re adding a

new editing mode, EditMode.Script In PressKey(), add the following:

One last detail is that we need to put a translucent black box under our new script editor

In Draw(), we’ll need to extend the rectangle that we drew under our load/save/path area:

spriteBatch.Draw(nullTex, new Rectangle(590, 0, 300, 600), new

Trang 20

Figure 6-7 Character editor with script-editing capabilties Go nuts!

Some Script Commands

Let’s plan some commands The following are some navigation commands:

• setanim newanim: Set current animation to newanim at frame 0.

• goto frame: Jump to frame frame of the current animation.

• ifupgoto frame: Jump to frame frame of the current animation if Up is pressed.

• ifdowngoto frame: Jump to frame frame of the current animation if Down is pressed.

For movement, we’ll use these commands:

• float: Cause an airborne character to begin hovering We’ll use this for air combos

• unfloat: Cause an airborne, floating character to stop floating and drop to the ground at normal speed

• slide xval: Slide the character forward by xval.

• backup xval: Back up the character by xval.

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

TỪ KHÓA LIÊN QUAN