I am currently building a game in AndEngine, but my collision detection seems a bit off. It works.. most of the time, but seems like when there is a collision with one object, it wont do the other. It's hard to explain and it's very unpredictable. If a car hits the snow, it should slow down. If a car hits ice, it should speed up.
for (int i = 0; i < rManager.carArray.length; i++)
{
if (rManager.getInstance().snowArray[0].getSnowSprite().collidesWith(rManager.getInstance().carArray[i].getCarSprite()))
{
Log.e("SNOW", "snow 0 collided with " + rManager.getInstance().carArray[i].ToString());
rManager.getInstance().carArray[i].setCarSpeed(0.1f);
break;
}
if (rManager.getInstance().iceArray[0].getIceSprite().collidesWith(rManager.getInstance().carArray[i].getCarSprite()))
{
Log.e("ICE", "ice 0 collided with " + rManager.getInstance().carArray[i].ToString());
rManager.getInstance().carArray[i].setCarSpeed(1f);
break;
}
else
{
rManager.getInstance().carArray[i].setCarSpeed(0.5f);
}
}
Is there anything wrong with my code? Currently, both enemy arrays only have 1 element. That is why I am only checking 0. Thanks!
You should remove the break; within the collision detection if test. (Or change it to continue if you only want snow or ice but not both for the same car...not sure quite how your game works in that regard).
Related
I am working on a card game and I'm facing a problem regarding the gameplay. So basically the rules of the game are that who finishes the hand first gets placed first, second second and so on. I am keeping a list of the players in a List<Player, and if one finishes I just skip the turn from him (checks if >= 1 cards in hand), until 1 player is left. Now, the rule is that if one finishes with an unbeatable card/move or everyone else passes for example, the turn should be to the next player and he is free to make a move. I've been struggling and haven't found a proper solution yet. How to achieve this?
I am currently saving the waste (last played list of cards) cards into a List<Card>, and I am keeping a Player instance lastPlayed for the last playing player, and a Player instance hasTurn for the current player on turn.
The turns are shifted in this method inside the Game class:
public void determineNextPlayerTurn()
{
if(playersLeft() > 1)
{
int i = players.indexOf(hasTurn) + 1;
if(i == 4)
i = 0;
hasTurn = players.get(i);
if(hasTurn.isPlaying())
{
if(!isHumanTurn())
{
display.disableButtons();
AI temp = (AI)players.get(i);
temp.onPlayerTurn(this);
}
else
display.enableButtons();
}
else
{
determineNextPlayerTurn();
}
}
else
newGame(0);
The method of AI that is called when it is an ai's turn:
public void onPlayerTurn(Game game)
{
selectCardsToPlay(game.getWaste(), game.getLastPlayedPlayer());
if(getSelectedCards().isEmpty())
{
game.determineNextPlayerTurn();
}
else
{
if(Moves.canBePlayed(getSelectedCards(), game.getWaste(), this, game.getLastPlayedPlayer()))
{
playMove(game);
game.determineNextPlayerTurn();
}
else
game.determineNextPlayerTurn();
}
}
While for the user, nothing is called as the determineNextPlayerTurn() is called within the ActionListener of the playing buttons (Play, Pass).
Note: Currently like this, if the scenario occurs with the human last playing there will be a stackoverflow for the reason that every ai is doing a Pass. Every other code is fine for now, but I need help with implementing a simple solution to that specific case, and if I am doing something wrong I am open.
Why don't you have a counter for the number of "passes" that are executed and then compare that to the number of players. If the passes are equal to the number of players - 1 then that would mean that following player should be free to make a move. Also what is an "unbeatable move" if there is such a thing then wouldn't you be able to classify the turn as that and then attach a boolean that checks the player for whether or not they have made one of these types of moves?
I am currently making a tower defence game.
Simply put it works like this: green circles (enemies) move across the screen. By clicking, you can place a tower. The enemy has a rectangle hidden underneath it, and the tower has a large opaque rectangle around it indicating its hit range. If they are colliding, the enemy starts to lose health, until it dies.
Before, I used this test to see if the enemy was within range of the tower:
for(int i=0;i<enemy.length; i++) //Runs for the total amount of enemies
{
for(int j=0; j<boxes.length;j++) //Runs for the total amount of towers placed
{
if(enemy[i].getEBox().intersects(boxes[j])) //boxes[j] is the towers' range box
{
enemy.setHealth(enemy.getHealth()-1);
}
}
}
However, I would like the towers to only be able to shoot one enemy at a time, most preferably the enemy at the front. To do this I need java to detect that there are multiple enemies colliding with the rectangle and only damage the front enemy.
Here is the test I ran to do this (The enemies array value go backwards so the first one to appear is enemy[0] and the last enemy[10] for example):
for(int i=1;i<enemy.length; i++)
{
for(int j=0; j<boxes.length;j++)
{
if(enemy[i].getEBox().intersects(boxes[j])&&!(enemy[i-1].getEBox().intersects(boxes[j])))
{
enemy.setHealth(enemy.getHealth()-1);
}
}
}
however, the second condition always returns a positive. How can I change my if statement to conduct a successful test?
To make a tower only shoot at one enemy, flip the loops and break the inner loop when shooting starts.
for(int j=0; j<boxes.length;j++) //Runs for the total amount of towers placed
{
for(int i=0;i<enemy.length; i++) //Runs for the total amount of enemies
{
if(enemy[i].getEBox().intersects(boxes[j])) //boxes[j] is the towers' range box
{
enemy[i].setHealth(enemy[i].getHealth()-1);
break; // skip remaining enemies, since towers has used
// up it's shooting capability for this round
}
}
}
If a tower can prioritize which enemy to shoot at, loop through all the enemies to find the best candidate, then shoot at it.
for (int j=0; j<boxes.length; j++) //Runs for the total amount of towers placed
{
int enemyToShootIdx = -1;
for (int i=0; i<enemy.length; i++) //Runs for the total amount of enemies
if (enemy[i].getEBox().intersects(boxes[j])) //boxes[j] is the towers' range box
if (enemyToShootIdx == -1 || betterCandidate(boxes[j], enemy[i], enemy[enemyToShootIdx]))
enemyToShootIdx = i;
if (enemyToShootIdx != -1)
enemy[enemyToShootIdx].setHealth(enemy[enemyToShootIdx].getHealth()-1);
}
Now you just have to implement the betterCandidate() method.
You could store the enemies in the order you detect them so you will know which is the closest. Like an ArrayList for detected enemies or an ID kind of variable for each enemy object, which initialized when detected. Im pretty sure there are a lot ways like this, so storing an order somehow could work. Once you have an order you can attack only that one and there is no need to test the detected objects anymore while still looking for coming enemies and keep storing them so on.
In your case
if(enemy[i].getEBox().intersects(boxes[j])&&!(enemy[i- 1].getEBox().intersects(boxes[j])))
I don't really see (or maybe just too tired) why you need these conditions to attack. If your array of enemies is already in order why dont you just attack the first? If inRange && isAlive if not you go on the next one.
I hope i did not misunderstand anything and probably could help a bit. :)
As a preface, I have searched the forums but found nothing relating to my specific situation. I just started learning Java about a week ago, and this is my first foray into object oriented programming.
I'm building a basic game (think somewhat like Space Invaders when it comes to mechanics). I have a "Projectile" class, a "FallingThings" class (which is the parent class to the classes I have for objects falling down (Money, Friend, Enemy)). Each projectile that is shot is stored in an ArrayList, and as is every instance of Money, Friend, and Enemy (each in their own ArrayList).
The problem happens when I implement collision detection. First off, it takes multiple bullets to make the collision mechanism work (I think I might have just messed up some numbers here but I'm not 100% sure). Now, sometimes after I fire multiple bullets (and they are long gone), a collision is detected without me firing another bullet and a FallingThings object disappears from the screen. Also, at other times, multiple objects disappear at once. The weirdest thing is that all this is inconsistent, and not always reproducible in the same fashion. However, my collisions with the player character work perfectly.
Anyone have some ideas as to how I can fix this? My code is below:
Method in the "FallingThings" class (the ArrayLists are defined in the StartingClass (the main class)).
public void checkBulletCollision(Rectangle rectangle) {
for (int j = 0; j < Character.getProjectiles().size(); j++) {
Projectile p = (Projectile) Character.getProjectiles().get(j);
if (p.isVisible() == true) {
for (int i = 0; i < StartingClass.getMoneys().size(); i++) {
Money m = (Money) StartingClass.getMoneys().get(i);
if (m.getR().intersects(rectangle)) {
m.remove(i);
System.out.println("bullet collision");
}
}
for (int i = 0; i < StartingClass.getEnemies().size(); i++) {
Enemy e = (Enemy) StartingClass.getEnemies().get(i);
if (e.getR().intersects(rectangle)) {
e.remove(i);
}
}
for (int i = 0; i < StartingClass.getFriends().size(); i++) {
Friend f = (Friend) StartingClass.getFriends().get(i);
if (f.getR().intersects(rectangle)) {
f.remove(i);
}
}
}
}
}
My update method for projectiles:
public void update() {
y -= speedY;
if (y < 0) {
visible = false;
}
rectangle.setBounds(getRectangle());
}
I've been trying to fix this for the entire day, and still can't get a proper implementation. I have tried using ListIterator, but that caused the program to freeze and a typecasting error to be thrown.
Thank you so much for the help! =)
I suspect you are having problems because you are removing items from the list by index while looping over that list. Removing items causes the index counter to get out of allignment. Try use an actual Iterator. No need to even think about indexes. The Iterator has a remove method for these situations..
Iterator<Enemy> iterator = StartingClass.getEnemies().iterator();
while (iterator.hasNext()) {
Enemy e = iterator.next();
if (e.getR().intersects(rectangle)) {
iterator.remove();
}
}
I don't understand what m.remove does, you get the item from the list but then call "remove" on the item. do you want to delete it from the List instead?
StartingClass.getMoneys().remove(i);
Looks like the issue is that you are letting all types of loops to run. So even after removing a Money with your Projectile, you are on to removing and Enemy and a Friend also with the same Projectile - which is possible if that Projectile is fired from anything bigger or from a .44 magnum.
Anyway, to me, looks like you need to break your iteration once you remove one item with one projectile.. so your code should be like(Use generics and enhanced for loops) :
foreachprojectile:
for( Projectile projectile : Character.getProjectiles()){
if (projectile.isVisible() == true) {
Iterator<Money> iterator = StartingClass.getMoneys().iterator();
while (iterator.hasNext()) {
Money m = iterator.next();
if (m.getR().intersects(rectangle)) {
iterator.remove();
projectile.setVisible(false); // or any other method that does similar
break foreachprojectile; //Found a hit, so do not
//look for any more hits with current projectile
}
}
//And so on..
}
}
Above code probably will get done what you are looking for; but this logic can be encapsulated better to clearly communicate the intent.
I figured out what was wrong and fixed the problem. It turns out that the issue was not in my implementation of the for loops (although using a listIterator is still more efficient and less error-prone, so I've still opted to change that aspect of my code), but rather in the implementation of my collision detection. I forgot that the projectile and rectangle (for the projectile) are two different objects, and as such, the rectangle was not moving with the projectile, resulting in all sorts of problems.
I determined the issue by painting the rectangle to the screen to check how it behaved, and sure enough, it just stayed in one place, not moving with the projectile. I made some changes to the projectile's update() method so that when called, the rectangle moves with the bullet. This resulted in proper collision detection and a functioning program!
Thank you so much to everyone for all the help, I learned a lot here about writing efficient code and debugging techniques! I really appreciate it! =)
Update: Added in some more details so a bit more context is given to the snippet of code I gave.
I recently submitted a game I made in Processing as part of my university coursework, but it didn't turn out exactly how I wanted it to, so I'm working on adding some features and re-coding some of it to make it more fun and replayable.
Anyway, the problem I'm having is with enemy wave generation. How my game works is that there is a class specifically for a single enemy instance, and I made an ArrayList for enemy generation. The below code has a for loop that sets itself depending on the amount of waves set as the integer waveCount. It adds a number of enemies to the ArrayList equal to the value waveCount, and then shows the enemies on the screen. The enemy is removed individually if they are shot, and if they touch the player, the player's health is reduced, then the player position is reset, as are the enemy's positions. They simply come from the top of the screen and move down towards the player at the bottom, slowly orientating themselves to the player's x and y position.
I have the enemy waves working correctly, but in the last version of my game I manually increased the waves as the player reaches certain scores with if statements, and now I want to figure out a way to have the game automatically add a wave when the player score reaches a 200 increment. I also want the enemy speed to increase slightly every time the play score reaches a 1000 increment.
Right now, the way I've coded it leads to it it only increasing the number of waves once at 200/400/600/etc before going back to a single wave. I've handled the enemies as an ArrayList of classes. If anyone can help me figure out a way to code an automated, infinite wave system, with one wave being added at score increments of 200, and the enemy speed increasing at score increments of 1000, that would be MASSIVELY helpful!
updateWave = false;
hasAddedWave = false;
scoreCheck = score.score;
enemySpeedX = 0.6;
enemySpeedY = 1;
waveCount = 1;
if(scoreCheck > 0 && scoreCheck % 200 == 0 && hasAddedWave == false){
updateWave = true;
}
if(updateWave == true && hasAddedWave == false){
waveCount += 1;
hasAddedWave = true;
}
if(updateWave == true && hasAddedWave == true){
updateWave = false;
hasAddedWave = false;
}
for(int i = 0; i < waveCount; i++){
zombiePosition = random(100,400);
zombies.add(new Enemy(zombiePosition,-50,enemySpeedX,enemySpeedY));
zombies.get(i).show();
}
In theory, what you need is a way to say :
"Hey, this guy reached 200 points further than before! Let's throw a new wave at him! "
Just by that sentence you can easily deduce that it's going to pass a LOT by repetitive cicles, evidently I cannot give you a code sample, as I can't guess what your code is (as someone already pointed, you haven't given us much to work with) . Try out something such as
if (pointsNow >= pointsBefore+200) doSomething
Furthermore, the reason why it goes back to a single wave is :
if(scoreCheck > 0 && scoreCheck % 200 == 0 && hasAddedWave == false){
updateWave = true;
}
What this if-statement means that scoreCheckis bigger than 0, AND divisible by 200. Which means that scoreCheck divided by 200 has a remainder of 0. Imagine if your player gets a score of 401, the score check wouldn't be able to be divided by 200, as the remained is NOT 0. Instead, try to:
scoreCheck > lastScoreCheck where you add 200 to lastScoreCheck (or whatever ammount you want)
And finally, about the speed, once again, play with the variables. Instead of having speed = 1 (for example) have : speed = 1 + level*multiplier , what this do is it sets the speed to a certain value in this case, 1, and adds a multiplier, which is depended by another variable which would be the level. You can manipulate it to make the game easier or harder, for example : speed = 1 + level*5 is a LOT faster than speed = 1 + level*0.5
I have a text based game that I am making. It is a RPG style where the user is given options linked to numbers and they have to choose a number. Now my problem is that when running the program. A certain method, Decision(), only works certain times. The method is in a superClass while it is being called in the subclass. in the subclass, It works the first time, but not necessarily the second. Also, when I copy the decision method from the superclass into the subclass its starts working, but the next time it is called, it stops. Here is what I've tried and the results. I've included the decision method and where it is being called.
Decision Method:
public int decision(String question, int length, String[] choices){
int[] numbers = new int[length];
int iterator = 1;
for(int i = 0; i < length; i++){
numbers[i] = iterator;
iterator++;
}
boolean done = false;
while(!done){
//print("Test");
print("");
print(question);
String options = "";
for(int i = 0; i < numbers.length; i++){
options = (options + numbers[i] + " - " + choices[i] + " ");
}
print(options);
boolean univSet = true;
int entry = 1;
while(univSet){
if(univInt != 0){
univSet = false;
entry = univInt;
univInt = 0;
//print("testing");
}
}
if(entry == 23){
help();
}else{
for(int i = 0; i < numbers.length; i++){
if(entry == numbers[i]){
done = true;
univInt = 0;
return entry;
}
}
print("Invalid Number, Try again");
print("");
univInt = 0;
}
}
return (Integer) null;
}
Chapter1 Class (Where it's being called:
public class Chapter1 extends Story implements Serializable {
Player player;
public Chapter1(Player player){
this.player = player;
}
public void engage() {
// TODO Auto-generated method stub
player.chapter = 1;
save(player.name);
sPrint("Welcome to Chapter 1");
print("You wake up in a lighted room with white walls.\nA fresh breeze is coming through the window yet the air smells rotten.");
print("You jolt up suddenly. You don't remember anything about how you got here. You've even forgotten who you are.");
print("You look down at your white shirt, there is a streak of blood across the top.\nYou are wearing a nametag that says: " + player.name + ".");
print("You're sitting in a chair but there are no restraints. You decide to get up and look around");
cur = decision("What do you do?", 2, new String[]{"Try the door", "Look out the window"});
print(cur + "");
if(cur == 1){
print("You walk over to the door and try and open it, it is unlocked.\nYou walk through and are welcomed by a cold and poorly lit hallway");
}else{
print("You walk to the window and look outside. You see a huge barren field. You can make out a humanoid like structure.\nYou call out yet the figure doesn't move.");
print("You decide to try the door. It's unlocked so you walk through into a cold dimly lit hallway.");
}
print("You see a dull knife on the floor as well as a door on the end of the hallway");
cur = decision("What do you do?", 2, new String[]{"Go to the door", "Take the knife"});
if(cur == 2){
print("You pick up the knife.");
addWeapon("Kitchen Knife", player);
}else{
print("You walk down the hallway to the door when suddenly the door opens and out comes a zombie.\nIt Lunges for your shoulder. You are caught by surprise and it bites into your skin and you are infected");
gameOver();
}
print("You continue to walk down the hall when suddenly a hideous creature lunges out from the door.\nYou jump back and prepare yourself for a battle.");
battle("Zombie", 5, 2, player);
sPrint("I see that you have succeeded in your first encounter with the undead.\nI congratulate you but you have a long way to go. Remember, I am your only way to learning about your past. \nNow, make your way down to the bottom of the tower. I will help you where I see fit along the way.");
print("You look around and see that the lights have brightened up. The zombie has been mutilated by your Kitchen Knife. \nYou don't know where the voice came from but you are scared. Behind the zombie's original hiding spot you see a staircase.\nYou follow it down, onto what seems to be..the 11th floor.");
print("");
print("Please input 'complete' to continue");
pause();
sPrint("Chapter 1 complete");
}
Now in this class, engage() is being called to run this chapter. And decision is being called where you see it, as well as in the battle() method(the battle method loops a couple times and decision() is called every loop.
Originally, both Decision and battle are in the superclass, but not in the sub class. This results in the first decision method in the class to be called, but not the second. In the second, it stops at the loop checking the value of univInt.
When I put the decision method into the sub class, It passes the first two but it fails to get past the first one in the battle method for the same reason.
When I put both the decision and battle method into the sub class, it has the same result as just putting decision.
Finally if I put battle in the sub class but not decision it only passes the first two again.
In the project I have one variable named cur that holds the integer value of whatever decision returns. I reuse it for every decision. I don't know if that has anything to do with it. This really doesn't make sense to me how whether the methods are in the same class, or inherited would matter at all if they are the same method.
I am ready to clarify anything and I hope someone is able to understand what is going wrong.
EDIT:
univInt is being set to another number other than 0 outside of decision. thats why it works some times. It is a swing class and a method in a superclass sets univInt to whatever is in a TextField when a button is pressed so with that while loop I try to constantly check to see univInt has been changed from 0
It seems like your "univInt" is a class member, not a local variable, and you do not reinitialize it when entering the function. Thus it won't be changed back to allow the program to enter the if-statement you mention.