0
\$\begingroup\$

I want to create a game where enemies spawn, fly toward the player's ship, and stick to the side of it. The player can then rotate the ship and the stuck enemies will rotate with it.

The way I have this working now, the ship and the enemies are each part of a group and a collision group; when an enemy collides with the ship, it leaves its old group and collision group and joins those of the ship. The player is then able to rotate the ship's group, including the stuck enemies.

But from there, things get weird. If you rotate the ship 90 degrees to the left and then stick an enemy to its right edge, the enemy vanishes and appears at the top edge of the ship. Try to stick another enemy to the same point on the right edge, and it too will teleport to the top of the circle, colliding with the other enemy there. Also, enemies that have been "stuck" won't collide with those that have not.

If I move everything into one collision group, rotating the ship with enemies stuck to it will be reflected onscreen but not in the physics. You can spin the ship around all you like, and the enemies stuck to it will appear to rotate around it, but the non-stuck enemies will act as if they aren't moving.

How can I get a group of physics bodies to act like one body, rotating together and colliding with other objects in the gameworld? Code is below; try it out here.

var game = new Phaser.Game("100%", "100%", Phaser.AUTO, '', { preload: preload, create: create, update: update, render: render });
var debug = false;

var ship, enemy, enemies, shipCollisionGroup, enemyCollisionGroup, spawnEnemy;

function preload() {
    game.load.image('ship', 'simple-ship.svg');
    game.load.image('enemy', 'square-enemy.svg');
}

function create() {
    game.physics.startSystem(Phaser.Physics.P2JS);
    game.physics.p2.setImpactEvents(true);
    game.physics.p2.updateBoundsCollisionGroup();
    game.stage.backgroundColor = '#1C1C1C';

    shipCollisionGroup = game.physics.p2.createCollisionGroup();
    enemyCollisionGroup = game.physics.p2.createCollisionGroup();
    enemies = game.add.group();
    enemies.enableBody = true;
    enemies.physicsBodyType = Phaser.Physics.P2JS;
    ship = game.add.sprite(200, 200, 'ship');
    shipGroup = game.add.group();
    shipGroup.enableBody = true;
    shipGroup.addChild(ship);
    shipGroup.x = 200;
    shipGroup.y = 200;
    shipGroup.pivot.x = 200;
    shipGroup.pivot.y = 200;
    spawn();

    game.physics.p2.enable([ship, enemies], debug);
    ship.body.setCircle(200);
    ship.body.setCollisionGroup(shipCollisionGroup);
    ship.body.collides([shipCollisionGroup, enemyCollisionGroup], collision);

    cursors = game.input.keyboard.addKeys({
        'left': Phaser.KeyCode.A,
        'right': Phaser.KeyCode.D,
        'space': Phaser.KeyCode.SPACEBAR
    });
}

function update() {
    ship.body.setZeroVelocity();
    ship.body.setZeroRotation();

    if (cursors.left.isDown) {
        shipGroup.rotation -= .1;
    } else if (cursors.right.isDown) {
        shipGroup.rotation += .1;
    } else if (cursors.space.isDown) {
        spawnEnemy = true;
    } else if (cursors.space.isUp && spawnEnemy) {
        spawn();
        spawnEnemy = false;
    }
}

function render() {
    game.debug.text('A and D to rotate; spacebar to spawn enemies', 32, 32);
}

function collision(shipBody, impactorBody) {
    var enemy = impactorBody.sprite;
    // enemies.remove(enemy);
    shipGroup.addChild(enemy);
    enemy.body.removeCollisionGroup(enemyCollisionGroup);
    enemy.body.setCollisionGroup(shipCollisionGroup);
    enemy.body.setZeroVelocity();
    enemy.body.setZeroRotation();
}

function spawn() {
    var enemy = enemies.create(700, 200, 'enemy');
    enemy.body.velocity.x = -100;
    enemy.body.setCollisionGroup(enemyCollisionGroup);
    enemy.body.collides([shipCollisionGroup, enemyCollisionGroup]);
    enemy.body.sprite = enemy;
    enemy.anchor.x = 0.5;
    enemy.anchor.y = 0.5;
}
\$\endgroup\$
2
  • \$\begingroup\$ Hey, just a small note why I removed your links. Generally, the stuff pointed by the links will evolve over time as you keep on working on your project. At some point, this issue will be fixed but the code wont reflect what's in this post. If you have anything relevant to the issue to add, it should be added directly in the post, as code or as animated gifs instead of links that point to external and unstable resources. \$\endgroup\$ – Vaillancourt Sep 4 '17 at 4:08
  • 1
    \$\begingroup\$ The main project is stored on GitHub; the Glitch page I linked to was created specifically for this question, and it should be durable. I would have used CodePen, but the project has graphical assets that need to be included. I will put my code into the body of the question, and link to the durable Glitch page as a backup. \$\endgroup\$ – DawnPaladin Sep 5 '17 at 15:35
1
\$\begingroup\$

A solution for the ships colliding after being added to the shipgroup is to call enemy.body.clearCollision() before adding it to the shipcollisiongroup.

To not have them all go to the same place you could save their x,y before adding them to the shipgroup and then set their position to what you saved, remember to do it relatively to the group's position.

\$\endgroup\$
3
  • \$\begingroup\$ Thanks for answering! How do I "do it relatively to the group's position"? \$\endgroup\$ – DawnPaladin Sep 7 '17 at 4:30
  • \$\begingroup\$ Did you try adding the clearCollision()? I tried getting them to not change their position but it didn't work... How did it go for you? \$\endgroup\$ – Erik Sep 7 '17 at 17:12
  • \$\begingroup\$ clearCollision() does cause the enemies to no longer collide with each other, but when they join shipGroup they all appear in the same place. Phaser.Sprite has methods for toGlobal and toLocal - how do I use these? \$\endgroup\$ – DawnPaladin Sep 9 '17 at 21:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.