I want to use moveToAction and move the actor. But its not moving if i use moveToAction. If change x,y in draw method it works, but not with movetoaction
public class Aks extends Actor {
private State state;
private MainGame game;
private TextureAtlas movingAtlas;
private Animation movingAnimation;
private float elapsedTime = 0f;
public Aks(MainGame game) {
this.game = game;
movingAtlas = new TextureAtlas(Gdx.files.internal("atlas/myaltas/atlas.atlas"));
movingAnimation = new Animation(1f/15f, movingAtlas.getRegions());
TextureRegion texture = (TextureRegion) movingAnimation.getKeyFrame(elapsedTime, true);
setBounds(getX(),getY(),texture.getRegionWidth(),texture.getRegionHeight());
MoveToAction moveAction = new MoveToAction();
moveAction.setPosition(300f, 300f);
moveAction.setDuration(10f);
this.addAction(moveAction);
addListener(new ActorGestureListener(){
#Override
public void tap(InputEvent event, float x, float y, int count, int button) {
Gdx.app.log("Tag", "Actor touched x = " );
super.tap(event, x, y, count, button);
}
});
}
#Override
public void draw(Batch batch, float alpha){
drawFlying(batch);
}
void drawFlying(Batch batch){
TextureRegion texture = (TextureRegion) movingAnimation.getKeyFrame(elapsedTime, true);
setBounds(getX(),getY(),texture.getRegionWidth(),texture.getRegionHeight());
Gdx.app.log("Tag", "x =" + getX() + " y =" + getY() );
batch.draw(texture, getX(),getY(),50,50);
}
#Override
public void act(float delta){
elapsedTime = elapsedTime+delta;
}
}
You needs to call super.act(delta), in the actor class, the act method control all the actions so if you don't call it, the actions wont happen, on the contrary you don't need to call super.draw() that's because actor class was created just for logical part of a entity, you must define what it will draw in case you need it.
I hope it helps!
Your draw function needs to call super.draw(batch, alpha) for it to affect child actions.
Related
I want to add to the score of my game +1 when an enemy was touched, I tried two methods addListener and touchDown but not worked for me or I didn't use them right.
How can I do that my (enemy object is linked to an userData and Actor classes, I regroup many different sizes for my enemy in an enum class also those enemies move from the top of the screen to bot. How to detect if an enemy was touched?
public class GameStage extends Stage {
// This will be our viewport measurements while working with the debug renderer
private static final int VIEWPORT_WIDTH = 13;
private static final int VIEWPORT_HEIGHT = 20;
private World world;
private Ground ground;
private Enemy enemy;
private final float TIME_STEP = 1 / 300f;
private float accumulator = 0f;
private Rectangle bounds;
private Vector3 touchPoint = new Vector3();;
private int score;
private String yourScoreName;
BitmapFont yourBitmapFontName;
private SpriteBatch batch;
private OrthographicCamera camera;
private Box2DDebugRenderer renderer;
public GameStage() {
world = WorldUtils.createWorld();
renderer = new Box2DDebugRenderer();
Gdx.input.setInputProcessor(this);
batch = new SpriteBatch();
score = 0;
yourScoreName = "score: 0";
yourBitmapFontName = new BitmapFont();
setUpWorld();
setUpCamera();
}
public void setUpWorld(){
world = WorldUtils.createWorld();
setUpGround();
createEnemy();
}
private void setUpGround(){
ground = new Ground (WorldUtils.createGround(world));
addActor(ground);
}
private void createEnemy() {
enemy = new Enemy(WorldUtils.createEnemy(world));
// (1) *****using addListener method
enemy.addListener(new InputListener()
{
#Override
public boolean touchDown(InputEvent event, float x, float y,
int pointer, int button)
{
score++;
yourScoreName = "score: " + score;
return true;
}
});
/*enemy.addListener(new ClickListener() {
public void clicked() {
world.destroyBody(enemy.getBody());
}});*/
//bounds = new Rectangle(enemy.getX(), enemy.getY(), enemy.getWidth(), enemy.getHeight());
addActor(enemy);
}
private void setUpCamera() {
camera = new OrthographicCamera(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0f);
camera.update();
}
#Override
public void act(float delta) {
super.act(delta);
checkEnemy();
// Fixed timestep
accumulator += delta;
while (accumulator >= delta) {
world.step(TIME_STEP, 6, 2);
accumulator -= TIME_STEP;
}
//TODO: Implement interpolation
}
private void checkEnemy(){
final Body body = enemy.getBody();
UserData userData = enemy.getUserData();
bounds = new Rectangle(enemy.getBody().getPosition().x, enemy.getBody().getPosition().y, enemy.getUserData().getWidth(), enemy.getUserData().getHeight());
// bounds = new Rectangle(body.getPosition().x, body.getPosition().y,userData.getWidth() ,userData.getHeight());
if (!BodyUtils.enemyInBounds(body,userData)){
world.destroyBody(body);
createEnemy();}
}
public World getWorld(){
return world;
}
// (2) ****using TouchDown method
#Override
public boolean touchDown(int x, int y, int pointer, int button) {
// Need to get the actual coordinates
translateScreenToWorldCoordinates(x, y);
// score++;
// yourScoreName = "score: " + score;
if(enemyTouched(touchPoint.x,touchPoint.y)){
// world.destroyBody(enemy.getBody());
score++;
yourScoreName = "score: " + score;
}
return super.touchDown(x, y, pointer, button);
}
private boolean enemyTouched(float x, float y) {
return bounds.contains(x, y);
}
private void translateScreenToWorldCoordinates(int x, int y) {
getCamera().unproject(touchPoint.set(x, y, 0));
}
#Override
public void draw() {
super.draw();
batch.begin();
yourBitmapFontName.setColor(1.0f, 1.0f, 1.0f, 1.0f);
yourBitmapFontName.draw(batch, yourScoreName, 25, 100);
batch.end();
enemy.setBounds(enemy.getBody().getPosition().x,enemy.getBody().getPosition().y,enemy.getUserData().getWidth(),enemy.getUserData().getHeight());
renderer.render(world, camera.combined);
}
}
A screen from my game:
It should work the way you did it (with the addListener() method). But you have to set the correct bounds of the actor (width, height, position): actor.setBounds(x, y, width, height). I would use the body to get these values. You can also use a ClickListener instead of the InputListener.
I've created a game that uses 4 different GameStates: READY,RUNNING,GAMEOVER,and HIGHSCORE(variation of GAMEOVER except this one notifies the player that a highscore has been reached). My issue is that the way I've set up my InputHandler is that in the GameState.READY form the user can touch anywhere in the screen to advance into the GameState.RUNNING form. I've tried multiple tactics into creating a playButton, however nothing seems to be working my way. I created a PlayButton class as such:
public class PlayButton {
private Vector2 position;
private Rectangle boundingRectangle;
private int width;
private int height;
private PlayScreen playScreen;
public PlayButton (float x, float y, int width, int height) {
this.width = width;
this.height = height;
position = new Vector2(x, y);
boundingRectangle = new Rectangle();
}
public void update(float delta) {
boundingRectangle.set(position.x,(position.y),width,height);
}
public float getTheX() {
return position.x;
}
public float getY() {
return position.y;
}
public float getWidth() {
return width;
}
public float getHeight() {
return height;
}
public Rectangle getBoundingRectangle(){
return boundingRectangle;
}
}
and in my InputHandler i tried this:
public InputHandler(GameWrold myWorld, float scaleFactorX, float scaleFactorY){
this.myWorld = myWorld;
mySam = myWorld.getSam();
playButton = new PlayButton(45,gameHeight-75,50,-35);
buttonPlay = myWorld.getPlayButton();
int midPointY = myWorld.getMidPointY();
this.scaleFactorX = scaleFactorX;
this.scaleFactorY = scaleFactorY;
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
Vector2 touchPos = new Vector2();
touchPos.set(Gdx.input.getX(), Gdx.input.getY());
Vector2 tuch = new Vector2(screenX,screenY);
buttonPlay.getBoundingRectangle();
touch = new Rectangle(touchPos.x,touchPos.y,5,5);
if (myWorld.isReady()) {
if(playButton.getBoundingRectangle().contains(touchPos)){
myWorld.start();
}
}
mySam.onClick();
if (myWorld.isGameOver() || myWorld.isHighScore()) {
// Reset all variables, go to GameState.READ
myWorld.restart();
}
return true;
}
}
As you can see I tried creating a Rectangle with the touch variable and I tried checking if touch collided with the playButton boundingRectangle like this:
if(Intersector.overlaps(touch,playButton.getBoundingRectangle())){ or
(playButton.getBoundingRectangle().overlaps(playButton.getBoundingRectangle()))
Do not invent a circle and don't break open doors.
Use Scene2d :)
It is a simple UI framework fully compatible with libGDX that allows you to create Buttons, Sliders, Windows and another widgets in about one line of code.
You will find a nice description in a link I've attached above but TLDR version is:
Create Skin and pack a texture atlas for this using TexturePacker (free version is enough usually)
Create a Stage with appropriate Viewport
Stage stage = new Stage(new FitViewport(WIDTH, HEIGHT));
Set the stage as input processor (it means that all event on the stage will be catched)
Gdx.input.setInputProcessor(stage);
Create a Button with appropriate style (defined in Skin)
Button button = new Button(skin, "style");
Attach a ClickListener with appropriate action to the Button
button.addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y)
{
//some action
}
});
Set it's position and add it to the stage
button.setPosition(x, y);
stage.addActor(button);
Fire act() and draw() stage's methods in your render()
//render()
stage.act();
stage.draw();
You've earned few hours ;)
I have a tiled map on which I set characters(every character is of the size of one tile). I managed to make them clickable, even when screen resizes everything works perfect. Every time I click on character I want a button to show up above it. For a button I use stage and place the button in the place I clicked with small transition and it also works.
My problem is when I try to use clicklistener on this button. If the screen does not resize, clicklistener works. Problem starts when the screen get resized - clicks on players works well, only button does not work - after a resize the clicking space and the button space are not aligned. For test purposes I made a test map that shows me grids. It seems that stage is not properly resized. Picture for a reference. I tried many solutions I came upon on the Internet and still can't find a solution to my problem. I have shortened my code down to a minimum basic example:
public class Test extends ApplicationAdapter {
public static Stage stage;
public TiledMap tiledMap;
static OrthographicCamera camera;
TiledMapRenderer tiledMapRenderer;
public static boolean showMenu;
GestureDetector gesture;
InputMultiplexer myInputMultiplexer;
public static int posx, posy;
public static Image move;
public Texture moveMenu;
#Override
public void create() {
moveMenu = new Texture(Gdx.files.internal("move.png"));
gesture = new GestureDetector(new MyGestureListener());
myInputMultiplexer = new InputMultiplexer();
float unitScale = 1 / 32f;
camera = new OrthographicCamera();
camera.setToOrtho(true, 33, 21);
stage = new Stage(new ScreenViewport());
stage.getViewport().setCamera(camera);
tiledMap = new TmxMapLoader().load("test.tmx");
tiledMapRenderer = new OrthogonalTiledMapRenderer(tiledMap, unitScale);
myInputMultiplexer.addProcessor(stage);
myInputMultiplexer.addProcessor(gesture);
Gdx.input.setInputProcessor(myInputMultiplexer);
move = new Image(moveMenu);
move.setWidth(2);
move.setHeight(2);
move.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
move(); //my action, works fine
showMenu = false;
}
});
stage.addActor(move);
}
#Override
public void render() {
super.render();
stage.act();
tiledMapRenderer.setView(camera);
camera.update();
tiledMapRenderer.render();
if (showMenu) {
mainMenuDraw();
}
}
public static void mainMenuDraw() {
move.setPosition(posx, posy-2);
stage.draw();
}
public void resize(int width, int height) {
stage.getViewport().update(width, height, true);
}
public static OrthographicCamera getCamera() {
return camera;
}
public static Vector3 unprojectCoords(Vector3 coords) {
camera.unproject(coords);
return coords;
} }
and part of my gesturelistener:
public boolean touchDown(float x, float y, int pointer, int button) {
Vector3 temp_coord = new Vector3(x, y, 0);
Vector3 coords = Test.unprojectCoords(temp_coord);
return false;
}
#Override
public boolean tap(float x, float y, int count, int button) {
Vector3 temp_coord = new Vector3(x, y, 0);
Vector3 coords = Test.unprojectCoords(temp_coord);
Test.posx = (int) coords.x;
Test.posy = (int) coords.y;
tap = true;
Test.showMenu = true;
return false;
}
I would suggest to you read more about re-sizing and displaying pixels.
You need to recalculate pixels always when you render something.
- player, background image, buttons, events.
Actually you don't need to use resize method, just get the camera width and height.
You need to share more code, because it depends on everything.
I don't see how you are doing rendering.
tiledMapRenderer.render(), background rendering / layers?
player rendering?
menu rendering?
buttons rendering?
Example: (the same should be for event handler)
public GameButton(TextureRegion reg, float x, float y, OrthographicCamera cam) {
this.reg = reg;
this.x = x;
this.y = y;
this.cam = cam;
width = reg.getRegionWidth();
height = reg.getRegionHeight();
vec = new Vector3();
Texture tex = Game.res.getTexture("hud");
font = new TextureRegion[11];
for(int i = 0; i < 11; i++) {
font[i] = new TextureRegion(tex, 32 + i * 9, 16, 9, 9); //use height and width here)
}
}
I am rather new to the libgdx Framework so I hope I am not asking anything stupid, but I have a problem with updating my screen on the toucheEvent. It seems that the touch event fires, but the stage is not updated so the screen is all the time the same. Here is the code
MainClass
public class MainGame implements Screen {
public LabirintGame game;
public Stage stage;
public OrthographicCamera camera;
public ActorM rigth;
public ActorM wrong;
public MainGame(LabirintGame game) {
this.game = game;
this.camera = new OrthographicCamera();
}
#Override
public void show() {
this.camera.setToOrtho(false, 800, 480);
stage = new Stage(new ScreenViewport());
stage.clear();
Words group = new Words(stage);
InputMultiplexer inputMultiplexer = new InputMultiplexer();
inputMultiplexer.addProcessor(stage);
inputMultiplexer.addProcessor(new MyInputProcessor(stage, camera));
Gdx.input.setInputProcessor(inputMultiplexer);
//Add wrong and rigth boxes
rigth = new ActorM("box", 0, 0, 200,200);
wrong = new ActorM("box",(game.width - 230), 0, 200, 200);
wrong.moveBy(200,200);
Button createButtons = new Button();
createButtons.setStyle("atlas-besede/besede.atlas", "buttonOff", "buttonOn");
TextButton ValidationButton = createButtons.createButton("Validate", (game.width/2), 0, 150, 150);
ValidationButton.addListener(new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
game.setScreen(new Labirint(game));
return true;
}
});
stage.addActor(ValidationButton);
stage.addActor(rigth);
stage.addActor(wrong);
List<String> backgrounds = Arrays.asList("s", "z");
for (int i = 0; i < backgrounds.size(); i++) {
Word actor = new Word(backgrounds.get(i),(i + 1) * 300, 300, 100, 100);
actor.setPosition((i + 1) * 300, 300);
actor.setName(backgrounds.get(i));
group.addActor(actor);
}
stage.addActor(group);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
game.batch.begin();
game.batch.setProjectionMatrix(camera.combined);
game.batch.end();
}
ActorM
package com.mygdx.game;
public class ActorM extends Actor {
public SpriteBatch batch;
public TextureAtlas atlas;
public TextureAtlas.AtlasRegion region;
Sprite sprite;
public int x;
public int y;
public int width;
public int height;
public ActorM(String actorName, int x, int y, int width, int height) {
//this.region = region;
super();
batch = new SpriteBatch();
atlas = new TextureAtlas(Gdx.files.internal("atlas-start/atlas-start.atlas"));
sprite = atlas.createSprite(actorName);
this.width = width;
this.height = height;
this.x = x;
this.y = y;
this.setBounds(0, 0, sprite.getWidth(), sprite.getHeight());
setTouchable(Touchable.disabled);
setName(actorName);
setPosition(x,y);
}
#Override
public void draw (Batch batch, float parentAlpha) {
batch.draw(sprite, x,y, width, height);
}
public void move(int posX){
this.x = this.x + posX;
}
}
MyInputProcessor
public class MyInputProcessor implements InputProcessor {
private OrthographicCamera camera;
private Stage stage;
private Vector2 coordinates;
private Music sound;
public MyInputProcessor( Stage stage, OrthographicCamera camera) {
this.stage = stage;
this.camera = camera;
}
#Override
public boolean keyDown(int keycode) {
return false;
}
#Override
public boolean keyUp(int keycode) {
return false;
}
#Override
public boolean keyTyped(char character) {
return false;
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button)
{
//Gdx.app.log("", "x " + screenX + " y " + screen`enter code here`Y + " pointer " + pointer);
Vector2 coordinates = stage.screenToStageCoordinates(new Vector2((float)screenX,(float)screenY));
Actor hitactor = stage.hit(coordinates.x, coordinates.y, true);
Gdx.app.log("", coordinates.toString());
if (hitactor != null){
//Gdx.app.log("", "HIT" + hitactor.getName());
Gdx.app.log("", "HIT" + hitactor.getRotation());
hitactor.setRotation(hitactor.getRotation() + 1f);
hitactor.setPosition(5,5);
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
}
return true;
}
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
return false;
}
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
coordinates = stage.screenToStageCoordinates(new Vector2((float)screenX,(float)screenY));
Actor hitactor = stage.hit(coordinates.x, coordinates.y, true);
if (hitactor != null){
Gdx.app.log("", "Drag");
hitactor.setRotation(hitactor.getRotation() + 1f);
}
camera.update();
return true;
}
#Override
public boolean mouseMoved(int screenX, int screenY) {
return false;
}
#Override
public boolean scrolled(int amount) {
return false;
}
}
Your "ValidationButton" uses an InputProcessor that always returns true and it's the first actor in the stage, so nothing else in the stage will ever get an opportunity to respond to touch down events. Furthermore, since your stage is the first input processor in your InputMultiplexer, your other input processor never gets an opportunity to respond to touch down events either.
You should use an EventListener on your button instead of an InputListener, so much of the logic will be taken care of for you.
By the way, your ActorM class is spawning a SpriteBatch that it never uses. SpriteBatch takes up significant memory, and there's no need for there to be more than one of them in your game. The Stage already has a reference to a SpriteBatch that it passes into your Actor's draw method, so the Actor does not need to create or even reference a SpriteBatch.
Also, your ActorM class is loading a complete copy of a TextureAtlas for itself so there will be duplicate Textures loaded for each instance of ActorM, and you lose all the benefits of a TextureAtlas, since you won't be using it for sprite batching. You need to load the TextureAtlas only one time, and pass a reference of it into the constructor of your ActorM class, so they can all share the same Texture.
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;
}
}