trying to develop typing game using libgdx in android - android

I want to create multiple independent Texture objects with key words on it falling from top to bottom and a key board displaying at bottom to type the letter on the texture object to capture it and generate new objects repeatedly for given time interval I have gone through the wiki's code for help but when I'm trying to display the words on the texture objects they change the letter on every Texture object on the Batch
package com.example.jtech.bubbletypinggame;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.TimeUtils;
import java.util.Iterator;
public class BubbleTypingGame extends ApplicationAdapter {
private Texture [] dropImage = new Texture[5];
private Texture bucketImage;
private Texture background;
private Sound dropSound;
private Music rainMusic;
private SpriteBatch batch;
private OrthographicCamera camera;
private Rectangle bucket;
private Array<CustomRectangle> raindrops;
private Array<String> rainKeyWords;
private Sprite mySprite;
CustomRectangle raindrop;
private long lastDropTime;
String[] chars = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"};
int i = 0;
String captionString;
private BitmapFont font;
int j = 0;
int x = 10, y = 740;
#Override
public void create() {
font = new BitmapFont();
font.setColor(Color.RED);
//load backgroud image for the game
background = new Texture("background_nebula.jpg");
// load the images for the droplet and the bucket, 64x64 pixels each
dropImage [0] = new Texture(Gdx.files.internal("balloon_a.png"));
dropImage [1] = new Texture(Gdx.files.internal("balloon_b.png"));
dropImage [2] = new Texture(Gdx.files.internal("balloon_c.png"));
dropImage [3] = new Texture(Gdx.files.internal("balloon_d.png"));
dropImage [4] = new Texture(Gdx.files.internal("balloon_e.png"));
// 25JANwORKING//
//25JANWORKING//
bucketImage = new Texture(Gdx.files.internal("bucket.png"));
// load the drop sound effect and the rain background "music"
dropSound = Gdx.audio.newSound(Gdx.files.internal("drop.mp3"));
rainMusic = Gdx.audio.newMusic(Gdx.files.internal("rain.mp3"));
// start the playback of the background music immediately
rainMusic.setLooping(true);
rainMusic.play();
// create the camera and the SpriteBatch
camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 480);
batch = new SpriteBatch();
// create a Rectangle to logically represent the bucket
bucket = new Rectangle();
bucket.x = 800 / 2 - 64 / 2; // center the bucket horizontally
bucket.y = 20; // bottom left corner of the bucket is 20 pixels above the bottom screen edge
bucket.width = 64;
bucket.height = 64;
// create the raindrops array and spawn the first raindrop
raindrops = new Array<CustomRectangle>();
rainKeyWords = new Array<String>();
spawnRaindrop();
}
private void spawnRaindrop() {
raindrop = new CustomRectangle();
raindrop.x = MathUtils.random(0, 800-100);
raindrop.y = 480;
raindrop.width = 100;
raindrop.height = 50;
raindrop.keyWord = "k";
raindrops.add(raindrop);
lastDropTime = TimeUtils.nanoTime();
if(i==chars.length){
i=0;
}
captionString = chars[i];
rainKeyWords.add(captionString);
i++;
}
private void displayKeyWord(){
if(i==chars.length){
i=0;
}
captionString = chars[i];
rainKeyWords.add(captionString);
lastDropTime = TimeUtils.nanoTime();
i++;
}
#Override
public void render() {
// clear the screen with a dark blue color. The
// arguments to glClearColor are the red, green
// blue and alpha component in the range [0,1]
// of the color to be used to clear the screen.
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// tell the camera to update its matrices.
camera.update();
// tell the SpriteBatch to render in the
// coordinate system specified by the camera.
batch.setProjectionMatrix(camera.combined);
// begin a new batch and draw the bucket and
// all drops
batch.begin();
if(j==5){
j=0;
}
batch.draw(background,0,0);
batch.draw(bucketImage, bucket.x, bucket.y);
batch.draw(dropImage[j], raindrop.x, 400);
/*for(Rectangle raindrop: raindrops) {
batch.draw(dropImage[i], raindrop.x, raindrop.y);
//font.draw(batch, captionString, raindrop.x+45, raindrop.y+30);
}*/
batch.end();
/*// process user input
if(Gdx.input.isTouched()) {
Vector3 touchPos = new Vector3();
touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(touchPos);
bucket.x = touchPos.x - 64 / 2;
}
if(Gdx.input.isKeyPressed(Keys.LEFT)) bucket.x -= 200 * Gdx.graphics.getDeltaTime();
if(Gdx.input.isKeyPressed(Keys.RIGHT)) bucket.x += 200 * Gdx.graphics.getDeltaTime();
// make sure the bucket stays within the screen bounds
if(bucket.x < 0) bucket.x = 0;
if(bucket.x > 800 - 64) bucket.x = 800 - 64;
// check if we need to create a new raindrop*/
if(TimeUtils.nanoTime() - lastDropTime > 1000000000) spawnRaindrop();
// move the raindrops, remove any that are beneath the bottom edge of
// the screen or that hit the bucket. In the later case we play back
// a sound effect as well.
Iterator<CustomRectangle> iter = raindrops.iterator();
while(iter.hasNext()) {
Rectangle raindrop = iter.next();
raindrop.y -= 100 * Gdx.graphics.getDeltaTime();
if(raindrop.y + 64 < 0) iter.remove();
if(raindrop.overlaps(bucket)) {
dropSound.play();
iter.remove();
}
}
}
#Override
public void dispose() {
// dispose of all the native resources
dropImage[j].dispose();
bucketImage.dispose();
dropSound.dispose();
rainMusic.dispose();
batch.dispose();
}
}

Now, the code where it looks like you draw the letters are commented out, but I assume this is what you intend to use.
for(Rectangle raindrop: raindrops) {
batch.draw(dropImage[i], raindrop.x, raindrop.y);
font.draw(batch, captionString, raindrop.x+45, raindrop.y+30);
}
What this means: for each object in the raindrops array, you draw the captionString. So if you have 20 objects in raindrops and captionString = "a", then you will draw the letter "a" 20 times.
You are using a single string to represent 20 strings. A String can only hold a single value. So, the last value you give captionString, is the only value you can display using it. You don't change the value in the loop.
Every raindrop object needs to have its own string value. And this value is the one you will need to draw, not captionString.
[edit]
Looks like you already have this in place. Just use the right string.
Try:
for(Rectangle raindrop: raindrops) {
batch.draw(dropImage[i], raindrop.x, raindrop.y);
font.draw(batch, raindrop.keyWord, raindrop.x+45, raindrop.y+30);
}

Related

Class DescriptorExtractor not available in opencv 4.1.0 for Android

Im pretty new at openCV and I'm working with some documentation intended to work with openCV 3, I'm writing a filter which uses org.opencv.features2d.DescriptorExtractor class, however, the class is not available in openCV 4.1.0.
What I need is to use the existing classes in openCV 4.1.0 in order to achieve the same goal since I cannot use DescriptorExtractor.
The app recognizes certain arbitrary, rectangular images, for example, paintings, and determine their pose in a 2D projection. The app will draw an outline around a tracked image when it appears in the camera feed.
Here is the section of the code using the missing class:
public final class ImageDetectionFilter {
// Not relevant section...
// A descriptor extractor, which creates descriptors of features.
private final DescriptorExtractor mDescriptorExtractor =
DescriptorExtractor.create(DescriptorExtractor.ORB);
public ImageDetectionFilter(final Context context,
final int referenceImageResourceID) throws IOException {
// Not relevant section...
// Detect the reference features and compute their descriptors.
mFeatureDetector.detect(referenceImageGray, mReferenceKeypoints);
mDescriptorExtractor.compute(referenceImageGray, mReferenceKeypoints, mReferenceDescriptors);
}
#Override
public void apply(final Mat src, final Mat dst) {
// ...
// Detect the scene features, compute their descriptors,
// and match the scene descriptors to reference descriptors.
mFeatureDetector.detect(mGraySrc, mSceneKeypoints);
mDescriptorExtractor.compute(mGraySrc, mSceneKeypoints, mSceneDescriptors);
mDescriptorMatcher.match(mSceneDescriptors, mReferenceDescriptors, mMatches);
//...
}
}
Here is the full class for your reference just in case:
package com.sample.opencv.filters;
import android.content.Context;
import org.opencv.android.Utils;
import org.opencv.calib3d.Calib3d;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.DMatch;
import org.opencv.core.KeyPoint;
import org.opencv.core.Mat;
import org.opencv.core.MatOfDMatch;
import org.opencv.core.MatOfKeyPoint;
import org.opencv.core.MatOfPoint;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.features2d.DescriptorExtractor;
import org.opencv.features2d.DescriptorMatcher;
import org.opencv.features2d.ORB;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public final class ImageDetectionFilter implements Filter {
// The reference image (this detector's target).
private final Mat mReferenceImage;
// Features of the reference image.
private final MatOfKeyPoint mReferenceKeypoints =
new MatOfKeyPoint();
// Descriptors of the reference image's features.
private final Mat mReferenceDescriptors = new Mat();
// The corner coordinates of the reference image, in pixels.
// CvType defines the color depth, number of channels, and
// channel layout in the image. Here, each point is represented
// by two 32-bit floats.
private final Mat mReferenceCorners =
new Mat(4, 1, CvType.CV_32FC2);
// Features of the scene (the current frame).
private final MatOfKeyPoint mSceneKeypoints =
new MatOfKeyPoint();
// Descriptors of the scene's features.
private final Mat mSceneDescriptors = new Mat();
// Tentative corner coordinates detected in the scene, in
// pixels.
private final Mat mCandidateSceneCorners =
new Mat(4, 1, CvType.CV_32FC2);
// Good corner coordinates detected in the scene, in pixels.
private final Mat mSceneCorners = new Mat(4, 1, CvType.CV_32FC2);
// The good detected corner coordinates, in pixels, as integers.
private final MatOfPoint mIntSceneCorners = new MatOfPoint();
// A grayscale version of the scene.
private final Mat mGraySrc = new Mat();
// Tentative matches of scene features and reference features.
private final MatOfDMatch mMatches = new MatOfDMatch();
// A feature detector, which finds features in images.
private final ORB mFeatureDetector =
ORB.create();
// A descriptor extractor, which creates descriptors of
// features.
private final DescriptorExtractor mDescriptorExtractor =
DescriptorExtractor.create(DescriptorExtractor.ORB);
// A descriptor matcher, which matches features based on their descriptors.
private final DescriptorMatcher mDescriptorMatcher =
DescriptorMatcher.create(
DescriptorMatcher.BRUTEFORCE_HAMMINGLUT);
// The color of the outline drawn around the detected image.
private final Scalar mLineColor = new Scalar(0, 255, 0);
public ImageDetectionFilter(final Context context,
final int referenceImageResourceID) throws IOException {
// Load the reference image from the app's resources.
// It is loaded in BGR (blue, green, red) format.
mReferenceImage = Utils.loadResource(context,
referenceImageResourceID,
Imgcodecs.IMREAD_COLOR);
// Create grayscale and RGBA versions of the reference image.
final Mat referenceImageGray = new Mat();
Imgproc.cvtColor(mReferenceImage, referenceImageGray,
Imgproc.COLOR_BGR2GRAY);
Imgproc.cvtColor(mReferenceImage, mReferenceImage,
Imgproc.COLOR_BGR2RGBA);
// Store the reference image's corner coordinates, in pixels.
mReferenceCorners.put(0, 0,
new double[]{0.0, 0.0});
mReferenceCorners.put(1, 0,
new double[]{referenceImageGray.cols(), 0.0});
mReferenceCorners.put(2, 0,
new double[]{referenceImageGray.cols(),
referenceImageGray.rows()});
mReferenceCorners.put(3, 0,
new double[]{0.0, referenceImageGray.rows()});
// Detect the reference features and compute their descriptors.
mFeatureDetector.detect(referenceImageGray,
mReferenceKeypoints);
mDescriptorExtractor.compute(referenceImageGray,
mReferenceKeypoints, mReferenceDescriptors);
}
#Override
public void apply(final Mat src, final Mat dst) {
// Convert the scene to grayscale.
Imgproc.cvtColor(src, mGraySrc, Imgproc.COLOR_RGBA2GRAY);
// Detect the scene features, compute their descriptors,
// and match the scene descriptors to reference descriptors.
mFeatureDetector.detect(mGraySrc, mSceneKeypoints);
mDescriptorExtractor.compute(mGraySrc, mSceneKeypoints,
mSceneDescriptors);
mDescriptorMatcher.match(mSceneDescriptors,
mReferenceDescriptors, mMatches);
// Attempt to find the target image's corners in the scene.
findSceneCorners();
// If the corners have been found, draw an outline around the
// target image.
// Else, draw a thumbnail of the target image.
draw(src, dst);
}
private void findSceneCorners() {
final List<DMatch> matchesList = mMatches.toList();
if (matchesList.size() < 4) {
// There are too few matches to find the homography.
return;
}
final List<KeyPoint> referenceKeypointsList =
mReferenceKeypoints.toList();
final List<KeyPoint> sceneKeypointsList =
mSceneKeypoints.toList();
// Calculate the max and min distances between keypoints.
double maxDist = 0.0;
double minDist = Double.MAX_VALUE;
for (final DMatch match : matchesList) {
final double dist = match.distance;
if (dist < minDist) {
minDist = dist;
}
if (dist > maxDist) {
maxDist = dist;
}
}
// The thresholds for minDist are chosen subjectively
// based on testing. The unit is not related to pixel
// distances; it is related to the number of failed tests
// for similarity between the matched descriptors.
if (minDist > 50.0) {
// The target is completely lost.
// Discard any previously found corners.
mSceneCorners.create(0, 0, mSceneCorners.type());
return;
} else if (minDist > 25.0) {
// The target is lost but maybe it is still close.
// Keep any previously found corners.
return;
}
// Identify "good" keypoints based on match distance.
final ArrayList<Point> goodReferencePointsList =
new ArrayList<Point>();
final ArrayList<Point> goodScenePointsList =
new ArrayList<Point>();
final double maxGoodMatchDist = 1.75 * minDist;
for (final DMatch match : matchesList) {
if (match.distance < maxGoodMatchDist) {
goodReferencePointsList.add(
referenceKeypointsList.get(match.trainIdx).pt);
goodScenePointsList.add(
sceneKeypointsList.get(match.queryIdx).pt);
}
}
if (goodReferencePointsList.size() < 4 ||
goodScenePointsList.size() < 4) {
// There are too few good points to find the homography.
return;
}
// There are enough good points to find the homography.
// (Otherwise, the method would have already returned.)
// Convert the matched points to MatOfPoint2f format, as
// required by the Calib3d.findHomography function.
final MatOfPoint2f goodReferencePoints = new MatOfPoint2f();
goodReferencePoints.fromList(goodReferencePointsList);
final MatOfPoint2f goodScenePoints = new MatOfPoint2f();
goodScenePoints.fromList(goodScenePointsList);
// Find the homography.
final Mat homography = Calib3d.findHomography(
goodReferencePoints, goodScenePoints);
// Use the homography to project the reference corner
// coordinates into scene coordinates.
Core.perspectiveTransform(mReferenceCorners,
mCandidateSceneCorners, homography);
// Convert the scene corners to integer format, as required
// by the Imgproc.isContourConvex function.
mCandidateSceneCorners.convertTo(mIntSceneCorners,
CvType.CV_32S);
// Check whether the corners form a convex polygon. If not,
// (that is, if the corners form a concave polygon), the
// detection result is invalid because no real perspective can
// make the corners of a rectangular image look like a concave
// polygon!
if (Imgproc.isContourConvex(mIntSceneCorners)) {
// The corners form a convex polygon, so record them as
// valid scene corners.
mCandidateSceneCorners.copyTo(mSceneCorners);
}
}
protected void draw(final Mat src, final Mat dst) {
if (dst != src) {
src.copyTo(dst);
}
if (mSceneCorners.height() < 4) {
// The target has not been found.
// Draw a thumbnail of the target in the upper-left
// corner so that the user knows what it is.
// Compute the thumbnail's larger dimension as half the
// video frame's smaller dimension.
int height = mReferenceImage.height();
int width = mReferenceImage.width();
final int maxDimension = Math.min(dst.width(),
dst.height()) / 2;
final double aspectRatio = width / (double) height;
if (height > width) {
height = maxDimension;
width = (int) (height * aspectRatio);
} else {
width = maxDimension;
height = (int) (width / aspectRatio);
}
// Select the region of interest (ROI) where the thumbnail
// will be drawn.
final Mat dstROI = dst.submat(0, height, 0, width);
// Copy a resized reference image into the ROI.
Imgproc.resize(mReferenceImage, dstROI, dstROI.size(),
0.0, 0.0, Imgproc.INTER_AREA);
return;
}
// Outline the found target in green.
Imgproc.line(dst, new Point(mSceneCorners.get(0, 0)),
new Point(mSceneCorners.get(1, 0)), mLineColor, 4);
Imgproc.line(dst, new Point(mSceneCorners.get(1, 0)),
new Point(mSceneCorners.get(2, 0)), mLineColor, 4);
Imgproc.line(dst, new Point(mSceneCorners.get(2, 0)),
new Point(mSceneCorners.get(3, 0)), mLineColor, 4);
Imgproc.line(dst, new Point(mSceneCorners.get(3, 0)),
new Point(mSceneCorners.get(0, 0)), mLineColor, 4);
}
}
Downgrade to a lower version of opencv, 3.4.9 worked for me!

Drawing many actors takes long time in scene2d

I have a problem with drawing many actors as it takes long time when testing with desktop project and not working on my android device.
I have a play button that when clicked should show 100 level for player to choose from.
Here is my code:
stage = new Stage(new ScalingViewport(Scaling.fill, 800, 1280));
Gdx.input.setInputProcessor(stage);
skin = new Skin(Gdx.files.internal("data/uiskin.json"));
Image play = new Image(new Texture(Gdx.files.internal("play.png")));
stage.addActor(play);
play.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
Table container = new Table();
stage.addActor(container);
container.setFillParent(true);
Table table = new Table();
Puzzle[] puzzles = new Puzzle[100];
for (int i=0; i<puzzles.length; i++) {
table.padTop(60);
table.padBottom(60);
puzzles[i] = new Puzzle(i, false);
if (i%6 == 0) table.row();
table.add(puzzles[i]).pad(5);
}
ScrollPane scroll = new ScrollPane(table, skin);
container.add(scroll).expand().fill().colspan(4);
}
});
Here is puzzle class which simply shows a rectangle with puzzle number and if it is solved its color should be blue and if not color should be white.
private class Puzzle extends Actor {
TextureRegion rect;
BitmapFont font;
float w,h;
boolean solved;
int drawNum;
public Puzzle(int number, boolean solved) {
rect = new TextureRegion(new Texture(Gdx.files.internal("rect.png")));
setSize(rect.getRegionWidth(), rect.getRegionHeight());
this.drawNum = number + 1;
this.solved = solved;
if (solved) font = HelpingMethods.createFont(38, Color.GOLD);
else font = HelpingMethods.createFont(38, Color.DARK_GRAY);
GlyphLayout layout = new GlyphLayout();
layout.setText(font, "" + this.drawNum);
w = layout.width;
h = layout.height;
}
#Override
public void draw(Batch batch, float parentAlpha) {
Color color = getColor();
if (!solved) batch.setColor(1, 1, 1, color.a * parentAlpha);
else batch.setColor(0, 0, 1, color.a * parentAlpha);
font.setColor(color.r, color.g, color.b, color.a * parentAlpha);
batch.draw(rect, getX(), getY());
font.draw(batch, "" + drawNum, getX() + getWidth()/2 - w/2,
getY() + h + getHeight()/2 - h/2);
}
}
Here is createFont() method:
public static BitmapFont createFont(int size, Color color) {
FreeTypeFontGenerator generator = new FreeTypeFontGenerator
(Gdx.files.internal("fonts/font.ttf"));
FreeTypeFontGenerator.FreeTypeFontParameter parameter =
new FreeTypeFontGenerator.FreeTypeFontParameter();
parameter.size = size;
parameter.color = color;
parameter.minFilter = Texture.TextureFilter.Linear;
parameter.magFilter = Texture.TextureFilter.Linear;
BitmapFont font = generator.generateFont(parameter);
return font;
}
Any Solutions ?
The problem is, that whenever the play is clicked, you create new 100 Puzzle objects. In Puzzle constructor you generate BitmapFont with FreeTypeFontGenerator, which is expensive operation. And you do that 100 times. Instead, you should generate your BitmapFont object once (for example, when you initialize your game), and pass a reference to it to every Puzzle object. Also reuse Talbe container and GlyphLayout objects.
In game development in general you should avoid creating new objects, when possible, and reuse them instead. And the reason is not only it can be slow, but also, as in your case, when you create new Puzzle objects instead of old ones, you create a lot of work for a garbage collector, which can cause stutters.
Don't forget to dispose the BitmapFont object, when it's not needed anymore.

Using player's face from camera as a sprite in unity

Is there a way to get a picture of the player and then cropping the face for a sprite or something?
Like the apps that add your face to a body, but the face would be stored in some way.
Following this question answer, you can retrieve the picture from the Android Camera and save it as a texture. Then you use a Texture2D containing your mask (let's say a circle on the middle with alpha around it) to check which byte you want to save and which byte will be transparent. Don't forget to set this Texture2D import properties to Advanced and check Read/Write enabled. Finally you can load the newly created picture as a sprite using either Unity WWW class or System.IO.ReadAllBytes.
Here is a quick implementation of this:
[SerializeField]
private Texture2D maskTexture;
private WebCamTexture webCamTexture;
protected void Start()
{
GetComponent<RawImage>().rectTransform.sizeDelta = new Vector2(maskTexture.width, maskTexture.height);
webCamTexture = new WebCamTexture();
GetComponent<Renderer>().material.mainTexture = webCamTexture;
webCamTexture.Play();
}
public void SavePicture()
{
StartCoroutine(SavePictureCoroutine());
}
private IEnumerator SavePictureCoroutine()
{
yield return new WaitForEndOfFrame();
RawImage rawImageToRead = GetComponent<RawImage>();
//This is to save the current RenderTexture: RenderTexture.GetTemporary() and RenderTexture.ReleaseTemporary() can also be used
RenderTexture previousRenderTexture = RenderTexture.active;
RenderTexture.active = rawImageToRead.texture as RenderTexture;
Texture2D renderedTexture = new Texture2D(maskTexture.width, maskTexture.height, TextureFormat.ARGB32, false);
renderedTexture.ReadPixels(new Rect(Screen.width * 0.5f - maskTexture.width * 0.5f, Screen.height * 0.5f - maskTexture.height * 0.5f, renderedTexture.width, renderedTexture.height), 0, 0);
renderedTexture.Apply();
RenderTexture.active = previousRenderTexture;
//----
for(int i = 0; i < renderedTexture.width; i++)
{
for(int j = 0; j < renderedTexture.height; j++)
{
if(maskTexture.GetPixel(i, j).a > 0.5f)
{
renderedTexture.SetPixel(i, j, renderedTexture.GetPixel(i, j));
}
else
{
renderedTexture.SetPixel(i, j, new Color(0.0f, 0.0f, 0.0f, 0.0f));
}
}
}
renderedTexture.Apply();
yield return renderedTexture;
File.WriteAllBytes(Path.Combine(Application.dataPath, "YOUR_FILE_NAME"), renderedTexture.EncodeToPNG());
}
(Warning: untested code)
Also keep in mind to try to provide what you already tried before asking questions: it helps other users understand what and how you want to achieve it.
Hope this helps,

Libgdx collision detect from two sources on one body [array out of bounds excpetion -1]

OK for sake of argument and simplicity this code here has a rectangle sprite/texture that shoots(cuz it's a gun) upwards. And an enemy rectangle/sprite/texture the spawns downwards. Then the player detects if it hits a enemy. When the player hits an enemy I get an out of bounds exception -1
package com.TheGame.Pack;
import java.util.Iterator;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.TimeUtils;
public class GameScreen implements Screen {
final MasterClass game;
Texture FleetTexture;
Texture PlayerTexture;
Texture ShootingTexture;
OrthographicCamera camera;
Rectangle Player;
Array<Rectangle> Emma;
Array<Rectangle> Shooting;
long EmmaSpawnTime;
long ShootingTime;
public static int EmmaKilled = 0;
public GameScreen(final MasterClass gam) {
this.game = gam;
// load the images for the droplet and the Player, 64x64 pixels each
FleetTexture = new Texture(Gdx.files.internal("cirA.png")); //Enemies
PlayerTexture = new Texture(Gdx.files.internal("BoxA.png"));
ShootingTexture = new Texture(Gdx.files.internal("gun.png"));
// load the drop sound effect and the rain background "music"
// dropSound = Gdx.audio.newSound(Gdx.files.internal("drop.wav"));
// rainMusic = Gdx.audio.newMusic(Gdx.files.internal("rain.mp3"));
// rainMusic.setLooping(true);
// create the camera and the SpriteBatch
camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 480);
// create a Rectangle to logically represent the Player
Player = new Rectangle();
Player.x = 800 / 2 - 64 / 2; // center the Player horizontally
Player.y = 20; // bottom left corner of the Player is 20 pixels above
// the bottom screen edge
Player.width = 40;
Player.height = 30;
// create the Emma array and spawn the first EmmaInArray
Emma = new Array<Rectangle>();
Shooting = new Array<Rectangle>();
spawnEmma();
}
private void spawnEmma() {
Rectangle EmmaInArray = new Rectangle();
EmmaInArray.x = MathUtils.random(0, 800 - 64);
EmmaInArray.y = 480;
EmmaInArray.width = 40;
EmmaInArray.height = 30;
Emma.add(EmmaInArray);
EmmaSpawnTime = TimeUtils.nanoTime();
}
private void spawnShooting(){
Rectangle ShootingInArray = new Rectangle();
ShootingInArray.x = Player.x;
ShootingInArray.y = Player.y;
ShootingInArray.width = 40;
ShootingInArray.height = 30;
Shooting.add(ShootingInArray);
ShootingTime = TimeUtils.nanoTime();
}
#Override
public void render(float delta) {
// clear the screen with a dark blue color. The
// arguments to glClearColor are the red, green
// blue and alpha component in the range [0,1]
// of the color to be used to clear the screen.
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// tell the camera to update its matrices.
camera.update();
// tell the SpriteBatch to render in the
// coordinate system specified by the camera.
game.batch.setProjectionMatrix(camera.combined);
// begin a new batch and draw the Player and
// all drops
game.batch.begin();
game.font.draw(game.batch, "Drops Collected: " + EmmaKilled, 0, 480);
game.batch.draw(PlayerTexture, Player.x, Player.y, Gdx.graphics.getWidth() / 20,
Gdx.graphics.getHeight()/ 20);
for (Rectangle EmmaInArray : Emma) {
game.batch.draw(FleetTexture, EmmaInArray.x, EmmaInArray.y);
}
for(Rectangle ShootingInArray : Shooting){
game.batch.draw(ShootingTexture, ShootingInArray.x, ShootingInArray.y);
ShootingInArray.y +=10;
}
game.batch.end();
// process user input
if (Gdx.input.isTouched()) {
Vector3 touchPos = new Vector3();
touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(touchPos);
Player.x = touchPos.x - 64 / 2;
}
if (Gdx.input.isKeyPressed(Keys.LEFT))
Player.x -= 400 * Gdx.graphics.getDeltaTime();
if (Gdx.input.isKeyPressed(Keys.RIGHT))
Player.x += 400 * Gdx.graphics.getDeltaTime();
// make sure the Player stays within the screen bounds
if (Player.x < 0)
Player.x = 0;
if (Player.x > 800 - 64)
Player.x = 800 - 64;
// check if we need to create a new EmmaInArray
if (TimeUtils.nanoTime() - EmmaSpawnTime > 100000000){
spawnEmma();
}
if(TimeUtils.nanoTime() - ShootingTime > 100000000){
spawnShooting();
}
// move the Emma, remove any that are beneath the bottom edge of
// the screen or that hit the Player. In the later case we play back
// a sound effect as well.
Iterator<Rectangle> EmmaIterator = Emma.iterator();
while (EmmaIterator.hasNext()) {
Rectangle EmmaInArray = EmmaIterator.next();
EmmaInArray.y -= 200 * Gdx.graphics.getDeltaTime();
if (EmmaInArray.y + 64 < 0){
EmmaIterator.remove();
}
Iterator<Rectangle> ShootingIterator = Shooting.iterator();
while(ShootingIterator.hasNext()){
Rectangle ShootingInArray = ShootingIterator.next();
// ShootingInArray.y += 200 * Gdx.graphics.getDeltaTime();
if(ShootingInArray.y > 480){
ShootingIterator.remove();
}
if(EmmaInArray.overlaps(ShootingInArray)){
ShootingIterator.remove();
EmmaIterator.remove();
}
if (Player.overlaps(EmmaInArray)) {
EmmaKilled++;
game.setScreen(game.HS);
// dropSound.play();
if I comment out EmmaIterator.remove(); it runs fine with it uncommented it crashes upon hit.
Why does this crash is this not the proper way to do this? Do I need to somehow detect hit's at the same time? How can the array be at negative 1 when clearly there are still enemies on the screen?
EmmaIterator.remove();
}
}
Though this is not the way I will have things setup this code still should run with no issues. I encounter the same problem when instead of detecting the player enemies collisions I have 2 guns checking for collisions. This seems like a big problem to me which is why I'd say I'm just doing it wrong but documentation is light so I come here.
}
}
#Override
public void resize(int width, int height) {
}
#Override
public void show() {
// start the playback of the background music
// when the screen is shown
//rainMusic.play();
}
#Override
public void hide() {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void dispose() {
FleetTexture.dispose();
PlayerTexture.dispose();
ShootingTexture.dispose();
// dropSound.dispose();
// rainMusic.dispose();
}
}
It's unlikely, unless multithreading is being used, that anything will happen at the same time exactly. You have a number of probable typos in your code, but one will break it:
Rectangle var1_holder = iter.next();
That same reference to iter is in both the first block, which should use it, and the second block, which should use iter1. You should consider using matching variable names, like
Iterator<Rectangle> iter3 = var3.iterator();
if you must have numbers as the only distinguishing feature.
notostraca is right. But to make it more clear i will show u an example with for loops which i use for collisions. it can't make any harm and i hope it will make it more clear for u
int v2 = var2.size();
for (int i = 0; i < v2; i++) {
if (object.getBounds().overlaps(var2.get(i).getBounds())) {
var2.remove(i);
v2--;
//in this line u might use break; if u know that just one object
//from var2 array can hit at a time
}
}

libgdx pixel issues between desktop and android projects

UPDATE Looks like this is a problem because of the static notification bar on tablet because of the lack of hardware buttons. I just didn't think about that. Anyway, in the case of the TF101 it returns a resolution of 1280x752 so about 1.702 (80 : 47) ratio. If I use a suitable unit size, like 33.5 or 11.75 vertically I get the proper scaling and this seems to fix the problem of skewed pixels.
END UPDATE
I've been setting up a game using 16x16 units for my tiled maps. I am using the resolution 1280x800 on both my desktop and android projects, I'm testing this to get a sense of how it will look on my TF101 asus tablet. I currently use a camera with units of 20x12.5 (wxh) and notice no pixel scaling on my desktop project, but when I run the game on my android I get weird scaling, and a green horizontal line. I can also move about quarter cell further along the x-axis on the tablet, shown in the screen shots. The pixels on the android project don't seem uniform at all.
I set the verticalTiles amount to 12.5f, then calculate the horizontalTiles amount as
verticalTiles = 12.5f;
...
horizontalTiles = (float) width / (float) height * verticalTiles;
camera = new OrthographicCamera(horizontalTiles, verticalTiles);
I'm aiming for devices with different aspect ratios to simply see more or less of the map, but can't seem to get working correctly. Any help would be appreciated.
Android Capture - http://imageshack.us/f/7/dsvg.png/ - notice the highlights on the roof edges, they are not uniform at all.
Desktop Capture - http://imageshack.us/f/853/5itv.png/
Current MainGame class
package com.bitknight.bqex;
/* Bunch of imports */
public class MainGame implements ApplicationListener {
private OrthographicCamera camera;
private SpriteBatch spriteBatch;
private TiledMap map;
private OrthogonalTiledMapRenderer mapRenderer;
private Texture texture;
private Texture clothArmor;
private Sprite sprite;
private BitmapFont font;
private float horizontalTiles = 0;
private float verticalTiles = 12.5f;
private int hoverTileX = 0;
private int hoverTileY = 0;
private TiledMapTileLayer layer;
private Cell cell;
private TiledMapTile canMoveToTile;
private TiledMapTile cannotMoveToTile;
private AnimatedTiledMapTile animatedStopTile;
private AnimatedTiledMapTile animatedGoTile;
private Texture spriteSheet;
private TextureRegion region;
private Player player;
float h, w;
float ppuX, ppuY;
#Override
public void create() {
// Setup the animated tiles
Array<StaticTiledMapTile> tileArray;
// Start position on the sheet
int startX = 192;
int startY = 1568;
spriteSheet = new Texture(Gdx.files.internal("data/maps/tilesheet.png"));
spriteSheet.setFilter(TextureFilter.Nearest, TextureFilter.Nearest);
// We are trying to load two strips of 4 frames, 8 total
for( int i = 0; i < 2; ++i ) {
tileArray = new Array<StaticTiledMapTile>(4);
for( int j = 0; j < 4; ++j ) {
region = new TextureRegion(spriteSheet, startX, startY, 16, 16);
tileArray.add(new StaticTiledMapTile(region));
startX += 16;
}
if( i == 0 ) {
animatedStopTile = new AnimatedTiledMapTile(1/10f, tileArray);
} else {
animatedGoTile = new AnimatedTiledMapTile(1/10f, tileArray);
}
}
// Load the map
map = new TmxMapLoader().load("data/maps/base.tmx");
// Setup the two tiles that show movable and not movable sprites
canMoveToTile = map.getTileSets().getTileSet(0).getTile(1959);
canMoveToTile.setBlendMode(BlendMode.ALPHA);
cannotMoveToTile = map.getTileSets().getTileSet(0).getTile(1958);
cannotMoveToTile.setBlendMode(BlendMode.ALPHA);
// Manually create the layer used to show the cursor sprites
layer = new TiledMapTileLayer(100, 100, 16, 16);
layer.setName("display");
cell = new Cell();
cell.setTile(canMoveToTile);
layer.setOpacity(1f);
mapRenderer = new OrthogonalTiledMapRenderer(map, 1/16f);
spriteBatch = new SpriteBatch();
font = new BitmapFont(Gdx.files.internal("data/consolas.fnt"), false);
font.setScale(0.6f);
texture = new Texture(Gdx.files.internal("data/maps/tilesheet.png"));
texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
clothArmor = new Texture(Gdx.files.internal("data/img/native/clotharmor.png"));
region = new TextureRegion(clothArmor, 32, 256, 32, 32);
sprite = new Sprite(region);
sprite.setOrigin(0.5f, 0.5f);
sprite.setPosition(0f - 0.5f, 0f);
sprite.setSize(2, 2);
// Setup player and associated animations
Array<TextureRegion> regions = new Array<TextureRegion>();
player = new Player();
}
#Override
public void dispose() {
spriteBatch.dispose();
texture.dispose();
clothArmor.dispose();
spriteSheet.dispose();
}
#Override
public void render() {
player.update(Gdx.graphics.getDeltaTime());
camera.update();
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if( Gdx.input.isKeyPressed(Input.Keys.ESCAPE) ) {
Gdx.app.exit();
}
// Clear the last cell
layer.setCell(hoverTileX, hoverTileY, null);
// Convert screen coordinates to world coordinates
Vector3 worldCoordinates = new Vector3(Gdx.input.getX(0), Gdx.input.getY(0), 0);
camera.unproject(worldCoordinates);
hoverTileX = (int)(worldCoordinates.x);
hoverTileY = (int)(worldCoordinates.y);
TiledMapTileLayer layer = (TiledMapTileLayer)map.getLayers().get("collision");
if( Gdx.input.isTouched(0) ) {
//sprite.setPosition(hoverTileX - 0.5f, hoverTileY);
player.pos.x = hoverTileX - 0.5f;
player.pos.y = hoverTileY - 0.25f;
cell.setTile(animatedGoTile);
} else {
if (layer.getCell(hoverTileX, hoverTileY) != null) {
cell.setTile(cannotMoveToTile);
} else {
cell.setTile(canMoveToTile);
}
}
layer.setCell(hoverTileX, hoverTileY, cell);
mapRenderer.setView(camera);
mapRenderer.render();
mapRenderer.getSpriteBatch().begin();
mapRenderer.renderTileLayer(layer);
mapRenderer.getSpriteBatch().end();
spriteBatch.setProjectionMatrix(camera.combined);
spriteBatch.begin();
player.render(spriteBatch);
spriteBatch.end();
}
#Override
public void resize(int width, int height) {
horizontalTiles = (float) width / (float) height * verticalTiles;
camera = new OrthographicCamera(horizontalTiles, verticalTiles);
w = width;
h = height;
}
#Override
public void pause() {
}
#Override
public void resume() {
}
}
Looks like this is a problem because of the static notification bar on tablet because of the lack of hardware buttons. I just didn't think about that. Anyway, in the case of the TF101 it returns a resolution of 1280x752 so about 1.702 (80 : 47) ratio. If I use a suitable unit size, like 33.5 or 11.75 vertically I get the proper scaling and this seems to fix the problem of skewed pixels.
Also, while this is good for the TF101 tablet in my case it's not really a great solution. Here is a Gemserk series that talks about a nice solution.
http://blog.gemserk.com/2013/01/22/our-solution-to-handle-multiple-screen-sizes-in-android-part-one/

Categories

Resources