Package com.rim.samples.device.openglspritegamedemo

Source Code of com.rim.samples.device.openglspritegamedemo.SpriteGameLevel$LevelSaxHandler

/*
* SpriteGameLevel.java
*
* Copyright � 1998-2011 Research In Motion Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Note: For the sake of simplicity, this sample application may not leverage
* resource bundles and resource strings.  However, it is STRONGLY recommended
* that application developers make use of the localization features available
* within the BlackBerry development platform to ensure a seamless application
* experience across a variety of languages and geographies.  For more information
* on localizing your application, please refer to the BlackBerry Java Development
* Environment Development Guide associated with this release.
*/

package com.rim.samples.device.openglspritegamedemo;

import java.io.IOException;
import java.io.InputStream;
import java.util.Vector;

import javax.microedition.khronos.opengles.GL11;

import net.rim.device.api.animation.Animation;
import net.rim.device.api.animation.Animator;
import net.rim.device.api.math.BoundingBox;
import net.rim.device.api.math.BoundingSphere;
import net.rim.device.api.math.Bounds;
import net.rim.device.api.math.Matrix4f;
import net.rim.device.api.math.Transform3D;
import net.rim.device.api.math.Vector3f;
import net.rim.device.api.opengles.GL20;
import net.rim.device.api.system.Application;
import net.rim.device.api.xml.parsers.ParserConfigurationException;
import net.rim.device.api.xml.parsers.SAXParser;
import net.rim.device.api.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
* Represents the current level in the game. This class is responsible for
* initializing, rendering, and updating the different game objects such as the
* enemies, tiles, character, etc. There is also logic for collision detection.
*/
public class SpriteGameLevel {
    /** Represents the margin of error allowed during collision detection */
    private static final float EPSILON = 0.0005f;

    /** Holds the LOSE state of the level */
    public static final int LEVEL_LOSE = -1;

    /** Holds the ACTIVE state of the level */
    public static final int LEVEL_ACTIVE = 0;

    /** Holds the WIN state of the level */
    public static final int LEVEL_WIN = 1;

    /** Holds the level's end object */
    private Sprite _levelGoal = null;

    /** Holds the level's blocks */
    private final Vector _tiles = new Vector();

    /** Holds the level's obstacles */
    private final Vector _enemies = new Vector();

    /** Holds the hero's translation during render */
    private final Vector3f _t = new Vector3f();

    /** Hold's the level's good guy character */
    private SpriteGameCharacter _character;

    /** A flag indicating if the level has been initialized */
    private boolean _isLevelInitialized = false;

    /** A flag indicating if the level has been loaded */
    private boolean _isLevelLoaded = false;

    /** Holds the level width */
    private float _levelWidth = 0;

    /** Holds the level height */
    private float _levelHeight;

    /**
     * Creates a new SpriteGameLevel object
     *
     * @param levelPath
     *            The path where the level file is located
     * @param animator
     *            The animator that will be used for the level's animations
     */
    public SpriteGameLevel(final String levelPath, final Animator animator) {
        loadLevel(levelPath, animator);
    }

    /**
     * Initializes the game level
     *
     * @param gl
     *            The OpenGL v1.1 object that will be used to render graphics on
     *            the display
     */
    public void initialize(final GL11 gl) {
        Sprite.Batch.clearBatch(gl);

        // Initialize all the tiles in the level
        int count = _tiles.size();
        Sprite tile;

        for (int i = 0; i < count; i++) {
            tile = (Sprite) _tiles.elementAt(i);
            tile.initialize(gl);
            tile.setIsBatched(gl, true);
        }

        // Initialize all the enemies in the level
        count = _enemies.size();

        for (int i = 0; i < count; i++) {
            ((Sprite) _enemies.elementAt(i)).initialize(gl);
        }

        // Initialize the level goal and the character
        _levelGoal.initialize(gl);
        _character.initialize(gl);
        _isLevelInitialized = true;
    }

    /**
     * Initializes the game level
     *
     * @param gl
     *            The OpenGL v2.0 object that will be used to render graphics on
     *            the display
     */
    public void initialize(final GL20 gl) {
        Sprite.Batch.clearBatch(gl);

        // Initialize all the tiles in the level
        int count = _tiles.size();
        Sprite tile;

        for (int i = 0; i < count; i++) {
            tile = (Sprite) _tiles.elementAt(i);
            tile.initialize(gl);
            tile.setIsBatched(gl, true);
        }

        // Initialize all the enemies in the level
        count = _enemies.size();

        for (int i = 0; i < count; i++) {
            ((Sprite) _enemies.elementAt(i)).initialize(gl);
        }

        // Initialize the level goal and the character
        _levelGoal.initialize(gl);
        _character.initialize(gl);
        _isLevelInitialized = true;
    }

    /**
     * Updates the level
     *
     * @return LEVEL_LOSE if the character died; LEVEL_WIN if the character
     *         reached the level goal; LEVEL_ACTIVE if the level is still in
     *         play.
     */
    public int update() {
        // Update the obstacle animations
        _character.update();

        // Calculate the character's movement restrictions and whether
        // the level has been lost or won using collision detection.
        return detectCollisions();
    }

    /**
     * Renders the level using OpenGL v1.1
     *
     * @param gl
     *            The reference to the OpenGL v1.1 object.
     */
    public void render(final GL11 gl) {
        // Save current matrix.
        gl.glPushMatrix();

        // Load the identity matrix
        gl.glLoadIdentity();

        _character._transform.getTranslation(_t);

        // Determine which horizontal section of the level to render
        if (_t.x > 0.0f) {
            gl.glTranslatef(-_t.x, 0.0f, 0.0f);
        }

        // Determine which vertical section of the level to render
        if (_t.y > 0.0f && _t.y <= _levelHeight) {
            gl.glTranslatef(0.0f, -_t.y, 0.0f);
        } else if (_t.y > _levelHeight) {
            gl.glTranslatef(0.0f, -_levelHeight, 0.0f);
        }

        // Render the level's tiles
        int count = _tiles.size();
        for (int i = 0; i < count; i++) {
            ((Sprite) _tiles.elementAt(i)).render(gl);
        }

        // Render the level's enemies
        count = _enemies.size();
        for (int i = 0; i < count; i++) {
            ((Sprite) _enemies.elementAt(i)).render(gl);
        }

        // Render the level's goal and the character
        _levelGoal.render(gl);
        _character.render(gl);
        gl.glPopMatrix();
    }

    /**
     * Renders the level using OpenGl v2.0
     *
     * @param gl
     *            The reference to the OpenGL v2.0 object
     */
    public void render(final GL20 gl, final Matrix4f modelview) {
        final Matrix4f m = new Matrix4f(modelview);
        _character._transform.getTranslation(_t);

        // Determine which horizontal section of the level to render
        if (_t.x > 0.0f) {
            m.translate(-_t.x, 0.0f, 0.0f);
        }

        // Determine which vertical section of the level to render
        if (_t.y > 0.0f && _t.y <= _levelHeight) {
            m.translate(0.0f, -_t.y, 0.0f);
        } else if (_t.y > _levelHeight) {
            m.translate(0.0f, -_levelHeight, 0.0f);
        }

        // Render the level's tiles
        int count = _tiles.size();
        for (int i = 0; i < count; i++) {
            ((Sprite) _tiles.elementAt(i)).render(gl, m);
        }

        // Render the level's enemies
        count = _enemies.size();
        for (int i = 0; i < count; i++) {
            ((Sprite) _enemies.elementAt(i)).render(gl, m);
        }

        // Render the level's goal and the character
        _levelGoal.render(gl, m);
        _character.render(gl, m);
    }

    /**
     * Retrieves the current loaded state
     *
     * @return True if the level is loaded; false if the level isn't loaded
     */
    public boolean isLevelLoaded() {
        return _isLevelLoaded;
    }

    /**
     * Retrieves if the level is initialized or not
     *
     * @return True if the level is initialized; false if the level isn't
     *         initialized
     */
    public boolean isLevelInitialized() {
        return _isLevelInitialized;
    }

    /**
     * Retrieves the level's character object
     *
     * @return The level's character object
     */
    public SpriteGameCharacter getCharacter() {
        return _character;
    }

    /**
     * Detects collisions and whether the level has been won or lost
     *
     * @return 0 if the level is still active, -1 if the level has been lost and
     *         1 if the level has been won.
     */
    private int detectCollisions() {
        Bounds boundsLevel;

        final BoundingBox bounds = (BoundingBox) _character.getBounds();
        final BoundingBox prevBounds = (BoundingBox) _character.getPrevBounds();

        // Get the character's corners
        final Vector3f[] corners = new Vector3f[8];

        for (int i = 0; i < corners.length; i++) {
            corners[i] = new Vector3f();
        }
        bounds.getCorners(corners, 0);

        final float charTop = corners[0].y;
        final float charBottom = corners[1].y;
        final float charLeft = corners[0].x;
        final float charRight = corners[2].x;

        prevBounds.getCorners(corners, 0);
        final float prevCharTop = corners[0].y;
        final float prevCharBottom = corners[1].y;
        final float prevCharLeft = corners[0].x;
        final float prevCharRight = corners[2].x;

        final Vector3f characterCenter =
                new Vector3f((charLeft + charRight) / 2.0f,
                        (charTop + charBottom) / 2.0f, 0.0f);

        // Die if you fell off the level
        if (characterCenter.y < -20.0f) {
            return -1;
        }

        // Detect collision with the level end object
        boundsLevel = _levelGoal.getBounds();
        if (bounds.intersects(boundsLevel)) {
            _character.addMovementRestriction(SpriteGameCharacter.MOVE_DOWN
                    | SpriteGameCharacter.MOVE_UP
                    | SpriteGameCharacter.MOVE_LEFT
                    | SpriteGameCharacter.MOVE_RIGHT);
            return 1;
        }

        // Detect collisions with obstacles
        int count = _enemies.size();

        for (int i = 0; i < count; i++) {
            boundsLevel = ((Sprite) _enemies.elementAt(i)).getBounds();
            if (bounds.intersects(boundsLevel)) {
                _character.addMovementRestriction(SpriteGameCharacter.MOVE_DOWN
                        | SpriteGameCharacter.MOVE_UP
                        | SpriteGameCharacter.MOVE_LEFT
                        | SpriteGameCharacter.MOVE_RIGHT);
                return -1;
            }
        }

        _character.clearMovementRestrictions();

        // Detect collisions with blocks and calculate the character's movement
        // restrictions
        BoundingBox tileBounds;
        count = _tiles.size();
        Sprite tile;

        for (int i = 0; i < count; i++) {
            tile = (Sprite) _tiles.elementAt(i);
            tileBounds = (BoundingBox) tile.getBounds();
            if (bounds.intersects(tileBounds)) {
                // Calculate the center point of the block's bounding box
                final Vector3f min = new Vector3f();
                final Vector3f max = new Vector3f();
                tileBounds.getMin(min);
                tileBounds.getMax(max);
                final Vector3f blockCenter = new Vector3f(min);
                blockCenter.add(max);
                blockCenter.scale(0.5f);

                // Get character scale
                final Vector3f s = new Vector3f();
                _character._transform.getScale(s);

                // Determine which way(s) the character's
                // movement should be restricted. We also set the character's
                // translation vector
                // so that it does not visibly intersect the blocks.
                final float tileTop = max.y;
                final float tileBottom = min.y;
                final float tileLeft = min.x;
                final float tileRight = max.x;

                final float tileMidX = (tileLeft + tileRight) / 2.0f;
                final float tileMidY = (tileBottom + tileTop) / 2.0f;

                final Vector3f v = new Vector3f();

                // If character's top or bottom is between tile's
                // top and bottom, restrict horizontally
                if (charTop < tileTop - 0.1f && charTop > tileBottom + 0.1f
                        || charBottom > tileBottom + 0.1f
                        && charBottom < tileTop - 0.1f) {
                    // If left edge of character is against right
                    // edge of block, cannot move left.
                    if (prevCharLeft > tileRight - 0.1f && charLeft < tileRight
                            && charLeft > tileMidX) {
                        _character._transform.getTranslation(v);
                        v.x = tileRight + s.x - EPSILON;
                        _character._transform.setTranslation(v);
                        _character
                                .addMovementRestriction(SpriteGameCharacter.MOVE_LEFT);
                    }

                    // Right edge of character is against left
                    // edge of block -> cannot move right.
                    if (prevCharRight < tileLeft + 0.1f && charRight > tileLeft
                            && charRight < tileMidX) {
                        _character._transform.getTranslation(v);
                        v.x = tileLeft - s.x + EPSILON;
                        _character._transform.setTranslation(v);
                        _character
                                .addMovementRestriction(SpriteGameCharacter.MOVE_RIGHT);
                    }
                }

                // If character's left or right edge is between tile's left
                // and right edges, restrict vertically.
                if (charLeft > tileLeft + 0.1f && charLeft < tileRight - 0.1f
                        || charRight < tileRight - 0.1f
                        && charRight > tileLeft + 0.1f) {
                    // Bottom edge of character is against top
                    // edge of block -> cannot move down.
                    if (prevCharBottom > tileTop - 0.1f && charBottom < tileTop
                            && charBottom > tileMidY) {
                        _character._transform.getTranslation(v);
                        v.y = tileTop + s.y - EPSILON;
                        _character._transform.setTranslation(v);
                        _character.setTy(v.y);
                        _character
                                .addMovementRestriction(SpriteGameCharacter.MOVE_DOWN);
                    }

                    // Top edge of character is against bottom
                    // edge of block -> cannot move up.
                    if (prevCharTop < tileBottom + 0.1f && charTop > tileBottom
                            && charTop < tileMidY) {
                        _character._transform.getTranslation(v);
                        v.y = tileBottom - s.y + EPSILON;
                        _character._transform.setTranslation(v);
                        _character
                                .addMovementRestriction(SpriteGameCharacter.MOVE_UP);
                    }
                }
            }
        }

        return 0;
    }

    /**
     * Loads from the given material XML file into the given model's material
     *
     * @param levelPath
     *            Path to the material file
     * @param animator
     *            The animator that the material can use
     */
    public void loadLevel(final String levelPath, final Animator animator) {
        try {
            _levelWidth = 0.0f;
            _levelHeight = 0.0f;

            _tiles.removeAllElements();
            _enemies.removeAllElements();

            // Set up the SAXParser that will parse the XML file
            final SAXParser parser =
                    SAXParserFactory.newInstance().newSAXParser();
            InputStream stream;
            stream =
                    Application.getApplication().getClass()
                            .getResourceAsStream(levelPath);
            final DefaultHandler dh = new LevelSaxHandler(animator);
            parser.parse(stream, dh);
        } catch (final ParserConfigurationException e) {
            SpriteGame.errorDialog(e.toString());
        } catch (final SAXException e) {
            SpriteGame.errorDialog(e.toString());
        } catch (final IOException e) {
            SpriteGame.errorDialog(e.toString());
        }
    }

    /**
     * This class parses the level file and creates the different level objects
     * (tile, enemy, character, etc) with their specific attributes.
     */
    private class LevelSaxHandler extends DefaultHandler {
        private static final String ANIMATION = "animation";
        private static final String CURVE = "curve";
        private static final String DURATION = "duration";
        private static final String ENEMY = "enemy";
        private static final String FRAMES = "frames";
        private static final String GOAL = "goal";
        private static final String CHARACTER = "character";
        private static final String LEVEL = "level";
        private static final String LINEAR = "linear";
        private static final String POSITION = "position";
        private static final String REPEAT = "repeat";
        private static final String ROTATE = "rotate";
        private static final String SCALE = "scale";
        private static final String TEXTURE = "texture";
        private static final String TILE = "tile";
        private static final String TIMES = "times";
        private static final String TRANSLATE = "translate";
        private static final String TYPE = "type";
        private static final String VALUES = "values";

        private int _enemyCount = 0;

        private final Animator _animator;

        /**
         * Creates a new LevelSaxHandler object
         *
         * @param animator
         *            The animator that the different level entities can use
         */
        public LevelSaxHandler(final Animator animator) {
            _animator = animator;
        }

        /**
         * @see org.xml.sax.helpers.DefaultHandler#startElement(String, String,
         *      String, Attributes)
         */
        public void startElement(final String uri, final String localName,
                final String qName, final Attributes attributes)
                throws SAXException {
            // Determine what kind of level object we are about to parse
            if (qName.equalsIgnoreCase(TILE)) {
                parseTile(attributes);
            } else if (qName.equalsIgnoreCase(ENEMY)) {
                parseEnemy(attributes);
            } else if (qName.equalsIgnoreCase(CHARACTER)) {
                parseHero(attributes);
            } else if (qName.equalsIgnoreCase(GOAL)) {
                parseLevelGoal(attributes);
            } else if (qName.equalsIgnoreCase(ANIMATION)) {
                parseAnimation(attributes);
            }
        }

        /**
         * @see org.xml.sax.helpers.DefaultHandler#endElement(String, String,
         *      String)
         */
        public void endElement(final String uri, final String localName,
                final String qName) {
            // Check if we made it to the end of the file
            if (qName.equalsIgnoreCase(LEVEL)) {
                _isLevelLoaded = true;
                _levelWidth += 1.0f;
                _levelHeight += 1.0f;
            } else if (qName.equalsIgnoreCase(ENEMY)) {
                // We've gone to the next obstacle
                _enemyCount++;
            }
        }

        /**
         * Parses data from the level load file to create a row of game tiles
         *
         * @param attributes
         *            The attributes of the tile
         */
        private void parseTile(final Attributes attributes) {
            final float[] pos = new float[2];
            parseString(attributes.getValue(POSITION), ',', pos, 0);
            final String texture = attributes.getValue(TEXTURE);
            final int repeat = Integer.parseInt(attributes.getValue(REPEAT));
            final String scaleStr = attributes.getValue(SCALE);
            float scale = 1.0f;

            // Check the tiles scale
            if (scaleStr != null) {
                scale = Float.parseFloat(scaleStr);
            }

            // Potentially increase the width of the level
            if (pos[0] + repeat > _levelWidth) {
                _levelWidth = pos[0] + repeat;
            }

            // Potentially increase the height of the level
            if (pos[1] > _levelHeight) {
                _levelHeight = pos[1];
            }

            // Add tiles for the amount of times that the tile should be
            // repeated
            for (int i = 0; i < repeat; i++) {
                final Sprite tile =
                        new Sprite(texture, new Vector3f(-11.0f + (pos[0] + i)
                                * 2.0f, -11.0f + pos[1] * 2.0f, 0.0f));
                tile._transform.scale(scale);
                _tiles.addElement(tile);
            }
        }

        /**
         * Parses the data from the level load file to create an enemy
         *
         * @param attributes
         *            The attributes of the enemy
         */
        private void parseEnemy(final Attributes attributes) {
            final float[] pos = new float[2];
            parseString(attributes.getValue(POSITION), ',', pos, 0);
            final String texture = attributes.getValue(TEXTURE);
            final String scaleStr = attributes.getValue(SCALE);
            float scale = 1.0f;

            // Check the enemy's scale
            if (scaleStr != null) {
                scale = Float.parseFloat(scaleStr);
            }

            // Create the enemy
            Sprite enemy;
            Bounds bounds = null;

            if (texture.equals("obstacle_ball.png")) {
                bounds =
                        new BoundingBox(new Vector3f(-0.9f, -0.9f, 0.0f),
                                new Vector3f(0.9f, 0.9f, 0.0f));
            } else if (texture.equals("obstacle_spikewheel.png")) {
                bounds = new BoundingSphere(new Vector3f(), 0.75f);
            }

            enemy =
                    new Sprite(texture, bounds, new Vector3f(-11.0f + pos[0]
                            * 2.0f, -11.0f + pos[1] * 2.0f, 0.0f));
            enemy._transform.scale(scale);
            _enemies.addElement(enemy);
        }

        /**
         * Parses the data form the level load file to create the character
         *
         * @param attributes
         *            The attributes of the character
         */
        private void parseHero(final Attributes attributes) {
            final float[] pos = new float[2];
            parseString(attributes.getValue(POSITION), ',', pos, 0);
            final String texture = attributes.getValue(TEXTURE);
            final String scaleStr = attributes.getValue(SCALE);
            float scale = 1.0f;

            // Check the character's scale
            if (scaleStr != null) {
                scale = Float.parseFloat(scaleStr);
            }

            // Create the character
            _character =
                    new SpriteGameCharacter(texture, _animator, new Vector3f(
                            -11.0f + pos[0] * 2.0f, -11.0f + pos[1] * 2.0f,
                            0.0f));
            _character._transform.scale(scale);
        }

        /**
         * Parses the data from the load level file to create the level's goal
         *
         * @param attributes
         *            The attributes of the level goal
         */
        private void parseLevelGoal(final Attributes attributes) {
            final float[] pos = new float[2];
            parseString(attributes.getValue(POSITION), ',', pos, 0);
            final String texture = attributes.getValue(TEXTURE);
            final String scaleStr = attributes.getValue(SCALE);
            float scale = 1.0f;

            // Check the goal's scale
            if (scaleStr != null) {
                scale = Float.parseFloat(scaleStr);
            }

            // Create the level goal object
            _levelGoal =
                    new Sprite(texture, new Vector3f(-11.0f + pos[0] * 2.0f,
                            -11.0f + pos[1] * 2.0f, 0.0f));
            _levelGoal._transform.scale(scale);
        }

        /**
         * Parses the data from the level load file to create an animation
         *
         * @param attributes
         *            The attributes of the animation
         */
        private void parseAnimation(final Attributes attributes) {
            final Sprite enemy = (Sprite) _enemies.elementAt(_enemyCount);

            // Get the number of key frames and the key times
            final int keyframes = Integer.parseInt(attributes.getValue(FRAMES));
            final float[] keyTimes = new float[keyframes];
            parseString(attributes.getValue(TIMES), ';', keyTimes, 0);

            // Get the duration of the animation
            final long duration = Long.parseLong(attributes.getValue(DURATION));

            // Default to linear
            int curve = Animation.EASINGCURVE_LINEAR;

            if (attributes.getValue(CURVE).equalsIgnoreCase(LINEAR)) {
                curve = Animation.EASINGCURVE_LINEAR;
            }

            Animation animation = null;

            // Check if the animation is a TRANSLATE
            if (attributes.getValue(TYPE).equalsIgnoreCase(TRANSLATE)) {
                animation =
                        parseTranslationAnimation(enemy, keyframes, keyTimes,
                                duration, curve, attributes);
            }

            // Check if the animation is a ROTATE
            else if (attributes.getValue(TYPE).equalsIgnoreCase(ROTATE)) {
                animation =
                        parseRotationAnimation(enemy, keyframes, keyTimes,
                                duration, curve, attributes);
            }

            // Check if the animation is a SCALE
            else if (attributes.getValue(TYPE).equalsIgnoreCase(SCALE)) {
                animation =
                        parseScaleAnimation(enemy, keyframes, keyTimes,
                                duration, curve, attributes);
            }

            // Add the animation to the enemy
            if (animation != null) {
                enemy.addAnimation(animation);

                final int repeatCount =
                        Integer.parseInt(attributes.getValue(REPEAT));
                if (repeatCount == -1) {
                    animation.setRepeatCount(Animation.REPEAT_COUNT_INDEFINITE);
                } else {
                    animation.setRepeatCount(repeatCount);
                }
            }
        }

        /**
         * Parses a translation animation
         *
         * @param enemy
         *            Enemy to add the animation to
         * @param keyframes
         *            The animations key frames
         * @param keyTimes
         *            The animations key times
         * @param duration
         *            The duration of the animation
         * @param curve
         *            The curve at which the animation will travel
         * @param attributes
         *            The attributes of the animation
         * @return True if adding the animation was a success; false if adding
         *         the animation failed
         */
        private Animation parseTranslationAnimation(final Sprite enemy,
                final int keyframes, final float[] keyTimes,
                final long duration, final int curve,
                final Attributes attributes) {
            final Vector3f t = new Vector3f();
            enemy._transform.getTranslation(t);

            // Get the key values
            final String[] strs = parseString(attributes.getValue(VALUES), ';');

            // Get key values out as floats
            final float[] values = new float[keyframes * 3];

            for (int i = 0; i < keyframes; i++) {
                // Parse the string
                parseString(strs[i], ',', values, i * 3);

                // Convert the coords
                values[i * 3] = values[i * 3] * 2 + t.x;
                values[i * 3 + 1] = values[i * 3 + 1] * 2 + t.y;
                values[i * 3 + 2] = t.z;
            }

            // Create the animation
            return _animator.addAnimation(enemy._transform,
                    Transform3D.ANIMATION_PROPERTY_TRANSLATE, keyframes,
                    keyTimes, 0, values, 0, curve, duration);

        }

        /**
         * Parses a rotation animation
         *
         * @param enemy
         *            Enemy to add the animation to
         * @param keyframes
         *            The animations key frames
         * @param keyTimes
         *            The animations key times
         * @param duration
         *            The duration of the animation
         * @param curve
         *            The curve at which the animation will travel
         * @param attributes
         *            The attributes of the animation
         * @return True if adding the animation was a success; false if adding
         *         the animation failed
         */
        private Animation parseRotationAnimation(final Sprite enemy,
                final int keyframes, final float[] keyTimes,
                final long duration, final int curve,
                final Attributes attributes) {
            final float[] values = new float[keyframes];

            // Get the key values
            parseString(attributes.getValue(VALUES), ';', values, 0);

            final int size = keyframes * 4;

            // Get the key values out as floats
            final float[] keyValues = new float[size];
            int j = 0;

            // Convert the degrees into radians
            for (int i = 0; i < size; i++) {
                if (i % 4 == 3) {
                    keyValues[i] = (float) (values[j++] * 180 / Math.PI);
                } else if (i % 4 == 2) {
                    keyValues[i] = 1.0f;
                } else {
                    keyValues[i] = 0.0f;
                }
            }

            // Create the animation
            return _animator.addAnimation(enemy._transform,
                    Transform3D.ANIMATION_PROPERTY_ROTATE, keyframes, keyTimes,
                    0, keyValues, 0, curve, duration);
        }

        /**
         * Parses a scale animation
         *
         * @param enemy
         *            Enemy to add the animation to
         * @param keyframes
         *            The animations key frames
         * @param keyTimes
         *            The animations key times
         * @param duration
         *            The duration of the animation
         * @param curve
         *            The curve at which the animation will travel
         * @param attributes
         *            The attributes of the animation
         * @return True if adding the animation was a success; false if adding
         *         the animation failed
         */
        private Animation parseScaleAnimation(final Sprite enemy,
                final int keyframes, final float[] keyTimes,
                final long duration, final int curve,
                final Attributes attributes) {
            final float[] values = new float[keyframes];

            // Get the key values
            parseString(attributes.getValue(VALUES), ';', values, 0);

            final int size = keyframes * 3;

            // Get the key values out as floats
            final float[] keyvalues = new float[size];
            int j = 0;

            for (int i = 0; i < size; i++) {
                if (i % 3 == 2) {
                    keyvalues[i] = 1.0f;
                    j++;
                } else {
                    keyvalues[i] = values[j];
                }
            }

            return _animator.addAnimation(enemy._transform,
                    Transform3D.ANIMATION_PROPERTY_SCALE, keyframes, keyTimes,
                    0, keyvalues, 0, curve, duration);
        }

        /**
         * Parses a string
         *
         * @param src
         *            The source string
         * @param delim
         *            The string delimiter
         * @return The string tokens
         */
        private String[] parseString(final String src, final char delim) {
            return explode(src, delim);
        }

        /**
         * Parses a string
         *
         * @param src
         *            The source string
         * @param delim
         *            The string delimiter
         * @param dst
         *            The destination string
         * @param index
         *            The position in the destination string to start butting
         *            the string tokens
         */
        private void parseString(final String src, final char delim,
                final float[] dst, final int index) {
            final String[] tokens = explode(src, delim);
            final int count = tokens.length;

            for (int i = 0; i < count; i++) {
                dst[i + index] = Float.parseFloat(tokens[i]);
            }
        }
    }

    /**
     * Breaks the source string up into the different .tokens based on the
     * delimiter
     *
     * @param src
     *            The source string
     * @param delim
     *            The delimiter to use
     * @return A string array containing the string tokens
     */
    private static String[] explode(final String src, final char delim) {
        // Determine the number of tokens
        int count = 1;
        for (int i = 0, length = src.length(); i < length; i++) {
            if (src.charAt(i) == delim) {
                ++count;
            }
        }
        final String[] array = new String[count];

        // Fill the string array with the tokens that
        // are separated by the delimiter.
        for (int arrayIndex = 0, strIndex = 0; arrayIndex < array.length
                && strIndex < src.length(); arrayIndex++) {
            final int nextDelimIndex = src.indexOf(delim, strIndex);

            if (nextDelimIndex < 0) {
                array[arrayIndex] = src.substring(strIndex);
            } else {
                array[arrayIndex] = src.substring(strIndex, nextDelimIndex);
                strIndex = nextDelimIndex + 1;
            }
        }
        return array;
    }
}
TOP

Related Classes of com.rim.samples.device.openglspritegamedemo.SpriteGameLevel$LevelSaxHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.