Spelprogrammering och spelrecensioner
Startsidan Blogg Fotoalbum Gästbok
Debatt Topplistor Logga in
Ti On To Fr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<<
Mars (2024)
>>


Så kan man också göra..

Tydligen så ritas textsträngar från "baseline" av strängen, enkelt uttryckt detsamma som linjen man skriver på i ett anteckningsblock. Alltså när jag anger ett Y-värde för att den ska ritas på skärmen så anger jag var denna linje ska vara och inte var den övre vänstra punkten på strängen är, som t ex ritning av bilder fungerar.
För att lösa detta ska man addera strängens "ascent" med hjälp av klassen FontMetrics till det önskade y värdet. Tyvärr tycks inte det fungera särskilt bra alls.
Förmodligen beror det på att jag skriver med svenskt typsnitt, och därmed vill den även ha med prickarna över exempelvis ett stort Ö.

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4399887

Otroligt störande då jag vill säga exakt var texten ritas precis som med en bild och inte på ett ungefär och låta delar av texten sticka ut ur t ex en dialogruta...

Jag misstänker att det måste finnas en annan metod för att rita strängar någonstans, jag önskar att man skulle kunna ange baseline /alt topleft.
4 Maj 2012  | Länk | Java | 0 kommentar
Nya äventyr (bara en bild från spelet)

Vår hjälte tar en paus vid duckhunt-dog-in-a-box-sjön.

Avatar! You cannot do that!
4 April 2012  | Länk | Java | 0 kommentar
Handlingskraft i handlingar

Satt för en timme sedan och tänkte att nu ska jag minsann skriva en fungerande handling(action) så att jag får använda mitt menysystem.

Vad är en handling då? Och vad är speciellt med dessa handlingar?

En handling är idé jag har haft att man kan skilja de saker som existerar i världen med sakerna man kan göra med dem. Detta är tänkt att medföra förenkling i skapa innehåll(content) i världen. Så när jag gör ännu en ny form av träd så behöver jag i princip bara implementera trädmetoderna och i en av dessa metoder berätta vad man kan göra med detta träd. I den metod som berättar vad man kan göra kan hänvisa först till generella trädhandlingar och därefter kan jag fylla på med handlingar som är mer specifika eller rent utav exklusiva.

Varför är detta enklare? Detta tänker jag är att jag så långt som möjligt ska behöva skriva en typ av händelse en gång, och därefter dela den med de saker kan existera i världen som man kan göra denna händelse med.

Ok, det låter som ett koncept, det är säkert bra. Men nu kommer en liten fördjupning: Dessa handlingar säger inte exakt vad som ska göras utan anger bara en sekvens av kod som

bearbetar sakernas egna metoder.

..

Alltså är alla handlingar fullständigt modulära med varje ny typ av sak som följer en given gränssnittstyp. Ett träd kan huggas ner, men exakt hur det går till beror på trädet. Hur hårt trädet är en typisk variabel, och det är inget märkvärdigt att låta sådana vara olika för olika typer av saker under ett gränssnitt. Men det som är fiffigt med denna lösning är att även metodernas implementering kan variera. Dessutom så blir handlingarna mer abstrakta och lättlästa då de lämnar detaljerna åt den sak som ska bli handlad på.

--

Samtidigt skulle detta system vara snabbt och fungera i ett globalt och individuellt schemasystem. Det globala schemat är en datastruktur som håller i alla handlingar eller övriga fenomen som har planerats att hända vid givna tidpunkter. En sorts klocka som räknar speltics(turer) sekunder, minuter, timmar, dagar osv.. Tittar i detta schema varje speltur och ser om något ska hända. Datastrukturen är effektiv och håller ordning alla handlingar och fenomen och vet vilken som ska hända härnäst, alltså behöver vi bara kolla om klockan och tidpunkten för nästa händelse är lika för att därmed be den schemalagda händelsen att inträffa.

Problemet är att om jag har objekt som är sk handlingar, så skulle jag få problem med sk. garbage collection. Minneshanteringen i java är automatisk och vissa hanteringar är mer besvärliga än andra, och där räknas alla objektinstanser.

Det fanns en uppsjö med lösningar men jag är särskilt nöjd med min:
När det globala schemats nästa handling är lika med klockan, så aktiveras det gränssnitt som det globala schemats bokning refererar till. Detta gränssnitt kallas instruktion(instruction) och innehåller bara en metod som heter read(). Det objekt som implementerar detta gränssnitt är entity(entitet) som helt enkelt är levande varelser för det mesta, och det är ganska logiskt då de är de enda som utför handlingar. Varje varelse som är intelligent har nämligen ett eget individuellt schema, som jag sa förut, och detta schema vet vad nästa sak som ska hända är, och därifrån kan handlingen utlösas.

Men.

---

Problemet som jag slagits inför är att alla handlingar är varianter av handlingsgränssnitt, och av nödvändighet så finns en typ av handlingsgränssnitt för varje typ av sakgränsnitt som finns. Sakgränssnitt är t ex entity, plant(växtlighet), terrain(marktyp), item(pryl), usable(användningsbar), osv.. Problemet var att varje handling kräver referensinformation såsom var det ska hända, av vem, mot vad, när det ska hända och vad som ska hända. Men jag ville inte att schemasystemet skulle innebära att det spottades ut massor nya objektinstanser hela tiden bara för att hålla koll på dessa referenser tillsammans med handlingarnas instruktioner.

Att ha olika referenslistor hos varje entity innebar problem om schemat skulle behöva ändras, då de olika referenserna inte var inkapslade i tillsammans. Alltså behövdes objekt av något slag. En objektpool skulle det bli. Men alla handlingar är typinterfaces och kan inte göras instanser av.

Jag fick huvudvärk, var mitt system så flexibelt att det aldrig skulle gå att få det effektivt? Varför hade jag gjort såhär? Varför kunde jag inte bara gjort ett snålare system och varit kreativ inom det systemet istället? Så verkar alla andra göra. Inget annat spel hade den här funktionaliteten och hade som avsikt att det skulle fungera på en skala av miljoner med entiteter som hittade på handlingar konstant. Så går det när man inte kan bestämma sig, då blir det abstrakta fabrikmetodershierarkier och ingen verkstad, inget blir gjort, bara mer komplicerat. (ha ha ha..)

Men jag gav inte upp och fortsatte att fundera den där kvällen och till sist hade jag löst det.(klockan fem på natten en lördagkväll) Kanske inte så märkvärdig lösning egentligen, men för mig var/är den märkvärdig. Jag har fortfarande inte kommit på ett bättre sätt att göra det på, och även om det känns väldigt omständigt, är det också ganska finurligt.

Lösningen var naturligtvis fler gränssnitt! (Läsaren gör en facepalm)

Hrm. Alltså ja. Mer gränsnitt var det ja. Hrrmm.

Jag kunde ha gjort instanser av varje enskild handling och gjort ett avancerat poolsystem, men detta skulle garanterat behöva ändras storlek på och innebära enorm overhead. Och det finns massor med ideér jag hade som inte jag kommer beskriva här då det är ett så öppet problem med flera lösningar.

Jag tänkte att om jag behöver instanser men inte kan göra instanser av de generella handlingstyperna så behöver jag ett objekt för varje handlingstyp som innehåller de referensvariabler som är nödvändiga, inklusive en referens till själva handlingsobjektet så att dess metod kan hanteras. Anledningen till att det behövs en sort för varje handlingstyp är att metodparametrarna skulle vara olika för varje handlingstyp. En entitetshandling skulle antagligen ha som target(mål) en entitet, och därmed behövs en typ som har just en sådan variabel. Att ha en sort som innehåller alla variabler hade varit slöseri på minne då vissa variabler skulle stått tomma, och så finns det risker med att arbeta runt den hårda typsäkerhet som finns i java. Jag hade lika gärna kunnat använda instanceof operatorn och använd "explicit casting" men detta har tydligen en riktigt fet overhead och är innebär risker om något blir fel. Dessa lösningar kändes inte eleganta. (men mer gränssnitt är alltid elegant!)

Men vad nu då? några nya typer vars instanser inkapslar referenserna för varje handlingstyp? Inga nya gränssnitt än så länge? Anledningen till att detta inte räckte var att det skulle innebära att entiteternas schemasystem skulle behöva flera listor i sitt schema då varje inkapslingsstyp var olika. Detta innebär återigen problem att hålla listan ordnad. Jag skulle kunna haft ytterligare en lista som höll koll på ordningen men prestanda och minnet hade gråtit. Så jag uppfann ett gränssnitt som kapslade in alla dessa inkapslare i en enda handlingschemaläggning(ScheduledAction) Det fungerar eftersom alla delar samma metodimplementering förutom vilken sort den är(vilket kan representeras av en sträng eller en enumrering) och hur den aktiveras. Så om jag aktiverar detta gränsnitt så kommer den aktivera aktiveringsmetoden i rätt handling, i rätt handlingstyp med rätt parametrar för dessa är alltid samma för varje handlingstyp.

Så då kan jag ha ett begränsat antal instanspooler och slippa garbarge collection och samtidigt ha en enda lista i entitetsschemat, och samtidigt ha totalt flexibla handlingar där variabler och utförningsmetoden är helt fri att implementera, som leder till att handlingar och saker skiljs åt i datastrukturen och i implementeringsklasser. Den lilla bilden ovan visar hur jag nu i efterhand att jag löst problemet försökt skissa ihop en av problemets delar för att få bukt på om detta verkligen är en bra lösning, om det fungerar, och om jag borde göra annorlunda. Det verkar dock som att det blir såhär.

To action!

Bah! Jpegen går inte alls att läsa.. Nåväl, ni får bli imponerade av att jag till synes gjort en ostandardiserad flowchart. =)
3 April 2012  | Länk | Java | 0 kommentar
Hur ett meny fönster ritar sig självt.

Det här är metoden som gör att ett menyfönster kan rita sig självt. Den har redan initierats och vet sin storlek och plats i fönstret, och den har även listat ut om den är för nära den nedre eller högra kanten och måste öppna sig åt någon annan riktning än sydöst, därav circlecorner enumreringen. Denna fungerar så att rutan förskjuts i hela sin storlek åt den/de riktningar som behövs och därmed byts markeringshörn, ungefär som högerklickningar i windows fungerar på skrivbordet, fast coolare då mina fönster har en liten fin vit markeringsring. Fönstret ritar sig självt genom att använda tiles som är 32x32 stora .png bilder.

public void paint(Graphics g){
//Börjar med att rita menyn utan hörn.
//Övre sidan och undre sidan.
for(int x = 1; x < Math.ceil(sizeX / 32d) - 1; x++){
//Övre
g.drawImage(MenuPart.MENUBORDERN.getMenuTileImage(), posX + x*ViewArea.TILESIZE, posY, viewArea.getViewPanel());
//Undre, ta hänsyn till att rutor ritas från topleft
g.drawImage(MenuPart.MENUBORDERS.getMenuTileImage(), posX + x*ViewArea.TILESIZE, posY + sizeY - ViewArea.TILESIZE, viewArea.getViewPanel());
}
//Vänstra sidan, kroppen, och högra sidan.
for(int y = 1; y < Math.ceil(sizeY / 32d) - 1; y++){
//Vänstra
g.drawImage(MenuPart.MENUBORDERW.getMenuTileImage(), posX, posY + y*ViewArea.TILESIZE, viewArea.getViewPanel());
//Rita kroppen.
for(int x = 1; x < Math.ceil(sizeX / 32d) - 1; x++){
g.drawImage(MenuPart.MENUBACKGROUND.getMenuTileImage(), posX + x*ViewArea.TILESIZE, posY + y*ViewArea.TILESIZE, viewArea.getViewPanel());
}
//Högra, ta hänsyn till att rutor ritas från topleft
g.drawImage(MenuPart.MENUBORDERE.getMenuTileImage(), posX + sizeX - ViewArea.TILESIZE, posY + y*ViewArea.TILESIZE, viewArea.getViewPanel());
}

//Ritar hörnen DENNA DEL BEROR PÅ CIRCLECORNER.
if(corner == CircleCorner.nw){
//NW
g.drawImage(MenuPart.MENUBORDERWHITECIRCLENW.getMenuTileImage(), posX, posY, viewArea.getViewPanel());
//NE
g.drawImage(MenuPart.MENUBORDERNE.getMenuTileImage(), posX + sizeX - ViewArea.TILESIZE, posY, viewArea.getViewPanel());
//SW
g.drawImage(MenuPart.MENUBORDERSW.getMenuTileImage(), posX, posY + sizeY - ViewArea.TILESIZE, viewArea.getViewPanel());
//SE
g.drawImage(MenuPart.MENUBORDERSE.getMenuTileImage(), posX + sizeX - ViewArea.TILESIZE, posY + sizeY - ViewArea.TILESIZE, viewArea.getViewPanel());
}
if(corner == CircleCorner.ne){
//NW
g.drawImage(MenuPart.MENUBORDERNW.getMenuTileImage(), posX, posY, viewArea.getViewPanel());
//NE
g.drawImage(MenuPart.MENUBORDERWHITECIRCLENE.getMenuTileImage(), posX + sizeX - ViewArea.TILESIZE, posY, viewArea.getViewPanel());
//SW
g.drawImage(MenuPart.MENUBORDERSW.getMenuTileImage(), posX, posY + sizeY - ViewArea.TILESIZE, viewArea.getViewPanel());
//SE
g.drawImage(MenuPart.MENUBORDERSE.getMenuTileImage(), posX + sizeX - ViewArea.TILESIZE, posY + sizeY - ViewArea.TILESIZE, viewArea.getViewPanel());
}
if(corner == CircleCorner.sw){
//NW
g.drawImage(MenuPart.MENUBORDERNW.getMenuTileImage(), posX, posY, viewArea.getViewPanel());
//NE
g.drawImage(MenuPart.MENUBORDERNE.getMenuTileImage(), posX + sizeX - ViewArea.TILESIZE, posY, viewArea.getViewPanel());
//SW
g.drawImage(MenuPart.MENUBORDERWHITECIRCLESW.getMenuTileImage(), posX, posY + sizeY - ViewArea.TILESIZE, viewArea.getViewPanel());
//SE
g.drawImage(MenuPart.MENUBORDERSE.getMenuTileImage(), posX + sizeX - ViewArea.TILESIZE, posY + sizeY - ViewArea.TILESIZE, viewArea.getViewPanel());
}
if(corner == CircleCorner.se){
//NW
g.drawImage(MenuPart.MENUBORDERNW.getMenuTileImage(), posX, posY, viewArea.getViewPanel());
//NE
g.drawImage(MenuPart.MENUBORDERNE.getMenuTileImage(), posX + sizeX - ViewArea.TILESIZE, posY, viewArea.getViewPanel());
//SW
g.drawImage(MenuPart.MENUBORDERSW.getMenuTileImage(), posX, posY + sizeY - ViewArea.TILESIZE, viewArea.getViewPanel());
//SE
g.drawImage(MenuPart.MENUBORDERWHITECIRCLESE.getMenuTileImage(), posX + sizeX - ViewArea.TILESIZE, posY + sizeY - ViewArea.TILESIZE, viewArea.getViewPanel());
}
//TODO draw the different action lists.
26 Mars 2012  | Länk | Java | 0 kommentar
Den sista biten i en större förändring faller på plats.

Många förändringar har genomförts i hur datastrukturerna i spelet hanteras.
Detta för att kunna husera den relativt sätt enorma (730*8000)^2 världen. Alla ursprungliga delar i map-hierarkin har blivit interfaces och flera olika implementeringar av dessa har skapats för att ge plats åt både kartgenerering och resurssnål statisk terräng, men möjliggör fortfarande skapandet av dynamisk terräng genom omvandling. Den sistnämnda använder den ursprungliga datastrukturshierkin medan den statiska ingår i olika uppsättningar hashmaps som cache:r. Flera andra optimeringar har genomförts.

Ett tag var jag nära att använda en särskild hashmap för alla entiteter inom det statiska fältet, men jag insåg att möjligheten att läsa av ett halvstort område efter entiteter kunde bli flera storleksordningar mer kostsamt än att helt enkelt ladda in ett cache:at område och låta denna husera en lista för alla entities. Detta förenklar pathfinding och förutsägandet av andra entiteters närhet på både ett grafiskt och ett AI-funktionellt plan.

Den banbrytande bilden illustrerar hur avataren Digital-Emil rör sig över en tidigare visad grafiskt illustrerad karta. Jag bör nog påpeka att spelets nuvarande tilegrafik är ytterst tillfällig och funktionell. Det grafiska interfacet i övrigt är enkelt uttryckt icke existerande.

Nu väntar träden på att växa, och tiden på att börja ticka, och värmen att börja tina upp, respektive frysa ner olika klimatzoner!

Längre fram kommer skapandet av GUI med inventory och dylikt och möjlighet att ändra omgivningen på olika sätt.

Framförallt är jag glad att pusslet faktiskt föll på plats så enkelt. Efter allt funderande och ändrande här och där under en längre period utan att kunna köra programmet så förväntade jag timmar av buggrensning. och så fungerade det istället helt perfekt vid första försöket!
9 Maj 2011  | Länk | Java | 0 kommentar
Feature: the world

Om världens fysikaliska data.

Världen kommer bestå av en fyrkantig karta där x axelns kanter möts likt en cylinder. Tänk civilisation 2.

Jag har funderat lite på hur stor en sådan här värld borde vara. Om byteshandel ska bli meningsfullt, men framförallt en utmaning så får inte världen inte vara för liten, dessutom tycker jag utforskande och nybyggande är spännande i sig.

Den nuvarande planen är att världen kommer ta två år in game att gå runt.
Ett år har 365 dagar, 12 månader. Som på jorden fast förenklat dvs.

En hel dag i spelet dvs 24 timmar motsvarar två timmar irl.
730 dagar är 1460 timmar. Dock så förutsätter detta att man "endast" vandrar i 12 timmar om dagen, dvs 1 timmer irl. Så 730 irl timmar för den nyfikna som vill ta reda på om världen är rund, det borde räcka.

Världen har en exakt area på 34105600000000 rutor varav de flesta kommer skapas procedurellt. Vår jord har 510072000000000 kvadratmeter om jag inte räknat fel, varav 148940000000000 kvm är land. Det ger för handen att världen i spelet är ungefär 6% så stor som den riktiga jorden om vi förutsätter att en ruta är en kvadratmeter. Tidsförhållande mot den riktiga världen är 1:12 och ytförhållandet mot jorden är ca 1:14 vilket inte var planerat men verkar ha blivit en naturlig följd av att jag fått för mig att två år är en rimlig tid att gå runt jorden på. Detta gällde dock att gå runt landytan och åka båt eller liknande på resten av vägen men det är ändå intressant att det finns en likhet i förhållandet.

Världen ska bestå av klimatzoner som beror på latitud och höjd för temperatur, liksom nederbördsområden som beror på topologi och väder. Dessa zoner kommer definieras av sk biomer, vilket liknar dwarf fortress motsvarighet. Djurliv och växter avgörs av dessa biomer. Varaktiga förändringar i klimatet kommer förändra områdens biomer.
Temperatur kommer även styras av en dag och natt cykel liksom växlande säsonger. Hav definieras procedurellt och sjöar och floder kommer kartläggas efter ansamlingsberäkningar och fallhöjdsberäkningar i förhållande till nederbörd(men detta är inget som jag genomfört eller ens vet hur ännu, men jag är optimistisk..).

Väder kommer på något vis simuleras med någon enkel form av vädersystemssimulering med vindar och nederbörd i form av snö och regn.
13 Februari 2011  | Länk | Java | 0 kommentar
Fler rubriker på F i februari.

Cirkeln integrerades additivt med denna genererade bild med den första bilden som resultat.
13 Februari 2011  | Länk | Java | 0 kommentar
Form

Den förra bilden har skapats särskilt med denna cirkelform, angiven med en given högsta höjd, given lutning vid ändradien för cirkeln, och given bottenhöjd.
13 Februari 2011  | Länk | Java | 0 kommentar
Fruit of labor

Februariuppdateringens förslag gick i stöpet, och det ordentligt. Efter en hel del tjurighet och 4 olika RNGs med otaliga variationer och trixande så får det här duga tills vidare. Och mer bilder blir det! =)
13 Februari 2011  | Länk | Java | 1 kommentar
februariuppdatering.

Jag har försökt få ihop de lite spretiga koncepten för datastrukturerna på ett abstrakt plan, vilket måste klicka som bra pusselbitar innan jag börjar med det roligare implementeringen av faktiska features.

Detta har gått bra men sakta, men däremot så har jag inte nått några nya goda resultat med min perlin noise/fractal Brownian motion baserade landskapsgenerator. Jag fick dugliga resultat med javas Random, men jag vill har bättre resultat och har prövat, grävt och pillat med allt jag hittar på internet mer eller mindre. Eftersom jag inte är en matematiker så är det svårt för mig att intuitivt känna vad som borde bli rätt, därför är det mycket testande. Just nu prövar jag en java implementering av George Marsaglias XORShiftGenerator med 5 states som gjorts av Daniel W. Dyer. Daniels hemsida http://uncommons.org/ huserar källkodspaketet "Uncommon Maths" som jag tagit och fipplat ihop en egen variant av. Det huvudsakliga förändringen är att jag nu kan ändra states och att dessa inte är final, och att setSeed() tar en array med Integers(heltal) istället för bytes.

5 Heltal krävs och jag tar dessa ifrån xkoordinaten, ykoordinaten och tre slumptal.
Denna seedstrategi är undermålig och jag är inte nöjd med det eller resultatet.
Jag övervägde att modifiera x och y kordinaterna genom att addera ett heltal. Men jag läste nyligen från "The G95 Project" från 4 december 2003 (http://www.g95.org/2003.shtml) om att heltal där flera bitar är 0 så blir resultatet inte så slumpmässigt till att börja med. Dessutom har jag vid test sett att desto högre koordinatvärde desto mindre blir "kontrasteffekten" som sker vid låga koordinater, dvs att väldigt höga och väldigt låga slumptal ges och lite emellan. Jag har redan låtit generatorn löpa ett antal bitar in för att förbättra slumpen men detta är kostsamt och bör minimeras för att få så bra prestanda som möjligt.. Jag återkommer närmare om jag får bättre resultat.
11 Februari 2011  | Länk | Java | 0 kommentar
A world of noise

Visade precis lillstrumpa denna bild, det gör min idé mer rättvisa än alla mina försök att förklara vad jag försökt göra den senaste tiden. Och så ser alltså min Perlin noise funktion ut just nu när den ritas ut och färgläggs.

Den som nu tänker: Daniel tänker låta spelets terräng på något vis baseras på denna funktion. Den har rätt. Det är precis så jag tänker göra.
Problemet är att jag just nu använder en prng, och det är inte helt oproblematiskt att seeda två koordinater + ett slumpmässigt tal. Dessutom så innebär återseedningen för varje ruta att många slumpgeneratorer måste ominitialiseras varje gång! Detta känns fel i magen. Jag vill använda koordinaterna och ett slumptal som seed för en slumpfunktion och den ska inte bli ledsen när jag återseedar varje gång. Jag har läst lite om någon som skrivit om hashtabeller och permuteringstabeller, men det har jag inte haft tid att läsa klart om ännu. Men nu har jag ett proof of concept ivf efter lite mixtrande med Javas egna Random.


http://www.nolithius.com/game-development/world-generation-breakdown
Hittade denna för någon vecka sedan och den ger bra bilder för vad jag tänkt på nu i december när tiden givits.
4 Januari 2011  | Länk | Java | 5 kommentarer
slumpen skördar sina offer.

Eftersom fungerande resultat dröjer så kommer en beskrivning av vad jag gjort hittils:

Först trodde jag att jag hade löst det, sedan fick jag felsöka och jag hittade flera fel. Men det fungerade fortfarande inte. Talen från slumpgeneratorn var för lika varandra. Jag tittade genom alla operationer och beräkningar som gjordes och kom fram till att det borde fungera.

Efter lite tester så märkte jag att jag inte hade gjort fel, utan att seedtalen var väldigt lika varandra när jag stegade fram.. Oron växte och när jag lusläste metoden jag använde i Random-klassen så framgick att den använde sig av metoden next() ett antal gånger för att ta fram tillräckligt antal bitar för att därefter skapa slumptal i de andra metoderna. För att lösa detta så räknade jag fram hur många bitar, dvs hur många gånger next() använder och därefter så fick seedtalen ges med samma faktor. Detta oroade mig då jag vet att längden på perioden inte är jättelång för javas Random och att perioden i praktiken minskade med denna förändring. Det fungerade dock fortfarande inte, talen är för lika, och därför har jag gett upp java Random för ändamålet.

När jag sökt lite på generatorer så stötte jag på mersenne twister som på något sätt använder primtal med samma namn. När jag läste implementeringen så blev jag blek. Därefter så hittade jag ett paket med generatorer som använde olika implementering och låg under BSD licens, dvs gratis så länge jag ger cred. Den nuvarande planen är alltså att använda någon av dessa generatorer i stället, jag har läst att en av dem uttryckligen motverkar problemet som stegande genom seedtalet kan ge. Det verkar som sagt lovande.

Förklaringen på varför jag gör det här kommer jag ge när jag har resultat som fungerar. =)
10 December 2010  | Länk | Java | 2 kommentarer
Fail

Nu har jag fått lite mer tid till att programmera igen. Eftersom jag nu jobbar på den "magiska" funktionen och det kan ta lite tid, så kan jag i vart fall visa hur det inte ska se ut.. Hoppas att jag posta något mer lyckat snart. =)
3 December 2010  | Länk | Java | 0 kommentar
Unforseen consequenses...

Men istället för att ha råkat öppna en portal till en annan värld a la Half-Life, så har jag kommit fram till att skjuta upp idén med mjuka övergångar mellan rutor på obestämd tid.

Hela poängen med rutsystem just nu är och var att det skulle förenkla en hel rad med saker, så som pathfinding, det närliggande collisionchecks, grafikritning, muspekarinterface, och storlek på saker är några saker som jag kommer på nu. Om jag implementerar mjuka rörelser så måste jag göra det på något annat sätt än att skapa mindre koordinater i rutsystemet. Det huvudsakliga problemet är att om storleken på en sak, så som nu, alltid är exakt en ruta så kommer det ofta vara så att saker kommer överlappa till två eller t o m fyra rutor. Detta innebär att hela koordinatsystemet med rutorna skulle behöva göras om, och jag tror det skulle leda till att de inte blev mer än kollisionstestrutor. Jag överväger istället att övergången mellan rutor kan vara animerad men det är inte lika avgörande för att implementera andra mycket roligare funktioner såsom muspekarstöd, inventory och interaktionspaneler.

Det är helt enkelt lättare att med korrekthet arbete med celler i ett rutnät än att hela tiden behöva kolla upp storlek och position på allting i en särskild lista. Performancemässigt så är det inte avgörande tror jag, men samtidigt är det inte en funktion som ger tillräckligt mycket tillbaka utöver mjuka övergångar, därför detta beslut.

Celler och därmed fler andra roligare finesser. Men inga spoilers ännu. :)
11 Oktober 2010  | Länk | Java | 5 kommentarer
Jarrr!

Den tråkiga men tekniska delen av att kunna läsa in filer utifrån relativa sökvägar blev inte lättare när jag skulle försöka göra det i en .jar fil.
Nu kan jag i alla fall få ihop hela program i en exekverbar fil som funkar oavsett var den är och som ska fungera oavsett vem som använder den.

Det var mycket besvärligt att försöka lösa detta, men det är ett krav om jag ska kunna använda java webstart någon gång.

Men nu ska jag återgå till att koppla ihop tangentbordet bättre och även muspekare till spelet, och allra först att skapa mjuk gång mellan rutor. Tänk the legend of Zelda.
7 Oktober 2010  | Länk | Java | 0 kommentar
A vile force of darkness has arrived!

En oförutsedd effekt av att gå utanför kartans gräns som jag vill dela med mig av.
För att undvika krasher så kommer alla anrop till koordinater som inte existerar att returnera ruta 0,0. Det råkar vara samma metod som används när en entitet byter ruta, alltså är den entitet som går utanför kartan på 0,0 och 0,0 ritas överallt även om det bara är en entitet.

If you release one dwarf silver poodle, you release them all..
5 Oktober 2010  | Länk | Java | 0 kommentar
and it was all Yellow

Den gula bakgrunden skiner igenom mina alphamaskade .png tiles in glorious green. Vägvalet är gjort och all hämtning av bilder sker genom eventdispatchhandlertråden genom swing.

Vidare har jag förenklat hanteringen av koordinater på kartan. En tidigare temporär plan att ha alla rutor refererade till omedelbart är avvecklad. detta härrör till en tidig fråga om större rutor ska hantera mindre, eller om klassen map ska hantera det. Nu är jag tillbaka på spåret att map endast äger de stora rutorna, men nu ska map hantera alla koordinatförfrågningar från resten av programmet, den bästa kompromissen.

Så vad är fördelen med detta? En omedelbar fördel är att världen enkelt uttryckt kan vara mycket större då hela världen inte är aktualiserad omedelbart utan efter behov. Så hur gör jag det på ett säkert sätt? Hur gör jag vid en situation då någon laddar en tidigare sparad simulering på samma karta men där nyupptäckandet av ett rutområde måste innehålla samma geografi som innan laddandet? Jo jag använder slumpen genom bestämda seednummer för varje map!

Dvs jag använder samma teknik som Frontier (Elite2) använde för att få plats med en hel galax i en floppydiskett, eller som jag antar att Spore skapar procedurell grafik, m fl.

Coolt. Så då öppnas alltså porten till oändliga kartor? Ja men bara om jag utgår ifrån ett mittpunktskoordinatsystem med både positiva och negativa koordinater i båda dimensionerna. Vilket är den nya planen. Så har jag underförstått att man gjorde i Hearth and Haven för att dynamiskt kunna skapa nya supertiles.

Men jag tänker inte ha oändliga kartor men ganska stora. Detta därför att jag vill ha klimatområden och en värld som av enkelhetsskäl (läs 2d skäl) beskrivs som en cylinder.

Om vi återgår till seednummer och frågar oss vad det är så kan jag ge ett svar som inte är tekniskt, mest för att jag förstår tekniken på ett icke tekniskt plan.
Slumpgeneratorer och all slump i en dator är egentligen inte en riktig slump, vilket för mig är en filosofisk självklarhet då slumpen faktiskt inte finns på riktigt den är precis som den är i datorn en mänsklig konstruktion som används för att beskriva komplexa system. Ett seednummer har jag själv antagit är en plats på en väldigt lång talserie som uppfyller vissa krav för att kunna följa statistiska mönster, t ex så är kvoten på hela serien antagligen 0.5*, då alla tal är någonstans mellan 1 och 0.

*(Dock tror jag inte att numret faktiskt innehåller decimaler, men det är teknikaliteter i sammanhanget som är oviktiga)

Men om vi lämnar statistikens tekniska del åt sidan så framgår följande: Om vi vet att talet är determinerat i förväg så borde sekvensen vara förutägbar då den är sekventiell när den hämtar nya slumptal. För att att kunna förutsäga talföljden behöver vi bara veta de statistiska uttryck som använder serien och viktigast av allt vi behöver veta var i sekvensen vi börjar! Och där i ligger den heliga graalen för procedurelig programmering tror jag. Men om slumpen ska vara just slumpmässig så borde ju datorn välja startplats slumpmässigt eller hur? Så hur gör den? Jag kan bara tala för java men jag tror att de flesta varianter fungerar på samma sätt. Vad är det som inte är samma någon gång på en dator när du startar den?

Klockan. Starten på seedtalet väljs efter det datum och tid som är just när generatorn skapas, om du inte själv väljer en startpunkt. Jag antar att sekvensen gås igenom periodiskt så det borde alltså finnas flera start-tal som ger samma följd i sådana fall men det är spekulation som jag är mindre säker på en de andra spekulationerna här. :)

All datorslumpfilosofi åt sidan, hur använder jag denna förutsägbar serie på ett förutsägbart sätt, om jag frågar efter den på ett oförutsägbart sätt, t ex inte laddar rutor i samma ordning? Jo jag använder koordinaterna på något sätt när jag frågar generatorn. Nu är jag inne på djupt vatten då jag inte vet riktigt hur jag ska göra det men jag antar själv att det borde vara så då koordinaterna är förutsägbara.

Den riktiga maskburken tillträder dock när jag ska hålla reda på allt som är ändrat efter ursprungsskapelsen, eftersom människan kan ändra rutorna i världen så kommer dessa att behöva hållas reda på, och när du ska gå in i en by ska hela den vara bestämd eller även den slumpas?

Om du hugger ner ett träd djupt in i skogen hur länge ska stubben finnas kvar? Det kan jag lösa, men om jag ska hålla reda på hur länge stubbarna finns kvar när någon annan än spelaren har avverkat så blir det svårare. Om du har varit där och tittat så borde ju inte stubben flyttas nästa gång du går dit, samtidigt som jag helst skulle vilja att inte behöva hålla reda på det i datorminnet om det inte är ditt verk. Om jag skulle implementera naturlig livstid för träd blir det ännu mer besvärligt..
17 September 2010  | Länk | Java | 0 kommentar
Misströsta ej.

Klassen MediaManager fungerar och jag kan rita bilder.

Detta är testat med en ful-lösning, tanken är att låta Swings egna eventhandler tråd rita all grafik, men ska den gå igenom bildritningen själv eller få ett imageobjekt som är färdigritat? I vilket fall kommer jag använda ett mellankontext för att buffra bilden. Fördelen med att att eventhandler ritar allt själv är att jag lättare kan få flyt i uppdateringen av grafiken oavsett resten, nackdelen är inte självklar men jag blir orolig när en tråd ska springa runt och läsa av variabler i mina klasser samtidigt som maintråden..

Det farliga är synkroniseringsproblem, om eventhandlertråden vill läsa imagefilen för en tile så kanske den redan håller på att skrivas till av main? Dock ska det mesta i den vägen vara färdigt omedelbart efter initiering av all tile grafik. Men tänk om jag vill att vissa entities som t ex en människa som byter kläder ska byta image? I sådana fall bör nästan eventhandlern ta hand om detta om den endå ska vara där och fiffla. Tills detta beslut är löst så står utvecklingen åter stilla.
8 September 2010  | Länk | Java | 0 kommentar
No alarms and no surprises please.

Notis: Jag återgår till vanlig textredigering på obestämd tid.

Hej små knattar!
Idag ska vi titta på varför jag är dum i huvet, nått så jävulskt som använder java för att försöka, med betoning på försöka, göra datorspel med grafik...

Nedan angivna klass(vilket betyder för er som inte förstår objekt-ritning(Eftersom ingen förstår mer av den förklaringen så får ni utgå ifrån att det är så krångligt som det låter) läser in en bild och gör den tillgänglig till resten av programmet genom en lista som nås av en publik statisk metod. Alltså. Den läser in en bild.

EN bild!

Eller nåja, den läser in en bild till en lista och kan göra det flera gånger, men i dagsläget läser den helt enkelt in en .PNG "gräsruta" på 30x30 pixlar som är ritad så fint så fint i GIMP.
Vad värre är att jag ägnat en dag på att använda Toolbox.getDefaultToolbox.getImage(), vilket fungerade först men sedan inte kunde läsa min filadress.. Nu fungerar det iallafall eftersom jag övergivit denna usla metod.
Tror jag.

Eftersom jag fortfarande är dum i huvet, nåt så jävulskt så har jag faktiskt aldrig ritat min bild på skärmen så jag hoppas att det en bild jag laddat in.

och att jag vidare hoppas på att min fils alphachannel registreras, lär väl det med också sluta med tragik.

Så för alla tvivlare, jag kan nörda även med java, och jag lär mig och går mot nya horisonter en dag i taget med flera program. (Läs små usla spel)

Behold!

package gui;

import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;

import javax.imageio.ImageIO;

public class MediaManager {
private GameWindow gameWindow;
private static ArrayList graphicsList;
private Scanner graphicsScanner;
private MediaTracker mediaTracker;
private GraphicsConfiguration graphicsConfig;

public MediaManager(GameWindow gameWind){
gameWindow = gameWind;
graphicsList = new ArrayList();
try {
graphicsScanner = new Scanner(new File(System.getProperty("user.dir") + "\\graphicslist.txt"));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
System.out.println("Grafiklista hittas ej");
e.printStackTrace();
}
mediaTracker = new MediaTracker(gameWindow);
graphicsConfig = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
while(graphicsScanner.hasNext()){
//Läs in filadress och namn för fil från textfil.
String graphicPath = System.getProperty("user.dir") + "\\" + graphicsScanner.next();
System.out.println(graphicPath);
String graphicName = graphicsScanner.next();
System.out.println(graphicName);

//Läs in fil från scannad filadress.
//Image newImage = Toolkit.getDefaultToolkit().getImage(graphicPath);
Image newImage = null;
try {
newImage = ImageIO.read(new File(graphicPath));
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println(("Kan inte ladda fil = " + new File(graphicPath).getAbsolutePath()));
e.printStackTrace();
}

//Kolla att ImageIO.read hinner ladda newImage från fil innan compatibleImage skapas och blir ritad på.
mediaTracker.addImage(newImage, 0);
while(mediaTracker.checkID(0) == false){ //TODO kanske kan bli snabbare genom att ladda alla bilder?
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Toolkit.getImage hinner inte bli klar i tid med newImage för fil = " + graphicPath);
}
mediaTracker.removeImage(newImage);

//Skapa compatibleImage för accelererad visning, skapa kontext och skriv in newImage.
BufferedImage compatibleImage = graphicsConfig.createCompatibleImage(newImage.getWidth(null), newImage.getHeight(null), Transparency.TRANSLUCENT);
Graphics2D compatibleContext = compatibleImage.createGraphics();

//Kopiera newImage till compatiblecontext, dvs compatibleImage.
if(compatibleContext.drawImage(newImage, 0, 0, null) == false) System.out.println("NewImage är inte klar för ritning till compatibleContext");

//Skapa en ImageType för compatibleImage, med image och NAMN för enumtester.
ImageType graphicType = new ImageType(compatibleImage, graphicName.toUpperCase());

//Lägg ImageType i graphicsList.
graphicsList.add(graphicType);

//Lägg in ImageType för kontroll i mediaTracker.
mediaTracker.addImage(graphicType.getImage(), graphicsList.size());

}
while(mediaTracker.checkAll() == false){ //Testa alla ImageTypes.
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Väntar på att grafik laddats in i minnet.");
System.out.println(mediaTracker.checkID(0));
}
if(mediaTracker.isErrorAny()){
System.out.println("Fel i grafikladdning påträffat");
System.exit(0);
}
System.out.println("Färdig med grafikladdning.");
}
public static ArrayList getGraphicsList(){
return graphicsList;
}
}
4 September 2010  | Länk | Java | 0 kommentar


hittabutik.se - 12.000 webbutiker! | ehandelstips.se - allt om ehandel
(c) 2011, nogg.se & Daniel H                                             Skaffa en gratis hemsida