Thank you for the reply. Maybe I am misunderstanding you but essentially, that’s what ProcessXCollision() is. ProcessCollision() is an abstract method of State, which is a member of Mob. ProcessXCollision is just a subdivision of that method, i.e. it gets called by ProcessCollision() and is unique to that particular Mob state.
Here’s the declaration:
public interface State {
public State init(Mob m);
public State update();
public void render(Screen s);
public void processCollision(Mob m);
public Mob getMob();
}
So my problem is that the collision is processed differently depending on the Mob that “this” comes in contact with. processCollision() takes Mob as an argument, and the Mob state has to be checked so “this” knows how to properly react, and the only way I know how to do that is with “instanceof”. That ProcessXCollision is unique to the ball’s state BallNormalState:
package com.noah.breakit.entity.mob.ball;
import com.noah.breakit.entity.mob.Mob;
import com.noah.breakit.entity.mob.brick.Brick;
import com.noah.breakit.entity.mob.brick.BrickPortalState;
import com.noah.breakit.entity.mob.brick.BrickSolidState;
import com.noah.breakit.entity.mob.forcefield.ForceField;
import com.noah.breakit.entity.mob.player.Player;
import com.noah.breakit.entity.state.State;
import com.noah.breakit.graphics.Screen;
import com.noah.breakit.sound.SoundFX;
import com.noah.breakit.util.Config;
import com.noah.breakit.util.Util;
public class BallNormalState implements State {
protected Ball b = null;
public State init(Mob m) {
b = (Ball) m;
b.setCol(0xff00ff);
adjustSize(4);
return this;
}
public State update() {
b.processWallCollision();
b.updatexa();
b.updateya();
if (!b.released) b.setxa(b.getPlayfield().getPlayer().getxa());
b.movex();
b.movey();
b.portalSicknessTimer = Util.max(++b.portalSicknessTimer, Ball.PORTAL_SICKNESS_TIME);
return this;
}
public void render(Screen s) {
s.fillRect(b.getx(), b.gety(), b.getWidth(), b.getHeight(), b.getCol());
if (b.released) return;
String s0 = "stage-" + (b.getPlayfield().getStage() + 1);
String s1 = "press <space>";
String s2 = "to launch!";
int xofs = Config.WINDOW_WIDTH >> 1;
int yofs = Config.WINDOW_HEIGHT >> 1;
s.renderString8x8(xofs - ((s0.length() << 3) >> 1), yofs - 10, 0xffffff, s0);
s.renderString8x8(xofs - ((s1.length() << 3) >> 1), yofs, 0xffffff, s1);
s.renderString8x8(xofs - ((s2.length() << 3) >> 1), yofs + 10, 0xffffff, s2);
}
public void processCollision(Mob m) {
if (!b.released) return;
if (m instanceof Brick && m.getState() instanceof BrickPortalState) {
BrickPortalState s = (BrickPortalState) m.getState();
if(b.portalSicknessTimer == Ball.PORTAL_SICKNESS_TIME) {
int xd = Math.abs(b.getx() + b.getWidth() / 2 - m.getx() - m.getWidth() / 2);
int yd = Math.abs(b.gety() + b.getHeight() / 2 - m.gety() - m.getHeight() / 2);
if (xd <= 8 && yd <= 4) {
b.portalSicknessTimer = 0;
b.setx(s.getMate().getMob().getx() + s.getMate().getMob().getWidth() / 2);
b.sety(s.getMate().getMob().gety() + s.getMate().getMob().getHeight() / 2);
b.setydir(b.getydir() * -1);
SoundFX.PORTAL.play();
}
}
return;
}
processXCollision(m);
processYCollision(m);
if (m instanceof Player || m instanceof ForceField) {
b.setMultiplier(1);
SoundFX.HI_BOUNCE.play();
}
}
protected void processXCollision(Mob m) {
int xDist = (b.getx() + b.getWidth() / 2) - (m.getx() + m.getWidth() / 2);
b.setxspeed(Math.abs(xDist / 4));
if (m instanceof Player || m instanceof ForceField) {
b.setxdir(Util.clamp(xDist, -1, 1));
if(m instanceof ForceField)
b.setxspeed(Util.clamp(b.getxspeed(), -3, 3));
}
if (m instanceof Player) {
b.setxdir(Util.clamp(xDist, -1, 1));
b.setxspeed(Math.abs(xDist / 4));
}
else if (m.getState() instanceof BrickSolidState) {
if (b.getxspeed() == 0) b.setxspeed(Util.random.nextInt(2) > 0 ? -1 : 1);
if (b.getxdir() == 0) b.setxdir(Util.random.nextInt(2) > 0 ? -1 : 1);
}
}
protected void processYCollision(Mob m) {
if(m instanceof Brick) {
int yDist = (b.gety() + b.getHeight() / 2) - (m.gety() + (m.getHeight() / 2));
b.setyspeed(Util.min(Math.abs(yDist / 2), 3));
if (b.getyspeed() == 0) b.setyspeed(3);
b.setydir(Util.clamp(yDist, -1, 1));
if (b.getydir() == 0) b.setydir(-1);
} else
b.setydir(-1);
}
public Mob getMob() {
return b;
}
protected void adjustSize(int size) {
int wOld = b.getWidth();
int hOld = b.getHeight();
b.setWidth(size);
b.setHeight(size);
b.setx(b.getx() - (b.getWidth() / 2) + (wOld / 2));
b.sety(b.gety() - (b.getHeight() / 2) + (hOld / 2));
}
}
You can see I have many “instanceof” keywords in there. It works fine for this game since it is a very small one, but I’m thinking in terms of larger projects in the future. How can I design this to not use instance of, which seems to be brittle and scale poorly, or am I overthinking this? I’t hard to tell because there really is no manual for something like this.