Zprovozni si v Apache cgi scripty.
Zasláno z mobilního telefonu.
Přijde mi, že trochu nevíš, co chceš. Nebo to popisuješ dost divně:
PHPMyAdmin nevytvořil funkční soubor se známou příponou
Co vím, PHPMyAdmin neumí vytvářet databázové soubory. Jen export struktury (plus možná dat) do souboru pro načtení v jiné databázi/programu. K takovému souboru nebudeš přistupovat jako k databázi, ale jako k texťáku.
Mám funkční připojení na PHPMyAdmin databázi
PHPMyAdmin nemá žádnou databázi, je to jen správce databáze.
Jak říkal KIT, použij SQLite. Knihovnu pod .NET na ní určitě seženeš. Databázi budeš mít v jednom souboru, bez nutnosti nějakého daemona na pozadí.
Než jsem se dostal k nějakým opravám, jen jsem přepsal podmínky ve funkci deleteNodes. Pokud máš dobře napsané ty testy, pak byl zakopaný pudl právě zde. Nic nepadá, ve výpisu je OK. I dosazení 4 funguje.
Node *deleteNodes(Node *node, int value){
// Pokud je node prázdný
if( node != NULL ) {
// Pokud je hodnota nodu větší než předaná hodnota
if ( value < node->key ) {
node->left = deleteNodes(node->left, value);
// Pokud je hdonota menší než předaná hodnota
} else if ( value > node->key ) {
node->right = deleteNodes(node->right, value);
// Pokud je hodnota nodu shodná s předanou hodnotou
} else {
// Pokud nod nemá právého ani levého potomka
if( node->left == NULL && node->right == NULL){
free(node);
node = NULL;
// Pokud má potomka napravo
} else if( node->left == NULL){
Node *temp = node;
node = node->right;
free(temp);
// Pokud má potomka nalevo
} else if(node->right == NULL){
Node *temp = node;
node = node->left;
free(temp);
// Pokud má dva potomky
} else {
Node *temp = findMin(node->right);
node->key = temp->key;
node->right = deleteNodes(node->right, temp->key);
}
}
}
return node;
}
Možná pomůže kód:
#include <cstdlib>
#include <cstdio> // pro printf
#include <cmath> // pro fabs
int main () {
// Porovnávané číslo vůči nule
double x = 0.000001;
// Všechna čísla, jejichž absolutní hodnota bude menší než y jsou považovány za nulu
double y = 0.001;
if ( fabs( x ) < y ) {
printf("X = 0\n");
} else {
printf("X != 0\n");
}
}
Pokud budu vycházet z původního zápisu funkce insertNodes:
insertNodes( Node* node, int key ) {
// něco dělá
}
//volání
insertNodes( tree->root, 3 )
znamená to, že zavoláním funkce insertNodes vytváříš novou proměnnou node, která bude ukazovat na to, na co ukazuje root.
Jestliže root už nějaký obsah měl (ukazoval na platnou strukturu Node) pak změnou proměnné node:
node->key = 11;
dosáhneš změny i v tree->root->key.
Pokud ale root, potažmo node bude obsahovat NULL, přiřazením nějaké hodnoty do node už nezměníš to, kam ukazuje root. Po ukončení platnosti funkce insertNodes se proměnná node smaže a ty o data přijdeš.
V jiném případě, kdy bys do funkce chtěl dostat proměnnou, kterou ve funkci chceš měnit (bez toho abys ji musel vracet, například proto, že návratovou hodnotu chceš použít jako indikaci (ne)zdaru) použil bys ukazatel:
int cislo = 10;
foo( int * i ) {
// neco dela
}
foo( &cislo );
Root ale už ukazatel je, jednoduché doplnění ampersandu do volání funkce insertNodes( &root->child, 3) bude mít za následek chybovou hlášku:
main.cpp:23:22: error: cannot convert 'Node**' to 'Node*' for argument '1' to 'Node *insertNodes(Node*, int)'
Což už tě samo navádí k tomu, že potřebuješ ukazatel na ukazatel.
insertNodes(Node **node, int key) {
// něco dělá
}
// Volání
insertNodes( &tree->root, key);
Tím vytvoříš po volání funkce proměnnou, která ukazuje na root. K root se dostaneš pomocí *node. Editací této proměnné upravuješ zároveň proměnnou root. Proto ti po zániku lokální proměnné node zůstanou všechna data v pořádku až do smazání tree->root.
Whew, jestli jsi to dočetl až sem, máš u mě palec hore!
Omlouvám se, chtělo to dodatečné úpravy.
#include <cstdio>
#include <cstdlib>
typedef struct Node {
int key;
struct Node* parent;
struct Node* left;
struct Node* right;
} Node;
typedef struct BinarySearchTree {
Node* root;
} BinarySearchTree;
// nahoře je předdefinované
// dole napsané mnou
Node *createNode(int key){
Node *newNode = (Node*)malloc(sizeof(Node));
newNode->key = key;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
Node *insertNodes(Node **node, int key){
if( *node == NULL){
*node = createNode(key);
return *node;
} else {
if( key <= (*node)->key){
(*node)->left = insertNodes( &((*node)->left), key);
return *node;
} else {
(*node)->right = insertNodes( &((*node)->right), key);
return *node;
}
}
}
void insertNode(BinarySearchTree *tree, int key) {
insertNodes( &tree->root, key);
}
int main () {
BinarySearchTree *tree = (BinarySearchTree*)malloc(sizeof(BinarySearchTree));
tree->root = NULL;
insertNode( tree, 3);
if ((tree->root == NULL) || (tree->root->key != 3)) {
printf("NOK - chybne vkladani do prazdneho stromu\n");
} else {
printf("Pointer: %p, Key: %i", tree->root, tree->root->key);
}
}
Vyprázdnění paměti nechávám na vás ;)
Node *insertNodes(Node **node, int key){ // << Zde změna
if( *node == NULL ){ // << Zde změna
node = createNode(key);
return node;
}else { // << Pro úklid a můj duševní klid
if(key <= node->key){
node->left = insertNodes(node->left, key);
return node;
}else{
node->right = insertNodes(node->right, key);
return node;
}
}
}
void insertNode( BinarySearchTree *tree, int key ) {
insertNodes( &tree->root, key); // << Zde změna
}
// mělo by to fakčit
Tuším že při udělení práv pro spuštění všem:
chmod a+x script.sh
bude uživatel moci spustit váš skript bez jakéhokoliv dalšího nastavování.
To samé bude fungovat i u aplikace. Samotný skript je v takovém případě zbytečný. Nicméně může pomoci při řešení dalších problémů - nastavení adresáře, kontrola přítomnosti knihoven, atd.
Edit: Děkuji za upozornění, opraveno.
Toto by mělo vypsat všechny desetinné čísla.
printf( "%.*f", proměnná );
Další možnost je zadání počtu znaku natvrdo. Za A dosaď šířku před desetinnou čárkou. Pokud nebude mít číslo dostatek číslic, bude zarovnano mezerami. Za B dosaď počet číslic za čárkou.
printf( "%A.Bf", proměnná );
Pokud bys četl pouze ASCII soubor, kde každý znak je reprezentován skutečně jednou hodnotou, mohlo by fungovat něco takového.
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
std::string text;
std::stringstream stream;
int main() {
// Otevřeme soubor
std::ifstream file( "test.txt", std::fstream::out );
// Pokud se soubor podařilo otevřít
if( file.is_open() ) {
// Přejdeme až na konec souboru
file.seekg( 0, std::ios::end );
// Získáme délku souboru
int length = file.tellg();
// Opět přejdeme na začátek
file.seekg(0, std::ios::beg);
// Zeptáme se uživatele, kam chce přesunout "kurzor"
std::cout << "Pozice kurzoru: (0-" << length << "):";
int seek_position;
std::cin >> seek_position;
// Pokud je pozice v rozsahu 0 až délka souboru
if( seek_position >= 0 && seek_position <= length ) {
// Přesuneme se na zadanou pozici
file.seekg( seek_position, std::ios::beg );
// Načteme text
stream << file.rdbuf();
text = stream.str();
// Vypíšeme text
std::cout << text << std::endl;
// Pokud uživatel zadal neplatnou pozici
} else {
std::cout << "Spatna pozice!" << std::endl;
}
// Pokud se soubor nezdařilo otevřít
} else {
std::cout << "Soubor se nezdarilo otevrit." << std::endl;
}
return 0;
}
Obsah souboru:
Test pohybovani kurzorem v souboru.
Zkusime preskocit na tento radek.
I tento radek bude zobrazen!
Výstup:
# Pozice kurzoru: (0-98): 36
> Zkusime preskocit na tento radek.
> I tento radek bude zobrazen!
Problém je, že znaky jako ěščřžýáíé jsou uloženy jako základní znak a háček. Tím pádem získáš dvojnásobnou délku, která ve skutečnosti neodpovídá skutečné délce. Tady asi bude jednodušší celý soubor (nebo jeho část) načíst do paměti a pracovat s textem až zde.
Dost záleží, co s tím souborem pak chceš dělat. Následujícím kódem získáš postupně ze souboru všechny znaky. Já je jen vypisuji, ale ty si je můžeš uložit do pole, std::vectoru, std::stringu nebo čehokoliv, co ti bude pro tvé použití vyhovovat nejlépe.
// bude obsahovat právě načtený znak
char znak;
// Otevře soubor
std::fstream soubor( "jmenosoubor.txt", std::fstream::in );
//.. test správného otevření vynechán
// Dokud je co číst
while ( soubor >> std::noskipws >> znak) {
// Vypíše jeden znak
std::cout << znak;
}
Podle tvé analogie bych mohl být třeba mechanikem. Netřeba se nic učit, vždyť na webu je spousta fotek aut a když nebudu vědět co dál (což bude hned jak zvednu kapotu), řeknu zkušenýmu mechanikovi od vedle... Bez zakladní povědomosti o tom jak je funguje se na webu dřív nebo později stejně neobejdeš.
Pokud nechceš, aby vyskakoval alert, smaž funkci alert.
Protože tenhle řádek:
document.title = elapsed;
nastavuje čas do titulku, ne do elementu, ve kterém je kód vložen.
Doporučil bych ti přečíst si něco o Javascriptu a kouknout na ty odkazy, které ti peter poslal.
Pokud budeš chtít, aby ti uživatel nemohl časovač "oblbnout", budeš stejně muset ukládat čas posledního zadání CAPTCHA do databáze. Při dalším pokusu pak musíš na serveru zkontrolovat, zda uplynulo skutečně dostatek času.
#10 Marek
V porovnání a<b nemá proměnná a žádný obsah. Nejspíš tedy nějaký obsah má, ale není pro vás relevantní. Dalším tipem je pojmenovávat proměnné trochu smysluplněji, než jednotlivými písmeny.
Pokud chcete vypsat více čísel, budete muset použít pole. Tady už by se možná vyplatilo si všechna čísla zapsat do pole, toto pole seřadit od nejmenšího po největší, rozdělit na stovce a poté vypisovat všechna čísla menší nebo větší, tak jak jsou uložena v poli na jednu nebo druhou stranu.
// Vektor naplnime vsemi cisly. Mezi ně vložíme i naší 100
std::vector<int> cisla;
// Seřadíme
std::sort( cisla.begin(), cisla.end() );
// Najdeme naší stovku
std::vector<int>::iterator it = std::find( cisla.begin(), cisla.end(), 100);
// Všechna čísla od cisla.begin() po it jsou menší než 100, seřazena od nejmenšího po největší.
// Všechna čísla od it po cisla.end() jsou větší než 100, seřazena od nejmenšího po největší.
Když na to tak koukám, je to možná overkill. Nicméně princip bude stejný i při použití standardních cčkových polí, ručního řazení atd. Jen to bude více psaní ;)
Pokud to chceš řešit pomocí session:
<?php
// Nejprve musíš session povolit. To uděláš funkcí session_start() na úplném začátku souboru.
session_start();
?>
<!-- Teprve zde začíná samotný HTML obsah -->
<!DOCTYPE html>
<html>
<body>
<?php
// Hodnoty nastavuješ stejně jako v případě $_POST, nebo $_GET
$_SESSION["klic"] = "hodnota";
// Stejně tak je i použiješ
echo "Proměnná: " . $_SESSION["klic"];
?>
</body>
</html>
Rušení session a další viz manuál.
Další možností je použití mod_rewrite. Tím buď zavést pěkné url - místo ID si zobrazovat třeba jméno nebo provést podstrčení (teoreticky by to snad mělo jít?).
Nebo můžeš použít javascript:
<form method="POST" action="kamchcesjit.php" id="formular" style="display:none;">
<input type="hidden" name="id" value="69" />
</form>
<a href="" onclick="document.getElementById('formular').submit();return false;" />
Nicméně snažit se neměnit adresu ale obsah je dle mého špatný nápad. Už jen kvůli uživatelům. Jak pošlou kamarádovi odkaz na hru, kterou si právě prohlížejí?
Jinak osobně preferuji tebou zamítnutý netbeans, což ti asi moc nepomůže :). Patří spolu s Eclipse k těm lepším IDE pro Javu.
Jestli to chápu dobře, nejprve vytvoříte proměnné PocetM a PocetN. Do nich načtete počet sloupců a řádků. Pole A ale máte vytvořeno předem pouze pro 10 prvků. Zápis by měl být spíše:
A:array[1..pocetM,1..pocetN] of integer;
S tím, že pole vytvoříte až poté, co víte jak velké bude (po načtení hodnot do PocetM a PocetN).
Funkce random vrací čísla od 0 do 99, což neodpovídá zadání. Přičtěte jedničku a pak jen kontrolujte, zda číslo není větší než 99 (pak ho nastavte na 99).
mojeNahodneCislo = random(100) + 1;
if mojeNahodneCislo > 99 then
begin
mojeNahodneCislo := 99;
end;
Poslední dva cykly for vypadají divně. Pokud M jsou řádky a N jsou sloupce, první řádek je na M = 0, stačí iterovat N. Stejně tak poslední řádek je na M = PocetM a stačí iterovat N.
Pro rychlejší běh bych doporučoval omezit počet for v kódu na absolutní minimum. Cokoli lze udělat při prvním průběhu, udělejte to! Například sčítat první a poslední řádek lze při vytváření čísel. To samé by platilo o výpisu matice do konzoly, zadání však požaduje volání funkce.
Pascal neovládám, takže ti to napíšu jen v pseudokódu. Přepsat to by neměl být problém:
// Tyto proměnné je nutné načíst - buď z parametrů předaných skriptu, od uživatele nebo ze souboru.
integer sloupcu; // Tohle je šířka matice (M)
integer radku; // Tohle je výška matice (N)
// Dvourozměrné pole alokované s dostatkem místa pro naše čísla
integer matice[radku][sloupcu];
// Předběžné proměnné pro sumu prvního a posledního řádku
integer suma_prv_radek = 0;
integer suma_pos_radek = 0;
for( integer radek = 0; radek < vyska; radek++ ) {
for( integer sloupec = 0; sloupec < sirka; sloupec++ ) {
// Vygenerujeme náhodné číslo od 0 do 99 a uložíme ho do matice
matice[radek][sloupec] = rand( 1, 99 );
// Pokud pracujeme s prvním řádkem, rovnou si připočteme aktuální hodnotu k sumě prvního řádku.
if ( radek == 0 ) {
suma_prv_radek += matice[radek][sloupec];
}
// Pokud pracujeme s posledním řádkem, rovnou si připočteme aktuální hodnotu k sumě posledního řádku.
if ( radek == vyska-1 ) {
suma_pos_radek += matice[radek][sloupec];
}
}
}
function zobrazMatrix( integer pole[][], integer radky, integer sloupce ) {
for ( integer x = 0; x < radky; x++ ) {
for( integer y = 0; y < sloupce; y++ ) {
// Vypíše do konzole hodnotu pole a mezeru
output( pole[x][y] );
output( " " );
}
// Odsadí nový řádek matice
output( "\n" );
}
}
// Zobrazíme matrix do konzoly
zobrazMatrix( matrix, radku, sloupcu );
// Vypíšeme, výsledek
if( suma_prv_radek > suma_pos_radek ) {
output("Suma prvního řádku je větší než suma posledního řádku.");
} else if( suma_prv_radek < suma_pos_radek ) {
output("Suma posledního řádku je větší než suma prvního řádku.");
} else {
output("Součet hodnot prvního i posledního řádku jsou stejné.");
}
Kód ber jen orientačně, psal jsem ho narychlo. Snad pomůže ;).
Změň text field na zadání data v pevně dané formě (třeba d. m. y). Celkem se mi líbí řešení z Androidu, které vypadá celkem použitelně.
Při pevném formátu data není s porovnáváním problém.
Funkce open_file_read a open_file_write by měly nejspíš vracet ukazatel na FILE. V takovém případě jsi vlastně ale napsal funkci, která se od fopen liší jen v tom, že v případě neúspěchu vypíše hlášku.
FILE *open_file_read(){
// Nastavuj ukazatele na NULL nebo nulu hned při jejich deklaraci
FILE *zdroj = 0;
zdroj = fopen("zdroj.txt", "r");
if ( !zdroj ){
printf("Nepodařilo se otevřít soubor \n");
return 0;
}
// Vrátíme odkaz na nově otevřený soubor
return zdroj;
}
FILE *open_file_write(){
// Nastavuj ukazatele na NULL nebo nulu hned při jejich deklaraci
FILE *cil = 0;
cil = fopen("cil.txt", "w");
if ( !cil ){
printf("Nepodařilo se otevřít soubor \n");
return NULL;
}
// Vrátíme odkaz na nově otevřený soubor
return cil;
}
Netuším jak hluboké máš znalosti a jestli jsi při učení se došel i k předávání parametrů, jestliže ano, bylo by dobré k funkcím přidat parametr se jménem souboru. Funkce tak budou univerzálnější - budou moct otevřít jakýkoli soubor (s ohledem na práva).
FILE *open_file_read( const char *soubor ){
FILE *zdroj = 0;
// Změníme první parametr funkce fopen
zdroj = fopen( soubor , "r");
if ( !zdroj ){
printf("Nepodařilo se otevřít soubor \n");
return 0;
}
return zdroj;
}
A když koukám na ty poslední funkce, pracují s proměnnými, které nejsou v jejich oboru viditelnosti. Přepiš je tak, aby jako parametry braly ukazatel na FILE a tento soubor zavřely. Pak stačí jen jedna funkce.
int close_file( FILE *soubor ){
// změníme parametr funkce fclose
fclose( soubor ) == 0 ? return 1 : return 0;
}
#2 vitamin
Co získám druhou cestou? Pokud odvodím novou třídu od RenderXY, bude mít jen metodu render( int x, int y) - což je správně. V druhém případě ale po odvození od Render získám stejný stav jako mám teď. Tedy odvozená třída bude mít jak render() tak render(int x, int y)...
Dobré odpoledne,
Mám virtuální třídu Renderable, která je předkem pro všechny další třídy, které je možné vykreslit do okna. Tato třída mimo jiné obsahuje metody render(), render(int x, int y). U některých potomků (Texture, Image, ...) je ale nevhodné (alespoň z mého hlediska) aby si pamatovali svou pozici, využívají tedy pro vykreslení metodu render( int x, int y ). Složitější potomci (Avatar, Widget, ... ) by si na druhou stranu měli svou pozici pamatovat a využívají bezparametrickou metodu render(). V jejich případě nevidím v druhé odvozené metodě žádný přínos. Co s ní?
Mám ji u potomka dát mezi private aby ji nešlo volat? Volat uvnitř bezparametrickou metodu a ignorovat předané parametry? Nebo jde celkově o špatný návrh a je třeba rozdělit rodiče na dva (nebo jiný zásah do návrhu)?
Předem děkuji za Vaše nápady.
#4 vitamin
Nie, ak chces volat aj nekonstantne metody tak musis urobyt kopiu premennej
To neumožní editovat vnitřní instanci "zapouzdřené" třídy.
vytvorit nekonstantny geter
Jde vytvořit přetíženou metodu na základě toho, zda je const? Jednu pro kopírovací konstruktor a druhou pro získání nekonstantní reference pro použití "zvenčí".
pripadne dat premennu verejnu a vykaslat sa na getre
To vypadá jako možné řešení. Nicméně moje otázka stále trvá, není to, že řeším podobné problémy způsobeno špatným návrhem tříd a jejich vzájemné spolupráce?
Dobrý den,
momentálně řeším problém týkající se práce s třídami. Pravděpodobně jsem při studiu OOP něco důležitého přehlédl, protože dlouhodobě bojuji s tím, jak mám z třídy vracet instanci privátního člena.
class Obal {
private:
Prvek prvek;
public:
Prvek getPrvek1() const { // 1
return this->prvek;
}
Prvek &getPrvek2() const {
return this->prvek;
}
Prvek *getPrvek3() const {
return &this->prvek;
}
}
Pokud bych chtěl z instance třídy Obal dostat vnitřní třídu Prvek, kterou z metod bych měl použít? V prvním případě se Prvek "překopíruje", takže bych ve výsledku neměnil vnitřní instanci.
Ve druhém případě pravděpodobně bude kompilátor skřehotat kvůli převodu z const Prvek na &Prvek.
Třetí případ dopadne stejně jako druhý. Problém s převodem const Prvek na *Prvek.
Ve třetím případě by se chyba odstranila smazáním const za jménem metody. To mi ale znemožní takovou metodu volat například v kopírovacím konstruktoru:
Obal::Obal( const Obal &original ) {
this->prvek = *original.getPrvek3();
}
Takže na jednu stranu potřebuju, aby metoda byla const - pro použití v kopírovacím konstruktoru, ale také, aby nebyla const - a mohl jsem volat nekonstantní metody třídy Prvek.
Jde o špatný návrh tříd? Dědění se mi v tomto případě zdá jako špatný nápad. Obal není speciálním případem Prvku, jen využívá jeho metod.
Jak se řeší podobné případy?
Děkuji.
Dobrý podvečer,
často se setkávám s tím, že potřebuji předat do nějaké třídy "odkaz" na třídu další. Například do seznamu všech postaviček na mapě přidat jednotlivé postavičky.
Ze seznamu bych chtěl umět jednotlivé postavičky upravovat a to tak, aby se změna projevila u dané postavičky i mimo seznam. Naopak změnění postavičky musí reflektovat postavička v seznamu.
Chápu že mám v zásadě asi dvě možnosti. Předání pomocí reference nebo ukazatele. Bohužel v těchto pojmech trochu plavu... Nevím kdy použít kterou. Obecně se snažím předávat vše pomocí hodnoty ( základní typy jako int) nebo referencí (třídy). Ukazatele vesměs nepoužívám, protože to znamená další práci se správou paměti navíc.
V seznamu postaviček mám vektor, list atd. Občas je potřeba data zase ze seznamu vytáhnout. Vytahovat referenci není asi nejchytřejší nápad (při změně vektoru, listu budou neplatné), takže se většinou uchyluji k použití ukazatele. Podobný postup se mi ale vůbec nezdá. Člověk používá tečkovou notaci:
Seznam.metoda()
a najednou musí používat šipku:
Seznam.dejPostavicku()->zmenJmeno("Pepa")
Konečně tedy položím otázku. Je můj postup (vracení referencí, pokud to jde, jinak pomocí ukazatele) ten správný způsob? Není nějaký lepší? V jakých případech se vyplatí více použít reference a kdy ukazatel? Děkuji za odpovědi.
Je jich spousta. Namátkou třeba highlight.js nebo SyntaxHighlighter
#1 rodinne.baleni.ryze
V QT to jde taky. Jinak záleží na tom, co preferuješ. Můžeš použít winsock, ale počítej s tím, že to bude běžet jen pod Windows.
Boost je Boost, většinou to znamená tisíce funkcí a souborů, které nikdy nepoužiješ, ale jakmile do toho pronikneš, získáš velmi účinný nástroj. Někteří na něj nedají dopustit, jiní se ho bojí jako čert kříže. Záleží na preferencích.
Co se mě osobně týče, zkusil bych najít nějakou vysokoúrovňovou a multiplatformní knihovnu. Když se jednou mám něco učit, tak chci abych to mohl použít na co nejvíce projektů.
#2 Tom
predpokladam, ze vse pocitas a vykreslujes v jednom threadu a ve sve herni smycce nedas procesoru ani instrukci odpocinout.
Ano, vše jede v jednom threadu. Zatím jsem na toto téma nic moc nečetl, tak zkusím jen takový nápad. Pomohlo by limitovat FPS třeba na 60 a tím dát procesoru trochu odpočinout?
#3
o errory ktore si poslal sa nemusis start (nie su z tvojho kodu)
A mohu se zeptat, jak je možné že valgrind hlásí chyby v ostatních knihovnách? To je memtest takový pedant, nebo jsou v základních systémových, potažmo grafických/zvukových knihovnách memory leaky?
Ahoj, snažím se naprogramovat jednoduchou hru v C++ za použití knihovny SDL. Momentálně hra umí načíst mapu, přehrávat hudbu a pohybovat s panáčkem.
Vše funguje (alespoň co se po vizuální stránce zdá) dobře. Postavička se pohybuje, hudba se neseká a mapa se načítá jak má. Kdyby ale všechno fungovalo tak perfektně, asi bych nepsal ;).
Jen tak ze zvědavosti jsem si vedle spuštěné hry zapnul i top (program na sledování využití CPU a paměti). Využití CPU se drží na 23%. To mi přijde dost (na to, jak hra vypadá a poměr proti ostatním aplikacím, které nevyužívají ani 2-3%). Někde jsem četl, že vykreslování se samotným SDL je pomalé, takže jsem CPU nevěnoval až takovou váhu. Horší to ale bylo s pamětí. Využití začíná někde na 1-2%, ale postupně roste. Schválně jsem chvíli počkal a po 2 minutách jsem byl na 80%.
Několik záseků jsem už odstranil (třeba generování SDL_Surface s mapou v každém cyklu, přidal několik SDL_FreeSurface atd..
Valgrind hlásí (převážně) chyby v SDL jako takovém viz. pastebin. Valgrind používám prvně, takže si jeho hlášky možná špatně vykládám.
Kdyby měl někdo zájem nahlédnout do zdrojových kódů: Download Přiloženy jsou i projektové soubory pro Netbeans a všechna potřebná data. Některé parametry jsou napsané natvrdo, jde jen o testovací nastavení.
Je normální, že i takto jednoduchá hra vytěžuje procesor na 20%? Vyřešilo by to spojení s OpenGL? V čem by mohl být schovaný memory leak (alespoň tipy)?
Zkus se kouknout na specifikaci vektoru. Popřípadě na spojový seznam. Oboje už tu bylo zmíněno.
Samozřejmě můžeš čísla ukládat třeba do souboru, řetězce atd...
// Z čeho budu mazat
string str("(555) 555-5555");
// Co chci mazat
char chars[] = "()-";
for (unsigned int i = 0; i < strlen(chars); ++i) {
// Nezapomeň vložit #include <algorithm>
str.erase (std::remove(str.begin(), str.end(), chars[i]), str.end());
}
// výsledek: 555 5555555
cout << str << endl;
V tutoriálech popisujících SDL skoro vždy zpracování událostí demonstrují na následujícím kódu:
SDL_Event event;
while( SDL_PollEvent( &event ) ){
switch( event.type ){
case SDL_KEYDOWN:
printf( "Key press detected\n" );
break;
case SDL_KEYUP:
printf( "Key release detected\n" );
break;
default:
break;
}
}
Pokud budu načítat tři obrázky, které následně zobrazím, počkám na stisknutí křížku nebo ESC a celou aplikaci ukončím, bude mi něco podobného stačit.
V případě že budu mít několik objektů (dejme tomu - okno, tlačítko, textové pole), které se mají v reakci na události nějak chovat, bude situace trochu složitější. V zásadě mě napadla dvě řešení:
A) Do každého objektu vložit metodu handleEvents(SDL_Event *event). Tato metoda projde všechny události které jsou pro daný objekt zajímavý a něco udělá.
while( SDL_PollEvent( &event ) ){
switch( event.type ){
case SDL_KEYDOWN:
printf( "Key press detected\n" );
break;
case SDL_KEYUP:
printf( "Key release detected\n" );
break;
default:
break;
}
// button.handleEvents(&event);
}
B) Druhá možnost, která mě napadla byla vytvoření jednoho hlavního objektu, který by v sobě uschovával seznam akcí na které chci reagovat a funkcí, které se v reakci na událost mají spustit.
Do tohoto objektu bych některou metodou přidal tzv. listenery pro každý objekt, který se má chovat v závislosti na událostech. Místo toho abych do hlavní smyčky programu vložil pro každý objekt řádek s mujobjekt.handleEvent(&event), stačilo by volání hlavního objektu, který by se o zbytek postaral.
Používá se v reálu některá z mnou popsaných metod, nebo se pro zpracování událostí a předání informací o události ostatním objektům používá něco úplně jiného?
Děkuji za vaše odpovědi,
Lorin
Mám kód, ve kterém využívám std::multimap. Do mapy vkládám a odebírám z ní prvky. Po vložení a smazání několika prvků, se mi ale přestane správně řadit. Normálně by mapa měla být seřazena podle klíče (jako klíč používám int32_t a jako hodnotu ukazatel na třídu, to celé vkládám jako std::pair).
Je problém ve využití int32_t, nebo std::multimap po smazání prvky neseřadí a musím se o to postarat sám? Nebo je problém v použití defaultního porovnávače std::less?
Děkuji za rady.
Tak jsem možná našel něco, co se hodně blíží tomu, co jsem hledal. Prošel jsem to jen tak, narychlo, ale vypadá to dobře.
Link: http://www-cs-students.stanford.edu/~amitp/gameprog.html
Což o to, o SDL, OpenGL popř DirectX vím, ale chtěl jsem do nich jít s jistou znalostí toho, jak fungují některé obecně používané věci pod kapotou. Takové obecné blábolení o tom, jak se věci mají, fungují a jaké jsou možnosti řešení.
Takže díky za rady, kouknu se do zdrojáků nějaké knihovny a zkusím ještě něco vygooglit.
To jsme si nejspíš moc nerozuměli. Hru chci rozhodně dělat v C++. GameMaker jsem zkoušel dříve a nevyhovoval mi. Moc klikání.. Vím že je možná nějaký lepší jazyk než C++ do začátku, ale celkem ho ovládám tak to chci zkusit v něm.
K principům... Mě šlo spíše o to, jak se jednotlivé věci (mnou jmenované) v herním prostředí nejčastěji řeší. Například jakým způsobem se počítá (v pathfindingu), kterou cestou se herní postavička dá. Jak se řeší tvorba tile-based mapy atd... Třeba jako odpověď na můj druhý příklad bych si představoval něco jako Tile Based Games. Jde sice o příklad k Flashi, ale pro pochopení je to tam popsáno dobře. Ale asi mi nezbude nic jiného, než najít nějakou knihovnu, stáhnout si zdroják a učit se.
Ahoj. Chtěl bych si vytvořit jednoduchou hru ve stylu PacMana nebo Tetrisu. Nic složitého, jen pro zábavu a naučení se herním principům. Narazil jsem ale na ten problém, že nevím nic o programování s grafikou. Myslím tím práce s texturami, grafickými efekty, animacemi, sprity, vektory, izometrické zobrazení, atd... Protože jde o můj první počin, neznám ani jiné herní mechanismy. Namátkou pathfinding, mapa založená na dlaždicích (tile),základy AI. Zase bych mohl jmenovat více. Vím že polovinu (nebo více) mnou jmenovaných věcí v takto jednoduché hře nepoužiji, ale když už se mám něco učit, tak ať je to se vším všudy.
Proto bych se vás chtěl zeptat, zda nevíte o nějakém uceleném zdroji informací (knihy, videa, tutoriály, články, fóra, weby) na toto téma (tvorba her). Jde mi spíše o popsání principů toho, jak se věci mají a jak fungují, než přímé ukázky využití nějaké knihovny. Samozřejmě čeština/slovenština je vítaná, ale zvládám i angličtinu.
Předem děkuji za odpovědi,
Lorin
Jestli jsem to pochopil správně, musím kolem includů (které se opakují a nechci je načítat vícekrát) dát kombinaci maker preprocesoru #ifndef, #define a #endif?
#ifndef KNIHOVNA_H
#define KNIHOVNA_H
#ifndef KNIHOVNA_string
#define KNIHOVNA_string
#include <string>
#endif
#ifndef KNIHOVNA_sstream
#define KNIHOVNA_sstream
#include <sstream>
#endif
// ... samotný obsah hlavičkového souboru
#endif
#5 yaqwsx
Překladač hlídá vícenásobné vložení funkcí do výsledného binárního (spustitelného souboru)
O tom vím.
#pragma once
Dejme tomu, že by gcc podporovalo #pragma once. Nezamezuje pragma jen tomu, aby mnou vytvořený hlavičkový soubor byl includován několikrát? Jestliže ano, mou situaci to myslím neřeší. Chci zabránit vícenásobnému vkládání cizích hlavičkových souborů. Příklad:
knihovna.hpp
// hlavickovy soubor knihovna.hpp
#include "nejaky_soubor.h"
#include "nejaky_dalsi_soubor_h"
#include <string>
class test {
private:
// ...
public:
// ...
};
knihovna2.hpp
// hlavickovy soubor knihovna2.hpp
#include "nejaky_soubor.h"
#include <string>
class test2 {
private:
// ...
public:
// ..
};
main.cpp
// hlavni soubor
#include <iostream>
#include "knihovna.hpp"
#include "knihovna2.hpp"
int main(int argc, char **argv) {
// ...
}
Jak je vidět, hlavičkový soubor knihovna.hpp i knihovna2.hpp includují nejaky_soubor.h. Já chci zamezit tomu, aby se tento soubor vkládal 2x.
#3 ingiraxo
Ve mnou psaných hlavičkových souborech používám kombinaci #ifndef, #define, #endif,#pragma once je použitelné jen pro Visual Studio ne?
#2 yaqwsx
Proč se tedy používají výše zmíněné makra, když si vše hlídá překladač? Je to nějaký přežitek z dob, kdy to nebylo u překladačů standardem?
----
Takže ve výsledku můžu do každého (mnou psaného) hlavičkového souboru includovat co chci a jestliže jsem to již includoval dříve, nic se přidávat nebude?
Ahoj. Snažím se vytvořit jednoduchou knihovnu pro C++ v řádu desítky souborů. Každá třída je uložena v samostatném souboru, soubory jsou roztříděny do několika adresářů.
Každá třída využívá několik hlavičkových souborů. Ty, které využije jen daná třída (popřípadě ještě jedna, či dvě), vkládám (#include) přímo do hlavičkových souborů dané třídy. Problém je s hlavičkovými soubory, které využívám ve většině tříd (string, iostream, a další). Nechce se mi je psát ke každé třídě, protože nechci několikrát načítat jednu a tu samou věc.
Jak se v tomto případě postupuje?
1) Napadlo mě vytvořit jeden hlavičkový soubor, který by každá třída includovala. To ale nic neřeší, naopak se přidává další soubor, který je potřeba načíst.
2) Druhý nápad bylo vytvoření jednoho "hlavního" hlavičkového souboru, který by do sebe includoval potřebné C++ knihovny (již zmíněný string, iostream, ...). Tento hlavičkový soubor by se v projektu, který by knihovnu využíval, musel uvést jako první (první by se přidal pomocí Include) a ostatní hlavičkové soubory by z něj jen čerpaly (vše potřebné by již bylo vloženo).
3) A poslední možností je nechat vše na uživateli a starat se jen o nestandardní knihovny, které se většinou neincludují (zmínkou třeba boost). String a iostream by musel includovat do svého projektu sám uživatel.
Jak s druhým, tak s posledním případem mám problémy. Nedokážu donutit překladač (používám g++ 4.4.5), aby ignoroval chyby z neincludování potřebných hlavičkových souborů.
Díky za nápady, Lorin
V ncurses jsem nikdy nedělal, takže jsem jen použil google. Zkus: wresize (příklad: zde), popřípadě resizeterm.
#4 vitamin
Uint32 používám právě z toho důvodu, že na všech OS, na které je SDL portováno, bude mít Uint stejnou velikost.
Co se týče u_int32_t, jaký je rozdíl mezi ním a uint32_t? Není to tak, že u_int32_t je definováno v nějakém linuxovém hlavičkovém souboru (tuším sys/types.h) a uint32_t je v <stdint.h>? Pak by byl u_int32_t nepoužitelný na jiných platformách (Windows, Mac), čemuž bych se chtěl vyhnout.
Ahoj, mám následující kód pro převod z šestnáctkové do desítkové soustavy:
#include <iostream>
#include <sstream>
#include <string>
#include <SDL/SDL.h> // kvůli Uint32
Uint32 hexToDec(std::string hex) {
std::istringstream iss(hex);
Uint32 decimal;
iss >> std::hex >> decimal;
return decimal;
}
void htmlColor(std::string htmlColorString) {
std::string temp = htmlColorString;
if (temp.length() > 7) {
std::cout << "Error" << std::endl;
}
//
if (temp.at(0) != '#') {
std::cout << "Error" << std::endl;
} else {
temp = temp.substr(1, temp.length());
}
std::cout << temp.substr(0, 2) << " " << hexToDec(temp.substr(0, 2)) << std::endl;
std::cout << temp.substr(2, 2) << " " << hexToDec(temp.substr(2, 3)) << std::endl;
std::cout << temp.substr(4, 2) << " " << hexToDec(temp.substr(4, 5)) << std::endl;
}
int main(int argc, char **argv) {
htmlColor("#00FFDD");
}
Po zkompilování a spuštění dostávám následující výsledky:
# ./hexToDec.run
00 0
FF 4093
DD 221
První a poslední hodnota (00 = 0, DD = 221) jsou správné, ale hodnota pro FF by měla být 255. Může mi někdo objasnit, kde je problém?