Быстрый и грязный платформер с физикой имеет ошибки при перемещении платформ - PullRequest
0 голосов
/ 24 ноября 2010

Хорошо, поэтому я пытаюсь создать быстрый и грязный платформерный движок, и у меня возникли некоторые проблемы с обнаружением столкновений и движущимися платформами. с одной стороны, «игрок», кажется, слегка подпрыгивает на движущихся платформах, и когда он попадает в правую сторону, случаются и ошибки. Я загружу демо jnlp, чтобы вы могли попытаться найти больше ошибок и посмотреть, что происходит, но вот источник:

import java.awt.Rectangle;
import java.util.Vector;

import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;


public class Platformer extends BasicGame{

 boolean keys[];
 int ALL_KEYS = 0xFF;
 Player player;
 Vector<Vector<Thing> > things;
 int level = 0;

 public Platformer() {
  super("You've met with a terrible fate, haven't you?");
 }

 public void init(GameContainer gc) throws SlickException {
  keys = new boolean[ALL_KEYS];
  for(int i = 0; i < ALL_KEYS; i++){
   keys[i] = false;
  }

  player = new Player();
  things = new Vector<Vector<Thing> >();
  Vector<Thing> temp = new Vector<Thing>();
  temp.add(new Thing(0, 440, 640, 40, 1));
  temp.add(new Thing(200, 300, 240, 50, 1));
  temp.add(new Thing(500, 200, 240, 50, 1));

  things.add(temp); 
 }

 public void update(GameContainer gc, int delta) throws SlickException{
  if(keys[Input.KEY_UP]){
   player.velo = player.maxJump;
   keys[Input.KEY_UP] = false;
  }

  if(keys[Input.KEY_DOWN]){
   keys[Input.KEY_DOWN] = false;
  }

  if(keys[Input.KEY_LEFT]){
   player.delta -= player.speed;

   if(player.delta < -player.maxSpeed)
    player.delta = -player.maxSpeed;
  }

  else if(keys[Input.KEY_RIGHT]){
   player.delta += player.speed;

   if(player.delta > player.maxSpeed)
    player.delta = player.maxSpeed;
  }

  else{
   if(player.delta < -0.5){
    player.delta += player.speed;
   }

   else if(player.delta > 0.5){
    player.delta -= player.speed;
   }

   else if(player.delta > -0.5 && player.delta < 0.5){
    player.delta = 0; 
   }
  }

  if(player.delta < 0)
   player.moveLeft(things.get(level));

  else if(player.delta > 0)
   player.moveRight(things.get(level));

  if(player.velo < 0)
   player.moveUp(things.get(level));

  else
   player.moveDown(things.get(level));


  things.get(level).get(1).moveRight(player, things.get(level));

 }

 public void render(GameContainer gc, Graphics g) throws SlickException{
  g.setColor(new Color(0,55,55));
  g.fillRect(0, 0, 640, 480);

  g.setColor(new Color(255,0,0));
  g.fillRect(player.x, player.y, player.width, player.height);

  for(int i = 0; i < things.get(level).size(); i++){
   if(things.get(level).get(i).type == 1)
    g.setColor(new Color(0,100,100));

   g.fillRect(things.get(level).get(i).x, things.get(level).get(i).y,things.get(level).get(i).width, things.get(level).get(i).height);
  }
 }

 public void keyPressed(int key, char c) {
  keys[key] = true;
 }

 public void keyReleased(int key, char c) {
  keys[key] = false;
 }

 public static void main(String[] args) throws SlickException{
   AppGameContainer app =
   new AppGameContainer( new Platformer() );

   app.setShowFPS(false);
   app.setAlwaysRender(true);
   app.setTargetFrameRate(60);
   app.setDisplayMode(640, 480, false);
   app.start();
 }


 class Player{
  float x = 50;
  float y = 50;

  float delta = 0; // x momentum
  float velo = 0;
  int height = 50;
  int width = 30;
  float speed = 0.2f;
  int maxSpeed = 6;
  int maxFallSpeed = 5;
  int maxJump = -8;

  public void moveLeft(Vector<Thing> things){
   x += delta;

   if(x < 0)
    x = 0;

   for(int i = 0; i < things.size(); i++){
    if(new Rectangle((int) x, (int) y, width, height).intersects(new Rectangle((int) things.get(i).x, (int) things.get(i).y, things.get(i).width, things.get(i).height))){
     x += (things.get(i).x + things.get(i).width) - x;
     delta = 0;
    }
   }
  }

  public void moveRight(Vector<Thing> things){
   x += delta;

   if(x + width > 640)
    x = (640 - width);

   for(int i = 0; i < things.size(); i++){
    if(new Rectangle((int) x, (int) y, width, height).intersects(new Rectangle((int) things.get(i).x, (int) things.get(i).y, things.get(i).width, things.get(i).height))){
     x -= (x + width) - things.get(i).x;
     delta = 0;
    }
   }
  }

  public void moveLeftWithThing(Vector<Thing> things, float thingSpeed){
   x -= thingSpeed;

   if(x < 0)
    x = 0;

   for(int i = 0; i < things.size(); i++){
    if(new Rectangle((int) x, (int) y, width, height).intersects(new Rectangle((int) things.get(i).x, (int) things.get(i).y, things.get(i).width, things.get(i).height))){
     x += (things.get(i).x + things.get(i).width) - x;
     delta = 0;
    }
   }
  }

  public void moveRightWithThing(Vector<Thing> things, float thingSpeed){
   x += thingSpeed;

   if(x + width > 640)
    x = (640 - width);

   for(int i = 0; i < things.size(); i++){
    if(new Rectangle((int) x, (int) y, width, height).intersects(new Rectangle((int) things.get(i).x, (int) things.get(i).y, things.get(i).width, things.get(i).height))){
     x -= (x + width) - things.get(i).x;
     delta = 0;
    }
   }
  }

  public void moveUp(Vector<Thing> things){
   y += velo;

   velo += speed;

   if(velo > maxFallSpeed)
    velo = maxFallSpeed;

   for(int i = 0; i < things.size(); i++){
    if(new Rectangle((int) x, (int) y, width, height/2).intersects(new Rectangle((int) things.get(i).x, (int) things.get(i).y, things.get(i).width, things.get(i).height))){
     y += (things.get(i).y + things.get(i).height) - y;
     velo = 0;
    }
   }
  }

  public void moveDown(Vector<Thing> things){
   y += velo;

   velo += speed;

   if(velo > maxFallSpeed)
    velo = maxFallSpeed;


   boolean b = false;
   for(int i = 0; i < things.size(); i++){
    if(!b && new Rectangle((int) x, (int) y + (height/2), width, height).intersects(new Rectangle((int) things.get(i).x, (int) things.get(i).y, things.get(i).width, things.get(i).height))){
     y -= (y + height) - things.get(i).y;
     velo = 0;
    }
   }
  }

 }

 class Thing{
  float x = 50;
  float y = 50;
  int height = 50;
  int width = 30;
  int type = -1;
  float speed = 0.5f;

  public Thing(float x, float y, int width, int height, int type){
   this.x = x;
   this.y = y;
   this.width = width;
   this.height = height;
   this.type = type;
  }

  public void moveUp(Player player){
   y -= 0.5f;

   if(new Rectangle((int) x,(int) y, width, height).intersects(new Rectangle((int) player.x, (int) player.y, player.width, player.height))){
    player.y -= (player.y + player.height) - y;
    player.velo = 0;
   }
  }

  public void moveRight(Player player, Vector<Thing> things){
   x += speed;

   if(new Rectangle((int) x,(int) y - 1, width, height).intersects(new Rectangle((int) player.x, (int) player.y, player.width, player.height))){
    player.moveRightWithThing(things, speed);
   }
  }
 }

}

А вот демоверсия: http://prime.programming -designs.com / java / platformer_demo / platdemo.jnlp

1 Ответ

7 голосов
/ 24 ноября 2010

Причина, по которой вы не можете найти ошибку, заключается в том, что код ужасен.

  • Огромные количества дублирования кода: moveLeft, moveRight, moveUp и moveDown очень похожи.
  • Логика ускорения под действием силы тяжести появляется в двух местах.
  • Повсюду повторяется логика столкновений.
  • Отчаянно неудачный выбор имен. velo для скорости вниз, но delta для скорости вправо (неправильно обозначается как «импульс»): почему бы не vy и vx? Также maxSpeed для максимальной горизонтальной скорости, но maxFallSpeed для максимальной вертикальной скорости.
  • Ускорение / замедление называется speed.
  • Расточительное распределение, например звоните new Rectangle каждый раз, когда вы хотите проверить, не попало ли что-то еще.
  • Позиции с плавающей точкой, но столкновение основано на целых числах.

Дублирование кода приводит к появлению ошибок, потому что когда дублируется функциональность, есть возможность ошибиться в одном из мест, а также скрывать ошибки, потому что объем кода затрудняет их обнаружение.

В любом случае, подпрыгивание на платформах может быть связано с тем, что в Player:moveDown вы используете прямоугольник, который смещен на половину высоты игрока, тогда как в Thing:moveRight вы сталкиваетесь с прямоугольником, который не смещен. (Но это только предположение.)

...