Movement
譯:運動
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:
譯:讓游戲角色動起來!在我們的例子中,運動由實體類來處理。每次循環我們將要求實體們移動自己。為了方便實現,我們為游戲主窗口添加了一個實體列表。每次游戲循環重新開始我們將循環實體列表要求每一實體移動并繪制自己。在我們的游戲中,這樣來實現實體的運動:
// cycle round asking each entity to move itself
循環實體列表要求每一實體移動自己。
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
循環繪制游戲中所有的實體。
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.
譯:計算上次循環開始到本次循環的時長,它能夠用來算出實體應該在當前循環中移動多遠。好的,現在我們知道實體需要實現什么功能了。
The Entity class 實體類
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.
譯:實體類將控制其在屏幕中的當前位置,當前的移動和外觀。在實體構建時,這些值將會被定義。這包括從緩存中獲取代表實體的精靈。實體的位置和運動可以通過set和get方法進行讀取和設置。
/** The current x location of this entity 實體的當前位置 x 坐標*/
protected double x;
/** The current y location of this entity 實體的當前位置 y 坐標*/
protected double y;
/** The sprite that represents this entity 代表實體的精靈*/
protected Sprite sprite;
/** The current speed of this entity horizontally (pixels/sec) 實體水平方向上的當前速度(像素/秒)*/
protected double dx;
/** The current speed of this entity vertically (pixels/sec) 實體垂直方向上的當前速度(像素/秒)*/
protected double dy;
/**
* Construct a entity based on a sprite image and a location.
* 在精靈圖片和坐標的基礎上構造一個實體
*/
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:
譯:一旦這些屬性被定義,我們可以覆蓋實現實體類要求實現的兩個方法。move() 方法的實現如下:
public void move(long delta) {
// update the location of the entity based on move speeds 根據運動速度更新實體的坐標位置
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).
譯:就是這么簡單!我們用逝去時間(delta,以毫秒為單位)乘以在每個方向的運動速度(以像素/秒為單位),再除以1000是為了將運動速度的單位從“像素/秒”轉換成“像素/毫秒”,計算結果累加到實體的坐標位置(計算結果與實體的坐標位置相加,再復制給實體坐標位置)。這樣一來,每次循環,所有實體將被按照他們當前的移動速度值和逝去時間進行移動。
Next we need to be able to draw an Entity onto our accelerated graphics context. draw() is implemented like this:
譯:接下來,我們需要能夠將實體繪制到我們的加速圖形上下文環境。draw()方法是這樣實現的:
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.
譯:實際上,我們只是將精靈按照其坐標位置繪制到draw()方法參數提供的圖像上下文中。因此,每一次循環實體都移動,然后在正確的位置重繪自己。
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.
譯:現在我們已經定義了我們的基本實體,我們應該創造一些子類,作為占位符,以在將來添加更多的功能。 我們只需要建立三個實體子類:ShipEntity(玩家戰船),ShotEntity(子彈實體)和AlienEntity(外星人實體)。
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:
譯:最后一步是創建我們的實體,并將它們加入到游戲的世界。我們將增加一個叫作initEntities()的方法到核心 Game 類,其將在游戲啟動時,初始化一個實體的集合。當前的實現如下:
private void initEntities() {
// create the player ship and place it roughly in the center of the screen
//創建玩家飛船,并將其繪制在屏幕中間
ship = new ShipEntity(this,"sprites/ship.gif",370,550);
entities.add(ship);
// create a block of aliens (5 rows, by 12 aliens, spaced evenly)
//創建外星人方陣(5行,每行12個外星人,間隔軍均勻)
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.
譯:就像你看到的,初始化分為兩步。第一步是創建玩家戰船。我們簡單地創建了一個 ShipEntity ,并將其繪制到游戲畫布的底部中心位置。
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.
譯:第二步是創建所以的外星人。我們通過循環創建一個外星人方陣。每一個外星人只是一個放置在正確位置的AlienEntity 對象。 此外,我們還統計創建了多少外星人,以追蹤玩家是否贏得了比賽。
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.
譯:假設代碼支持移動和顯示已被添加到游戲主循環的實體,現在運行游戲應顯示玩家的船和一群外星人。
Now each type of Entity moves in its own way and with its own contraints. Lets look at each one.
譯:現在,每個類型的實體以自己的方式運動,并有它們自己的約束。讓我們看一下每一個實體的實現。
Ship Entity 戰船實體
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:
譯:由于戰船將由玩家控制(后面我們可以看到)。在 ShipEntity 的 move() 中我們只有很少的事情可以做,就是防止戰船移動時越過屏幕的兩側。因此,我們在 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 如果戰船正在向左移動,并且已經到達屏幕左邊界,停止移動
if ((dx < 0) && (x < 10)) {
return;
}
// if we're moving right and have reached the right hand side
// of the screen, don't move 如果戰船正在向右移動,并且已經到達屏幕右邊界,停止移動
if ((dx > 0) && (x > 750)) {
return;
}
super.move(delta); //移動
}
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.
譯:我們基本上是在這里說的是,如果戰船正在向左移動,并且將要移出屏幕左邊界,則不允許移動(即retrun )。反之,如果戰船正在向右移動,并且將要移出屏幕右邊界,則不允許移動。否則,我們執行實體正常的運動邏輯。
Shot Entity 子彈實體
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).
譯:子彈實體很簡單,它只是想在屏幕上跑起來直到它擊中外星人(見后面碰撞)或移出屏幕的頂部,這時,我們要從實體列表將其刪除(有關刪除實體的方法實現詳情請參考源代碼)。
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:
譯:初始化子彈的移動速度為一個負數,其將從屏幕下方向上方做垂直運動。移動方法的實現看起來像這樣:
public void move(long delta) {
// proceed with normal move 處理正常移動
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.
譯:簡單地說,如果子彈移出屏幕上方,將其刪除。
Alien Entity 外星人實體
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)
譯:外星人的實現是我們的太空入侵者游戲中最棘手的部分。在他們移動的過程中,我們需要檢測到他們何時碰觸到屏幕的邊界,并讓他們開始向相反的方向移動。每當外星人實體一起選擇改變移動方向時,我們希望他們都向下移動一步。本部分的實現一部分由實體類的move() 方法,另一部分在實現游戲邏輯時實現(游戲主循環中)。在游戲邏輯的實現中,我們需要首先檢測到的外星人應該改變移動方向,然后改變所有外星人的移動方向(而不是像其他實體的局部變化) 。
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:
譯:希望我們現在已經知道我們想要做什么了,那么又如何實現呢?首先,我們初始化外星人運動,讓它們以預定義的速度開始向左移動。接下來我們像下面代碼實現這樣檢測一個外星人在運動中是否碰觸了邊界:
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 如果我們到達了屏幕左邊界并且正在向左移動,請求游戲更新邏輯(讓所有外星人向相反方向移動)
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 如果我們到達了屏幕右邊界并且正在向右移動,請求游戲更新邏輯(讓所有外星人向相反方向移動)
if ((dx > 0) && (x > 750)) {
game.updateLogic();
}
// proceed with normal move 處理正常移動
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 的方法一樣,我們檢查該實體是否碰觸了屏幕的邊緣。然而,在這種情況下,游戲通知所有實體的游戲邏輯需要運行。稍后,我們會調整外星人的移動實現。
學軟件開發,到蜂鳥科技!
超強的師資力量 、完善的課程體系 、超低的培訓價格 、真實的企業項目。
網址:
電話:
鄭州軟件開發興趣小組群: