我做了一个蛇游戏,当蛇和食物发生碰撞时,应该在分数上加1。相反,一旦蛇吃了食物,它会增加多个点。苹果附有多个固定装置(这可能是检测到多个碰撞的原因)。我有什么方法可以确保得分只上升一分吗?一些想法会有所帮助。
我尝试使用布尔值来确保在重新定位食物之前没有注册碰撞但是没有解决问题。
代码:(一些不相关的代码被遗漏了,所以我不会压倒人,例如我有一个vector2列表,用于对象的多边形形状的顶点。顶点创建多个灯具。)
Apple.java:
public class Apple {
private Sprite img;
private float width, x, y;
private Body body;
private Vector2[][] vertices;
public boolean isRelocating;
private Vector2 previousPosition;
//constructor
public Apple(float x, float y, float width, World world) {
this.x = x;
this.y = y;
this.width = width;
isRelocating = false;
//intialize previous number to a mechncially imposible number
previousPosition = new Vector2(-100, -100);
img = new Sprite(new Texture(Gdx.files.internal("Emoji/Red Apple.png")));
img.setSize(width, width * 0.9416f);
img.setPosition(x, y);
//set up the physics body
BodyDef def = new BodyDef();
def.type = BodyDef.BodyType.DynamicBody; //keep it dynamic so collisions can be collected
def.position.set(x, y);
body = world.createBody(def);
loadVertices();
//scale vertices accroding to the width
for (int i = 0; i < vertices.length; i++) {
for (int j = 0; j < vertices[i].length; j++) {
vertices[i][j].scl(width);
}
}
//attach multiple fixtures to the body
FixtureDef fixtureDef = new FixtureDef();
PolygonShape shape = new PolygonShape();
fixtureDef.isSensor = true;
shape.set(vertices[0]);
}
public void update(float dt) {
img.setPosition(x, y);
body.setTransform(x, y, body.getAngle());
}
public void draw(SpriteBatch batch) {
batch.begin();
img.setAlpha(0.1f);
img.draw(batch);
batch.end();
}
public void changePosition(float newX, float newY) {
x = newX;
y = newY;
body.setTransform(x,y,body.getAngle());
isRelocating = false;
}
public float getWidth(){
return img.getWidth();
}
public float getHeight(){
return img.getHeight();
}
public Vector2 getPosition(){
return new Vector2(x,y);
}
public Vector2 getPreviousPosition(){
return previousPosition;
}
public void setPreviousPosition(Vector2 value){
previousPosition = value;
}
}
Snake.java:
public class Snake {
private ArrayList<Segment> snake;
private float speed;
private World worldRef;
private float width;
public Snake(float x, float y, float width, float speed, World world) {
snake = new ArrayList<Segment>();
this.speed = speed;
worldRef = world;
//add the head
snake.add(new Segment(width, x, y, true, Segment.Direction.UP, speed, world));
}
public void draw(SpriteBatch batch){
for (int i = 0; i < snake.size(); i ++ ){
snake.get(i).draw(batch);
}
}
public void update(float dt){
for (int i = 0; i < snake.size(); i ++){
snake.get(i).update(dt);
}
}
public void changeDirection(Segment.Direction direction){
//change the direction of the head, and the rest will follow
snake.get(0).setDirection(direction);
}
public Rectangle[] getTakeArea(){
Rectangle[] rects = new Rectangle[snake.size()];
for (int i = 0; i < rects.length; i ++){
rects[i] = snake.get(i).getArea();
}
return rects;
}
public float getWidth(){
return width;
}
}
Segment.java:
public class Segment {
//direction enum
public enum Direction {
UP,
DOWN,
LEFT,
RIGHT;
}
private Sprite img;
private float width, x, y;
private Body body;
private float speed;
private Direction direction;
private boolean isHead;
private Vector2[] vertices1;
private Vector2[] vertices2;
private Vector2[] vertices3;
private Vector2[] vertices4;
//constructor
public Segment(float width, float x, float y, boolean isHead, Direction
direction, float speed, World world) {
this.width = width;
this.x = x;
this.y = y;
this.direction = direction;
this.speed = speed;
this.isHead = isHead;
if (isHead)
img = new Sprite(new Texture(Gdx.files.internal("Emoji/Tears of Joy.png")));
else
img = new Sprite(new Texture(Gdx.files.internal("Emoji/Smiling Face with Mouth Open" +
".png")));
img.setSize(width, width);
img.setPosition(x, y);
//load up the physcis
BodyDef bodyDef = new BodyDef();
bodyDef.position.set(x, y);
bodyDef.type = BodyDef.BodyType.DynamicBody;
body = world.createBody(bodyDef);
//load up fixtures
loadVertices();
for (int i = 0; i < vertices1.length; i++) {
vertices1[i].scl(width);
vertices2[i].scl(width);
vertices3[i].scl(width);
vertices4[i].scl(width);
}
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.friction = 0;
fixtureDef.restitution = 1;
PolygonShape shape1 = new PolygonShape();
shape1.set(vertices1);
fixtureDef.shape = shape1;
body.createFixture(fixtureDef);
shape1.dispose();
//add userData to all the fixtures
for (int i = 0; i < body.getFixtureList().size; i++) {
body.getFixtureList().get(i).setUserData(new UserData("segment"));
}
}
public void update(float dt) {
//update the position based on the speed
switch (direction) {
case UP:
body.setLinearVelocity(0, speed);
break;
case DOWN:
body.setLinearVelocity(0, -speed);
break;
case RIGHT:
body.setLinearVelocity(speed, 0);
break;
case LEFT:
body.setLinearVelocity(-speed, 0);
break;
}
//make sure that the segment stays in side the camara
if (x > (Launcher.WIDTH/SnakeMain.PPM))
body.setTransform(x - (Launcher.WIDTH/SnakeMain.PPM) - width,y, body.getAngle());
x = body.getPosition().x;
y = body.getPosition().y;
//have to adjust the sprite if it is head
if (isHead) {
img.setPosition(x - (width * 0.03f), y - (width * 0.024f));
} else {
img.setPosition(x, y);
}
img.setRotation((float) Math.toDegrees(body.getAngle()));
}
public void draw(SpriteBatch batch) {
batch.begin();
img.setAlpha(0.1f);
img.draw(batch);
batch.end();
}
public Direction getDirection() {
return direction;
}
public Rectangle getArea(){
return new Rectangle(x,y,width,width);
}
public void setDirection(Direction newDirection) {
direction = newDirection;
}
}
SnakeMain.java:
public class SnakeMain implements Screen {
private Launcher mainRef;
private OrthographicCamera camera;
private FitViewport viewport;
private World world;
private Box2DDebugRenderer debugRenderer;
public static final float PPM = 100;
private Snake snake;
private Apple apple;
private Stage HUD;
private Table hubTable;
private Label lblScore;
private int score = 0;
//constructor
public SnakeMain(Launcher main) {
mainRef = main;
camera = new OrthographicCamera();
viewport = new FitViewport(Launcher.WIDTH / PPM, Launcher.HEIGHT / PPM, camera);
viewport.apply();
world = new World(new Vector2(0, 0), true);
debugRenderer = new Box2DDebugRenderer();
snake = new Snake((Launcher.WIDTH / 2) / PPM, (Launcher.HEIGHT / 2) / PPM, 200 / PPM, 400
/ PPM, world);
apple = new Apple((Launcher.WIDTH / 2) / PPM, (Launcher.HEIGHT / 2 - 300) / PPM, 200 / PPM,
world);
world.setContactListener(new CollisionDetector(this));
Gdx.input.setInputProcessor(new GestureDetector(new TouchListener(snake)));
HUD = new Stage();
HUD.setViewport(new FitViewport(Launcher.WIDTH /3, Launcher.HEIGHT/3, new OrthographicCamera
()));
hubTable = new Table();
String strScore = "Score: " + score;
lblScore = new Label(strScore, mainRef.getSkin(), "small38");
hubTable.add(lblScore);
hubTable.top();
hubTable.padTop(10);
hubTable.setFillParent(true);
HUD.addActor(hubTable);
}
@Override
public void show() {
}
public void update(float delta) {
world.step(1 / 30f, 6, 2);
snake.update(delta);
apple.update(delta);
lblScore.act(delta);
HUD.act();
}
@Override
public void render(float delta) {
update(delta);
debugRenderer.render(world, camera.combined);
mainRef.batch.setProjectionMatrix(camera.combined);
snake.draw(mainRef.batch);
apple.draw(mainRef.batch);
HUD.draw();
}
public Apple getApple(){
return apple;
}
//handles things when the snake eats the food
public void foodEaten() {
score ++;
String strScore = "Score: " + score;
lblScore.setText(strScore);
//relocate the food to a new location
boolean isValid = false;
float newX = -1;
float newY = -1;
Rectangle rect = new Rectangle();
while (!isValid) {
newX = (float) Math.random() * (Launcher.WIDTH - apple.getWidth() * PPM);
newY = (float) Math.random() * (Launcher.HEIGHT - apple.getHeight() * PPM);
rect.set(newX, newY, apple.getWidth(), apple.getHeight());
isValid = true;
//check to make sure that the apple will not be in the same position as the snake
for (int i = 0; i < snake.getTakeArea().length; i++) {
if (rect.overlaps(snake.getTakeArea()[i])) {
isValid = false;
}
}
}
apple.changePosition(newX/PPM, newY/PPM);
Gdx.app.log("SnakeMain.java", "Done relocating the apple");
}
@Override
public void resize(int width, int height) {
viewport.update(width, height, true);
HUD.getViewport().update(width,height,true);
}
@Override
public void pause() {
}
@Override
public void resume() {
}
@Override
public void hide() {
}
@Override
public void dispose() {
}
}
CollisionDetector.java:
public class CollisionDetector implements ContactListener {
private SnakeMain mainRef;
//constructor
public CollisionDetector(SnakeMain main) {
mainRef = main;
}
@Override
public void beginContact(Contact contact) {
try {
UserData userData1 = (UserData) contact.getFixtureA().getUserData();
UserData userData2 = (UserData) contact.getFixtureB().getUserData();
//if there is a collision between an apple and a segment
if ((userData1.getId() == "apple" && userData2.getId() == "segment")
|| (userData1.getId() == "segment" && userData2.getId() == "apple")) {
if (!mainRef.getApple().isRelocating) {
Gdx.app.log("Apple eaten", "About to reset Apple");
Gdx.app.log("Apple eaten", "State of apple: " + mainRef.getApple()
.isRelocating);
mainRef.getApple().isRelocating = true;
mainRef.foodEaten();
}
}
} catch (Exception e) {
Gdx.app.log("Error!", e.getMessage());
}
}
@Override
public void postSolve(Contact contact, ContactImpulse impulse) {
}
@Override
public void endContact(Contact contact) {
}
@Override
public void preSolve(Contact contact, Manifold oldManifold) {
}
}
答案 0 :(得分:0)
考虑在Apple吃掉苹果后立即添加一个hasBeenEaten布尔值。然后,当检测到碰撞时(可能是再次),在调用foodEaten()函数之前检查hasBeenEaten的状态。
public void beginContact(Contact contact) {
try {
UserData userData1 = (UserData) contact.getFixtureA().getUserData();
UserData userData2 = (UserData) contact.getFixtureB().getUserData();
//if there is a collision between an apple and a segment
if ((userData1.getId() == "apple" && userData2.getId() == "segment")
|| (userData1.getId() == "segment" && userData2.getId() == "apple")) {
if (!mainRef.getApple().hasBeenEaten) {
mainRef.getApple().isRelocating = true;
mainRef.getApple().hasBeenEaten = true;
mainRef.foodEaten();
}
}
} catch (Exception e) {
Gdx.app.log("Error!", e.getMessage());
}
}