Seite 1 von 1

Kollisionsabfrage von QGraphicsItems

Verfasst: 1. März 2007 19:10
von slash-ex
ich bin am überlegen wie ich es am besten hinkriege das gezeichnete Objekte - die ich evtl. mit der Maus bewege - nicht einfach überlagern, falls es nicht erwünscht ist.

Nun habe ich einfach mal probiert ne Positionsabfrage zu machen und gegebenenfalls die Position-koordinaten zurückzusetzen, das finde ich aber dann doch recht aufwändig...

gibt es eine schnelle möglichkeit ein GrphicItem unddurchlässig für andere bildchen zu machen?

Verfasst: 1. März 2007 20:17
von upsala
setZValue

Verfasst: 2. März 2007 13:41
von slash-ex
ich glaube das geht nicht so sehr in den bereich kollisionsabfrage, denn ich will ja verhindern, dass eine spielfigur ein ein objekt reingeschoben wird...

ich werde mal mein problemcode reinstellen...
das ist ein teil der "figur" die klasse ist von QGrphicsItem abgeleitet...

Code: Alles auswählen

void QUnit::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
{
	painter->setPen(Qt::NoPen);
	painter->setBrush(Qt::darkGray);
	//painter->drawEllipse(-7, -7, unit_size, unit_size);		//(-7, -7, 20, 20)

	QRadialGradient gradient(-3, -3, 10);
	if (option->state & QStyle::State_Sunken) 
	{
		gradient.setCenter(3, 3);
		gradient.setFocalPoint(3, 3);
		gradient.setColorAt(1, QColor(Qt::yellow).light(120));
		gradient.setColorAt(0, QColor(Qt::darkYellow).light(120));
	} 
	else 
	{
		gradient.setColorAt(0, Qt::yellow);
		gradient.setColorAt(1, Qt::darkYellow);
	}

	painter->setBrush(gradient);
	painter->setPen(QPen(Qt::black, 0));
	painter->drawEllipse(-10, -10, unit_size, unit_size);		//(-7, -7, 20, 20)

/*
	if(this->collidingItems().size() > 1)
		setFlags(QGraphicsItem::ItemIsSelectable);
	if(this->collidingItems().size() == 0)
		 setFlags(ItemIsSelectable | ItemIsMovable);
*/

	motion_buffer.append(this->pos() );
}

Code: Alles auswählen

QList<QPointF> QUnit::last_pos()
{
	return motion_buffer;
}
das ist das objekt (HAUS; WALD; SONTIGES) bei dem eine kollision überprüft wird...

Code: Alles auswählen

void QArea::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
{
	painter = draw_area(AType, painter);

	QList<QGraphicsItem*> collisions = check_collision();
}

/*this function is reimplemented;
the shape is used for collision detection*/
QPainterPath QArea::shape() const
{
	QPainterPath path;
	path.addRect(-10, -10, width_area, height_area);
	return path;
}

QPainter *QArea::draw_area(AreaType type, QPainter *pntr)
{
	QPainter *painter = pntr;
	painter->setPen(Qt::NoPen);
	painter->setBrush(Qt::darkGray);

	if(type == bunker)
	{
		QRectF rectangle(-7, -7, width_area, height_area);
		painter->drawRect(rectangle);

		QLinearGradient gradient(-7, -7, width_area, height_area);
		gradient.setColorAt(0, QColor(Qt::darkYellow).light(120));
		
		painter->setBrush(gradient);
		painter->setPen(QPen(Qt::black, 0));
		painter->drawRect(-10, -10, width_area, height_area);
		std::cout<<"Draw bunker"<<std::endl;
	}

	return painter;
}

QList<QGraphicsItem*> QArea::check_collision()
{
	QList<QGraphicsItem*> collisions = collidingItems();
	for(int i = 0; i < collisions.size(); i++)
	{
		std::cout<<"collision with: "<<collisions.at(i)<<std::endl;
	}

	if(collisions.size() > 1)
		for(int i = 0; i < collisions.size(); i++)
		{
			//temp item to reset position
			QGraphicsItem *item = collisions.at(i);

/*
			//position of crashing GrphicsItem
			QPointF *position = new QPointF;
			position = &item->pos();

			if(position->rx() >= (this->pos() ).rx() )
			{
				//20 should be the radius of the crashing one
				item->setPos((this->pos()).rx() - 20, position->ry());
				std::cout<<"1.) crashing one moved back horizontally"<<std::endl;
			}

			if(position->rx() <= (this->pos() ).rx() + width_area)
			{
				//20 should be the radius of the crashing one
				item->setPos((this->pos()).rx() + width_area + 20, position->ry());
				std::cout<<"2.) crashing one moved back horizontally"<<std::endl;
			}
*/

			QUnit *UItem = static_cast<QUnit *>(item);
			QList<QPointF> MBuffer = UItem->last_pos();
			std::cout<<MBuffer.size()<<std::endl;
			for(int i = MBuffer.size() - 1; i >= 0; i--)
			{
				UItem->setPos(MBuffer.at(i) );
				std::cout<<"crashing one moving back"<<std::endl;
			}
		}

	return collisions;
}
man sieht die auskommentierten ansätze... ich habe noch nie mit sowas gearbeitet und frage mich wie man sowas am effektivsten macht...

evtl sollte ich an der figur und nicht am hindernis prüfen... aber das müsste eigentlich egal sein?!

Verfasst: 2. März 2007 16:02
von upsala
Achso, du willst eine Kollisionsabfrage... Nimm halt die Default-Klassen, die sollten sowas können oder wandle deine Kontur in eine Pfad um.

Verfasst: 3. März 2007 17:47
von slash-ex
wie meinst du das? ich habe mir gedacht ich speichere die positionsdaten von der figur bei der bewegung in ein array und setz das bei ner kollision schrittweise wieder zurück (d.h. ich mache eine abfrage ab welcher position noch keine kollision stattgefunden hätte)?! ich denke dass würde am schnellsten gehen. aber ich habe noch nie mit GraphicItems gearbeitet und komm nicht so sehr óft zum programmieren, sodass mir auf dem gebiet erfahrungen fehlen.

Verfasst: 4. März 2007 11:31
von upsala
Dann würde ich mich an deiner Stelle ein bißchen in dieses Thema einarbeiten. Hier in diesem Beispiel wird z.B. auch eine Kollisionsabfrage verwendet...

Verfasst: 4. März 2007 11:56
von slash-ex
naja, ich denke ich bin grad dabei mich einzuarbeiten^^ ich mach ja schließlich nur ein übungsspielchen...

danach wollte ich ein bissel netzwerkzeugs und verschlüsselung üben und eine art instant messanger basteln.

das mice-example kenne ich übrigens.. nur das dort lediglich einje kollision abgefragt wird (bool) mit der einfachen funktion und dann die ohren sich umfärben... aber ich habe schon eine idee wie ich das in den griff kriege. wenn ich so weit bin, werde ich mal die auflösung hier reinstellen.
mal sehen ob ich heute mal dran rumbastel... :oops: