I'm currently trying to build a game, and I have an intro sequence of images with accompanying text for the background story of the game. In the beginning, I fade in an image with accompanying text, and then fade both out. Then, I begin the next image-text pairing once the previous fade is complete, and I do this until the background story is complete, but when I do that the image and text flicker for a split-second before the fade in begins for every image and text. I've tried a number of things but can't seem to get rid of the flicker, can anyone help?
This is the function I use for this part in the intro:
private void backgroundStory (Stage stage, MediaPlayer mediaPlayer, String nameEntry, int width, int height, Color color) {
Group backstoryRoot = changeScene(stage, width, height, color);
GridPane backstoryPane = new GridPane();
backstoryRoot.getChildren().add(backstoryPane);
Label storyLabel1 = createLabel("Sometimes, life can get monotonous...");
backstoryPane.getColumnConstraints().add(new ColumnConstraints(width));
RowConstraints initialConstraint = new RowConstraints ((height/2)+20);
backstoryPane.getRowConstraints().add(initialConstraint);
int fadeDuration = 4000;
FadeTransition storyTextTransition1 = storyTextFade(storyLabel1, fadeDuration);
backstoryPane.getChildren().add(storyLabel1);
GridPane.setValignment(storyLabel1, VPos.BOTTOM);
GridPane.setHalignment(storyLabel1, HPos.CENTER);
storyTextTransition1.setOnFinished(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
backstoryPane.getChildren().remove(storyLabel1);
backstoryPane.getRowConstraints().remove(initialConstraint);
backstoryPane.getRowConstraints().add(new RowConstraints(25));
VBox vbox = new VBox (10);
backstoryPane.add(vbox, 0, 1);
vbox.setAlignment(Pos.TOP_CENTER);
ImageView dayAndNight = createImage ("Images/Day_And_Night.jpg");
Label storyLabel2 = createLabel("I was living in the city, following the same routine day and night.");
vbox.getChildren().add(dayAndNight);
vbox.getChildren().add(storyLabel2);
storyImageFade(dayAndNight, fadeDuration);
FadeTransition storyTextTransition2 = storyTextFade(storyLabel2, fadeDuration);
String officeReception = "Images/Office_Reception.jpg";
String receptionText = "Seeing the same faces every morning.";
FadeTransition storyTextTransition3 = nextPicture (storyTextTransition2, officeReception, receptionText, fadeDuration, vbox);
String office = "Images/Office.jpg";
String officeText = "Doing the same work every day.";
FadeTransition storyTextTransition4 = nextPicture (storyTextTransition3, office, officeText, fadeDuration, vbox);
}
});
//mediaPlayer.stop();
//introExplanation (stage, nameEntry, width, height, color);
}
These are the functions that are called within it:
private Label createLabel(String labelText) {
Label storyLabel = new Label(labelText);
Font storyFont = Font.font( "Blackadder ITC", 25 );
storyLabel.setTextFill(Color.INDIANRED);
storyLabel.setFont(storyFont);
return storyLabel;
}
private FadeTransition storyTextFade(Label label, int duration) {
FadeTransition storyTransition = new FadeTransition(Duration.millis(duration), label);
storyTransition.setFromValue(0);
storyTransition.setToValue(1);
storyTransition.setCycleCount(2);
storyTransition.setAutoReverse(true);
storyTransition.play();
return storyTransition;
}
private void storyImageFade(ImageView image, int duration) {
FadeTransition imageTransition = new FadeTransition(Duration.millis(duration), image);
imageTransition.setFromValue(0);
imageTransition.setToValue(1);
imageTransition.setCycleCount(2);
imageTransition.setAutoReverse(true);
imageTransition.play();
}
private ImageView createImage (String imageName) {
Image image = new Image(imageName);
ImageView imageview = new ImageView(image);
imageview.setFitWidth(500);
imageview.setFitHeight(500);
//imageview.setPreserveRatio(true);
imageview.setSmooth(true);
imageview.setCache(true);
return imageview;
}
private FadeTransition nextPicture (FadeTransition transition, String image, String imageLabel, int fadeDuration, VBox vbox) {
ArrayList<FadeTransition> transitionList = new ArrayList<FadeTransition>();
transition.setOnFinished(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
vbox.getChildren().clear();
ImageView imageview = createImage (image);
storyImageFade(imageview, fadeDuration);
Label storyLabel = createLabel(imageLabel);
FadeTransition storyTextTransition = storyTextFade(storyLabel, fadeDuration);
transitionList.add(storyTextTransition);
vbox.getChildren().add(imageview);
vbox.getChildren().add(storyLabel);
}
});
return transitionList.get(0);
}
Thanks!
This is my first response, so I do apologize if I'm not responding appropriately.
I was facing the same issue when transitioning between scenes. My solution was to set the node opacity to 0 before adding the node to the container.
For your case, it appears as though all of your labels and images are created in the createLabel and createImage methods, and the resulting values are what are being faded in.
private Label createLabel(String labelText) {
Label storyLabel = new Label(labelText);
Font storyFont = Font.font( "Blackadder ITC", 25 );
storyLabel.setTextFill(Color.INDIANRED);
storyLabel.setFont(storyFont);
// Set the opacity before returning the object
storyLabel.setOpacity(0);
return storyLabel;
}
private ImageView createImage (String imageName) {
Image image = new Image(imageName);
ImageView imageview = new ImageView(image);
imageview.setFitWidth(500);
imageview.setFitHeight(500);
//imageview.setPreserveRatio(true);
imageview.setSmooth(true);
imageview.setCache(true);
// Set the opacity before returning the object
imageview.setOpacity(0);
return imageview;
}
I hope this helps.
Related
I'm trying to build a program that takes your photo and places it with a different background, like a monument or so. So far, I was able to turn the camera on when I start the project with this code
webcamTexture = new WebCamTexture();
rawImage.texture = webcamTexture;
rawImage.material.mainTexture = webcamTexture;
webcamTexture.Play();
Texture2D PhotoTaken = new Texture2D (webcamTexture.width, webcamTexture.height);
PhotoTaken.SetPixels (webcamTexture.GetPixels ());
PhotoTaken.Apply ();
However, I can't take a screenshot or photo because it always ends up all black. I've tried different codes but nothing is working. Can someone please help? Thanks
EDIT
After some tries, this is the code I have:
WebCamTexture webcamTexture;
public RawImage rawImage;
void Start () {
webcamTexture = new WebCamTexture();
rawImage.texture = webcamTexture;
rawImage.material.mainTexture = webcamTexture;
webcamTexture.Play();
RenderTexture texture= new RenderTexture(webcamTexture.width, webcamTexture.height,0);
Graphics.Blit(webcamTexture, texture);
Button btn = yourButton.GetComponent<Button>();
btn.onClick.AddListener(OnClick);
}
public IEnumerator Coroutine(){
yield return new WaitForEndOfFrame ();
}
public void OnClick() {
var width = 767;
var height = 575;
Texture2D texture = new Texture2D(width, height);
texture.ReadPixels(new Rect(0, 0, width, height), 0, 0);
texture.Apply();
// Encode texture into PNG
var bytes = texture.EncodeToPNG();
//Destroy(texture);
File.WriteAllBytes (Application.dataPath + "/../SavedScreen.png", bytes);
}
and with this next code the screenshot is taken, but it takes a photo of the whole thing, and not just a bit of the screen.
void Start()
{
// Set the playback framerate!
// (real time doesn't influence time anymore)
Time.captureFramerate = frameRate;
// Find a folder that doesn't exist yet by appending numbers!
realFolder = folder;
int count = 1;
while (System.IO.Directory.Exists(realFolder))
{
realFolder = folder + count;
count++;
}
// Create the folder
System.IO.Directory.CreateDirectory(realFolder);
}
void Update()
{
// name is "realFolder/shot 0005.png"
var name = string.Format("{0}/shot {1:D04}.png", realFolder, Time.frameCount);
// Capture the screenshot
Application.CaptureScreenshot(name, sizeMultiplier);
}
}
You can take a screenshot like this in Unity
Application.CaptureScreenshot("Screenshot.png");
Reference
EDIT 1
To take a screenshot on a specific part of the screen use the following script:
var width = 400;
var height = 300;
var startX = 200;
var startY = 100;
var tex = new Texture2D (width, height, TextureFormat.RGB24, false);
tex.ReadPixels (Rect(startX, startY, width, height), 0, 0);
tex.Apply ();
// Encode texture into PNG
var bytes = tex.EncodeToPNG();
Destroy(tex);
File.WriteAllBytes(Application.dataPath + "/../SavedScreen.png", bytes);
Reference
I am currently using itextPdf library to generate PDF file.
For to set an image I used this solution of itextpdf.com
Now I want to set a small size image as a background in PdfPCell in mode mosaic : if cell have 3 x ImageSize, in PDF I will have my image repeated 3 times in cell
How I can do it ?
this is my example
public class ImageBackgroundEvent implements PdfPCellEvent {
protected Image image;
protected boolean mosaic;
protected boolean full;
public ImageBackgroundEvent(Image image, boolean mosaic, boolean full) {
this.image = image;
this.mosaic = mosaic;
this.full = full;
}
public void cellLayout(PdfPCell cell, Rectangle position,
PdfContentByte[] canvases) {
try {
PdfContentByte cb = canvases[PdfPTable.BACKGROUNDCANVAS];
if(full){
cell.setImage(image);
}
else if(mosaic){
float imgWidth = image.getWidth();
float imgHeight = image.getHeight();
float cellWidth = cell.getWidth();
float cellHeight = cell.getHeight();
if(imgHeight < cellHeight && imgWidth < cellWidth){
PdfPatternPainter pattern = cb.createPattern(imgWidth, imgHeight);
pattern.addImage(image);
pattern.setPatternMatrix(-0.5f, 0f, 0f, 0.5f, 0f, 0f);
cb.setPatternFill(pattern);
//cb.ellipse(180, 408, 450, 534);
cb.fillStroke();
} else{
image.scaleAbsolute(position);
image.setAbsolutePosition(position.getLeft(), position.getBottom());
cb.addImage(image);
}
} else{
image.scaleAbsolute(position);
image.setAbsolutePosition(position.getLeft(), position.getBottom());
cb.addImage(image);
}
} catch (DocumentException e) {
throw new ExceptionConverter(e);
}
}
}
Please take a look at the TiledBackgroundColor example. It takes an image of a light bulb and uses it to define a pattern color:
PdfContentByte canvas = writer.getDirectContent();
Image image = Image.getInstance(IMG);
PdfPatternPainter img_pattern = canvas.createPattern(
image.getScaledWidth(), image.getScaledHeight());
image.setAbsolutePosition(0, 0);
img_pattern.addImage(image);
BaseColor color = new PatternColor(img_pattern);
Now you can use that color for the background of your cell:
PdfPCell cell = new PdfPCell();
cell.setFixedHeight(60);
cell.setBackgroundColor(color);
table.addCell(cell);
The result looks like this: tiled_patterncolor.pdf
Or you could add the image in a cell event as shown in the TiledBackground example. This example was written in answer to the question iTextSharp. Why cell background image is rotated 90 degrees clockwise?
I've written a variation on this example: TiledBackgroundColor2
The event looks like this:
class TiledImageBackground implements PdfPCellEvent {
protected Image image;
public TiledImageBackground(Image image) {
this.image = image;
}
public void cellLayout(PdfPCell cell, Rectangle position,
PdfContentByte[] canvases) {
try {
PdfContentByte cb = canvases[PdfPTable.BACKGROUNDCANVAS];
image.scaleToFit(10000000, position.getHeight());
float x = position.getLeft();
float y = position.getBottom();
while (x + image.getScaledWidth() < position.getRight()) {
image.setAbsolutePosition(x, y);
cb.addImage(image);
x += image.getScaledWidth();
}
} catch (DocumentException e) {
throw new ExceptionConverter(e);
}
}
}
As you see, I don't care about the actual dimensions of the image. I scale the image in such a way that it fits the height of the cell. I don't use a pattern color either. I just add the image as many time as it fits the width of the cell.
This is how I declare the event to the cell:
PdfPCell cell = new PdfPCell();
Image image = Image.getInstance(IMG);
cell.setCellEvent(new TiledImageBackground(image));
The result looks like this:
Many variations are possible depending on your exact requirement.
I'm starting a project with monogame. I've made games with MonoGame before, but I felt the switching between multiple forms and monogame was clunky. For example I had a homescreen with buttons to Play, Hiscores & Quit. So I had forms for the homescreen and the hiscores. And then when you clicked Play the actualy MonoGame game would open.
Am I supposed to create everything in MonoGame? Or do I use panels in a single Form?
What I did to make it easier for myself is to make a class called "Screen", and just make a List<Screen> that holds all the different screens, so now, all I have to do to switch screen is set "Visible" to false or true on the screens I want to show or hide.
Here is part of how that class looks
public class Screen
{
public int ID;
public string Name;
public List<Form> Forms = new List<Form>();
public List<Label> Labels = new List<Label>();
public List<Button> Buttons = new List<Button>();
public List<Textbox> Textboxes = new List<Textbox>();
public List<EViewport> Viewports = new List<EViewport>();
public bool Visible;
// and a bunch of functions to add forms, buttons, do events, etc
// when adding a control, it's important that it is set to the right viewport
public Button AddButton(int _ID, string _Name, Texture2D _Sprite, int _Width, int _Height, Vector2 _Position, EViewport _Viewport, string _Text = "", bool _Visible = false)
{
Buttons.Add(new Button(_ID, _Name, _Sprite, _Width, _Height, new Vector2(_Position.X, _Position.Y), _Text, _Visible));
Button getButton = Buttons[Buttons.Count - 1];
getButton.ParentScreen = this;
getButton.ParentViewport = _Viewport;
return getButton;
}
public void Draw(SpriteBatch _spriteBatch, SpriteFont font, GameTime gameTime, Textbox focusedTextbox)
{
if (Visible)
{
// Draw only if screen is visible (this is not the full Draw function btw)
for(int j = 0; j < Viewports.Count; j++)
{
for(int i = 0; i < Buttons.Count; i++)
{
if(Buttons[i].ParentViewport.ID == Viewports[j].ID) // then draw
}
}
}
}
}
So basically all I do is add buttons, forms and viewports (because on my main menu I only need one viewport, but in-game I need 3 different viewports (one for game screen, one for UI and one for the chat) and then change their visibility like this:
storage.GetScreenByName("GameScreen").Visible = true;
(storage is just a singleton class that holds the sprite objects and screens in my game)
Oh, by the way, here's my EViewport class:
public class EViewport
{
/* Extended Viewport */
public Viewport _Viewport;
public Screen ParentScreen = new Screen();
public int ID;
public string Name;
public bool AllowResize;
public int MaxWidth;
public int MaxHeight;
public int MinHeight;
public float AspectRatio { get { return (float)MaxWidth / (float)MaxHeight; } }
public EViewport()
{
ID = -1;
}
public EViewport(int _ID, string _Name, int x, int y, int width, int height, bool _AllowResize = false, int _MinHeight = 0)
{
ID = _ID;
Name = _Name;
_Viewport = new Viewport(x, y, width, height);
AllowResize = _AllowResize;
MinHeight = _MinHeight;
MaxWidth = width;
MaxHeight = height;
}
public bool HasParentScreen()
{
return (ParentScreen.ID != -1);
}
}
I hope this helps, feel free to ask questions regarding how to implement such a system.
I have two images that i want to draw into a canvas object. I got those images from a server and when the loadHandler invokes, i get the dimensions of the image (they have the same width and height) and calculate the dimensions of the canvas. Then i draw each image, at the calculated x,y position in canvas. The problem is that only one image appears in canvas. Why?
Here is a part of the code:
final Image siImg = new Image();
siImg.setVisible(false);
siImg.setUrl(Constants.URL_PREFIX + siPath);
siImg.addLoadHandler(new LoadHandler() {
#Override
public void onLoad(LoadEvent event) {
int siWidth = siImg.getWidth();
int siHeight = siImg.getHeight();
siImg.removeFromParent();
if (!CategoryTableView.this.dimFromBg) {
CategoryTableView.this.width = siWidth;
CategoryTableView.this.height = siHeight * sSize;
//CategoryTableView.this.setPixelSize(CategoryTableView.this.width, CategoryTableView.this.height);
CategoryTableView.this.canvas.setPixelSize(CategoryTableView.this.width, CategoryTableView.this.height);
CategoryTableView.this.canvas.setCoordinateSpaceHeight(CategoryTableView.this.height);
CategoryTableView.this.canvas.setCoordinateSpaceWidth(CategoryTableView.this.width);
CategoryTableView.this.dimFromBg = true;
}
ImageElement imageElement = (ImageElement) siImg.getElement().cast();
int left = xOff;
int top = yOff + (siHeight * fi);
CategoryTableView.this.context.drawImage(imageElement, left, top);
}
});
RootPanel.get().add(siImg);
Ok i think i find it...i have to save the context's state each time. Is that right? (Because it works now!)
You add the image to your root panel in the last line
final Image siImg = new Image();
...
RootPanel.get().add(siImg);
instead of adding your canvas. So you will only see the image instead of the canvas. You have to add the Canvas to your root panel and draw both images to your canvas. For performance-reasons it is better to draw to a backbuffer instead of drawing directly to the canvas. Here is a little example:
Canvas canvas = Canvas.createIfSupported();
Canvas backBuffer = Canvas.createIfSupported();
Context2d context = canvas.getContext2d();
Context2d backBufferContext = backBuffer.getContext2d();
Image image1 = new Image("http://your.url.to/image.jpg");
image1.addLoadHandler(new LoadHandler() {
public void onLoad(LoadEvent event) {
// do anything you want here
doDraw();
}
});
Image image2 = new Image("http://your.url.to/image2.jpg");
image2.addLoadHandler(new LoadHandler() {
public void onLoad(LoadEvent event) {
// do anything you want here
doDraw();
}
});
RootPanel.get().add(canvas);
And the draw-method would look like this:
public void doDraw() {
backBufferContext.setFillStyle(redrawColor);
backBufferContext.fillRect(0, 0, width, height);
ImageElement imageElement = ImageElement.as(image1.getElement());
backBufferContext.drawImage(imageElement, 0, 0, 1024, 768, 0, 0, 102, 76);
ImageElement imageElement = ImageElement.as(image2.getElement());
backBufferContext.drawImage(imageElement, 0, 0, 1024, 768, 102, 76, 102, 76);
context.drawImage(backBufferContext.getCanvas(), 0, 0);
}
Please note: You have to use global variables in this example. Change this to your needs by either passing the arguments/classes or defining the variables class-wide. Also the drawing-areas are hardcoded in this example: this you have also to change to your needs.
I am trying to do something similar to this but in Android.
In Android I can extend the ProgressBar but I am doubting of how to add the TextViews on top. In iphone it was easy because I can use absolute positions, but not here.
Any ideas?
EDIT:
I decided to use SeekBar instead of ProgressBar to add the thumb drawable. I commented below. Some points to notice:
I am using hardcoded values, actually three but it can be more or less.
When the thumb is moved it moves to 50 but it should move to the different options.
I am using pixels instead of dpi. I should fix that.
I need to solve the lack of animation when the thumb moves.
My progress so far:
public class SliderFrameLayout extends FrameLayout implements OnSeekBarChangeListener {
private SeekBar mSlider;
private Context mContext;
private int mSize = 3;
private TextView[] mTextViews;
private String[] mTexts = {"Nafta", "Gas", "Gasoil"};
public SliderFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
setWillNotDraw(false);
mTextViews = new TextView[mSize];
addSlider();
addTextViews();
}
private void addTextViews() {
for ( int i=0 ; i < mSize ; i++ ) {
TextView tv;
tv = new TextView(mContext);
tv.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
tv.setText(mTexts[i]);
mTextViews[i] = tv;
addView(tv);
}
}
private void addSlider() {
FrameLayout fl = new FrameLayout(mContext, null);
LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
fl.setLayoutParams(params);
fl.setPadding(30, 30, 30, 0);
mSlider = new SeekBar(mContext, null);
LayoutParams lp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
//lp.setMargins(30, 30, 30, 0);
//mSlider.setPadding(30, 30, 30, 0);
mSlider.setLayoutParams(lp);
//mSlider.setMax(mSize-1);
mSlider.setThumbOffset(30);
//mSlider.setProgressDrawable(mContext.getResources().getDrawable(R.drawable.slider_track));
//mSlider.setThumb(mContext.getResources().getDrawable(R.drawable.slider_thumb));
mSlider.setOnSeekBarChangeListener(this);
//addView(mSlider);
fl.addView(mSlider);
addView(fl);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Rect rectf = new Rect();
mSlider.getLocalVisibleRect(rectf);
Log.d("WIDTH :",String.valueOf(rectf.width()));
Log.d("HEIGHT :",String.valueOf(rectf.height()));
Log.d("left :",String.valueOf(rectf.left));
Log.d("right :",String.valueOf(rectf.right));
Log.d("top :",String.valueOf(rectf.top));
Log.d("bottom :",String.valueOf(rectf.bottom));
int sliderWidth = mSlider.getWidth();
int padding = sliderWidth / (mSize-1);
for ( int i=0 ; i < mSize ; i++ ) {
TextView tv = mTextViews[i];
tv.setPadding(i* padding, 0, 0, 0);
}
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
Log.d("SEEK", "value: " + seekBar.getProgress());
seekBar.setProgress(50);
}
}
You're already overriding onDraw, why not just draw the text strings yourself? Rather than go through the overhead of adding TextViews and messing with the padding, just use canvas.drawText to physically draw the text strings in the right place.
You can specify the style and color of the text using a Paint object:
Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setColor(r.getColor(R.color.text_color));
textPaint.setFakeBoldText(true);
textPaint.setSubpixelText(true);
textPaint.setTextAlign(Align.LEFT);
And get the exact positioning by using the measureText method on that Paint object to find what width a particular string would be when drawn on a canvas:
textWidth = (int)textPaint.measureText(mTexts[i]);
Then you can iterate over your array of text strings and draw each string in the right place.
#Override
protected void onDraw(Canvas canvas) {
int myWidth = getMeasuredWidth()-LEFT_PADDING-RIGHT_PADDING;
int separation = myWidth / (mSize-1);
for (int i = 0; i++; i < mSize) {
int textWidth = (int)textPaint.measureText(mTexts[i]);
canvas.drawText(mTexts[i],
LEFT_PADDING+(i*separation)-(int)(textWidth/2),
TOP_PADDING,
textPaint);
}
}
You'll probably want to do the measurements in onMeasure instead of onDraw, and you should probably only measure the width of each string when you change the text or the paint, but I've put it all in one place to (hopefully) make it easier to follow.
Just a try. You could put your custom progressBar inside a FrameLayout then, inside this layout, you have to add three TextViews with fill_parent as width.
Then you can align the three texts in this way: left, center and right. Your texts shouldn't overwrite and you can adjust a little their position using margins.
You can use this... not exact what you looking for... but really easy to set up and customize...
You can set the TextViews to have:
android:layout_width="0dp"
android:layout_weight="1"
This will let the android framework take care of the placing of the TextViews and save you from manually calculating the padding of each one.