I am working on a game that uses a grid system (think chess board). Each tile on the board has a Location (row/column). There is also the concept of a Direction (N, E, S, W, NE, SE, NW, SW).
Given two Locations I am calculating 3 direction things:
The direction (N, E, S, W, NE, SW, NW, SW, NONE, or null. Null is when the tiles do not line up exactly on one of the direction).
The general direction (If it isn't one of the specific directions then it falls into the NE, SE, NW, SW general direction).
The closest direction (if there is a tie it is null).
For example, (0, 0) -> (4, 3) has:
direction of null
general direction of SE
closest direction of SE
and (0, 0) -> (4, 1) has:
direction of null
general direction of SE
closest direction of S
The code works, but it is terribly ugly. I am sure there must be a cleaner algorithm for setting the values, one with far less repetition. Any thoughts on ways to reduce the duplicate code?
public final class Dimension
{
private final int rowDistance;
private final int columnDistance;
private final Direction direction;
private final Direction generalDirection;
private final Direction closestDirection;
public Dimension(final Location locationA,
final Location locationB)
{
if(locationA == null)
{
throw new IllegalArgumentException("locationA cannot be null");
}
if(locationB == null)
{
throw new IllegalArgumentException("locationB cannot be null");
}
rowDistance = locationB.getRow() - locationA.getRow();
columnDistance = locationB.getColumn() - locationA.getColumn();
// not moving at all
if(rowDistance == 0 && columnDistance == 0)
{
direction = Direction.NONE;
generalDirection = Direction.NONE;
closestDirection = Direction.NONE;
}
else
{
final int absoluteDifference;
absoluteDifference = Math.abs(Math.abs(rowDistance) - Math.abs(columnDistance));
// North Westish
if(rowDistance <= 0 && columnDistance <= 0)
{
final int north;
final int west;
final int northWest;
if(absoluteDifference == 0)
{
direction = Direction.NORTH_WEST;
generalDirection = Direction.NORTH_WEST;
}
else if(rowDistance == 0)
{
direction = Direction.WEST;
generalDirection = Direction.WEST;
}
else if(columnDistance == 0)
{
direction = Direction.NORTH;
generalDirection = Direction.NORTH;
}
else
{
direction = null;
generalDirection = Direction.NORTH_WEST;
}
north = Math.abs(columnDistance);
west = Math.abs(rowDistance);
northWest = Math.abs(
Math.abs(Math.max(rowDistance, columnDistance)) -
Math.abs(Math.min(rowDistance, columnDistance)));
if(northWest < west && northWest < north)
{
closestDirection = Direction.NORTH_WEST;
}
else if(west < northWest && west < north)
{
closestDirection = Direction.WEST;
}
else if(north < northWest && north < west)
{
closestDirection = Direction.NORTH;
}
else
{
closestDirection = null;
}
}
// North Eastish
else if(rowDistance <= 0 && columnDistance >= 0)
{
final int north;
final int east;
final int northEast;
if(absoluteDifference == 0)
{
direction = Direction.NORTH_EAST;
generalDirection = Direction.NORTH_EAST;
}
else if(rowDistance == 0)
{
direction = Direction.EAST;
generalDirection = Direction.EAST;
}
else if(columnDistance == 0)
{
direction = Direction.NORTH;
generalDirection = Direction.NORTH;
}
else
{
direction = null;
generalDirection = Direction.NORTH_EAST;
}
north = Math.abs(columnDistance);
east = Math.abs(rowDistance);
northEast = Math.abs(
Math.abs(Math.max(rowDistance, columnDistance)) -
Math.abs(Math.min(rowDistance, columnDistance)));
if(northEast < east && northEast < north)
{
closestDirection = Direction.NORTH_EAST;
}
else if(east < northEast && east < north)
{
closestDirection = Direction.EAST;
}
else if(north < northEast && north < east)
{
closestDirection = Direction.NORTH;
}
else
{
closestDirection = null;
}
}
// South Westish
else if(rowDistance >= 0 && columnDistance <= 0)
{
final int south;
final int west;
final int southWest;
if(absoluteDifference == 0)
{
direction = Direction.SOUTH_WEST;
generalDirection = Direction.SOUTH_WEST;
}
else if(rowDistance == 0)
{
direction = Direction.WEST;
generalDirection = Direction.WEST;
}
else if(columnDistance == 0)
{
direction = Direction.SOUTH;
generalDirection = Direction.SOUTH;
}
else
{
direction = null;
generalDirection = Direction.SOUTH_WEST;
}
south = Math.abs(columnDistance);
west = Math.abs(rowDistance);
southWest = Math.abs(
Math.abs(Math.max(rowDistance, columnDistance)) -
Math.abs(Math.min(rowDistance, columnDistance)));
if(southWest < west && southWest < south)
{
closestDirection = Direction.SOUTH_WEST;
}
else if(west < southWest && west < south)
{
closestDirection = Direction.WEST;
}
else if(south < southWest && south < west)
{
closestDirection = Direction.SOUTH;
}
else
{
closestDirection = null;
}
}
// South Eastish
else
{
final int south;
final int east;
final int southEast;
if(absoluteDifference == 0)
{
direction = Direction.SOUTH_EAST;
generalDirection = Direction.SOUTH_EAST;
}
else if(rowDistance == 0)
{
direction = Direction.EAST;
generalDirection = Direction.EAST;
}
else if(columnDistance == 0)
{
direction = Direction.SOUTH;
generalDirection = Direction.SOUTH;
}
else
{
direction = null;
generalDirection = Direction.SOUTH_EAST;
}
south = Math.abs(columnDistance);
east = Math.abs(rowDistance);
southEast = Math.abs(
Math.abs(Math.max(rowDistance, columnDistance)) -
Math.abs(Math.min(rowDistance, columnDistance)));
if(southEast < east && southEast < south)
{
closestDirection = Direction.SOUTH_EAST;
}
else if(east < southEast && east < south)
{
closestDirection = Direction.EAST;
}
else if(south < southEast && south < east)
{
closestDirection = Direction.SOUTH;
}
else
{
closestDirection = null;
}
}
}
}
public int getRowDistance()
{
return (rowDistance);
}
public int getColumnDistance()
{
return (columnDistance);
}
public Direction getDirection()
{
return (direction);
}
public Direction getGeneralDirection()
{
return (generalDirection);
}
public Direction getClosestDirection()
{
return (closestDirection);
}
}
I would compute the distance much as you have, then I would pass the orthogonal distances to Math.Atan2 to compute a heading H that can be scaled (int)Math.Round(H * 4 / Math.PI) into the range 0-7 as a hash that counts clockwise through the compass points from N, and which you can directly cast into your enum assuming you enumerate clockwise.
Related
Hello I have a connect four game who worked before null safety but I try to make the migration, but I have a problem with scores[i] = null; I can't write like that but without it I have a freeze when CPU is certain to loose
int _compute(Board board, int step, int deepness, List<double> scores) {
for (var i = 0; i < 7; ++i) {
final boardCopy = board.clone();
final target = boardCopy.getColumnTarget(i);
if (target == -1) {
scores[i] = null; // <<<---- HERE I CAN'T USE NULL
continue;
}
final coordinate = Coordinate(i, target);
boardCopy.setBox(coordinate, player);
if (boardCopy.checkWinner(coordinate, player)) {
scores[i] += deepness / (step + 1);
continue;
}
for (var j = 0; j < 7; ++j) {
final target = boardCopy.getColumnTarget(j);
if (target == -1) {
continue;
}
final coordinate = Coordinate(j, target);
boardCopy.setBox(coordinate, otherPlayer);
if (boardCopy.checkWinner(coordinate, otherPlayer)) {
scores[i] -= deepness / (step + 1);
continue;
}
if (step + 1 < deepness) {
_compute(board, step + 1, deepness, scores);
}
}
}
return _getBestScoreIndex(scores);
}
int _getBestScoreIndex(List<double> scores) {
int bestScoreIndex = scores.indexWhere((s) => s != null);
scores.asMap().forEach((index, score) {
if (score != null &&
(score > scores[bestScoreIndex] ||
(score == scores[bestScoreIndex] && _random.nextBool()))) {
bestScoreIndex = index;
}
});
return bestScoreIndex;
}
if I use List<double?>
int _compute(Board board, int step, int deepness, List<double?> scores) {
for (var i = 0; i < 7; ++i) {
final boardCopy = board.clone();
final target = boardCopy.getColumnTarget(i);
if (target == -1) {
scores[i] = null;
continue;
}
final coordinate = Coordinate(i, target);
boardCopy.setBox(coordinate, player);
if (boardCopy.checkWinner(coordinate, player)) {
scores[i] += deepness / (step + 1);//<<<---- HERE I CAN'T USE +=
continue;
}
for (var j = 0; j < 7; ++j) {
final target = boardCopy.getColumnTarget(j);
if (target == -1) {
continue;
}
final coordinate = Coordinate(j, target);
boardCopy.setBox(coordinate, otherPlayer);
if (boardCopy.checkWinner(coordinate, otherPlayer)) {
scores[i] -= deepness / (step + 1); //<<<---- HERE I CAN'T USE -=
continue;
}
if (step + 1 < deepness) {
_compute(board, step + 1, deepness, scores);
}
}
}
return _getBestScoreIndex(scores);
}
int _getBestScoreIndex(List<double?> scores) {
int bestScoreIndex = scores.indexWhere((s) => s != null);
scores.asMap().forEach((index, score) {
if (score != null && // <<<---- HERE I CAN'T USE score !=
(score > scores[bestScoreIndex] || // <<<---- HERE I CAN'T USE score >
(score == scores[bestScoreIndex] && _random.nextBool()))) {
bestScoreIndex = index;
}
});
return bestScoreIndex;
}
The issue with your code is that in the function definition you have defined the data type of score variable as List<double>. Due to which you get an error on assigning score[i] = null. To fix this use data type of score as List<double?>
i believe the param scores is a type-defined value and it has a double, which is a non null value. So you can't assign null to double as it has the type of value assigned.
You can make it double as an optional value, like a List<double?>. but with this, the values in the list will be optional and you need to force unwrap or do null check before using them.
I am making a running game that detect the player knee movement and add speed , its working fine but the problem is when I stop running and keep one knee up the game speed do not stop ,I need the speed to be decreased when I stop running even if one knee is still.
if (!player1)
{
player1 = GameObject.Find("player1");
player1State.text = "";
}
if (player1)
{
player1FootRight = player1.transform.Find("KneeRight").gameObject;
player1FootLeft = player1.transform.Find("KneeLeft").gameObject;
player1State.text = "OK";
player1State.color = Color.white;
newPosP1 = player1FootRight.transform.position.y;
oldPosP1 = player1FootLeft.transform.position.y;
if (startRunning) {
if (foot1 && newPosP1 > oldPosP1)
{
float k = newPosP1 - oldPosP1;
if (k > 1 && speed < 100)
{
speed = speed + 7;
if(leftPath.speed < 15)
{
leftPath.speed = leftPath.speed + 3;
}
footOld = foot1;
foot1 = !foot1;
}
else
{
if (speed > 0)
{
speed = speed - 1;
if (leftPath.speed > 0)
{
leftPath.speed = leftPath.speed - 1;
}
}
if (speed < 0)
{
speed = 0;
}
if (leftPath.speed < 0)
{
leftPath.speed = 0;
}
}
}
if (!foot1 && newPosP1 < oldPosP1)
{
float k = oldPosP1 - newPosP1;
if (k > 1 && speed < 100)
{
speed = speed + 7 ;
if (leftPath.speed < 15)
{
leftPath.speed = leftPath.speed + 3;
}
footOld = foot1;
foot1 = !foot1;
}
else
{
if (speed > 0)
{
speed = speed - 1;
if (leftPath.speed > 0)
{
leftPath.speed = leftPath.speed - 1;
}
}
if (speed < 0)
{
speed = 0;
}
if (leftPath.speed < 0)
{
leftPath.speed = 0;
}
}
}
I am really sorry for this stupid question but i don't know what i should do.
I tried so many things nothing works.
I try to calculate the distance between playerx and the width of playerx.
Can someone just correct my code so i can understand it please try not to explain it.
var playerx = 0;
var z = 0;
var playery = 750;
var ball = {
x: 400,
y: 400,
speedx: 2,
speedy: 3,
};
function setup() {
createCanvas(800,800);}
function draw(){
background(0);
ball1();
player();
click();
wall();
bounce();
hit();
}
function hit(){
var AA = dist(playerx,playery,player.x + 200,playery)
var BB = dist(ball.x,ball.y,AA,).
if (BB <= 20){
ball.speedy = -7;
}
}
function ball1(){
fill(255);
rect(ball.x,ball.y,20,20);
}
function bounce(){
ball.x += ball.speedx;
ball.y += ball.speedy;
if (ball.x>800){
ball.speedx = -2;
}else if (ball.x<0){
ball.speedx = 3;
}else if (ball.y>800){
ball.speedy = -3;
} else if(ball.y<0){
ball.speedy = 2;
}
}
function player(){
fill(255);
rect(playerx,playery,200,20);
}
function click(){
if(keyCode === RIGHT_ARROW) {
playerx += z;
z = 3;
} else if (keyCode === LEFT_ARROW){
playerx += z;
z = -3;
}
}
function wall(){
if (playerx > 600){
playerx = 600;
} else if (playerx < 1){
playerx = 1;
}
}
check this library, it contains the code for collision detection:
https://github.com/bmoren/p5.collide2D
var playerx = 400;
var z = 0;
var playery = 750;
var ball = {
x: 400,
y: 400,
speedx: 2,
speedy: 3,
};
function setup() {
createCanvas(800, 800);
}
function draw() {
background(0);
ball1();
player();
click();
wall();
bounce();
hit();
}
function hit() {
if(checkCollision(playerx, playery, 200, 20, ball.x, ball.y, 20)){
ball.speedy = -7;
console.log("colliding");
}
}
function ball1() {
fill(255);
ellipse(ball.x, ball.y, 20, 20);
}
function bounce() {
ball.x += ball.speedx;
ball.y += ball.speedy;
if (ball.x > 800) {
ball.speedx = -2;
} else if (ball.x < 0) {
ball.speedx = 3;
} else if (ball.y > 800) {
ball.speedy = -3;
} else if (ball.y < 0) {
ball.speedy = 2;
}
}
function player() {
fill(255);
rect(playerx, playery, 200, 20);
}
function click() {
if (keyCode === RIGHT_ARROW) {
playerx += z;
z = 3;
} else if (keyCode === LEFT_ARROW) {
playerx += z;
z = -3;
}
}
function wall() {
if (playerx > 600) {
playerx = 600;
} else if (playerx < 1) {
playerx = 1;
}
}
function checkCollision(rx, ry, rw, rh, cx, cy, diameter) {
//2d
// temporary variables to set edges for testing
var testX = cx;
var testY = cy;
// which edge is closest?
if (cx < rx){ testX = rx // left edge
}else if (cx > rx+rw){ testX = rx+rw } // right edge
if (cy < ry){ testY = ry // top edge
}else if (cy > ry+rh){ testY = ry+rh } // bottom edge
// // get distance from closest edges
var distance = dist(cx,cy,testX,testY)
// if the distance is less than the radius, collision!
if (distance <= diameter/2) {
return true;
}
return false;
};
I have the method below, which in my Blackjack app will get the value of the hand which is an NSMutableArray. The problem here is that when 2 Ace's are in a hand, it should be a 12, but because it counts Ace's as 11, it results in being 22, which then makes lowValue returned.
How can I make it so that I can check and see if the for loop has already found an Ace and if it finds another, makes the next Ace worth only 1, not 11?
Thanks!
int getHandValue(NSMutableArray *hand) {
int lowValue = 0;
int highValue = 0;
for (KCCard *aCard in hand) {
if (aCard.value == Ace) {
lowValue+= 1;
highValue+= 11;
} else if (aCard.value == Jack || aCard.value == Queen || aCard.value == King) {
lowValue += 10;
highValue += 10;
} else {
lowValue += aCard.value;
highValue += aCard.value;
}
}
return (highValue > 21) ? lowValue : highValue;
}
Perhaps you can add a boolean value before the for loop setting it initially to NO. When an Ace is found then you can break from the for loop after setting the boolean to YES, that way if you encounter another Ace && your boolean value == YES you can handle the case accordingly.
int getHandValue(NSMutableArray *hand) {
int lowValue = 0;
int highValue = 0;
BOOL isFoundAce = NO;
for (KCCard *aCard in hand) {
if (aCard.value == Ace) {
if (isFoundAce) {
lowValue+= 1;
highValue+= 1;
}
else {
lowValue+= 1;
highValue+= 11;
isFoundAce= YES;
}
} else if (aCard.value == Jack || aCard.value == Queen || aCard.value == King) {
lowValue += 10;
highValue += 10;
} else {
lowValue += aCard.value;
highValue += aCard.value;
}
}
return (highValue > 21) ? lowValue : highValue;
}
My example without a redundant code from zsxwing's example:
int getHandValue(NSMutableArray *hand) {
int cardValue = 0;
int aceCount = 0;
for (KCCard *aCard in hand) {
if (aCard.value == Ace) {
aceCount++;
cardValue += 11;
} else if (aCard.value == Jack || aCard.value == Queen || aCard.value == King) {
cardValue += 10;
} else {
cardValue += aCard.value;
}
}
while ((cardValue > 21) && (aceCount > 0)) {
cardValue -= 10;
aceCount--;
}
return cardValue;
}
I am wondering why my code doesn't work. I want my ball (UIImageView) to bounce off of a block (also a UIImageView). My ball switches both the x and y movements to negative instead of just one. What is wrong??? Please Help... Here is my code
-(void)animateBall:(NSTimer *)theTimer {
collisionCount ++;
bouncyBall.center = CGPointMake(bouncyBall.center.x + ballMovement.x, bouncyBall.center.y + ballMovement.y);
if (CGRectIntersectsRect(bouncyBall.frame, wallOne.frame)) {
if (collisionCount >= 5) {
[self processCollision:wallOne];
collisionCount = 0;
}
}
if (bouncyBall.center.x > 313 || bouncyBall.center.x < 8) {
ballMovement.x = -ballMovement.x;
}
if (bouncyBall.center.y > 453 || bouncyBall.center.y < 8) {
ballMovement.y = -ballMovement.y;
}
}
-(void)processCollision:(UIImageView *)wall {
if (ballMovement.x > 0 && wall.frame.origin.x - bouncyBall.center.x <= 4) {
ballMovement.x = -ballMovement.x;
}
else if (ballMovement.x < 0 && bouncyBall.center.x - (wall.frame.origin.x + wall.frame.size.width) <= 4) {
ballMovement.x = -ballMovement.x;
}
if (ballMovement.y > 0 && wall.frame.origin.y - bouncyBall.center.y <= 4) {
ballMovement.y = -ballMovement.y;
}
else if (ballMovement.y < 0 && bouncyBall.center.y - (wall.frame.origin.y + wall.frame.size.height) <= 4) {
ballMovement.y = -ballMovement.y;
}
}
Does it happen even when the ball hits the center of an edge? Anyway don't you just need to handle one dimension at a time? Can't the third if be else if?