Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Imports UI changes from comp/2024. #268

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions ateam_ui/src/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "ATeam_UI",
"version": "1.0.1",
"description": "Robocup A-Team UI",
"scripts": {
"scripts": {
"configure": "yarn install; (test -d ./bin || neu update)",
"typecheck": "vue-tsc --noEmit",
"dev": "vite --host",
Expand All @@ -15,6 +15,7 @@
"vue": "^3.3.2",
"vuetify": "^3.2.4",
"pixi.js": "^7.2.4",
"pixi-viewport": "^5.0.3",
"roslib": "^1.3.0"
},
"devDependencies": {
Expand All @@ -29,4 +30,4 @@
"vite": "^4.3.5",
"vue-tsc": "^1.6.4"
}
}
}
5 changes: 4 additions & 1 deletion ateam_ui/src/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<v-row class="flex-nowrap">
<v-col v-if="!this.state.comp" class="flex-grow-0 flex-shrink-0">
<RefButtonsComponent/>
<FieldSideComponent/>
</v-col>
<v-col class="flex-grow-0 flex-shrink-0">
<StatusComponent ref="robotStatus"/>
Expand Down Expand Up @@ -51,6 +52,7 @@ import RefButtonsComponent from './components/RefButtonsComponent.vue'
import GameStatusComponent from './components/GameStatusComponent.vue'
import AIComponent from './components/AIComponent.vue'
import PlaybookComponent from './components/PlaybookComponent.vue'
import FieldSideComponent from './components/FieldSideComponent.vue'
import { provide } from 'vue'
import { defineComponent, toRaw } from 'vue'

Expand Down Expand Up @@ -106,7 +108,8 @@ export default {
RefButtonsComponent,
GameStatusComponent,
AIComponent,
PlaybookComponent
PlaybookComponent,
FieldSideComponent
}
}
</script>
1 change: 0 additions & 1 deletion ateam_ui/src/src/components/AIComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import AIRecursiveComponent from "./AIRecursiveComponent.vue";
export default {
inject: ['state'],
mounted() {
console.dir(this.$el)
},
computed: {
getAIDescription: function() {
Expand Down
258 changes: 243 additions & 15 deletions ateam_ui/src/src/components/FieldComponent.vue
Original file line number Diff line number Diff line change
@@ -1,58 +1,286 @@
<template>
<canvas ref="canvas" style="width:100%; height:auto; display:block;"/>
<canvas ref="canvas" style="width:100%; height:auto; display:block;" />
</template>


<script lang="ts">
import { ref, inject } from 'vue';
import { shallowRef, ref, inject } from 'vue';
import * as PIXI from 'pixi.js';
import { Viewport } from 'pixi-viewport'
import { TeamColor } from "@/team"
import { Pose } from 'roslib';

export default {
inject: ['state'],
data() {
return {
pixi: {}
pixi: {},
startDragPoint: null
}
},
mounted() {
// size is based on 140 pixels per meter times the standard max field size including boundaries (13.4 x 10.4m)
// TODO: Make this properly resize itself
const width = 1876;
const height = 1456;
this.pixi = new PIXI.Application({
let pixi = new PIXI.Application({
width: width,
height: height,
background: 'green',
antialias: true,
view: this.$refs.canvas
});

this.pixi = shallowRef(pixi);
this.state.world.field.initializePixi(this.pixi, this.state);

// TODO: clean this up
this.pixi.stage.eventMode = 'static';
this.pixi.stage.hitArea = new PIXI.Rectangle(-width/2, -height/2, width, height);
this.pixi.stage.on("pointerdown", this.onClick);
this.prepareRobotDragging();

this.pixi.stage.eventMode = "static";
this.pixi.stage.on("rightdown", this.onRightDown);
window.addEventListener("keydown", function(event){
if (event.key == "z") {
const viewport = pixi.stage.getChildAt(0) as Viewport;
viewport.setZoom(1, false);
viewport.moveCenter(0, 0);
}
}, false);

},
methods: {
update: function() {
this.state.world.field.update(this.pixi, this.state);
},
onClick: function(event: UIEvent) {
// TODO: Replace this with ball/robot drag code. Currently having an issue where
// enabling event handling on field elements throws an error about not having
// a propagation path
redraw: function() {
this.state.world.field.drawFieldLines(this.pixi.stage.getChildAt(0).getChildByName("fieldLines"), this.state);
this.state.world.field.drawSideIgnoreOverlay(this.pixi.stage.getChildAt(0).getChildByName("fieldUI"), this.state);
},
onRightDown: function(event: MouseEvent) {
const stage = this.pixi.stage;
const viewport = this.pixi.stage.getChildByName("viewport");
const ballVelLine = this.pixi.stage.getChildByName("ballVelLine") as PIXI.Graphics;

this.startDragPoint = new PIXI.Point(event.global.x, event.global.y);
const sdPoint = this.startDragPoint; // so we have access inside the function
const scale = this.state.renderConfig.scale;
const state = this.state;
const defending = this.getDefending;

this.pixi.stage.on("pointermove", this.rightClickDrag);
this.pixi.stage.on("rightup", function(event){
const ballVelText = ballVelLine.getChildByName("ballVelText");
if (ballVelText) {
ballVelLine.removeChild(ballVelText);
}

ballVelLine.clear();
stage.off("pointermove");
stage.off("rightup");

const vec = new PIXI.Point(
sdPoint.x - event.global.x,
sdPoint.y - event.global.y
);

const dist = Math.sqrt(vec.x**2 + vec.y**2);
if (dist / scale < 0.05) {
return;
}

let pos = PIXI.Point;
viewport.toLocal(sdPoint, null, pos);
const simulator_command = {
teleport_ball: [{
pose: {
position: {
x: pos.x * -defending / scale,
y: -pos.y / scale
},
},
twist: {
linear:{
x: 2 * vec.x * -defending / scale,
y: -2 * vec.y / scale,
}
},
roll: true
}],
};

state.sendSimulatorControlPacket(simulator_command);
});



let pos = PIXI.Point;
viewport.toLocal(event.global, null, pos);

this.state.world.ball.pose.position.x = pos.x * -this.getDefending / scale;
this.state.world.ball.pose.position.y = -pos.y / scale;

const simulator_command = {
teleport_ball: [{
pose: this.state.world.ball.pose
}],
};

this.state.sendSimulatorControlPacket(simulator_command);
},
rightClickDrag: function(event) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function seems like it moves the ball to the cursor, and if dragged, draws the ball velocity vector, but it does not seem to update the state

const viewport = this.pixi.stage.getChildAt(0);
const ball_pos = viewport.getChildByName("ball").getChildAt(0).position;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to be unused
Is this deliberate?


const ballVelLine = this.pixi.stage.getChildByName("ballVelLine") as PIXI.Graphics;
ballVelLine.clear();
const oldBallVelText = ballVelLine.getChildByName("ballVelText");
if (oldBallVelText) {
ballVelLine.removeChild(oldBallVelText);
}

let pos = PIXI.Point;
pos = event.global;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest merge with line 139 to reduce confusion


let vec = PIXI.Point;
vec.x = this.startDragPoint.x - pos.x;
vec.y = this.startDragPoint.y - pos.y;

const dist = Math.sqrt(vec.x**2 + vec.y**2);
const scale = this.state.renderConfig.scale;
if (dist / scale < 0.05) {
// Only start the drag routine if you have moved the mouse far enough away from the ball
return;
}

const kick_vel = 2 * dist / scale;

ballVelLine.lineStyle(.08 * scale , "F7F7F750");
ballVelLine.moveTo(this.startDragPoint.x, this.startDragPoint.y);
ballVelLine.lineTo(pos.x, pos.y);

const text = new PIXI.Text(String(kick_vel.toFixed(2)) + " m/s", {
fontSize: 20,
fill: "F7F7F750"
});
text.name = "ballVelText"

text.anchor.set(0.5, 0.5);
text.rotation = -this.state.renderConfig.angle;

text.position.x = this.startDragPoint.x + (0.2 * scale * vec.x / dist);
text.position.y = this.startDragPoint.y + (0.2 * scale * vec.y / dist);

ballVelLine.addChild(text);

},
prepareRobotDragging: function() {
const state = this.state; // fix dumb javascript things
const stage = this.pixi.stage;
const viewport = this.pixi.stage.getChildAt(0);
var defending = this.getDefending;

const robotArray = Object.entries(this.state.world.teams).map(i => { return i[1].robots }).flat()
const robots = viewport.getChildByName("robots").children;
for (let i = 0; i < robotArray.length; i++) {
const robot = robots[i] as PIXI.Container;
robot.on("pointerdown", function(event){
if (!robot.visible) {
return;
}

viewport.pause = true;
state.draggedRobot = i;

stage.on("pointerup", function(event){
viewport.pause = false;
state.draggedRobot = null;

const robot_obj = robotArray[i];
let pos = PIXI.Point;
viewport.toLocal(event.global, null, pos);
const scale = state.renderConfig.scale;

robot_obj.pose.position.x = pos.x * -defending / scale;
robot_obj.pose.position.y = -pos.y / scale;

const simulator_command = {
teleport_robot: [{
id: {
id: [robot_obj.id],
team: [{
color: robot_obj.team == TeamColor.Yellow ? 1 : 2
}]
},
pose: robot_obj.pose,
present: true
}],
};

state.sendSimulatorControlPacket(simulator_command);

stage.off("pointerup");
stage.off("pointermove");
});
stage.on("pointermove", function(event){
viewport.toLocal(event.global, null, robot.position);
});
});
}
}
},
computed: {
getFieldDimensions: function() {
return this.state.world.field.fieldDimensions;
}
},
getDefending: function() {
return this.state.world.teams[this.state.world.team].defending;
},
getIgnoreFieldSide: function() {
return this.state.world.ignore_side * -this.getDefending;
},
getHoverIgnoreSide: function() {
return this.state.hovered_field_ignore_side * -this.getDefending;
},
},
watch: {
getFieldDimensions: {
handler() {
this.state.world.field.drawFieldLines(this.pixi.stage.getChildByName("fieldLines"), this.state);
this.redraw();
},
deep: true
},
getIgnoreFieldSide: {
handler() {
const viewport = this.pixi.stage.getChildByName("viewport");
let ignoreOverlay = viewport.getChildByName("fieldUI").getChildByName("ignoreOverlay");
let hoverOverlay = viewport.getChildByName("fieldUI").getChildByName("hoverOverlay");
hoverOverlay.visible = false;

if (this.state.world.ignore_side == 0) {
ignoreOverlay.visible = false;
} else{
ignoreOverlay.visible = true;
ignoreOverlay.scale.x = this.getIgnoreFieldSide;
}
},
deep: true
},
getHoverIgnoreSide: {
handler() {
const viewport = this.pixi.stage.getChildByName("viewport");
let ignoreOverlay = viewport.getChildByName("fieldUI").getChildByName("ignoreOverlay");
let hoverOverlay = viewport.getChildByName("fieldUI").getChildByName("hoverOverlay");

if (this.state.hovered_field_ignore_side == 0) {
hoverOverlay.visible = false;
if (this.state.world.ignore_side != 0) {
ignoreOverlay.visible = true;
}
} else {
ignoreOverlay.visible = false;
if (this.getIgnoreFieldSide != this.getHoverIgnoreSide) {
hoverOverlay.visible = true;
hoverOverlay.scale.x = this.getHoverIgnoreSide;
}
}
},
deep: true
}
Expand Down
Loading
Loading