it seems as though i cannot get the draw method to work???
it seems as though the bullet.draw(batcher)
does not work and i cannot understand why as the bullet is a sprite.
i have made a Sprite[] and added them as animation.
could that be it?
i tried
batcher.draw(AssetLoader.bulletAnimation.getKeyFrame(runTime), bullet.getX(), bullet.getY(), bullet.getOriginX() / 2, bullet.getOriginY() / 2, bullet.getWidth(), bullet.getHeight(), 1, 1, bullet.getRotation());
but that dont work, the only way it draws is this
batcher.draw(AssetLoader.bulletAnimation.getKeyFrame(runTime), bullet.getX(), bullet.getY());
below is the code.
// this is in a Asset Class
texture = new Texture(Gdx.files.internal("SpriteN1.png"));
texture.setFilter(TextureFilter.Nearest, TextureFilter.Nearest);
bullet1 = new Sprite(texture, 380, 350, 45, 20);
bullet1.flip(false, true);
bullet2 = new Sprite(texture, 425, 350, 45, 20);
bullet2.flip(false, true);
Sprite[] bullets = { bullet1, bullet2 };
bulletAnimation = new Animation(0.06f, bullets);
bulletAnimation.setPlayMode(Animation.PlayMode.LOOP);
// this is the GameRender class
public class GameRender() {
private Bullet bullet;
private Ball ball;
public GameRenderer(GameWorld world) {
myWorld = world;
cam = new OrthographicCamera();
cam.setToOrtho(true, 480, 320);
batcher = new SpriteBatch();
// Attach batcher to camera
batcher.setProjectionMatrix(cam.combined);
shapeRenderer = new ShapeRenderer();
shapeRenderer.setProjectionMatrix(cam.combined);
// Call helper methods to initialize instance variables
initGameObjects();
initAssets();
}
private void initGameObjects() {
ball = GameWorld.getBall();
bullet = myWorld.getBullet();
scroller = myWorld.getScroller();
}
private void initAssets() {
ballAnimation = AssetLoader.ballAnimation;
bulletAnimation = AssetLoader.bulletAnimation;
}
public void render(float runTime) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL30.GL_COLOR_BUFFER_BIT);
batcher.begin();
// Disable transparency
// This is good for performance when drawing images that do not require
// transparency.
batcher.disableBlending();
// The ball needs transparency, so we enable that again.
batcher.enableBlending();
batcher.draw(AssetLoader.ballAnimation.getKeyFrame(runTime), ball.getX(), ball.getY(), ball.getWidth(), ball.getHeight());
batcher.draw(AssetLoader.bulletAnimation.getKeyFrame(runTime), bullet.getX(), bullet.getY());
// End SpriteBatch
batcher.end();
}
}
// this is the gameworld class
public class GameWorld {
public static Ball ball;
private Bullet bullet;
private ScrollHandler scroller;
public GameWorld() {
ball = new Ball(480, 273, 32, 32);
bullet = new Bullet(10, 10);
scroller = new ScrollHandler(0);
}
public void update(float delta) {
ball.update(delta);
bullet.update(delta);
scroller.update(delta);
}
public static Ball getBall() {
return ball;
}
public ScrollHandler getScroller() {
return scroller;
}
public Bullet getBullet() {
return bullet;
}
}
is there anyway so make the sprite work?
i am adding the bullet class to see if there could be something wrong there.
public class Bullet extends Sprite {
public static final float BULLET_HOMING = 6000;
public static final float BULLET_SPEED = 300;
private Vector2 velocity;
private float lifetime;
public Bullet(float x, float y) {
velocity = new Vector2(0, 0);
setPosition(x, y);
}
public void update(float delta) {
float targetX = GameWorld.getBall().getX();
float targetY = GameWorld.getBall().getY();
float dx = targetX - getX();
float dy = targetY - getY();
float distToTarget = (float) Math.sqrt(dx * dx + dy * dy);
dx /= distToTarget;
dy /= distToTarget;
dx *= BULLET_HOMING;
dy *= BULLET_HOMING;
velocity.x += dx * delta;
velocity.y += dy * delta;
float vMag = (float) Math.sqrt(velocity.x * velocity.x + velocity.y * velocity.y);
velocity.x /= vMag;
velocity.y /= vMag;
velocity.x *= BULLET_SPEED;
velocity.y *= BULLET_SPEED;
Vector2 v = velocity.cpy().scl(delta);
setPosition(getX() + v.x, getY() + v.y);
setOriginCenter();
setRotation(velocity.angle());
lifetime += delta;
setRegion(AssetLoader.bulletAnimation.getKeyFrame(lifetime));
}
}
Your keyframes are kept in an array called bullets, but when you call the Animation constructor you pass something called 'aims' as the second argument. You should try instead passing 'bullets', as in:
bulletAnimation = new Animation(0.06f,bullets);
You shouldn't have a problem with using a Sprite[] as the Sprite class extends TextureRegion I think.
------ OP fixed the typo and still didn't work------
I think the problem will be with the origin arguments of the batcher.draw()call. The position of the Sprite is relative to the origin of the SpriteBatch's co-ordinate system, and the origin of the Sprite is relative to this position (i.e. the bottom-left corner of the Sprite rectangle). To get an origin in the center of the Sprite, i think originX should be width/2 and originY should be height/2. So try:
batcher.draw(AssetLoader.bulletAnimation.getKeyFrame(runTime),bullet.getX(),bullet.getY(), bullet.getWidth()/2,bullet.getHeight()/2,bullet.getWidth(),bullet.getHeight(),1,1,bullet.getRotation());
Because if your getOriginX/Y methods return origins relative to the SpriteBatcher's co-ordinate system(the screen co-ordinates), then your Sprites could be rotating and scaling around some ridiculous origin and end up being drawn off-screen.
I hope I'm right and it's problem solved.
----- OP posted further code, the 'bullet' class-----
When you call bullet.getWidth() and bullet.getHeight() in your draw method, these will return 0.0f because you haven't specified values for them. Remember the Sprites you are actually drawing are bullet1 and bullet2 from your AssetLoader class. Try setting bullet's width and height with:
setSize(AssetLoader.bullet1.getWidth(), AssetLoader.bullet1.getHeight());
in your bullet constructor.
I don't think you need to use setRegion() in your bullet class either, again, because the Sprites you're actually drawing are bullet1 and 2.
fingers crossed.
try and change the update method to this
Vector2 target = new Vector2(GameWorld.getBall().getX(), GameWorld.getBall().getY());
target.sub(getX(), getY());
target.nor().scl(BULLET_HOMING);
velocity.add(target.scl(delta));
velocity.nor().scl(BULLET_SPEED);
Vector2 v = velocity.cpy().scl(delta);
translate(v.x, v.y);
setOriginCenter();
setRotation(velocity.angle());
that should clean your code a little
Related
I've been working on this a while and feel so close! Should be easy, but I'm still new to this.
The skeleton hand data is being passed in as joints[KinectPV2.JointType_HandLeft] and can be accessed through joint.getX() and joint.getY(). I want to pass this data into the update function to replace mouseX and mouseY. I'm guessing I have to create global variables to access it within the update function or maybe I have to pass the skeleton data as parameters into the update function? How can I replace the mouse position data with the hand position?
import KinectPV2.*;
KinectPV2 kinect;
private class MyFluidData implements DwFluid2D.FluidData{
// update() is called during the fluid-simulation update step.
#Override
public void update(DwFluid2D fluid) {
float px, py, vx, vy, radius, vscale, temperature;
radius = 15;
vscale = 10;
px = width/2;
py = 50;
vx = 1 * +vscale;
vy = 1 * vscale;
radius = 40;
temperature = 1f;
fluid.addDensity(px, py, radius, 0.2f, 0.3f, 0.5f, 1.0f);
fluid.addTemperature(px, py, radius, temperature);
particles.spawn(fluid, px, py, radius, 100);
boolean mouse_input = mousePressed;
// add impulse: density + velocity, particles
if(mouse_input && mouseButton == LEFT){
radius = 15;
vscale = 15;
px = mouseX;
py = height-mouseY;
vx = (mouseX - pmouseX) * +vscale;
vy = (mouseY - pmouseY) * -vscale;
fluid.addDensity (px, py, radius, 0.25f, 0.0f, 0.1f, 1.0f);
fluid.addVelocity(px, py, radius, vx, vy);
particles.spawn(fluid, px, py, radius*2, 300);
}
// add impulse: density + temperature, particles
if(mouse_input && mouseButton == CENTER){
radius = 15;
vscale = 15;
px = mouseX;
py = height-mouseY;
temperature = 2f;
fluid.addDensity(px, py, radius, 0.25f, 0.0f, 0.1f, 1.0f);
fluid.addTemperature(px, py, radius, temperature);
particles.spawn(fluid, px, py, radius, 100);
}
// particles
if(mouse_input && mouseButton == RIGHT){
px = mouseX;
py = height - 1 - mouseY; // invert
radius = 50;
particles.spawn(fluid, px, py, radius, 300);
}
}
}
int viewport_w = 1280;
int viewport_h = 720;
int viewport_x = 230;
int viewport_y = 0;
int gui_w = 200;
int gui_x = 20;
int gui_y = 20;
int fluidgrid_scale = 3;
DwFluid2D fluid;
// render targets
PGraphics2D pg_fluid;
//texture-buffer, for adding obstacles
PGraphics2D pg_obstacles;
// custom particle system
MyParticleSystem particles;
// some state variables for the GUI/display
int BACKGROUND_COLOR = 0;
boolean UPDATE_FLUID = true;
boolean DISPLAY_FLUID_TEXTURES = false;
boolean DISPLAY_FLUID_VECTORS = false;
int DISPLAY_fluid_texture_mode = 0;
boolean DISPLAY_PARTICLES = true;
public void settings() {
size(viewport_w, viewport_h, P2D);
smooth(4);
}
public void setup() {
surface.setLocation(viewport_x, viewport_y);
// main library context
DwPixelFlow context = new DwPixelFlow(this);
context.print();
context.printGL();
// fluid simulation
fluid = new DwFluid2D(context, viewport_w, viewport_h, fluidgrid_scale);
// set some simulation parameters
fluid.param.dissipation_density = 0.999f;
fluid.param.dissipation_velocity = 0.99f;
fluid.param.dissipation_temperature = 0.80f;
fluid.param.vorticity = 0.10f;
fluid.param.timestep = 0.25f;
fluid.param.gridscale = 8f;
// interface for adding data to the fluid simulation
MyFluidData cb_fluid_data = new MyFluidData();
fluid.addCallback_FluiData(cb_fluid_data);
// pgraphics for fluid
pg_fluid = (PGraphics2D) createGraphics(viewport_w, viewport_h, P2D);
pg_fluid.smooth(4);
pg_fluid.beginDraw();
pg_fluid.background(BACKGROUND_COLOR);
pg_fluid.endDraw();
// pgraphics for obstacles
pg_obstacles = (PGraphics2D) createGraphics(viewport_w, viewport_h, P2D);
pg_obstacles.smooth(4);
pg_obstacles.beginDraw();
pg_obstacles.clear();
float radius;
radius = 200;
pg_obstacles.stroke(64);
pg_obstacles.strokeWeight(1);
pg_obstacles.fill(0);
pg_obstacles.rect(1*width/2f, 1*height/4f, radius, radius/2, 10);
pg_obstacles.stroke(64);
pg_obstacles.strokeWeight(1);
pg_obstacles.fill(0);
pg_obstacles.rect(1*width/3.5f, 1*height/2.5f, radius, radius/2, 10);
//// border-obstacle
//pg_obstacles.strokeWeight(20);
//pg_obstacles.stroke(64);
//pg_obstacles.noFill();
//pg_obstacles.rect(0, 0, pg_obstacles.width, pg_obstacles.height);
pg_obstacles.endDraw();
fluid.addObstacles(pg_obstacles);
// custom particle object
particles = new MyParticleSystem(context, 1024 * 1024);
kinect = new KinectPV2(this);
//Enables depth and Body tracking (mask image)
kinect.enableDepthMaskImg(true);
kinect.enableSkeletonDepthMap(true);
kinect.init();
background(0);
frameRate(60);
}
public void draw() {
PImage imgC = kinect.getDepthMaskImage();
image(imgC, 0, 0, 320, 240);
//get the skeletons as an Arraylist of KSkeletons
ArrayList<KSkeleton> skeletonArray = kinect.getSkeletonDepthMap();
//individual joints
for (int i = 0; i < skeletonArray.size(); i++) {
KSkeleton skeleton = (KSkeleton) skeletonArray.get(i);
//if the skeleton is being tracked compute the skleton joints
if (skeleton.isTracked()) {
KJoint[] joints = skeleton.getJoints();
color col = skeleton.getIndexColor();
fill(col);
stroke(col);
drawHandState(joints[KinectPV2.JointType_HandRight]);
drawHandState(joints[KinectPV2.JointType_HandLeft]);
}
}
// update simulation
if(UPDATE_FLUID){
fluid.addObstacles(pg_obstacles);
fluid.update();
particles.update(fluid);
}
// clear render target
pg_fluid.beginDraw();
pg_fluid.background(BACKGROUND_COLOR);
pg_fluid.endDraw();
// render fluid stuff
if(DISPLAY_FLUID_TEXTURES){
// render: density (0), temperature (1), pressure (2), velocity (3)
fluid.renderFluidTextures(pg_fluid, DISPLAY_fluid_texture_mode);
}
if(DISPLAY_FLUID_VECTORS){
// render: velocity vector field
fluid.renderFluidVectors(pg_fluid, 10);
}
if( DISPLAY_PARTICLES){
// render: particles; 0 ... points, 1 ...sprite texture, 2 ... dynamic points
particles.render(pg_fluid, BACKGROUND_COLOR);
}
// display
image(pg_fluid , 320, 0);
image(pg_obstacles, 320, 0);
// display number of particles as text
//String txt_num_particles = String.format("Particles %,d", particles.ALIVE_PARTICLES);
//fill(0, 0, 0, 220);
//noStroke();
//rect(10, height-10, 160, -30);
//fill(255,128,0);
//text(txt_num_particles, 20, height-20);
// info
//String txt_fps = String.format(getClass().getName()+ " [size %d/%d] [frame %d] [fps %6.2f]", fluid.fluid_w, fluid.fluid_h, fluid.simulation_step, frameRate);
//surface.setTitle(txt_fps);
}
//draw a ellipse depending on the hand state
void drawHandState(KJoint joint) {
noStroke();
handState(joint.getState());
//println(joint.getState());
pushMatrix();
translate(joint.getX(), joint.getY(), joint.getZ());
//println(joint.getX(), joint.getY(), joint.getZ());
ellipse(joint.getX(), joint.getY(), 70, 70);
popMatrix();
}
/*
Different hand state
KinectPV2.HandState_Open
KinectPV2.HandState_Closed
KinectPV2.HandState_Lasso
KinectPV2.HandState_NotTracked
*/
//Depending on the hand state change the color
void handState(int handState) {
switch(handState) {
case KinectPV2.HandState_Open:
fill(0, 255, 0);
break;
case KinectPV2.HandState_Closed:
fill(255, 0, 0);
break;
case KinectPV2.HandState_Lasso:
fill(0, 0, 255);
break;
case KinectPV2.HandState_NotTracked:
fill(100, 100, 100);
break;
}
}
I'm guessing I have to create global variables to access it within the update function or maybe I have to pass the skeleton data as parameters into the update function?
What happened when you tried those approaches?
Either approach sounds fine. You could store the variables in a sketch-level variable, set those variables from the kinect code, then use those variables in your drawing code. Or you could pass the variables as a parameter to the drawing code. Either should work fine. I'd probably go for the first approach because it sounds easier to me, but that's just my personal preference.
I suggest working in smaller chunks. Create a separate program that ignores the kinect for now. Create a hard-coded sketch-level variable that holds the same type of information you'd get from the kinect. Then write drawing code that uses that hard-coded variable to draw the frame. Get that working perfectly before you try adding the kinect code back in.
Then if you get stuck on a specific step, you can post a MCVE and we can go from there. Good luck.
I'm working on a simple game and i need these squareBumpers which simply stands idle and when got hit, collides and reflects the ball. But currently the ball just flies through my squareBumpers. I can only use java awt and swing libraries. Here's the code:
class squareBumper {
private int x = 300;
private int y = 300;
private Color color = new Color(66,139,139);
public void paint(Graphics g) {
Rectangle clipRect = g.getClipBounds();
g.setColor(color);
g.fillRect(x, y, 31, 31);
}
}
class BouncingBall {
// Overview: A BouncingBall is a mutable data type. It simulates a
// rubber ball bouncing inside a two dimensional box. It also
// provides methods that are useful for creating animations of the
// ball as it moves.
private int x = 320;
private int y = 598;
public static double vx;
public static double vy;
private int radius = 6;
private Color color = new Color(0, 0, 0);
public void move() {
// modifies: this
// effects: Move the ball according to its velocity. Reflections off
// walls cause the ball to change direction.
x += vx;
if (x <= radius) { x = radius; vx = -vx; }
if (x >= 610-radius) { x = 610-radius; vx = -vx; }
y += vy;
if (y <= radius) { y = radius; vy = -vy; }
if (y >= 605-radius) { y = 605-radius; vy = -vy; }
}
public void randomBump() {
// modifies: this
// effects: Changes the velocity of the ball by a random amount
vx += (int)((Math.random() * 10.0) - 5.0);
vx = -vx;
vy += (int)((Math.random() * 10.0) - 5.0);
vy = -vy;
}
public void paint(Graphics g) {
// modifies: the Graphics object <g>.
// effects: paints a circle on <g> reflecting the current position
// of the ball.
// the "clip rectangle" is the area of the screen that needs to be
// modified
Rectangle clipRect = g.getClipBounds();
// For this tiny program, testing whether we need to redraw is
// kind of silly. But when there are lots of objects all over the
// screen this is a very important performance optimization
if (clipRect.intersects(this.boundingBox())) {
g.setColor(color);
g.fillOval(x-radius, y-radius, radius+radius, radius+radius);
}
}
public Rectangle boundingBox() {
// effect: Returns the smallest rectangle that completely covers the
// current position of the ball.
// a Rectangle is the x,y for the upper left corner and then the
// width and height
return new Rectangle(x-radius, y-radius, radius+radius+1, radius+radius+1);
}
}
Take a look at the classes that implement the Shape interface. There are ellipses and other shapes, and they all implement a intersects(Rectangle2D) method. It might help you if you don't want to perform intersection yourself.
As for dealing with the collision, well, it depends on the level of accuracy you want. Simply deflecting the ball of edges is quite easy. Just determine whether the collided side of the rectangle is vertical or horizontal, and negate the corresponding velocity component accordingly. If you want to handle the corners, well that is a bit more complicated.
You need to detect when the ball has collided with the bumper. You have the boundingBox() method of BouncingBall, this will get you a rectangle that contains your ball. So you need to check if this rectangle intersects your square bumper (which implies a collision), and then do something with that.
I'm trying to make a java 2d game, and it seems to work out fine in general. The only problem is, that I can't figure out how to place my "delta" time, to make the movements move the same on 30 FPS as on 1000 FPS.
This is my code for the Entity class:
import java.awt.Rectangle;
import map.Tile;
import graphics.Sprite;
public class Entity {
private String name;
private float positionx, positiony; // Current coordinate
private int targetx,targety; // Target coordinate
private double vx, vy; // Current vector
private double lx, ly; // Last vector
private float speed;
private Sprite sprite;
public Entity(String name, int x, int y, Sprite sprite){
this.name = name;
this.speed = 1f;
this.positionx = x;
this.positiony = y;
this.sprite = sprite;
main.Main.e.addEntity(this); // These kind of calls are ugly, and should be fixed.
}
public void remove(){
main.Main.e.removeEntity(this);
sprite.remove();
}
public void setVector(double vx, double vy){
this.vx = vx;
this.vy = vy;
}
public void update(long delta){
//Multiply modifier to make it act the same on 30 fps as 1000 fps.
vx = vx*delta;
vy = vy*delta;
// Calculate vector
double distance = Math.sqrt((vx * vx) + (vy * vy));
if(distance > 0){ // Have we reached the target yet?
vx = ((vx / distance));
vy = ((vy / distance));
}else{
vx = 0;
vy = 0;
}
//Check collision with objects:
Rectangle rx = new Rectangle((int) (vx+positionx), (int)positiony, 32, 32);
Rectangle ry = new Rectangle((int) positionx, (int)(vy+positiony), 32, 32);
for(Entity e : main.Main.e.getEntities()){
if(this != e){
if(isIntersecting(rx, e.getBounds())){
vx = 0; // Disallow x direction.
}
if(isIntersecting(ry, e.getBounds())){
vy = 0; // Disallow y direction.
}
}
}
//Check tiles:
for(Tile t : main.Main.m.getNeighbours(positionx,positiony)){
if(t.isBlocking()){
if(isIntersecting(rx, t.getBounds())){
vx = 0;
}
if(isIntersecting(ry, t.getBounds())){
vy = 0;
}
}
}
//Update the position:
positionx += vx*speed;
positiony += vy*speed;
//Animate:
animate(vx, vy);
}
public boolean isIntersecting(Rectangle r1, Rectangle r2){
return r1.intersects(r2);
}
public Rectangle getBounds(){
return new Rectangle((int) positionx,(int) positiony,32,32);
}
public void setMoveTo(int x, int y){
this.targetx = x;
this.targety = y;
}
//This function is used by the bots, and not on players (they are setting the vector and use update directly):
public void moveTo(long delta){
setVector((targetx-positionx),(targety-positiony));
update(delta);
}
public void animate(double dx, double dy){
sprite.setPosition((int)positionx, (int)positiony);
if(dx > 0){
sprite.setAnimation(0, 7, 100); // Walk right.
}else if(dx < 0){
sprite.setAnimation(1, 7, 100); // Walk left.
}else{
if(lx > 0){
sprite.setAnimation(2, 3, 200); // Stand right.
}else if(lx < 0){
sprite.setAnimation(3, 3, 200); // Stand left.
}
}
lx = dx;
ly = dy;
}
}
The two problems, that I always run into:
1# The game runs differently on 60FPS than on 500FPS.
2# The game runs the same on 60FPS as 500FPS, but my collision screws up, and I can't move closer than 15px from the other object. I think I need to implement something like: If I can't get 10px closer, then move it 10px closer, but I don't know how to implement it.
How can I implement it correctly? That would help a lot!
The easiest way would be to consider that if you want a constant displacement with a constant velocity you can scale all the deltas relative to the delta of 30 FPS like so:
So if you run at 60 FPS but want the same displacement as on 30FPS alpha would be (1/30)/(1/60) = 2
So
Remove vx = vx*delta;
vy = vy*delta;
and change your position update to
alpha = (1.0/30)*delta;
positionx += alpha*vx*speed;
positiony += alpha*vy*speed;
This is only a crude solution, let me know how it works, I will drop in later and update for a more correct solution (taking into account that delta is not always 1/FPS due to rendering and computation taking some time).
Edit: Variable delta will come later. But some optimizations:
You don't need to construct a rectangle in both Y and X for collisiondetection, try drawing two rectangles, if they intersect they do so on both axis. Just create a rectangle from vx + posx, vy+posy and check for intersection with this.
The above should half your collisionchecks. For further optimization consider using a QuadTree an implementation can be found here.
For the problem of "blocky" collision testing (where you stop X pixels from the blocking object). You can do the following, in pseudocode:
if(new position will make this colide)
while(this.position is more than one pixel away from blocking object)
keep moving one pixel
This will make you stop 1px from the target.
So I understand the concept. The idea is that box2d more or less works in meters, so you need to do a conversion from pixels to it. Makes sense. I was following the tutorial/intro to box2d here. It mentions to do the conversion and gives you some example amounts to use. Now, that's all well and good, but I find when I'm using such techniques, the debugger box doesn't seem to render where they should. The collision does work as expected however.
In my GameScreen class, here's how I initialize the ground:
ground = new BodyDef();
// set the position half way up the ground
ground.position.set(0,16 * GameScreen.WORLD_TO_BOX);
groundBody = world.createBody(ground);
groundShape = new PolygonShape();
// make the height 16px so it doubles to 32
groundShape.setAsBox(Gdx.graphics.getWidth() * GameScreen.WORLD_TO_BOX, 16.0f * GameScreen.WORLD_TO_BOX);
groundBody.createFixture(groundShape, 0.0f);
My render method in that screen is like so:
public void render(float delta) {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
camera.update();
stateTime += Gdx.graphics.getDeltaTime();
batch.begin();
batch.draw(background, 0, Gdx.graphics.getHeight() - 512, 512, 512);
batch.draw(trailingBackground, 512, Gdx.graphics.getHeight() - 512);
int heightToCover = Gdx.graphics.getHeight() - 512;
int widthToCover = Gdx.graphics.getWidth();
for(int w = 0; w < widthToCover; w += 32) {
for(int h = 0; h < heightToCover; h += 32) {
batch.draw(lightBackgroundTile, w, h, 32, 32);
}
}
player.update();
player.render(stateTime, batch);
batch.end();
levels.get(currentLevel).render(camera);
// physics updates
world.step(1/60f, 6, 2);
debugRenderer.render(world, camera.combined);
}
Here's the constructor of the player class, so you can see how im setting up its collision box2d objects. I also pasted the update method which is called in the above render loop to adjust the sprites position.
public Player(int x, int y, World world) {
super();
playerTexture = new Texture(Gdx.files.internal("assets/hero.png"));
init(x, y, 128, 128, playerTexture, false, world);
bodyDef = new BodyDef();
bodyDef.type = BodyType.DynamicBody;
bodyDef.position.set(x * GameScreen.WORLD_TO_BOX, y * GameScreen.WORLD_TO_BOX);
body = getWorld().createBody(bodyDef);
collisionBox = new PolygonShape();
collisionBox.setAsBox(32 * GameScreen.WORLD_TO_BOX, 64 * GameScreen.WORLD_TO_BOX, new Vector2(64 * GameScreen.WORLD_TO_BOX, 64 * GameScreen.WORLD_TO_BOX), 0.0f);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = collisionBox;
fixtureDef.density = 10f;
fixtureDef.friction = 0.4f;
fixtureDef.restitution = 0f;
body.createFixture(fixtureDef);
collisionBox.dispose();
addFrame(0, 0, 128, 128);
}
public void update() {
this.setX((int) ((body.getPosition().x) * GameScreen.BOX_TO_WORLD));
this.setY((int) ((body.getPosition().y) * GameScreen.BOX_TO_WORLD));
}
Now, when I remove the multiplication of those static floats in the various calculations, sizes, etc, the collision remains correct and the debugger box shows up. However passing the raw pixels to box2d feels wrong. Is there something I'm missing here as to why the debugging boxes don't show up as is?
I do like you are doing but might be a little different.
Might be a little overkill but here's my jucl port
jucl/Android - pastebin
Then I just have utility classes ie:
public class Pixel {
public static float toMeter(float pixels) {
return (float)LengthConversions.Pixel2SIf(pixels);
}
public static Vector2 toMeter(Vector2 vecPixel) {
return new Vector2(Pixel.toMeter(vecPixel.x), Pixel.toMeter(vecPixel.y));
}
}
public class Meter {
public static final float METERS_PER_PIXEL = (float) LengthConversions.SI_PIXEL;
public static float toPixel(float meter) {
return (float)LengthConversions.SI2Pixelf(meter);
}
}
In my initialize:
int graphicsWidth = Gdx.graphics.getWidth();
int graphicsHeight = Gdx.graphics.getHeight();
CAMERA_WIDTH_METERS = Pixel.toMeter(graphicsWidth);
CAMERA_HEIGHT_METERS = Pixel.toMeter(graphicsHeight);
Then in my game classes (like your Player class). In my case it was a pinball game so i have Flipper, Ball, Bumper, etc. I have a #Override render() method where I sync up the sprite with the physics body.
Here's an example file..sry it's messy but might be helpful.
Pinball Engine Class file
I'm trying to make an object appear where the person last touched. However when I try to do so it appears in the wrong place. I assume this is because of the fact the coordinates that the input returns is different to the display coordinates, my code is as follows:
public class Core implements ApplicationListener, InputProcessor
{ //Has to be here otherwise the code formatting becomes buggy
private Mesh squareMesh;
private PerspectiveCamera camera;
private Texture texture;
private SpriteBatch spriteBatch;
Sprite sprite;
float moveX = 0;
private final Matrix4 viewMatrix = new Matrix4();
private final Matrix4 transformMatrix = new Matrix4();
#Override
public void create()
{
Gdx.input.setInputProcessor(this);
texture = new Texture(Gdx.files.internal("door.png"));
spriteBatch = new SpriteBatch();
sprite = new Sprite(texture);
sprite.setPosition(0, 0);
viewMatrix.setToOrtho2D(0, 0, 480, 320);
float x = 0;
float y = 0;
}
#Override
public void dispose()
{
}
#Override
public void pause()
{
}
#Override
public void render()
{
viewMatrix.setToOrtho2D(0, 0, 480, 320);
spriteBatch.setProjectionMatrix(viewMatrix);
spriteBatch.setTransformMatrix(transformMatrix);
spriteBatch.begin();
spriteBatch.disableBlending();
spriteBatch.setColor(Color.WHITE);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
//spriteBatch.draw(texture, 0, 0, 1, 1, 0, 0, texture.getWidth(),
// texture.getHeight(), false, false);
sprite.draw(spriteBatch);
spriteBatch.end();
update();
}
#Override
public void resize(int width, int height)
{
float aspectRatio = (float) width / (float) height;
camera = new PerspectiveCamera(67, 2f * aspectRatio, 2f);
}
#Override
public void resume()
{
}
public void update()
{
float delta = Gdx.graphics.getDeltaTime();
if(Gdx.input.isTouched())
{
Vector3 worldCoordinates = new Vector3(sprite.getX(), sprite.getY(), 0);
camera.unproject(worldCoordinates);
sprite.setPosition(Gdx.input.getX(), Gdx.input.getY());
float moveX = 0;
float moveY = 0;
}
}
I cropped this code for sake of simplicty.
I also made a video demonstrating the bug:
http://www.youtube.com/watch?v=m89LpwMkneI
Camera.unproject converts screen coordinates to world coordinates.
Vector3 pos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(pos);
sprite.setPosition(pos.x, pos.y);
Firstly, Gdx.input.getX() and Gdx.input.getY() return "screen coordinates". You want to transform these to your "camera coordinates". Screen coordinates typically have (0,0) in the top left corner of the window. I think your camera coordinates have (0,0) at the bottom left corner (either libgdx or opengl are doing that). Your video seems to suggest that this true. So you will need to multiply the Y value by -1. Secondly, I suspect the scale of the screen is different from the scale of the camera. I think you can fix the scale by multiplying by (world/screen).
Let's say your screen has width=800, height=600 and your world has width=480 height=320. Then your new X,Y for your sprite should be:
X = Gdx.input.getX()*(480/800)
Y = Gdx.input.getY()*(320/600)*-1
you should check your touch cordinates.
Gdx.app.log("", "hello x"+touchx);
Gdx.app.log("", "hello x"+touchy);
here touchx and touchy are your input x and input y variables
then do calculation where touch should work
like if u touched x=100,y=100
and touchx is coming 120
and touch y is coming 120
soo in your update method do this
sprite.setPosition(Gdx.input.getX()-20, Gdx.input.getY()-20);
i think this will help
I figured out the screen size/ game ratio and multiplied it to the current screen size:
rect.x=((((1024/Gdx.graphics.getWidth()))* Gdx.graphics.getWidth())
for a screen width of 1024 pixels
There must be an easier way however this works for me.