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.
Related
I have a gameObject called BounceBack that is supposed to bounce the ball back far away when they collide together.
public class BounceBack : MonoBehaviour
{
public GameObject Player;
public float force;
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag(Player.tag))
{
Player.GetComponent<PlayerController>().ForceBack(force);
}
}
}
The ball Player (ball) script:
public class PlayerController : MonoBehaviour
{
public int acceleration;
public int speedLimit;
public int sideSpeed;
public Text countText;
public Text winText;
public GameObject pickUp;
public GameObject finishLine;
//internal void ForceBack() //Not sure what it does and why it's there.
//{
// throw new NotImplementedException();
//}
private int count;
private Rigidbody rb;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
SetCount();
}
// Update is called once per frame
void FixedUpdate()
{
float moveHorizontal = Input.GetAxis("Horizontal") * sideSpeed * rb.velocity.magnitude / acceleration;
//float moveVertical = Input.GetAxis("Vertical") * acceleration;
if (rb.velocity.magnitude <= speedLimit)
{
rb.AddForce(0.0f, 0.0f, acceleration); // add vertical force
}
rb.AddForce(moveHorizontal, 0.0f, 0.0f); // add horizontal force
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag(pickUp.tag))
{
other.GetComponent<Rotate>().Disapear();
count++;
SetCount();
}
if (other.gameObject.CompareTag(finishLine.tag))
{
acceleration = 0;
sideSpeed = 0;
finishLine.GetComponent<GameEnd>().FadeOut();
if (count >= 2)
{
winText.GetComponent<WinTextFadeIn>().FadeIn("Vous avez remporté la partie!");
}
else
{
winText.GetComponent<WinTextFadeIn>().FadeIn("Vous avez perdu. Réesayer?");
}
}
}
private void SetCount()
{
countText.text = "Count : " + count.ToString();
}
public void ForceBack(float force)
{
Rigidbody rb = GetComponent<Rigidbody>();
rb.AddForce(0.0f, 0.0f, -force, ForceMode.VelocityChange);
Debug.Log("Pass");
}
}
The AddForce function does not do anything. I tried with setActive(false) and it's not working either. The only thing that works is Debug.Log(). I'm not sure if the speedlimit and acceleration are interfering with the function.
EDIT: I'm not sure if the problem is from Unity but I can't access any variable of the class from the forceBack function inside the class.
EDIT2: I also tried to call the AddForce function directly in the Bounce Back script but it's not working either.
Player.GetComponent<Rigidbody>().AddForce(0.0f, 0.0f, -force, ForceMode.VelocityChange);
Player (Ball) Screenshot
Bounce Back Screenshot
So, a couple things:
1.) The physics system should already cause the ball to bounce if you've set up the colliders and rigidbodies properly. You should only need to do something like this if the ball should gain momentum when it bounces, which is unlikely. You should post screenshots of their inspectors if this answer doesn't help.
2.) On your rb.AddForce() call, you're applying a force in world-space, which may be the wrong direction to bounce. If you know the ball is oriented the way it's moving, then you can call AddRelativeForce with the same parameters. If the ball's orientation is not controlled, then you need to calculate the correct world-space direction to use before applying the force.
3.) Finally, just to confirm, the objects with BounceBack attached do have a non-zero value in the 'force' parameter in the inspector, right?
I am building a flappy bird style side scroller game and currently implementing collectible items for the main sprite to collect as it flies. I am not moving the main sprite but moving the background using ParallaxEffect and intend to move the collectibles (called orbs) towards the main sprite (bird). The Orbs are rendered in random positions but the position is not changed even after the update method is called.
Here is my CollectibleOrbs.java
public class CollectibleOrbs {
private static final int ORB_COUNT = 10;
private Array<Orb> orbs;
private Orb orb;
public CollectibleOrbs(){
orbs = new Array<Orb>();
for(int i=0;i<ORB_COUNT; i++) {
orb = new Orb();
orbs.add(orb);
}
}
public void update(float delta){
for(Orb orb: orbs){
orb.update(delta);
}
}
public void render(SpriteBatch sb){
for(Orb orb:orbs){
orb.draw(sb);
}
}
private class Orb{
private ParticleEffect effect;
private Vector2 position;
private Random rand;
public Orb(){
effect = new ParticleEffect();
rand = new Random();
position = new Vector2(rand.nextInt(Gdx.graphics.getWidth()),rand.nextInt(Gdx.graphics.getHeight()));
effect.load(Gdx.files.internal("particle/orbred.p"),
Gdx.files.internal("particle"));
effect.setPosition(position.x,position.y);
}
public void draw(SpriteBatch sb){
effect.draw(sb,Gdx.graphics.getDeltaTime());
}
public void update(float dt){
if(position.x< 10){
position.x = rand.nextInt(Gdx.graphics.getWidth());
position.y = rand.nextInt(Gdx.graphics.getHeight());
}
else
{
position.x-= 100*dt;
}
}
}
}
The orbs are rendered but they are not moving whereas the bird animation and the parallax background does:
I am calling the update method of CollectibleOrb class in the update of my game state and respectively for the render method while passing required parameters. How do to make sure the orbs move on the game screen?
The problem is that position is just unrelated to effect vector. Changing just position won't change effect's position. One way to solve it:
public void update(float dt){
if(position.x< 10){
position.x = rand.nextInt(Gdx.graphics.getWidth());
position.y = rand.nextInt(Gdx.graphics.getHeight());
}
else
{
position.x-= 100*dt;
}
// you should update ParticleEffect position too, just like you did in the constructor
effect.setPosition(position.x, position.y);
}
I am creating a game wherein an apple is being shot with an arrow. The apple's location is the XY location of the user input and the arrow actor has to move to that location using the code actor.moveto. The problem is the arrow only moves only once to the user input's direction. I know that the moveTo action of the actor is updated many times per second when I called stageArrow.act in the update method so I am wondering why the arrow only moves once. Here's my code:
appleclass.java
public class AppleClass implements Screen {
Arrow arrow;
private final MainApp app;
public Image ShotImage;
public AppleClass(final MainApp app){
this.app = app;
this.stageApple = new Stage(new StretchViewport(app.screenWidth,app.screenHeight , app.camera));
this.stageArrow =new Stage(new StretchViewport(app.screenWidth,app.screenHeight , app.camera));
arrow = new ArrowClass(app);
}
#Override
public void show() {
InputMultiplexer inputMultiplexer = new InputMultiplexer();
inputMultiplexer.addProcessor(stageApple);
inputMultiplexer.addProcessor(stageArrow);
Gdx.input.setInputProcessor(inputMultiplexer);
arrow();
}
public void arrow(){
arrow.isTouchable();
stageArrow.addActor(arrow);
arrow.addAction((moveTo(Gdx.input.getX(),Gdx.input.getY(),0.3f))); //===> only executes once.
arrow.addListener(new InputListener(){
public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor){
if (Gdx.input.isTouched()){
ShotImage.setVisible(true);
}
}
});}
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
update(delta);
}
public void update(float deltaTime){
stageApple.draw();
stageArrow.draw();
stageApple.act(deltaTime);
stageArrow.act(deltaTime);
}
ArrowClass.java
public class ArrowClass extends Actor {
MainApp app;
AppleClass appleClass;
public Texture arrowTexture;
public ArrowClass(final MainApp app){
this.app = app;
arrowTexture = new Texture("medievalarrow.png");
this.setSize(arrowWidth, arrowHeight);
this.setTouchable(Touchable.enabled);
this.setBounds(app.screenWidth*0.45f,0,arrowWidth,arrowHeight);
this.setOrigin(0,0);
}
#Override
public void draw(Batch batch, float parentAlpha) {
super.draw(batch, parentAlpha);
final float delta = Gdx.graphics.getDeltaTime();
this.act(delta);
app.batch.begin();
app.batch.draw(arrowTexture, getX(),getY(),getWidth(),getHeight());
app.batch.end();
}
}
Any help will be highly appreciated. Thanks.
I think the problem is because you are calling this.act(delta) in your ArrowClass' draw method. When you call Stage#act(), it will call the act method on all of its actors for you. Since you're calling it once when you draw and again when you update the stage, it's moving at twice the normal speed and that could be causing it to reach its destination prematurely.
A few other comments about your code, if I may:
First, you probably don't want two separate stages- unless you're using Scene2D.UI, you would normally have a single stage with Arrow and Apple added to it as actors.
Second, when you override Actor#draw(), you should use the batch it passes you to do the rendering instead of using the one from app. You also don't want to call begin() and end() inside your draw method- these are 'expensive' and you only want to call them once per frame. However, if you just use the batch that is passed to draw(), the Stage class will handle beginning and ending for you and you won't need to call them explicitly.
Third, you actually don't need to call super.draw(batch, parentAlpha) because it's an empty method in the Actor class.
Thus, your class could be simplified to the following:
public class ArrowClass extends Actor {
AppleClass appleClass; // You never set this; you may not need it
Texture arrowTexture;
public ArrowClass(MainApp app, arrowWidth, arrowHeight) {
arrowTexture = new Texture("medievalarrow.png");
this.setSize(arrowWidth, arrowHeight);
this.setTouchable(Touchable.enabled);
this.setBounds(app.screenWidth*0.45f,0,arrowWidth,arrowHeight);
this.setOrigin(0,0);
}
#Override
public void draw(Batch batch, float parentAlpha) {
batch.draw(arrowTexture, getX(),getY(),getWidth(),getHeight());
}
}
I want to make a text appear in the center of the screen, indicating
the current level. It should appear gradually and after a while disappear gradually. I'm using scene2d with stages, actors.. so i would use Actions.
This is what i have now:
public class TextActor extends Actor {
private BitmapFont font;
private CharSequence charSequence;
public TextActor(CharSequence charSequence) {
font = new BitmapFont(Gdx.files.internal("fonts/white_standard_font.fnt"));
this.charSequence = charSequence;
}
#Override
public void act(float delta) {
super.act(delta);
}
#Override
public void draw(Batch batch, float delta) {
super.draw(batch, delta);
font.draw(batch, charSequence, getX(), getY());
}
}
In the class that creates the TextActor..
textActor.addAction(Actions.sequence(Actions.fadeIn(1f), Actions.delay(1f), Actions.fadeOut(1f), new Action() {
#Override
public boolean act(float delta) {
textActor.remove();
transitionInProgress = false;
gameState = GameState.RUNNING;
Gdx.input.setInputProcessor(stage);
return true;
}
}));
gameTable.addActor(textActor);
fadeIn, fadeOut, alpha.. don't work. I tried with "moveBy" and it works, so it seems a problem concerning the appearance of the Actor. There is something that escapes me.
The fade actions modify the alpha value of the Actor's color (getColor().a). You're drawing the font directly without applying the color associated with the actor.
Take a look at how Label.draw is implemented for a better understanding. In the meantime, just try adding this above your font.draw(...) call:
font.setColor(getColor())
Or, if you don't want to modify the entire color, just the alpha, try this:
font.getColor().a = getColor().a;
UPDATE:
Also note that you should apply the parentAlpha (second parameter of draw - labelled as delta in your example) to the final alpha:
font.getColor().a = getColor().a * parentAlpha
This allows your actor to fade if you change the alpha of the stage or any parents.
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)