JohnathonNow / Bending

A 2D, multiplayer online action game.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Lots of "instanceof" checks

JohnathonNow opened this issue · comments

These should be refactored. Perhaps each entity could have a method for handling collisions with the player and doing the right thing afterwards.

for (Entity e:world.entityList)
{
if (e instanceof MissileEntity)
{
MissileEntity me = (MissileEntity)e;
//if (pointDis(me.X, me.Y, world.x, world.y)<me.radius*2&&me.maker!=ID)
if (checkCollision(me.X,me.Y)&&me.maker!=ID&&(gameMode>0?badTeam.contains(me.maker) :true))
{
me.alive = false;
hurt(10);
xspeed+=7-random.nextInt(14);
world.vspeed-=5;
lastHit = me.maker;
killMessage = "~ was blown away by `.";
}
}
if (e instanceof TornadoEntity)
{
TornadoEntity me2 = (TornadoEntity)e;
if (checkCollision(me2.X,me2.Y)&&me2.life<80)
{
hurt(1);
//world.vspeed-=1;
xspeed+=1-random.nextInt(2);
xspeed*=-1;
world.x = (int)me2.X+(int)xspeed;
world.move = 0;
lastHit = me2.maker;
killMessage = "~ was sucked into `'s Tornado.";
}
}
if (e instanceof GustEntity)
{
GustEntity me2 = (GustEntity)e;
if (checkCollision(me2.X,me2.Y))
{
hurt(7);
world.vspeed+=me2.yspeed*2;
xspeed+=me2.xspeed*2;
me2.alive = false;
lastHit = me2.maker;
lungs = maxlungs;
killMessage = "~ met `'s gust of air!";
}
}
if (e instanceof RockEntity)
{
RockEntity me3 = (RockEntity)e;
if (checkCollision(me3.X,me3.Y)&&me3.maker!=ID&&(gameMode>0?badTeam.contains(me3.maker) :true))
{
hurt(18);
world.vspeed-=5;
xspeed+=7-random.nextInt(14);
lastHit = me3.maker;
me3.alive = false;
killMessage = "~ was built into a bridge by `.";
}
}
if (e instanceof FireBallEntity)
{
FireBallEntity me3 = (FireBallEntity)e;
if (checkCollision(me3.X,me3.Y)&&me3.maker!=ID&&(gameMode>0?badTeam.contains(me3.maker) :true))
{
hurt(15);
world.status|=World.ST_FLAMING;
world.vspeed-=7;
xspeed+=9-random.nextInt(18);
lastHit = me3.maker;
me3.alive = false;
world.status |= World.ST_FLAMING;
killMessage = "~ was burninated by `.";
}
}
if (e instanceof FirePuffEntity)
{
FirePuffEntity me3 = (FirePuffEntity)e;
if (checkCollision(me3.X,me3.Y)&&me3.maker!=ID&&(gameMode>0?badTeam.contains(me3.maker) :true))
{
hurt(2);
world.status|=World.ST_FLAMING;
world.vspeed-=2;
xspeed+=2-random.nextInt(4);
lastHit = me3.maker;
me3.alive = false;
world.status |= World.ST_FLAMING;
killMessage = "~ was set ablaze by `.";
}
}
if (e instanceof EnemyEntity)
{
EnemyEntity me3 = (EnemyEntity)e;
if (checkCollision(me3.X,me3.Y)&&me3.master!=ID&&(gameMode>0?!myTeam.contains(me3.master):true))
{
hurt(7);
world.vspeed-=4;
xspeed+=4-random.nextInt(8);
lastHit = me3.master;
killMessage = "~ was defeated by `'s dark minion.";
}
}
if (e instanceof BuritoEntity)
{
BuritoEntity me3 = (BuritoEntity)e;
if (checkCollision(me3.X,me3.Y)&&me3.maker!=ID&&(gameMode>0?badTeam.contains(me3.maker) :true))
{
hurt(65);
world.status|=World.ST_FLAMING;
world.vspeed-=39;
xspeed+=47-random.nextInt(94);
lastHit = me3.maker;
me3.alive = false;
world.status |= World.ST_FLAMING;
killMessage = "~ shouldn't have stolen `'s burito...";
}
}
if (e instanceof LavaBallEntity)
{
LavaBallEntity me3 = (LavaBallEntity)e;
if (checkCollision(me3.X,me3.Y)&&me3.maker!=ID&&(gameMode>0?badTeam.contains(me3.maker) :true))
{
lastHit = me3.maker;
killMessage = "How did ` beat ~?";
me3.alive = false;
}
}
if (e instanceof SoulDrainEntity)
{
SoulDrainEntity me3 = (SoulDrainEntity)e;
if (checkCollision(me3.X,me3.Y)&&me3.maker!=ID&&(gameMode>0?badTeam.contains(me3.maker) :true))
{
lastHit = me3.maker;
killMessage = "~'s soul was stolen by `!";
me3.alive = false;
ByteBuffer bb = ByteBuffer.allocate(8);
bb.putInt(lastHit).putInt(hurt(21));
world.vspeed-=5;
xspeed+=7-random.nextInt(14);
try {
out.addMesssage(bb, Server.DRAIN);
} catch (IOException ex) {
//Logger.getLogger(APPLET.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
if (e instanceof FireJumpEntity)
{
FireJumpEntity me3 = (FireJumpEntity)e;
if (pointDis(me3.X, me3.Y, world.x, world.y)<me3.radius*4&&me3.maker!=ID&&(gameMode>0?badTeam.contains(me3.maker) :true))
{
hurt(15);
world.status|=World.ST_FLAMING;
world.vspeed+=me3.yspeed*2;
xspeed+=me3.xspeed;
lastHit = me3.maker;
me3.alive = false;
killMessage = "~ was flung into orbit by `'s falcon pawnch!";
}
}
if (e instanceof ShardEntity)
{
ShardEntity me3 = (ShardEntity)e;
if (pointDis(me3.X, me3.Y-World.head, world.x, world.y)<me3.radius*4&&me3.maker!=ID&&(gameMode>0?badTeam.contains(me3.maker) :true))
{
hurt(15);
world.vspeed-=5;
xspeed+=7-random.nextInt(14);
lastHit = me3.maker;
me3.alive = false;
killMessage = "~ was sniped by `.";
}
}
if (e instanceof SandEntity)
{
SandEntity me3 = (SandEntity)e;
double d = pointDis(me3.X, me3.Y, world.x, world.y);
//System.out.println(d);
if (d<me3.radius*3&&me3.maker!=ID&&(gameMode>0?badTeam.contains(me3.maker) :true))
{
hurt(2);
world.vspeed-=1;
xspeed+=(me3.xspeed/64);
lastHit = me3.maker;
me3.alive = false;
killMessage = "~ was shredded by `'s shotgun.";
}
}
if (e instanceof IceShardEntity)
{
IceShardEntity me3 = (IceShardEntity)e;
if (checkCollision(me3.X,me3.Y)&&me3.maker!=ID&&(gameMode>0?badTeam.contains(me3.maker) :true))
{
hurt(15);
world.vspeed-=5;
xspeed+=7-random.nextInt(14);
lastHit = me3.maker;
me3.alive = false;
killMessage = "~ was hit by `'s icey attack!";
}
}
if (e instanceof SnowEntity)
{
SnowEntity me3 = (SnowEntity)e;
if (checkCollision(me3.X,me3.Y)&&me3.maker!=ID&&(gameMode>0?badTeam.contains(me3.maker) :true))
{
hurt(8);
world.vspeed-=3;
xspeed+=3-random.nextInt(6);
lastHit = me3.maker;
me3.alive = false;
killMessage = "~ will need to be thawed out after fighting `!";
}
}
if (e instanceof SpoutEntity)
{
SpoutEntity me3 = (SpoutEntity)e;
if (checkCollision(me3.X,me3.Y))
{
if (me3.maker!=ID&&(gameMode>0?badTeam.contains(me3.maker) :true))
{
hurt(5);
lastHit = me3.maker;
}
world.vspeed-=5;
killMessage = "~ was kicked out of `'s swimming pool.";
}
}
if (e instanceof BallLightningEntity)
{
BallLightningEntity me3 = (BallLightningEntity)e;
if (checkCollision(e.X,e.Y))
{
if (me3.maker!=ID&&(gameMode>0?badTeam.contains(me3.maker) :true))
{
hurt(10);
lastHit = me3.maker;
world.vspeed-=random.nextInt(22);
xspeed+=18-random.nextInt(36);
killMessage = "~ was shockingly killed by `!";
}
}
}
if (e instanceof WallofFireEntity)
{
WallofFireEntity me3 = (WallofFireEntity)e;
checkCollision(me3.X,me3.Y);//Just to move the hitbox so when it is passed, it works
//pointDis(me3.X, me3.Y, world.x, world.y)<me3.height
if (me3.checkCollision(playerHitbox) &&me3.maker!=ID&&(gameMode>0?badTeam.contains(me3.maker) :true))
{
hurt(35);
me3.alive = false;
lastHit = me3.maker;
world.vspeed-=8;
xspeed+=9-random.nextInt(18);
world.status |= World.ST_FLAMING;
killMessage = "~ smelled `'s armpits, and then died.";
}
}
}

I can work on this, give me 2 days to run the game and get an idea of the code base, and I can come up with a plan to refactor this part based on best practices.
If the plan sounds fine to you, I can make the PR post discussion.
Can you assign this to me?

Thanks, for assigning this to me.

I have taken a look at the code and as you suggested, we can have an abstract method in Entity.java and we could make each entity handle this.
One thing to double check is exactly what can be modified by each Entity. i.e what needs to be passed and what needs to be returned and set. So far speed variables and world values seem to be changing. But I will take a deeper look to see if anything else needs to be modified and design the return Class accordingly.

Would a mediator pattern be more appropriate here?

I had thought of using an interface (Mediator) to deal with Collisions. But every Entity logically would need to handle collisions and making each entity implement the interface, might lead to a lot more work for no particular reason. Ref
One benefit of the Mediator (As I understand it, let me know if I misunderstood it) would be to slightly decouple the Client.java from the Entity. but the Client.java would still need to be passed in the mediator, so I don't know how much benefit this would yield.

Yeah that is the benefit - not that what you have here isnt fine. The mediator would let the collision logic live outside of the entities themselves, so neither they nor the client would never have to know or care about what is happening during the collision, they would just have their properties updated.

I'm not sure, how the mediator pattern would be implemented here.

Say we have a MediatorClass

public class MediatorClass {
   Client client;
   Entity entity;
   //constructor, this would need to be constructed for each different entity in the entityList?

   //methods, this would be called by the entity in WaterEntity::handleCollision { mediator.handleCollisionWithWaterEntity() }
   handleCollisionWithWaterEntity() {
   //update client
   //update entity 
   }
   // wouldn't we need to create a method for each different type of entity?
   // and there is also possibility of accidental misuse. i.e an entity caling the wrong collision handling method.
   // and I'm not sure how this would work on the Client side either

This rough implementation is based on what's suggested here. Ref.
Do you have any idea on how this could be implemented better?

So, my recommendation would be:
in the entitiy classes, store the changes that need to happen in the class itself (make them in the base entity class). Then, the mediator can be agnostic to the specific changes that need to happen. eg:
changeinxspeed
changeinworldx

etc.
If there is more specific logic required, you can make it a virtual funciton on the entity class and implement it in the children, eg. virtual void SetWorldX(int startingx)