Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: Ei voida avata kuvaa

Sivun loppuun

mika132 [03.03.2010 20:37:29]

#

Eli mitä syitä voi olla, että kuva tiedostoa ei voida "avata". Seuraavat asiat ovat tarkistettu ja oikein:
1. Polku on oikea.
2. Nimi on oikea.
3. Formaatti on oikea (.bmp 24bittinen)

Mitä muita syitä voi olla, koska teen mitä vain niin ohjelmani kirjoittaa konsoliin "Kuva tiedostoa grafiikka/valikon_tausta.bmp ei voida avata."

Teuro [03.03.2010 20:43:59]

#

Miten ja millä lataat kyseisen tiedoston?

#include "kuvavarasto.hpp"
#include <SDL.h>

SDL_Surface *tausta = image_cache::common().get("tausta.bmp");
SDL_Surface *ruutu = NULL;

ruutu = SDL_BlitSurface(tausta, NULL, ruutu, NULL);

SDL_Flip(ruutu);

SDL_FreeSurface(ruutu);

mika132 [03.03.2010 21:06:19]

#

No katsoin matopelistä mallia, jotta välttäisin raskaan pelin ja oppisin tekemään kevyitä pelejä enkä tee aluksi raskaita ja sitten muutan kevyempään, koska se on kuin opettelisi alusta, mutta sitten asiaan.

Näin lataan kuvia:

#include "ohjelma.hpp"
#include <iostream>
#include <stdexcept>
#include <SDL/SDL.h>

namespace ohjelma {
	static SDL_Surface *ruutu;
	static void piirra_kuva(SDL_Surface *kuva, int x, int y, bool keskikohta = false);
	namespace kuvat {
		static SDL_Surface *lataa(const char *nimi, bool lapinakyva);

		static SDL_Surface *tausta_valikko;
	}
}
kuvat::tausta_valikko = kuvat::lataa("grafiikka/valikko_tausta.bmp", true);


static SDL_Surface *ohjelma::kuvat::lataa(const char *nimi, bool lapinakyva) {

	if (SDL_Surface *tmp = SDL_LoadBMP(nimi)) {
		if (SDL_Surface *opti = SDL_DisplayFormat(tmp)) {
			SDL_FreeSurface(tmp);
			tmp = opti;
		}
		if (lapinakyva) {
			SDL_SetColorKey(tmp, SDL_SRCCOLORKEY, SDL_MapRGB(tmp->format, 255, 255, 255));
		}
		return tmp;
	}
	throw std::runtime_error(SDL_GetError());
}

Metabolix [03.03.2010 21:13:55]

#

Luultavasti ohjelmasi työskentelyhakemisto on väärä. Liitä <cstdlib> ja laita main-funktion alkuun rivi system("dir"), niin näet, missä hakemistossa ohjelma työskentelee.

Teuro [03.03.2010 21:21:42]

#

Pikainen testi antaisi olettaa, että tausta.bmp nimistä tiedostoa ei ole olemassa, koska oma testini kaatuu tuon kuvanlatauksen jälkeen. Kuvan lisäämisen jälkeen aohjelmaa toimii ihan oikein.

mika132 [03.03.2010 21:56:09]

#

Aika jännä nimittäin tuo kertomasi "system("dir") kertoo kyllä että kaniosta data etsitään halutut tiedot, mutta ei missään vaiheessa puhuta kansiosta "grafiikka" miksi?

E: Eli main.cpp on alimmassa kansiossa josta includetetaan sitten data kansiossa olevat:
peli.cpp/hpp ohjelma.cpp/hpp jne.
grafiikka kansio on data kansiossa eli silloin kun ohjelma.cpp etsii kuvaa se etsitään näin:
grafiikka/kuvannimi.bmp
eikä
data/grafiikka/kuvanimi.bmp.

Eli tuokaan ei ole väärin, mutta miksi se ei ovi osata etsiä tuota kuvaa eikä missään vaiheessa koko ohjelma koske edes tuohon kansioon.

mika132 [03.03.2010 22:59:11]

#

RATKAISTU!

Koodiin piti kuitenkin laittaa data/grafiikka/kuvanimi.bmp. En tiedä miksi koska tiedosto mistä niitä etitään sijaitsee data kansiossa ja siitä seuraava kansio on grafiikka.

jmp [03.03.2010 23:05:05]

#

Lähdekooditiedostojen sijainti ei vaikuta siihen, mistä käännetty ohjelma lataa kuvat. Työskentelyhakemisto vaikuttaa.

Jos työskentelyhakemisto on x ja lataat kuvat esim. koodilla kuvat::lataa("grafiikka/kuva.bmp", true), niin ohjelma yrittää ladata tiedostoa polusta x/grafiikka/kuva.bmp.

mika132 [04.03.2010 00:01:13]

#

Pienoinen ongelma taas tullut eteen. Tämä matopelistä katsottu juttu on hieman uutta minulle, joten tekeminenkin on hieman vaikeampaa. Eli suomeksi, minulla sijaitsee samat asiat samoissa paikoissa tarkoitan, että pelaaja yms oliot "alustetaan" peli.hpp tiedossa jne, mutta en saa laitettua elämä palkkia mihinkään aina tulee joku errori että namespace ohjelma ei sisällä sitä eikä tätä vaikka yritän ettiä "peli::pelaaja::elama paikasta.. Ensin kerron miten sen toteutan:

notlife niminen kuva sisältää punaisen 100x25 kuvan.
life sisältää vihreän 1x25 kokoisen kuvan.
for silmukalla katsotaan kuinka paljon "elama" on vielä jäljellä ja lisätään aina yksi "life" kuva yksi pikseli oikealle.

Vaikeasti selitetty.


Ongelma:

Sitten itse koodin kimppuun

//peli.hpp
#ifndef _PELI_HPP
#define _PELI_HPP


namespace peli {
    int aja();

	struct alue {
		int x0, y0, x1, y1;
	};

    struct lifepack {
        float x, y;
    };
    struct enemy {
        float x, y;
    };
    struct point {
        float x, y;
    };
    struct pelaaja {
            struct timo {
            float x, y;
            float x0, y0;
			timo *nenampi, *hannampi;
        };
        timo *nena, *hanta;
        float suunta, vaihe, elama;
    };
}

#endif
//peli.cpp


namespace peli {
	// Pienin aikamäärä, jonka kello etenee. Liian lyhyt väli vaatii paljon
	// tehoa. Matopelissä 0.02 (eli 2 / 100) sekuntia on tarpeeksi lyhyt.
	static const float ajan_muutos = 0.02;
	static const float elama=100;
	static pelaaja uusi_mato();

}

peli::pelaaja peli::uusi_mato() {
	pelaaja m;
	m.elama=100; //yritin tässä saada alustettua elama muuttujaa, mutta ei auttanut, koska errori on piirtofunktiossa.
	m.suunta = m.vaihe = 0;
	m.nena = m.hanta = new pelaaja::timo; //täällä on jotain kopioitu koska tutustun näiden toimintaan.
	m.nena->nenampi = m.hanta->hannampi = 0;
	m.nena->x = m.nena->x0 = (pelialue.x0 + pelialue.x1) / 2;
	m.nena->y = m.nena->y0 = (pelialue.y0 + pelialue.y1) / 2;
	return m;
}
//ohjelma.cpp
//ohjelma.hpp on tismalleen samallainen kuin matopelissä.
//ja tästä puuttuu kaikki muut funktiot paitsi piirto, jotta pysyisi tässä foorumissa siistiniä.

namespace ohjelma {
	// Staattisia, siis vain tämän tiedoston käyttöön.
	static SDL_Surface *ruutu;
	static void piirra_kuva(SDL_Surface *kuva, int x, int y, bool keskikohta = false);
	namespace kuvat {
		static SDL_Surface *lataa(const char *nimi, bool lapinakyva);

		// Kuvat.
		static SDL_Surface *tausta_valikko;
		static SDL_Surface *valikko_peli, *valikko_peli_valittu;
		static SDL_Surface *valikko_lopetus, *valikko_lopetus_valittu;
		static SDL_Surface *saari, *PeliHahmo, *elamapaketti;
		static SDL_Surface *life, *notlife;
	}
}





void ohjelma::piirra_peli(peli::alue const& alue, peli::pelaaja const& pelaaja, peli::lifepack const& lifepack) {

	piirra_kuva(kuvat::saari, 0, 0);

	piirra_kuva(kuvat::notlife, 0, 0);
	for (float op=1; op <= m.elama; op++) //tässä tekeleeni
	{
        piirra_kuva(kuvat::life, op, 0);
	}
	const float yksikko_x = kuvat::PeliHahmo->w;
	const float yksikko_y = kuvat::PeliHahmo->h;

	// (Oletetaan, että alue mahtuu kerralla ruudulle!)
	const float keski_x = ruutu->w / 2 - yksikko_x * (alue.x0 + alue.x1) / 2;
	const float keski_y = ruutu->h / 2 - yksikko_y * (alue.y0 + alue.y1) / 2;

	for (peli::pelaaja::timo *j = pelaaja.hanta; j != 0; j = j->nenampi) {
		piirra_kuva(kuvat::PeliHahmo, keski_x + yksikko_x * j->x, keski_y + yksikko_y * j->y, true);
	}

	piirra_kuva(kuvat::elamapaketti, keski_x + yksikko_x * lifepack.x, keski_y + yksikko_y * lifepack.y, true);

	SDL_Flip(ruutu);
}

Errorit:
\tyopoydan_kansiot\CPelit\Timo ja Tomi - Saarella\data\ohjelma.cpp||In function `void ohjelma::piirra_peli(const peli::alue&, const peli::pelaaja&, const peli::lifepack&)':|
\tyopoydan_kansiot\CPelit\Timo ja Tomi - Saarella\data\peli.hpp|28|

error: invalid use of non-static data member `peli::pelaaja::elama'|
\tyopoydan_kansiot\CPelit\Timo ja Tomi - Saarella\data\ohjelma.cpp|202|

error: from this location|
\tyopoydan_kansiot\CPelit\Timo ja Tomi - Saarella\data\ohjelma.cpp|217|
||=== Build finished: 2 errors, 4 warnings ===|

En kylläkään tiedä itse mikä menee pieleen. Miten saan sen elaman alustettua oikein arvoon 100 ja piirrettyä elama muuttujan avulla ohjelmassa? :o


Ps. Koitin saada viestistä siistin.

Metabolix [04.03.2010 00:12:01]

#

Ota staattinen elämä pois, koska et käytä sitä ja oikea muuttuja on jo pelaaja-rakenteen sisällä, ja korjaa kaikki kohdat käyttämään pelaajan omaa elämää, kuten olet piirtofunktiossa jo tehnytkin. Koodistasi puuttui tuo virheen aiheuttanut kohta (ohjelma.cpp, peli::pelaaja::elama), mutta joka tapauksessa siinä olet tehnyt jotain väärin. Toistan: pitää tehdä kuten piirtofunktiossa.

Edit. Ja piirtofunktion virhe on siinä, että eihän kyseisessä funktiossa ole pelaaja-tyyppistä muuttujaa m, vaan sillä on muu nimi – löydätkö?

mika132 [04.03.2010 01:07:28]

#

Juu sain toimimaan kiitos. =)

Päätin muuttaa ohjauksen hiirtä seuraavaksi ja liitinkin kirjaston <cmath> tuonne, mutta ei silti tottele. Väittää ettei atan2 funktiota löydy mistään vai onko koodini aivan päin p*rsettä?

#include "peli.hpp"
#include "ohjelma.hpp"
#include <iostream>
#include <fcntl.h>
#include <cmath>
#include <io.h>
#include <cstdlib>
#include <ctime>
#include <SDL\SDL.h>

namespace peli {
	// Pienin aikamäärä, jonka kello etenee. Liian lyhyt väli vaatii paljon
	// tehoa. Matopelissä 0.02 (eli 2 / 100) sekuntia on tarpeeksi lyhyt.
	static const float ajan_muutos = 0.02;

	// Pelikentän rajat (x0, y0, x1, y1).
	static const alue pelialue = {-8, -6, 8, 6};

	// Jaokkeen ja omenan säteet, puoli yksikköä kummatkin.
	static const float jaokkeen_sade = 0.5, omenan_sade = 0.5;

	// Madon kääntymisnopeus radiaaneina sekunnissa, puoli kierrosta.
	static const float pii = 3.14159265358979323846;
	static const float kaannosnopeus = pii;

	static const float vaihenopeus = 2.7;
	static const float etenema = 0.65 * 2 * jaokkeen_sade;

	static const float matelun_heitto = 0.07;

	static const float elama=90;

	static pelaaja uusi_mato();
	static void tuhoa_mato(pelaaja& m);
	float angle(float cx, float cy, float px, float py, int Player_x, int Player_y, int Target_x, int Target_y);
	double rad2deg(double rad);
	static lifepack arvo_lifepack(pelaaja const& m);

	static void liikuta(pelaaja& m, bool oikealle, bool vasemmalle);
	static bool osuu_elamaan(pelaaja const& m, lifepack const& o);

	static inline float etaisyys(float x0, float y0, float x1, float y1) {
		float dx = x1 - x0, dy = y1 - y0;
		return std::sqrt(dx * dx + dy * dy);
	}
}

float peli::angle(float cx, float cy, float px, float py, int Player_x, int Player_y, int Target_x, int Target_y)
{
    float i;
    double ili=std::atan2((double)cx,(double)cy,(double)px,(double)py);
    i=ToDeg*ili;
    if (i<0)
    {
      return i+360;
    }
    else
    {
      return i;
    }
}

double peli::rad2deg(double rad){
    return ((rad * 180) / 3.1415927);
}





void peli::liikuta(pelaaja& m, bool oikealle, bool vasemmalle) {
    Uint8* nappi;
	//if (oikealle && !vasemmalle) {
		//m.suunta += ajan_muutos * kaannosnopeus;
	//} else if (vasemmalle && !oikealle) {
		//m.suunta -= ajan_muutos * kaannosnopeus;
	//}
        //kaikki yläpuolelta lähtee jos vaan saan tuon alapuolella olevan toimimaan:

	int hiiren_x, hiiren_y;
	hiiri=SDL_GetMouseState(&hiiren_x,&hiiren_y);
	int x_jana = (hiiren_x - m.nena->x);
	int y_jana = (hiiren_y - m.nena->y);
	double kulma = std::atan2((double)-y_jana, (double)x_jana);
	temp = rotozoomSurface(PeliHahmo, rad2deg(m.suunta), 1, 1);



    nappi = SDL_GetKeyState(NULL);
    if (nappi[SDLK_UP])
    {
	m.vaihe += ajan_muutos * vaihenopeus;
	while (m.vaihe >= 1)
	{
		m.vaihe -= 1;

		for (pelaaja::timo *j = m.hanta; j != m.nena; j = j->nenampi) {
			j->x0 = j->nenampi->x0;
			j->y0 = j->nenampi->y0;
		}
		m.nena->x0 += std::cos(m.suunta) * etenema;
		m.nena->y0 += std::sin(m.suunta) * etenema;
	}
            m.nena->x = m.nena->x0 + std::cos(m.suunta) * etenema * m.vaihe;
            m.nena->y = m.nena->y0 + std::sin(m.suunta) * etenema * m.vaihe;
    }
}

Ps. Kiitos paljon jos viitsitte auttaa vielä tämän kanssa.

E: kyllä pelaajalla oli nimi pelaaja. En vain ole koskaan käyttänyt tuota tyyliä enkä ymmärtänyt sitä heti. :)

Metabolix [04.03.2010 11:57:22]

#

Mikä noiden ongelmien ratkaisemisessa on niin vaikeaa? Voit tarkistaa äärimmäisen yksinkertaisilla hakusanoilla C++ atan2, mitä parametreja kyseiselle funktiolle annetaan. Kääntäjäkin antaa luultavasti aivan selkeän ilmoituksen:

error: too many arguments to function 'double atan2(double, double)'

Olet muuten sotkenut koodista monta olennaista asiaa. Esimerkiksi mitään SDL:ään liittyvää koodia ei pitänyt olla noissa muissa tiedostoissa, ainoastaan siinä yhdessä. Tämä ei ole huvin vuoksi tehty päätös, vaan näin ohjelman rakenne todella pysyy selkeämpänä. Jos et kykene toteuttamaan ohjelmaa tällä tavalla, se on vain osoitus siitä, ettet hallitse C++:n perusteita tarpeeksi hyvin.

Mitä ihmettä varten <fcntl.h> on?

Miksi säilytät kulman asteina, kun kaikki matematiikkafunktiot käyttävät radiaaneja?

mika132 [04.03.2010 16:41:58]

#

sain tuonkin pienen pähkäilyn jälkeen toimimaan. Tai melkein. Koodini tekee "PeliHahmo" kuvan valkoisesta tausta transparentin. Valkoinen tausta on (tarkistin) 255,255,255 ja kuvista joissa on 255,255,255 väriä tehdään läpinäkyvä. Kuitenkin tilanne on tämä:

Kuva


Ja koodini on tämä:

//peli.cpp
void peli::liikuta(pelaaja& m, bool oikealle, bool vasemmalle) {
    Uint8* nappi;

    float hiiri;
    int hiiren_x, hiiren_y;
    hiiri=SDL_GetMouseState(&hiiren_x,&hiiren_y);
	int x_jana = (hiiren_x - m.x);
	int y_jana = (hiiren_y - m.y);
	m.suunta = std::atan2((double)-y_jana, (double)x_jana);


    nappi = SDL_GetKeyState(NULL);
    if (nappi[SDLK_s])
    {
        m.y+=1;
    }
    if (nappi[SDLK_w])
    {
        m.y-=1;
    }
    if (nappi[SDLK_d])
    {
        m.x+=1;
    }
    if (nappi[SDLK_a])
    {
        m.x-=1;
    }
}
//ohjelma.cpp
#include "ohjelma.hpp"
#include <iostream>
#include <stdexcept>
#include <cmath>
#include <SDL/SDL.h>
#include <SDL_rotozoom.h>

namespace ohjelma {
	// Staattisia, siis vain tämän tiedoston käyttöön.
	static SDL_Surface *ruutu;
	static void piirra_kuva(SDL_Surface *kuva, int x, int y, bool keskikohta = false);
	namespace kuvat {
		static SDL_Surface *lataa(const char *nimi, bool lapinakyva);

		// Kuvat.
		static SDL_Surface *tausta_valikko;
		static SDL_Surface *valikko_peli, *valikko_peli_valittu;
		static SDL_Surface *valikko_lopetus, *valikko_lopetus_valittu;
		static SDL_Surface *saari, *PeliHahmo, *elamapaketti;
		static SDL_Surface *life, *notlife, *pistooli;
	}
}

void ohjelma::alku() {
	std::clog << "ohjelma::alku()" << std::endl;
	if (SDL_Init(SDL_INIT_VIDEO) != 0) {
		throw std::runtime_error(SDL_GetError());
	}
	ruutu = SDL_SetVideoMode(800, 600, 32, SDL_DOUBLEBUF|SDL_FULLSCREEN);
	if (!ruutu) {
		throw std::runtime_error(SDL_GetError());
	}
	SDL_WM_SetCaption("Timo ja Tomi - Saarella", "Timo ja Tomi - Saarella");

	kuvat::life = kuvat::lataa("data/grafiikka/life.bmp", false);
	kuvat::saari = kuvat::lataa("data/grafiikka/saari.bmp", false);
	kuvat::notlife = kuvat::lataa("data/grafiikka/notlife.bmp", false);
	kuvat::tausta_valikko = kuvat::lataa("data/grafiikka/valikko_tausta.bmp", true);
	kuvat::PeliHahmo = kuvat::lataa("data/grafiikka/peli_hahmo.bmp", true);
	kuvat::valikko_peli = kuvat::lataa("data/grafiikka/aloita_peli.bmp", true);
	kuvat::valikko_peli_valittu = kuvat::lataa("data/grafiikka/aloita_peli_valittu.bmp", true);
	kuvat::valikko_lopetus = kuvat::lataa("data/grafiikka/lopeta_peli.bmp", true);
	kuvat::valikko_lopetus_valittu = kuvat::lataa("data/grafiikka/lopeta_peli_valittu.bmp", true);
	kuvat::elamapaketti = kuvat::lataa("data/grafiikka/lifepack.bmp", true);
	kuvat::pistooli = kuvat::lataa("data/grafiikka/pistooli.bmp", true);

	// Nollataan sekuntilaskuri.
	sekunnit(true);
}

// Lataa kuvan ja optimoi sen piirtoa varten.
static SDL_Surface *ohjelma::kuvat::lataa(const char *nimi, bool lapinakyva) {
	// Jos lataus onnistuu...
	if (SDL_Surface *tmp = SDL_LoadBMP(nimi)) {
		// Yritetään optimoida.
		if (SDL_Surface *opti = SDL_DisplayFormat(tmp)) {
			// Tuhotaan alkuperäinen ja palautetaan optimoitu.
			SDL_FreeSurface(tmp);
			tmp = opti;
		}
		// Asetetaan läpinäkyvä väri (magenta eli pinkki).
		if (lapinakyva) {
			SDL_SetColorKey(tmp, SDL_SRCCOLORKEY, SDL_MapRGB(tmp->format, 255, 255, 255));
		}
		// Palautetaan kuva.
		return tmp;
	}
	// Muuten heitetään virhe.
	throw std::runtime_error(SDL_GetError());
}



void ohjelma::piirra_peli(peli::alue const& alue, peli::pelaaja const& pelaaja, peli::lifepack const& lifepack) {
	piirra_kuva(kuvat::saari, 0, 0);

	piirra_kuva(kuvat::notlife, 0, 0);
	for (float op=0; op <= pelaaja.elama; op++)
	{
        piirra_kuva(kuvat::life, op, 0);
	}
	if (pelaaja.ase==1)
	{
        piirra_kuva(kuvat::pistooli, 0, 30);
	}
	const float yksikko_x = kuvat::PeliHahmo->w;
	const float yksikko_y = kuvat::PeliHahmo->h;

	// Lasketaan lisättävä pikselimäärä, jotta pelialue tulee ruudun keskelle.
	// (Oletetaan, että alue mahtuu kerralla ruudulle!)
	const float keski_x = ruutu->w / 2 - yksikko_x * (alue.x0 + alue.x1) / 2;
	const float keski_y = ruutu->h / 2 - yksikko_y * (alue.y0 + alue.y1) / 2;
	SDL_Surface *temp;
	temp = rotozoomSurface(ohjelma::kuvat::PeliHahmo, rad2deg(pelaaja.suunta), 1, 1);
        piirra_kuva(temp, pelaaja.x - temp->w / 2, pelaaja.y - temp->h / 2, false);
        SDL_FreeSurface(temp);

	piirra_kuva(kuvat::elamapaketti, keski_x + yksikko_x * lifepack.x, keski_y + yksikko_y * lifepack.y, true);

	SDL_Flip(ruutu);
}

vehkis91 [04.03.2010 18:43:48]

#

Edit: unohdin mainita ne turhat parametrit, eli vasemmalle ja oikealle, ovat tässä tapauksessa turhia.


Mitkä noi parametrit

void peli::liikuta(pelaaja& m, bool oikealle, bool vasemmalle)

ovat? Käisttääkseni tuoss sinun pelissäsi ei tarvita noita parametreja...

mika132 [04.03.2010 18:59:42]

#

Juu ei tarvita ja otinkin ne pois kun huomasin sen itse tuossa tunti takaperin, mutta se ei auttanut tuohon ongelmaan mikä minulla on. Olen jo koittanut kaiken näköistä, mutta mikään ei tepsi.

E: Sain läpinäkyvyyden, mutta miksi tuohon karttaan jää musta "reikä"? :o


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta