boids: initial
This commit is contained in:
parent
04c265e253
commit
7f01fd0483
4
Makefile
4
Makefile
@ -33,7 +33,9 @@ OBJS = \
|
|||||||
src/hud.o \
|
src/hud.o \
|
||||||
src/lighting.o \
|
src/lighting.o \
|
||||||
src/collision_scene.o \
|
src/collision_scene.o \
|
||||||
src/line_art.o
|
src/line_art.o \
|
||||||
|
src/boids.o \
|
||||||
|
src/boids_scene.o
|
||||||
|
|
||||||
all: test.so
|
all: test.so
|
||||||
|
|
||||||
|
|||||||
53
include/boids.h
Normal file
53
include/boids.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
namespace boids {
|
||||||
|
|
||||||
|
struct boid_configuration {
|
||||||
|
float vision_length;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
float coefficient;
|
||||||
|
} cohesion;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
float coefficient;
|
||||||
|
} alignment;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
float minimum_length;
|
||||||
|
float coefficient;
|
||||||
|
} separation;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
float coefficient;
|
||||||
|
} bounds;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct boid_forces {
|
||||||
|
float vision_neighbor_count;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
// intermediate state
|
||||||
|
XMVECTOR center_of_mass;
|
||||||
|
XMVECTOR force;
|
||||||
|
} cohesion;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
// intermediate state
|
||||||
|
XMVECTOR average_velocity;
|
||||||
|
XMVECTOR force;
|
||||||
|
} alignment;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
// intermediate state
|
||||||
|
XMVECTOR force;
|
||||||
|
} separation;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct boid {
|
||||||
|
XMVECTOR position;
|
||||||
|
XMVECTOR velocity;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern boid_configuration configuration;
|
||||||
|
|
||||||
|
boid_forces const & evaluate(boid const * const boids, int length, int boid_index);
|
||||||
|
}
|
||||||
12
include/boids_scene.h
Normal file
12
include/boids_scene.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace boids_scene {
|
||||||
|
|
||||||
|
void update(int up, int down, int left, int right,
|
||||||
|
int w, int s, int a, int d,
|
||||||
|
int t, int g, int f, int h,
|
||||||
|
int i, int k, int j, int l);
|
||||||
|
|
||||||
|
void load();
|
||||||
|
void draw();
|
||||||
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "directxmath/directxmath.h"
|
||||||
|
|
||||||
namespace line_art {
|
namespace line_art {
|
||||||
void load();
|
void load();
|
||||||
|
|
||||||
@ -14,5 +16,7 @@ namespace line_art {
|
|||||||
void draw_capsule(XMMATRIX const & transform, XMVECTOR a, XMVECTOR b, float radius);
|
void draw_capsule(XMMATRIX const & transform, XMVECTOR a, XMVECTOR b, float radius);
|
||||||
void draw_cube(XMMATRIX const & transform, XMVECTOR const & position);
|
void draw_cube(XMMATRIX const & transform, XMVECTOR const & position);
|
||||||
void scene_start(XMMATRIX const & transform);
|
void scene_start(XMMATRIX const & transform);
|
||||||
|
void draw_grid(XMMATRIX const & transform);
|
||||||
void set_color(float r, float g, float b);
|
void set_color(float r, float g, float b);
|
||||||
|
void set_colorv(XMFLOAT3 const & value);
|
||||||
}
|
}
|
||||||
|
|||||||
1
main.lua
1
main.lua
@ -120,6 +120,7 @@ function love.run()
|
|||||||
|
|
||||||
love.graphics.present()
|
love.graphics.present()
|
||||||
love.timer.sleep(0.001)
|
love.timer.sleep(0.001)
|
||||||
|
--love.timer.sleep(0.1)
|
||||||
--local fps = love.timer.getFPS( )
|
--local fps = love.timer.getFPS( )
|
||||||
--print(fps)
|
--print(fps)
|
||||||
end
|
end
|
||||||
|
|||||||
29
minecraft/gen/arrow.obj
Normal file
29
minecraft/gen/arrow.obj
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Blender 5.0.0
|
||||||
|
# www.blender.org
|
||||||
|
o Cone
|
||||||
|
v 0.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 0.000000
|
||||||
|
v 0.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 0.000000
|
||||||
|
v 0.000000 1.000000 0.000000
|
||||||
|
vn 0.6667 0.3333 -0.6667
|
||||||
|
vn 0.6667 0.3333 0.6667
|
||||||
|
vn -0.0000 -1.0000 -0.0000
|
||||||
|
vn -0.6667 0.3333 0.6667
|
||||||
|
vn -0.6667 0.3333 -0.6667
|
||||||
|
vt 0.250000 0.490000
|
||||||
|
vt 0.250000 0.250000
|
||||||
|
vt 0.490000 0.250000
|
||||||
|
vt 0.250000 0.010000
|
||||||
|
vt 0.990000 0.250000
|
||||||
|
vt 0.510000 0.250000
|
||||||
|
vt 0.750000 0.490000
|
||||||
|
vt 0.010000 0.250000
|
||||||
|
vt 0.750000 0.010000
|
||||||
|
s 0
|
||||||
|
f 1/1/1 5/2/1 2/3/1
|
||||||
|
f 2/3/2 5/2/2 3/4/2
|
||||||
|
f 2/5/3 4/6/3 1/7/3
|
||||||
|
f 3/4/4 5/2/4 4/8/4
|
||||||
|
f 4/8/5 5/2/5 1/1/5
|
||||||
|
f 2/5/3 3/9/3 4/6/3
|
||||||
102
src/boids.cpp
Normal file
102
src/boids.cpp
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "directxmath/directxmath.h"
|
||||||
|
|
||||||
|
#include "boids.h"
|
||||||
|
|
||||||
|
namespace boids {
|
||||||
|
|
||||||
|
boid_forces forces;
|
||||||
|
boid_configuration configuration;
|
||||||
|
|
||||||
|
static inline void reset_cohesion()
|
||||||
|
{
|
||||||
|
forces.cohesion.center_of_mass = XMVectorZero();
|
||||||
|
forces.cohesion.force = XMVectorZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void reset_alignment()
|
||||||
|
{
|
||||||
|
forces.alignment.average_velocity = XMVectorZero();
|
||||||
|
forces.alignment.force = XMVectorZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void reset_separation()
|
||||||
|
{
|
||||||
|
forces.separation.force = XMVectorZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline constexpr bool vector_equal(XMVECTOR V1, XMVECTOR V2)
|
||||||
|
{
|
||||||
|
uint32_t CR;
|
||||||
|
XMVectorEqualR(&CR, V1, V2);
|
||||||
|
return XMComparisonAllTrue(CR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline XMVECTOR cohesion_force(boid const & this_boid, float const reciprocal_neighbor_count)
|
||||||
|
{
|
||||||
|
XMVECTOR center_of_mass = forces.cohesion.center_of_mass * reciprocal_neighbor_count;
|
||||||
|
XMVECTOR cohesion_vector = center_of_mass - this_boid.position;
|
||||||
|
if (vector_equal(cohesion_vector, XMVectorZero()))
|
||||||
|
return XMVectorZero();
|
||||||
|
XMVECTOR cohesion_direction = XMVector3NormalizeEst(cohesion_vector);
|
||||||
|
return cohesion_direction * configuration.cohesion.coefficient;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline XMVECTOR alignment_force(boid const & this_boid, float const reciprocal_neighbor_count)
|
||||||
|
{
|
||||||
|
XMVECTOR average_velocity = forces.alignment.average_velocity * reciprocal_neighbor_count;
|
||||||
|
XMVECTOR alignment_vector = average_velocity - this_boid.velocity;
|
||||||
|
if (vector_equal(alignment_vector, XMVectorZero()))
|
||||||
|
return XMVectorZero();
|
||||||
|
XMVECTOR alignment_direction = XMVector3NormalizeEst(alignment_vector);
|
||||||
|
return alignment_direction * configuration.alignment.coefficient;
|
||||||
|
}
|
||||||
|
|
||||||
|
boid_forces const & evaluate(boid const * const boids, int length, int boid_index)
|
||||||
|
{
|
||||||
|
forces.vision_neighbor_count = 0;
|
||||||
|
|
||||||
|
reset_cohesion();
|
||||||
|
reset_alignment();
|
||||||
|
reset_separation();
|
||||||
|
|
||||||
|
boid const & this_boid = boids[boid_index];
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
if (i == boid_index)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
boid const & other_boid = boids[i];
|
||||||
|
|
||||||
|
XMVECTOR position_vector = this_boid.position - other_boid.position;
|
||||||
|
float position_length = XMVectorGetX(XMVector3LengthEst(position_vector));
|
||||||
|
if (position_length < configuration.vision_length) {
|
||||||
|
forces.vision_neighbor_count += 1;
|
||||||
|
|
||||||
|
// cohesion
|
||||||
|
forces.cohesion.center_of_mass += other_boid.position;
|
||||||
|
|
||||||
|
// alignment
|
||||||
|
forces.alignment.average_velocity += other_boid.velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// separation
|
||||||
|
if (vector_equal(position_vector, XMVectorZero()))
|
||||||
|
continue;
|
||||||
|
if (position_length < configuration.separation.minimum_length) {
|
||||||
|
float reciprocal_position_length = 1.0f / position_length;
|
||||||
|
//float reciprocal_position_length = 1.0f;
|
||||||
|
XMVECTOR separation_direction = position_vector * reciprocal_position_length;
|
||||||
|
forces.separation.force += separation_direction * reciprocal_position_length * configuration.separation.coefficient;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (forces.vision_neighbor_count != 0) {
|
||||||
|
float reciprocal_vision_neighbor_count = 1.0f / forces.vision_neighbor_count;
|
||||||
|
forces.cohesion.force = cohesion_force(this_boid, reciprocal_vision_neighbor_count);
|
||||||
|
forces.alignment.force = alignment_force(this_boid, reciprocal_vision_neighbor_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
return forces;
|
||||||
|
}
|
||||||
|
}
|
||||||
116
src/boids_scene.cpp
Normal file
116
src/boids_scene.cpp
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "glad/gl.h"
|
||||||
|
|
||||||
|
#include "line_art.h"
|
||||||
|
#include "boids.h"
|
||||||
|
|
||||||
|
namespace boids_scene {
|
||||||
|
|
||||||
|
const int boids_length = 20;
|
||||||
|
boids::boid boids[boids_length];
|
||||||
|
|
||||||
|
const XMFLOAT3 colors[] = {
|
||||||
|
{(float)0xb5 / 255.0, (float)0x7f / 255.0, (float)0x50 / 255.0},
|
||||||
|
{(float)0x37 / 255.0, (float)0xff / 255.0, (float)0x8b / 255.0},
|
||||||
|
{(float)0x51 / 255.0, (float)0xd6 / 255.0, (float)0xff / 255.0},
|
||||||
|
{(float)0x54 / 255.0, (float)0x2e / 255.0, (float)0x71 / 255.0},
|
||||||
|
{(float)0xff / 255.0, (float)0x84 / 255.0, (float)0x84 / 255.0},
|
||||||
|
};
|
||||||
|
|
||||||
|
void update(int up, int down, int left, int right,
|
||||||
|
int w, int s, int a, int d,
|
||||||
|
int t, int g, int f, int h,
|
||||||
|
int i, int k, int j, int l)
|
||||||
|
{
|
||||||
|
float rate = 0.05f;
|
||||||
|
|
||||||
|
float forward[4];
|
||||||
|
float strafe[4];
|
||||||
|
|
||||||
|
forward[0] = (rate * up + -rate * down);
|
||||||
|
strafe[0] = (-rate * left + rate * right);
|
||||||
|
|
||||||
|
forward[1] = (rate * w + -rate * s);
|
||||||
|
strafe[1] = (-rate * a + rate * d);
|
||||||
|
|
||||||
|
forward[2] = (rate * t + -rate * g);
|
||||||
|
strafe[2] = (-rate * f + rate * h);
|
||||||
|
|
||||||
|
forward[3] = (rate * i + -rate * k);
|
||||||
|
strafe[3] = (-rate * j + rate * l);
|
||||||
|
|
||||||
|
//for (int i = 0; i < 4; i++)
|
||||||
|
//point_position[i] = XMVector3Transform(point_position[i], XMMatrixTranslation(strafe[i], forward[i], 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float random()
|
||||||
|
{
|
||||||
|
float r = 1.0f / (float)RAND_MAX;
|
||||||
|
return (float)rand() * r * 2.0f - 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void load()
|
||||||
|
{
|
||||||
|
srand(0x12345678);
|
||||||
|
|
||||||
|
for (int i = 0; i < boids_length; i++) {
|
||||||
|
boids[i].position = XMVectorSet(random() * 5, random() * 5, 0, 0);
|
||||||
|
boids[i].velocity = XMVectorSet(random(), random(), 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
boids::configuration.vision_length = 2.0f;
|
||||||
|
boids::configuration.cohesion.coefficient = 0.001f;
|
||||||
|
boids::configuration.alignment.coefficient = 0.01f;
|
||||||
|
boids::configuration.separation.minimum_length = 0.7f;
|
||||||
|
boids::configuration.separation.coefficient = 0.5f;
|
||||||
|
boids::configuration.bounds.coefficient = 0.02f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw()
|
||||||
|
{
|
||||||
|
XMMATRIX transform = line_art::view() * line_art::projection();
|
||||||
|
|
||||||
|
line_art::scene_start(transform);
|
||||||
|
|
||||||
|
glLineWidth(1.0f);
|
||||||
|
|
||||||
|
line_art::set_colorv(colors[4]);
|
||||||
|
for (int i = 0; i < boids_length; i++)
|
||||||
|
line_art::draw_sphere(transform, boids[i].position, 0.3);
|
||||||
|
|
||||||
|
for (int i = 0; i < boids_length; i++) {
|
||||||
|
boids::boid_forces const & forces = evaluate(boids, boids_length, i);
|
||||||
|
|
||||||
|
glLineWidth(4.0f);
|
||||||
|
line_art::set_colorv(colors[0]);
|
||||||
|
line_art::draw_line(transform, boids[i].position, boids[i].position + forces.cohesion.force);
|
||||||
|
line_art::set_colorv(colors[1]);
|
||||||
|
line_art::draw_line(transform, boids[i].position, boids[i].position + forces.alignment.force);
|
||||||
|
line_art::set_colorv(colors[2]);
|
||||||
|
line_art::draw_line(transform, boids[i].position, boids[i].position + forces.separation.force);
|
||||||
|
|
||||||
|
boids[i].velocity += forces.cohesion.force + forces.alignment.force + forces.separation.force;
|
||||||
|
const float speed_limit = 2.0;
|
||||||
|
if (XMVectorGetX(XMVector3LengthEst(boids[i].velocity)) > speed_limit) {
|
||||||
|
boids[i].velocity = XMVector3NormalizeEst(boids[i].velocity) * speed_limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (XMVectorGetX(boids[i].position) > 5.0)
|
||||||
|
boids[i].velocity += XMVectorSetX(XMVectorZero(), -boids::configuration.bounds.coefficient);
|
||||||
|
|
||||||
|
if (XMVectorGetX(boids[i].position) < -5.0)
|
||||||
|
boids[i].velocity += XMVectorSetX(XMVectorZero(), boids::configuration.bounds.coefficient);
|
||||||
|
|
||||||
|
if (XMVectorGetY(boids[i].position) > 5.0)
|
||||||
|
boids[i].velocity += XMVectorSetY(XMVectorZero(), -boids::configuration.bounds.coefficient);
|
||||||
|
|
||||||
|
if (XMVectorGetY(boids[i].position) < -5.0)
|
||||||
|
boids[i].velocity += XMVectorSetY(XMVectorZero(), boids::configuration.bounds.coefficient);
|
||||||
|
|
||||||
|
boids[i].position += boids[i].velocity * 0.05f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -169,7 +169,7 @@ namespace line_art {
|
|||||||
|
|
||||||
XMMATRIX projection()
|
XMMATRIX projection()
|
||||||
{
|
{
|
||||||
return XMMatrixOrthographicRH(10, 10, 0, 10);
|
return XMMatrixOrthographicRH(20, 20, 0, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_transform(XMMATRIX const & transform)
|
void set_transform(XMMATRIX const & transform)
|
||||||
@ -227,6 +227,18 @@ namespace line_art {
|
|||||||
glDrawElementsBaseVertex(GL_LINE_STRIP, 5, GL_UNSIGNED_SHORT, (void*)(cube_base_index), cube_base_vertex);
|
glDrawElementsBaseVertex(GL_LINE_STRIP, 5, GL_UNSIGNED_SHORT, (void*)(cube_base_index), cube_base_vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void draw_grid(XMMATRIX const & transform)
|
||||||
|
{
|
||||||
|
// grid
|
||||||
|
glLineWidth(1.0f);
|
||||||
|
set_transform(transform);
|
||||||
|
glUniform3f(location.uniform.base_color, 0, 1, 0);
|
||||||
|
glUniform1i(location.uniform.use_grid_transform, 1);
|
||||||
|
glDrawArraysInstanced(GL_LINES, 0, 4, 7);
|
||||||
|
|
||||||
|
glUniform1i(location.uniform.use_grid_transform, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void scene_start(XMMATRIX const & transform)
|
void scene_start(XMMATRIX const & transform)
|
||||||
{
|
{
|
||||||
glUseProgram(program);
|
glUseProgram(program);
|
||||||
@ -238,19 +250,15 @@ namespace line_art {
|
|||||||
glBindVertexArray(vertex_array_object);
|
glBindVertexArray(vertex_array_object);
|
||||||
glBindVertexBuffer(0, per_vertex_buffer, 0, per_vertex_size);
|
glBindVertexBuffer(0, per_vertex_buffer, 0, per_vertex_size);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);
|
||||||
|
|
||||||
// grid
|
|
||||||
glLineWidth(1.0f);
|
|
||||||
set_transform(transform);
|
|
||||||
glUniform3f(location.uniform.base_color, 0, 1, 0);
|
|
||||||
glUniform1i(location.uniform.use_grid_transform, 1);
|
|
||||||
glDrawArraysInstanced(GL_LINES, 0, 4, 7);
|
|
||||||
|
|
||||||
glUniform1i(location.uniform.use_grid_transform, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_color(float r, float g, float b)
|
void set_color(float r, float g, float b)
|
||||||
{
|
{
|
||||||
glUniform3f(location.uniform.base_color, r, g, b);
|
glUniform3f(location.uniform.base_color, r, g, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_colorv(XMFLOAT3 const & value)
|
||||||
|
{
|
||||||
|
glUniform3fv(location.uniform.base_color, 1, (float const *)&value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
11
src/test.cpp
11
src/test.cpp
@ -20,6 +20,7 @@
|
|||||||
#include "line_art.h"
|
#include "line_art.h"
|
||||||
#include "collision_scene.h"
|
#include "collision_scene.h"
|
||||||
#include "collision.h"
|
#include "collision.h"
|
||||||
|
#include "boids_scene.h"
|
||||||
|
|
||||||
struct line_location {
|
struct line_location {
|
||||||
struct {
|
struct {
|
||||||
@ -288,6 +289,7 @@ void load(const char * source_path)
|
|||||||
|
|
||||||
line_art::load();
|
line_art::load();
|
||||||
collision_scene::load();
|
collision_scene::load();
|
||||||
|
boids_scene::load();
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_keyboard(int up, int down, int left, int right,
|
void update_keyboard(int up, int down, int left, int right,
|
||||||
@ -298,10 +300,16 @@ void update_keyboard(int up, int down, int left, int right,
|
|||||||
//float forward = (0.1f * up + -0.1f * down);
|
//float forward = (0.1f * up + -0.1f * down);
|
||||||
//float strafe = (-0.1f * left + 0.1f * right);
|
//float strafe = (-0.1f * left + 0.1f * right);
|
||||||
//view::third_person::apply_translation(forward, strafe, 0);
|
//view::third_person::apply_translation(forward, strafe, 0);
|
||||||
|
/*
|
||||||
collision_scene::update(up, down, left, right,
|
collision_scene::update(up, down, left, right,
|
||||||
w, s, a, d,
|
w, s, a, d,
|
||||||
t, g, f, h,
|
t, g, f, h,
|
||||||
i, k, j, l);
|
i, k, j, l);
|
||||||
|
*/
|
||||||
|
boids_scene::update(up, down, left, right,
|
||||||
|
w, s, a, d,
|
||||||
|
t, g, f, h,
|
||||||
|
i, k, j, l);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_collisions(collision::Sphere const & sphere, XMVECTOR const & direction,
|
void check_collisions(collision::Sphere const & sphere, XMVECTOR const & direction,
|
||||||
@ -560,7 +568,8 @@ void draw()
|
|||||||
} else {
|
} else {
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
collision_scene::draw();
|
//collision_scene::draw();
|
||||||
|
boids_scene::draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
last_frame_time = current_time;
|
last_frame_time = current_time;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user