Slick Forums

Discuss the Slick 2D Library
It is currently Sun May 19, 2013 4:44 pm

All times are UTC




Post new topic Reply to topic  [ 14 posts ] 
Author Message
PostPosted: Thu May 29, 2008 8:28 am 
Offline
Game Developer
User avatar

Joined: Sun May 25, 2008 9:45 am
Posts: 578
I think a cross fade transition would be neat. One GameState fades out while the other is drawn under the first. I messed around trying to get it to work for a while but it wasn't as easy as I first thought. :oops:

This would be neat to combine with any of the other effects. Eg, the GameState that is fading out could enlarge as it fades (too bad there isn't an "enlarge" trasition though! hmmm ;)).


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 29, 2008 9:02 am 
Offline
Site Admin
User avatar

Joined: Thu Jan 01, 1970 12:00 am
Posts: 3143
http://slick.cokeandcode.com/javadoc/or ... ition.html

Does the transition test have anything similar to what you wanted?

Kev


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 29, 2008 9:58 am 
Offline
Game Developer
User avatar

Joined: Sun May 25, 2008 9:45 am
Posts: 578
Not really. What I tried initially was using that class and FadeOutTransition. What happend was the first GameState renders, then the second GameState renders on top of the first, then the FadeOutTransition draws a translucent black box on top of that. Obviously not the desired effect! :) I'm not sure what the most efficient way is to make the second GameState render translucent?


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 29, 2008 10:41 am 
Offline
Site Admin
User avatar

Joined: Thu Jan 01, 1970 12:00 am
Posts: 3143
I'm not sure I really understand what you want. However, I think I get it :)

You'd need to render the first state to a texture (Image the size of the screen) and then use this image as an overlay when rendering the next state.
This would be reasonably efficient but you'd need a texture the size of the screen which some cards won't support.

Kev


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 30, 2008 9:05 am 
Offline
Game Developer
User avatar

Joined: Sun May 25, 2008 9:45 am
Posts: 578
Played around a bit. Here is what I came up with...
Code:
/**
* @author Nathan Sweet <misc@n4te.com>
*/
public class CrossFadeTransition implements Transition {
   private GameState firstState;
   private GameState secondState;
   private FadeOutTransition fade;

   public CrossFadeTransition (int fadeMillis) {
      fade = new FadeOutTransition(Color.black, fadeMillis);
   }

   public void init (GameState firstState, GameState secondState) {
      this.firstState = firstState;
      this.secondState = secondState;
   }

   public void preRender (StateBasedGame game, GameContainer container, Graphics g) throws SlickException {
   }

   public void postRender (StateBasedGame game, GameContainer container, Graphics g) throws SlickException {
      firstState.render(container, game, g);
      g.clearAlphaMap();
      g.setDrawMode(Graphics.MODE_ALPHA_MAP);
      fade.postRender(game, container, g);
      g.setDrawMode(Graphics.MODE_ALPHA_BLEND);
      secondState.render(container, game, g);
      g.setDrawMode(Graphics.MODE_NORMAL);
   }

   public void update (StateBasedGame game, GameContainer container, int delta) throws SlickException {
      fade.update(game, container, delta);
   }

   public boolean isComplete () {
      return fade.isComplete();
   }
}


1) Is this an efficient way to achieve my goal? I messed with writing to an Image, but couldn't get the Image to be transparent when drawn. I found g.drawImage(Image, int, int, Color) tints the image the specified Color, but doesn't draw the image with transparency.

2) Since it messes with the graphics context, should it be in a SlickCallable safe block?

Notice I didn't use CrossStateTransition. I found it to just get in the way more than anything.

Overall, something seems not right with the transition API. Once you start to call render on GameState's you lose the ability to chain transiitions. Eg, take this transition...
Code:
/**
* @author Nathan Sweet <misc@n4te.com>
*/
public class EnlargeTransition implements Transition {
   private static SGL GL = Renderer.get();

   private int fadeMillis;
   private float percentComplete, enlargedPercent;
   private GameState firstState;
   private GameState secondState;

   public EnlargeTransition (int fadeMillis, float enlargedPercent) {
      this.fadeMillis = fadeMillis;
      this.enlargedPercent = enlargedPercent;
   }

   public void init (GameState firstState, GameState secondState) {
      this.firstState = firstState;
   }

   public void preRender (StateBasedGame game, GameContainer container, Graphics g) throws SlickException {
   }

   public void postRender (StateBasedGame game, GameContainer container, Graphics g) throws SlickException {
      float enlargeFactor = (enlargedPercent * percentComplete) + 1;
      int normalWidth = container.getWidth();
      int normalHeight = container.getHeight();
      int enlargedWidth = (int)(normalWidth * enlargeFactor);
      int enlargedHeight = (int)(normalHeight * enlargeFactor);
      int offsetX = (normalWidth - enlargedWidth) / 2;
      int offsetY = (normalHeight - enlargedHeight) / 2;
      SlickCallable.enterSafeBlock();
      GL.glTranslatef(offsetX, offsetY, 0);
      GL.glScalef(enlargeFactor, enlargeFactor, 0);
      GL.glPushMatrix();
      firstState.render(container, game, g);
      GL.glPopMatrix();
      SlickCallable.leaveSafeBlock();
   }

   public void update (StateBasedGame game, GameContainer container, int delta) throws SlickException {
      percentComplete += delta * (1.0f / fadeMillis);
      if (percentComplete > 1) percentComplete = 1;
   }

   public boolean isComplete () {
      return percentComplete >= 1;
   }
}
What happens if I want to use these two transitions so the resulting transition fades out as it enlarges? From what I can see, it just doesn't work with the current API.

It is just a rough idea right now, but what about a system like this... if there is a leaveTransition, StateBasedGame#render() calls Transition#render() *instead* of the GameState#render(). Transition#render() takes an argument of type Transition. The GameState is wrapped in a Transition that just calls GameState#render. That wrapper Transition is wrapped in the leaveTransition. The leaveTransition does what it needs, then calls render on it's Transition, which calls render on the GameState. This way any number of Transitions could be layered and all could manipulate the graphics context before or after the GameState is rendered.

See any holes in the approach? Might it be a problem if some implementations of GameState#render undo changes made to the graphics context by the transitions before rendering the GameState?

BUG: CombinedTransition doesn't call init() on the list of transitions. Missing code:
Code:
public void init (GameState firstState, GameState secondState) {
   for (int i = transitions.size() - 1; i >= 0; i--) {
      ((Transition)transitions.get(i)).init(firstState, secondState);
   }
}


BTW, here is a test for the transitions above...
Code:
public class CrossFadeTest extends StateBasedGame {
   private GameState state1 = new SimpleState(1, "testdata/wallpaper/paper1.png");
   private GameState state2 = new SimpleState(2, "testdata/wallpaper/paper2.png");

   public CrossFadeTest () {
      super("CrossFadeTest");
   }

   public void initStatesList (GameContainer container) throws SlickException {
      addState(state1);
      addState(state2);
   }

   public void keyPressed (int key, char c) {
      Transition transition = new CrossFadeTransition(2000);
      // Transition transition = new EnlargeTransition(2000, 1.3f);
      switch (key) {
      case Input.KEY_1:
         enterState(state1.getID(), transition, null);
         break;
      case Input.KEY_2:
         enterState(state2.getID(), transition, null);
         break;
      }
   }

   public static void main (String[] args) throws Exception {
      CanvasGameContainer container = new CanvasGameContainer(new CrossFadeTest());
      container.setSize(512, 512);
      JFrame frame = new JFrame("CrossFadeTest");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.add(container);
      frame.pack();
      frame.setVisible(true);
      container.start();
   }

   static private class SimpleState extends BasicGameState {
      private final int id;
      private final String imageRef;
      private Image image;

      public SimpleState (int id, String imageRef) {
         this.id = id;
         this.imageRef = imageRef;

      }

      public int getID () {
         return id;
      }

      public void init (GameContainer container, StateBasedGame game) throws SlickException {
         image = new Image(imageRef);
      }

      public void render (GameContainer container, StateBasedGame game, Graphics g) throws SlickException {
         g.drawImage(image, 0, 0);
      }

      public void update (GameContainer container, StateBasedGame game, int delta) throws SlickException {
      }
   }
}


Edit: CrossFadeTransition works fine in the test, but when fading between 2 black screens that have white text, the screen I'm fading to looks like crap. The white text is very thick until the transition is over. Blah... sleepy time...


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jun 04, 2008 10:58 pm 
Offline
Site Admin
User avatar

Joined: Thu Jan 01, 1970 12:00 am
Posts: 3143
Fixed the bug. No ideas about what to do about the rest.

Kev


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jun 04, 2008 11:44 pm 
Offline
Game Developer
User avatar

Joined: Sun May 25, 2008 9:45 am
Posts: 578
:lol:

What I really wanted was a cross fade transition. Not sure what the best way to implement that is. The above way my try.

While doing that, I had this idea for a revamp of the transition system. What do you think?
Quote:
It is just a rough idea right now, but what about a system like this... if there is a leaveTransition, StateBasedGame#render() calls Transition#render() *instead* of the GameState#render(). Transition#render() takes an argument of type Transition. The GameState is wrapped in a Transition that just calls GameState#render. That wrapper Transition is wrapped in the leaveTransition. The leaveTransition does what it needs, then calls render on it's Transition, which calls render on the GameState. This way any number of Transitions could be layered and all could manipulate the graphics context before or after the GameState is rendered.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 19, 2009 7:15 am 
Offline
Game Developer
User avatar

Joined: Sun May 25, 2008 9:45 am
Posts: 578
I am rewriting SingSong from scratch to clean up some things and move to TWL and I revisited the transition issues I was having. I thought I'd post a bit about where I varied from StateBasedGame. I can post the code, though some of it is specific to my game.

I ended up using a list of transitions instead of just one. This allows me to do something like fade + enlarge + spin.

I made my transition base class time based so subclasses don't have the same boilerplate. I can't think of a transition that isn't time based, but subclasses can ignore the functionality.

I have a flag so the transition knows whether it is being used for exit or enter and the base class automatically reverses the percent complete. This saves writing the reverse transition (eg fade in/out).

I allow transitions to be reset. This lets you pass in one list of transitions to be used for exit and enter and they will be reset in between.

I don't have my equivalent to StateBasedGame handle input. Instead, I add the current state as an input listener. I found it important to not allow a state to get input while a transition is in progress.

I have notification methods on my state class for enterTransition, enter, exitTransition, and exit. I found I need to know when entering a state so I can set things up to be drawn during the enter transition, and I also need to know when the enter transition is over.

I don't have the StateBasedGame keep a list of states. Instead I pass the one I want to change to in. The StateBasedGame inits it only the first time. This gives a little more flexibility for adding and removing states.

Here is a little example:
Code:
List<Transition> exit = new ArrayList();
exit.add(new FadeTransition(2000, Color.black));
exit.add(new EnlargeTransition(1000, 2));

List<Transition> enter = new ArrayList();
enter.add(new FadeTransition(2000, Color.black));
enter.add(new DelayTransition(1000, new EnlargeTransition(1000, 2)));

game.setScreen(m, exit, enter);

The DelayTransition delegates to the wraper transition once its time has expired.

I would still like to have a crossfade transition. I am worried that writing the whole screen to an image won't work for some users. Is there a way to do this safely, so if a user's hardware can't handle it it fails gracefully?

_________________
SingSong Karaoke - http://singthegame.com


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 19, 2009 12:58 pm 
Offline
Game Developer
User avatar

Joined: Sun May 25, 2008 9:45 am
Posts: 578
Hey I found a way that seems to work! If we change Color#bind to this:
Code:
public void bind() {
   GL.glColor4f(r,g,b,moo * a);
}

Then I can set moo < 1 and render a state on top of the current state without messing up transparency like using an alpha map does. What do you think about adding a method on Graphics that does this?

_________________
SingSong Karaoke - http://singthegame.com


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 19, 2009 1:05 pm 
Offline
Site Admin
User avatar

Joined: Thu Jan 01, 1970 12:00 am
Posts: 3143
That'll only work where other binds don't override.

Kev


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 19, 2009 1:09 pm 
Offline
Game Developer
User avatar

Joined: Sun May 25, 2008 9:45 am
Posts: 578
In a Slick app hopefully that doesn't happen, or is at least in my control...

It seems like a simple thing I want to do, equivalent to Java2D's AlphaComposite. :x

_________________
SingSong Karaoke - http://singthegame.com


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 20, 2009 5:35 am 
Offline
Game Developer
User avatar

Joined: Sun May 25, 2008 9:45 am
Posts: 578
I implemented this like...

public static float scale;

...in my local Slick. 8)

_________________
SingSong Karaoke - http://singthegame.com


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 25, 2009 8:58 pm 
Offline
Site Admin
User avatar

Joined: Thu Jan 01, 1970 12:00 am
Posts: 3143
Added Renderer.getRenderer().setGlobalAlphaScale() which should effect
any Slick call even outside of Color.bind().

Kev


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 20, 2009 5:35 am 
Offline
Game Developer
User avatar

Joined: Sun May 25, 2008 9:45 am
Posts: 578
Sweet! I can remove my hack now. :)

_________________
SingSong Karaoke - http://singthegame.com


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 14 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group