I am using processing and I would like to create a game where the player is in a room and if they hit a wall they stop moving like a normal wall. However I don't really have any idea how to do this. With my current method once they hit the wall they can't move on the x axis anymore. Any help would be greatly appreciated.
PVector playerPosition;
PVector barrierPosition;
float velocity = 4;
boolean goLeft=false;
boolean goRight=false;
boolean goUp=false;
boolean goDown=false;
float playerWidth = 10;
float playerHeight = 10;
float barrierWidth = 10;
float barrierHeight = 600;
void setup() {
size(800,600);
rectMode(CORNER);
playerPosition = new PVector(200,200);
barrierPosition = new PVector(0,0);
}
void draw() {
background(255);
drawPlayer();
movePlayerPosition();
drawBarrier();
checkCollide();
}
//check for collision with barrier then stop player moving
void checkCollide() {
if (playerPosition.y <= barrierHeight + playerHeight && playerPosition.x <= barrierWidth + playerWidth)
{
println("COLLIDED");
playerPosition.x = barrierPosition.x + 10;
}
}
void drawPlayer() {
fill(255,0,0);
rect(playerPosition.x,playerPosition.y,playerWidth,playerHeight);
}
void drawBarrier() {
fill(0);
rect(barrierPosition.x,barrierPosition.y,barrierWidth,barrierHeight);
}
void movePlayerPosition() {
//moves up and down
if (goUp && playerPosition.y > 0)
{
playerPosition.y = playerPosition.y - velocity;
} else if (goDown && playerPosition.y < 598-playerHeight)
{
playerPosition.y = playerPosition.y + velocity;
}
//moves right and left
if (goLeft && playerPosition.x > 0)
{
playerPosition.x = playerPosition.x -velocity;
} else if (goRight && playerPosition.x <800-playerWidth)
{
playerPosition.x = playerPosition.x + velocity;
}
}
//if the keys are pressed move in that direction
void keyPressed() {
if (key == 'w') {
goUp=true;
} else if (key == 'a') {
goLeft=true;
} else if (key == 's') {
goDown=true;
} else if (key == 'd') {
goRight=true;
}
}
//if the keys are released stop moving
void keyReleased() {
if (key == 'w') {
goUp=false;
} else if (key == 'a') {
goLeft=false;
} else if (key == 's') {
goDown=false;
} else if (key == 'd') {
goRight=false;
}
}
Simple answer first; Your checkForCollide method should return a boolean instead of been void, then you can use this method with your movePlayerPosition one and only perform the X axis movement when there has been no collision.
Now, in a more complete answer; You should study a little more about the subject, there are a lot of patterns and libraries to better and easier handle this topic.
I recommend you the Nature of code, you can get this pdf for free and you have a lot about the use of physic libraries from chapter 5 and on, also lots of samples about programming games.
Hope this helps and good luck.
Regards Jose
You're so very close!
After this line:
println("COLLIDED");
you set the new coordinates like so:
playerPosition.x = barrierPosition.x + 10;
This means after the first collision takes places, the x position will always be set to barrierPosition.x + 10;
What you probably want to do is move the player by 10 pixels, but relative to it's present position:
playerPosition.x = playerPosition.x + 10;
or:
playerPosition.x += 10;
Have fun!
For reference, your full code with a few characters modified:
PVector playerPosition;
PVector barrierPosition;
float velocity = 4;
boolean goLeft=false;
boolean goRight=false;
boolean goUp=false;
boolean goDown=false;
float playerWidth = 10;
float playerHeight = 10;
float barrierWidth = 10;
float barrierHeight = 600;
void setup() {
size(800,600);
rectMode(CORNER);
playerPosition = new PVector(200,200);
barrierPosition = new PVector(0,0);
}
void draw() {
background(255);
drawPlayer();
movePlayerPosition();
drawBarrier();
checkCollide();
}
//check for collision with barrier then stop player moving
void checkCollide() {
if (playerPosition.y <= barrierHeight + playerHeight && playerPosition.x <= barrierWidth + playerWidth)
{
println("COLLIDED");
playerPosition.x += 10;
}
}
void drawPlayer() {
fill(255,0,0);
rect(playerPosition.x,playerPosition.y,playerWidth,playerHeight);
}
void drawBarrier() {
fill(0);
rect(barrierPosition.x,barrierPosition.y,barrierWidth,barrierHeight);
}
void movePlayerPosition() {
//moves up and down
if (goUp && playerPosition.y > 0)
{
playerPosition.y = playerPosition.y - velocity;
} else if (goDown && playerPosition.y < 598-playerHeight)
{
playerPosition.y = playerPosition.y + velocity;
}
//moves right and left
if (goLeft && playerPosition.x > 0)
{
playerPosition.x = playerPosition.x -velocity;
} else if (goRight && playerPosition.x <800-playerWidth)
{
playerPosition.x = playerPosition.x + velocity;
}
}
//if the keys are pressed move in that direction
void keyPressed() {
if (key == 'w') {
goUp=true;
} else if (key == 'a') {
goLeft=true;
} else if (key == 's') {
goDown=true;
} else if (key == 'd') {
goRight=true;
}
}
//if the keys are released stop moving
void keyReleased() {
if (key == 'w') {
goUp=false;
} else if (key == 'a') {
goLeft=false;
} else if (key == 's') {
goDown=false;
} else if (key == 'd') {
goRight=false;
}
}
Related
I am trying to use a local variable to syncronise among all the work-items in a work-group. However else part on conditional check always fails. Value of d[0] for other work-items does not equals to zero. Why local variable is not visible in the work-group?
I am using AMD APU A12-9800
__kernel void test(__global int *input_vector,__global atomic_int *mem_flag)
{
local int d[32];
if(get_local_id(0)==0) {
d[0] = 100;
}
barrier(CLK_GLOBAL_MEM_FENCE| CLK_LOCAL_MEM_FENCE);
while(1) {
if(get_local_id(0) == 0) {
d[0] = 0;
break;
}
else {
if(d[0] == 0)
break;
}
}
}
as suggested by #alexg I added the barrier along with else condition removed and it worked. Here is the full code
__kernel void test(__global int *input_vector,__global atomic_int *mem_flag)
{
local int d[32];
if(get_local_id(0)==0) {
d[0] = 100;
}
barrier(CLK_GLOBAL_MEM_FENCE| CLK_LOCAL_MEM_FENCE);
while(1) {
mem_fence(CLK_GLOBAL_MEM_FENCE| CLK_LOCAL_MEM_FENCE);
if(d[0] == 0)
break;
if(get_local_id(0) == 0) {
d[0] = 0;
}
}
}
Is there any way to allow the user to interactively resize the columns when headers are hidden?
You can install an event filter on the table's viewport and implement needed behavior manually. Below is a sample implementation.
Header:
#include <QTableView>
class Table_cell_resizer : public QObject {
Q_OBJECT
public:
explicit Table_cell_resizer(QTableView *view = 0);
protected:
bool eventFilter(QObject* object, QEvent* event);
private:
QTableView* m_view;
//max distance between mouse and a cell, small enough to trigger resize
int m_sensibility;
//variables for saving state while dragging
bool m_drag_in_progress;
Qt::Orientation m_drag_orientation;
int m_drag_section;
int m_drag_previous_pos;
// check if mouse_pos is around right or bottom side of a cell
// (depending on orientation)
// and return the index of that cell if found
QModelIndex index_resizable(QPoint mouse_pos, Qt::Orientation orientation);
};
Source:
#include "Table_cell_resizer.h"
#include <QMouseEvent>
#include <QHeaderView>
Table_cell_resizer::Table_cell_resizer(QTableView* view) :
QObject(view), m_view(view)
{
m_view->viewport()->installEventFilter(this);
m_view->viewport()->setMouseTracking(true);
m_sensibility = 5;
m_drag_in_progress = false;
}
bool Table_cell_resizer::eventFilter(QObject* object, QEvent* event) {
if (object == m_view->viewport()) {
QMouseEvent* mouse_event = dynamic_cast<QMouseEvent*>(event);
if (mouse_event) {
if (mouse_event->type() == QEvent::MouseMove) {
if (m_drag_in_progress) { // apply dragging
int delta;
QHeaderView* header_view;
if (m_drag_orientation == Qt::Vertical) {
delta = mouse_event->pos().y() - m_drag_previous_pos;
header_view = m_view->verticalHeader();
m_drag_previous_pos = mouse_event->pos().y();
} else if (m_drag_orientation == Qt::Horizontal) {
delta = mouse_event->pos().x() - m_drag_previous_pos;
header_view = m_view->horizontalHeader();
m_drag_previous_pos = mouse_event->pos().x();
}
//using minimal size = m_sensibility * 2 to prevent collapsing
header_view->resizeSection(m_drag_section,
qMax(m_sensibility * 2, header_view->sectionSize(m_drag_section) + delta));
return true;
} else { // set mouse cursor shape
if (index_resizable(mouse_event->pos(), Qt::Vertical).isValid()) {
m_view->viewport()->setCursor(Qt::SplitVCursor);
} else if (index_resizable(mouse_event->pos(), Qt::Horizontal).isValid()) {
m_view->viewport()->setCursor(Qt::SplitHCursor);
} else {
m_view->viewport()->setCursor(QCursor());
}
}
} else if (mouse_event->type() == QEvent::MouseButtonPress &&
mouse_event->button() == Qt::LeftButton &&
!m_drag_in_progress) { // start dragging
if (index_resizable(mouse_event->pos(), Qt::Vertical).isValid()) {
m_drag_in_progress = true;
m_drag_orientation = Qt::Vertical;
m_drag_previous_pos = mouse_event->y();
m_drag_section = index_resizable(mouse_event->pos(), Qt::Vertical).row();
return true;
} else if (index_resizable(mouse_event->pos(), Qt::Horizontal).isValid()) {
m_drag_in_progress = true;
m_drag_orientation = Qt::Horizontal;
m_drag_previous_pos = mouse_event->x();
m_drag_section = index_resizable(mouse_event->pos(), Qt::Horizontal).column();
return true;
}
} else if (mouse_event->type() == QEvent::MouseButtonRelease &&
mouse_event->button() == Qt::LeftButton &&
m_drag_in_progress) { // stop dragging
m_drag_in_progress = false;
return true;
}
}
}
return false;
}
QModelIndex Table_cell_resizer::index_resizable(QPoint mouse_pos, Qt::Orientation orientation) {
QModelIndex index = m_view->indexAt(mouse_pos - QPoint(m_sensibility + 1, m_sensibility + 1));
if (index.isValid()) {
if (orientation == Qt::Horizontal) {
if (qAbs(m_view->visualRect(index).right() - mouse_pos.x()) < m_sensibility &&
m_view->horizontalHeader()->sectionResizeMode(index.column()) == QHeaderView::Interactive) {
return index;
}
} else {
if (qAbs(m_view->visualRect(index).bottom() - mouse_pos.y()) < m_sensibility &&
m_view->verticalHeader()->sectionResizeMode(index.row()) == QHeaderView::Interactive) {
return index;
}
}
}
return QModelIndex();
}
Usage:
new Table_cell_resizer(ui->table);
User can now resize rows and columns using cell area in addition to header areas. You can hide headers if you wish. This implementation respects header resize modes, so make sure that resize mode is set to QHeaderView::Interactive for headers which you want to be resizable. For example, you can set horizontal header mode to Interactive and vertical header mode to Fixed, resulting in resizable columns and fixed rows.
I'm trying to write button class, one that would switch between on and off states using boolean function.
Switch should happen after if(mousePressed). I can get it to work one way, but I'm lost while trying to get it to switch back to previous state.
When I change one of the if(mousePressed) to if(keyPressed) everything works just fine.
Thank you for your time good Sir.
bclass button;
int offset = 20;
void setup() {
rectMode(CORNERS);
noStroke();
size(300, 100);
button = new bclass(offset, offset, width-offset, height-offset);
}
void draw() {
button.display();
button.state(mouseX, mouseY);
}
class bclass {
float x;
float y;
float w;
float h;
boolean state = false;
bclass(float x_, float y_, float w_, float h_) {
x = x_;
y = y_;
w = w_;
h = h_;
}
void display() {
if (state) {
fill(255, 0, 0);
} else {
fill(0);
}
rect(x, y, w, h);
}
void state(int mx, int my) {
if (!state) {
if (mousePressed) {
if (mx > x && mx < x + w) {
state = true;
}
}
}
if (state) {
if (mousePressed) {
if (mx > x && mx < x + w) {
state = false;
}
}
}
}
}
Change your state method to:
void state(int mx, int my) {
if (mousePressed) {
if (mx > x && mx < x + w) {
state = !state; // change state to opposite value
delay(100); // delay 100ms (mousePressed lasts some millis)
}
}
}
But better solution will be to use Processing's mouseClicked() event:
public void draw() {
button.display();
}
public void mouseClicked() {
button.state(mouseX, mouseY);
}
class bclass {
...
void state(int mx, int my) {
if (mx > x && mx < x + w) {
state = !state;
}
}
}
In this solution button.state() is called only from mouseClicked(), and mouseClicked() is called by Processing when it discovers such event.
I created a custom QLineEdit for timecode (a timecode looks like this : hh:mm:ss:ff) edition.
It react with the keyboard and the mouse. If the user edit the timecode with the mouse (draging up/down a couple of digit) the highlighting is wrong : it select all the characters from the cursor to the end. (ie: If I drag mm the selection will be mm:ss:ff).
In order to get rid of that, I use setSelection(x,2) which select only the wanted digit (verified using qDebug() << selectedText()) but the highlighting is still wrong :
#include "PhTimecodeEdit.h"
PhTimeCodeEdit::PhTimeCodeEdit(QWidget *parent) :
QLineEdit(parent),
_tcType(PhTimeCodeType25)
{
connect(this, SIGNAL(textChanged(QString)), this, SLOT(onTextChanged(QString)));
this->installEventFilter(this);
_mousePressed = false;
_selectedIndex = 0;
}
bool PhTimeCodeEdit::isTimeCode()
{
PhFrame frame;
QString text;
frame = PhTimeCode::frameFromString(this->text(),_tcType);
text = PhTimeCode::stringFromFrame(frame, _tcType);
if(text == this->text())
return true;
else
return false;
}
bool PhTimeCodeEdit::eventFilter(QObject *, QEvent *event)
{
switch (event->type()) {
case QEvent::MouseButtonPress:
_mousePressed = true;
_mousePressedLocation = static_cast<QMouseEvent *>(event)->pos();
if(_mousePressedLocation.x() > 110 and _mousePressedLocation.x() < 145) {
_selectedIndex = 0;
}
else if(_mousePressedLocation.x() > 145 and _mousePressedLocation.x() < 190) {
_selectedIndex = 3;
}
else if(_mousePressedLocation.x() > 190 and _mousePressedLocation.x() < 230) {
_selectedIndex = 6;
}
else if(_mousePressedLocation.x() > 230 and _mousePressedLocation.x() < 270) {
_selectedIndex = 9;
}
return true;
case QEvent::MouseButtonRelease:
_mousePressed = false;
return true;
case QEvent::MouseMove:
{
if(_mousePressed) {
int y = static_cast<QMouseEvent *>(event)->pos().y();
PhFrame currentFrame = PhTimeCode::frameFromString(this->text(), _tcType);
if(_selectedIndex == 0) {
if(_mousePressedLocation.y() > y)
currentFrame += 25 * 60 * 60;
else
currentFrame -= 25 * 60 * 60;
}
else if(_selectedIndex == 3) {
if(_mousePressedLocation.y() > y)
currentFrame += 25 * 60;
else
currentFrame -= 25 * 60;
}
else if(_selectedIndex == 6) {
if(_mousePressedLocation.y() > y)
currentFrame += 25;
else
currentFrame -= 25;
}
else if(_selectedIndex == 9) {
if(_mousePressedLocation.y() > y)
currentFrame++;
else
currentFrame--;
}
_mousePressedLocation.setY(y);
this->setText(PhTimeCode::stringFromFrame(currentFrame, _tcType));
setSelection(_selectedIndex,2);
}
return false;
}
default:
return false;
}
}
What should I do to get it right ?
I'm not sure, but your eventFilter is strange. It conflicts with mouse processing of QLineEdit.
Try to return QLineEdit::eventFilter(); in default section.
You didn't implement mouse tracking. You should disable it with mouse capture and overloading mouse*Event();. Mouse events processing should be disabled while you track manually mouse.
Reason of bug: mouse moving, that processed by QLineEdit overrides text selection that you set in eventFilter. It happens on mouse release.
Possible hotfix (dirty): implement your own slot for set selection and call it via Qt::QueuedConnection. So your direct call of setSelection will be processed after releasing of mouse.
When a parent widget is defined with:
setWindowFlags(Qt::FramelessWindowHint | Qt::Popup);
Any edit box widget placed on top of it will not receive keyboard input. Mouse will work, right click, context menu, paste will work -- but not direct keyboard input. Any ideas why and how it can be fixed?
As I mentioned previously in a comment I had the same problem but now it is fixed with the following code:
// virtual override
void MyDialog::showEvent( QShowEvent* aShowEvent )
{
QDialog::showEvent( aShowEvent );
activateWindow();
}
After I added the activateWindow() function call I could use QLineEdit on my popup dialog.
I use Visual Studio 2013 and Qt 5.4.1 on Windows 8.1.
#include "StdAfx.h"
#include "qfindedit.h"
QFindEdit::QFindEdit(QWidget *parent)
: QLineEdit(parent)
, m_bEditFocus(true)
{
setPlaceholderText("please input find word");
m_stringListmodel = new QStringListModel(this);
m_pFindWnd = new QListView(this);
//m_pFindWnd->setWindowFlags(Qt::Popup);
m_pFindWnd->setEditTriggers(QAbstractItemView::NoEditTriggers);
m_pFindWnd->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_pFindWnd->setSelectionBehavior(QAbstractItemView::SelectRows);
m_pFindWnd->setSelectionMode(QAbstractItemView::SingleSelection);
m_pFindWnd->setParent(0, Qt::Popup);
m_pFindWnd->setFocusPolicy(Qt::NoFocus);
m_pFindWnd->setFocusProxy(this);
connect(this, SIGNAL(textEdited(const QString&)), this, SLOT(textEditedSlot(const QString&)));
QObject::connect(m_pFindWnd, SIGNAL(clicked(QModelIndex)),
this, SLOT(clickedSlot(QModelIndex)));
QObject::connect(this, SIGNAL(activated(QModelIndex)),
m_pFindWnd, SLOT(hide()));
this->installEventFilter(this);
m_pFindWnd->installEventFilter(this);
}
QFindEdit::~QFindEdit()
{
delete m_pFindWnd;
}
QStringList& QFindEdit::stringList()
{
return m_stringList;
}
void QFindEdit::showFindWnd(const QString& text)
{
QStringList sl;
foreach(QString word, m_stringList) {
if (word.contains(text)) {
sl << word;
}
}
if (sl.size() == 0)
{
hideFineWnd();
return;
}
m_stringListmodel->setStringList(sl);
m_pFindWnd->setModel(m_stringListmodel);
m_pFindWnd->resize(rect().width(), 200);
QPoint pTopleft = mapToGlobal(rect().bottomLeft());
m_pFindWnd->move(pTopleft.x(), pTopleft.y());
m_pFindWnd->show();
}
void QFindEdit::textEditedSlot(const QString& text)
{
QString strText = text.trimmed();
if (!strText.isEmpty())
{
showFindWnd(strText);
}
else
{
hideFineWnd();
}
}
void QFindEdit::clickedSlot(QModelIndex modelIndex)
{
setText(m_pFindWnd->model()->data(modelIndex).toString());
hideFineWnd();
}
void QFindEdit::hideFineWnd()
{
m_pFindWnd->hide();
}
bool QFindEdit::eventFilter(QObject *o, QEvent *e)
{
if (m_bEditFocus && (o == this) && e->type() == QEvent::FocusOut)
{
if (m_pFindWnd && m_pFindWnd->isVisible())
return true;
}
if (o != m_pFindWnd)
return __super::eventFilter(o, e);
switch (e->type())
{
case QEvent::KeyPress:
{
QKeyEvent *ke = static_cast<QKeyEvent *>(e);
QModelIndex curIndex = m_pFindWnd->currentIndex();
QModelIndexList selList = m_pFindWnd->selectionModel()->selectedIndexes();
const int key = ke->key();
if ((key == Qt::Key_Up || key == Qt::Key_Down) && selList.isEmpty() && curIndex.isValid() )
{
m_pFindWnd->setCurrentIndex(curIndex);
return true;
}
switch (key)
{
case Qt::Key_End:
case Qt::Key_Home:
if (ke->modifiers() & Qt::ControlModifier)
return false;
break;
case Qt::Key_Up:
if (!curIndex.isValid())
{
int rowCount = m_pFindWnd->model()->rowCount();
QModelIndex lastIndex = m_pFindWnd->model()->index(rowCount - 1, m_pFindWnd->modelColumn());
m_pFindWnd->setCurrentIndex(lastIndex);
return true;
}
else if (curIndex.row() == 0)
{
return true;
}
return false;
case Qt::Key_Down:
if (!curIndex.isValid())
{
QModelIndex firstIndex = m_pFindWnd->model()->index(0, m_pFindWnd->modelColumn());
m_pFindWnd->setCurrentIndex(firstIndex);
return true;
}
else if (curIndex.row() == m_pFindWnd->model()->rowCount() - 1)
{
return true;
}
return false;
}
m_bEditFocus = false;
this->event(ke);
m_bEditFocus = true;
if ( e->isAccepted() || !m_pFindWnd->isVisible()) {
if (!this->hasFocus())
hideFineWnd();
if (e->isAccepted())
return true;
}
switch (key)
{
case Qt::Key_Return:
case Qt::Key_Enter:
case Qt::Key_Tab:
hideFineWnd();
if (curIndex.isValid())
{
QString text = m_pFindWnd->currentIndex().data().toString();
setText(text);
}
break;
case Qt::Key_F4:
if (ke->modifiers() & Qt::AltModifier)
hideFineWnd();
break;
case Qt::Key_Backtab:
case Qt::Key_Escape:
hideFineWnd();
break;
default:
break;
}
return true;
}
case QEvent::MouseButtonPress:
if (!m_pFindWnd->underMouse())
{
hideFineWnd();
return true;
}
return false;
case QEvent::InputMethod:
case QEvent::ShortcutOverride:
QApplication::sendEvent(this, e);
break;
default:
return false;
}
return false;
}
Maybe try activating the window and/or setting widget focus?