com.gamejolt.mikykr5.ceidecpong.ecs.systems.CollisionDetectionSystem.java Source code

Java tutorial

Introduction

Here is the source code for com.gamejolt.mikykr5.ceidecpong.ecs.systems.CollisionDetectionSystem.java

Source

/*
 * Copyright (c) 2014, Miguel Angel Astor Romero
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer. 
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * Read the LICENSE file for more details.
 */
package com.gamejolt.mikykr5.ceidecpong.ecs.systems;

import com.badlogic.ashley.core.ComponentType;
import com.badlogic.ashley.core.Engine;
import com.badlogic.ashley.core.Entity;
import com.badlogic.ashley.core.Family;
import com.badlogic.ashley.systems.IteratingSystem;
import com.badlogic.ashley.utils.ImmutableArray;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.gamejolt.mikykr5.ceidecpong.ProjectConstants;
import com.gamejolt.mikykr5.ceidecpong.ecs.components.BoundingBoxComponent;
import com.gamejolt.mikykr5.ceidecpong.ecs.components.Mappers;
import com.gamejolt.mikykr5.ceidecpong.ecs.components.PlayerComponent;
import com.gamejolt.mikykr5.ceidecpong.ecs.components.PositionComponent;
import com.gamejolt.mikykr5.ceidecpong.ecs.components.SoundComponent;
import com.gamejolt.mikykr5.ceidecpong.ecs.components.SpriteComponent;
import com.gamejolt.mikykr5.ceidecpong.ecs.components.VelocityComponent;
import com.gamejolt.mikykr5.ceidecpong.ecs.systems.messaging.InterSystemMessage;
import com.gamejolt.mikykr5.ceidecpong.ecs.systems.messaging.InterSystemMessagingQueue;

public class CollisionDetectionSystem extends IteratingSystem {
    private ImmutableArray<Entity> collidables;
    private final float screenLeftBorder;
    private final float screenRightBorder;
    private final float screenTopBorder;
    private final float screenBottomBorder;
    private final Vector2 randomVector = new Vector2();

    @SuppressWarnings("unchecked")
    public CollisionDetectionSystem(Engine engine) {
        super(Family.getFor(
                ComponentType.getBitsFor(PositionComponent.class, BoundingBoxComponent.class,
                        VelocityComponent.class),
                ComponentType.getBitsFor(), ComponentType.getBitsFor(PlayerComponent.class)));

        collidables = engine.getEntitiesFor(Family.getFor(BoundingBoxComponent.class));
        screenLeftBorder = -((float) ProjectConstants.FB_WIDTH / 2.0f);
        screenRightBorder = ((float) ProjectConstants.FB_WIDTH / 2.0f) - 1.0f;
        screenTopBorder = ((float) ProjectConstants.FB_HEIGHT / 2.0f) - 1.0f;
        screenBottomBorder = -((float) ProjectConstants.FB_HEIGHT / 2.0f);
    }

    @Override
    public void processEntity(Entity entity, float deltaTime) {
        InterSystemMessage message;
        PositionComponent position = Mappers.positionMapper.get(entity);
        BoundingBoxComponent bounds = Mappers.bboxMapper.get(entity);
        VelocityComponent velocity = Mappers.velocityMapper.get(entity);
        SoundComponent sound = Mappers.soundMapper.get(entity);

        // Check if this entity is within the screen.
        // If the entity collides with any of the borders then bounce or score as needed.
        if (position.x < screenLeftBorder) {
            resetEntity(entity);

            message = new InterSystemMessage(ScoringSystem.class.getCanonicalName());
            message.data.put("SCORE", 1);
            InterSystemMessagingQueue.pushMessage(message);

            message = new InterSystemMessage(SoundSystem.class.getCanonicalName());
            message.data.put("PLAY", "data/sfx/atari_boom.ogg");
            InterSystemMessagingQueue.pushMessage(message);
        }

        if (position.x + bounds.bbox.getWidth() >= screenRightBorder) {
            resetEntity(entity);

            message = new InterSystemMessage(ScoringSystem.class.getCanonicalName());
            message.data.put("SCORE", 0);
            InterSystemMessagingQueue.pushMessage(message);

            message = new InterSystemMessage(SoundSystem.class.getCanonicalName());
            message.data.put("PLAY", "data/sfx/oh_yeah_wav_cut.ogg");
            InterSystemMessagingQueue.pushMessage(message);
        }

        if (position.y < screenBottomBorder) {
            position.y = screenBottomBorder;
            velocity.vy = velocity.vy < 0.0f ? -velocity.vy : velocity.vy;
            accelerate(velocity);
            if (sound != null) {
                message = new InterSystemMessage(SoundSystem.class.getCanonicalName());
                message.data.put("PLAY", sound.path);
                InterSystemMessagingQueue.pushMessage(message);
            }
        }

        if (position.y + bounds.bbox.getHeight() >= screenTopBorder) {
            position.y = screenTopBorder - bounds.bbox.getHeight();
            velocity.vy = velocity.vy > 0.0f ? -velocity.vy : velocity.vy;
            accelerate(velocity);
            if (sound != null) {
                message = new InterSystemMessage(SoundSystem.class.getCanonicalName());
                message.data.put("PLAY", sound.path);
                InterSystemMessagingQueue.pushMessage(message);
            }
        }

        for (int i = 0; i < collidables.size(); i++) {
            BoundingBoxComponent collidable;
            PositionComponent colPosition;

            if (collidables.get(i).getIndex() == entity.getIndex()) {
                continue;
            } else {
                collidable = Mappers.bboxMapper.get(collidables.get(i));
                colPosition = Mappers.positionMapper.get(collidables.get(i));
                if (colPosition == null)
                    continue;

                bounds.bbox.setPosition(position.x, position.y);
                collidable.bbox.setPosition(colPosition.x, colPosition.y);

                if (collidesLeft(bounds.bbox, collidable.bbox)) {
                    velocity.vx = velocity.vx < 0.0f ? -velocity.vx : velocity.vx;
                    accelerate(velocity);

                    if (sound != null) {
                        message = new InterSystemMessage(SoundSystem.class.getCanonicalName());
                        message.data.put("PLAY", sound.path);
                        InterSystemMessagingQueue.pushMessage(message);
                    }
                } else if (collidesRight(bounds.bbox, collidable.bbox)) {
                    velocity.vx = velocity.vx > 0.0f ? -velocity.vx : velocity.vx;
                    accelerate(velocity);

                    if (sound != null) {
                        message = new InterSystemMessage(SoundSystem.class.getCanonicalName());
                        message.data.put("PLAY", sound.path);
                        InterSystemMessagingQueue.pushMessage(message);
                    }
                }
            }
        }

        message = new InterSystemMessage(ComputerPlayerPositioningSystem.class.getCanonicalName());
        message.data.put("BALL_Y", position.y);
        InterSystemMessagingQueue.pushMessage(message);
    }

    private void accelerate(VelocityComponent velocity) {
        velocity.vx *= 1.03f;
        velocity.vy *= 1.03f;
    }

    private boolean collidesLeft(Rectangle a, Rectangle b) {
        float leftBottomCornerY, leftTopCornerY, leftCenterY;

        leftBottomCornerY = a.y;
        leftTopCornerY = a.y + a.height;
        leftCenterY = a.y + (a.height / 2);

        return b.contains(a.x, leftBottomCornerY) || b.contains(a.x, leftTopCornerY)
                || b.contains(a.x, leftCenterY);
    }

    private boolean collidesRight(Rectangle a, Rectangle b) {
        float x, rightBottomCornerY, rightTopCornerY, rightCenterY;

        x = a.x + a.width;
        rightBottomCornerY = a.y;
        rightTopCornerY = a.y + a.height;
        rightCenterY = a.y + (a.height / 2);

        return b.contains(x, rightBottomCornerY) || b.contains(x, rightTopCornerY) || b.contains(x, rightCenterY);
    }

    private void resetEntity(Entity entity) {
        PositionComponent position = Mappers.positionMapper.get(entity);
        SpriteComponent sprite = Mappers.spriteMapper.get(entity);
        VelocityComponent velocity = Mappers.velocityMapper.get(entity);
        int randomSign = MathUtils.random(-1, 1) >= 0 ? 1 : -1;

        randomVector.set(Vector2.X).setAngle(MathUtils.random(-60, 60));
        velocity.setXY(randomVector.x * -475 * randomSign, randomVector.y * 475 * randomSign);

        if (position != null) {
            if (sprite != null) {
                position.setXY(-(sprite.sprite.getWidth() / 2), -(sprite.sprite.getHeight() / 2));
            } else {
                position.setXY(0, 0);
            }
        }
    }
}