Skip to content

Commit

Permalink
fix(client): entity interaction
Browse files Browse the repository at this point in the history
  • Loading branch information
Veradictus committed Sep 26, 2023
1 parent 858e76a commit 7d97e6b
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 22 deletions.
16 changes: 10 additions & 6 deletions packages/client/data/sprites.json
Original file line number Diff line number Diff line change
Expand Up @@ -4193,8 +4193,8 @@
},
{
"id": "mobs/rat",
"width": 48,
"height": 48,
"width": 32,
"height": 32,
"idleSpeed": 250,
"animations": {
"death": {
Expand Down Expand Up @@ -4237,12 +4237,14 @@
"length": 4,
"row": 9
}
}
},
"offsetX": -8,
"offsetY": -8
},
{
"id": "mobs/icerat",
"width": 48,
"height": 48,
"width": 32,
"height": 32,
"idleSpeed": 200,
"animations": {
"death": {
Expand Down Expand Up @@ -4285,7 +4287,9 @@
"length": 4,
"row": 9
}
}
},
"offsetX": -8,
"offsetY": -8
},
{
"id": "mobs/redcockroach",
Expand Down
Binary file modified packages/client/public/img/sprites/mobs/icerat.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified packages/client/public/img/sprites/mobs/rat.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions packages/client/src/entity/entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,21 @@ export default abstract class Entity {
return Math.abs(gridX - entity.gridX) + Math.abs(gridY - entity.gridY);
}

/**
* Extracts the bounding rectangle box for the entity. We use this to determine the centre
* point for the sprite for either debugging or when detecting mouse interaction.
* @returns A rectangle that contains the bounding box of the entity.
*/

public getBoundingBox(): Rectangle {
return {
x: this.x + this.sprite.offsetX / 2,
y: this.y + this.sprite.offsetY / 2,
width: this.sprite.width + this.sprite.offsetX,
height: this.sprite.height + this.sprite.offsetY
};
}

/**
* Changes the values of the entity visibility.
*/
Expand Down
39 changes: 23 additions & 16 deletions packages/client/src/game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ export default class Game {
* @returns An entity if found, otherwise undefined.
*/

public searchForEntityAt(position: Position, radius = 2): Entity | undefined {
public searchForEntityAt(position: Position, radius = 3): Entity | undefined {
let entities = this.entities.grids.getEntitiesAround(
position.gridX!,
position.gridY!,
Expand All @@ -354,30 +354,37 @@ export default class Game {
closest: Entity | undefined;

/**
* The `position` parameter contains the absolute x and y coordinates
* of the cursor. We iterate through the entities and try to find
* the distance between the cursor and the entity. We then compare
* the distance to the previous entity and if it is smaller, we
* replace the previous entity with the current one.
* We iterate through every entity that we find near the mouse position. We
* check if the entity can be interacted with, and then we do some magical
* math to determine if the mouse position is within the entity's boundaries.
* We take the entity's bounding box, find the centre of it, and then we
* calculate the distance between the mouse position and the centre of the
* bounding box. Think of it as a circle, actually, turn on debug mode so
* you can see the entity bounding box better.
*/

for (let entity of entities) {
// Skip pets from the search.
if (entity.isPet()) continue;
// Exclude unnecessary entities.
if (entity.isProjectile() || entity.isPet() || this.isMainPlayer(entity.instance))
continue;

// Skip if the entity is a resource and is exhausted.
if (entity.isResource() && (entity as Resource).exhausted) continue;

let { x, y, sprite } = entity,
{ width, height, offsetX, offsetY } = sprite,
largest = width > height ? width : height,
toX = x - offsetX / 2,
toY = y + offsetY / 2,
distance = Utils.distance(position.x, position.y, toX, toY),
boundary = largest / 2 + Utils.halfTile + (width > 32 ? this.map.tileSize : 0);
// Get the bounding box, determine the centre, calculate distance between mouse and centre.
let boundingBox = entity.getBoundingBox(),
centreX = boundingBox.x + boundingBox.width / 2,
centreY = boundingBox.y + boundingBox.height / 2,
distance = Utils.distance(position.x, position.y, centreX, centreY),
threshold =
(entity.sprite.width < entity.sprite.height
? entity.sprite.width
: entity.sprite.height) / 2;

// Skip if the distance is greater than the boundary.
if (distance > boundary) continue;
if (distance > threshold) continue;

// Find the closest entity to the mouse position.
if (!closest || distance < closest.distance) {
closest = entity;
closest.distance = distance;
Expand Down
34 changes: 34 additions & 0 deletions packages/client/src/renderer/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,9 @@ export default class Renderer {
// Check that the entity is loaded, has an animation, and is visible.
if (!entity.sprite?.loaded || !entity.animation || !entity.isVisible()) return;

// Draw the entity's debugging information if debugging is enabled.
if (this.debugging) this.drawEntityBoundary(entity);

// Handle tree drawing as separate from other entities.
if (entity.isTree()) return this.drawTree(entity as Tree);

Expand Down Expand Up @@ -611,6 +614,37 @@ export default class Renderer {
});
}

/**
* Draws the boundary area around an entity. This is a circle that represents
* the interaction area of the entity when using a mouse or tapping on/near it.
* @param entity The entity we are drawing the bounding circle for.
*/

private drawEntityBoundary(entity: Entity): void {
this.entitiesContext.save();
//this.setCameraView(this.entitiesContext);

this.entitiesContext.lineWidth = 2 * this.camera.zoomFactor;

let boundingBox = entity.getBoundingBox();

this.entitiesContext.translate(
(boundingBox.x + boundingBox.width / 2) * this.camera.zoomFactor,
(boundingBox.y + boundingBox.height / 2) * this.camera.zoomFactor
);

this.entitiesContext.strokeStyle = 'rgba(255, 50, 50, 0.4)';

let smallest =
entity.sprite.width < entity.sprite.height ? entity.sprite.width : entity.sprite.height;

this.entitiesContext.beginPath();
this.entitiesContext.arc(0, 0, (smallest / 2) * this.camera.zoomFactor, 0, 2 * Math.PI);
this.entitiesContext.stroke();

this.entitiesContext.restore();
}

/**
* Draws the currently calculated path that the player will
* be taking. Highlights the upcoming tile cells in the path.
Expand Down
7 changes: 7 additions & 0 deletions packages/common/types/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,10 @@ declare interface Coordinate {
gridX: number;
gridY: number;
}

declare interface Rectangle {
x: number;
y: number;
width: number;
height: number;
}

0 comments on commit 7d97e6b

Please sign in to comment.