I am drawing with libgdx and using OrthographicCamera. During render I draw a bit more than the screen can contain. As OrthographicCamera is always centred my camera moves quickly to the last primitive a draw. That's not what I need. So I want my camera to move slowly
What I need is to draw a lot of squares they are in GameRoute.Level[] and to slowly "walk along them" with the camera
#Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
/*Drawing moving route*/
int x = 0, y = 0;
for(int i = 0; i < Route.Size; i++){
batch.draw(GameRoute.Level[i].Step, x, y);
if (GameRoute.Level[i].getDir() == 0) {
x += 64;
}
if (GameRoute.Level[i].getDir() == 1) {
y += 64;
}
}
camera.position.set(0, 0, 0);
GameRoute.ExpandLevel();
batch.end();
}
Solved, I remade the structure.
Now instead of having a huge moving route, I am moving a small object
Now future need in setting camera.
Related
I have a picture then used a flashlight type of light to only show where the mouse is hovering over. That part of the code works, but now I want to use if/else statements to zoom in on the selected area and then click again to zoom back out. Any other way to zoom in on specific area then back out of that area also helps. Really any help will be appreciated!
PImage ispy;
void setup () {
size(1024,768);
ispy = loadImage("ispy2.jpeg");
}
void draw () {
loadPixels();
ispy.loadPixels();
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int loc = x+y*width;
float r = red(ispy.pixels[loc]);
float g = green(ispy.pixels[loc]);
float b = blue(ispy.pixels[loc]);
float d = dist(mouseX, mouseY, x, y); //
float factor = map(d, 0, 200, 2, 0);
pixels[loc] = color(r*factor, g*factor, b*factor);
}
}
updatePixels();
}
Here is my interpretation of what you are talking about. We store a isClicked boolean to store the state of whether we should zoom in or not. When we are going to draw the image, we translate() to the mouse, then we scale(), then we translate() back the same amount that we moved before, but in the opposite direction. What this does is it does the scale transform around the mouse position.
One thing that I couldn't find a way around way your way of updating the pixels directly from the image and the flashlight effect. What the program is doing instead is using your method to make a mask image and applying that to a PGraphics object. Another thing that I noticed is that when just rendering straight to the screen, there is considerable lag from the scaling. Instead, I have moved the drawing to a PGraphics object. This improves the performance.
In the end, to render, the program is drawing everything on the PGraphics object, then applying the mask to that object to get the flashlight effect.
Here is the code that I have:
PImage ispy, distMask;
boolean isClicked = false;
PGraphics renderer;
void createDistanceMask(PImage distMask){ //Takes image and changes its pixels to "alpha" for the PGraphics renderer
distMask.loadPixels();
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int loc = x+(height-y-1)*width;
float d = dist(mouseX, mouseY, x, y); //
int factor = int(map(d, 0, 200, 400, 0)); //Pixel data will be between 0 and 255, must scale down later.
if (factor > 255)
factor = 255;
distMask.pixels[loc] = color(factor,factor,factor);
}
}
distMask.updatePixels();
}
void setup () {
size(1024,768, P2D);
ispy = loadImage("ispy2.jpeg");
distMask = new PImage(width,height);
renderer = createGraphics(width,height,P2D);
mouseX = width/2; //Not necessary, but will have black screen until mouse is moved
mouseY = height/2;
}
void draw () {
background(0);
pushMatrix();
createDistanceMask(distMask);
renderer.beginDraw(); //Starts processing stuff into PGraphics object
renderer.background(0);
if(isClicked){ //This is to get the zoom effect
renderer.translate(mouseX, mouseY);
renderer.scale(2);
renderer.translate(-mouseX, -mouseY);
}
renderer.image(ispy,0,0); //Render Image
renderer.endDraw();
renderer.mask(distMask); //Apply Distance mask for flashlight effect
image(renderer,0,0); //Draw renderer result to screen
popMatrix();
}
void mouseClicked(){
isClicked = !isClicked;
}
In my comment, I asked about having the screen move to the mouse, which is what this is doing. If you want to "freeze" the screen in one position, what you can do is store a lastMouseClickPosition PVector or simply just ints. Then, when translating, translate to the position instead of the PVector.
Here's the code that would change:
PVector lastClickPos = new PVector(); //Make the position
if(isClicked){ //When Rendering
renderer.translate(lastClickPos.x, lastClickPos.y);
renderer.scale(scalingFactor);
renderer.translate(-lastClickPos.x, -lastClickPos.y);
}
void mouseClicked(){ //At the bottom
isClicked = !isClicked;
lastClickPos.set(mouseX, mouseY);
}
I'm coding an Android game and I'm trying to put the character in the middle of the screen (X axis).
In order to get the middle of the screen I get the screen width withe the following command:
int phoneWidth = Resources.getSystem().getDisplayMetrics().widthPixels;
Then I divide phoneWidth by two and hoped that the character would appear in the middle of the screen but it appears slightly to the right.
This is the code that I use:
public void drawCharacter() {
charImg = new Texture("pika.PNG");
charSprite = new Sprite(charImg);
float ahaha = Gdx.graphics.getWidth();
charPosX = (float)phoneWidth/ 2;
}
#Override
public void render() {
ch.stop();
double elapsedSeconds = ch.getSeconds();
checkLevel();
handleObstacles();
scrollTimer = scrollTimer + Gdx.graphics.getDeltaTime() / 2;
if (scrollTimer > 1.0f)
scrollTimer = 0.0f;
sprite.setV(scrollTimer);
sprite.setV2(scrollTimer + 2);
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
charSprite.setPosition(charPosX, charPosY);
for (int i = 0; i < obstacles.size(); i++) {
obstacleSprites.get(i).setPosition(obstacles.get(i).getPosX(), obstacles.get(i).getPosY());
}
spriteBatch.begin();
sprite.draw(spriteBatch);
charSprite.draw(spriteBatch);
for (int i = 0; i < obstacleSprites.size(); i++) {
obstacleSprites.get(i).draw(spriteBatch);
}
spriteBatch.end();
moveCharacter();
moveObstacle();
}
Does anyone know where this error come from?
The left-hand edge of your sprite will be in the middle of the screen.
Subtract half the sprite width from half the screen width to draw the sprite centered horizontally.
Maybe my title doesn't fit very well but I will try to clearly explain.
In fact, I'm currently working on a little project using Libgdx. At the moment, the goal of this project is to be able to randomly display several circles on my screen.
I correctly displayed these circles on the screen but they are blinking.
#Override
public void render(float delta) {
renderer.begin(ShapeType.Filled);
if(!mapIsCreated)
{
Random rand = new Random();
int x, y;
for(int i=0;i<200;i++)
{
x = rand.nextInt(Gdx.graphics.getWidth());
y = rand.nextInt(Gdx.graphics.getHeight());
renderer.setColor(Color.DARK_GRAY);
renderer.circle(x, y, 5);
renderer.setColor(Color.GRAY);
renderer.circle(x, y, 3);
}
mapIsCreated = true;
}
renderer.end();
}
Are there any solutions to definitively fix them on the background without blinking/reloading effects ?
If more details are needed, please let me know.
You never seem to clear your screen.
You should call the following lines at the start of your render method:
// This is black, you can choose any color, technically one call is enough
Gdx.gl.glClearColor(0f, 0f, 0f, 1f);
// This line clears the screen (more precisely the color buffer, there are others but this one should be fine)
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Now, since it looks like you only want to generate them randomly once create them once in your initialization method (like the create method) and save them in an array/Collection:
// Global field
Array<Vector2> circlePositions = new Array<>();
// initialization method
renderer = new ShapeRenderer();
Random rand = new RandomXS128();
for (int i = 0; i < 200; i++)
{
circlePositions.add(
new Vector2(
rand.nextInt(Gdx.graphics.getWidth()),
rand.nextInt(Gdx.graphics.getHeight())));
circlePositions.add(
new Vector2(
rand.nextInt(Gdx.graphics.getWidth()),
rand.nextInt(Gdx.graphics.getHeight())));
}
Then in your render method you can draw your circles like this:
Gdx.gl.glClearColor(0f, 0f, 0f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
renderer.begin(ShapeType.Filled);
for (int i = 0; i < circlePositions.size; i++)
{
Vector2 pos = circlePositions.get(i);
if (i % 2 == 0)
{
renderer.setColor(Color.DARK_GRAY);
renderer.circle(pos.x, pos.y, 5);
} else
{
renderer.setColor(Color.GRAY);
renderer.circle(pos.x, pos.y, 3);
}
}
renderer.end();
If you don't want to redraw everything at e.g. 60 fps, then take a look at non continues rendering.
I want to implement a kind of drums. For every hit I want to play a song. So I need to detect every "hit" and the position. before I start implementing a function who will analyse the positions and detect "hits" I want to be sure that there is no other solution, so is there any event, gesture detection who allow me to detect that ?
As far as I know there is no "event" that is defined natively other than stream callbacks which are called when you receive data such as the joint positions and depth image which should be enough to get you started.
I would take a look at this:https://code.google.com/p/kineticspace/ in order to know what to expect or how to proceed with your own code.
Once you manage to get the skeleton data just find where the hand is at that time, put a threshold to its position and start tracking for a certain amount time and see if its movement path fits your pattern for a particular gesture such as "translation in y direction for x amount of seconds". Then you have very simple "hit" gesture detection. This can get as complex as you need, but there is not much to it at the basics in terms of what you receive from the library side.
Good luck.
I made a drum kit with the Kinect using this is a wonderful class for placing and using boxes in Kinect.
Import Libraries:
import processing.opengl.*;
import SimpleOpenNI.*;
Use something like this bit of code inside your Setup()
myTrigger = new Hotpoint(200, 10, 800, size);
Use the methods inside your draw()
if(myTrigger.currentlyHit()) {
myTrigger.play();
println("trigger hit");
}
Use the following methods inside this class!
class Hotpoint {
PVector center;
color fillColor;
color strokeColor;
int size;
int pointsIncluded;
int maxPoints;
boolean wasJustHit;
int threshold;
Hotpoint(float centerX, float centerY, float centerZ, int boxSize) {
center = new PVector(centerX, centerY, centerZ);
size = boxSize;
pointsIncluded = 0;
maxPoints = 1000;
threshold = 0;
fillColor = strokeColor = color(random(255), random(255), random(255));
}
void setThreshold( int newThreshold ){
threshold = newThreshold;
}
void setMaxPoints(int newMaxPoints) {
maxPoints = newMaxPoints;
}
void setColor(float red, float blue, float green){
fillColor = strokeColor = color(red, blue, green);
}
boolean check(PVector point) {
boolean result = false;
if (point.x > center.x - size/2 && point.x < center.x + size/2) {
if (point.y > center.y - size/2 && point.y < center.y + size/2) {
if (point.z > center.z - size/2 && point.z < center.z + size/2) {
result = true;
pointsIncluded++;
}
}
}
return result;
}
void draw() {
pushMatrix();
translate(center.x, center.y, center.z);
fill(red(fillColor), blue(fillColor), green(fillColor),
255 * percentIncluded());
stroke(red(strokeColor), blue(strokeColor), green(strokeColor), 255);
box(size);
popMatrix();
}
float percentIncluded() {
return map(pointsIncluded, 0, maxPoints, 0, 1);
}
boolean currentlyHit() {
return (pointsIncluded > threshold);
}
boolean isHit() {
return currentlyHit() && !wasJustHit;
}
void clear() {
wasJustHit = currentlyHit();
pointsIncluded = 0;
}
}
Some Context:
I am creating an Android game which draws a maze onto a canvas against a background image, this uses a square block and therefore the maze is always automtically zoomed in to a 5 x 5 square, of a maze that may be 20 x 20. The maze is drawn by simply running through a set of for loops and then drawing lines in the relevent places. This is all working perfectly, however I am having an issue with getting my onDraw to work smoothly. This is occuring due to the fact that everytime I invalidate I have to re-run the for look and run various if statements to check positions (unfortunetly this process cannot be improved).
The Question:
I am looking to re-write the way my maze is drawn onto the canvas, below are the 3 main features I need to implement:
1 - Draw the whole maze onto the canvas (this is easy enough)
2 - Zoom in on the maze so only a 5 x 5 is shown
3 - Move the character (who is always centered on the screen) and draw the next seciton of the maze
Now as mentioned above drawing the whole maze is easy enough and will make the onDraw signifcatly quicker as their is no need to run the for loop on invaldate, it can be done once when the level is first loaded up.
In terms of point 2 & 3, the way I see this working is the charcacter to be drawn in the middle of the canvas then a 2d birdseye view camera to be attached / linked to the characters movement. This camera would also need to be zoomed in to an extent that it only displays a 5 x 5 of the overall maze grid. Then as the charcater moves the camera moves with the character and displays the next section of the maze which has already been drawn. I have tried a few things and done some reasearch however I have never worked with canvas before and no idea really where to start and if this is even possible.
So to sum up the main part of the question is whether their is a way to link a birdseye view camera to a character which is zoomed in and moves with the character image.
Below is a snippet as to how the maze is currently drawn, using 2 sets of for loops checking against 2 sets of boolean arrays[][], which simply store the vertical and horixaonl lines to be drawn.
#Override
protected void onDraw(Canvas canvas)
{
canvas.drawRect(0, 0, width, 100, background);
RectBackground.set(0,0, FullScreenWidth, FullScreenWidth);
canvas.drawBitmap(gameBackground, null, RectBackground, null);
for(int i = 0; i < 5; i++)
{
for(int j = 0; j < 5; j++)
{
float x = j * totalCellWidth;
float y = i * totalCellHeight;
indexY = i + currentY;
indexX = j + currentX;
// Draw Verticle line (y axis)
if (indexY < vLength && indexX < vLines[indexY].length && vLines[indexY][indexX])
{
RectOuterBackground.set((int)x + (int)cellWidth, (int)y, (int)x + (int)cellWidth + 15, (int)y + (int)cellHeight + 15);
canvas.drawBitmap(walls, null, RectOuterBackground, null);
}
// Draws Horizontal lines (x axis)
if (indexY < hLength && indexX < hLines[indexY].length && hLines[indexY][indexX])
{
RectOuterBackground.set((int)x, (int)y + (int)cellHeight,(int)x + (int)cellWidth + 15,(int)y + (int)cellHeight + 15);
canvas.drawBitmap(walls, null, RectOuterBackground, null);
}
}
}
}
To make the drawing faster, you can double buffer the canvas by drawing directly into a bitmap and flashing the bitmap into the canvas like this. It's very fast.
private void init()
{
//variables below are class-wide variables
b = Bitmap.createBitmap(cwidth, cheight, Bitmap.Config.ARGB_8888);
bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bitmapPaint.setStyle(Paint.Style.STROKE);
bitmapPaint.setStrokeWidth(3);
myPaint.setColor(0xff000000);
myCanvas = new Canvas(b);
}
protected void onDraw(Canvas c)
{
super.onDraw(c);
c.drawBitmap(b, 0, 0, myPaint);
for(int i = 0; i < number lines; i++)
{
//draw here using myPath
}
if(b != null)
c.drawBitmap(b, 0, 0, myPaint);
myCanvas.drawPath(myPath, bitmapPaint);
}
Then, to "move around" I would suggest using a crop box. What this means is that a 1:1 scale, the image is larger than the viewport displayed on the screen. Really what's happening when someone "moves" is the bitmap is being moved beneath the crop box.
You could use BitmapRegionDecoder and display only the region the character is in (this might be slowish) or by using
public void drawBitmap (Bitmap bitmap, Rect src, RectF dst, Paint paint)
The src parameter here allows you to specify a small region of the bitmap to display. It is effectively a crop box.
To zoom in and out you need to multiply the coordinates by a number( zoom factor)
int x1 = (int)x + (int)cellWidth;
int y1 = (int)y;
int x2 = (int)x + (int)cellWidth + 15;
int y2 = (int)y + (int)cellHeight + 15;
RectOuterBackground.set(x1*zoom, y1*zoom, x2*zoom, y2*zoom);
note that zoom must be a floating point number, using zoom=2 that makes everything twice as big.
if you want to put the camera on top of the cell (xc, yc) you need to do this:
RectOuterBackground.set( (x1-xc)*zoom, (y1-yc)*zoom, (x2-xc)*zoom, (y2-yc)*zoom);
Try first drawing the whole maze, and soon you will figure out how to only draw the bit of the maze that is only inside the screen
I hope this helps and let me know if you have any questions :)