Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
123e9751c9 | |||
e1886e850b | |||
088578d34c |
@ -1,119 +0,0 @@
|
|||||||
package com.example.doubledeckerbus;
|
|
||||||
|
|
||||||
import javafx.scene.canvas.GraphicsContext;
|
|
||||||
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
public abstract class AbstractMap {
|
|
||||||
private IDrawingObject _drawingObject = null;
|
|
||||||
protected int[][] _map = null;
|
|
||||||
protected int _width;
|
|
||||||
protected int _height;
|
|
||||||
protected float _size_x;
|
|
||||||
protected float _size_y;
|
|
||||||
protected final Random _random = new Random();
|
|
||||||
protected final int _freeRoad = 0;
|
|
||||||
protected final int _barrier = 1;
|
|
||||||
|
|
||||||
protected GraphicsContext gc;
|
|
||||||
|
|
||||||
public void CreateMap(int width, int height, IDrawingObject drawingObject, GraphicsContext gc)
|
|
||||||
{
|
|
||||||
_width = width;
|
|
||||||
_height = height;
|
|
||||||
_drawingObject = drawingObject;
|
|
||||||
this.gc = gc;
|
|
||||||
GenerateMap();
|
|
||||||
while (!SetObjectOnMap())
|
|
||||||
{
|
|
||||||
GenerateMap();
|
|
||||||
}
|
|
||||||
DrawMapWithObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean SetObjectOnMap()
|
|
||||||
{
|
|
||||||
if (_drawingObject == null || _map == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int x = _random.nextInt(0, 10);
|
|
||||||
int y = _random.nextInt(0, 10);
|
|
||||||
_drawingObject.SetObject(x, y, _width, _height);
|
|
||||||
return !CheckCollision();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawMapWithObject()
|
|
||||||
{
|
|
||||||
if (_drawingObject == null || _map == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < _map.length; ++i)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < _map[0].length; ++j)
|
|
||||||
{
|
|
||||||
if (_map[i][j] == _freeRoad)
|
|
||||||
{
|
|
||||||
DrawRoadPart(i, j);
|
|
||||||
}
|
|
||||||
else if (_map[i][j] == _barrier)
|
|
||||||
{
|
|
||||||
DrawBarrierPart(i, j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_drawingObject.DrawingObject(gc);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void MoveObject(Direction direction)
|
|
||||||
{
|
|
||||||
_drawingObject.MoveObject(direction);
|
|
||||||
if (CheckCollision()) {
|
|
||||||
switch (direction) {
|
|
||||||
case Left -> _drawingObject.MoveObject(Direction.Right);
|
|
||||||
case Right -> _drawingObject.MoveObject(Direction.Left);
|
|
||||||
case Up -> _drawingObject.MoveObject(Direction.Down);
|
|
||||||
case Down -> _drawingObject.MoveObject(Direction.Up);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
DrawMapWithObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean CheckCollision() {
|
|
||||||
var pos = _drawingObject.GetCurrentPosition();
|
|
||||||
int startX = (int)((pos.Left) / _size_x);
|
|
||||||
int endX = (int)((pos.Right) / _size_x);
|
|
||||||
int startY = (int)((pos.Top) / _size_y);
|
|
||||||
int endY = (int)((pos.Bottom) / _size_y);
|
|
||||||
|
|
||||||
if (startX < 0 || startY < 0 || endX > _map[0].length || endY > _map.length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int y = startY; y <= endY + 1; y++)
|
|
||||||
{
|
|
||||||
for (int x = startX; x <= endX + 1; x++)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
if (_map[x][y] == _barrier)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (ArrayIndexOutOfBoundsException e) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected abstract void GenerateMap();
|
|
||||||
protected abstract void DrawRoadPart(int i, int j);
|
|
||||||
protected abstract void DrawBarrierPart(int i, int j);
|
|
||||||
}
|
|
@ -17,40 +17,40 @@ import java.util.Random;
|
|||||||
|
|
||||||
public class ControllerBus {
|
public class ControllerBus {
|
||||||
|
|
||||||
protected DrawingBus _bus;
|
private DrawingBus _bus;
|
||||||
protected ObservableList<Integer> countOfDoors = FXCollections.observableArrayList(3, 4, 5);
|
ObservableList<Integer> countOfDoors = FXCollections.observableArrayList(3, 4, 5);
|
||||||
@FXML
|
@FXML
|
||||||
protected Button buttonCreate;
|
private Button buttonCreate;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
protected Button buttonDown;
|
private Button buttonDown;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
protected Button buttonLeft;
|
private Button buttonLeft;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
protected Button buttonRight;
|
private Button buttonRight;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
protected Button buttonUp;
|
private Button buttonUp;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
protected Canvas canvasBus;
|
private Canvas canvasBus;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
protected AnchorPane pictureBoxBus;
|
private AnchorPane pictureBoxBus;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
protected Label statusColor;
|
private Label statusColor;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
protected Label statusSpeed;
|
private Label statusSpeed;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
protected Label statusWeight;
|
private Label statusWeight;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
protected ChoiceBox<Integer> choiceDoors;
|
private ChoiceBox<Integer> choiceDoors;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
void ButtonCreate_Click(ActionEvent event) {
|
void ButtonCreate_Click(ActionEvent event) {
|
||||||
@ -58,18 +58,14 @@ public class ControllerBus {
|
|||||||
pictureBoxBus.heightProperty().addListener(listener);
|
pictureBoxBus.heightProperty().addListener(listener);
|
||||||
|
|
||||||
Random rnd = new Random();
|
Random rnd = new Random();
|
||||||
_bus = new DrawingBus(rnd.nextInt(100, 300), rnd.nextFloat(1000, 2000),
|
_bus = new DrawingBus();
|
||||||
Color.rgb(rnd.nextInt(256), rnd.nextInt(0, 256), rnd.nextInt(0, 256)), choiceDoors.getValue());
|
_bus.Init(rnd.nextInt(100, 300), rnd.nextFloat(1000, 2000),
|
||||||
_bus.SetPosition(rnd.nextInt(10, 100), rnd.nextInt(10, 100), (int) pictureBoxBus.getWidth(), (int) pictureBoxBus.getHeight());
|
Color.rgb(rnd.nextInt(0, 256), rnd.nextInt(0, 256), rnd.nextInt(0, 256)), choiceDoors.getValue());
|
||||||
BorderChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetData() {
|
|
||||||
Random rnd = new Random();
|
|
||||||
_bus.SetPosition(rnd.nextInt(10, 100), rnd.nextInt(10, 100), (int) pictureBoxBus.getWidth(), (int) pictureBoxBus.getHeight());
|
_bus.SetPosition(rnd.nextInt(10, 100), rnd.nextInt(10, 100), (int) pictureBoxBus.getWidth(), (int) pictureBoxBus.getHeight());
|
||||||
statusSpeed.setText("Скорость: %s".formatted(_bus.Bus.Speed));
|
statusSpeed.setText("Скорость: %s".formatted(_bus.Bus.Speed));
|
||||||
statusWeight.setText("Вес: %s".formatted(_bus.Bus.Weight));
|
statusWeight.setText("Вес: %s".formatted(_bus.Bus.Weight));
|
||||||
statusColor.setText("Цвет: %s".formatted(_bus.Bus.BodyColor));
|
statusColor.setText("Цвет: %s".formatted(_bus.Bus.BodyColor));
|
||||||
|
BorderChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
@ -106,17 +102,4 @@ public class ControllerBus {
|
|||||||
Draw();
|
Draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
|
||||||
private void ButtonCreateExtra_Click(ActionEvent event) {
|
|
||||||
pictureBoxBus.widthProperty().addListener(listener);
|
|
||||||
pictureBoxBus.heightProperty().addListener(listener);
|
|
||||||
Random rnd = new Random();
|
|
||||||
_bus = new DrawingDDB(rnd.nextInt(300), rnd.nextInt(2000),
|
|
||||||
Color.rgb(rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256)),
|
|
||||||
choiceDoors.getValue(),
|
|
||||||
Color.rgb(rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256)),
|
|
||||||
rnd.nextBoolean(), rnd.nextBoolean());
|
|
||||||
SetData();
|
|
||||||
BorderChanged();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,124 +0,0 @@
|
|||||||
package com.example.doubledeckerbus;
|
|
||||||
|
|
||||||
import javafx.collections.FXCollections;
|
|
||||||
import javafx.collections.ObservableList;
|
|
||||||
import javafx.event.ActionEvent;
|
|
||||||
import javafx.fxml.FXML;
|
|
||||||
import javafx.scene.canvas.Canvas;
|
|
||||||
import javafx.scene.canvas.GraphicsContext;
|
|
||||||
import javafx.scene.control.Button;
|
|
||||||
import javafx.scene.control.ChoiceBox;
|
|
||||||
import javafx.scene.control.Label;
|
|
||||||
import javafx.scene.layout.AnchorPane;
|
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
public class ControllerMap{
|
|
||||||
private AbstractMap _abstractMap;
|
|
||||||
protected ObservableList<Integer> countOfDoors = FXCollections.observableArrayList(3, 4, 5);
|
|
||||||
protected ObservableList<String> countOfMap = FXCollections.observableArrayList("Простая карта", "Водная карта");
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private ChoiceBox<String> choiceMap;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
protected Button buttonCreate;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
protected Button buttonDown;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
protected Button buttonLeft;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
protected Button buttonRight;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
protected Button buttonUp;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
protected Canvas canvasBus;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
protected AnchorPane pictureBoxBus;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
protected Label statusColor;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
protected Label statusSpeed;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
protected Label statusWeight;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
protected ChoiceBox<Integer> choiceDoors;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
void ButtonCreate_Click(ActionEvent event) {
|
|
||||||
BorderChanged();
|
|
||||||
Random rnd = new Random();
|
|
||||||
var bus = new DrawingBus(rnd.nextInt(100, 300), rnd.nextFloat(1000, 2000),
|
|
||||||
Color.rgb(rnd.nextInt(256), rnd.nextInt(0, 256), rnd.nextInt(0, 256)),
|
|
||||||
choiceDoors.getValue());
|
|
||||||
SetData(bus);
|
|
||||||
}
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
public void initialize() {
|
|
||||||
choiceDoors.setItems(countOfDoors);
|
|
||||||
choiceDoors.setValue(countOfDoors.get(0));
|
|
||||||
choiceMap.setItems(countOfMap);
|
|
||||||
choiceMap.setValue(countOfMap.get(0));
|
|
||||||
|
|
||||||
_abstractMap = new SimpleMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
void ButtonCreateExtra_Click() {
|
|
||||||
canvasBus.setWidth(pictureBoxBus.getWidth());
|
|
||||||
canvasBus.setHeight(pictureBoxBus.getHeight());
|
|
||||||
Random rnd = new Random();
|
|
||||||
var bus = new DrawingDDB(rnd.nextInt(300), rnd.nextInt(2000),
|
|
||||||
Color.rgb(rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256)),
|
|
||||||
choiceDoors.getValue(),
|
|
||||||
Color.rgb(rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256)),
|
|
||||||
rnd.nextBoolean(), rnd.nextBoolean());
|
|
||||||
SetData(bus);
|
|
||||||
}
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
void ButtonMove_Click(ActionEvent event) {
|
|
||||||
String name = ((Button) event.getSource()).getId();
|
|
||||||
Direction dir = Direction.None;
|
|
||||||
switch (name) {
|
|
||||||
case "buttonUp" -> dir = Direction.Up;
|
|
||||||
case "buttonDown" -> dir = Direction.Down;
|
|
||||||
case "buttonLeft" -> dir = Direction.Left;
|
|
||||||
case "buttonRight" -> dir = Direction.Right;
|
|
||||||
}
|
|
||||||
_abstractMap.MoveObject(dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BorderChanged() {
|
|
||||||
canvasBus.setWidth(pictureBoxBus.getWidth());
|
|
||||||
canvasBus.setHeight(pictureBoxBus.getHeight());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetData(DrawingBus bus)
|
|
||||||
{
|
|
||||||
statusSpeed.setText("Скорость: %s".formatted(bus.Bus.Speed));
|
|
||||||
statusWeight.setText("Вес: %s".formatted(bus.Bus.Weight));
|
|
||||||
statusColor.setText("Цвет: %s".formatted(bus.Bus.BodyColor));
|
|
||||||
GraphicsContext gc = canvasBus.getGraphicsContext2D();
|
|
||||||
|
|
||||||
switch (choiceMap.getValue()) {
|
|
||||||
case "Простая карта" -> _abstractMap = new SimpleMap();
|
|
||||||
case "Водная карта" -> _abstractMap = new WaterMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
_abstractMap.CreateMap((int) pictureBoxBus.getWidth(), (int) pictureBoxBus.getHeight(),
|
|
||||||
new DrawingObjectBus(bus), gc);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
package com.example.doubledeckerbus;
|
package com.example.doubledeckerbus;
|
||||||
|
|
||||||
public enum Direction {
|
public enum Direction {
|
||||||
None(0),
|
|
||||||
Up(1),
|
Up(1),
|
||||||
Down(2),
|
Down(2),
|
||||||
Left(3),
|
Left(3),
|
||||||
|
@ -3,43 +3,38 @@ package com.example.doubledeckerbus;
|
|||||||
import javafx.scene.canvas.GraphicsContext;
|
import javafx.scene.canvas.GraphicsContext;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
public class DrawingBus {
|
public class DrawingBus {
|
||||||
public EntityBus Bus;
|
public EntityBus Bus;
|
||||||
|
|
||||||
public IDrawingDoors Doors;
|
public DrawingDoors Doors;
|
||||||
|
|
||||||
public EntityBus getBus() {
|
public EntityBus getBus() {
|
||||||
return Bus;
|
return Bus;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int _null = -1000;
|
private static final int _null = -1000;
|
||||||
protected float _startPosX;
|
private float _startPosX;
|
||||||
protected float _startPosY;
|
private float _startPosY;
|
||||||
private int _pictureWidth;
|
private int _pictureWidth;
|
||||||
private int _pictureHeight;
|
private int _pictureHeight;
|
||||||
private static final int _busWidth = 100;
|
private static final int _busWidth = 100;
|
||||||
private static final int _busHeight = 50;
|
private static final int _busHeight = 50;
|
||||||
|
|
||||||
public DrawingBus(int speed, float weight, Color bodyColor, int countOfDoors) {
|
public void Init(int speed, float weight, Color bodyColor, int countOfDoors) {
|
||||||
Bus = new EntityBus(speed, weight, bodyColor);
|
Bus = new EntityBus();
|
||||||
switch (new Random().nextInt(3)) {
|
Bus.Init(speed, weight, bodyColor);
|
||||||
case 0 -> Doors = new DrawingTriangleDoors();
|
Doors = new DrawingDoors();
|
||||||
case 1 -> Doors = new DrawingDoors();
|
|
||||||
case 2 -> Doors = new DrawingEllipsoidDoors();
|
|
||||||
}
|
|
||||||
Doors.setCountOfDoors(countOfDoors);
|
Doors.setCountOfDoors(countOfDoors);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetPosition(int x, int y, int width, int height) {
|
public void SetPosition(int x, int y, int width, int height) {
|
||||||
if (width <= _busWidth || height <= _busHeight) {
|
if (x < 0 || y < 0) return;
|
||||||
|
|
||||||
|
if (_pictureWidth <= _busWidth || _pictureHeight <= _busHeight) {
|
||||||
_pictureWidth = _null;
|
_pictureWidth = _null;
|
||||||
_pictureHeight = _null;
|
_pictureHeight = _null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_startPosX = x;
|
_startPosX = x;
|
||||||
_startPosY = y;
|
_startPosY = y;
|
||||||
_pictureWidth = width;
|
_pictureWidth = width;
|
||||||
@ -88,6 +83,7 @@ public class DrawingBus {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gc.clearRect(0, 0, _pictureWidth, _pictureHeight);
|
||||||
gc.setFill(Bus.BodyColor);
|
gc.setFill(Bus.BodyColor);
|
||||||
gc.fillRect(_startPosX, _startPosY + 10, 100, 30);
|
gc.fillRect(_startPosX, _startPosY + 10, 100, 30);
|
||||||
|
|
||||||
@ -125,8 +121,4 @@ public class DrawingBus {
|
|||||||
_startPosY = _pictureHeight - _busHeight;
|
_startPosY = _pictureHeight - _busHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Position GetCurrentPosition() {
|
|
||||||
return new Position(_startPosX, _startPosX + _busWidth, _startPosY, _startPosY + _busHeight);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
package com.example.doubledeckerbus;
|
|
||||||
|
|
||||||
import javafx.scene.canvas.GraphicsContext;
|
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
|
|
||||||
public class DrawingDDB extends DrawingBus{
|
|
||||||
public DrawingDDB(int speed, float weight, Color bodyColor, int countOfDoors, Color extraColor, boolean ladder, boolean secondStage) {
|
|
||||||
super(speed, weight, bodyColor, countOfDoors);
|
|
||||||
Bus = new EntityDDB(speed, weight, bodyColor, extraColor, ladder, secondStage);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void DrawTransport(GraphicsContext gc)
|
|
||||||
{
|
|
||||||
if (Bus == null) return;
|
|
||||||
|
|
||||||
_startPosY += 30;
|
|
||||||
super.DrawTransport(gc);
|
|
||||||
_startPosY -= 30;
|
|
||||||
EntityDDB ddb = (EntityDDB) Bus;
|
|
||||||
|
|
||||||
gc.setFill(ddb.ExtraColor);
|
|
||||||
if (ddb.SecondStage) {
|
|
||||||
gc.fillRect(_startPosX, _startPosY + 10, 100, 30);
|
|
||||||
gc.setFill(Color.BLACK);
|
|
||||||
gc.fillRect(_startPosX + 30, _startPosY + 20, 10, 20);
|
|
||||||
|
|
||||||
gc.setFill(Color.BLUE);
|
|
||||||
gc.fillOval(_startPosX + 10, _startPosY + 15, 10, 15);
|
|
||||||
gc.fillOval(_startPosX + 50, _startPosY + 15, 10, 15);
|
|
||||||
gc.fillOval(_startPosX + 70, _startPosY + 15, 10, 15);
|
|
||||||
gc.fillOval(_startPosX + 90, _startPosY + 15, 10, 15);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ddb.Ladder) {
|
|
||||||
gc.strokeLine(_startPosX, _startPosY + 70, _startPosX, _startPosY + 10);
|
|
||||||
gc.strokeLine(_startPosX + 10, _startPosY + 70, _startPosX + 10, _startPosY + 10);
|
|
||||||
|
|
||||||
gc.strokeLine(_startPosX, _startPosY + 20, _startPosX + 10, _startPosY + 20);
|
|
||||||
gc.strokeLine(_startPosX, _startPosY + 30, _startPosX + 10, _startPosY + 30);
|
|
||||||
gc.strokeLine(_startPosX, _startPosY + 40, _startPosX + 10, _startPosY + 40);
|
|
||||||
gc.strokeLine(_startPosX, _startPosY + 50, _startPosX + 10, _startPosY + 50);
|
|
||||||
gc.strokeLine(_startPosX, _startPosY + 60, _startPosX + 10, _startPosY + 60);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,11 +3,10 @@ package com.example.doubledeckerbus;
|
|||||||
import javafx.scene.canvas.GraphicsContext;
|
import javafx.scene.canvas.GraphicsContext;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
|
|
||||||
public class DrawingDoors implements IDrawingDoors {
|
public class DrawingDoors {
|
||||||
private CountOfDoors _countOfDoors;
|
private CountOfDoors _countOfDoors;
|
||||||
|
|
||||||
@Override
|
public void DrawDoors(GraphicsContext gc, int _startPosX, int _startPosY) {
|
||||||
public void DrawDoors(GraphicsContext gc, float _startPosX, float _startPosY) {
|
|
||||||
gc.setFill(Color.BLACK);
|
gc.setFill(Color.BLACK);
|
||||||
gc.fillRect(_startPosX, _startPosY + 20, 10, 20);
|
gc.fillRect(_startPosX, _startPosY + 20, 10, 20);
|
||||||
gc.fillRect(_startPosX + 20, _startPosY + 20, 10, 20);
|
gc.fillRect(_startPosX + 20, _startPosY + 20, 10, 20);
|
||||||
@ -20,13 +19,13 @@ public class DrawingDoors implements IDrawingDoors {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void setCountOfDoors(int number) {
|
||||||
public void setCountOfDoors(int count) {
|
|
||||||
for (CountOfDoors item: CountOfDoors.values()) {
|
for (CountOfDoors item: CountOfDoors.values()) {
|
||||||
if (item.getId() == count) {
|
if (item.getId() == number) {
|
||||||
_countOfDoors = item;
|
_countOfDoors = item;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
package com.example.doubledeckerbus;
|
|
||||||
|
|
||||||
import javafx.scene.canvas.GraphicsContext;
|
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
|
|
||||||
public class DrawingEllipsoidDoors implements IDrawingDoors{
|
|
||||||
private CountOfDoors _countOfDoors;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void DrawDoors(GraphicsContext gc, float _startPosX, float _startPosY) {
|
|
||||||
gc.setFill(Color.GRAY);
|
|
||||||
gc.fillOval(_startPosX, _startPosY + 20, 10, 20);
|
|
||||||
gc.fillOval(_startPosX + 20, _startPosY + 20, 10, 20);
|
|
||||||
gc.fillOval(_startPosX + 40, _startPosY + 20, 10, 20);
|
|
||||||
if (_countOfDoors.getId() >= 4) {
|
|
||||||
gc.fillOval(_startPosX + 60, _startPosY + 20, 10, 20);
|
|
||||||
}
|
|
||||||
if (_countOfDoors.getId() >= 5) {
|
|
||||||
gc.fillOval(_startPosX + 80, _startPosY + 20, 10, 20);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setCountOfDoors(int count) {
|
|
||||||
for (CountOfDoors item: CountOfDoors.values()) {
|
|
||||||
if (item.getId() == count) {
|
|
||||||
_countOfDoors = item;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
package com.example.doubledeckerbus;
|
|
||||||
|
|
||||||
import javafx.scene.canvas.GraphicsContext;
|
|
||||||
|
|
||||||
public class DrawingObjectBus implements IDrawingObject {
|
|
||||||
private DrawingBus _bus = null;
|
|
||||||
|
|
||||||
public DrawingObjectBus(DrawingBus bus)
|
|
||||||
{
|
|
||||||
_bus = bus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float Step() {
|
|
||||||
if (_bus != null && _bus.Bus != null) {
|
|
||||||
return _bus.Bus.Step;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Position GetCurrentPosition()
|
|
||||||
{
|
|
||||||
if (_bus != null) {
|
|
||||||
return _bus.GetCurrentPosition();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void MoveObject(Direction direction)
|
|
||||||
{
|
|
||||||
_bus.MoveTransport(direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetObject(int x, int y, int width, int height)
|
|
||||||
{
|
|
||||||
_bus.SetPosition(x, y, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DrawingObject(GraphicsContext gc)
|
|
||||||
{
|
|
||||||
_bus.DrawTransport(gc);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
package com.example.doubledeckerbus;
|
|
||||||
|
|
||||||
import javafx.scene.canvas.GraphicsContext;
|
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
|
|
||||||
public class DrawingTriangleDoors implements IDrawingDoors{
|
|
||||||
private CountOfDoors _countOfDoors;
|
|
||||||
|
|
||||||
public void FillTriangle(GraphicsContext gc, float x, float y) {
|
|
||||||
gc.fillPolygon(new double[] {(double) x, (double) (x + 5), (double) (x + 10)},
|
|
||||||
new double[] {(double) y + 20, (double) (y), (double) y + 20}, 3) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void DrawDoors(GraphicsContext gc, float _startPosX, float _startPosY) {
|
|
||||||
gc.setFill(Color.BLUE);
|
|
||||||
FillTriangle(gc, _startPosX, _startPosY + 20);
|
|
||||||
FillTriangle(gc,_startPosX + 20, _startPosY + 20);
|
|
||||||
FillTriangle(gc,_startPosX + 40, _startPosY + 20);
|
|
||||||
if (_countOfDoors.getId() >= 4) {
|
|
||||||
FillTriangle(gc, _startPosX + 60, _startPosY + 20);
|
|
||||||
}
|
|
||||||
if (_countOfDoors.getId() >= 5) {
|
|
||||||
FillTriangle(gc, _startPosX + 80, _startPosY + 20);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setCountOfDoors(int count) {
|
|
||||||
for (CountOfDoors item: CountOfDoors.values()) {
|
|
||||||
if (item.getId() == count) {
|
|
||||||
_countOfDoors = item;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,7 +10,7 @@ public class EntityBus {
|
|||||||
public Color BodyColor;
|
public Color BodyColor;
|
||||||
public float Step;
|
public float Step;
|
||||||
|
|
||||||
public EntityBus(int speed, float weight, Color bodyColor)
|
public void Init(int speed, float weight, Color bodyColor)
|
||||||
{
|
{
|
||||||
Random rnd = new Random();
|
Random rnd = new Random();
|
||||||
Speed = (speed <= 0) ? rnd.nextInt(50, 150): speed;
|
Speed = (speed <= 0) ? rnd.nextInt(50, 150): speed;
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
package com.example.doubledeckerbus;
|
|
||||||
|
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
|
|
||||||
public class EntityDDB extends EntityBus {
|
|
||||||
|
|
||||||
public Color ExtraColor;
|
|
||||||
|
|
||||||
public boolean Ladder;
|
|
||||||
|
|
||||||
public boolean SecondStage;
|
|
||||||
|
|
||||||
|
|
||||||
private void setExtraColor(Color extraColor) {
|
|
||||||
ExtraColor = extraColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setLadder(boolean ladder) {
|
|
||||||
Ladder = ladder;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setSecondStage(boolean secondStage) {
|
|
||||||
SecondStage = secondStage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EntityDDB(int speed, float height, Color bodyColor, Color extraColor, boolean ladder, boolean secondStage)
|
|
||||||
{
|
|
||||||
super(speed, height, bodyColor);
|
|
||||||
ExtraColor = extraColor;
|
|
||||||
Ladder = ladder;
|
|
||||||
SecondStage = secondStage;
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,7 +10,7 @@ import java.io.IOException;
|
|||||||
public class Form extends Application {
|
public class Form extends Application {
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage stage) throws IOException {
|
public void start(Stage stage) throws IOException {
|
||||||
FXMLLoader fxmlLoader = new FXMLLoader(Form.class.getResource("FormMap.fxml"));
|
FXMLLoader fxmlLoader = new FXMLLoader(Form.class.getResource("hello-view.fxml"));
|
||||||
Scene scene = new Scene(fxmlLoader.load());
|
Scene scene = new Scene(fxmlLoader.load());
|
||||||
stage.setTitle("DoubleDeckerBus");
|
stage.setTitle("DoubleDeckerBus");
|
||||||
stage.setScene(scene);
|
stage.setScene(scene);
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
package com.example.doubledeckerbus;
|
|
||||||
|
|
||||||
import javafx.scene.canvas.GraphicsContext;
|
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
|
|
||||||
public interface IDrawingDoors {
|
|
||||||
void DrawDoors(GraphicsContext gc, float _startPosX, float _startPosY);
|
|
||||||
void setCountOfDoors(int count);
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
package com.example.doubledeckerbus;
|
|
||||||
|
|
||||||
import javafx.scene.canvas.GraphicsContext;
|
|
||||||
|
|
||||||
public interface IDrawingObject {
|
|
||||||
float Step = -1;
|
|
||||||
|
|
||||||
void SetObject(int x, int y, int width, int height);
|
|
||||||
|
|
||||||
void MoveObject(Direction direction);
|
|
||||||
|
|
||||||
void DrawingObject(GraphicsContext g);
|
|
||||||
|
|
||||||
Position GetCurrentPosition();
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
package com.example.doubledeckerbus;
|
|
||||||
|
|
||||||
public class Position {
|
|
||||||
public float Left;
|
|
||||||
public float Right;
|
|
||||||
public float Top;
|
|
||||||
public float Bottom;
|
|
||||||
|
|
||||||
public Position (float left, float right, float top, float bottom) {
|
|
||||||
Left = left;
|
|
||||||
Right = right;
|
|
||||||
Top = top;
|
|
||||||
Bottom = bottom;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
package com.example.doubledeckerbus;
|
|
||||||
|
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
|
|
||||||
public class SimpleMap extends AbstractMap{
|
|
||||||
@Override
|
|
||||||
protected void GenerateMap() {
|
|
||||||
_map = new int[100][100];
|
|
||||||
_size_x = (float)_width / _map.length;
|
|
||||||
_size_y = (float)_height / _map[0].length;
|
|
||||||
|
|
||||||
for (int i = 0; i < _map.length; ++i)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < _map[0].length; ++j)
|
|
||||||
{
|
|
||||||
_map[i][j] = _freeRoad;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int counter = 0;
|
|
||||||
while (counter < 50)
|
|
||||||
{
|
|
||||||
int x = _random.nextInt(0, 100);
|
|
||||||
int y = _random.nextInt(0, 100);
|
|
||||||
if (_map[x][y] == _freeRoad)
|
|
||||||
{
|
|
||||||
_map[x][y] = _barrier;
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void DrawRoadPart(int i, int j) {
|
|
||||||
gc.setFill(Color.GRAY);
|
|
||||||
gc.fillRect(i * _size_x, j * _size_y, i * (_size_x + 1), j * (_size_y + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void DrawBarrierPart(int i, int j) {
|
|
||||||
gc.setFill(Color.BLACK);
|
|
||||||
gc.fillRect(i * _size_x, j * _size_y, i * (_size_x + 1), j * (_size_y + 1));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
package com.example.doubledeckerbus;
|
|
||||||
|
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
|
|
||||||
public class WaterMap extends AbstractMap{
|
|
||||||
@Override
|
|
||||||
protected void GenerateMap() {
|
|
||||||
_map = new int[100][100];
|
|
||||||
_size_x = (float)_width / _map.length;
|
|
||||||
_size_y = (float)_height / _map[0].length;
|
|
||||||
|
|
||||||
for (int i = 0; i < _map.length; ++i)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < _map[0].length; ++j)
|
|
||||||
{
|
|
||||||
_map[i][j] = _freeRoad;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int counter = 0;
|
|
||||||
while (counter < 50)
|
|
||||||
{
|
|
||||||
int x = _random.nextInt(0, 100);
|
|
||||||
int y = _random.nextInt(0, 100);
|
|
||||||
if (_map[x][y] == _freeRoad)
|
|
||||||
{
|
|
||||||
_map[x][y] = _barrier;
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void DrawRoadPart(int i, int j) {
|
|
||||||
if (_random.nextInt(0,20) == 9) {
|
|
||||||
gc.setFill(Color.GREEN);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
gc.setFill(Color.LIGHTGREEN);
|
|
||||||
}
|
|
||||||
gc.fillRect(i * _size_x, j * _size_y, i * (_size_x + 1), j * (_size_y + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void DrawBarrierPart(int i, int j) {
|
|
||||||
gc.setFill(Color.BLUE);
|
|
||||||
gc.fillRect(i * _size_x, j * _size_y, i * (_size_x + 1), j * (_size_y + 1));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<?import javafx.geometry.Insets?>
|
|
||||||
<?import javafx.scene.canvas.Canvas?>
|
|
||||||
<?import javafx.scene.control.Button?>
|
|
||||||
<?import javafx.scene.control.ChoiceBox?>
|
|
||||||
<?import javafx.scene.control.Label?>
|
|
||||||
<?import javafx.scene.image.Image?>
|
|
||||||
<?import javafx.scene.image.ImageView?>
|
|
||||||
<?import javafx.scene.layout.AnchorPane?>
|
|
||||||
<?import javafx.scene.layout.ColumnConstraints?>
|
|
||||||
<?import javafx.scene.layout.GridPane?>
|
|
||||||
<?import javafx.scene.layout.HBox?>
|
|
||||||
<?import javafx.scene.layout.RowConstraints?>
|
|
||||||
|
|
||||||
<GridPane alignment="CENTER" prefHeight="758.0" prefWidth="1166.0" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.doubledeckerbus.ControllerMap">
|
|
||||||
<columnConstraints>
|
|
||||||
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" percentWidth="100.0" />
|
|
||||||
</columnConstraints>
|
|
||||||
<rowConstraints>
|
|
||||||
<RowConstraints fillHeight="false" maxHeight="1.7976931348623157E308" percentHeight="90.0" vgrow="ALWAYS" />
|
|
||||||
<RowConstraints fillHeight="false" maxHeight="-Infinity" minHeight="-Infinity" percentHeight="10.0" prefHeight="31.0" vgrow="NEVER" />
|
|
||||||
</rowConstraints>
|
|
||||||
<children>
|
|
||||||
<HBox alignment="CENTER_LEFT" prefHeight="57.0" prefWidth="777.0" spacing="20.0" GridPane.rowIndex="1">
|
|
||||||
<children>
|
|
||||||
<Label fx:id="statusSpeed" text="Скорость:" />
|
|
||||||
<Label fx:id="statusWeight" text="Вес:" />
|
|
||||||
<Label fx:id="statusColor" text="Цвет:" />
|
|
||||||
<Label text="Колл-во дверей:" />
|
|
||||||
<ChoiceBox fx:id="choiceDoors" prefHeight="24.0" prefWidth="58.0" />
|
|
||||||
</children>
|
|
||||||
</HBox>
|
|
||||||
<AnchorPane fx:id="pictureBoxBus" maxHeight="2000000.0" maxWidth="2000000.0" minHeight="0.0" minWidth="0.0" prefHeight="2000000.0" prefWidth="2000000.0">
|
|
||||||
<children>
|
|
||||||
<Canvas fx:id="canvasBus" layoutY="38.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
|
||||||
<Button fx:id="buttonLeft" layoutX="975.0" layoutY="427.0" mnemonicParsing="false" onAction="#ButtonMove_Click" prefHeight="0.0" prefWidth="0.0" AnchorPane.bottomAnchor="40.0" AnchorPane.rightAnchor="60.0">
|
|
||||||
<graphic>
|
|
||||||
<ImageView fitHeight="27.0" fitWidth="10.0" pickOnBounds="true" preserveRatio="true">
|
|
||||||
<image>
|
|
||||||
<Image url="@images/LeftArrow.png" />
|
|
||||||
</image>
|
|
||||||
</ImageView>
|
|
||||||
</graphic></Button>
|
|
||||||
<Button fx:id="buttonDown" layoutX="1005.0" layoutY="457.0" mnemonicParsing="false" onAction="#ButtonMove_Click" prefHeight="0.0" prefWidth="0.0" AnchorPane.bottomAnchor="10.0" AnchorPane.rightAnchor="30.0">
|
|
||||||
<graphic>
|
|
||||||
<ImageView fitHeight="27.0" fitWidth="10.0" pickOnBounds="true" preserveRatio="true">
|
|
||||||
<image>
|
|
||||||
<Image url="@images/DownArrow.png" />
|
|
||||||
</image>
|
|
||||||
</ImageView>
|
|
||||||
</graphic></Button>
|
|
||||||
<Button fx:id="buttonRight" layoutX="1035.0" layoutY="427.0" mnemonicParsing="false" onAction="#ButtonMove_Click" prefHeight="0.0" prefWidth="0.0" AnchorPane.bottomAnchor="40.0" AnchorPane.rightAnchor="0.0">
|
|
||||||
<graphic>
|
|
||||||
<ImageView fitHeight="27.0" fitWidth="10.0" pickOnBounds="true" preserveRatio="true">
|
|
||||||
<image>
|
|
||||||
<Image url="@images/RightArrow.png" />
|
|
||||||
</image>
|
|
||||||
</ImageView>
|
|
||||||
</graphic></Button>
|
|
||||||
<Button fx:id="buttonUp" layoutX="1005.0" layoutY="397.0" mnemonicParsing="false" onAction="#ButtonMove_Click" prefHeight="0.0" prefWidth="0.0" AnchorPane.bottomAnchor="70.0" AnchorPane.rightAnchor="30.0">
|
|
||||||
<graphic>
|
|
||||||
<ImageView fitHeight="27.0" fitWidth="10.0" pickOnBounds="true" preserveRatio="true">
|
|
||||||
<image>
|
|
||||||
<Image url="@images/UpArrow.png" />
|
|
||||||
</image>
|
|
||||||
</ImageView>
|
|
||||||
</graphic></Button>
|
|
||||||
<Button fx:id="buttonCreate" layoutY="455.0" mnemonicParsing="false" onAction="#ButtonCreate_Click" text="Создать" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="0.0" />
|
|
||||||
<ChoiceBox fx:id="choiceMap" layoutY="2.0" prefWidth="150.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="2.0" />
|
|
||||||
<Button layoutX="82.0" layoutY="565.0" mnemonicParsing="false" onAction="#ButtonCreateExtra_Click" text="Продвинутый объект" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="82.0" />
|
|
||||||
</children>
|
|
||||||
</AnchorPane>
|
|
||||||
</children>
|
|
||||||
<padding>
|
|
||||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
|
|
||||||
</padding>
|
|
||||||
</GridPane>
|
|
@ -27,8 +27,8 @@
|
|||||||
<Label fx:id="statusSpeed" text="Скорость:" />
|
<Label fx:id="statusSpeed" text="Скорость:" />
|
||||||
<Label fx:id="statusWeight" text="Вес:" />
|
<Label fx:id="statusWeight" text="Вес:" />
|
||||||
<Label fx:id="statusColor" text="Цвет:" />
|
<Label fx:id="statusColor" text="Цвет:" />
|
||||||
<Label text="Колл-во дверей:" />
|
<Label text="Колл-во дверей:" />
|
||||||
<ChoiceBox fx:id="choiceDoors" prefHeight="24.0" prefWidth="58.0" />
|
<ChoiceBox fx:id="choiceDoors" prefHeight="24.0" prefWidth="58.0" />
|
||||||
</children>
|
</children>
|
||||||
</HBox>
|
</HBox>
|
||||||
<AnchorPane fx:id="pictureBoxBus" maxHeight="2000000.0" maxWidth="2000000.0" minHeight="0.0" minWidth="0.0" prefHeight="603.0" prefWidth="1020.0">
|
<AnchorPane fx:id="pictureBoxBus" maxHeight="2000000.0" maxWidth="2000000.0" minHeight="0.0" minWidth="0.0" prefHeight="603.0" prefWidth="1020.0">
|
||||||
@ -67,7 +67,6 @@
|
|||||||
</ImageView>
|
</ImageView>
|
||||||
</graphic></Button>
|
</graphic></Button>
|
||||||
<Button fx:id="buttonCreate" layoutY="455.0" mnemonicParsing="false" onAction="#ButtonCreate_Click" text="Создать" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="0.0" />
|
<Button fx:id="buttonCreate" layoutY="455.0" mnemonicParsing="false" onAction="#ButtonCreate_Click" text="Создать" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="0.0" />
|
||||||
<Button fx:id="buttonCreateExtra" layoutX="82.0" layoutY="565.0" mnemonicParsing="false" onAction="#ButtonCreateExtra_Click" text="Продвинутый объект" />
|
|
||||||
</children>
|
</children>
|
||||||
</AnchorPane>
|
</AnchorPane>
|
||||||
</children>
|
</children>
|
Loading…
Reference in New Issue
Block a user