I am trying to make a game engine and I want a camera controlled by the player and also effected by other jBullet entities in Java. I got suggested to use Kinematic Objects so I looked up about them. I couldn't find any documentation which I could understand.
Can someone explain how to set up and use kinematic objects or at least show me where I can start?
The documentation for KinematicCharacterController, found here isn't too entirely helpful, but the source in the CharacterDemo can be. Two main properties are defined in the demo.
public KinematicCharacterController character;
public PairCachingGhostObject ghostObject;
The ghost can be used for dynamic collision detection, as it does not automatically react to those events. The character can be moved by changing the Transform.
//from the source src\com\bulletphysics\demos\character\CharacterDemo.java
Transform startTransform = new Transform();
startTransform.setIdentity();
startTransform.origin.set(0.0f, 4.0f, 0.0f);
Vector3f worldMin = new Vector3f(-1000f,-1000f,-1000f);
Vector3f worldMax = new Vector3f(1000f,1000f,1000f);
AxisSweep3 sweepBP = new AxisSweep3(worldMin, worldMax);
ghostObject = new PairCachingGhostObject();
ghostObject.setWorldTransform(startTransform);
sweepBP.getOverlappingPairCache().setInternalGhostPairCallback(new GhostPairCallback());
float characterHeight = 1.75f * characterScale;
float characterWidth = 1.75f * characterScale;
ConvexShape capsule = new CapsuleShape(characterWidth, characterHeight);
ghostObject.setCollisionShape(capsule);
ghostObject.setCollisionFlags(CollisionFlags.CHARACTER_OBJECT);
float stepHeight = 0.35f * characterScale;
character = new KinematicCharacterController(ghostObject, capsule, stepHeight);
dynamicsWorld.addCollisionObject(ghostObject, CollisionFilterGroups.CHARACTER_FILTER, (short)(CollisionFilterGroups.STATIC_FILTER | CollisionFilterGroups.DEFAULT_FILTER));
dynamicsWorld.addAction(character);
It would also be wise to extend the MotionState class to hold the transform
public class MyMotionState extends MotionState {
private Transform worldTransform;
public MyMotionState()
{
worldTransform = new Transform();
worldTransform.setIdentity();
}
#Override
public Transform getWorldTransform(Transform worldTrans)
{
worldTrans.set(worldTransform);
return worldTrans;
}
#Override
public void setWorldTransform(Transform worldTrans)
{
worldTransform.set(worldTrans);
}
}
and linking the Kinematic to a RigidBody for applying the physics to the character, and getting info on rendering.
rigidBody.setCollisionFlags(rigidBody.getCollisionFlags() | CollisionFlags.KINEMATIC_OBJECT);
rigidBody.setActivationState(CollisionObject.DISABLE_DEACTIVATION);
Don't forget to update the physics engine once every iteration of the game loop.
Transform transform = new Transform();
transform.setIdentity();
transform.origin.set(input.getX(), input.getY(), input.getZ());
myMotionState.setWorldTransform(transform);
rigidBody.setCenterOfMassTransform(myMotionState.getWorldTransform());
If you prefer, you could put these in your MainCharacter class or whatever you call it (I like it for the object oriented feel and ease to understand)
public class MainCharacter implements KeyListener, MouseListener
{
private DynamicsWorld world;
private MyMotionState myMotionState;
private RigidBody rigidBody;
private KinematicCharacterController character;
private ConvexShape shape;
private Texture texture;
private GhostObject ghost;
private Vector3f pos;
public MainCharacter(DynamicsWorld world, Vector3f initialPosition, ConvexShape shape, Texture texture)
{
this.world = world;
RigidBodyConstructionInfo constructInfo = new RigidBodyConstructionInfo(...);
this.myMotionState = myMotionState;
rigidBody = new RigidBody(constructInfo);
ghost = new GhostObject();
character = new KinematicCharacterController(ghost,shape,1);
}
public void render()
{
glBegin(GL_QUADS);
glVertex3f(...
...
glEnd();
}
public void mouseMoved(MouseEvent e)
{
//pseudocode
this.yaw = e.getDX();
this.pitch = e.getDY();
}
public void keyPressed(KeyEvent e)
{
Vector3f dPos = null;
if(e.getKeyChar() == 'W')
{
dPos.x = 10;
}
else if(e.getKeyChar() == 'S')
{
dPos.x = -10;
}
etc...
move(dPos.x,dPos.y,dPos.z);
}
public void move(float dx, float dy, float dz) {
pos.z += dx * (float) Math.cos(Math.toRadians(yaw - 90)) + dz * Math.cos(Math.toRadians(yaw));
pos.x -= dx * (float) Math.sin(Math.toRadians(yaw - 90)) + dz * Math.sin(Math.toRadians(yaw));
pos.y += dy * (float) Math.sin(Math.toRadians(pitch - 90)) + dz * Math.sin(Math.toRadians(pitch));
//pseudocode
rigidBody.update(pos);
world.update(pos);
}
}
I hope I have helped you.
Related
I'm trying to develop a small tower defense game with libGDX and am getting the following exception:
Exception in thread "LWJGL Application" java.lang.NullPointerException
at com.badlogic.gdx.graphics.g2d.SpriteBatch.switchTexture(SpriteBatch.java:1067)
at com.badlogic.gdx.graphics.g2d.SpriteBatch.draw(SpriteBatch.java:558)
at com.badlogic.gdx.graphics.g2d.Sprite.draw(Sprite.java:517)
at levels.AISprite.draw(AISprite.java:33)
at levels.levelGenerator.render(levelGenerator.java:44)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:232)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:127)
I understand that there is something that is not initialized, but what? Would be really happy if you could help me and explain whats the issue.
I would also be glad if you could improve my code! Thanks in advance
Code (only where the magic happens):
levelGenerator Class
public class levelGenerator extends ApplicationAdapter {
private final String level;
SpriteBatch batch;
Texture img;
Scorpion scorpion;
private Array<AISprite> aiSprites;
public levelGenerator(String level){
this.level = level;
}
#Override
public void create () {
Gdx.graphics.setTitle("Tower Defense Game");
scorpion = new Scorpion();
img = new Texture(level);
scorpion.createImage();
aiSprites = new Array<AISprite>();
aiSprites.add(new AISprite(scorpion, LevelOne.levelOnePath()));
}
public void render () {
batch = new SpriteBatch();
batch.begin();
//just the level image background
batch.draw(img, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
scorpion.renderImage();
for(AISprite aiSprite: aiSprites){
aiSprite.draw(batch);
}
for(AISprite aiSprite: aiSprites){
Vector2 previous = aiSprite.getPath().first();
for(Vector2 waypoint: aiSprite.getPath()){
previous = waypoint;
}
}
}
#Override
public void dispose () {
batch.dispose();
img.dispose();
scorpion.disposeImage();
}
}
Entity Class:
public class Entity extends Sprite {
String atlasPath;
private Animation<TextureRegion> animation;
private TextureAtlas entityAtlas;
private float timePassed = 0;
SpriteBatch batch;
public Entity(String atlasPath){
this.atlasPath = atlasPath;
}
public void createImage(){
// path for scorpion atlas file: "assetsPack/scorpions/scorpionRunning/scorpionPack.atlas"
entityAtlas = new TextureAtlas(Gdx.files.internal(atlasPath));
animation = new Animation<TextureRegion>(1/40f, entityAtlas.getRegions());
}
public void renderImage(){
batch = new SpriteBatch();
batch.begin();
timePassed += Gdx.graphics.getDeltaTime();
batch.draw(animation.getKeyFrame(timePassed, true), 0, 0);
batch.end();
}
public void disposeImage(){
entityAtlas.dispose();
}
}
Scorpion (Entity) Class:
public class Scorpion extends Entity {
public Scorpion(){
super("assetsPack/scorpions/scorpionRunning/scorpionPack.atlas");
}
Next class is the one for the pathfinding of the entities
public class AISprite extends Sprite {
private Vector2 velocity = new Vector2();
private float speed = 100, tolerance = 3;
public Array<Vector2> getPath() {
return path;
}
private Array<Vector2> path;
private int waypoint = 0;
public AISprite(Entity entity, Array<Vector2> path){
super(entity);
this.path = path;
}
public void draw(SpriteBatch spriteBatch){
update(Gdx.graphics.getDeltaTime());
super.draw(spriteBatch);
}
public void update(float delta){
float angle = (float) Math.atan2(path.get(waypoint).y - getY(), path.get(waypoint).x - getX());
velocity.set((float) Math.cos(angle) * speed, (float) Math.sin(angle) * speed);
setPosition(getX() + velocity.x * delta, getY() + velocity.y * delta);
if(isWaypointReached()){
setPosition(path.get(waypoint).x, path.get(waypoint).y);
if(waypoint + 1 >= path.size){
waypoint = 0;
}
else{
waypoint++;
}
}
}
public boolean isWaypointReached(){
return path.get(waypoint).x - getX() <= speed / tolerance * Gdx.graphics.getDeltaTime() && path.get(waypoint).y - getY() <= speed / tolerance * Gdx.graphics.getDeltaTime() ;
}
}
use a debugger, set a breakpoint on levels.levelGenerator.render(levelGenerator.java:44), and check what causes the erro .... if you never used a debugger, I strongly(!!!) recommend you learn how to use one before you continue with libgdx
Make sure that all your Gdx calls are made after the create() method is called. All gdx objects are null before that point, so calls such as Gdx.graphics.(...) or Gdx.app.(...) or Gdx.audio.(...) etc. will throw a NPE
Hi guys so i was trying to make this simple game in libgdx and everything was fine until i noticed that i need to apply a big force just to make the player move a little is there any way to make it need less force?
This is my PlayScreen where I render the player.
`
private Logang game;
//basic playscreen variables
private OrthographicCamera gamecam;
private Viewport gamePort;
//Box2d variables
private World world;
private Box2DDebugRenderer b2dr;
boolean drawn = true;
private Player p;
private int pX = 100, pY = 300;
public GameScreen(Logang game) {
this.game = game;
//create cam used to follow mario through cam world
gamecam = new OrthographicCamera();
gamecam.update();
Box2D.init();
//create our Box2D world, setting no gravity in X, -10 gravity in Y, and allow bodies to sleep
world = new World(new Vector2(0, Logang.GRAVITY), true);
//allows for debug lines of our box2d world.
b2dr = new Box2DDebugRenderer();
//create a FitViewport to maintain virtual aspect ratio despite screen size
gamePort = new ScalingViewport(Scaling.fill, Logang.GWIDTH, Logang.GHEIGHT, gamecam);
p = new Player(new Sprite(new Texture("hud_p3.png")), world, pX, pY, 1);
//initially set our gamcam to be centered correctly at the start of of map
gamecam.position.set(gamePort.getWorldWidth() / 2 , gamePort.getWorldHeight() / 2, 0);
line();
}
#Override
public void show() {
}
public void update(float dt) {
//handle user input first
p.update(dt);
//update our gamecam with correct coordinates after changes
}
#Override
public void render(float delta) {
//separate our update logic from render
update(delta);
//Clear the game screen with Black
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
world.step(1f / 60f, 6, 2);
gamecam.position.set(p.getSprite().getX(),Logang.GHEIGHT / 2, 0); // x and y could be changed by Keyboard input for example
gamecam.update();
game.getBatch().setProjectionMatrix(gamecam.combined);
//renderer our Box2DDebugLines
b2dr.render(world, gamecam.combined);
System.out.println("Player x: " + p.getSprite().getX() + " Camera X: " + gamecam.position.x + " Body X: " + p.getBody().getPosition().x);
//System.out.println("Player y: " + p.getSprite().getY() + " Camera Y: " + gamecam.position.y + " Body Y: " + p.getBody().getPosition().y);
game.getBatch().begin();
if (p.getBody() != null)
p.render(game.getBatch());
EntityManager.renderTerra(game.getBatch(), delta);
game.getBatch().end();
}
public void line() {
Texture tmp = new Texture("hud_p3.png");
tmp.setWrap(Texture.TextureWrap.MirroredRepeat, Texture.TextureWrap.MirroredRepeat);
for (int i = 0; i < 50; i++) {
EntityManager.add(new Ground(new Sprite(tmp), world, (int)(i * Logang.TILE), 1, 2));
}
// EntityManager.changeSize(((Logang.TILE) * 5),Logang.TILE);
}
#Override
public void resize(int width, int height) {
//updated our game viewport
gamePort.update(width, height);
}
public World getWorld() {
return world;
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
world.dispose();
b2dr.dispose();
}`
And this is my Entity class which is extended by the player
private World world;
private Sprite sprite;
private Body body;
private int tipo;
public Entity(Sprite sprite, World world, int x, int y, int tipo){
this.sprite = sprite;
this.world = world;
getSprite().setPosition(x, y);
getSprite().setSize(Logang.TILE , Logang.TILE);
define(tipo);
this.tipo = tipo;
}
public void update(float dt){
if(Gdx.input.isKeyPressed(Input.Keys.LEFT)){
getBody().applyLinearImpulse(new Vector2(-Logang.PPM,0f), getBody().getWorldCenter(), true);
}
if(Gdx.input.isKeyPressed(Input.Keys.RIGHT)){
getBody().applyLinearImpulse(new Vector2(Logang.PPM,0f), getBody().getWorldCenter(), true);
}
if(Gdx.input.isKeyPressed(Input.Keys.SPACE)){
getBody().applyLinearImpulse(0f,-Logang.GRAVITY * Logang.PPM, getBody().getPosition().x, getBody().getPosition().y, true);
}
}
}
public void define(int tipo){
BodyDef bdef = new BodyDef();
bdef.position.set((getSprite().getX() + getSprite().getWidth() / 2), (getSprite().getY() + getSprite().getHeight() / 2));
switch(tipo){
case 1: {
bdef.type = BodyDef.BodyType.DynamicBody;
break;
}
case 2:{
bdef.type = BodyDef.BodyType.StaticBody;
break;
}
case 3:{
bdef.type = BodyDef.BodyType.DynamicBody;
break;
}
}
body = world.createBody(bdef);
FixtureDef fdef = new FixtureDef();
PolygonShape shape = new PolygonShape();
shape.setAsBox(getSprite().getWidth() / 2, getSprite().getHeight() / 2);
fdef.shape = shape;
body.createFixture(fdef);
body.setUserData(this);
shape.dispose();
}
public void render(SpriteBatch batch){
if(tipo != 2) {
float posX = getBody().getPosition().x;
float posY = getBody().getPosition().y;
getSprite().setPosition(posX - getSprite().getWidth() / 2, posY - getSprite().getHeight() / 2);
}
getSprite().draw(batch);
}
public Sprite getSprite() {
return sprite;
}
public void setSprite(Sprite sprite) {
this.sprite = sprite;
}
public Body getBody() {
return body;
}
public void setBody(Body body) {
this.body = body;
}
}
Thank everybody for any answer
Box2D is a physics engine so tries to imitate real life physics in game. So if your object is large and heavy it will require a large amount of force to move it.
To make it so your objects can move with less force you can either make them smaller or change the density of them to make them lighter which will allow them to be moved with less force.
To change the density you set it in the fixtureDefinition
FixtureDef fdef = new FixtureDef();
fdef.density=0.1f; // (weight: range 0.01 to 1 is good)
fdef.friction = 0.7f; // (how slippery it is: 0=like ice 1 = like rubber)
fdef.restitution = 0.3f; //(how bouncy is it 0= not bouncy 1 = 100% bouncy)
Another thing I noticed is you are using what seems to be a PixelPerMeter ratio for your forces in this line:
getBody().applyLinearImpulse(new Vector2(-Logang.PPM,0f), getBody().getWorldCenter(), true);
You shouldn't use this value for your forces as this is for converting box2d world to render coordinates and you can use the following code to apply the force to the center.
getBody().applyLinearImpulse(new Vector2((10f*getBody().getMass()),0f), getBody().getWorldCenter(), true);
As a side note the impulse is used to create a single application of force whereas body.applyForceToCenter(force,wake); is used to apply a constant force over time. Try with the apply force method and see if this helps.
Hello fellow programmers,
I am currently writing a small graphical application for my studies that should showcase an AI in a small 2D game. I am kind of stuck though right now.
I have made a class hierarchy with Entity at the top to represent basically any entity, like the player, enemies and obstacles, it has a Node attribute that shall represent the Entity graphically. Entity also has two protected SimpleIntegerProperty objects x and y, to which I bind the layout-properties of the Node attribute, so that whenever I change the values of x and y, the graphical representation moves as well.
So far, I could do anything that doesn't rely on Entity-object coordinates well. Collision works etc.
However, when I tried to implement a system that spawns bullets (little Circle objects) at the place the player character is (the values of both x and y properties), there was a strange offset of double the distance the player has to the upper left corner (to the bottom right). I experimented a little and saw that when I checked the coordinates through the localToScene method, with either the values of both properties or directly the layoutX and layoutY methods of the Node, it would give me coordinates TWICE AS BIG as the actual coordinates.
My pane is 600x600 px big and when I place my player (another object that extends to Entity) at 300,300, everything looks fine, but the localToScene method apparently tells me that it is at double of that, so 600,600. When I go with my player to the bottom right corner and print the coordinates via localToScene, it tells me that it is at 1200,1200.
public void addProjectile(Projectile p)
{
Projectile p2 = new PlayerProjectile(100, 100, 0.5);
projectiles.add(p2);
System.out.println(p2.getSkin().localToScene(p2.getX(), p2.getY()));
System.out.println(p2.getSkin().getLayoutX() + " " + p2.getSkin().getLayoutY());
this.getChildren().add(p2.getSkin());
System.out.println(p2.getSkin().getLayoutX() + " " + p2.getSkin().getLayoutY());
// p.setPosition(p.getSkin().localToScreen(p.getX(), p.getY()));
}
This method creates a Projectile at 100,100 (layoutX and Y confirms that as well). Then, I add that Projectile p2 to an ArrayList (not of importance).
The first print there gives me two coordinates, 200 and 200.
The second print gives me 100 and 100.
The third print gives me 100 and 100 as well (adding to this, which is a Pane, doesn't change anything apparently and is not the cause).
Does anyone have a clue why it just doubles everything? Here is every related class.
PlayerProjectile class:
public class PlayerProjectile extends Projectile
{
public static final int FIRE_RATE = 5; // Higher is slower
public PlayerProjectile(int x, int y, double dir)
{
super(x, y, dir);
range = 150;
speed = 4;
damage = 20;
nx = (int) (speed * Math.cos(angle));
ny = (int) (speed * Math.sin(angle));
}
#Override
public void update()
{
move();
}
#Override
protected void move()
{
x.setValue(x.getValue() + nx);
y.setValue(y.getValue() + ny);
// if (distance() > range)
// {
// remove();
// }
}
}
Projectile class:
public abstract class Projectile extends Entity
{
final protected int xOrigin, yOrigin;
protected double angle;
protected int nx, ny;
protected double distance;
protected double speed, range, damage;
public Projectile(int x, int y, double dir)
{
super(x, y);
skin = new Circle(x, y, 3);
((Circle) skin).setFill(new Color(0, 1, 0, 1));
xOrigin = x;
yOrigin = y;
angle = dir;
// this.getVisual().translateXProperty().bind(this.x);
// this.getVisual().translateYProperty().bind(this.y);
this.getSkin().layoutXProperty().bind(this.x);
this.getSkin().layoutYProperty().bind(this.y);
// this.getVisual().getChildren().add(skin);
}
protected void move()
{
}
public int getX()
{
return x.getValue().intValue();
}
public int getY()
{
return y.getValue().intValue();
}
public int getOriginX()
{
return xOrigin;
}
public int getOriginY()
{
return yOrigin;
}
}
Entity class:
public class Entity
{
private boolean removed = false;
protected Level level;
protected Node skin;
// PROPERTIES FÜR X UND Y KOORDINATEN DES SKINS DES SPIELERS
protected SimpleIntegerProperty x, y;
// VISUELLE REPRÄSENTATION DER ENTITY
// protected Pane visual = new Pane();
public Entity()
{
}
public Entity(int x, int y)
{
this.x = new SimpleIntegerProperty(x);
this.y = new SimpleIntegerProperty(y);
}
public void update()
{
}
public void remove()
{
// Remove from level
removed = true;
}
public void setX(int x)
{
this.x.setValue(x);
}
public void setY(int y)
{
this.y.setValue(y);
}
public void setPosition(Point2D p)
{
this.setX((int) p.getX());
this.setY((int) p.getY());
}
public boolean isRemoved()
{
return removed;
}
public void init(Level level)
{
this.level = level;
}
// public Pane getVisual()
// {
// return visual;
// }
public Node getSkin()
{
return skin;
}
}
localToScene transforms from local coordinates to the scene coordinates. Local coordinates are relative to the origin of the node the method is called for. The transform already includes layoutX and layoutY of this node. Therefore given P = (layoutX, layoutY) the result you get is
Inverse(sceneToLocal) * P = Inverse(Inverse(nodeTransform)) * P
= Inverse(Inverse(Translation(P))) * P
= Translation(P) * P
= 2 * P
Transform the origin in the local coordinate system instead to get the real position:
p.setPosition(p.getSkin().localToScreen(0, 0));
UPDATE
I have a hint. That is because the center of the screen in JBox2D is (0, 0). This is so weird because x and y are not from -1 to 1, it depends of the screen size.
This means the Util class I copied from the internet (everybody shared this code) is not up to date. I still need help because I can't find any 'algorithm' to have aspect ratio + screen size dependency.
BASE QUESTION
Since I have added the "slick2D to jbox2D position" and vice versa (it's like position in screen = position in screen / 100 for JBox), I don't get a good result. Screenshots below
I'm explaining with code:
public class Util {
private static final float SCALE = 0.01f; // 1/100 pixels
public static float toPosX(float posX) { return (posX * SCALE); }
public static float toPosY(float posY) { return (-posY * SCALE); }
public static float toScreenX(float posX) { return (posX / SCALE); }
public static float toScreenY(float posY) { return (-posY / SCALE); }
}
Square.java :
public class Square {
private Body body;
private Rectangle rectangle;
Square(World world, BodyType type, Vec2 pos, Vec2 size) {
float x = Util.toPosX(pos.x);
float y = Util.toPosY(pos.y);
float sx = Util.toPosX(size.x);
float sy = Util.toPosY(size.y);
//body definition
BodyDef bd = new BodyDef();
bd.position.set(x, y);
bd.type = type;
//define shape of the body.
PolygonShape cs = new PolygonShape();
cs.setAsBox(sx, sy);
//define fixture of the body.
FixtureDef fd = new FixtureDef();
fd.shape = cs;
fd.density = 1f;
fd.friction = 0.3f;
fd.restitution = 1.0f;
//create the body and add fixture to it
body = world.createBody(bd);
body.createFixture(fd);
rectangle = new Rectangle(0, 0, size.x, size.y);
rectangle.setLocation(pos.x, pos.y);
}
public Body getBody() { return this.body; }
public Rectangle getRectangle() { return this.rectangle; }
}
And finally my display class:
public class DisplayManager extends BasicGame {
private GameManager gameManager;
private Body b1, b2;
private Rectangle r1, r2;
private World world;
public DisplayManager(GameManager game) {
super("Title");
this.gameManager = game;
}
#Override
public void init(GameContainer container) throws SlickException {
this.gameManager.initPlayersSprites();
world = new World(new Vec2(0, -10));
Square s1, s2;
s1 = new Square(world, BodyType.STATIC, new Vec2(10, 800), new Vec2(1900, 30));
b1 = s1.getBody();
r1 = s1.getRectangle();
s2 = new Square(world, BodyType.DYNAMIC, new Vec2(945, 200), new Vec2(30, 30));
b2 = s2.getBody();
r2 = s2.getRectangle();
}
public void render(GameContainer container, Graphics g) throws SlickException {
float step = 1.0f / 600.0f;
world.step(step, 6, 2);
r1.setLocation(Util.toScreenX(b1.getPosition().x), Util.toScreenY(b1.getPosition().y));
r2.setLocation(Util.toScreenX(b2.getPosition().x), Util.toScreenY(b2.getPosition().y));
g.draw(r1);
g.draw(r2);
}
}
Here is the result :
first frame :
http://i.stack.imgur.com/WgQPK.png
some frames later :
http://i.stack.imgur.com/a1XyL.png
(the ground didn't move, it's just another screenshot took from my hand)
In other words, the cube falls down like for ever. I debugged the position of the cube and it doesn't stop to go down.
With Slick2D DebugDraw it doesn't help because the cube goes through the ground anyway.
Please note that in JBox2D, it worked with pixels measurements (that was not accurate at all but collisions worked well)
That was because of the negative size. (toPoxY reverse the y pos)
I have made a class for the level generation and have got so far with it:
public class LevelGenerator {
private Sprite environment;
private float leftEdge, rightEdge, minGap, maxGap, y;
public Enemy enemy;
public LevelGenerator(Sprite environment, float leftEdge, float rightEdge,
float minGap, float maxGap) {
this.environment = environment;
this.leftEdge = leftEdge;
this.rightEdge = rightEdge;
this.minGap = minGap;
this.maxGap = maxGap;
}
public void generate(float topEdge){
if(y + MathUtils.random(minGap, maxGap) < topEdge)
return;
y = topEdge;
float x = MathUtils.random(leftEdge, rightEdge);
}
Basically, what I want to happen is for the enemy block to randomly generate on the sides of the screen. Here is the enemy block class (very simple):
public class Enemy extends Sprite{
public Enemy(Sprite sprite) {
super(sprite);
}
#Override
public void draw(Batch spriteBatch){
super.draw(spriteBatch);
}
}
This is what the game looks like at the moment when the block is just simply drawn on the game screen in a static position: http://i.imgur.com/SIt18Qn.png. What I am trying to achieve is for these "enemy" blocks to spawn randomly on either side of the screen but I can't seem to figure out a way to do it with the code I have so far.
Thank you!
I could not test but I think it will be fine, you have a rectangle if you want to see if it collides with another actor, if so updates its position in the update and draw method, and ramdon method start customizing to see if the coordinates, which colicionan be assigned to another actor rectagulo enemy or bye.
public class overFlowEnemy extends Sprite {
private final float maxH = Gdx.graphics.getHeight();
private final float maxW = Gdx.graphics.getWidth();
private Rectangle rectangle;
private Random random = new Random();
private float inttt = 0;
private float randomN = 0;
private boolean hasCollided = false;
public overFlowEnemy(Sprite sprite) {
super(sprite);
crearEnemigo();
rectangle = new Rectangle(getX(), getY(), getWidth(), getHeight());
}
#Override
public void draw(Batch spriteBatch) {
super.draw(spriteBatch);
}
private void crearEnemigo(){
setX(RandomNumber((int)maxW));
setY(RandomNumber((int)maxH));
}
private int RandomNumber(int pos) {
random.setSeed(System.nanoTime() * (long) inttt);
this.randomN = random.nextInt(pos);
inttt += randomN;
return (int)randomN;
}
public Rectangle getColliderActor(){
return this.rectangle;
}
}
the class as this should create a random enemy.
Edit: rereading your question, is that my English is not very good, and I think you wanted to be drawn only on the sides of the screen if so, tell me or adapts the class because when you create thought, which was across the screen.
I just added another class, if you can and want to work as you tell me which is correct, and delete the other.
public class overFlow extends Sprite {
private final float maxH = Gdx.graphics.getHeight();
private final float maxW = Gdx.graphics.getWidth();
private Rectangle rectangle;
private Random random = new Random();
private float inttt = 0;
private float randomN = 0;
private boolean hasCollided = false;
public overFlow(Sprite sprite) {
super(sprite);
crearEnemigo();
rectangle = new Rectangle(getX(), getY(), getWidth(), getHeight());
}
#Override
public void draw(Batch spriteBatch) {
super.draw(spriteBatch);
}
private void crearEnemigo(){
setX(RandomNumber((int)maxW, true));
setY(RandomNumber((int)maxH, false));
}
private int RandomNumber(int pos, boolean w) {
random.setSeed(System.nanoTime() * (long) inttt);
if (w = true){
this.randomN = random.nextInt((pos));
if(randomN % 2 == 0){
randomN = (pos - getWidth());
}else{
randomN = 0; //left screen
}
}else{
this.randomN = random.nextInt(pos - (int)getHeight());
}
inttt += randomN;
return (int)randomN;
}
public Rectangle getColliderActor(){
return this.rectangle;
}
}