I'm using Actor class in my game for several advantages of Actors class. But currently I'm facing an issue on using Stage.hit(...) method.
As we know, "hit" returns Actor object.
public class Enemy extends Actor
{
int health = 100;
public Enemy (int type, float x, float y)
{
setX(x);
setY(y);
}
public void act(float deltaTime)
{
Actor hitActor = GameAsset.stage.hit(getX(), getY(), false);
if(hitActor != null))
{
health -= 10;
// next, should be reducing hitActor health in stage, but how?
}
}
...
The question is, is there any way to do in the comments above?
Sorry for bad english :D
Put this inside the hitActor != null test:
if (hitActor instanceof Enemy) {
Enemy e = (Enemy)hitActor;
e.health -= 10;
}
That checks if the returned Actor happens to be an instance of the Enemy subclass. If so, you can cast the object and apply the change. If not, the hit is ignored.
You can learn more about casting objects from their generic types to more specific types here:
http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html (especially the last section about "Casting Objects".
Related
I am analizing a game code.
A method which name is act() is running despite it is not called.
Its like, there is a secret method somwere but i cant see it.
i follow source of method.i find so code.The some part of codes are as below.
I think parent class send method to child class when a new object execuded.
Is there a name of this approach.
This is LevelScreen class.It does not have act() method but act() method is working.I can see the changes when i change the parametres in act() method in Plane class.
class LevelScreen : BaseScreen(){
plane = Plane(100f, 500f, mainStage)}
This is Plane class which has act() method.
class Plane(x: Float, y: Float, s: Stage) : BaseActor(x, y, s){
override fun act(dt: Float) {
super.act(dt)
// simulate force of gravity
setAcceleration(800f)
accelerateAtAngle(270f)
applyPhysics(dt)
................
.............
}
This is parent class of Plane class
open class BaseActor(x: Float, y: Float, s: Stage) : Group(){
override fun act(dt: Float) {
super.act(dt)
if (!animationPaused)
elapsedTime += dt
}
}
This is a class which is in framework of libGDX
public class Group extends Actor implements Cullable{
public void act (float delta) {
super.act(delta);
Actor[] actors = children.begin();
for (int i = 0, n = children.size; i < n; i++)
actors[i].act(delta);
children.end();
}
}
Look at the main project file where the Stage is created. The main file will have a method called render and this is where the act method is called for the first time. All Actors are added to the Stage and then inside of the render method the act method is called on the Stage, which then calls the act method on all of the Actors that it contains.
This is the section you are looking for (taken from one of my projects):
#Override
public void render (){
Gdx.gl.glClearColor(0.6f, 0.64f, 0.7f, 1.0f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(Gdx.graphics.getRawDeltaTime()); // START OF ACT METHODS
stage.draw();
}
I am making a game in libgdx, where you shoot aliens with bullets. I have 2 ArrayLists of objects and would like to check if any of objects in bulletArrayList is colliding with any object from alienArrayList. What is the best way to do that? I was thinking of contactListener.
In the screen class I am generating objects like this:
public class PlayScreen implements Screen, InputProcessor,ContactListener {
public ArrayList<Alien> alienArrayList = new ArrayList<Alien>();
public ArrayList<Bullet> bulletArrayList = new ArrayList<Bullet>();
public void generateAlien() {
alien = new Alien();
alienArrayList.add(alien);
}
public void shootBullet(float x, float y) {
//send x,y moving coordiantes
bullet = new Bullet(x,y);
bulletArrayList.add(bullet);
}
}
In object class I have Rectangle box which i am moving like this:
public class Alien {
public Alien() {
bound = new Rectangle( x, y, alienRegion.getRegionWidth(), alienRegion.getRegionHeight());
}
public void update(float delta) {
bound.y -= speed * delta;
}
public void render(SpriteBatch batch, float delta) {
update(delta);
elapsedTime += Gdx.graphics.getDeltaTime();
alienRegion = (TextureRegion) alien.getKeyFrame(elapsedTime, true);
batch.draw(alienRegion, getBound().x, getBound().y);
}
}
Because you are using Rectangles in your Alien class, we can use a class called Intersector which has static methods to check for collision detection.
for(Alien alien1: alienArrayList) {
for(Alien alien2 : bulletArrayList) {
if(Intersector.overlaps(alien1.rect, alien2.rect)) {
// Collision code
}
}
}
First, we iterate through the two lists using a nested special for loop. Then we pass two Rectangles to the Intersector.overlaps(rect1, rect2). This is a static method defined in the Intersector class which will return true if the rectangles are overlapping.
Also, this code can go straight into your render method.
This code is not the most optimized because it will check 2 rects twice however, I will leave the optimization to you.
I hope that this answer was helpful and if you have any further questions please feel free to post a comment below.
My game has a class named Enemy which extends Actor. Additionally, I have an EnemyAffector class which has methods that affect Enemies, roughly like this:
class EnemyAffector {
public void affect(Enemy enemy) { ... }
}
In my Stage, in the act method, I want to iterate over all Enemies and apply an EnemyAffector to them. The obvious way is by casting:
#Override
public void act() {
super.act();
for (Actor actor: getActors()) {
if (actor instanceof Enemy) {
enemyAffector.affect((Enemy)actor);
}
}
...
}
However, legend has it that using instanceof should be avoided. So, I considered keeping an additional Array to which I will add Enemies as they are added to the Stage, i.e., by overloading my Stage with another addActor method:
public void addActor(EnemyProjectile pEnemyProjectile) { // add to Enemy Array }
So now my act method looks like this:
#Override
public void act() {
super.act();
for (Enemy enemy: enemyArray) {
enemyAffector.affect(enemy);
}
...
}
Yay! No instanceof!
However, the problem with this solution is that I will always need to synchronize between the Enemy Array, and the standard Actor Array because Enemies in the Enemy Array may have been removed from the Stage.
My question is, is there a different, cleaner, approach which can I take here?
You could either use the UserObject that you can add to an actor:
public enum ActorType
{
PLAYER, ENEMY, ETC;
}
//...
Enemy enemy = new Enemy();
// Or set this in the constructor
enemy.setUserObject(ActorType.ENEMY);
for (Actor actor : actors)
{
if (actor.getUserObject() == ActorType.ENEMY)
{
// Do stuff...
}
}
Or put your two arrays in an extra class and add methods for adding/removing:
public class ActorManager
{
private Array<Actor> actors = new Array<>();
private Array<Enemy> enemies = new Array<>();
public void add(Actor actor)
{
actors.add(actor);
}
public void add(Enemy enemy)
{
actors.add(enemy);
enemies.add(enemy);
}
public void remove(Actor actor)
{
actors.removeValue(actor, true);
}
public void remove(Enemy enemy)
{
actors.removeValue(enemy, true);
enemies.removeValue(enemy, true);
}
// To make sure our backing arrays are not modified:
public Array<Actor> getAll()
{
return new Array<>(actors);
}
public Array<Actor> getEnemies()
{
return new Array<>(enemies);
}
}
I quickly encountered a similar situation with LibGDX with both the Actor and Stage class. I created my own sub-class extending Actor, which I was going to use as the "base Actor" Object for all my Actors.
That way, you can set up methods which will be called by all your Actors on certain situations.
class MyStage extends Stage
{
public void addActor(MyActor pEnemyProjectile) { // call onAdd }
//override other methods as necessary,
//possibly getActors() to return Actors as MyActors, etc
}
class MyActor extends Actor
{
public void update(double delta)
{
//I find it easiest to have "removal" code happen in the Actor's update method, then I can call onRemove()
//This could happen by finding death conditions or just checking a "isDead" boolean.
}
public void onAdd()
{
//can set up a default behavior, or just override on other subclasses
}
public void onRemove()
{
//call for every Actor that gets removed - can extend and remove Enemies from an Enemy list if desired
}
//maybe it would be better to check if the Object can be Affected here?
//rather than keeping and maintaining a separate list
public boolean isAffected()
{
return false; //return true by Enemies
}
}
class Enemy extends MyActor
{
//implement onRemove, onAdd, etc..
}
If it works better, MyActor could also be created as an interface instead - and then you could just as easily create sub-classes for Label or other LibGdx classes which inherit from Actor.
I personally chose to make it a sub-class, just because I could create helper-methods which were easier to type and call - such as my "movement" and "rotation" code, which don't use the Action classes which LibGdx comes with.
The easiest and in my opinion generating least lines of code is to use UserObject Actor field like:
Actor actor = new Actor(); //or its children ofc
actor.setUserObject("enemy");
//...
if( actor.getUserObject().equals("enemy") )
{
//yup this is enemy
}
Of course it is not the best solution due to OOP and can be not very flexible in some cases but to be honest in a case like this handling additional arrays etc etc only complicates things.
Notice that UserObject is object type so if you want to push there something that Java cannot cast itself you will have to cast it on your own.
However if you would want to be super ok here's another more elegant solution:
You are overriding the Actor class with your own MyActor class with some customAction() method which do nothing. You will be inheriting from this class not from Actor now
In every child class the method do nothing but in your Enemy class you are implementing the funcionality
In a loop you are casting to (MyActor) and calling customAction method
for (Actor actor: getActors()) {
((MyActor)actor).customAction();
}
The customAction method has a logic from EnemyEffector
This would generate some problems if you are inheriting classes that inherits from Actor (like Label class) and also will be a problem if the EnemyEffector logic is using data that Actor instance should not know because they are global for example and shouldn't be redundant (of course you can also pass the information as a parameter of customAction method)
I'm new at Libgdx and one aspect that blocks me to continue with my Libgdx learning is the fact that a I don't know how to use the GestureListener. It's seems there's a user with the same doubt if you see in this link LibGdx: Utilizing a Gesture Listener, but it didn't help me much. So my question is: how do I use my own GestureListener class to process my player moviments? I wanna use the pan function to make it jump, but I don't know how to put my player object inside the method. If you see my gesture detector class:
public class GestureHandler implements GestureListener {
// Main Game class
private ClimbUp mainGame;
public GestureHandler(ClimbUp game) {
this.mainGame = game;
}
#Override
public boolean touchDown(float x, float y, int pointer, int button) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean tap(float x, float y, int count, int button) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean longPress(float x, float y) {
// TODO Auto-generated method stub
return false;
}
...
Then I followed what they told the user what to do: in the main class I passed the fallowing instruction:
Gdx.input.setInputProcessor(new GestureDetector(new GestureHandler(this)));
Now in my splash screen, I don't know how to use. How to make my GestureHandler object works for all project? I'll be very grateful with an answer!
So, you have some you class which need GestureListener "services" - you want to be informed when some gesture event happens and you want to have information of gesture properties.
Then, as you did, make your class implement GestureListener interface.
After that your IDE (Eclipse or Android Studio or something else) will complain that you didn't implemented all GestureListener methods, but it can also do that for you. If you (in eclipse) hover the error in the code IDE will offer you to create missing methods.
I would say you are at about that step. But now your methods have to do something useful. Like, if you want to do something when player taps the screen add your code inside that method. Do something there. Inside GestureListener methods you have some info available, as method parameters like x & y coordinates, button (left, middle, right) and something like that.
So, when you call that setInputProcessor with object created in you class that implemented G.L. interface libGDX will know to call your methods when some event occurs.
Every method IDE generated has that "todo" mark - that's where you have to put your code instead. The code that will handle that event, move your space ship, fire the bullet or what ever. You don't have to do something for every event, but only for those you are interested in. You can leave other empty, but your class must have them.
Here is some example:
// importing interface
import com.badlogic.gdx.input.GestureDetector.GestureListener;
// defining my class that implements that interface
public class TouchController implements GestureListener{
// constructor - just storing objects passed to it.
public TouchController(Playground pg, Army army, Hud hud){
super();
this.pg = pg;
this.army = army;
this.hud = hud;
initialZoom = pg.zoom;
}
// Adding some action to touchDown method - I'm just calling my hud object's method and passing coords I get
#Override
public boolean touchDown(float x, float y, int pointer, int button) {
hud.pressedAt(x, pg.camera.viewportHeight-y); // opposite Y axis
// TODO Auto-generated method stub
return false;
}
// Similar thing. I unproject coords I get.
#Override
public boolean tap(float x, float y, int count, int button) {
if (!hud.buttonPressed){
Vector3 touchPos = new Vector3();
touchPos.set(x, y, 0);
pg.camera.unproject(touchPos);
army.add(touchPos.x, touchPos.y, SoldierSide.RED);
}else hud.released();
return false;
}
// Again similar stuff, but this pan methods is getting also delta value (difference from last reading x and y values) which can be useful
#Override
public boolean pan(float x, float y, float deltaX, float deltaY) {
if (hud.aimDrag) hud.aimDragged((int)deltaX, (int)deltaY);
else if (hud.sliderDrag) hud.sliderDragged((int)deltaX, (int)deltaY);
else if (!hud.buttonPressed) pg.panned((int)deltaX, (int)deltaY);
return false;
}
...
I'm trying to use the overlaps method to determine whether two sprites collide but from some reason it simply doesn't work. It always returns false, even when I clearly see the sprites collide with each other.
The funny thing is, this is not the first time it's happenning to me. I don't know why the overlaps method doesn't work.
Here is my Hero class which has a method called isCollided.
package world_objects;
import helpers.Values;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.Rectangle;
/* Created by David Lasry : 10/25/14 */
public class Hero{
public enum HeroState {
Walking_Forward,
Walking_Left,
Walking_Right,
Dead
}
public HeroState state;
private Rectangle body;
private float x,y;
public Hero() {
x = Values.SCREEN_WIDTH/5;
y = Values.SCREEN_HEIGHT/5;
body = new Rectangle(x, y, Values.Hero_Width, Values.Hero_Height);
state = HeroState.Walking_Forward;
}
public Rectangle getBody() {
return body;
}
public boolean isCollided(Rectangle rect) {
Gdx.app.log("Collision Detected", ""+body.overlaps(rect));
return rect.overlaps(body);
}
public HeroState getState() {
return state;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
public void setX(float x) {
this.x = x;
}
public void setY(float y) {
this.y = y;
}
}
As you can see, I tried to debug it by figuring out what the returned value is. Every single time it is false, even when it should be true.
What can I do? Is there any alternative method that I can use?
Edit: After debugging a little bit and trying to figure out the values of the two objects(Hero, Object) in real time, I came up with this screen shot: http://i.gyazo.com/852fea520b060870a4cb5731c21fa833.png.
The values of the two objects in this exact same position are(The X/Y is at the bottom-left corner):
**Hero X/Y: 64.5,283.40985**
**Hero WIDTH/HEIGHT: 25,50**
**Square X/Y: 76.25,0.0**
**Square WIDTH/HEIGHT: 47.5,309.13348**
As you can see, the values are perfectly normal. I don't understand where is the problem.
The problem is probably this - as Angel Angel suggested in the comments - when you create your Hero he has his x, y location values. The hero's body (a rectangle) also has its own x, y values. When he moves, you are probably only updating the Hero's x, y values and not the body's x, y values or vice versa. If you looked at the values with the debugger you would see exactly what's happening. My guess is you looked at the wrong values and made some incorrect assumptions that the method doesn't work. I guarantee you, the overlap method is very simple and does work. If you don't know how to use the debugger, this is the perfect time to learn. It will pay off many many times in the future as you continue developing your game. Unless you enjoy writing thousands of System.out calls to find every little bug you face, learn to use the debugger now! Had you known how to use the debugger this bug could have been fixed within a couple of minutes and without the need to write a question in stack overflow.
I made some tests and everything work as expected. Here below the classe I used for testing:
Value holds the the values for screen height / width and actor size
public class Values {
public static final int SCREEN_HEIGHT = 240;
public static final int SCREEN_WIDTH = 400;
public static float Hero_Width = 20;
public static float Hero_Height = 30;
}
This is the Hero, similar to your version I just removed what is not need specifically required for the test.
public class Hero {
private Rectangle body;
private float x, y;
public Hero() {
x = Values.SCREEN_WIDTH / 5;
y = Values.SCREEN_HEIGHT / 5;
body = new Rectangle(x, y, Values.Hero_Width, Values.Hero_Height);
}
public boolean isCollided(Rectangle rect) {
Gdx.app.log("Collision Detected", "" + body.overlaps(rect));
return rect.overlaps(body);
}
}
The ***Hero* according to the Values that I chose would have:
body = new Rectangle(80,48,20,30);
Then I made 3 tests with this testing code:
Hero hero = new Hero();
Rectangle rectangle = new Rectangle(10, 10, 100, 100);
// is true
boolean isCollided = hero.isCollided(rectangle);
Rectangle rectangle2 = new Rectangle(10, 10, 40, 40);
// is false
boolean isCollided2 = hero.isCollided(rectangle2);
Rectangle rectangle3 = new Rectangle(50, 30, 40, 20);
// is true
boolean isCollided3 = hero.isCollided(rectangle3);
I assume that there are some incorrect values passed to the isCollide method. As the other comments suggested, try debug which values of the rectangle are given when you call that method. Somehow the Hero object or the test rectangle are not like you would expect them.
If this would not fix your issue, consider posting more description / code in your original post.