Android Open Source - Droid-Maze Maze Shape






From Project

Back to project page Droid-Maze.

License

The source code is released under:

Apache License

If you think the Android project Droid-Maze listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/**
 * Copyright 2011 Massimo Gaddini/*from   www. j a  v  a 2 s.  c  o m*/
 * 
 * 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.  
 */
package com.sgxmobileapps.droidmaze.ui.shape;

import android.content.Context;
import android.hardware.SensorManager;
import android.os.AsyncTask;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.sgxmobileapps.droidmaze.maze.generator.MazeCell;
import com.sgxmobileapps.droidmaze.maze.generator.MazeGenerator;

import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.handler.IUpdateHandler;
import org.anddev.andengine.entity.primitive.Rectangle;
import org.anddev.andengine.entity.shape.Shape;
import org.anddev.andengine.entity.sprite.Sprite;
import org.anddev.andengine.extension.physics.box2d.PhysicsConnector;
import org.anddev.andengine.extension.physics.box2d.PhysicsFactory;
import org.anddev.andengine.extension.physics.box2d.PhysicsWorld;
import org.anddev.andengine.extension.physics.box2d.util.Vector2Pool;
import org.anddev.andengine.opengl.font.FontManager;
import org.anddev.andengine.opengl.texture.TextureManager;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.sensor.accelerometer.AccelerometerData;
import org.anddev.andengine.sensor.accelerometer.IAccelerometerListener;
import org.anddev.andengine.util.Callback;
import org.anddev.andengine.util.Debug;




/**
 * This class hide the generating and drawing of the maze. 
 * A maze is a grid of cells where each cell has one or more side carved.
 * 
 * @author Massimo Gaddini
 *
 */
public class MazeShape extends Rectangle implements ComplexShape, IAccelerometerListener {

    
    /**
     * Maze wall width in pixel
     */
    private static final int WALL_WIDTH = 2;
    
    
    /**
     * Maze generator
     */
    private MazeGenerator mMazeGenerator;
    

    /**
     * The maze grid
     */
    private MazeCell[][] mMazeGrid;
    
    /**
     * Maze width
     */
    private int mMazeWidth = 0;
    
    /**
     * Maze height
     */
    private int mMazeHeight = 0;
    
    /**
     * Horizontal cell size
     */
    private float mStepX;
    
    /**
     * Vertical cell size
     */
    private float mStepY;
    
    /**
     * The marker's texture
     */
    private TextureRegion mMarkerTexture;
    
    /**
     * The target's texture
     */
    private TextureRegion mTargetTexture;
    
    /**
     * The target's sprite
     */
    private Sprite mTargetSprite;
    
    /**
     * The marker's sprite
     */
    private Sprite mMarkerSprite;
    
    /**
     * The context
     */
    private Context mCtx;
    
    /**
     * The physics world used for move marker
     */
    private PhysicsWorld mPhysicsWorld;
    
    /**
     * The AndEngine engine
     */
    private Engine mEngine;

    /**
     * The update handler for the shape
     */
    IUpdateHandler mUpdateHandler;
    
    /**
     * Constructs MazeShape object.
     * 
     * @param pX  X left top corner
     * @param pY  Y left top corner
     * @param width width of the shape
     * @param height height of the shape
     * @param mazeHeight maze height expressed in number of cell
     * @param mazeWidth maze width expressed in number of cell
     * @param generator maze generator instance to be used for generate maze
     * @param ctx the context
     */
    public MazeShape(float pX, float pY, float width, float height, 
                    int mazeHeight, int mazeWidth, MazeGenerator generator, Context ctx) {
        super(pX, pY, width, height);
        
        Debug.setDebugTag("MazeShape");
        
        mMazeHeight = mazeHeight;
        mMazeWidth = mazeWidth;
        mMazeGenerator = generator;
        mCtx = ctx;
    }
   
    /* (non-Javadoc)
     * @see com.sgxmobileapps.droidmaze.ui.shape.ComplexShape#loadResources(org.anddev.andengine.opengl.texture.TextureManager, org.anddev.andengine.opengl.font.FontManager, android.content.Context)
     */
    public void loadResources(TextureManager textureManager, FontManager fontManager, Context ctx) {
        /* Texture */
        BitmapTextureAtlas textureMarker = new BitmapTextureAtlas(32, 32, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
        BitmapTextureAtlas textureTarget = new BitmapTextureAtlas(32, 32, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
        
        /* TextureRegion */
        mMarkerTexture = BitmapTextureAtlasTextureRegionFactory.createFromAsset(textureMarker, ctx, "gfx/ball.png", 0, 0); // 32x32
        mTargetTexture = BitmapTextureAtlasTextureRegionFactory.createFromAsset(textureTarget, ctx, "gfx/target_hole.png", 0, 0); // 32x32
        
        textureManager.loadTextures(textureMarker, textureTarget);
    }
    
    /* (non-Javadoc)
     * @see com.sgxmobileapps.droidmaze.ui.shape.ComplexShape#init(boolean, org.anddev.andengine.util.Callback, org.anddev.andengine.util.Callback, android.content.Context)
     */
    public void init(boolean visible, final Callback<Boolean> callback, final Callback<Exception> exceptionCallback, Context ctx) {
        setVisible(visible);
        
        mPhysicsWorld = new PhysicsWorld(new Vector2(0, SensorManager.GRAVITY_EARTH), false);
        
        new AsyncTask<Void, Void, Boolean>() {
            private Exception mException = null;

            @Override
            public void onPreExecute() {
                super.onPreExecute();
            }

            @Override
            public Boolean doInBackground(final Void... params) {
                Boolean result = true;
                try {
                    mMazeGrid = mMazeGenerator.generate(mMazeHeight, mMazeWidth);
                    Debug.i("Maze generation completed");
                } catch (final Exception e) {
                    mException = e;
                    result = false;
                }
                return result;
            }

            @Override
            public void onPostExecute(final Boolean result) {
                if (mException == null) {
                    try {
                        Debug.i("Maze drawing start");
                        drawMaze();
                        Debug.i("Maze drawing finish. Add marker");
                        addMarker();
                        Debug.i("Add marker finish. Add target");
                        addTarget();
                        Debug.i("Add target finish");
                        
                        callback.onCallback(result);
                    } catch(Exception e){
                        mException = e;
                    }    
                } 
                
                if (mException != null) {
                    if(exceptionCallback == null) {
                        Debug.e("Error", mException);
                    } else {
                        exceptionCallback.onCallback(mException);
                    }
                }
                
                super.onPostExecute(result);
            }
        }.execute((Void[]) null);
    }

    /* (non-Javadoc)
     * @see com.sgxmobileapps.droidmaze.ui.shape.ComplexShape#enable(org.anddev.andengine.engine.Engine)
     */
    public void enable(Engine engine) {
        setVisible(true);
        
        mEngine = engine;
        
        engine.enableAccelerometerSensor(mCtx, this);
        engine.registerUpdateHandler(mPhysicsWorld);
    }
    
    /* (non-Javadoc)
     * @see com.sgxmobileapps.droidmaze.ui.shape.ComplexShape#disable(org.anddev.andengine.engine.Engine)
     */
    public void disable(Engine engine) {
        engine.disableAccelerometerSensor(mCtx);
        engine.unregisterUpdateHandler(mPhysicsWorld);
        if (mUpdateHandler != null) {
            unregisterUpdateHandler(mUpdateHandler);
        }
    }
    
    public void setSolvedCallback(final Callback<Void> callback){
        
        mUpdateHandler = new IUpdateHandler() {
            
            private boolean mSolved = false;
            
            @Override
            public void reset() { }

            @Override
            public void onUpdate(final float pSecondsElapsed) {
                if(mMarkerSprite.collidesWith(mTargetSprite) && (!mSolved)) {
                    mSolved = true;
                    Debug.i("Collision !!! Maze solved!");  
                    callback.onCallback(null);
                }
            }
        };
        
        registerUpdateHandler(mUpdateHandler);
    }

    /* (non-Javadoc)
     * @see org.anddev.andengine.sensor.accelerometer.IAccelerometerListener#onAccelerometerChanged(org.anddev.andengine.sensor.accelerometer.AccelerometerData)
     */
    public void onAccelerometerChanged(AccelerometerData pAccelerometerData) {
        //mPhysicsWorld.setGravity(new Vector2(-pAccelerometerData.getX(), pAccelerometerData.getY()));
        
        Vector2 gravity = Vector2Pool.obtain(pAccelerometerData.getX(), pAccelerometerData.getY());
        mPhysicsWorld.setGravity(gravity);
        Vector2Pool.recycle(gravity);
    }

    protected void addMarker() {
        float scaleXY = getMaxMarkerDim() * 0.8f / mMarkerTexture.getWidth();

        if (scaleXY > 1) {
            scaleXY = 1;
        }

        mMarkerSprite = new Sprite(0, 0, 
                mMarkerTexture.getWidth() * scaleXY, 
                mMarkerTexture.getHeight() * scaleXY, 
                mMarkerTexture);

        mMarkerSprite.setPosition(getMarkerStartPositionX(), getMarkerStartPositionY());

        FixtureDef markerFixtureDef = PhysicsFactory.createFixtureDef(1, 0, 0);
        Body body = PhysicsFactory.createCircleBody(mPhysicsWorld, mMarkerSprite,
                BodyType.DynamicBody, markerFixtureDef);

        attachChild(mMarkerSprite);
        mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(mMarkerSprite, body, true, true));
    }
    
    protected void addTarget() {
        float scaleXY = getMaxMarkerDim() * 0.8f / mTargetTexture.getWidth();

        if (scaleXY > 1) {
            scaleXY = 1;
        }

        mTargetSprite = new Sprite(0, 0, 
                mTargetTexture.getWidth() * scaleXY, 
                mTargetTexture.getHeight() * scaleXY, 
                mTargetTexture);

        mTargetSprite.setPosition(getTargetPositionX(), getTargetPositionY());

        FixtureDef targetFixtureDef = PhysicsFactory.createFixtureDef(1, 0, 0);
        Body body = PhysicsFactory.createCircleBody(mPhysicsWorld, mTargetSprite,
                BodyType.StaticBody, targetFixtureDef);

        attachChild(mTargetSprite);
        mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(mTargetSprite, body, true, true));
    }

    protected void drawMaze() {
        mStepX = ( getWidthScaled() - ( mMazeWidth * WALL_WIDTH ) - WALL_WIDTH ) / (float) mMazeWidth;
        mStepY = ( getHeightScaled() - ( mMazeHeight * WALL_WIDTH ) - WALL_WIDTH ) / (float) mMazeHeight;

        FixtureDef wallFixtureDef = PhysicsFactory.createFixtureDef(1, 0.2f, 0);

        int start = -1;
        int end = -1;
        for (int i = 0; i < ( mMazeHeight - 1 ); i++) {

            start = end = -1;
            for (int j = 0; j < mMazeWidth; j++) {
                if (!mMazeGrid[i][j].isSouthWallClosed()) {
                    if (start >= 0) {
                        end = j;
                        
                        Shape wallH = new Rectangle(( ( start == 0 ) ? WALL_WIDTH : 0 ) + start
                                * ( mStepX + WALL_WIDTH ), ( i + 1 ) * ( mStepY + WALL_WIDTH ),
                                ( end - start ) * ( mStepX + WALL_WIDTH )
                                        + ( ( start == 0 ) ? 0 : WALL_WIDTH ), WALL_WIDTH);
                        PhysicsFactory.createBoxBody(mPhysicsWorld, wallH, BodyType.StaticBody,
                                wallFixtureDef);
                        attachChild(wallH);

                        start = end = -1;
                    }
                } else {
                    if (start < 0) {
                        start = j;
                    }
                }
            }

            if (start >= 0) {
                end = mMazeWidth;
                Shape wallH = new Rectangle(( ( start == 0 ) ? WALL_WIDTH : 0 ) + start
                        * ( mStepX + WALL_WIDTH ), ( i + 1 ) * ( mStepY + WALL_WIDTH ),
                        ( end - start ) * ( mStepX + WALL_WIDTH )
                                + ( ( start == 0 ) ? 0 : WALL_WIDTH ), WALL_WIDTH);
                PhysicsFactory.createBoxBody(mPhysicsWorld, wallH, BodyType.StaticBody,
                        wallFixtureDef);
                attachChild(wallH);
            }
        }

        for (int j = 0; j < ( mMazeWidth - 1 ); j++) {

            start = end = -1;

            for (int i = 0; i < mMazeHeight; i++) {
                if (!mMazeGrid[i][j].isEastWallClosed()) {
                    if (start >= 0) {
                        end = i;
                        
                        Shape wallV = new Rectangle(( j + 1 ) * ( mStepX + WALL_WIDTH ),
                                WALL_WIDTH + start * ( mStepY + WALL_WIDTH ), WALL_WIDTH,
                                ( end - start ) * ( mStepY + WALL_WIDTH ));
                        PhysicsFactory.createBoxBody(mPhysicsWorld, wallV, BodyType.StaticBody,
                                wallFixtureDef);
                        attachChild(wallV);

                        start = end = -1;
                    }
                } else {
                    if (start < 0) {
                        start = i;
                    }
                }
            }

            if (start >= 0) {
                end = mMazeHeight;
                Shape wallV = new Rectangle(( j + 1 ) * ( mStepX + WALL_WIDTH ), WALL_WIDTH
                        + start * ( mStepY + WALL_WIDTH ), WALL_WIDTH, ( end - start )
                        * ( mStepY + WALL_WIDTH ));
                PhysicsFactory.createBoxBody(mPhysicsWorld, wallV, BodyType.StaticBody,
                        wallFixtureDef);
                attachChild(wallV);
            }
        }
        
        /* box */
        Shape ground = new Rectangle(0, ( mStepY + WALL_WIDTH ) * mMazeHeight, 
                WALL_WIDTH + ( mStepX + WALL_WIDTH ) * mMazeWidth, WALL_WIDTH);
        Shape roof = new Rectangle(0, 0, WALL_WIDTH + ( mStepX + WALL_WIDTH ) * mMazeWidth, WALL_WIDTH);
        Shape left = new Rectangle(0, WALL_WIDTH, WALL_WIDTH, ( mStepY + WALL_WIDTH ) * mMazeHeight - WALL_WIDTH);
        Shape right = new Rectangle( ( mStepX + WALL_WIDTH ) * mMazeWidth, WALL_WIDTH, WALL_WIDTH, 
                ( mStepY + WALL_WIDTH ) * mMazeHeight - WALL_WIDTH);

        PhysicsFactory.createBoxBody(mPhysicsWorld, ground, BodyType.StaticBody, wallFixtureDef);
        PhysicsFactory.createBoxBody(mPhysicsWorld, roof, BodyType.StaticBody, wallFixtureDef);
        PhysicsFactory.createBoxBody(mPhysicsWorld, left, BodyType.StaticBody, wallFixtureDef);
        PhysicsFactory.createBoxBody(mPhysicsWorld, right, BodyType.StaticBody, wallFixtureDef);
        
        attachChild(ground);
        attachChild(roof);
        attachChild(left);
        attachChild(right);
    }

    /**
     * Computes the max marker dimension in pixel 
     * @return the max dimension
     */
    protected float getMaxMarkerDim() {
        return ( mStepX > mStepY ) ? mStepY : mStepX;
    }

    /**
     * Returns the start position's coordinate X of the marker in the maze
     * @return the start position's coordinate X
     */
    protected float getMarkerStartPositionX() {
        return WALL_WIDTH;
    }

    /**
     * Returns the start position's coordinate Y of the marker in the maze
     * @return the start position's coordinate Y
     */
    protected float getMarkerStartPositionY() {
        return WALL_WIDTH;
    }
    
    /**
     * Returns the target position's coordinate X
     * @return the target position's coordinate X
     */
    protected float getTargetPositionX() {
        return (mStepX + WALL_WIDTH) * (mMazeWidth - 1) + WALL_WIDTH + (mStepX - mTargetSprite.getWidthScaled())/2f;
    }

    /**
     * Returns the target position's coordinate Y
     * @return the target position's coordinate Y
     */
    protected float getTargetPositionY() {
        return (mStepY + WALL_WIDTH) * (mMazeHeight - 1) + WALL_WIDTH + (mStepY - mTargetSprite.getHeightScaled())/2f;
    }
}




Java Source Code List

com.sgxmobileapps.droidmaze.datastore.DroidMazeDbAdapter.java
com.sgxmobileapps.droidmaze.datastore.DroidMazeDbMetadata.java
com.sgxmobileapps.droidmaze.game.GameLevelManager.java
com.sgxmobileapps.droidmaze.game.model.GamePlayerProfile.java
com.sgxmobileapps.droidmaze.maze.generator.BacktrackingMazeGenerator.java
com.sgxmobileapps.droidmaze.maze.generator.IterativeBacktrackingMazeGenerator.java
com.sgxmobileapps.droidmaze.maze.generator.KruskalMazeGenerator.java
com.sgxmobileapps.droidmaze.maze.generator.MazeCell.java
com.sgxmobileapps.droidmaze.maze.generator.MazeGenerator.java
com.sgxmobileapps.droidmaze.maze.generator.PrimMazeGenerator.java
com.sgxmobileapps.droidmaze.ui.MainMenuActivity.java
com.sgxmobileapps.droidmaze.ui.MainSplashActivity.java
com.sgxmobileapps.droidmaze.ui.MazeActivity.java
com.sgxmobileapps.droidmaze.ui.animator.MultiSlideMenuAnimator.java
com.sgxmobileapps.droidmaze.ui.shape.ComplexShape.java
com.sgxmobileapps.droidmaze.ui.shape.LevelBarShape.java
com.sgxmobileapps.droidmaze.ui.shape.LoadingShape.java
com.sgxmobileapps.droidmaze.ui.shape.MazeShape.java
com.sgxmobileapps.droidmaze.util.ActivityUtils.java