Hi all thanks to read my answer hope you can help me
I am working on Image cropping in blackberry. In my application contain 3 main things.
1)Load the image on the screen
2)select the shape of the cropping area
3)display that cropping image on next screen with out losing its shape
Step1: i can done the image loading part
step2: using Menu i just add the 4 types of shapes
1)Circle
2)Rectangle with rounded shape
3)Star
4)Cloud
using menu when he click on any menu item ,then that particular shape image will display on the screen.
we can give the movement to that image because we have to provide him to select any portion of the image.
step3: After fix the position then we will allow the user to crop using menu.
when he click on menu item " CROP". then we have to crop the image according the shape and that image should display on the next screen
Note: Following code working only for Rectangular shape but i want to
use all shapes
This is my sample code ::
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Display;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.Screen;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.XYEdges;
import net.rim.device.api.ui.XYRect;
import net.rim.device.api.ui.component.BitmapField;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.Menu;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.container.VerticalFieldManager;
import net.rim.device.api.ui.decor.BackgroundFactory;
public class ClipMove extends MainScreen{
Bitmap circle_frame,rectangle_frame,star_frame,cloud_frame,image,selected_frame;
BitmapField frmae_field;
private int padding_x=0,padding_y=0;
private VerticalFieldManager vrt_mgr;
public ClipMove() {
//Here my shape images are transparent
circle_frame=Bitmap.getBitmapResource("circle.gif");
rectangle_frame=Bitmap.getBitmapResource("rect1.png");
star_frame=Bitmap.getBitmapResource("star.gif");
cloud_frame=Bitmap.getBitmapResource("cloud.gif");
//this is my actual image to crop
image=Bitmap.getBitmapResource("sample.jpg");
vrt_mgr=new VerticalFieldManager(){
protected void sublayout(int maxWidth, int maxHeight) {
super.sublayout(Display.getWidth(),Display.getHeight());
setExtent(Display.getWidth(),Display.getHeight());
}
};
vrt_mgr.setBackground(BackgroundFactory.createBitmapBackground(image));
add(vrt_mgr);
}
protected void makeMenu(Menu menu, int instance) {
super.makeMenu(menu, instance);
menu.add(new MenuItem("Rect",0,0) {
public void run() {
// TODO Auto-generated method stub
vrt_mgr.deleteAll();
selected_frame=rectangle_frame;
frmae_field=new BitmapField(rectangle_frame);
vrt_mgr.add(frmae_field);
vrt_mgr.invalidate();
}
});
menu.add(new MenuItem("Circle",0,0) {
public void run() {
// TODO Auto-generated method stub
vrt_mgr.deleteAll();
selected_frame=circle_frame;
frmae_field=new BitmapField(circle_frame);
vrt_mgr.add(frmae_field);
vrt_mgr.invalidate();
}
});
menu.add(new MenuItem("Star",0,0) {
public void run() {
// TODO Auto-generated method stub
vrt_mgr.deleteAll();
selected_frame=star_frame;
frmae_field=new BitmapField(star_frame);
vrt_mgr.add(frmae_field);
vrt_mgr.invalidate();
}
});
menu.add(new MenuItem("Cloud",0,0) {
public void run() {
// TODO Auto-generated method stub
vrt_mgr.deleteAll();
selected_frame=cloud_frame;
frmae_field=new BitmapField(cloud_frame);
vrt_mgr.add(frmae_field);
vrt_mgr.invalidate();
}
});
menu.add(new MenuItem("Crop",0,0) {
public void run() {
// TODO Auto-generated method stub
Field f=vrt_mgr.getField(0);
// XYRect rect=getFieldExtent(f);
XYRect rect=new XYRect(padding_x, padding_y,frmae_field.getBitmapWidth(),frmae_field.getBitmapHeight());
Bitmap crop = cropImage(image, rect.x, rect.y,
rect.width, rect.height);
synchronized (UiApplication.getEventLock()) {
UiApplication.getUiApplication().pushScreen(new sampleScreen(crop,selected_frame));
}
}
});
}
protected boolean navigationMovement(int dx, int dy, int status, int time) {
if(frmae_field!=null){
padding_x=padding_x+dx;
padding_y=padding_y+dy;
XYEdges edge=new XYEdges(padding_y, 0, 0, padding_x);
frmae_field.setPadding(edge);
vrt_mgr.invalidate();
return true;
}else {
return false;
}
}
public void DisplayMessage(final String str)
{
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.inform(str);
}
});
}
public XYRect getFieldExtent(Field fld) {
int cy = fld.getContentTop();
int cx = fld.getContentLeft();
Manager m = fld.getManager();
while (m != null) {
cy += m.getContentTop() - m.getVerticalScroll();
cx += m.getContentLeft() - m.getHorizontalScroll();
if (m instanceof Screen)
break;
m = m.getManager();
}
return new XYRect(cx, cy, fld.getContentWidth(), fld.getContentHeight());
}
// this logic only useful for rectangler shape
public Bitmap cropImage(Bitmap image, int x, int y, int width,int height) {
Bitmap result = new Bitmap(width, height);
Graphics g = Graphics.create(result);
g.drawBitmap(0, 0, width, height, image, x, y);
return result;
}
}
//this is my next screen to show the croped image
class sampleScreen extends MainScreen
{
VerticalFieldManager manager;
public sampleScreen(final Bitmap img,final Bitmap back) {
manager=new VerticalFieldManager(){
protected void paint(Graphics graphics) {
graphics.drawBitmap(0, 0, img.getWidth(), img.getHeight(), img, 0, 0);
super.paint(graphics);
}
protected void sublayout(int maxWidth, int maxHeight) {
super.sublayout( img.getWidth(), img.getHeight());
setExtent( img.getWidth(), img.getHeight());
}
};
BitmapField field=new BitmapField(back);
field.setPadding(0, 0, 0, 0);
manager.add(field);
add(manager);
}
}
My screen shots:
By using another dummy image, it is possible to determine which pixels of the original image needs to be deleted (we can make them transparent). Though It may not be the optimal solution, but it can be applied for any geometric figure we can draw on BlackBerry.
Check following steps:
Create a new Bitmap image (dummyImage) of same dimension as the
source image (myImage).
Draw (fill) the target geometric shape on it using a defined color
(fillColor).
Now for each pixel of myImage, if the same pixel of dummyImage
contains fillColor then keep it unchanged, else make this pixel
fully transparent by assigning zero (0) to it.
Now myImage is almost ready, need to trim this image for
transparent pixel removal.
Following code will apply a circular crop on a image. (but won't trim the transparent pixels).
package mypackage;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Display;
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.component.BitmapField;
import net.rim.device.api.ui.component.Menu;
import net.rim.device.api.ui.container.MainScreen;
class MyScreen extends MainScreen {
private Bitmap myImage = Bitmap.getBitmapResource("img/myImage.jpeg");
private BitmapField _bf;
public MyScreen() {
_bf = new BitmapField(myImage);
adjustBitmapMargin();
add(_bf);
}
private void adjustBitmapMargin() {
int x = (Display.getWidth() - myImage.getWidth()) / 2;
int y = (Display.getHeight() - myImage.getHeight()) / 2;
_bf.setMargin(y, 0, 0, x);
}
protected void makeMenu(Menu menu, int instance) {
menu.add(miCropCircle);
super.makeMenu(menu, instance);
}
private MenuItem miCropCircle = new MenuItem("Crop - Circle", 0, 0) {
public void run() {
cropImage();
}
};
private void cropImage() {
int width = myImage.getWidth();
int height = myImage.getHeight();
// get original data from the image
int myImageData[] = new int[width * height];
myImage.getARGB(myImageData, 0, width, 0, 0, width, height);
// get default color of a newly created bitmap
int defaultColors[] = new int[1 * 1];
(new Bitmap(1, 1)).getARGB(defaultColors, 0, 1, 0, 0, 1, 1);
int defaultColor = defaultColors[0];
int fillColor = Color.RED;
int diameter = 200;
// dummy data preparation
Bitmap dummyImage = new Bitmap(width, height);
Graphics dummyImageGraphics = Graphics.create(dummyImage);
dummyImageGraphics.setColor(fillColor);
int startX = width / 2 - diameter / 2;
int startY = height / 2 - diameter / 2;
dummyImageGraphics.fillArc(startX, startY, diameter, diameter, 0, 360);
int dummyData[] = new int[width * height];
dummyImage.getARGB(dummyData, 0, width, 0, 0, width, height);
// filling original data with transparent value.
int totalPixels = width * height;
for (int i = 0; i < totalPixels; i++) {
if (dummyData[i] == defaultColor) {
myImageData[i] = 0;
}
}
// set new data
myImage.setARGB(myImageData, 0, width, 0, 0, width, height);
// redraw screen
_bf.setBitmap(myImage);
adjustBitmapMargin();
invalidate();
// free up some memory here
defaultColors = null;
dummyImage = null;
dummyData = null;
dummyImageGraphics = null;
}
}
Output of the above code:
Related
I am trying to develop a Tower Defense Game using javafx and I am having trouble as to how to make it so that the enemies move around the screen. Which classes and methods should I be using in order to approach this problem?
A tower defense game is too much to be covered on SO. I had a little bit of spare time and modified the engine I created in this thread.
Here's the main class with the game loop where the game is loaded, input is checked, sprites are moved, collision is checked, score is updated etc. In opposite to the other engine here you don't need keyboard input. Instead use a mouse click to position a tower. I added 4 initial towers.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.scene.text.TextBoundsType;
import javafx.stage.Stage;
public class Game extends Application {
Random rnd = new Random();
Pane playfieldLayer;
Pane scoreLayer;
Image playerImage;
Image enemyImage;
List<Tower> towers = new ArrayList<>();;
List<Enemy> enemies = new ArrayList<>();;
Text scoreText = new Text();
int score = 0;
Scene scene;
#Override
public void start(Stage primaryStage) {
Group root = new Group();
// create layers
playfieldLayer = new Pane();
scoreLayer = new Pane();
root.getChildren().add( playfieldLayer);
root.getChildren().add( scoreLayer);
playfieldLayer.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
createTower(e.getX(), e.getY());
});
scene = new Scene( root, Settings.SCENE_WIDTH, Settings.SCENE_HEIGHT);
primaryStage.setScene( scene);
primaryStage.show();
loadGame();
createScoreLayer();
createTowers();
AnimationTimer gameLoop = new AnimationTimer() {
#Override
public void handle(long now) {
// add random enemies
spawnEnemies( true);
// check if target is still valid
towers.forEach( tower -> tower.checkTarget());
// tower movement: find target
for( Tower tower: towers) {
tower.findTarget( enemies);
}
// movement
towers.forEach(sprite -> sprite.move());
enemies.forEach(sprite -> sprite.move());
// check collisions
checkCollisions();
// update sprites in scene
towers.forEach(sprite -> sprite.updateUI());
enemies.forEach(sprite -> sprite.updateUI());
// check if sprite can be removed
enemies.forEach(sprite -> sprite.checkRemovability());
// remove removables from list, layer, etc
removeSprites( enemies);
// update score, health, etc
updateScore();
}
};
gameLoop.start();
}
private void loadGame() {
playerImage = new Image( getClass().getResource("player.png").toExternalForm());
enemyImage = new Image( getClass().getResource("enemy.png").toExternalForm());
}
private void createScoreLayer() {
scoreText.setFont( Font.font( null, FontWeight.BOLD, 48));
scoreText.setStroke(Color.BLACK);
scoreText.setFill(Color.RED);
scoreLayer.getChildren().add( scoreText);
scoreText.setText( String.valueOf( score));
double x = (Settings.SCENE_WIDTH - scoreText.getBoundsInLocal().getWidth()) / 2;
double y = 0;
scoreText.relocate(x, y);
scoreText.setBoundsType(TextBoundsType.VISUAL);
}
private void createTowers() {
// position initial towers
List<Point2D> towerPositionList = new ArrayList<>();
towerPositionList.add(new Point2D( 100, 200));
towerPositionList.add(new Point2D( 100, 400));
towerPositionList.add(new Point2D( 800, 200));
towerPositionList.add(new Point2D( 800, 600));
for( Point2D pos: towerPositionList) {
createTower( pos.getX(), pos.getY());
}
}
private void createTower( double x, double y) {
Image image = playerImage;
// center image at position
x -= image.getWidth() / 2;
y -= image.getHeight() / 2;
// create player
Tower player = new Tower(playfieldLayer, image, x, y, 0, 0, 0, 0, Settings.PLAYER_SHIP_HEALTH, 0, Settings.PLAYER_SHIP_SPEED);
// register player
towers.add( player);
}
private void spawnEnemies( boolean random) {
if( random && rnd.nextInt(Settings.ENEMY_SPAWN_RANDOMNESS) != 0) {
return;
}
// image
Image image = enemyImage;
// random speed
double speed = rnd.nextDouble() * 1.0 + 2.0;
// x position range: enemy is always fully inside the screen, no part of it is outside
// y position: right on top of the view, so that it becomes visible with the next game iteration
double x = rnd.nextDouble() * (Settings.SCENE_WIDTH - image.getWidth());
double y = -image.getHeight();
// create a sprite
Enemy enemy = new Enemy( playfieldLayer, image, x, y, 0, 0, speed, 0, 1,1);
// manage sprite
enemies.add( enemy);
}
private void removeSprites( List<? extends SpriteBase> spriteList) {
Iterator<? extends SpriteBase> iter = spriteList.iterator();
while( iter.hasNext()) {
SpriteBase sprite = iter.next();
if( sprite.isRemovable()) {
// remove from layer
sprite.removeFromLayer();
// remove from list
iter.remove();
}
}
}
private void checkCollisions() {
for( Tower tower: towers) {
for( Enemy enemy: enemies) {
if( tower.hitsTarget( enemy)) {
enemy.getDamagedBy( tower);
// TODO: explosion
if( !enemy.isAlive()) {
enemy.setRemovable(true);
// increase score
score++;
}
}
}
}
}
private void updateScore() {
scoreText.setText( String.valueOf( score));
}
public static void main(String[] args) {
launch(args);
}
}
Then you need a base class for your sprites. You can use it for enemies and towers.
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
public abstract class SpriteBase {
Image image;
ImageView imageView;
Pane layer;
double x;
double y;
double r;
double dx;
double dy;
double dr;
double health;
double damage;
boolean removable = false;
double w;
double h;
boolean canMove = true;
public SpriteBase(Pane layer, Image image, double x, double y, double r, double dx, double dy, double dr, double health, double damage) {
this.layer = layer;
this.image = image;
this.x = x;
this.y = y;
this.r = r;
this.dx = dx;
this.dy = dy;
this.dr = dr;
this.health = health;
this.damage = damage;
this.imageView = new ImageView(image);
this.imageView.relocate(x, y);
this.imageView.setRotate(r);
this.w = image.getWidth(); // imageView.getBoundsInParent().getWidth();
this.h = image.getHeight(); // imageView.getBoundsInParent().getHeight();
addToLayer();
}
public void addToLayer() {
this.layer.getChildren().add(this.imageView);
}
public void removeFromLayer() {
this.layer.getChildren().remove(this.imageView);
}
public Pane getLayer() {
return layer;
}
public void setLayer(Pane layer) {
this.layer = layer;
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
public double getR() {
return r;
}
public void setR(double r) {
this.r = r;
}
public double getDx() {
return dx;
}
public void setDx(double dx) {
this.dx = dx;
}
public double getDy() {
return dy;
}
public void setDy(double dy) {
this.dy = dy;
}
public double getDr() {
return dr;
}
public void setDr(double dr) {
this.dr = dr;
}
public double getHealth() {
return health;
}
public double getDamage() {
return damage;
}
public void setDamage(double damage) {
this.damage = damage;
}
public void setHealth(double health) {
this.health = health;
}
public boolean isRemovable() {
return removable;
}
public void setRemovable(boolean removable) {
this.removable = removable;
}
public void move() {
if( !canMove)
return;
x += dx;
y += dy;
r += dr;
}
public boolean isAlive() {
return Double.compare(health, 0) > 0;
}
public ImageView getView() {
return imageView;
}
public void updateUI() {
imageView.relocate(x, y);
imageView.setRotate(r);
}
public double getWidth() {
return w;
}
public double getHeight() {
return h;
}
public double getCenterX() {
return x + w * 0.5;
}
public double getCenterY() {
return y + h * 0.5;
}
// TODO: per-pixel-collision
public boolean collidesWith( SpriteBase otherSprite) {
return ( otherSprite.x + otherSprite.w >= x && otherSprite.y + otherSprite.h >= y && otherSprite.x <= x + w && otherSprite.y <= y + h);
}
/**
* Reduce health by the amount of damage that the given sprite can inflict
* #param sprite
*/
public void getDamagedBy( SpriteBase sprite) {
health -= sprite.getDamage();
}
/**
* Set health to 0
*/
public void kill() {
setHealth( 0);
}
/**
* Set flag that the sprite can be removed from the UI.
*/
public void remove() {
setRemovable(true);
}
/**
* Set flag that the sprite can't move anymore.
*/
public void stopMovement() {
this.canMove = false;
}
public abstract void checkRemovability();
}
The towers are subclasses of the sprite base class. Here you need a little bit of math because you want the towers to rotate towards the enemies and let the towers fire when the enemy is within range.
import java.util.List;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.image.Image;
import javafx.scene.layout.Pane;
public class Tower extends SpriteBase {
SpriteBase target; // TODO: use weakreference
double turnRate = 0.6;
double speed;
double targetRange = 300; // distance within tower can lock to enemy
ColorAdjust colorAdjust;
double rotationLimitDeg=0.0;
double rotationLimitRad = Math.toDegrees( this.rotationLimitDeg);
double roatationEasing = 10;
double targetAngle = 0;
double currentAngle = 0;
boolean withinFiringRange = false;
public Tower(Pane layer, Image image, double x, double y, double r, double dx, double dy, double dr, double health, double damage, double speed) {
super(layer, image, x, y, r, dx, dy, dr, health, damage);
this.speed = speed;
this.setDamage(Settings.TOWER_DAMAGE);
init();
}
private void init() {
// red colorization (simulate "angry")
colorAdjust = new ColorAdjust();
colorAdjust.setContrast(0.0);
colorAdjust.setHue(-0.2);
}
#Override
public void move() {
SpriteBase follower = this;
// reset within firing range
withinFiringRange = false;
// rotate towards target
if( target != null)
{
// parts of code used from shane mccartney (http://lostinactionscript.com/page/3/)
double xDist = target.getCenterX() - follower.getCenterX();
double yDist = target.getCenterY() - follower.getCenterY();
this.targetAngle = Math.atan2(yDist, xDist) - Math.PI / 2;
this.currentAngle = Math.abs(this.currentAngle) > Math.PI * 2 ? (this.currentAngle < 0 ? (this.currentAngle % Math.PI * 2 + Math.PI * 2) : (this.currentAngle % Math.PI * 2)) : (this.currentAngle);
this.targetAngle = this.targetAngle + (Math.abs(this.targetAngle - this.currentAngle) < Math.PI ? (0) : (this.targetAngle - this.currentAngle > 0 ? ((-Math.PI) * 2) : (Math.PI * 2)));
this.currentAngle = this.currentAngle + (this.targetAngle - this.currentAngle) / roatationEasing; // give easing when rotation comes closer to the target point
// check if the rotation limit has to be kept
if( (this.targetAngle-this.currentAngle) > this.rotationLimitRad) {
this.currentAngle+=this.rotationLimitRad;
} else if( (this.targetAngle-this.currentAngle) < -this.rotationLimitRad) {
this.currentAngle-=this.rotationLimitRad;
}
follower.r = Math.toDegrees(currentAngle);
// determine if the player ship is within firing range; currently if the player ship is within 10 degrees (-10..+10)
withinFiringRange = Math.abs( Math.toDegrees( this.targetAngle-this.currentAngle)) < 20;
}
super.move();
}
public void checkTarget() {
if( target == null) {
return;
}
if( !target.isAlive() || target.isRemovable()) {
setTarget( null);
return;
}
//get distance between follower and target
double distanceX = target.getCenterX() - getCenterX();
double distanceY = target.getCenterY() - getCenterY();
//get total distance as one number
double distanceTotal = Math.sqrt(distanceX * distanceX + distanceY * distanceY);
if( Double.compare( distanceTotal, targetRange) > 0) {
setTarget( null);
}
}
public void findTarget( List<? extends SpriteBase> targetList) {
// we already have a target
if( getTarget() != null) {
return;
}
SpriteBase closestTarget = null;
double closestDistance = 0.0;
for (SpriteBase target: targetList) {
if (!target.isAlive())
continue;
//get distance between follower and target
double distanceX = target.getCenterX() - getCenterX();
double distanceY = target.getCenterY() - getCenterY();
//get total distance as one number
double distanceTotal = Math.sqrt(distanceX * distanceX + distanceY * distanceY);
// check if enemy is within range
if( Double.compare( distanceTotal, targetRange) > 0) {
continue;
}
if (closestTarget == null) {
closestTarget = target;
closestDistance = distanceTotal;
} else if (Double.compare(distanceTotal, closestDistance) < 0) {
closestTarget = target;
closestDistance = distanceTotal;
}
}
setTarget(closestTarget);
}
public SpriteBase getTarget() {
return target;
}
public void setTarget(SpriteBase target) {
this.target = target;
}
#Override
public void checkRemovability() {
if( Double.compare( health, 0) < 0) {
setTarget(null);
setRemovable(true);
}
}
public boolean hitsTarget( SpriteBase enemy) {
return target == enemy && withinFiringRange;
}
public void updateUI() {
if( withinFiringRange) {
imageView.setEffect(colorAdjust);
} else {
imageView.setEffect(null);
}
super.updateUI();
}
}
The enemy class is easier. It needs only movement. However, in your final version the enemies should consider obstacles during movement. In this example I add a health bar above the enemy to show the health.
import javafx.scene.image.Image;
import javafx.scene.layout.Pane;
public class Enemy extends SpriteBase {
HealthBar healthBar;
double healthMax;
public Enemy(Pane layer, Image image, double x, double y, double r, double dx, double dy, double dr, double health, double damage) {
super(layer, image, x, y, r, dx, dy, dr, health, damage);
healthMax = Settings.ENEMY_HEALTH;
setHealth(healthMax);
}
#Override
public void checkRemovability() {
if( Double.compare( getY(), Settings.SCENE_HEIGHT) > 0) {
setRemovable(true);
}
}
public void addToLayer() {
super.addToLayer();
// create health bar; has to be created here because addToLayer is called in super constructor
// and it wouldn't exist yet if we'd create it as class member
healthBar = new HealthBar();
this.layer.getChildren().add(this.healthBar);
}
public void removeFromLayer() {
super.removeFromLayer();
this.layer.getChildren().remove(this.healthBar);
}
/**
* Health as a value from 0 to 1.
* #return
*/
public double getRelativeHealth() {
return getHealth() / healthMax;
}
public void updateUI() {
super.updateUI();
// update health bar
healthBar.setValue( getRelativeHealth());
// locate healthbar above enemy, centered horizontally
healthBar.relocate(x + (imageView.getBoundsInLocal().getWidth() - healthBar.getBoundsInLocal().getWidth()) / 2, y - healthBar.getBoundsInLocal().getHeight() - 4);
}
}
The health bar
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.StrokeType;
public class HealthBar extends Pane {
Rectangle outerHealthRect;
Rectangle innerHealthRect;
public HealthBar() {
double height = 10;
double outerWidth = 60;
double innerWidth = 40;
double x=0.0;
double y=0.0;
outerHealthRect = new Rectangle( x, y, outerWidth, height);
outerHealthRect.setStroke(Color.BLACK);
outerHealthRect.setStrokeWidth(2);
outerHealthRect.setStrokeType( StrokeType.OUTSIDE);
outerHealthRect.setFill(Color.RED);
innerHealthRect = new Rectangle( x, y, innerWidth, height);
innerHealthRect.setStrokeType( StrokeType.OUTSIDE);
innerHealthRect.setFill(Color.LIMEGREEN);
getChildren().addAll( outerHealthRect, innerHealthRect);
}
public void setValue( double value) {
innerHealthRect.setWidth( outerHealthRect.getWidth() * value);
}
}
And then you need some global settings like this
public class Settings {
public static double SCENE_WIDTH = 1024;
public static double SCENE_HEIGHT = 768;
public static double TOWER_DAMAGE = 1;
public static double PLAYER_SHIP_SPEED = 4.0;
public static double PLAYER_SHIP_HEALTH = 100.0;
public static int ENEMY_HEALTH = 100;
public static int ENEMY_SPAWN_RANDOMNESS = 50;
}
These are the images:
player.png
enemy.png
So summarized the gameplay is for now:
click on the screen to place a tower ( ie a smiley)
when an enemy is in range, the smiley becomes angry (i just change the color to red), in your final version the tower would be firing
as long as the tower is firing at the enemy, the health is reduced. i did it by changing the health bar depending on the health
when the health is depleted, the enemy is killed and the score is updated; you'd have to add an explosion
So all in all it's not so easy to create a tower defense game. Hope it helps as a start.
Heres' a screenshot:
here is a code snippet from my Image class:
class Image{
public int width;
public int height;
public PImage img;
Image(PApplet parent){
width = 512;
height = 512;
img = new PImage();
img = parent.loadImage("test.jpg");
img.resize(width, height);
}
}
I draw it in the main file in such a way:
image(image.img, 287, 280);
I'd like to choose the image having clicked it:
void mousePressed() {
if (gui.btnOver1) {
selectInput("Choose file:", "fileSelected");
}
}
However, I don't know how to use this function in an OOP way:
void fileSelected(File selection) {
if (selection == null) {
println("Window was closed or the user hit cancel.");
} else {
img = loadImage(selection.getAbsolutePath());
img.loadPixels();
}
}
Thanks for help.
what about adding a method to your class like:
class Image{
public int width;
public int height;
public PImage img;
Image(PApplet parent){
width = 512;
height = 512;
img = new PImage();
img = parent.loadImage("test.jpg");
img.resize(width, height);
}
public void loadNew(path){
img = loadImage(path);
// I don't think you need to .updatePixels() after .loadImage()
}
}
Then you use it like that:
void fileSelected(File selection) {
if (selection == null) {
println("Window was closed or the user hit cancel.");
} else {
// assuming you have an 'image' object of the type Image
image.loadNew(selection.getAbsolutePath());
}
}
Note:
It's been a while since I wrote my last line of Processing code and it may be a bit wrong, but it should answer your question
You could even have a function to draw the Image object, rather than calling the property imgof your image,
like that:
// a method of your class
public void draw(int x, int y){
image(img, x, y);
}
and then inside the main draw() you will call
// always your image object here
image.draw(20, 34);
I hope it helps!
I can't align text on the BlackBerry screen. I've tried using a LabelField or a RichTextField but the text is not getting aligned the way I want. It is aligned horizontally and hidden in the screen. I want the text to wrap on the next line, when it hits the end of the screen horizontally, rather than getting hidden.
Here is my code -
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.Font;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.Ui;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.RichTextField;
import net.rim.device.api.ui.component.SeparatorField;
import net.rim.device.api.ui.container.HorizontalFieldManager;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.container.VerticalFieldManager;
public class DetailBloodBank extends MainScreen
{
String resultData = "", location = "", phoneNumber = "";
LabelField bloodBankName, locationLabel, phoneNumLabel;
String bloodBank = "";
LabelField locationDetail, phoneNumDetail;
public DetailBloodBank(String data) {
super(NO_VERTICAL_SCROLL);
int height = Display.getHeight();
int widhth = Display.getWidth();
//SizedVFM horizontalFieldManager = new SizedVFM(widhth,height);
HorizontalFieldManager horizontalFieldManager = new HorizontalFieldManager(HorizontalFieldManager.NO_VERTICAL_SCROLL)
{
protected void paint(Graphics g) {
g.setBackgroundColor(Color.BLACK);
g.clear();
super.paint(g);
}
};
//setBanner(horizontalFieldManager);
resultData = data;
System.out.println(resultData);
bloodBankName = new LabelField(resultData)
{
public void paint(Graphics g) {
g.setColor(Color.WHITE);
super.paint(g);
}
};
Font font = Font.getDefault().derive(Font.BOLD, 8, Ui.UNITS_pt);
bloodBankName.setFont(font);
locationLabel = new LabelField("Location")
{
public void paint(Graphics g) {
g.setColor(Color.WHITE);
super.paint(g);
}
};
Font font2 = Font.getDefault().derive(Font.BOLD, 8, Ui.UNITS_pt);
locationLabel.setFont(font2);
phoneNumLabel = new LabelField("Phone Number")
{
public void paint(Graphics g) {
g.setColor(Color.WHITE);
super.paint(g);
}
};
Font font3 = Font.getDefault().derive(Font.BOLD, 8, Ui.UNITS_pt);
phoneNumLabel.setFont(font3);
DBHelpers dbh = new DBHelpers();
dbh.retrieveDetails(resultData);
location = dbh.getLocation();
phoneNumber = dbh.getPhoneNumber();
dbh.getConnectionClose();
phoneNumDetail = new LabelField(phoneNumber)
{
public void paint(Graphics g) {
g.setColor(Color.WHITE);
super.paint(g);
}
};
Font font4 = Font.getDefault().derive(Font.PLAIN, 6, Ui.UNITS_pt);
phoneNumDetail.setFont(font4);
locationDetail = new LabelField(location)
{
public void paint(Graphics g) {
g.setColor(Color.WHITE);
super.paint(g);
}
};
Font font5 = Font.getDefault().derive(Font.PLAIN, 6, Ui.UNITS_pt);
locationDetail.setFont(font5);
final SeparatorField sepfield2 = new SeparatorField(SeparatorField.LINE_HORIZONTAL | Field.USE_ALL_WIDTH)
{
protected void paint(Graphics g) {
g.setBackgroundColor(Color.WHITE);
g.clear();
super.paint(g);
}
protected void layout(int maxWidth, int maxHeight) {
int width = Display.getWidth();
int height = 25; //height of the manager
super.layout(1250, 15);
}
};
final VerticalFieldManager verticalFieldManager = new VerticalFieldManager(NO_HORIZONTAL_SCROLL);
verticalFieldManager.add(locationLabel);
verticalFieldManager.add(locationDetail);
final VerticalFieldManager verticalFieldManager2 = new VerticalFieldManager(NO_HORIZONTAL_SCROLL);
verticalFieldManager2.add(phoneNumLabel);
verticalFieldManager2.add(phoneNumDetail);
VerticalFieldManager routeManager2 = new VerticalFieldManager()
{
protected void sublayout(int width, int height) {
layoutChild(bloodBankName, getPreferredWidth(), getPreferredHeight());
layoutChild(sepfield2, getPreferredWidth(), getPreferredHeight());
layoutChild(verticalFieldManager, getPreferredWidth(), getPreferredHeight());
layoutChild(verticalFieldManager2, getPreferredWidth(), getPreferredHeight());
setPositionChild(bloodBankName, 5, 15);
setPositionChild(sepfield2, 0, 35);
setPositionChild(verticalFieldManager, 0, 72);
int y = verticalFieldManager.getHeight();
System.out.println(y);
setPositionChild(verticalFieldManager2, 0, y + 90);
super.setExtent(width, height);
}
};
routeManager2.add(bloodBankName);
routeManager2.add(sepfield2);
routeManager2.add(verticalFieldManager);
routeManager2.add(verticalFieldManager2);
horizontalFieldManager.add(routeManager2);
add(horizontalFieldManager);
}
}
The problem is with your layout logic in routeManager2.
layoutChild(bloodBankName, getPreferredWidth(), getPreferredHeight());
The preferred width of the LabelField or RichTextField is going to be the width of the String associated with it in the current font size. It would prefer to show everything on one line if possible. So, instead of passing its preference, pass the width provided to sublayout(int, int).
layoutChild(bloodBankName, width, getPreferredHeight());
Hope this helps.
I'm creating a simple blackberry application for testing purposes and my custom buttons do not show on the UI of the simulator.
I've created a custom button called CustomButtonField and here is the code:
package test.expense;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Graphics;
public class CustomButtonField extends Field {
String label;
int backgroundColor;
int foregroundColor;
public CustomButtonField(String label, int backgroundColor, int foregroundColor, long style){
super(style);
this.label = label;
this.backgroundColor = backgroundColor;
this.foregroundColor = foregroundColor;
}
public int getPreferedHeight(){
return getFont().getHeight() + 8;
}
public int getPreferedWidth(){
return getFont().getAdvance(label) + 8;
}
protected void layout(int width, int height) {
setExtent(Math.min(width, getPreferredWidth()), Math.min(height, getPreferredHeight()));
}
protected void paint(Graphics graphics) {
graphics.setColor(backgroundColor);
graphics.fillRoundRect(1, 1, getWidth()-2, getHeight()-2, 12, 12);
graphics.setColor(foregroundColor);
graphics.drawText(label, 4, 4);
}
}
And here is where I invoke it and display it:
HorizontalFieldManager buttonManager = new HorizontalFieldManager(FIELD_RIGHT);
CustomButtonField btnCancel;
CustomButtonField btnSubmit;
public ExpenseSheetScreen() {
super();
btnCancel = new CustomButtonField("Cancel", Color.WHITE, 0x716eb3, 0);
btnCancel.setChangeListener(this);
btnSubmit = new CustomButtonField("Submit", Color.WHITE, 0x716eb3, 0);
btnSubmit.setChangeListener(this);
buttonManager.add(btnCancel);
buttonManager.add(btnSubmit);
add(buttonManager);
}// End Expense Sheet Screen.
What am I doing wrong?
protected void layout(int width, int height) {
setExtent(Math.min(width, getPreferredWidth()),
Math.min(height, getPreferredHeight()));
}
setExtend is set to 0, 0 all the time.
I need to display a custom icon and two hyperlinks in model pop up on Blackberry map. How can I do this?
alt text http://img689.imageshack.us/img689/2886/maplinkicon.jpg
First implement extention of ButtonField which will:
look like icon
on click will open Browser with predefined link
will use context menu
Code for such control:
class MapLinkIcon extends ButtonField implements FieldChangeListener {
Bitmap mNormal;
Bitmap mFocused;
String mLink;
String mDescription;
int mWidth;
int mHeight;
public MapLinkIcon(Bitmap normal, Bitmap focused, String link,
String description) {
super(CONSUME_CLICK);
mNormal = normal;
mFocused = focused;
mLink = link;
mDescription = description;
mWidth = mNormal.getWidth();
mHeight = mNormal.getHeight();
setMargin(0, 0, 0, 0);
setPadding(0, 0, 0, 0);
setBorder(BorderFactory.createSimpleBorder(new XYEdges(0, 0, 0, 0)));
setBorder(VISUAL_STATE_ACTIVE, BorderFactory
.createSimpleBorder(new XYEdges(0, 0, 0, 0)));
this.setChangeListener(this);
}
protected void paint(Graphics graphics) {
Bitmap bitmap = null;
switch (getVisualState()) {
case VISUAL_STATE_NORMAL:
bitmap = mNormal;
break;
case VISUAL_STATE_FOCUS:
bitmap = mFocused;
break;
case VISUAL_STATE_ACTIVE:
bitmap = mFocused;
break;
default:
bitmap = mNormal;
}
graphics.drawBitmap(0, 0, bitmap.getWidth(), bitmap.getHeight(),
bitmap, 0, 0);
}
public int getPreferredWidth() {
return mWidth;
}
public int getPreferredHeight() {
return mHeight;
}
protected void layout(int width, int height) {
setExtent(mWidth, mHeight);
}
protected void applyTheme(Graphics arg0, boolean arg1) {
}
public void fieldChanged(Field field, int context) {
openLink(mLink);
}
MenuItem mMenuItem = new MenuItem("Go To Link", 0, 0) {
public void run() {
openLink(mLink);
}
};
protected void makeContextMenu(ContextMenu contextMenu) {
super.makeContextMenu(contextMenu);
contextMenu.addItem(mMenuItem);
}
private static void openLink(String link) {
Browser.getDefaultSession().displayPage(link);
}
}
Now we can use this button control in combination with MapField, override sublayout to place button over the map:
class CustomMapField extends VerticalFieldManager {
MapField mMapField;
MapLinkIcon mButton;
public CustomMapField() {
add(mMapField = new MapField());
}
public int getPreferredHeight() {
return getScreen().getHeight();
}
public int getPreferredWidth() {
return getScreen().getWidth();
}
public void moveTo(Coordinates coordinates, Bitmap icoNorm, Bitmap icoAct,
String link, String description) {
mMapField.moveTo(coordinates);
add(mButton = new MapLinkIcon(icoNorm, icoAct, link, description));
}
protected void sublayout(int maxWidth, int maxHeight) {
int width = getPreferredWidth();
int height = getPreferredHeight();
layoutChild(mMapField, width, height);
setPositionChild(mMapField, 0, 0);
layoutChild(mButton, mButton.mWidth, mButton.mHeight);
XYPoint fieldOut = new XYPoint();
mMapField.convertWorldToField(mMapField.getCoordinates(), fieldOut);
int xPos = fieldOut.x - mButton.mWidth / 2;
int yPos = fieldOut.y - mButton.mHeight;
setPositionChild(mButton, xPos, yPos);
setExtent(width, height);
}
}
Example of use:
class Scr extends MainScreen {
CustomMapField mMapField;
Coordinates mCoordinates;
public Scr() {
double latitude = 51.507778;
double longitude = -0.128056;
mCoordinates = new Coordinates(latitude, longitude, 0);
mMapField = new CustomMapField();
Bitmap icoNormal = Bitmap.getBitmapResource("so_icon_normal.png");
Bitmap icoActive = Bitmap.getBitmapResource("so_icon_active.png");
String link = "http://stackoverflow.com";
String description = "StackOverflow";
mMapField.moveTo(mCoordinates, icoNormal, icoActive, link, description);
add(mMapField);
}
}
See also:
How to show our own icon in BlackBerry Map?
How to show more than one location in Blackberry MapField?