Archief - Java paint op Icon?

Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.

Curahee Q

Legacy Member
Beste 9livers

Voor school moeten wij een spelletje maken en ik heb gekozen voor een kleine RPG. Nu moeten wij wel een voorgemaakte klasse gebruiken van de proffen zelf.

Het systeem erachter is dat dit een grid is (GridLayout) met allemaal JLabels op. Om dan een vak te voorzien van een image zet je daar een Icon op.

Nu wil ik in mijn spel natuurlijk ook leven voorzien voor het hoofdpersonage. Maximum leven is 100. Als ik door een monster wordt geraakt gaat er bijvoorbeeld 6 leven af (=94). Nu kan ik toch niet voor elke mogelijkheid een image voorzien (Leven van 0 tot en met 100). Wat ik dus wil doen is een Icon maken waarop ik dan zelf tekst kan voorzien. Hoe kan ik dit nu het beste doen? Ik heb al liggen zoeken om op dat Icon te tekenen of dergelijke...

Alvast bedankt

Parnakra

Legacy Member
Maak een klasse LifeIcon die de Icon-interface implementeert en gebruik (bijvoorbeeld) de fillRect-methode van g om in je paintIcon-methode een groene en rode balk te tekenen.

/edit: Als je enkel tekst/een numerieke waarde wil, is het natuurlijk nog makkelijker en gebruik je gewoon drawString(...).

forloRn_

Legacy Member
Je moet gewoon een implementatie van de javax.swing.Icon interface meegeven in plaats van een ImageIcon, genre:

new Icon() {
@Override
public int getIconHeight() {
return 100;
}

@Override
public int getIconWidth() {
return 100;
}

@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
g.setColor(java.awt.Color.BLACK);
g.drawString("94", 0, 50);
}
}

Curahee Q

Legacy Member
Oké, ik heb nu het volgende.

Code:
package demo;

import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Image;

import javax.swing.Icon;
import javax.swing.ImageIcon;

import bordspel.BordspelVenster;

public class LifeIcon implements Icon {

	private int width, height;
	private int health;
	private int length = 44;
	private Image background;
	
	public LifeIcon(int width, int height, String srcBackground) throws Exception {
		ImageIcon imageIcon= (ImageIcon) BordspelVenster.laadFiguur(srcBackground);
		
		this.background = imageIcon.getImage();
	}
	
	public void setLife(int health) {
		this.health = health;
	}
	
	@Override
	public int getIconHeight() {
		return this.height;
	}

	@Override
	public int getIconWidth() {
		return this.width;
	}

	@Override
	public void paintIcon(Component c, Graphics g, int x, int y) {
		int lifeBarLength = (int)Math.round((health/100.0)*length);
		
		Color kleur = Color.green;
		
		if(health < 30) {
			kleur = Color.red;
		}
		else if(health < 75) {
			kleur = Color.ORANGE;
		}
		
		g.drawImage(this.background, 0, 0, null);
		g.setColor(kleur);
		g.drawRect(1, 8, 47, 14);
		g.fillRect(3, 10, lifeBarLength, 11);
		g.setColor(Color.BLACK);
		g.drawString("" + this.health, 13, 40);
	}
}
Als mijn leven nu gereduceerd wordt wil ik een repaint bekomen van deze Icon. Echter bestaat er geen repaint() method. Hoe los ik zoiets dan op?

Parnakra

Legacy Member
Gebruik paintIcon(...)?

Ik zie niet meteen hoe je aanpassingen gaat opvangen, maar normaal gezien zou dat voldoende moeten zijn.

Curahee Q

Legacy Member
Als setLife() wordt aangeroepen weet ik dat er een repaint moet gebeuren.

paintIcon() wordt opgeroepen wanneer deze icon ergens wordt opgezet waarschijnlijk? Echter weet ik niet wat ik moet invullen voor Component en Graphics...

Cycloon

Legacy Member
Hoe ik het zou aanpakken:

Een klasse die uw personage voorstelt met een methode getIcon(). Je kan simpelweg een vast icon maken via een bufferedimage waar je op tekent en omzet dmv de ImageIcon klasse. Telkens een instelling wijzigt maak je een nieuw icon aan en bewaar je die in je object. Daarna gebruik je het observerpattern om wijzigingen in het leven van het personage kenbaar te maken aan je paneel met de gridlayout op waarna die getIcon() kan oproepen van je personage en het oude kan vervangen. Je kan dan ook direct een interface voorzien met die methode voor al je andere zaken die getoond moeten worden. Je zal hiermee ook een mooie performantiewinst halen bij het het herschalen e.d. van je window (omdat niet alles constant hertekend moet worden).

Curahee Q

Legacy Member
Ik heb dus nu een BufferedImage gemaakt.
Code:
package demo;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;

import javax.swing.Icon;
import javax.swing.ImageIcon;


public class LifeIcon extends BufferedImage {
	
	private Icon achtergrond;
	private int leven;
	private int length=44;
	
	public LifeIcon(int leven, int width, int height, Icon achtergrond) {
		super(width, height, BufferedImage.TYPE_INT_RGB);
		
		this.leven = leven;
		this.achtergrond = achtergrond;
		this.teken();
	}
	
	public void setLeven(int leven) {
		this.leven = leven;
	}
	
	public void teken() {
		Graphics g = super.getGraphics();
		
		int lifeBarLength = (int)Math.round((leven/100.0)*length);
		
		Color kleur = Color.green;
		
		if(leven < 30) {
			kleur = Color.red;
		}
		else if(leven < 75) {
			kleur = Color.ORANGE;
		}
		
		g.drawImage(((ImageIcon)this.achtergrond).getImage(), 0, 0, null);
		g.setColor(Color.BLACK);
		g.drawString("" + this.leven, 13, 40);
		g.fillRect(2, 9, 46, 13);
		g.setColor(kleur);
		g.drawRect(1, 8, 47, 14);
		g.fillRect(3, 10, lifeBarLength, 11);
	}
}

Deze krijg ik ook al op mijn scherm te zien dus tot daar zit ik goed.

Het stomme is wel dat ik niet aan mijn paneel met de gridlayout kan omdat dit een jar-file is gekregen van de proffen...

Da Turtle

Legacy Member
Kan je niet gewoon een oud icoon vervangen door een nieuw op de manier dat je het de eerste keer er op gezet hebt? Het zou handig zijn om de interface te zien van die klasse die je gekregen hebt.

Curahee Q

Legacy Member
Ik heb het inderdaad zo gedaan Da Turtle en het werkt goed.

Echter zou het denkik beter zijn moest ik echt een rechtstreekse repaint kunnen doen. Nu maak ik telkens een nieuw object aan.

Cycloon

Legacy Member
Curahee Q zei:
Het stomme is wel dat ik niet aan mijn paneel met de gridlayout kan omdat dit een jar-file is gekregen van de proffen...

9 kansen op 10 hebben zij al het observer pattern geïmplementeerd en moet jij het nog in mekaar haken.

Curahee Q

Legacy Member
Ik denk niet dat deze er al in zit, wat ze ons gegeven hebben is echt heel basic. We moesten gewoon een spelletje maken. Sommige maken pacman of schaken of dergelijke. Het is niet dat het een RPG moest zijn...

Dit zijn de docs van de reeds gegeven jar-file

Generated Documentation (Untitled)

Ik heb nu gewoon gebruik gemaakt van BordspelVenster.setVakFiguur(int x, int y, Icon).

(@Cycloon: Heb jij dat ook niet ooit moeten maken? III, vak OGP aan hogent.)

Parnakra

Legacy Member
Het zit er dus wel in. Je BordSpelVenster wordt opgevat als een Observable object dat, telkens er een bepaalde actie zich voordoet (muisklik, toets ingedrukt of timertik) al zijn Observers (in dit geval slechts één GebeurtenissenAfhandelaar) inlicht.

In jouw geval zou ik dus de tikTijd heel kort instellen en per tik gaan controleren wat het leven van je figuur is en de balk (indien nodig) gaan aanpassen. Om het in realtime te laten gebeuren, kan je eventueel een methode gaan implementeren in je GebeurtenissenAfhandelaar die opgeroepen wordt telkens er iets gebeurt waardoor het leven van je personage stijgt of daalt.

Qua design is dat niet perfect (je GebeurtenissenAfhandelaar is eerder een controllerklasse die optreedt als link tussen je GUI en je model en het stijgen/dalen van je leven hoort volledig bij je model), maar voor dit soort opdracht zal het wel voldoende zijn.

Cycloon

Legacy Member
Curahee Q zei:
(@Cycloon: Heb jij dat ook niet ooit moeten maken? III, vak OGP aan hogent.)

Nope, maar ik ken wel de manier van werken en wij hadden gelijkaardige oefeningen. Daarom dat ik vrijwel zeker was dat in deze oefening het observer pattern gebruikt werd.

Maar zoals parnakra al zei, met die gebeurtenisafhandelaar kan je perfect zien wanneer er acties gebeuren. En enkel bij bepaalde acties zal het leven van je karakter kunnen veranderen. Enkel op die momenten moet jij dus een nieuw icoon voorzien voor je grid.

Als je het nog wat beter wil opvangen kan je het mvc pattern implementeren. Je zorgt dat je een controller hebt die naar die gebeurtenissen luistert en bij bepaalde gebeurtenissen aan je model (de karakters en stuff) de gepaste nieuwe iconen opvraagt en die doorgeeft aan je grid.

Curahee Q

Legacy Member
Dat mvc pattern gaat al iets te ver voor deze opdracht. Maar ik zal het in gedachte houden voor als ik zelf is een klein spelletje ga maken.

Cycloon

Legacy Member
Als je het een klein beetje structureel goed aanpakt ga je sowieso bij iets terecht komen dat héél sterk zal gelijken op het mvc pattern. Ik zou het toch eens goed bekijken, want het concept stelt niet zo heel erg veel voor maar je kan dan wel netjes je game ontwerpen ;)

Curahee Q

Legacy Member
Dus als ik het goed begrijp splits ik dan mijn Leven op in 3 delen
- View -> LifeIcon extends BufferedImage voor de grafische weergave
- Controller -> Gaat het icon vernieuwen wanneer het leven veranderd
- Model -> Bevat de data, in dit geval het leven

Denk ik tot hier toe in de goede richting?

Moeten dit alle 3 aparte klassen zijn? Waarschijnlijk wel voor de herbruikbaarheid...

Cycloon

Legacy Member
Jep zoiets, al is de view hier reeds gemaakt: die grid. Je LifeIcon hoort eerder deels bij het model (alhoewel het in dit geval eigenlijk nogal een vreemde eend in de bijt is).

Curahee Q zei:
Moeten dit alle 3 aparte klassen zijn? Waarschijnlijk wel voor de herbruikbaarheid...

De controller op zich is altijd een aparte klasse (of meerdere controllers, die elk een klasse zijn). De view en het model bestaan uiteraard altijd uit meerdere componenten (zijn dus packages op zich).
Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.
Terug
Bovenaan