Creating the environment

MansionCanvas class

The Canvas, to which the mansion is drawn.

  1. Create the MansionCanvas class file.

  2. Import the required classes.

    
    package com.nokia.mid.mansion;
    
    import javax.microedition.lcdui.*;
    
    
  3. Set the MansionCanvas to extend Canvas. Define the objects, constants and variables used by the application and create the constructor.

    /**
     * Handles canvas and also Spectator.
     */
    public class MansionCanvas extends Canvas {
        final Display display;
        final int width, height;
        boolean paused;
        final static int NUM_SOURCES = 4;
        private Source[] sources = new Source[NUM_SOURCES];
        private House house;
        private Walker walker;
        int forcedReverb = -1;
        String msg = "";
        private int msgColor = 0xcc11cc;
     
        public MansionCanvas(Display d) {
    		display = d;
    		paused = true;
    		width = getWidth();
    		height = getHeight();
    		house = new House();
    		
    		// init sources:
    		sources[0] = new Source(6000, 6500, "/largedog16k.wav", house, this);
    		sources[1] = new Source(10000, 3500, "/budgie_16k.wav", house, this);
    		sources[2] = new Source(1100, 6000, "/owl_16k.wav", house, this);
    		sources[3] = new Source(1150, 6000, "/cock_16k.wav", house, this);
    	
    		for (int i = 0; i < NUM_SOURCES; i++){
    		    System.out.println("starting source "+ i);
    		    Thread t = new Thread(sources[i]);
    		    t.start();
    		}
    		walker = new Walker();
    		msg = "Welcome to Mansion!";
        }
    
    
  4. Create a method for drawing the graphics used by the application.

        /**
         * Draws everything.
         */
        protected void paint(Graphics g) {
            int x_min = g.getClipX();
            int y_min = g.getClipY();
            int w = g.getClipWidth();
            int h = g.getClipHeight();
    
    		// Empty the frame 
    		g.setColor(0xffffff);
    		g.fillRect(x_min, y_min, w, h);
    		g.translate(width/2, height/2); // move origin to the center
    	
    		// Draw sources
    		for (int i = 0; i < NUM_SOURCES; i++) {
    		    sources[i].draw(g, walker.getX(), walker.getY(), walker.getRot());
    		}
    	
    		// Draw house (walls and doors)
    		house.draw(g, walker.getX(), walker.getY(), walker.getRot());
    	
    		// Draw player (walker) at origin:
    		g.setColor(0xdd2222);
    		g.fillRect(-4, -1, 9, 2); // shoulders
    		g.setColor(0x66660a);
    		g.drawLine(0, -3, 0, -3); // nose
    		g.setColor(0);
    		g.fillArc(-2, -2, 5, 5, 0, 360); // head
    		g.translate(-width/2, -height/2); // reset translation
    	
    		// Draw the frame
    		g.setColor(0);
    		g.drawRect(0, 0, width-1, height-1);
    	
    		// Draw message:
            if (msg != null) {
                g.setColor(0xffffff);
                g.setClip(0, height-14, width, height);
                g.fillRect(0, height-20, width-2, 18);
                g.setColor(msgColor);
                g.drawString(msg, 5, height-14, 0);
    		    g.setColor(0);
                g.drawRect(0, 0, width-1, height-1);
            }
    		occludeSources();
        }//paint()
    
    
  5. Create a method for activating the sound sources that are located in the same room as the Walker object, and muting the rest.

        /**
         * Starts sources that are in the same room (or space) and stops the rest
         */
        private void occludeSources() {
    		int listeningRoom = house.inWhichRoom(walker.getX());
    		for (int i = 0; i < NUM_SOURCES; i++) {
    		    if(listeningRoom == house.inWhichRoom(sources[i].getX())) {
    		    	sources[i].start();
    		    } else {
    		    	sources[i].stop();
    		    }
    		}
        }
    
    
  6. Create methods for detecting key presses and repeated key presses.

        public void keyPressed(int keyCode) {
        	keyAction(keyCode);
        }
    
        public void keyRepeated(int keyCode) {
        	keyAction(keyCode);
        }
        
    
  7. Create a method for giving functionality to the various key presses.

        private void keyAction(int keyCode) {
    		int action = getGameAction(keyCode);	
    		switch (action) {
    		case LEFT:
    		    walker.rotateLeft();
    		    break;
    		case RIGHT:
    		    walker.rotateRight();
    		    break;
    		case UP:
    		    walker.moveForward(house);
    		    break;
    		case DOWN:
    		    walker.moveBackward(house);
    		    break;
    		case FIRE:
    		    forcedReverb += 1;
    		    forcedReverb = forcedReverb % House.NUM_REV_PRESETS;
    		    walker.forceReverb(forcedReverb);
    		    break;
    		}
    		msg = "" + walker.getRevName();
    		/*msg = "X:" + walker.getX() + "Y:" + walker.getY()
    		    + "r:" + walker.getRot()*10 + " " + walker.getRevName();*/
    		repaint();
        }//keyAction()
    
    
  8. Create a method for closing the sound sources.

        /**
         * Closes the sound sources.
         */
        void destroy() {
    		for(int i=0; i < NUM_SOURCES; i++) {
    	 	    sources[i].destroy();
    	 	}
        }
    
    
  9. Create methods for pausing and starting the running of the repainting.

        boolean isPaused() {
        	return paused;
        }
    
        void pause() {
    		if (!paused) {
    		    paused = true;	
    		}
    		repaint();
        }
    
        void start() {
    		if (paused) {
    		    paused = false;
    		    display.setCurrent(this);
    		}
    		repaint();
        }
    }

House class

The class that creates the actual mansion the game takes place in.

  1. Create the House class file.

  2. Import the required classes.

    package com.nokia.mid.mansion;
    
    import javax.microedition.lcdui.Graphics;
    
    
  3. Create the constructor and a method to run it..

    /**
     * Contains the walls and the reverb settings.
     *
     */
    public class House {
        public static final int NUM_REV_PRESETS = 10;
        private static final int ALLEY=0,ARENA=1, AUDITORIUM=2,BATHROOM=3,CAVE=4,
    	HALLWAY=5,HANGAR=6,LIVINGROOM=7,MOUNTAINS=8,ROOM=9;
        static final String REV_PRESETS[] = {
    		"alley", "arena", "auditorium", "bathroom", "cave",
    		"hallway", "hangar", "livingroom", "mountains", "room"
        };
    
        // coordinates and reverb settings of the rooms:
        private static final int[][] ROOMS =
        {//{Y_MIN,Y_MAX,X_MAX,REVERB_PRESET} 
    	{6000,6000,0,MOUNTAINS}, // dummy (sentinel)
    	{3000,10000,4000,MOUNTAINS}, //yard
    	{6000,7000,8000,HALLWAY},
    	{2000,10000,19000,AUDITORIUM},
    	{3500,3500,19000,ALLEY} // dummy (sentinel)
        };
    
        public House (){
    	
        }
    
    
  4. Create a method for detecting, whether a given coordinate is inside the bounds of the accessible "house" area.

        /**
         * @return true, if given coordinates are inside of the house.
         */
        public boolean isInside(int x, int y) {
    		boolean inside = false;
    		final int room = inWhichRoom(x);
    		if (y+100 < ROOMS[room][1] && y-100 > ROOMS[room][0])
    		    inside = true;
    		return inside;
        }
        
    
  5. Create a method for detecting the room of the "house" the given x-coordinate is in. Since none of the rooms are located on the same y-coordinates, a method for detecting them on that basis is not needed.

        /**
         * Tells in which room is the given x-coordinate in.
         *
         * @return room index
         */
        public int inWhichRoom(int x) {
    		int room = ROOMS.length-1;
    		for (int i = 0; i < ROOMS.length-1; i++) {
    		    if (x > ROOMS[i][2]) {
    		    	room = i+1;
    		    } else {
    		    	break;
    		    }
    		}
    		if (room >= ROOMS.length)
    		    System.out.println("bug in House.inWhichRoom()! room=" + room);
    		return room;
        }
    
    
  6. Create the methods to fetch the reverb preset names, by given room or by index.

        /**
         * Gets the reverb preset name for the given room
         */
        public static String presetName(int room) {
        	if(room < ROOMS.length && room >= 0) {
        		return REV_PRESETS[ROOMS[room][3]];
        	} else {
        		return "";
        	}
        }
    
        /**
         * Gets reverb preset name by index
         */
        public static String presetNameByIndex(int index) {
        	if(index < NUM_REV_PRESETS && index >= 0) {
        		return REV_PRESETS[index];
        	} else {
        		return "";
        	}
        }
         
    
  7. Create the method for drawing the actual house to a Graphics object.

        /**
         * Draws the house to given Graphics.
         * @param dx x translation in millipixels
         * @param dy y translation in millipixels
         * @param rot rotation in deci-angles
         */
        public void draw(Graphics g, int dx, int dy, int rot) {
        	for (int i=1; i < ROOMS.length; i++) {
    		    // door:
    		    g.setColor(0xee1111); //brick
    		    /*
    		      following min/max coding is necessary, because if the door
    		      ovelaps east wall, there will be artifacts visible, because
    		      overlapping doesn't seem to be perfect:
    		    */
    		    g.drawLine
    			(Trig.transXS(ROOMS[i-1][2]-dx, 
    					Math.min(ROOMS[i][1],ROOMS[i-1][1])-dy, rot),
    			 Trig.transYS(ROOMS[i-1][2]-dx,
    					Math.min(ROOMS[i][1],ROOMS[i-1][1])-dy, rot),
    			 Trig.transXS(ROOMS[i-1][2]-dx,
    					Math.max(ROOMS[i][0],ROOMS[i-1][0])-dy, rot),
    			 Trig.transYS(ROOMS[i-1][2]-dx,
    					Math.max(ROOMS[i][0],ROOMS[i-1][0])-dy, rot));
    	
    		    g.setColor(0x000000); // black
    	
    		    //east (northern from door) wall:
    		    g.drawLine
    			(Trig.transXS(ROOMS[i-1][2]-dx,ROOMS[i][1]-dy,rot),
    			 Trig.transYS(ROOMS[i-1][2]-dx,ROOMS[i][1]-dy,rot),
    			 Trig.transXS(ROOMS[i-1][2]-dx,ROOMS[i-1][1]-dy,rot),
    			 Trig.transYS(ROOMS[i-1][2]-dx,ROOMS[i-1][1]-dy,rot));
    		    
    		    // east (southern from door) wall:
    		    g.drawLine
    			(Trig.transXS(ROOMS[i-1][2]-dx,ROOMS[i][0]-dy,rot),
    			 Trig.transYS(ROOMS[i-1][2]-dx,ROOMS[i][0]-dy,rot),
    			 Trig.transXS(ROOMS[i-1][2]-dx,ROOMS[i-1][0]-dy,rot),
    			 Trig.transYS(ROOMS[i-1][2]-dx,ROOMS[i-1][0]-dy,rot));
    	
    		    //north wall:
    		    g.drawLine
    			(Trig.transXS(ROOMS[i-1][2]-dx,ROOMS[i][0]-dy,rot),
    			 Trig.transYS(ROOMS[i-1][2]-dx,ROOMS[i][0]-dy,rot),
    			 Trig.transXS(ROOMS[i][2]-dx,ROOMS[i][0]-dy,rot),
    			 Trig.transYS(ROOMS[i][2]-dx,ROOMS[i][0]-dy,rot));
    		    
    		    //south wall:
    		    g.drawLine
    			(Trig.transXS(ROOMS[i-1][2]-dx,ROOMS[i][1]-dy,rot),
    			 Trig.transYS(ROOMS[i-1][2]-dx,ROOMS[i][1]-dy,rot),
    			 Trig.transXS(ROOMS[i][2]-dx,ROOMS[i][1]-dy,rot),
    			 Trig.transYS(ROOMS[i][2]-dx,ROOMS[i][1]-dy,rot));
        	}
        }//draw()
    
    }// House