Whenever I upload a sprite atlas for animation purposes into a scene in overlaps2d version 0.1.2-snapshot. My app crashes with the following line (slightly redacted):
java.lang.NoSuchMethodError: No virtual method getKeyFrame(F)Lcom/badlogic/gdx/graphics/g2d/TextureRegion; in class Lcom/badlogic/gdx/graphics/g2d/Animation; or its super classes (declaration of 'com.badlogic.gdx.graphics.g2d.Animation' appears in /data/data/xxx.xxx.xxx/files/instant-run/dex/slice-gdx-1.9.5_xxx-classes.dex)
And it points to this line in my code:
sceneLoader.getEngine().update(Gdx.graphics.getDeltaTime());
Could this be a issue with a version mismatch as overlap2d hasn't been updated in over a year, but libgdx was just updated about a month ago? The crash only happens with an animated image, otherwise app runs fine. I looked at the libgdx file the error refers to and this is what it looks like:
package com.badlogic.gdx.graphics.g2d;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.utils.Array;
public class Animation<T> {
/** Defines possible playback modes for an {#link Animation}. */
public enum PlayMode {
NORMAL,
REVERSED,
LOOP,
LOOP_REVERSED,
LOOP_PINGPONG,
LOOP_RANDOM,
}
/** Length must not be modified without updating {#link #animationDuration}. See {#link #setKeyFrames(T[])}. */
T[] keyFrames;
private float frameDuration;
private float animationDuration;
private int lastFrameNumber;
private float lastStateTime;
private PlayMode playMode = PlayMode.NORMAL;
/** Constructor, storing the frame duration and key frames.
*
* #param frameDuration the time between frames in seconds.
* #param keyFrames the objects representing the frames. */
public Animation (float frameDuration, Array<? extends T> keyFrames) {
this.frameDuration = frameDuration;
T[] frames = (T[]) new Object[keyFrames.size];
for (int i = 0, n = keyFrames.size; i < n; i++) {
frames[i] = keyFrames.get(i);
}
setKeyFrames(frames);
}
/** Constructor, storing the frame duration and key frames.
*
* #param frameDuration the time between frames in seconds.
* #param keyFrames the objects representing the frames. */
public Animation (float frameDuration, Array<? extends T> keyFrames, PlayMode playMode) {
this(frameDuration, keyFrames);
setPlayMode(playMode);
}
/** Constructor, storing the frame duration and key frames.
*
* #param frameDuration the time between frames in seconds.
* #param keyFrames the objects representing the frames. */
public Animation (float frameDuration, T... keyFrames) {
this.frameDuration = frameDuration;
setKeyFrames(keyFrames);
}
/** Returns a frame based on the so called state time. This is the amount of seconds an object has spent in the
* state this Animation instance represents, e.g. running, jumping and so on. The mode specifies whether the animation is
* looping or not.
*
* #param stateTime the time spent in the state represented by this animation.
* #param looping whether the animation is looping or not.
* #return the frame of animation for the given state time. */
public T getKeyFrame (float stateTime, boolean looping) {
// we set the play mode by overriding the previous mode based on looping
// parameter value
PlayMode oldPlayMode = playMode;
if (looping && (playMode == PlayMode.NORMAL || playMode == PlayMode.REVERSED)) {
if (playMode == PlayMode.NORMAL)
playMode = PlayMode.LOOP;
else
playMode = PlayMode.LOOP_REVERSED;
} else if (!looping && !(playMode == PlayMode.NORMAL || playMode == PlayMode.REVERSED)) {
if (playMode == PlayMode.LOOP_REVERSED)
playMode = PlayMode.REVERSED;
else
playMode = PlayMode.LOOP;
}
T frame = getKeyFrame(stateTime);
playMode = oldPlayMode;
return frame;
}
/** Returns a frame based on the so called state time. This is the amount of seconds an object has spent in the
* state this Animation instance represents, e.g. running, jumping and so on using the mode specified by
* {#link #setPlayMode(PlayMode)} method.
*
* #param stateTime
* #return the frame of animation for the given state time. */
public T getKeyFrame (float stateTime) {
int frameNumber = getKeyFrameIndex(stateTime);
return keyFrames[frameNumber];
}
/** Returns the current frame number.
* #param stateTime
* #return current frame number */
public int getKeyFrameIndex (float stateTime) {
if (keyFrames.length == 1) return 0;
int frameNumber = (int)(stateTime / frameDuration);
switch (playMode) {
case NORMAL:
frameNumber = Math.min(keyFrames.length - 1, frameNumber);
break;
case LOOP:
frameNumber = frameNumber % keyFrames.length;
break;
case LOOP_PINGPONG:
frameNumber = frameNumber % ((keyFrames.length * 2) - 2);
if (frameNumber >= keyFrames.length) frameNumber = keyFrames.length - 2 - (frameNumber - keyFrames.length);
break;
case LOOP_RANDOM:
int lastFrameNumber = (int) ((lastStateTime) / frameDuration);
if (lastFrameNumber != frameNumber) {
frameNumber = MathUtils.random(keyFrames.length - 1);
} else {
frameNumber = this.lastFrameNumber;
}
break;
case REVERSED:
frameNumber = Math.max(keyFrames.length - frameNumber - 1, 0);
break;
case LOOP_REVERSED:
frameNumber = frameNumber % keyFrames.length;
frameNumber = keyFrames.length - frameNumber - 1;
break;
}
lastFrameNumber = frameNumber;
lastStateTime = stateTime;
return frameNumber;
}
/** Returns the keyframes[] array where all the frames of the animation are stored.
* #return The keyframes[] field. */
public T[] getKeyFrames () {
return keyFrames;
}
protected void setKeyFrames (T... keyFrames) {
this.keyFrames = keyFrames;
this.animationDuration = keyFrames.length * frameDuration;
}
/** Returns the animation play mode. */
public PlayMode getPlayMode () {
return playMode;
}
/** Sets the animation play mode.
*
* #param playMode The animation {#link PlayMode} to use. */
public void setPlayMode (PlayMode playMode) {
this.playMode = playMode;
}
/** Whether the animation would be finished if played without looping (PlayMode#NORMAL), given the state time.
* #param stateTime
* #return whether the animation is finished. */
public boolean isAnimationFinished (float stateTime) {
int frameNumber = (int)(stateTime / frameDuration);
return keyFrames.length - 1 < frameNumber;
}
/** Sets duration a frame will be displayed.
* #param frameDuration in seconds */
public void setFrameDuration (float frameDuration) {
this.frameDuration = frameDuration;
this.animationDuration = keyFrames.length * frameDuration;
}
/** #return the duration of a frame in seconds */
public float getFrameDuration () {
return frameDuration;
}
/** #return the duration of the entire animation, number of frames times frame duration, in seconds */
public float getAnimationDuration () {
return animationDuration;
}
From what i understand getting the key frame is what retrieves the frame out of the image atlas and changes it based on time to give the illusion of movement.
Use the previous version of libgdx, i.e., 1.9.4. In libgdx version 1.9.5 Animation class having some change, that is not updated with overlap2d snapshot version, so you are facing the problem.
Downgrade version in build.gradle of root project. Hopefully, it may be helpful.
Thanks.
Related
I am stuck on my Flood It game. I am trying to solve the problem of getting a starting matrix and finding the same color connected to the point (0,0). For instance if my starting matrix is generated:
1 4 5
1 1 1
5 3 2
It should capture the 1's so that on the next turn lets say I choose 4 then the matrix should be:
4 4 5
4 4 4
5 3 2
However when I choose 4 now the matrix is:
4 4 5
1 1 1
5 3 2
I know this is part of any normal Flood It game but I'm stuck on implementing it.
'
import java.awt.event.*;
import javax.swing.*;
public class GameController implements ActionListener {
private GameModel model;
private GameView view;
private MyStack<DotInfo> dots;
private int size;
private DotInfo dot;
/**
* Constructor used for initializing the controller. It creates the game's view
* and the game's model instances
*
* #param size
* the size of the board on which the game will be played
*/
public GameController(int size) {
this.size = size;
model = new GameModel(size);
view = new GameView(model, this);
dots = new MyStack<DotInfo>(size*size);
/*view.reset.addActionListener(this);
view.quit.addActionListener(this);
view.grey.addActionListener(this);
view.yellow.addActionListener(this);
view.blue.addActionListener(this);
view.green.addActionListener(this);
view.violet.addActionListener(this);
view.red.addActionListener(this);*/
}
/**
* resets the game
*/
public void reset(){
model.reset();
System.out.println(model);
}
/**
* Callback used when the user clicks a button (reset or quit)
*
* #param e
* the ActionEvent
*/
public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof JButton) {
JButton x = (JButton) e.getSource();
if (x.getText()=="Quit") { //Quit button
System.exit(0);
}
else if (x.getText()=="Reset") { //Reset button
reset();
view.update();
}
}
}
/**
* <b>selectColor</b> is the method called when the user selects a new color.
* If that color is not the currently selected one, then it applies the logic
* of the game to capture possible locations. It then checks if the game
* is finished, and if so, congratulates the player, showing the number of
* moves, and gives two options: start a new game, or exit
* #param color
* the newly selected color
*/
public void selectColor(int color){
model.setCurrentSelectedColor(color);
sendCapturedToStack();
equalityCheck(color);
System.out.println(model);
}
/**
* On every turn <b>sendCapturedToStack</b> will push every captured dot to the stack.
* It will also allow the colours to change every time a user picks a color.
*/
private void sendCapturedToStack() {
model.capture
for (int j=0;j<size;j++) {
for (int i=0;i<size;i++) {
if (model.isCaptured(i, j)) {
model.capture(i, j);
dots.push(model.get(i,j));
}
}
}
}
/**
* <b>equalityCheck</b> checks to see if there is a dot to the left, right, above, or below
* another dot. If there is then the dot will be captured and pushed to the top of the stack.
* #param newColor
* the newly selected color
*/
private void equalityCheck(int newColor) {
while (!dots.isEmpty()) {
dot = dots.pop();
int x = dot.getX();
int y = dot.getY();
if (y<size-1 && model.getColor(x,y+1)==newColor && !model.isCaptured(x,y+1)) {
model.capture(x, y+1);
dots.push(model.get(x,y+1));
} if (x<size-1 && model.getColor(x+1,y)==newColor && !model.isCaptured(x+1,y)) {
model.capture(x+1, y);
dots.push(model.get(x+1,y));
} if (y>0 && model.getColor(x,y-1)==newColor && !model.isCaptured(x,y-1)) {
model.capture(x, y-1);
dots.push(model.get(x,y-1));
} if (x>0 && model.getColor(x-1,y)==newColor && !model.isCaptured(x-1,y)) {
model.capture(x-1, y);
dots.push(model.get(x-1,y));
}
}
}
}
I have tried implementing a smooth Camera zoom method in libgdx, in which he method zoom interpolates between two vlaues of zoom amount i.e initial * final.
The problem howevever is that the camera snaps fast into position when zoomed or moved. How can I be able to create a smooth camera class and implement zoom without having a jumpy scrren?
private void panZoom(Vector3 spanCord, TweenManager tweenManager, GameWorld world)
{
/*
* Example Tween-Sequence: Zoom to 120%, Pan to point of interest #1 (0, -50), Wait 1 second, Pan back to the
* starting position, Zoom back to the initial value
*/
Timeline.createSequence()
.beginParallel()
.push(Tween.to(this, OrthographicCameraAccessor.POSITION, 3.5f).target(spanCord.x,spanCord.y,spanCord.z).ease(Elastic.OUT))
.push(Tween.to(this, OrthographicCameraAccessor.ZOOM, 3.5f).target(1.20f).ease(Elastic.OUT))
.end()
.beginParallel()
.push(Tween.to(this, OrthographicCameraAccessor.POSITION, 2.8f).target(world.getYoyo().position.x,0,0).ease(Bounce.INOUT))
.push(Tween.to(this, OrthographicCameraAccessor.ZOOM, 3.0f).target(1).ease(Bounce.INOUT))
.end()
.start(tweenManager);
}
public float calcZoom(float initialDistance, float distance)
{
float nextZoom;
if(initialDistance < distance)
{
float ratio = (initialDistance/distance)/10;
nextZoom = zoomIn(ratio);
}
else
{
float ratio = (distance/initialDistance)/10;
nextZoom = zoomOut(ratio);
}
return nextZoom;
}
public class OrthographicCameraAccessor implements TweenAccessor<MyOrthographicCamera> {
/** Tween position */
public static final int POSITION = 1;
/** Tween zoom */
public static final int ZOOM = 2;
/**
* #param camera
* camera to get values from
* #param tweentype
* type of tween (Position or Zoom)
* #param returnValues
* out parameter with the requested values
*/
#Override
public int getValues(MyOrthographicCamera camera, int tweenType, float[] returnValues)
{
switch (tweenType)
{
case POSITION:
returnValues[0] = camera.position.x;
returnValues[1] = camera.position.y;
returnValues[2] = camera.position.z;
return 3;
case ZOOM:
returnValues[0] = camera.zoom;
return 1;
default:
return 0;
}
}
/**
* #param camera
* camera whose some values are going to be set
* #param tweenType
* Position or Zoom
* #param newValues
* array containing the new values to configure the camera
*/
#Override
public void setValues(MyOrthographicCamera camera, int tweenType, float[] newValues)
{
switch (tweenType)
{
case POSITION:
camera.setPosition(newValues[0], 0);
camera.update();
break;
case ZOOM:
camera.setZoom(newValues[0]);
camera.update();
Gdx.app.log("CAMERA", "Clamped Zoom" +camera.zoom);
break;
default:
break;
}
}
The context behind the this question is that I am part of a small group working to create a small game on Android. The game we have chosen to develop is a top-down 2D shooter where the player controls a spaceship that must defend itself from alien creatures that move towards the player from the top of the gamescreen, similar to space invader, but different in that they spawn in random patterns.
So far, we have been able to get the game running, have the player and enemies to spawn and move in the right direction, as well as the player's weapon which is labelled as "projectile" (although it currently just spawns on its own and not on the player command). The issue we have though is that we are trying to set up a collision event in the code between the projectile and the enemies so that when they meet, the enemy and bullet both disappear.
However, what we have currently written in the code does not seem to make this work, so I was wondering if perhaps anyone else could see where we are going wrong. I've listed the relevant classes of code below. We would greatly appreciate any help anyone can give.
Collision Detector class( Holds the behavoir for collision detection for all entities in the game).
package uk.ac.qub.eeecs.gage.util;
import uk.ac.qub.eeecs.gage.world.GameObject;
/**
* Collision Detector Helper Library
*
* #version 1.0
*/
public class CollisionDetector {
/**
* Type of collision
*/
public enum CollisionType {
None, Top, Bottom, Left, Right, destroy //for the platform game, not yours
};
/**
* Determine if the two specified bounding boxes are in collision
*
* #param one
* First bounding box
* #param two
* Second bounding box
* #return boolean true if the boxes overlap, false otherwise
*/
//is relevant to your game
public static boolean isCollision(BoundingBox one, BoundingBox two) {
return (one.x - one.halfWidth < two.x + two.halfWidth
&& one.x + one.halfWidth > two.x - two.halfWidth
&& one.y - one.halfHeight < two.y + two.halfHeight && one.y
+ one.halfHeight > two.y - two.halfHeight);
//Do we add the code to set the enemies to disappear/destroy here or in the
//individual classes such as the player?
}
/**
* Determine the type of collision between the two bounding boxes.
* CollisionType.None is returned if there are no collisions.
*
* #param one
* First bounding box
* #param two
* Second bounding box
* #return Collision type
*/
AISpaceship.java class (class used for emeny alien entities and their properties).
package uk.ac.qub.eeecs.game.spaceDemo;
import uk.ac.qub.eeecs.gage.ai.SteeringBehaviours;
import uk.ac.qub.eeecs.gage.engine.ElapsedTime;
import uk.ac.qub.eeecs.gage.util.CollisionDetector;
import uk.ac.qub.eeecs.gage.util.Vector2;
import uk.ac.qub.eeecs.gage.util.CollisionDetector.CollisionType;
import uk.ac.qub.eeecs.gage.world.GameObject;
import uk.ac.qub.eeecs.gage.world.Sprite;
/**
* AI controlled spaceship
*
* #version 1.0
*/
public class AISpaceship extends Sprite {
// /////////////////////////////////////////////////////////////////////////
// Properties
// /////////////////////////////////////////////////////////////////////////
/**
* AI control behaviour
*/
/**
* Acceleration with which the spaceship can move along
* the x-axis
*/
private float RUN_ACCELERATION = 150.0f;
public enum ShipBehaviour {
Turret, Seeker
}
private boolean visible;
private ShipBehaviour mShipBehaviour;
/**
* Distance at which the spaceship should avoid other game objects
*/
private float separateThresholdShip = 75.0f;
private float separateThresholdAsteroid = 125.0f;
/**
* Accumulators used to build up the net steering outcome
*/
private Vector2 accAccumulator = new Vector2();
private Vector2 accComponent = new Vector2();
// /////////////////////////////////////////////////////////////////////////
// Constructors
// /////////////////////////////////////////////////////////////////////////
/**
* Create a AI controlled spaceship
*
* #param startX
* x location of the AI spaceship
* #param startY
* y location of the AI spaceship
* #param shipBehaviour
* Steering behaviour to be used by the AI ship
* #param gameScreen
* Gamescreen to which AI belongs
*/
public AISpaceship(float startX, float startY, ShipBehaviour shipBehaviour,
SteeringDemoGameScreen gameScreen) {
super(startX, startY, 50.0f, 50.0f, null, gameScreen);
mShipBehaviour = shipBehaviour;
visible = true;
switch (mShipBehaviour) {
case Turret:
maxAcceleration = 0.0f;
maxVelocity = 0.0f;
mBitmap = gameScreen.getGame().getAssetManager().getBitmap("Turret");
break;
case Seeker:
maxAcceleration = -40.0f;
maxVelocity = 50.0f;
mBitmap = gameScreen.getGame().getAssetManager().getBitmap("enemy sprites 7");
break;
}
}
// /////////////////////////////////////////////////////////////////////////
// Methods
// /////////////////////////////////////////////////////////////////////////
/*
* (non-Javadoc)
*
* #see
* uk.ac.qub.eeecs.gage.world.Sprite#update(uk.ac.qub.eeecs.gage.engine.
* ElapsedTime)
*/
#Override
public void update(ElapsedTime elapsedTime) {
switch (mShipBehaviour) {
case Seeker:
//Move down towards the player in a straight line
acceleration.y = RUN_ACCELERATION;
// Seek towards the player
// Try to avoid a collision with the playership
// Try to avoid a collision with the other spaceships
// Try to avoid a collision with the asteroids
SteeringBehaviours.separate(this,
((SteeringDemoGameScreen) mGameScreen).getAsteroids(),
separateThresholdAsteroid, 1.0f, accComponent);
accAccumulator.add(accComponent);
// If we are trying to avoid a collision then combine
// it with the seek behaviour, placing more emphasis on
// avoiding the collision.
if (!accAccumulator.isZero()) {
acceleration.x = 0.3f * acceleration.x + 0.7f
* accAccumulator.x;
acceleration.y = 0.3f * acceleration.y + 0.7f
* accAccumulator.y;
}
// Make sure we point in the direction of travel.
break;
}
// Call the sprite's superclass to apply the determine accelerations
super.update(elapsedTime);
// Check that our new position has not collided by one of the
// defined projectiles. If so, then removing any overlap and
// ensure a valid velocity.
checkForAndResolveCollisions(projectiles);
}
/**
* Check for and then resolve any collision between the AiShip and the
* player projectiles.
*
* #param projectiles
* Array of projectiles to test for collision against
*/
private void checkForAndResolveCollisions(GameObject[] projectiles) {
CollisionType collisionType;
// Consider each platform for a collision
for (GameObject projectile : projectiles) {
collisionType =
CollisionDetector.determineAndResolveCollision(this, Projectile);
switch (collisionType) {
case destroy:
visible = false;
break;
}
}
}
}
Projectile1 (The class used to determine all the game's projectiles and their behavoir).
package uk.ac.qub.eeecs.game.spaceDemo;
import uk.ac.qub.eeecs.gage.ai.SteeringBehaviours;
import uk.ac.qub.eeecs.gage.engine.ElapsedTime;
import uk.ac.qub.eeecs.gage.util.Vector2;
import uk.ac.qub.eeecs.gage.world.Sprite;
/**
* AI controlled spaceship
*
* #version 1.0
*/
public class Projectile1 extends Sprite {
// /////////////////////////////////////////////////////////////////////////
// Properties
// /////////////////////////////////////////////////////////////////////////
/**
* AI control behaviour
*/
/**
* Acceleration with which the projectile can move along
* the x-axis
*/
private float RUN_ACCELERATION = 150.0f;
public enum ShipBehaviour {
bullet
}
private ShipBehaviour mShipBehaviour;
/**
* Distance at which the spaceship should avoid other game objects
*/
/**
* Accumulators used to build up the net steering outcome
*/
private Vector2 accAccumulator = new Vector2();
private Vector2 accComponent = new Vector2();
// /////////////////////////////////////////////////////////////////////////
// Constructors
// /////////////////////////////////////////////////////////////////////////
/**
* Create a AI controlled spaceship
*
* #param startX
* x location of the AI spaceship
* #param startY
* y location of the AI spaceship
* #param shipBehaviour
* Steering behaviour to be used by the AI ship
* #param gameScreen
* Gamescreen to which AI belongs
*/
public Projectile1(float startX, float startY, ShipBehaviour shipBehaviour,
SteeringDemoGameScreen gameScreen) {
super(startX, startY, 50.0f, 50.0f, null, gameScreen);
mShipBehaviour = shipBehaviour;
switch (mShipBehaviour) {
case bullet:
maxAcceleration = 20.0f;
maxVelocity = 30.0f;
mBitmap = gameScreen.getGame().getAssetManager().getBitmap("Spaceship2");
break;
}
}
// /////////////////////////////////////////////////////////////////////////
// Methods
// /////////////////////////////////////////////////////////////////////////
/*
* (non-Javadoc)
*
* #see
* uk.ac.qub.eeecs.gage.world.Sprite#update(uk.ac.qub.eeecs.gage.engine.
* ElapsedTime)
*/
#Override
public void update(ElapsedTime elapsedTime) {
switch (mShipBehaviour) {
case bullet:
// Seek towards the player
acceleration.y = RUN_ACCELERATION;
break;
}
// Call the sprite's superclass to apply the determine accelerations
super.update(elapsedTime);
}
}
SterringGameDemo (The main class for the level on which the game play occurs and where the player, enemies and projectiles behave and interact with each other (note-it is called "SteeringGameDemo" because this is a leftover from a template we used to help make the class and has not been renamed yet)).
package uk.ac.qub.eeecs.game.spaceDemo;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import uk.ac.qub.eeecs.gage.Game;
import uk.ac.qub.eeecs.gage.engine.AssetStore;
import uk.ac.qub.eeecs.gage.engine.ElapsedTime;
import uk.ac.qub.eeecs.gage.engine.graphics.IGraphics2D;
import uk.ac.qub.eeecs.gage.util.BoundingBox;
import uk.ac.qub.eeecs.gage.util.CollisionDetector;
import uk.ac.qub.eeecs.gage.world.GameObject;
import uk.ac.qub.eeecs.gage.world.GameScreen;
import uk.ac.qub.eeecs.gage.world.LayerViewport;
import uk.ac.qub.eeecs.gage.world.ScreenViewport;
import android.graphics.Color;
/**
* Simple steering game world
*
* #version 1.0
*/
public class SteeringDemoGameScreen extends GameScreen {
// /////////////////////////////////////////////////////////////////////////
// Properties
// /////////////////////////////////////////////////////////////////////////
/**
* Width and height of the level
*/
private final float LEVEL_WIDTH = 480.0f;
private final float LEVEL_HEIGHT = 280.0f;
/**
* Define viewports for this layer and the associated screen projection
*/
private ScreenViewport mScreenViewport;
private LayerViewport mLayerViewport;
/**
* Define a background object, alongside a player controlled
* space ship and separate lists of asteroids and AI controlled
* space ships.
*/
private GameObject mSpaceBackground;
private PlayerSpaceship mPlayerSpaceship;
private final int NUM_ASTEROIDS = 0;
private List<Asteroid> mAsteroids;
private final int NUM_SEEKERS = 2;
private final int NUM_TURRETS = 1;
private final int NUM_PROJECTILE = 1;
private List<Projectile1> mProjectile1;
private List<AISpaceship> mAISpaceships;
// /////////////////////////////////////////////////////////////////////////
// Constructors
// /////////////////////////////////////////////////////////////////////////
/**
* Create a simple steering game world
*
* #param game
* Game to which this screen belongs
*/
public SteeringDemoGameScreen(Game game) {
super("SteeringDemoGameScreen", game);
// Create the screen viewport
mScreenViewport = new ScreenViewport(0, 0, game.getScreenWidth(),
game.getScreenHeight());
// Create the layer viewport, taking into account the orientation
// and aspect ratio of the screen.
if (mScreenViewport.width > mScreenViewport.height)
mLayerViewport = new LayerViewport(240.0f, 240.0f
* mScreenViewport.height / mScreenViewport.width, 240,
240.0f * mScreenViewport.height / mScreenViewport.width);
else
mLayerViewport = new LayerViewport(240.0f * mScreenViewport.height
/ mScreenViewport.width, 240.0f, 240.0f
* mScreenViewport.height / mScreenViewport.width, 240);
// Load in the assets used by the steering demo
AssetStore assetManager = mGame.getAssetManager();
assetManager.loadAndAddBitmap("Space BG 2", "img/Space BG 2.png");
assetManager.loadAndAddBitmap("Asteroid1", "img/Asteroid1.png");
assetManager.loadAndAddBitmap("Asteroid2", "img/Asteroid2.png");
assetManager.loadAndAddBitmap("enemy sprites 7", "img/enemy sprites 7.png");
assetManager.loadAndAddBitmap("Spaceship2", "img/Spaceship2.png");
assetManager.loadAndAddBitmap("Spaceship3", "img/Spaceship3.png");
assetManager.loadAndAddBitmap("Spaceship3", "img/Spaceship3.png");
assetManager.loadAndAddBitmap("Player sprite", "img/Player sprite.png");
assetManager.loadAndAddBitmap("Turret", "img/Turret.png");
// Create the space background
mSpaceBackground = new GameObject(LEVEL_WIDTH / 2.0f,
LEVEL_HEIGHT / 2.0f, LEVEL_WIDTH, LEVEL_HEIGHT, getGame()
.getAssetManager().getBitmap("Space BG 2"), this);
// Create the player spaceship
mPlayerSpaceship = new PlayerSpaceship(230, 10, this);
// Create a number of randomly positioned asteroids
Random random = new Random();
mAsteroids = new ArrayList<Asteroid>(NUM_ASTEROIDS);
for (int idx = 0; idx < NUM_ASTEROIDS; idx++)
mAsteroids.add(new Asteroid(random.nextFloat() * LEVEL_WIDTH, random.nextFloat() * LEVEL_HEIGHT, this));
// Create a number of randomly positioned AI controlled ships
mAISpaceships = new ArrayList<AISpaceship>(NUM_SEEKERS + NUM_TURRETS);
for (int idx = 0; idx < NUM_SEEKERS; idx++)
mAISpaceships.add(new AISpaceship(random.nextFloat() * LEVEL_WIDTH,
180 + random.nextFloat() * LEVEL_HEIGHT,
AISpaceship.ShipBehaviour.Seeker, this));
for (int idx = 0; idx < NUM_TURRETS; idx++)
mAISpaceships.add(new AISpaceship(random.nextFloat() * LEVEL_WIDTH,
random.nextFloat() * LEVEL_HEIGHT,
AISpaceship.ShipBehaviour.Turret, this));
//Use the above to help spawn the bullets
mProjectile1 = new ArrayList<Projectile1>(NUM_PROJECTILE);
for (int idx = 0; idx < NUM_PROJECTILE; idx++)
mProjectile1.add(new Projectile1(mPlayerSpaceship.position.x, mPlayerSpaceship.position.y,
Projectile1.ShipBehaviour.bullet, this));
}
// /////////////////////////////////////////////////////////////////////////
// Support methods
// /////////////////////////////////////////////////////////////////////////
/**
* Return the player spaceship
*
* #return Player spaceship
*/
public PlayerSpaceship getPlayerSpaceship() {
return mPlayerSpaceship;
}
public List<Projectile1> getProjectile1() {
return mProjectile1;
}
/**
* Return a list of the AI spaceships in the level
*
* #return List of AI controlled spaceships
*/
public List<AISpaceship> getAISpaceships() {
return mAISpaceships;
}
/**
* Return a list of asteroids in the the level
*
* #return List of asteroids in the level
*/
public List<Asteroid> getAsteroids() {
return mAsteroids;
}
// /////////////////////////////////////////////////////////////////////////
// Update and Draw methods
// /////////////////////////////////////////////////////////////////////////
/*
* (non-Javadoc) fs
*
* #see
* uk.ac.qub.eeecs.gage.world.GameScreen#update(uk.ac.qub.eeecs.gage.engine
* .ElapsedTime)
*/
#Override
public void update(ElapsedTime elapsedTime) {
// Update the player spaceship
mPlayerSpaceship.update(elapsedTime);
// Ensure the player cannot leave the confines of the world
BoundingBox playerBound = mPlayerSpaceship.getBound();
if (playerBound.getLeft() < 0)
mPlayerSpaceship.position.x -= playerBound.getLeft();
else if (playerBound.getRight() > LEVEL_WIDTH)
mPlayerSpaceship.position.x -= (playerBound.getRight() - LEVEL_WIDTH);
if (playerBound.getBottom() < 0)
mPlayerSpaceship.position.y -= playerBound.getBottom();
else if (playerBound.getTop() > LEVEL_HEIGHT)
mPlayerSpaceship.position.y -= (playerBound.getTop() - LEVEL_HEIGHT);
// Ensure the enemyships cannot leave the confines of the world
//Use the above for player and enemies bullets in this class
//IMPORTANT - THE below code is VITAL for the collision detection and was a
//added by the tutor. It calls the bounding box and collision detector for the
//player and enemy ship. Add this to the above section where the bounding box
// is already called, just below the update method.
BoundingBox playersBound = mPlayerSpaceship.getBound();
for (AISpaceship aiSpaceship : mAISpaceships) {
BoundingBox aiBound = aiSpaceship.getBound();
if(CollisionDetector.isCollision(playersBound, aiBound)) {
}
}
// Focus the layer viewport on the player
// Ensure the viewport cannot leave the confines of the world
if (mLayerViewport.getLeft() < 0)
mLayerViewport.x -= mLayerViewport.getLeft();
else if (mLayerViewport.getRight() > LEVEL_WIDTH)
mLayerViewport.x -= (mLayerViewport.getRight() - LEVEL_WIDTH);
if (mLayerViewport.getBottom() < 0)
mLayerViewport.y -= mLayerViewport.getBottom();
else if (mLayerViewport.getTop() > LEVEL_HEIGHT)
mLayerViewport.y -= (mLayerViewport.getTop() - LEVEL_HEIGHT);
// Update each of the AI controlled spaceships
for (AISpaceship aiSpaceship : mAISpaceships)
aiSpaceship.update(elapsedTime);
// Update each of the asteroids
for (Asteroid asteroid : mAsteroids)
asteroid.update(elapsedTime);
// Update each of the Player Projectile1
for (Projectile1 projectile1 : mProjectile1)
projectile1.update(elapsedTime);
}
/*
* (non-Javadoc)
*
* #see
* uk.ac.qub.eeecs.gage.world.GameScreen#draw(uk.ac.qub.eeecs.gage.engine
* .ElapsedTime, uk.ac.qub.eeecs.gage.engine.graphics.IGraphics2D)
*/
#Override
public void draw(ElapsedTime elapsedTime, IGraphics2D graphics2D) {
// Create the screen to black and define a clip based on the viewport
graphics2D.clear(Color.BLACK);
graphics2D.clipRect(mScreenViewport.toRect());
// Draw the background first of all
mSpaceBackground.draw(elapsedTime, graphics2D, mLayerViewport,
mScreenViewport);
// Draw each of the asteroids
for (Asteroid asteroid : mAsteroids)
asteroid.draw(elapsedTime, graphics2D, mLayerViewport,
mScreenViewport);
// Draw each of the AI controlled spaceships
for (Projectile1 projectile1 : mProjectile1)
projectile1.draw(elapsedTime, graphics2D, mLayerViewport,
mScreenViewport);
// Draw each of the AI controlled spaceships
for (AISpaceship aiSpaceship : mAISpaceships)
aiSpaceship.draw(elapsedTime, graphics2D, mLayerViewport,
mScreenViewport);
// Draw the player
mPlayerSpaceship.draw(elapsedTime, graphics2D, mLayerViewport,
mScreenViewport);
}
}
Again, I say thank you to anyone who can help.
I've done something similar before.
Try to create a rectangle for every Bullet, Enemy or whatever you've got. The rectangles should have a size thats about the size of the graphics used. Of course the rectangles have to move with the graphics.
You can check if a collision occured simply with
if(rectangleA.intersects(rectangleB)){
doAwesomeStuff();
}
I hope that helps.
I had been through this link1 link2 for an answer, but was not helpful.
Because
frame.setVisible(false);
is giving below exception,
Exception in thread "main" java.lang.NullPointerException
at Simulation.drawOcean(Simulation.java:72)
at Simulation.main(Simulation.java:191)
Application has below 2 java files.
Simulation class launches GUI.
After running Simulation.java with default command line parameters, Frame does not get close, despite finite while loop.
I could not close the Frame by clicking close button(top right - red), after the simulation is done.
Do i need to set some property for Frame?
Please help me!!!
/* Simulation.java */
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.util.Random;
/* DO NOT CHANGE THIS FILE (except as noted). */
/* (You may wish to make temporary changes or insert println() statements) */
/* while testing your code. When you're finished testing and debugging, */
/* though, make sure your code works with the original version of this file */
/**
* The Simulation class is a program that runs and animates a simulation of
* Sharks and Fish.
*
* The Simulation program takes up to four parameters. The first two specify
* the width and height of the ocean. The third parameter specifies the value
* of starveTIme. For example, if you run
*
* java Simulation 25 25 1
*
* then Simulation will animate a 25x25 ocean with a starveTime of 1. If you
* run "java Simulation" with no parameters, by default Simulation will animate
* a 50x25 ocean with a starveTime of 3. With some choices of parameters,
* the ocean quickly dies out; with others;, it teems forever.
*
* #author mohet01
*
*/
public class Simulation {
/**
* The constant cellSize determines the size of each cell on the screen
* during animation. (You may change this if you wish).
*/
private static final int cellSize = 4;
/**
* Default parameters. (You may change this of you wish).
*/
private static int i = 50; //Default ocean width
private static int j = 25; //Default ocean height
private static int starveTime = 3; //Default shark starvation time
/**
* drawOcean() adds cell contents as part of graphics
*/
private static void drawOcean(Graphics graphics, Ocean ocean){
if(ocean != null){
int width = ocean.width();
int height = ocean.height();
for(int row = 0; row < height; row++){
for(int col = 0; col < width; col++){
int contents = ocean.cellContents(row, col);
if(contents == Ocean.SHARK){
//Draw a red Shark
graphics.setColor(Color.red);
graphics.fillRect(row*cellSize, col*cellSize, cellSize, cellSize);
}else if(contents == Ocean.FISH){
// Draw a green fish
graphics.setColor(Color.green);
graphics.fillRect(row * cellSize, col * cellSize, cellSize, cellSize);
}else{
//Clear the rectangle
graphics.clearRect(row, col, cellSize, cellSize);
}
}
}
}
}
/**
* main() reads the parameters and performs the simulation and animation.
* #param args
* #throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
Ocean sea;
/**
* Read the input parameters
*/
if(args.length >0){
try{
i = Integer.parseInt(args[0]);
}catch(NumberFormatException e){
System.out.println("First argument to Simulation is not a number.");
}
}
if(args.length > 1){
try{
j = Integer.parseInt(args[1]);
}catch(NumberFormatException e){
System.out.println("Second argument to Simulation is not a number");
}
}
if(args.length > 2){
try{
starveTime = Integer.parseInt(args[2]);
}catch(NumberFormatException e){
System.out.println("Third argument to Simulation is not a number");
}
}
/**
* Create a window on your screen
*/
Frame frame = new Frame("Sharks and Fish");
frame.setSize(i*cellSize + 10, j*cellSize + 30);
frame.setVisible(true);
/**
* Create a "Canvas" we can draw upon; attach it to the window
*/
Canvas canvas = new Canvas();
canvas.setBackground(Color.white);
canvas.setSize(i*cellSize, j*cellSize);
frame.add(canvas);
Graphics graphics = canvas.getGraphics();
/**
* Create the initial ocean.
*/
sea = new Ocean(i, j, starveTime);
/**
* Visit each cell (in a roundabout order); randomnly place a fish, shark,
* or nothing in each.
*/
Random random = new Random(0);
int x = 0;
int y = 0;
for(int row = 0;row < j; row++){
//This will visit every x-coordinate once.
x = (x + 78887) %j;
if((x & 8) == 0){
for(int col = 0; col < i; col++){
//This will visit every y coordinate once.
y = (y+78887)%i;
if((y & 8) == 0){
int r = random.nextInt();
if(r < 0){
//50% of cells start with fish
//x - width, y - height
sea.addFish(x, y);
}else if(r > 1500000000){
//~15% of cells start with sharks
sea.addShark(x, y);
}
}
}
}
}
/**
* Perform timesteps forever
*/
int timeLeft = 20;
while (timeLeft > 0) {
// Wait one second (1000 milliseconds)
Thread.sleep(1000);
// Draw the current ocean
drawOcean(graphics, sea);
// For fun, you might wish to change the delay in the next line.
// If you make it too short, though, the graphics won't work properly.
// Simulate a timestep
sea = sea.timeStep();
timeLeft--;
}
}
}
/* Ocean.java */
/**
* The Ocean class defines an object that models an ocean full of sharks and
* fish. Descriptions of the methods you must implements appear below. They
* include a constructor of the form
*
* public Ocean(int i, int j, int starveTime);
*
* that creates an empty ocean having width i and height j, in which sharks
* starve after starveTime timesteps.
*
* See the README file accompanying this project for additional details.
*
* #author mohet01
*
*/
public class Ocean {
/**
* Do not rename these constants. WARNING: if you change the numbers, you
* will need to recompile Test4.java. Failure to do so will give you a very
* hard-to-find bug.
*/
public final static int EMPTY = 1;
public final static int SHARK = 2;
public final static int FISH = 3;
/**
* Define any variables associated with an Ocean object here. These
* variables MUST be private.
*
*/
private final static int UNKNOWN = -1; // for unknown return type
private int width;
private int height;
private int[][] oceanMatrix;
//TODO space optimization on below matrix
private int[][] sharkHungerLevelMatrix;
private int starveTime;
/**
* The following methods are required for Part I.
*
*/
/**
* Constructor that creates an empty ocean having width i and
* height j, in which sharks starve until after starveTime timesteps.
*
* #param width(i)
* is the width of the ocean.
* #param height(j)
* is the height of the ocean.
* #param starveTime
* is the number of timeSteps sharks survive without food.
*/
public Ocean(int i, int j, int starveTime) {
this.width = i;
this.height = j;
this.oceanMatrix = new int[j][i];
this.sharkHungerLevelMatrix = new int[j][i];
this.starveTime = starveTime;
for (int row = 0; row < j; row++) {
for (int col = 0; col < i; col++) {
oceanMatrix[row][col] = EMPTY;
}
}
for (int row = 0; row < j; row++) {
for (int col = 0; col < i; col++) {
sharkHungerLevelMatrix[row][col] = EMPTY;
}
}
}
/**
* width() returns the width of an ocean Object.
*
* #return the width of the ocean.
*
*/
public int width() {
return this.width;
}
/**
* height() returns the height of an Ocean object.
*
* #return the height of the Ocean.
*/
public int height() {
return this.height;
}
/**
* starveTime() returns the number of timesteps sharks survive without food.
*
* #return the number of timesteps sharks survive without food.
*/
public int starveTime() {
return starveTime;
}
/**
* addFish() places a fish in cell (x,y) if the cell is empty. If the cell
* is already occupied, leave the cell as it is.
*
* #param x
* is the x-coordinate of the cell to place a fish in.
* #param y
* is the y-coordinate of the cell to place a fish in.
*/
public void addFish(int x, int y) {
if (oceanMatrix[x][y] == EMPTY) {
oceanMatrix[x][y] = FISH;
}
}
/**
* addShark() (with two parameters) places a newborn shark in cell (x, y) if
* the cell is empty. A "newborn" shark is equivalent to a shark that has
* just eaten. If the cell is already occupied, leave the cell as it is.
*
* #param x
* is the x-coordinate of the cell to place a shark in.
* #param y
* is the y-coordinate of the cell to place a shark in.
*/
public void addShark(int x, int y) {
if (oceanMatrix[x][y] == EMPTY) {
oceanMatrix[x][y] = SHARK;
}
}
/**
* cellContents() returns EMPTY is cell (x,y) is empty, FISH if it contains
* a fish, and SHARK if it contains a shark.
*
* #param x
* is the x-coordinate of the cell whose contents are queried.
* #param y
* is the y-coordinate of the cell whose contents are queried.
*/
public int cellContents(int x, int y) {
return oceanMatrix[x][y];
}
/**
* isFish() checks for the existence of fish in that cell.
* #param x
* is the x-coordinate of the cell whose contents are queried.
* #param y
* is the y-coordinate of the cell whose contents are queried.
* #return the boolean value
*/
private boolean isFish(int x, int y){
return (this.oceanMatrix[x][y] == Ocean.FISH);
}
/**
* isShark() checks for the existence of shark in that cell.
* #param x
* is the x-coordinate of the cell whose contents are queried.
* #param y
* is the y-coordinate of the cell whose contents are queried.
* #return the boolean value
*/
private boolean isShark(int x, int y){
return (this.oceanMatrix[x][y] == Ocean.SHARK);
}
/**
* isSharkStarving() checks the hunger level of shark, if reached to starveTime level
* #param x
* is the x-coordinate of the cell whose contents are queried.
* #param y
* is the y-coordinate of the cell whose contents are queried.
* #return the boolean value
*/
private boolean isSharkStarving(int x, int y){
return (this.sharkHungerLevelMatrix[x][y] == (this.starveTime+1));
}
/**
* checkFish() checks the existence of atleast one fish
* surrounding shark cell
* #param x
* is the x-coordinate of the cell whose contents are queried.
* #param y
* is the y-coordinate of the cell whose contents are queried.
* #return returns true on atleast one fish exist otherwise false
*
*/
private boolean checkFish(int x, int y){
for(int i = x-1;i <= x+1; i++){
for(int j = y-1; j <= y+1; j++){
if(this.isFish(mod(i,this.height), mod(j,this.width))){
return true;
}
}
}
return false;
}
/**
* countShark() counts the number of sharks surrounding queried cell
* #param x
* is the x-coordinate of the cell whose contents are queried.
* #param y
* is the y-coordinate of the cell whose contents are queried.
* #return returns number of sharks surrounding fish cell
*/
private int countShark(int x, int y){
int neighbourSharkCount = 0;
for(int i = x-1;i <= x+1; i++){
for(int j = y-1; j <= y+1; j++){
if(this.isShark(mod(i,this.height), mod(j,this.width))){
neighbourSharkCount++;
}
} // end inner for loop
}//end outer for loop
return neighbourSharkCount;
}
/**
* countFish() counts the number of fish surrounding queried cell
* #param x
* is the x-coordinate of the cell whose contents are queried.
* #param y
* is the y-coordinate of the cell whose contents are queried.
* #return returns number of sharks surrounding queried cell
*/
private int countFish(int x, int y){
int neighbourFishCount = 0;
for(int i = x-1;i <= x+1; i++){
for(int j = y-1; j <= y+1; j++){
if(this.isFish(mod(i,this.height), mod(j,this.width))){
neighbourFishCount++;
}
} // end inner for loop
}//end outer for loop
return neighbourFishCount;
}
/**
* mod() performs the modulo operation using euclidean divison
*
* #param n
* is the numerator
* #param d
* is the denominator
* #return the remainder
*/
private int mod(int n, int d) {
if (n >= 0)
return n % d;
else
return d + ~(~n % d);
}
/**
* timeStep() performs a simulation timestep as described in README.
*
* #return an ocean representing the elapse of one timestep.
*/
public Ocean timeStep() {
Ocean sea = new Ocean(width, height, starveTime);
for (int row = 0; row < this.height; row++) {
for (int col = 0; col < this.width; col++) {
switch(this.oceanMatrix[row][col]){
case Ocean.SHARK:
boolean gotTheFish = false;
//Check all the 8 neighbors of a Shark Cell for fish
if(this.checkFish(row,col)){
gotTheFish = true;
}
//Updating Shark Cell
if(gotTheFish){
/*
* 1) If a cell contains a shark, and any of its neighbors is a fish, then the
* shark eats during the time step, and it remains in the cell at the end of the
* time step. (We may have multiple sharks sharing the same fish. This is fine;
* they all get enough to eat.)
*/
sea.oceanMatrix[row][col] = Ocean.SHARK; // for next time step
}else{
/*
* 2) If a cell contains a shark, and none of its neighbors is a fish, it gets
* hungrier during the time step. If this time step is the (starveTime + 1)th
* time step the shark has gone through without eating, then the shark dies
* (disappears). Otherwise, it remains in the cell.
*/
this.sharkHungerLevelMatrix[row][col]++;
if(this.isSharkStarving(row,col)){
this.oceanMatrix[row][col] = Ocean.EMPTY; // for this time step
this.sharkHungerLevelMatrix[row][col] = Ocean.EMPTY; // for this time step
}
sea.sharkHungerLevelMatrix[row][col] = this.sharkHungerLevelMatrix[row][col]; // for next time step
sea.oceanMatrix[row][col] = this.oceanMatrix[row][col]; // for next time step
}
break;
case Ocean.FISH:
int neighbourSharkCount=0;
//Check all the 8 neighbors of a Fish cell to count for sharks
neighbourSharkCount=countShark(row,col);
//Updating fish cell for current & next time step
if(neighbourSharkCount ==1){
/*
* 4) If a cell contains a fish, and one of its neighbors is a shark, then the
* fish is eaten by a shark, and therefore disappears.
*/
this.oceanMatrix[row][col] = Ocean.EMPTY; //fish disappears this time step
}
else if(neighbourSharkCount > 1){
/*
* 5) If a cell contains a fish, and two or more of its neighbors are sharks, then
* a new shark is born in that cell. Sharks are well-fed at birth; _after_ they
* are born, they can survive an additional starveTime time steps without eating.
*/
sea.oceanMatrix[row][col] = Ocean.SHARK; // new shark for next time step
}
else if(neighbourSharkCount < 1){
/*
* 3) If a cell contains a fish, and all of its neighbors are either empty or are
* other fish, then the fish stays where it is.
*/
sea.oceanMatrix[row][col] = FISH; //for next time step
}
break;
case Ocean.EMPTY:
int fishCount=0;
int sharkCount=0;
//Check all the 8 neighbors of an Empty cell to count sharks and Fish
fishCount = this.countFish(row,col);
sharkCount = this.countShark(row, col);
//Update Empty Cell for current & next time step.
/* (no need to handle this case)
* 6) If a cell is empty, and fewer than two of its neighbors are fish, then the
* cell remains empty.
*/
if((fishCount >= 2) && (sharkCount <=1)){
/*
* 7) If a cell is empty, at least two of its neighbors are fish, and at most one
* of its neighbors is a shark, then a new fish is born in that cell.
*/
this.oceanMatrix[row][col] = FISH;// for current time step
sea.oceanMatrix[row][col] = FISH; //for next time step
}else if((fishCount >= 2) && (sharkCount >= 2)){
/*
* 8) If a cell is empty, at least two of its neighbors are fish, and at least two
* of its neighbors are sharks, then a new shark is born in that cell. (The new
* shark is well-fed at birth, even though it hasn’t eaten a fish yet.)
*/
sea.oceanMatrix[row][col] = Ocean.SHARK; // for next time step
}
break;
}
}//end inner for loop
}//end outer for loop
return sea;
}
/**
* The following method is required for Part II.
*
*
*/
/**
* addShark() (with three parameters) places a shark in cell (x, y) if the
* cell is empty. The shark's hunger is represented by the third parameter.
* If the cell is already occupied, leave the cell as it is, You will need
* this method to help convert run-length encodings to Oceans.
*
* #param x
* is the x-coordinate of the cell to place a shark in.
* #param y
* is the y-coordinate of the cell to place a shark in.
* #param feeding
* is an integer that indicates the shark's hunger. You may
* encode it any way you want; for instance, "feeding" may be the
* last timestep the shark was fed, or the amount of time that
* has passed since the shark was last fed, or the amount of time
* left before the shark will starve. It's upto you, but be
* consistent.
*/
public void addShark(int x, int y, int feeding) {
this.oceanMatrix[x][y] = Ocean.SHARK;
this.sharkHungerLevelMatrix[x][y] = feeding;
}
/**
* The following method is required for Part III.
*/
/**
* sharkFeeding() returns an integer that indicates the hunger of the shark
* in cell (x, y), using the same "feeding" representation as the parameter
* to addShark() described above. If cell (x, y) does not contain a shark,
* then its return value is undefined--that is, anything you want. Normally,
* this method should not be called if cell (x, y) does not contain a shark.
* You will need this method to help convert Oceans to run-length encodings.
*
* #param x
* is the x-coordinate of the cell whose contents are queried.
* #param y
* is the y-coordinate of the cell whose contents are queried.
*
*/
public int sharkFeeding(int x, int y) {
if(this.isShark(x, y)){
return this.sharkHungerLevelMatrix[x][y];
}
return Ocean.UNKNOWN;
}
}
While this is not a Swing program, you can substitute JFrame for Frame to leverage EXIT_ON_CLOSE.
JFrame frame = new JFrame("Sharks and Fish");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
The AWT approach is to add a WindowListener.
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
Have you tried?
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
I am adding bitmap animations into my simple 2D android game engine(if you can call it one yet.. :D) and I am facing problem of cycling through frames at pre defined FPS/rate.
What I have done for now is simply use System to get currentTimeMillis and use it as reference but I am pretty sure that's not the best decision.. I was thinking I could pass current frame to the drawing method and use that to the drawing method.
Currently I have object that you get the drawable from and I use it on renderer like this:
canvas.drawBitmap(animation.getDrawable(), (int)x, (int)y, null);
and getDrawable() returns current frame of the animation or the only frame if its still image and heres the code
if(frames.size() > 1) {
long current = System.currentTimeMillis();
if (currentFrame == frames.size() - 1 && frameDirection == 1) {
frameDirection = -1;
} else if (currentFrame == 0 && frameDirection == -1) {
frameDirection = 1;
}
if ((current - lastFrame) > delay) {
currentFrame += frameDirection;
lastFrame = current;
}
}
return frames.get(currentFrame);
and in my eyes that just looks so bad and unefficient.. What can I do about this? Is the only way to go passing current frame to getDrawable or how should this be done?
If I understand this right, you want to create an animation class for you game engine?
In my Game Engine I've got a class called SpriteSheetAnimation, which basically iterates through every frame of the animation when the update method is called - I'm sure you'll understand the logic behind it and you'll find a way to use it:
public class SpriteSheetAnimation extends GameObjectTemplate {
int animationSheetLength;
int animationSheetHeight;
int columns;
int rows;
Rect srcRect;
int left;
int bottom;
int lengthOfSpriteInSheet;
int heightOfSpriteInSheet;
boolean repeatAnimation;
boolean animationCompleted;
boolean animationStarted;
Bitmap bitmap;
/**
* You input a bitmap and the number of sprites (by defining the number of rows and columns), and this class will
* take care of animating the sheet.
*
*/
public SpriteSheetAnimation(WorldTemplate world, Bitmap animationSheet, int amountOfRows, int amountOfColumns) {
super(world);
this.animationSheetLength = animationSheet.getWidth();
this.animationSheetHeight = animationSheet.getHeight();
this.columns = amountOfColumns;
this.rows = amountOfRows;
this.lengthOfSpriteInSheet = this.animationSheetLength/this.columns;
this.heightOfSpriteInSheet = this.animationSheetHeight/this.rows;
srcRect = new Rect();
left = 0;
bottom = this.heightOfSpriteInSheet;
repeatAnimation = false;
animationCompleted = false;
animationStarted = false;
this.bitmap = animationSheet;
this.drawShapesOfSprites = true;
this.gameObjectShape.addRectangle(new Rect(0, 0, 0 + this.heightOfSpriteInSheet, 0 + this.lengthOfSpriteInSheet));
}
#Override
public void defineGameObjectPositionShape() {
this.gameObjectShape.addRectangle(new Rect());
}
/**
* <b><i>public Rect getSrcRect()</i></b>
* <br>
* Since: API 1
* <br>
* <br>
* Retrieve the rect that will cover the current source of the sheet.
*
* #return
* The current rect that will cover the current source of the sheet.
*
*/
public Rect getSrcRect() {
return srcRect;
}
/**
* <b><i>public Rect getDstRect()</i></b>
* <br>
* Since: API 1
* <br>
* <br>
* Retrieve the rect where the bitmap will be scaled to fit into.
*
* #return
* The current rect where the bitmap will be scaled to fit into.
*
*/
public Rect getDstRect() {
return this.getGameObjectPositionRect();
}
/**
* <b><i>public void repeatAnimation(boolean repetition)</i></b>
* <br>
* Since: API 1
* <br>
* <br>
* This method will set if the animation should be repeated or not.
*
* #param state
* <br><br>
* 1. True = The animation will repeat once completed and keep on doing so.
* <br><br>
* 2. False = The animation will play only once.
*
*
*/
public void repeatAnimation(boolean repetition) {
this.repeatAnimation = repetition;
}
/**
* <b><i>public boolean isAnimationFinished()</i></b>
* <br>
* Since: API 1
* <br>
* <br>
* Retrieve if the animation has finished.
*
* #return
* If the animation has finished.
*
*/
public boolean isAnimationFinished() {
return animationCompleted;
}
/**
* <b><i>public boolean hasBeenStarted()</i></b>
* <br>
* Since: API 1
* <br>
* <br>
* Retrieve if the animation has started.
*
* #return
* If the animation has started.
*
*/
public boolean hasBeenStarted() {
return animationStarted;
}
/**
* <b><i>public void render()</i></b>
* <br>
* Since: API 1
* <br>
* <br>
* This method will render the animation (the current picture of the sheet).
*
*/
public void render() {
world.game.getGraphics().getCanvasGameScreen().drawBitmap(this.bitmap, this.getSrcRect(), this.getGameObjectPositionRect(), null);
}
/**
* <b><i>public void update()</i></b>
* <br>
* Since: API 1
* <br>
* <br>
* This method will update the animation.
*
*/
#Override
public void update() {
// Every update will advance to the next frame of the animation
// Set if animation has started
if(!animationStarted) {
animationStarted = true;
}
// Set the frame
srcRect.set(left, (bottom - this.heightOfSpriteInSheet), (left + this.lengthOfSpriteInSheet), bottom);
// Change the location, so the next time the frame is set, it will be set accordingly
left = left + this.lengthOfSpriteInSheet;
if(left == this.animationSheetLength && bottom == this.animationSheetHeight) {
if(repeatAnimation == true) {
left = 0;
bottom = 0;
}
else {
animationCompleted = true;
}
}
if(left == this.animationSheetLength) {
bottom = bottom + this.heightOfSpriteInSheet;
left = 0;
}
}
}
I hope this helps you and gets you started.