want to animate my logo by zooming it to an splash screen.
tried the following so far:
#Override
protected void postSpash1(Form f) {
findLogoLabel(f).setPreferredW(findLogoLabel(f).getPreferredW() * 5);
findAnimateContainer(f).animateLayoutAndWait(2000);
findLogoLabel(f).setPreferredSize(null);
}
The image doesn't animate and enlarges itself. However it changes its size abruptly after 2 sec which is not what I'm looking for. I want the zooming effect(the img should grow bigger slowly to a certain extent)
I tried other ways too, but the label moves from up to down smoothly instead of bg img getting bigger
findLogoLabel(f).setPreferredH(findLogoLabel(f).getPreferredH() * 3);
findAnimateContainer(f).animateLayoutAndWait(2000);
findLogoLabel(f).setPreferredSize(null);
PS: I set the bg image in logoLabel (Label) , Animatecontainer is the container that contains logoLabel.
Blocking API's are somewhat tricky as they might collide with some other behaviors preventing the rest of the current dispatch thread from finishing its job.
Also you set the null after animating instead of before...
So in your case this should work (with old Java 5 syntax):
#Override
protected void postSpash1(final Form f) {
findLogoLabel(f).setPreferredW(findLogoLabel(f).getPreferredW() * 5);
Display.getInstance().callSerially(new Runnable() {
public void run() {
findLogoLabel(f).setPreferredSize(null);
findAnimateContainer(f).animateLayoutAndWait(2000);
}
});
}
With cool Java 8 lambdas:
#Override
protected void postSpash1(final Form f) {
findLogoLabel(f).setPreferredW(findLogoLabel(f).getPreferredW() * 5);
Display.getInstance().callSerially(() -> {
findLogoLabel(f).setPreferredSize(null);
findAnimateContainer(f).animateLayoutAndWait(2000);
});
}
Related
I'm working on a vertical scrolling game, and I'm using a thread to generate new enemies every 2 seconds. Each enemy is an image in a JPanel. For some reason, The generated enemies are not showing up in the JFrame, but they are present. When the player collides with one of the enemies, all the enemies show up.
Here's the code:
private void checkCollision() {
for(AlienShip as : enemies) {
if(player.getBounds().intersects(as.getBounds()))
player.setVisible(false);
}
}
private void setAlien() {
alien = new AlienShip();
add(alien);
enemies.add(alien);
System.out.println("Enemies: " + enemies.size());
}
public Thread alienGenerator() {
for(int i = 0; i < 3; i++) { // these are being drawn
setAlien();
}
return new Thread(new Runnable() {
#Override
public void run() {
int sleepTime = 2000;
while(true) {
try {
Thread.sleep(sleepTime);
} catch(InterruptedException e) {
System.out.println(e);
}
setAlien(); //these aren't
}
}
});
}
private void gameLoop() {
alienGenerator().start();
mainTimer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
repaint();
checkCollision();
}
});
mainTimer.start();
}
It always seems that you're Darned If You Do And Darned If You Don't. As far as I'm concerned the code you had placed in your earlier post was adequate, as a matter of fact, it was still lacking (no PlayerShip Class). The code example in this post does even less justice. Never the less......
Before I get started I just want you to know that I personally would have tackled this task somewhat differently and the meager assistance provided here will be solely based on the code you have already provided in this and previous posts.
The reason you are not seeing your Alien Ships displaying onto the Game Board upon creation is because you don't revalidate the board panel. As you currently have your code now this can be done from within the Board.setAlien() method where the Alien Ships are added. Directly under the code lines:
alien = new AlienShip();
add(alien);
enemies.add(alien);
add the code line: revalidate();, so the code would look like this:
alien = new AlienShip();
add(alien);
enemies.add(alien);
revalidate();
Your Alien Ships should now display.
On A Side Note:
What is to happen when any Alien Ship actually makes it to the bottom of the Game Board? As a suggestion, have them re-spawn to the top of the game board (serves ya right fer missin em). This can be done from within the AlienShip.scrollShip() method by checking to see if the Alien Ship has reached the bottom of the board, for example:
public void scrollShip() {
if (getY() + 1 > this.getParent().getHeight()) {
setY(0 - PANEL_HEIGHT);
}
else {
setY(getY() + 1);
}
}
In my opinion, PANEL_HEIGHT is the wrong field name to use. I think it would be more appropriate to use something like ALIEN_SHIP_WIDTH and ALIEN_SHIP_HEIGHT. Same for the variables panelX and panelY, could be alienShipX and alienShipY. Food for thought.
As you can see in the code above the current Game Board height is acquired by polling the Game Board's getHeight() method with: this.getParent().getHeight(). This allows you to change the Game Board size at any time and the Alien Ships will know where that current boundary is when scrolling down. All this then means that the setResizable(false); property setting done in the Main Class for the Game's JFrame window can now be resizable: setResizable(true);.
You will also notice that when the Alien Ship is re-spawned at top of the Game Board it is actually out of site and it flows into view as it moves downward. I think this is a much smoother transition into the gaming area rather than just popping into view. This is accomplished with the setY(0 - PANEL_HEIGHT); code line above. As a matter of fact even when the game initially starts, your Alien Ships should flow into the the gaming area this way and that can be done from within the AlienShip.initAlienShip() method by initializing the panelY variable to panelY = -PANEL_HEIGHT;.
This now takes me to the initialization of the PANEL_WIDTH and PANEL_HEIGHT fields. The values seem enormous (224 and 250 respectively). Of course you may have set to these sizes for collision testing purposes, etc but I think an image size of 64 x 35 would most likely suffice:
This image should be a PNG image with a transparent background which then eliminates the need for the setBackground(Color.BLUE); code line located within the AlienShip.initAlienShip() method.
The AlienShip.getX() and AlienShip.getY() methods should be overridden:
#Override
public int getX() { ... }
#Override
public int getY() { ... }
I think extending the AlienShip Class to JLabel would be better than to JPanel. To JPanel seems like overkill:
public class AlienShip extends JLabel { ... }
Adding a background image to the Game Board can add pizazz to the game. This can be achieved by adding the following code to the Board.paintComponent() method:
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
ImageIcon imgIcon = new ImageIcon("images/StarBackground.png");
Image img = imgIcon.getImage();
g.drawImage(img, 0, 0, this.getSize().width, this.getSize().height, this);
}
Images can be acquired here.
This should keep you going for a while. Before to long it'll be Alien mayhem.
it's my first time posting and I'm self taught so be please gentle!
I've been building a bomberman replica game in libGDX using Game and Screen classes:
public class Main extends Game {
...
#Override
public void create() {
levelScreen = new LevelScreen(playerCount, new int[playerCount]);
levelScreen.level.addAction(Actions.sequence(Actions.alpha(0), Actions.fadeIn(2f)));
this.setScreen(levelScreen);
}
However when the game launches there is no fade effect.
public class LevelScreen implements Screen {
...
#Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 0.1f, 0.5f, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
level.act();
level.draw();
batch.end();
}
I want this levelScreen to fade in from black but it just doesn't!
When the round is over I want to fadeOut of this levelScreen to black, then fadeIn to a trophyScreen from black:
(From Main Class)
#Override
public void render() {
super.render();
if (endRoundTimer <= 0) {
trophyScreen = new TrophyScreen(playerCount, levelScreen.getScore());
levelScreen.level.addAction(Actions.sequence(Actions.fadeOut(1), Actions.run(new Runnable() {
#Override
public void run() {
setScreen(trophyScreen);
}
})));
}
}
And I've tried using the show() method in the TrophyScreen:
public class TrophyScreen implements Screen {
...
#Override
public void show() {
stage.addAction(Actions.sequence(Actions.alpha(0), Actions.fadeIn(1)));
}
I've done loads of searching and tried various things but no joy. I'm sure I'm missing something somewhere in a draw() or render() method that is preventing the fade Action from taking place.
UPDATE1
#Override public void draw() {
super.draw();
if (roundOver) {
this.getBatch().begin(); String s = String.format("%s", message);
font_text.draw(this.getBatch(), s, (90 + (2 * 30)), (this.getHeight() / 2));
this.getBatch().end();
}
For fading to work on actors, they must properly apply their own color's alpha in the draw method. And for an entire hierarchy of objects to fade at once, they must all also apply the parentAlpha parameter from the draw method signature.
So your draw method in any custom Actor subclass should look like this:
public void draw (Batch batch, float parentAlpha) {
Color color = getColor();
batch.setColor(color.r, color.g, color.b, color.a * parentAlpha);
//..do drawing
}
If you are using a Sprite in your Actor instead of a TextureRegion (which I don't recommend due to redundancies) you must apply the color to the Sprite instead of Batch.
Note that this method of fading the whole game is not a "clean" fade. Any actors that are overlapping other actors will show through each other when the parent alpha is less than 1 during the fade. An alternative that would provide a clean-looking fade would be to draw a copy of your background (or black) over your entire scene and fade that instead.
I assume that level is an object of class that extends Stage and you are creating a control inside the stage, which is weird. You are not appling color to your font_text which I assume it is a BitmapFont
Solution, the weird way
If you want to do it in this way you will need something like that:
#Override public void draw() {
super.draw();
if (roundOver) {
getBatch().begin();
String s = String.format("%s", message);
font_text.setColor(getRoot().getColor())
font_text.draw(this.getBatch(), s, (90 + (2 * 30)), (this.getHeight() / 2));
getBatch().end();
}
}
getRoot() gets Group from Stage, we do it, because every action applied to Stage is actually applied to this Group root element. We get color (which has alpha channel) and we copy the color to the bitmapFont.
This solution is weird, because you are actually creating an Label inside Stage. It is pointless, actors plays on stage, not inside.
Solution, the good way
You want to draw text, right? So just use Label which is an actor, who shows a text. Actors do jobs for you:
stage = new Stage();
Label.LabelStyle labelStyle = new Label.LabelStyle(bitmapFont, Color.WHITE);
Label label = new Label("Hi, I am a label!", labelStyle);
stage.addActor(label);
Then you can apply actions and they will work fine (and every actor can have own actions applied).
stage.addAction(Actions.sequence(Actions.alpha(0), Actions.fadeIn(5)));
label.addAction(Actions.moveBy(0, 300, 15));
There is a lot of different actors like TextButton, Image, ScrollPane. They are customizable, easy to manage and they can be integrated in groups and tables.
Output:
A better way would be to just start by drawing a black image over everything, so you don't have to mess with every scene object's alpha. Use layering to do that. This post may be helpful.
Then you can control it's alpha channel, change it's rendering to 0 right before unpausing the game action to get it's drawing cycles back. Reactivate it on stage ending for your fade out effect.
Thank you cray, it's way better like this.
So I have seven panels of different colors that need to be rotated in order. My code is working well for the most part but the first and last panels always have same color. How do I fix this?
I have already checked that each of my panels have a different color upon start.
Code:
public void run()
{
TimerTask colorAction = new TimerTask(){
public void run()
{
redPanel.setBackground(orangePanel.getBackground());
orangePanel.setBackground(yellowPanel.getBackground());
yellowPanel.setBackground(greenPanel.getBackground());
greenPanel.setBackground(bluePanel.getBackground());
bluePanel.setBackground(indigoPanel.getBackground());
indigoPanel.setBackground(violetPanel.getBackground());
violetPanel.setBackground(redPanel.getBackground());
}
};
java.util.Timer utilTimer = new java.util.Timer();
utilTimer.scheduleAtFixedRate(colorAction, START_AFTER, DELAY );
}
Snapshot (before change):
Snapshot (after change)
The basic problem, other then the fact that you are violating the single thread rules of Swing, is you are relying on a value from component whose background has already changed...
violetPanel.setBackground(redPanel.getBackground());
redPanel's background is now set to orangePanel background by the time you call this.
Instead, first grab redPanel's background color before you change anything, then apply it to violetPanel
Color redBackground = redPanel.getBackground();
redPanel.setBackground(orangePanel.getBackground());
//...
violetPanel.setBackground(redBackground);
Take a look (and get your teacher to do the same) at Concurrency in Swing and How to Use Swing Timers for more details...
If you MUST use a java.util.Timer, you should be wrapping your changes to UI in an invokeLater call, for example...
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Color redBackground = redPanel.getBackground();
redPanel.setBackground(orangePanel.getBackground());
//...
violetPanel.setBackground(redBackground);
}
});
Optional Ref (Regarding bulding gui and widgets in java)
AS said here i am making a simple clock widget. I chose SWt because i found it easier to learn and implement. The widget consists of several layers of concentric circles to impart different colors to each layer. The color of each layer depends on the time of the day and is controlled by a color function. The layers are ready but color function still needs to be made.
I was going through the docs of Java and found that all graphic objects ( like rectangles and circles) must be manually disposed to free system resources. Now my basic problem is this :
Basically i want the widget to run indefinitely until the window containing widget is closed( because there is a minute layer and hour layer which change colors).
How will i free the system resources and will the widget be a memory monster coz of infinteness ? Please answer with ref to Swt.
Additionally i wanted to know if this tyoe of animation strategy is suitable for this widget ? If not please suggest other alternatives keeping in mind my beginner level.
For the clock you need:
A widget to display the time (for example org.eclipse.swt.widgets.Canvas with a PaintListener to draw the clock)
A (daemon) thread which redraws your clock each second. The redraw call must be delegated to the EDT (event dispatch thread)
The thread should run as long as your widget isn't disposed.
To clean up any resources (fonts, colors, etc.) when your widget is disposed, use DisposeListener.
Code template:
public class ClockWidget extends Canvas {
public ClockWidget (Composite parent, int style) {
super(parent, style | SWT.DOUBLE_BUFFERED);
addPaintListener(new PaintListener() {
#Override
public void paintControl (PaintEvent e) {
GC gc = e.gc;
// paint clock on the graphics context
}
});
addDisposeListener(new DisposeListener() {
#Override
public void widgetDisposed (DisposeEvent e) {
// dispose all fonts and colors you created
}
});
final Display display = Display.getCurrent();
Thread timer = new Thread() {
#Override
public void run () {
while (!isDisposed()) {
display.syncExec(new Runnable() {
#Override
public void run () {
if (!isDisposed()) {
redraw();
}
}
});
long msToNextSec = 1000 - (System.currentTimeMillis() % 1000);
try {
Thread.sleep(msToNextSec);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
timer.setPriority(Thread.MIN_PRIORITY);
timer.setDaemon(true);
timer.start();
}
}
Using GWT I am displaying an image thumbnail with a ClickHandler that then shows the full image (can be several MB) in a centered PopupPanel. In order to have it centered the image must be loaded before the popup is shown, otherwise the top-left corner of the image is placed in the middle of the screen (the image thinks it is 1px large). This is the code I am using to do this:
private void showImagePopup() {
final PopupPanel popupImage = new PopupPanel();
popupImage.setAutoHideEnabled(true);
popupImage.setStyleName("popupImage"); /* Make image fill 90% of screen */
final Image image = new Image();
image.addLoadHandler(new LoadHandler() {
#Override
public void onLoad(LoadEvent event) {
popupImage.add(image);
popupImage.center();
}
});
image.setUrl(attachmentUrl + CFeedPostAttachment.ATTACHMENT_FILE);
Image.prefetch(attachmentUrl + CFeedPostAttachment.ATTACHMENT_FILE);
}
However, the LoadEvent event is never fired, and thus the image is never shown. How can I overcome this? I want to avoid using http://code.google.com/p/gwt-image-loader/ because I do not want to add extra libraries if I can avoid it at all. Thanks.
The onLoad() method will only fire once the image has been loaded into the DOM. Here is a quick workaround:
...
final Image image = new Image(attachmentUrl + CFeedPostAttachment.ATTACHMENT_FILE);
image.addLoadHandler(new LoadHandler() {
#Override
public void onLoad(LoadEvent event) {
// since the image has been loaded, the dimensions are known
popupImage.center();
// only now show the image
popupImage.setVisible(true);
}
});
popupImage.add(image);
// hide the image until it has been fetched
popupImage.setVisible(false);
// this causes the image to be loaded into the DOM
popupImage.show();
...
Hope that helps.