Hello,

I'm new to mobile development and Java. My first project is a tower defence game. I'm using j2me. I figured out how to paint the sprites, made a cursor that moves around and turns green or red depending if you can put a tower there or not. Made a sprite for a monster that follows a fixed path. I managed to adjust the view so that it follows the cursor around and also managed to keep the cursor on the background layer using the collision detection. I also managed to put a menu that opens when fire is pressed but I am unable to put it in the space it needs to be in (which should be the bottom of the screen)

I haven't implemented a timer that counts down until the wave arrives but it probably won't be a big deal.

My main problems are as follows;

-I cannot make multiple copies of the monster sprite and make them move one after the other. I made a class "monsterMovement" that governs the movement of that sprite.

-I cannot put towers where the cursor is on. I think I'm going to be using the get position method and put the tower there. but I have no idea how to do that.

My first goal is to be able to make a single wave of monsters move along the path and be able to get a single

I can't post my code and point to an error because I'm completely lost at this point.

You can find my gamecanvas below. I commented some of it...

import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.Screen;
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.lcdui.game.LayerManager;
import javax.microedition.lcdui.game.Sprite;
import javax.microedition.lcdui.game.TiledLayer;

public class TowerDefenseCanvas extends GameCanvas implements Runnable {

    private static final int viewBUFFER = 50;
    private static final int SPEED = 3;
    private Timer timer;
    private boolean interrupted;
    private GameDesign gameDesign;
    private Sprite spriteMonster;
    private Sprite spriteCursor;
    private Sprite spriteTower1;
    private Sprite spriteTower2;
    private Sprite spriteHQ;
    private Sprite spriteMenu;
    private LayerManager lm;
    private byte lastDirection = -1;
    private SpriteAnimationTask spriteMonsterAnimator;
    private SpriteAnimationTask spriteCursorAnimator;
    private MonsterMovement spriteMonsterMovement;
    private TiledLayer Grass;
    private TiledLayer Road;
    private TiledLayer Trees;
    private int viewPortX = 0;
    private int viewPortY = 0;
    private boolean wave1sent = false;
    private boolean wave2sent = false;
    private boolean wave3sent = false;
    private boolean wave4sent = false;
    private boolean menuOpen = false;

    public TowerDefenseCanvas() {
        super(true);

        try {
            this.setFullScreenMode(true);
            this.init();
        } catch (IOException ex) {
            ex.printStackTrace();
        }


    }

    private void init() throws IOException {
        this.timer = new Timer();
        this.gameDesign = new GameDesign();

        this.spriteTower1 = gameDesign.getSpriteTower1();
        this.spriteTower2 = gameDesign.getSpriteTower2();
        this.spriteTower1.defineReferencePixel(24, 18);
        this.spriteTower1.setVisible(false);
        this.spriteTower2.defineReferencePixel(28, 28);
        this.spriteTower2.setVisible(false);


        this.spriteMonster = gameDesign.getSpriteMonster();
        this.spriteMonster.defineReferencePixel(8, 8);
        this.spriteMonsterAnimator = new SpriteAnimationTask(this.spriteMonster, true);
        
        this.spriteMonsterMovement = new MonsterMovement(this, spriteMonster);

        this.spriteMenu = gameDesign.getSpriteMenu();
        
        





        this.spriteCursor = gameDesign.getSpriteCursor();
        this.spriteCursor.defineReferencePixel(15, 15);
        //Unused collision rectangle - for animation purposes pixel based collision detection is enough
        //this.spriteCursor.defineCollisionRectangle(8, 8, 15, 15);
        this.spriteCursorAnimator = new SpriteAnimationTask(this.spriteCursor, false);

        this.timer.scheduleAtFixedRate(this.spriteCursorAnimator, 0, gameDesign.spriteCursorGREENDelay);
        this.timer.scheduleAtFixedRate(this.spriteMonsterAnimator, 0, gameDesign.MonsterwalkSideDelay);

        this.Grass = this.gameDesign.getGrass();
        this.Road = this.gameDesign.getRoad();
        this.Trees = this.gameDesign.getTrees();

        this.lm = new LayerManager();
        gameDesign.updateLayerManagerForLVL1(lm);

        (new Thread(spriteMonsterMovement)).start();

    }

    public boolean outofBoundsDetect(Sprite sprite) {
        return sprite.collidesWith(sprite == this.spriteCursor ? this.spriteMonster : this.spriteCursor, true)
                || sprite.getX() < 0 || sprite.getY() < 0
                || sprite.getX() > (this.Grass.getWidth() - sprite.getWidth())
                || sprite.getY() > (this.Grass.getHeight() - sprite.getHeight());


    }

    public boolean collisionDetect(Sprite sprite) {
        return sprite.collidesWith(this.Trees, true)
                || sprite.collidesWith(this.Road, true)
                || sprite.getX() < 0 || sprite.getY() < 0
                || sprite.getX() > (this.Grass.getWidth() - sprite.getWidth())
                || sprite.getY() > (this.Grass.getHeight() - sprite.getHeight());
    }

    private class SpriteAnimationTask extends TimerTask {

        private boolean moving = false;
        private boolean forward = true;
        private Sprite sprite;

        public SpriteAnimationTask(Sprite sprite, boolean forward) {
            this.sprite = sprite;
            this.forward = forward;
        }

        public void run() {
            if (!this.moving) {
                return;
            }
            if (this.forward) {
                this.sprite.nextFrame();
            } else {
                this.sprite.prevFrame();
            }
        }

        public void forward() {
            this.forward = true;
            this.moving = true;
        }

        public void backward() {
            this.forward = false;
            this.moving = true;
        }

        public void setMoving(boolean isMoving) {
            this.moving = isMoving;
        }
    }

    public void run() {
        

        Graphics g = getGraphics();

        int w = this.Grass.getX() + this.Grass.getWidth() - spriteCursor.getWidth();
        int h = this.Grass.getY() + this.Grass.getHeight() - spriteCursor.getHeight();
        
        
        
        

        this.spriteTower1.setVisible(false);
        this.spriteTower2.setVisible(false);

        
        while (!this.interrupted) {







            //Checking for user input
            int keyState = getKeyStates();

            if ((keyState & FIRE_PRESSED) != 0) {

                if (menuOpen == false) {
                    menuOpen = true;
                    spriteCursor.setVisible(false);
                    spriteMenu.setVisible(true);


                } else if (menuOpen == true) {
                    menuOpen = false;
                    spriteCursor.setVisible(true);
                    spriteMenu.setVisible(false);


                }
            }

            if (menuOpen == false) {

                this.spriteMenu.setVisible(false);

                if ((keyState & LEFT_PRESSED) != 0) {

                    if (this.lastDirection != LEFT) {
                        this.lastDirection = LEFT;
                        continue;
                    }

                    //Makes the cursor red or green depending on the collisions

                    if (this.collisionDetect(this.spriteCursor)) {
                        this.spriteCursor.setFrameSequence(gameDesign.spriteCursorRED);
                        this.spriteCursorAnimator.forward();
                        this.spriteCursor.move(-SPEED, 0);
                    } else if (!this.collisionDetect(this.spriteCursor)) {
                        this.spriteCursor.setFrameSequence(gameDesign.spriteCursorGREEN);
                        this.spriteCursorAnimator.forward();
                        this.spriteCursor.move(-SPEED, 0);
                    }
                    if (this.outofBoundsDetect(this.spriteCursor)) {
                        this.spriteCursor.move(SPEED, 0);
                    }
                    this.adjustView(this.viewPortX - SPEED, this.viewPortY);


                } else if ((keyState & RIGHT_PRESSED) != 0) {

                    if (this.lastDirection != RIGHT) {
                        this.lastDirection = RIGHT;
                        continue;
                    }
                    if (this.collisionDetect(this.spriteCursor)) {
                        this.spriteCursor.setFrameSequence(gameDesign.spriteCursorRED);
                        this.spriteCursorAnimator.forward();
                        this.spriteCursor.move(SPEED, 0);
                    } else if (!this.collisionDetect(this.spriteCursor)) {
                        this.spriteCursor.setFrameSequence(gameDesign.spriteCursorGREEN);
                        this.spriteCursorAnimator.forward();
                        this.spriteCursor.move(SPEED, 0);
                    }
                    if (this.outofBoundsDetect(this.spriteCursor)) {
                        this.spriteCursor.move(-SPEED, 0);
                    }
                    this.adjustView(this.viewPortX + SPEED, this.viewPortY);

                } else if ((keyState & UP_PRESSED) != 0) {
                    if (this.lastDirection != UP) {
                        this.lastDirection = UP;
                        continue;
                    }
                    if (this.collisionDetect(this.spriteCursor)) {
                        this.spriteCursor.setFrameSequence(gameDesign.spriteCursorRED);
                        this.spriteCursorAnimator.forward();
                        this.spriteCursor.move(0, -SPEED);
                    } else if (!this.collisionDetect(this.spriteCursor)) {
                        this.spriteCursor.setFrameSequence(gameDesign.spriteCursorGREEN);
                        this.spriteCursorAnimator.forward();
                        this.spriteCursor.move(0, -SPEED);
                    }
                    if (this.outofBoundsDetect(this.spriteCursor)) {
                        this.spriteCursor.move(0, SPEED);
                    }
                    this.adjustView(this.viewPortX, this.viewPortY - SPEED);

                } else if ((keyState & DOWN_PRESSED) != 0) {
                    if (this.lastDirection != DOWN) {
                        this.lastDirection = DOWN;
                        continue;
                    }
                    if (this.collisionDetect(this.spriteCursor)) {
                        this.spriteCursor.setFrameSequence(gameDesign.spriteCursorRED);
                        this.spriteCursorAnimator.forward();
                        this.spriteCursor.move(0, SPEED);
                    } else if (!this.collisionDetect(this.spriteCursor)) {
                        this.spriteCursor.setFrameSequence(gameDesign.spriteCursorGREEN);
                        this.spriteCursorAnimator.forward();
                        this.spriteCursor.move(0, SPEED);
                    }
                    if (this.outofBoundsDetect(this.spriteCursor)) {
                        this.spriteCursor.move(0, -SPEED);
                    }
                    this.adjustView(this.viewPortX, this.viewPortY + SPEED);
                }
            } else if (menuOpen == true) {
                
            }



            this.lm.paint(g, 0, 0);
            flushGraphics(0, 0, this.getWidth(), this.getHeight());

            try {
                Thread.sleep(20);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }

    private void adjustView(int x, int y) {

        int sx = this.spriteCursor.getX();
        int sy = this.spriteCursor.getY();

        int xmin = this.viewPortX + viewBUFFER;
        int xmax = this.viewPortX + this.getWidth() - this.spriteCursor.getWidth() - viewBUFFER;
        int ymin = this.viewPortY + viewBUFFER;
        int ymax = this.viewPortY + this.getHeight() - this.spriteCursor.getHeight() - viewBUFFER;

        //These cases check and correct if the cursor is near the edges
        if (sx >= xmin && sx <= xmax && sy >= ymin && sy <= ymax) {
            return;
        }

        if (this.lastDirection == LEFT && sx >= xmin) {
            return;
        }

        if (this.lastDirection == RIGHT && sx <= xmax) {
            return;
        }

        if (this.lastDirection == UP && sy >= ymin) {
            return;
        }

        if (this.lastDirection == DOWN && sy <= ymax) {
            return;
        }

        //ensures that the background is shown and view does not extend to beyond the background layer (x values)

        if (x < this.Grass.getX()) {
            this.viewPortX = this.Grass.getX();
        } else if (x > this.Grass.getX() + this.Grass.getWidth() - this.getWidth()) {
            this.viewPortX = this.Grass.getX() + this.Grass.getWidth() - this.getWidth();
        } else {
            this.viewPortX = x;
        }
        //ensures that the background is shown and view does not extend to beyond the background layer (y values)
        if (y < this.Grass.getY()) {
            this.viewPortY = this.Grass.getY();
        } else if (y > this.Grass.getY() + this.Grass.getHeight() - this.getHeight()) {
            this.viewPortY = this.Grass.getY() + this.Grass.getHeight() - this.getHeight();
        } else {
            this.viewPortY = y;
        }

        //makes the adjustment

        this.lm.setViewWindow(this.viewPortX, this.viewPortY, this.getWidth(), this.getHeight());



    }

    public void stop() {
        this.interrupted = true;
    }
}

What does it take to compile and execute this program?

you need the layers, sprites and the monsterMovement class... Is this the answer you are looking for?

Just curious. If anyone were interested in helping, he'd need to be able to execute the code.
Good luck

if anyone needs it i will send them the project file. Thank you for your post.