Movement
譯:運(yùn)動(dòng)
Lets get things moving! Movement in our case is going to be handled by our Entity class. Each loop we'll ask the entities in the game to move themself. To facilitate this we add a list of entities to the main game class. Each loop we'll cycle round this list asking each entity to move and then draw itself. In our game loop, that looks like this:
譯:讓游戲角色動(dòng)起來(lái)!在我們的例子中,運(yùn)動(dòng)由實(shí)體類來(lái)處理。每次循環(huán)我們將要求實(shí)體們移動(dòng)自己。為了方便實(shí)現(xiàn),我們?yōu)橛螒蛑鞔翱谔砑恿艘粋€(gè)實(shí)體列表。每次游戲循環(huán)重新開(kāi)始我們將循環(huán)實(shí)體列表要求每一實(shí)體移動(dòng)并繪制自己。在我們的游戲中,這樣來(lái)實(shí)現(xiàn)實(shí)體的運(yùn)動(dòng):
// cycle round asking each entity to move itself
循環(huán)實(shí)體列表要求每一實(shí)體移動(dòng)自己。
for (int i=0;i<entities.size();i++) {
Entity entity = (Entity) entities.get(i);
entity.move(delta);
}
// cycle round drawing all the entities we have in the game
循環(huán)繪制游戲中所有的實(shí)體。
for (int i=0;i<entities.size();i++) {
Entity entity = (Entity) entities.get(i);
entity.draw(g);
}
Remember we calculated how long it'd been since we looped round. This can be used to work out how far an entity should move on the current loop. Right, now we know what Entity needs to be able to do, on to the implementation.
譯:計(jì)算上次循環(huán)開(kāi)始到本次循環(huán)的時(shí)長(zhǎng),它能夠用來(lái)算出實(shí)體應(yīng)該在當(dāng)前循環(huán)中移動(dòng)多遠(yuǎn)。好的,現(xiàn)在我們知道實(shí)體需要實(shí)現(xiàn)什么功能了。
The Entity class 實(shí)體類
The entity class will contain its currently location, its current movement and its visual representation. When an Entity is constructed these values will be defined. This includes retrieving the sprite from the store that should represent this entity. The location and movement associated with the entity will be definable and retriveable via get and set methods.
譯:實(shí)體類將控制其在屏幕中的當(dāng)前位置,當(dāng)前的移動(dòng)和外觀。在實(shí)體構(gòu)建時(shí),這些值將會(huì)被定義。這包括從緩存中獲取代表實(shí)體的精靈。實(shí)體的位置和運(yùn)動(dòng)可以通過(guò)set和get方法進(jìn)行讀取和設(shè)置。
/** The current x location of this entity 實(shí)體的當(dāng)前位置 x 坐標(biāo)*/
protected double x;
/** The current y location of this entity 實(shí)體的當(dāng)前位置 y 坐標(biāo)*/
protected double y;
/** The sprite that represents this entity 代表實(shí)體的精靈*/
protected Sprite sprite;
/** The current speed of this entity horizontally (pixels/sec) 實(shí)體水平方向上的當(dāng)前速度(像素/秒)*/
protected double dx;
/** The current speed of this entity vertically (pixels/sec) 實(shí)體垂直方向上的當(dāng)前速度(像素/秒)*/
protected double dy;
/**
* Construct a entity based on a sprite image and a location.
* 在精靈圖片和坐標(biāo)的基礎(chǔ)上構(gòu)造一個(gè)實(shí)體
*/
public Entity(String ref,int x,int y) {
this.sprite = SpriteStore.get().getSprite(ref);
this.x = x;
this.y = y;
}
Once these properties are defined we can cover the two methods that we require of Entity. The move() method looks like this:
譯:一旦這些屬性被定義,我們可以覆蓋實(shí)現(xiàn)實(shí)體類要求實(shí)現(xiàn)的兩個(gè)方法。move() 方法的實(shí)現(xiàn)如下:
public void move(long delta) {
// update the location of the entity based on move speeds 根據(jù)運(yùn)動(dòng)速度更新實(shí)體的坐標(biāo)位置
x += (delta * dx) / 1000;
y += (delta * dy) / 1000;
}
Simple! We take how every much time has passed, multiply it by the movement in each direction and add this on to the location. The division by 1000 is to adjust for the fact that the movement value is specified in pixels per second, but the time is specified in milliseconds. Each loop all the entities will be moved in accordance with their currently movement values (velocities).
譯:就是這么簡(jiǎn)單!我們用逝去時(shí)間(delta,以毫秒為單位)乘以在每個(gè)方向的運(yùn)動(dòng)速度(以像素/秒為單位),再除以1000是為了將運(yùn)動(dòng)速度的單位從“像素/秒”轉(zhuǎn)換成“像素/毫秒”,計(jì)算結(jié)果累加到實(shí)體的坐標(biāo)位置(計(jì)算結(jié)果與實(shí)體的坐標(biāo)位置相加,再?gòu)?fù)制給實(shí)體坐標(biāo)位置)。這樣一來(lái),每次循環(huán),所有實(shí)體將被按照他們當(dāng)前的移動(dòng)速度值和逝去時(shí)間進(jìn)行移動(dòng)。
Next we need to be able to draw an Entity onto our accelerated graphics context. draw() is implemented like this:
譯:接下來(lái),我們需要能夠?qū)?shí)體繪制到我們的加速圖形上下文環(huán)境。draw()方法是這樣實(shí)現(xiàn)的:
public void draw(Graphics g) {
sprite.draw(g,(int) x,(int) y);
}
Essentially, this just draws the sprite onto the supplied graphics context at its current location. So each loop, the entity moves and is then redrawn at the right location.
譯:實(shí)際上,我們只是將精靈按照其坐標(biāo)位置繪制到draw()方法參數(shù)提供的圖像上下文中。因此,每一次循環(huán)實(shí)體都移動(dòng),然后在正確的位置重繪自己。
Now we've defined our basic entity we should create a few subclasses as placeholders for some more functionality we'll add later on. We simply need to create the 3 subclasses of Entity; ShipEntity, ShotEntity and AlienEntity. For now we won't bother adding anything extra but it normally pays to be aware and add these things up front.
譯:現(xiàn)在我們已經(jīng)定義了我們的基本實(shí)體,我們應(yīng)該創(chuàng)造一些子類,作為占位符,以在將來(lái)添加更多的功能。 我們只需要建立三個(gè)實(shí)體子類:ShipEntity(玩家戰(zhàn)船),ShotEntity(子彈實(shí)體)和AlienEntity(外星人實(shí)體)。
The final step is to create our entities and add them to the game world. If we add a utility method to central Game class called initEntities(). This will initialise a set of entities at the game start. The current implementation looks like this:
譯:最后一步是創(chuàng)建我們的實(shí)體,并將它們加入到游戲的世界。我們將增加一個(gè)叫作initEntities()的方法到核心 Game 類,其將在游戲啟動(dòng)時(shí),初始化一個(gè)實(shí)體的集合。當(dāng)前的實(shí)現(xiàn)如下:
private void initEntities() {
// create the player ship and place it roughly in the center of the screen
//創(chuàng)建玩家飛船,并將其繪制在屏幕中間
ship = new ShipEntity(this,"sprites/ship.gif",370,550);
entities.add(ship);
// create a block of aliens (5 rows, by 12 aliens, spaced evenly)
//創(chuàng)建外星人方陣(5行,每行12個(gè)外星人,間隔軍均勻)
alienCount = 0;
for (int row=0;row<5;row++) {
for (int x=0;x<12;x++) {
Entity alien = new AlienEntity(this,
"sprites/alien.gif",
100+(x*50),
(50)+row*30);
entities.add(alien);
alienCount++;
}
}
}
As you can see, the initialisation takes two steps. The first is to create the player's ship. We simply create a ShipEntity with the appropriate graphic and center it at the bottom of our canvas.
譯:就像你看到的,初始化分為兩步。第一步是創(chuàng)建玩家戰(zhàn)船。我們簡(jiǎn)單地創(chuàng)建了一個(gè) ShipEntity ,并將其繪制到游戲畫(huà)布的底部中心位置。
The second step is to create all the aliens. We loop through creating a block of aliens. Again each alien is just the creation of the AlienEntity positioned at the right location. In addition we count how many aliens we've created so we can track whether the player has won the game.
譯:第二步是創(chuàng)建所以的外星人。我們通過(guò)循環(huán)創(chuàng)建一個(gè)外星人方陣。每一個(gè)外星人只是一個(gè)放置在正確位置的AlienEntity 對(duì)象。 此外,我們還統(tǒng)計(jì)創(chuàng)建了多少外星人,以追蹤玩家是否贏得了比賽。
Assuming the code to support moving and displaying the entities has been added to main game loop, running the game should now show the player's ship and a bunch of aliens.
譯:假設(shè)代碼支持移動(dòng)和顯示已被添加到游戲主循環(huán)的實(shí)體,現(xiàn)在運(yùn)行游戲應(yīng)顯示玩家的船和一群外星人。
Now each type of Entity moves in its own way and with its own contraints. Lets look at each one.
譯:現(xiàn)在,每個(gè)類型的實(shí)體以自己的方式運(yùn)動(dòng),并有它們自己的約束。讓我們看一下每一個(gè)實(shí)體的實(shí)現(xiàn)。
Ship Entity 戰(zhàn)船實(shí)體
Since the ship will be controlled by the player (see a little lower down) we have very little to do here. However, we do want to prevent the ship moving off the sides of the screen so we add this bit of code to the move() method in ShipEntity:
譯:由于戰(zhàn)船將由玩家控制(后面我們可以看到)。在 ShipEntity 的 move() 中我們只有很少的事情可以做,就是防止戰(zhàn)船移動(dòng)時(shí)越過(guò)屏幕的兩側(cè)。因此,我們?cè)?/span> ShipEntity 的 move()方法中加入這段代碼:
public void move(long delta) {
// if we're moving left and have reached the left hand side
// of the screen, don't move 如果戰(zhàn)船正在向左移動(dòng),并且已經(jīng)到達(dá)屏幕左邊界,停止移動(dòng)
if ((dx < 0) && (x < 10)) {
return;
}
// if we're moving right and have reached the right hand side
// of the screen, don't move 如果戰(zhàn)船正在向右移動(dòng),并且已經(jīng)到達(dá)屏幕右邊界,停止移動(dòng)
if ((dx > 0) && (x > 750)) {
return;
}
super.move(delta); //移動(dòng)
}
What we essentially are saying here is that if we're moving left and we're about to move off the left hand side of the screen then don't allow the movement (i.e. return). In reverse if we're moving to the right and are about to move off the right hand side of the screen then don't allow the movement. Otherwise we just do the normal Entity movement routine.
譯:我們基本上是在這里說(shuō)的是,如果戰(zhàn)船正在向左移動(dòng),并且將要移出屏幕左邊界,則不允許移動(dòng)(即retrun )。反之,如果戰(zhàn)船正在向右移動(dòng),并且將要移出屏幕右邊界,則不允許移動(dòng)。否則,我們執(zhí)行實(shí)體正常的運(yùn)動(dòng)邏輯。
Shot Entity 子彈實(shí)體
The shot entity is pretty simple, it just wants to run up the screen until it either hits an alien (see Collision later on) or runs off the top of the screen, at which point we'd like to remove it from the entity list (for details of the remove entity method check out the source).
譯:子彈實(shí)體很簡(jiǎn)單,它只是想在屏幕上跑起來(lái)直到它擊中外星人(見(jiàn)后面碰撞)或移出屏幕的頂部,這時(shí),我們要從實(shí)體列表將其刪除(有關(guān)刪除實(shí)體的方法實(shí)現(xiàn)詳情請(qǐng)參考源代碼)。
To start the shot moving with initialise the vertical movement to a negative number based on the speed we'd like the shot to move. The movement method itself looks like this:
譯:初始化子彈的移動(dòng)速度為一個(gè)負(fù)數(shù),其將從屏幕下方向上方做垂直運(yùn)動(dòng)。移動(dòng)方法的實(shí)現(xiàn)看起來(lái)像這樣:
public void move(long delta) {
// proceed with normal move 處理正常移動(dòng)
super.move(delta);
// if we shot off the screen, remove ourselfs 如果移出屏幕,刪除自己
if (y < -100) {
game.removeEntity(this);
}
}
Simply put, if the shot moves off the top of the screen, remove it.
譯:簡(jiǎn)單地說(shuō),如果子彈移出屏幕上方,將其刪除。
Alien Entity 外星人實(shí)體
Aliens are the most tricky part of our space invaders game. As they move around we need to notice when they hit the side of the screen and start them moving in the opposite direction. In conjuction each time they change direction we'd like them all to move down a step. Part of this will be covered in the movement routine and part in the game logic. Game logic is used in this case since we need to first detect that the aliens should change direction then change them all (rather than a localised change like the other entities)
譯:外星人的實(shí)現(xiàn)是我們的太空入侵者游戲中最棘手的部分。在他們移動(dòng)的過(guò)程中,我們需要檢測(cè)到他們何時(shí)碰觸到屏幕的邊界,并讓他們開(kāi)始向相反的方向移動(dòng)。每當(dāng)外星人實(shí)體一起選擇改變移動(dòng)方向時(shí),我們希望他們都向下移動(dòng)一步。本部分的實(shí)現(xiàn)一部分由實(shí)體類的move() 方法,另一部分在實(shí)現(xiàn)游戲邏輯時(shí)實(shí)現(xiàn)(游戲主循環(huán)中)。在游戲邏輯的實(shí)現(xiàn)中,我們需要首先檢測(cè)到的外星人應(yīng)該改變移動(dòng)方向,然后改變所有外星人的移動(dòng)方向(而不是像其他實(shí)體的局部變化) 。
Hopefully, we now know what we want to do, so how? First we initialise the movement of the aliens to start them moving to the left based on the predefined speed. Next we put the detection of an alien hitting the side in the movement routine like this:
譯:希望我們現(xiàn)在已經(jīng)知道我們想要做什么了,那么又如何實(shí)現(xiàn)呢?首先,我們初始化外星人運(yùn)動(dòng),讓它們以預(yù)定義的速度開(kāi)始向左移動(dòng)。接下來(lái)我們像下面代碼實(shí)現(xiàn)這樣檢測(cè)一個(gè)外星人在運(yùn)動(dòng)中是否碰觸了邊界:
public void move(long delta) {
// if we have reached the left hand side of the screen and
// are moving left then request a logic update 如果我們到達(dá)了屏幕左邊界并且正在向左移動(dòng),請(qǐng)求游戲更新邏輯(讓所有外星人向相反方向移動(dòng))
if ((dx < 0) && (x < 10)) {
game.updateLogic();
}
// and vice vesa, if we have reached the right hand side of
// the screen and are moving right, request a logic update 如果我們到達(dá)了屏幕右邊界并且正在向右移動(dòng),請(qǐng)求游戲更新邏輯(讓所有外星人向相反方向移動(dòng))
if ((dx > 0) && (x > 750)) {
game.updateLogic();
}
// proceed with normal move 處理正常移動(dòng)
super.move(delta);
}
In the same way as in ShipEntity, we check whether the entity has hit the edge of the screen. However, in this case we notify the game that the game logic for all entities need to be run. We'll make this logic adapt the movement of the aliens but more on this later.
譯:和 ShipEntity 的方法一樣,我們檢查該實(shí)體是否碰觸了屏幕的邊緣。然而,在這種情況下,游戲通知所有實(shí)體的游戲邏輯需要運(yùn)行。稍后,我們會(huì)調(diào)整外星人的移動(dòng)實(shí)現(xiàn)。
學(xué)軟件開(kāi)發(fā),到蜂鳥(niǎo)科技!
超強(qiáng)的師資力量 、完善的課程體系 、超低的培訓(xùn)價(jià)格 、真實(shí)的企業(yè)項(xiàng)目。
網(wǎng)址:www.ntcsoft.com
電話:0371-63839606
鄭州軟件開(kāi)發(fā)興趣小組群:38236716
posted on 2010-11-25 23:55
whistler 閱讀(410)
評(píng)論(0) 編輯 收藏