Giter VIP home page Giter VIP logo

asteroids05's Introduction

asteroids05

See the rest of the tutorial here.

Edit on StackBlitz ⚡️

Collisions

So far the game we have built allows you to hoon around in a space-ship blasting the void with fireballs which is kind of fun, but not very challenging. The Asteroids game doesn't really become "Asteroids" until you actually have... asteroids. Also, you should be able to break them up with your blaster and crashing into them should end the game. Here's a preview:

Spaceship flying, shooting asteroids and colliding with them

State

We will need to store two new pieces of state: the collection of asteroids (rocks) which is another array of Body, just like bullets; and also a boolean that will become true when the game ends due to collision between the ship and a rock.

  interface State {
    ...
    readonly rocks:ReadonlyArray<Body>,
    readonly gameOver:boolean
  }

Our initial state is going to include several rocks from the outside, as follows:

  const
    startRocks = [...Array(Constants.StartRocksCount)]
      .map((_,i)=>createCircle("rock")(i)
         (Constants.StartTime)(Constants.StartRockRadius)(Vec.Zero)
         (new Vec(0.5 - Math.random(), 0.5 - Math.random()))),
    initialState:State = {
      time:0,
      ship: createShip(),
      bullets: [],
      rocks: startRocks,
      exit: [],
      objCount: Constants.StartRocksCount,
      gameOver: false
    }

Our tick function is more or less the same as above, but it will apply one more transformation to the state that it returns, by applying the following function. This function checks for collisions between the ship and rocks, and also between bullets and rocks.
typescript handleCollisions = (s:State) => { const bodiesCollided = (a:Body,b:Body) => a.pos.sub(b.pos).len() < a.radius + b.radius, shipCollided = s.rocks.filter(r=>bodiesCollided(s.ship,r)).length > 0, allBulletsAndRocks = flatMap(s.bullets,b=>s.rocks.map(r=>({bullet:b,rock:r}))), collidedBulletsAndRocks = allBulletsAndRocks.filter(({bullet:b,rock:r})=>bodiesCollided(b,r)), collidedBullets = collidedBulletsAndRocks.map(({bullet})=>bullet), collidedRocks = collidedBulletsAndRocks.map(({rock})=>rock), createChildRock = (r:Body,dir:number)=> createCircle('rock')(0/we assign the ids later/) (s.time)(r.radius/2) (r.pos)(r.vel.ortho().scale(dir)), spawnChildRocks = (r:Body)=> r.radius >= Constants.StartRockRadius/4 ? [createChildRock(r,1),createChildRock(r,-1)] : [], newRocks = flatMap(collidedRocks, spawnChildRocks) .map((r,i)=>{...r, id: r.viewType + (s.objCount + i)}) return { ...s, bullets: s.bullets.filter(b=>!collidedBullets.includes(b)), rocks: s.rocks.filter(r=>!collidedRocks.includes(r)).concat(newRocks), exit: s.exit.concat(collidedBullets,collidedRocks), objCount: s.objCount + newRocks.length, gameOver: shipCollided } };

Finally, we need to update `updateView` function.  First, we need to update the visuals for each of the rocks, but these are the same as bullets.  The second, slightly bigger, change, is simply to display the text "Game Over" on `s.gameover` true. 
```typescript
  function updateView(s: State) {
  ...
    s.bullets.forEach(updateBodyView);
    s.rocks.forEach(updateBodyView);
    s.exit.forEach(o=>{
      const v = document.getElementById(o.id);
      if(v) svg.removeChild(v);
    })
    if(s.gameOver) {
      subscription.unsubscribe();
      const v = document.createElementNS(svg.namespaceURI, "text")!;
      attr(v,{x:Constants.CanvasSize/6,y:Constants.CanvasSize/2,class:"gameover"});
      v.textContent = "Game Over";
      svg.appendChild(v);
    }
  }

The other thing happening at game over, is the call to subscription.unsubscribe. This subscription is the object returned by the subscribe call on our main Observable:

  const subscription = interval(10).pipe(
    map(elapsed=>new Tick(elapsed)),
    merge(
      startLeftRotate,startRightRotate,stopLeftRotate,stopRightRotate),
    merge(startThrust,stopThrust),
    merge(shoot),
    scan(reduceState, initialState)
    ).subscribe(updateView);

At this point we have more-or-less all the elements of a game. The implementation above could be extended quite a lot. For example, we could add score, multiple lives, perhaps some more physics. But generally, these are just extensions to the framework above: manipulation and then display of additional state.

The key thing is that the observable has allowed us to keep well separated state management (model), its input and manipulation (control) and the visuals (view). Further extensions are just additions within each of these elements - and doing so should not add greatly to the complexity.

I invite you to click through on the animations above, to the live code editor where you can extend or refine the framework I've started.

asteroids05's People

Contributors

tgdwyer avatar haotongwang avatar yusufades avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.