Разработка на коленке

"тут должна быть красивая цитата о программировании"

Phaser: летающие шарики, которые никогда не останавливаются

2014-06-29 19:40
Луна

Вот такая луна получилась у меня после 20 минут рисования в Inkscape. Конечно невесть что, но для начала сойдёт. Эта луна будет у меня летать в компании таких же.

Phaser меня заинтересовал, продолжаю его изучать. На этот раз я хотел сделать несколько сталкивающихся шариков, движение которых никогда не затухает. Делать просто шары с отладочной графикой неитересно, да и смотреть на это никто не будет, а так вроде и картинка получилась.

Итак, чего я хотел:

  • игровой мир, в котором летают шарики;
  • движение никогда не должно останавливаться;
  • по клику - ставить на паузу.

Вот и все нехитрые требования.

Сделать шарики несложно, достаточно просто создать объект и установить тип для body:

moon.body.setCircle(radius);

Самым сложным оказалось организовать вечное движение. Дело в том, что при столкновении скорость движения затухает, а мне этого хотелось избежать. Поначалу я искал возможность выставить минимальную скорость у объекта или какой-нибудь постоянный импульс, но не нашёл. Потом хотел в update корректировать скорость, т.е. вычислять направление, а потом вычислять новый вектор скорости. Но с этим тоже не задалось, картинка всё время дёргалась. В конце концов нужного мне поведения добился, установив упругость в 1, т.е. при столкновениях с грацицами и между лунами, не происходит потеря энергии, это меня устроило:

var moonMaterial = game.physics.p2.createMaterial('moonMaterial');
var worldMaterial = game.physics.p2.createMaterial('worldMaterial');

var moon2worldCcontactMaterial = game.physics.p2.createContactMaterial(
    moonMaterial, worldMaterial, { restitution: 1.0 });
var moon2moonContactMaterial = game.physics.p2.createContactMaterial(
    moonMaterial, moonMaterial, { restitution: 1.0 });

game.physics.p2.setWorldMaterial(worldMaterial);

Ну а выставлять на паузу по клику и вовсе просто:

game.paused = !game.paused;

Вот что получилось в итоге:

Исходник bouncingmoons.js:

(function() {

    var onPreload = function() {
        game.load.image('moon', 'moon.png');
    };

    var onCreate = function() {
        game.stage.backgroundColor = '#373e48';
        game.physics.startSystem(Phaser.Physics.P2JS);
        game.physics.p2.gravity.y = 0;
        game.physics.p2.friction = 0;
        game.physics.p2.applyDamping = false;

        var moonMaterial = game.physics.p2.createMaterial('moonMaterial');
        var worldMaterial = game.physics.p2.createMaterial('worldMaterial');

        var moon2worldCcontactMaterial = game.physics.p2.createContactMaterial(
            moonMaterial, worldMaterial, { restitution: 1.0 });
        var moon2moonContactMaterial = game.physics.p2.createContactMaterial(
            moonMaterial, moonMaterial, { restitution: 1.0 });

        game.physics.p2.setWorldMaterial(worldMaterial);

        var maxMoonsNumber = 5;
        var maxVelocity = 400;

        var moons = game.add.group();
        for(var i = 0; i < maxMoonsNumber; i++) {
            var moon = moons.create(50 + 110 * i, 100, 'moon');
            game.physics.p2.enable(moon);

            var scale = 0.3 + 0.05 * i;
            moon.scale = {x: scale, y: scale};
            moon.body.setCircle(60 * scale);

            moon.damping = 0;
            moon.angularDamping = 0;

            moon.body.velocity.x = Math.floor(Math.random() * maxVelocity + 1);
            moon.body.velocity.y = Math.floor(Math.random() * maxVelocity + 1);

            moon.body.setMaterial(moonMaterial);
        }

        game.input.onDown.add(onClick, this);
    };

    var onClick = function() {
        game.paused = !game.paused;
    };

    var WIDTH = $(window).width();
    var HEIGHT = $(window).height();
    var game = new Phaser.Game(
        WIDTH, HEIGHT, Phaser.CANVAS, '', {preload: onPreload, create: onCreate});
})();

index.html:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />

    <title>moons</title>
    <style type="text/css" media="all">
    * {
        margin: 0;
        padding: 0;
    }
    </style>
</head>
<body>
    <script src="jquery.min.js" type="text/javascript" charset="utf-8"></script>
    <script src="phaser.min.js" type="text/javascript" charset="utf-8"></script>
    <script src="bouncingmoons.js" type="text/javascript" charset="utf-8"></script>
</body>
</html>