Skip to content

Player interaction Sprint3

Sirius7777 edited this page Oct 5, 2021 · 38 revisions

Animation controller

Use if else to switch one animation to another. Check the running is on or not. In case one animation is stopped before another start.

  • Animator5 is default animation - running.
  • animator1-6 is Attack, touch, buff, debuff and collecting coins.
  • This method runs every frame. So the first part to make sure the player is keep running.
  • The second part of the if statment to test if other animation is working or not. If attack starts,then running should stop until attack finished.
  • When other animation finished, restart the running animation.
public void update() {
    if(animator5.getCurrentAnimation() == null) {
       animator5.startAnimation("run");
    }
    if(animator.getCurrentAnimation() != null || animator2.getCurrentAnimation() != null|| animator3.getCurrentAnimation() != null || animator4.getCurrentAnimation() != null || animator6.getCurrentAnimation() != null){
      animator5.stopAnimation();
    }
    if (animator2.isFinished() || animator3.isFinished() || animator4.isFinished() || animator6.isFinished()){
      animator2.stopAnimation();
      animator3.stopAnimation();
      animator4.stopAnimation();
      animator6.stopAnimation();
      animator5.startAnimation("run");
    }
    if (moving) {
      updateSpeed();
    }
  }

Death animation

When player git hurt, test the player's health to find out show the death animation or not.

(Due to the bug given by team1, the death animation wont show correctly in the game. But the animation itself is working correctly by using other way to trigger.

if(attacker.getHealth() == 0){
        AnimationRenderComponent7 animator7 =
                attacker.getEntity().getComponent(AnimationRenderComponent7.class);
        animator7.startAnimation("death");
}

Coin collection animation

When player collect a coin, will show the animations and sound effect

The corresponding animation effect is triggered by determining the type of collision object

  • hit buff will trigger the positive effect
  • hit debuff will trigger the negative effect
  • hit coins will shows the player collecting a coin
  • Else show the hurt from enemy

Entity target = ((BodyUserData) other.getBody().getUserData()).entity;
    CombatStatsComponent targetStats = target.getComponent(CombatStatsComponent.class);
    if (targetStats != null) {
      if(targetStats.getEntity().getType() == Entity.Type.BUFF){
        targetStats.hitBuff(combatStats);
      }
      else if(targetStats.getEntity().getType() == Entity.Type.DEBUFF){
        targetStats.hitDeBuff(combatStats);
      }
      else if(targetStats.getEntity().getType() == Entity.Type.COLLECTABLES){
        targetStats.hitCoins(combatStats);
      }
      else{
        targetStats.hit(combatStats);
      }
    }

 public void hitCoins(CombatStatsComponent attacker) {
    try {
      if (ServiceLocator.getTimeSource().getTimeSince(invincibleStart) < 1000L) {
        return;
      }
      if (attacker.getEntity().getType() == Entity.Type.PLAYER) {
        logger.error("attacker--{}", attacker.getEntity().getType(),attacker.getEntity());
        AnimationRenderComponent6 animator =
                attacker.getEntity().getComponent(AnimationRenderComponent6.class);
        animator.startAnimation("coin");
        Sound coinSound = ServiceLocator.getResourceService().getAsset(
                "sounds/coin.ogg", Sound.class);
        coinSound.play();
        logger.error("--end--attacker--{}",attacker.getEntity().getType());
      }
    } catch (NullPointerException e) {
      int newHealth = getHealth() - attacker.getBaseAttack();
      setHealth(newHealth);
    }
}

Class diagram

The diagram shows the structure of player interaction related classes. It also shows how the playerFactory interact with different components including PlayerActions, CombatStatsComponent, TouchAttackComponent in the game. .

Sequence diagram for attack animation

.

Sequence diagram for touch animation

.

Sequence diagram for buff animation

.

Sequence diagram for debuff animation

.

Unit Testing

Unit test of class "PlayerActions"

Test whether the judgment of attack distance is valid, and whether the enemy will be disposed.

package com.deco2800.game.components.player;

import com.badlogic.gdx.utils.Array;
import com.deco2800.game.entities.Entity;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

public class PlayerActionsTest {
    private PlayerActions playerActions;

    private static Entity entity = new Entity();
    private Entity entity1 = new Entity(Entity.Type.GHOST);
    private Entity entity2 = new Entity(Entity.Type.GHOSTKING);
    private Entity entity3 = new Entity(Entity.Type.OBSTACLE);
    private Entity entity4 = new Entity(Entity.Type.BUFF);

    private Array<Entity> entities1 = new Array<>(1);
    private Array<Entity> entities2 = new Array<>(1);
    private Array<Entity> entities3 = new Array<>(1);
    private Array<Entity> entities4 = new Array<>(1);

    @Test
    public void findNearestTargetsTest1() {
        float minDstEnemy = 1.8f;
        float dst = 0;
        Entity entityFind = new Entity();
        entity.setPosition(0, 0);
        entity1.setPosition(1, 0);
        entities1.add(entity1);
        for (Entity en : entities1) {
            dst = entity.getPosition().dst(en.getPosition());
            if (minDstEnemy > dst) {
                entityFind = en;
            }
        }
        assertTrue(minDstEnemy > dst);
        assertEquals("GHOST", entityFind.getType().toString());
    }

    @Test
    public void findNearestTargetsTest2() {
        float minDstEnemy = 1.8f;
        float dst = 0;
        Entity entityFind = new Entity();
        entity.setPosition(0, 0);
        entity1.setPosition(2, 0);
        entities1.add(entity1);
        for (Entity en : entities1) {
            dst = entity.getPosition().dst(en.getPosition());
            if (minDstEnemy > dst) {
                entityFind = en;
            }
        }
        assertFalse(minDstEnemy > dst);
        assertNull(entityFind.getType());
    }

    @Test
    public void findNearestTargetsTest3() {
        float minDstEnemy = 1.8f;
        float dst = 0;
        Entity entityFind = new Entity();
        entity.setPosition(0, 0);
        entity2.setPosition(1, 0);
        entities2.add(entity2);
        for (Entity en : entities2) {
            dst = entity.getPosition().dst(en.getPosition());
            if (minDstEnemy > dst) {
                entityFind = en;
            }
        }
        assertTrue(minDstEnemy > dst);
        assertEquals("GHOSTKING", entityFind.getType().toString());
    }

    @Test
    public void findNearestTargetsTest4() {
        float minDstEnemy = 1.8f;
        float dst = 0;
        Entity entityFind = new Entity();
        entity.setPosition(0, 0);
        entity2.setPosition(8, 0);
        entities2.add(entity2);
        for (Entity en : entities2) {
            dst = entity.getPosition().dst(en.getPosition());
            if (minDstEnemy > dst) {
                entityFind = en;
            }
        }
        assertFalse(minDstEnemy > dst);
        assertNull(entityFind.getType());
    }

    @Test
    public void findNearestTargetsTest5() {
        float minDstObstacle = 1.8f;
        float dst = 0;
        Entity entityFind = new Entity();
        entity.setPosition(0, 0);
        entity3.setPosition(1, 0);
        entities3.add(entity3);
        for (Entity en : entities3) {
            dst = entity.getPosition().dst(en.getPosition());
            if (minDstObstacle > dst) {
                entityFind = en;
            }
        }
        assertTrue(minDstObstacle > dst);
        assertEquals("OBSTACLE", entityFind.getType().toString());
    }

    @Test
    public void findNearestTargetsTest6() {
        float minDstObstacle = 1.8f;
        float dst = 0;
        Entity entityFind = new Entity();
        entity.setPosition(0, 0);
        entity3.setPosition(5, 0);
        entities3.add(entity3);
        for (Entity en : entities3) {
            dst = entity.getPosition().dst(en.getPosition());
            if (minDstObstacle > dst) {
                entityFind = en;
            }
        }
        assertFalse(minDstObstacle > dst);
        assertNull(entityFind.getType());
    }

    @Test
    public void findNearestTargetsTest7() {
        float minDstObstacle = 1.8f;
        float dst = 0;
        Entity entityFind = new Entity();
        entity.setPosition(0, 0);
        entity4.setPosition(1, 0);
        entities4.add(entity4);
        for (Entity en : entities4) {
            dst = entity.getPosition().dst(en.getPosition());
            if (minDstObstacle > dst) {
                entityFind = en;
            }
        }
        assertTrue(minDstObstacle > dst);
        assertEquals("BUFF", entityFind.getType().toString());
    }

    @Test
    public void findNearestTargetsTest8() {
        float minDstObstacle = 1.8f;
        float dst = 0;
        Entity entityFind = new Entity();
        entity.setPosition(0, 0);
        entity4.setPosition(4, 0);
        entities4.add(entity4);
        for (Entity en : entities4) {
            dst = entity.getPosition().dst(en.getPosition());
            if (minDstObstacle > dst) {
                entityFind = en;
            }
        }
        assertFalse(minDstObstacle > dst);
        assertNull(entityFind.getType());
    }
}

Change to Plan

Our original plan was to merge all animation Atlas into one, which is easier to control different animations that we want to use on the player. But due to some technical problem (the software does not support more than 20 pictures in one atlas, while we have more than 40 pictures), we have to change the plan to find another way to control those animations. After many attempts, we successfully use judgment sentences to perfectly control the switching of different animation (Refer to Animation controller part in Wiki). So, the plan was changed to use animationStart and animationStop to control all player interactions.

In addition, all the animations are able to work correctly, but because of the bugs generated by team 1, when the player touches some obstacles, the game will quit automatically. Therefore, some of our animations like touch and death cannot be shown in the game because the auto quit will happen before the animation is being played. We are planning to help team1 fix this bug in the next sprint.

Table of Contents

Home

Game Design

Player Health System, Scoring System & Game Over
  • Enemies

Enemies
Enemies testing and testing plan
Player Interaction Sprint1 & Sprint2
Player Interaction Sprint3
Player Interaction Sprint4
Map contents Sprint1-3
Map contents Sprint4

Game Features

Game Engine

Getting Started

Entities and Components

Service Locator

Loading Resources

Logging

Unit Testing

Debug Terminal

Input Handling

UI

Animations

Audio

AI

Physics

Game Screens and Areas

Terrain

Concurrency & Threading

Settings

Troubleshooting

MacOS Setup Guide

Clone this wiki locally