/* * The MIT License (MIT) * * Copyright (c) 2013 Goran Mrzljak * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.turbogerm.helljump.game.platforms; import java.util.Comparator; import com.badlogic.gdx.assets.AssetManager; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.TextureAtlas; import com.badlogic.gdx.math.Intersector; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Array; import com.turbogerm.germlibrary.util.Pools; import com.turbogerm.helljump.dataaccess.PlatformData; import com.turbogerm.helljump.dataaccess.PlatformFeatureData; import com.turbogerm.helljump.game.CollisionEffects; import com.turbogerm.helljump.game.GameArea; import com.turbogerm.helljump.game.PlatformToCharCollisionData; import com.turbogerm.helljump.game.character.GameCharacter; import com.turbogerm.helljump.game.items.ItemBase; import com.turbogerm.helljump.game.platforms.features.PlatformFeatureBase; import com.turbogerm.helljump.game.platforms.features.PlatformFeatureFactory; import com.turbogerm.helljump.game.platforms.features.PlatformModifier; import com.turbogerm.helljump.game.platforms.movement.PlatformMovementBase; import com.turbogerm.helljump.game.platforms.movement.PlatformMovementFactory; import com.turbogerm.helljump.resources.ResourceNames; public abstract class PlatformBase { private static final int ATTACHED_ITEMS_INITIAL_CAPACITY = 2; private static final float DEFAULT_COLOR_VALUE = 0.5f; private static final Comparator<PlatformFeatureBase> PLATFORM_FEATURE_RENDER_COMPARATOR; static { PLATFORM_FEATURE_RENDER_COMPARATOR = new Comparator<PlatformFeatureBase>() { @Override public int compare(PlatformFeatureBase f1, PlatformFeatureBase f2) { if (f1.getRenderPrecedence() < f2.getRenderPrecedence()) { return -1; } else if (f1.getRenderPrecedence() > f2.getRenderPrecedence()) { return 1; } else { return 0; } } }; } private final int mRiseSectionId; private final int mPlatformId; private final Vector2 mInitialPosition; protected final Sprite mSprite; protected final PlatformModifier mPlatformModifier; private final PlatformMovementBase mPlatformMovement; private final boolean mHasVerticalMovement; private final Array<PlatformFeatureBase> mPlatformFeatures; private final Array<PlatformFeatureBase> mPlatformFeaturesForRendering; private final Array<ItemBase> mAttachedItems; public PlatformBase(int riseSectionId, PlatformData platformData, int startStep, AssetManager assetManager) { mRiseSectionId = riseSectionId; mPlatformId = platformData.getId(); mInitialPosition = platformData.getPosition(startStep); TextureAtlas atlas = assetManager.get(ResourceNames.PLATFORMS_ATLAS); mSprite = atlas.createSprite(getImageName(platformData)); mSprite.setBounds(mInitialPosition.x, mInitialPosition.y, PlatformData.PLATFORM_WIDTH, PlatformData.PLATFORM_HEIGHT); mPlatformModifier = new PlatformModifier(); mPlatformMovement = PlatformMovementFactory.create(platformData.getMovementData(), mInitialPosition, assetManager); mHasVerticalMovement = mPlatformMovement.hasVerticalMovement(); Array<PlatformFeatureBase> platformFeatures = getPlatformFeatures(platformData.getFeaturesData(), assetManager); mPlatformFeatures = platformFeatures != null ? platformFeatures : new Array<PlatformFeatureBase>(true, 0); mPlatformFeaturesForRendering = new Array<PlatformFeatureBase>(mPlatformFeatures); mPlatformFeaturesForRendering.sort(PLATFORM_FEATURE_RENDER_COMPARATOR); mAttachedItems = new Array<ItemBase>(ATTACHED_ITEMS_INITIAL_CAPACITY); } public final void update(float delta, Vector2 c1, Vector2 c2, PlatformToCharCollisionData collisionData) { // if platform can move up, additional platform to char collision must be checked if (mHasVerticalMovement && collisionData.isEnabled) { Vector2 position = getPosition(); Vector2 p1 = Pools.obtainVector(); p1.set(position.x, position.y + PlatformData.PLATFORM_HEIGHT); updateImpl(delta, c1, c2, collisionData); position = getPosition(); Vector2 p2 = Pools.obtainVector(); p2.set(position.x, position.y + PlatformData.PLATFORM_HEIGHT); // only check for collision when platform is going up, and character is going down if (p2.y > p1.y) { collisionData.isCollision = Intersector.intersectSegments( c1, c2, p1, p2, collisionData.collisionPoint); if (collisionData.isCollision) { collisionData.collisionPlatform = this; collisionData.collisionPoint.y = p2.y; } } Pools.freeVector(p1); Pools.freeVector(p2); } else { updateImpl(delta, c1, c2, collisionData); } } protected void updateImpl(float delta, Vector2 c1, Vector2 c2, PlatformToCharCollisionData collisionData) { for (PlatformFeatureBase platformFeature : mPlatformFeatures) { platformFeature.update(delta); } if (isMovingInternal()) { mPlatformMovement.update(delta); Vector2 position = getPosition(); for (ItemBase item : mAttachedItems) { item.updatePosition(position); } } updatePlatformModifier(); } public final void render(SpriteBatch batch) { Color spriteColor = mPlatformModifier.spriteColor; for (PlatformFeatureBase platformFeature : mPlatformFeaturesForRendering) { platformFeature.render(batch, getPosition(), spriteColor); } if (mPlatformModifier.isPlatformVisible) { Vector2 position = getPosition(); mSprite.setPosition(position.x, position.y); mSprite.setColor(mPlatformModifier.spriteColor); mSprite.draw(batch); } mPlatformMovement.render(batch, spriteColor.a); } public boolean isCollision(Vector2 c1, Vector2 c2, Vector2 intersection) { Vector2 position = getPosition(); Vector2 p1 = Pools.obtainVector(); Vector2 p2 = Pools.obtainVector(); float pY = position.y + PlatformData.PLATFORM_HEIGHT; p1.set(position.x - GameCharacter.COLLISION_LINE_LENGTH, pY); p2.set(position.x + PlatformData.PLATFORM_WIDTH - GameCharacter.COLLISION_WIDTH_OFFSET, pY); boolean isIntersection = Intersector.intersectSegments(c1, c2, p1, p2, intersection); Pools.freeVector(p1); Pools.freeVector(p2); return isIntersection; } public boolean isActive(float visibleAreaPosition, float visiblePlatformsAreaPadding) { if (!isActiveInternal()) { return false; } Vector2 position = getPosition(); float activeRangeLower = visibleAreaPosition - PlatformData.PLATFORM_HEIGHT - visiblePlatformsAreaPadding; float activeRangeUpper = visibleAreaPosition + GameArea.GAME_AREA_HEIGHT + visiblePlatformsAreaPadding; return position.y >= activeRangeLower && position.y <= activeRangeUpper; } public void applyEffect(int collisionEffect) { mPlatformMovement.applyEffect(collisionEffect); for (PlatformFeatureBase feature : mPlatformFeatures) { feature.applyEffect(collisionEffect); } } public void attachItem(ItemBase item) { item.setOffsetFromPlatform(mInitialPosition); mAttachedItems.add(item); } protected boolean isActiveInternal() { return true; } protected boolean isMovingInternal() { return true; } private void updatePlatformModifier() { mPlatformModifier.reset(); mPlatformModifier.spriteColor.set(DEFAULT_COLOR_VALUE, DEFAULT_COLOR_VALUE, DEFAULT_COLOR_VALUE, 1.0f); mPlatformMovement.applyModifier(mPlatformModifier); for (PlatformFeatureBase feature : mPlatformFeatures) { feature.applyModifier(mPlatformModifier); } } public void getCollisionEffects(float collisionPointX, CollisionEffects collisionEffects) { mPlatformMovement.applyContact(collisionEffects); float relativeCollisionPointX = collisionPointX - getPosition().x; for (PlatformFeatureBase feature : mPlatformFeatures) { if (feature.isContact(relativeCollisionPointX)) { feature.applyContact(collisionEffects); } } collisionEffects.set(CollisionEffects.VISIBLE_ON_JUMP); } public int getPlatformId() { return mPlatformId; } public int getRiseSectionId() { return mRiseSectionId; } public Vector2 getPosition() { return mPlatformMovement.getPosition(); } private static String getImageName(PlatformData platformData) { String platformType = platformData.getPlatformType(); if (PlatformData.CRUMBLE_TYPE.equals(platformType)) { return ResourceNames.PLATFORM_CRUMBLE_IMAGE_NAME; } else { return ResourceNames.getRandomPlatformNormalImageName(); } } private static Array<PlatformFeatureBase> getPlatformFeatures(Array<PlatformFeatureData> featuresData, AssetManager assetManager) { if (featuresData == null) { return null; } Array<PlatformFeatureBase> platformFeatures = new Array<PlatformFeatureBase>(true, featuresData.size); for (PlatformFeatureData featureData : featuresData) { PlatformFeatureBase platformFeature = PlatformFeatureFactory.create(featureData, assetManager); platformFeatures.add(platformFeature); } return platformFeatures; } }